diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000000000000000000000000000000000000..b41ec6b295a3e650b762617712ebadebe0383cfe --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,31 @@ +Checks: '-*,readability-identifier-naming,readability-function-size, + readability-braces-around-statements,readability-magic-numbers, + misc-unused-parameters,modernize-use-nullptr,modernize-replace-auto-ptr, + modernize-use-noexcept,modernize-use-override,performance-move-const-arg, + cppcoreguidelines-pro-type-cstyle-cast,cppcoreguidelines-pro-type-reinterpret-cast, + cppcoreguidelines-pro-type-const-cast' +CheckOptions: + - key: readability-identifier-naming.ClassCase + value: CamelCase + - key: readability-identifier-naming.StructCase + value: CamelCase + - key: readability-identifier-naming.TypedefCase + value: CamelCase + - key: readability-identifier-naming.EnumCase + value: CamelCase + - key: readability-identifier-naming.EnumConstantCase + value: camelBack + - key: readability-identifier-naming.UnionCase + value: CamelCase + - key: readability-identifier-naming.NamespaceCase + value: lower_case + - key: readability-identifier-naming.FunctionCase + value: CamelCase + - key: readability-identifier-naming.VariableCase + value: camelBack + - key: readability-identifier-naming.ConstantCase + value: camelBack + - key: readability-function-size.StatementThreshold + value: 50 + - key: readability-function-size.ParameterThreshold + value: 5 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..dcf0dec08f06bb5391c8935caae1a02ce71b0c3c --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +android/* +third_party/d8* +third_party/icu* +third_party/libdex* +third_party/aosp_10.0.0_r35* +third_party/aosp_modified* +third_party/ctorture* +third_party/llvm_modified* +third_party/llvm-* +tools/lib +tools/bin* +tools/android* +tools/aosp* +tools/clang* +tools/gcc* +tools/gn* +tools/icu* +tools/libz* +tools/zlib* +tools/ninja* +tools/qemu* +tools/r8* +tools/release* +tools/sysroot-glibc* +build/logs* +libjava-core +output +compile_commands.json +testsuite/tools* +*__pycache__* diff --git a/.gn b/.gn new file mode 100644 index 0000000000000000000000000000000000000000..c00e581063d8ce84c72d56d979a105c8d833a701 --- /dev/null +++ b/.gn @@ -0,0 +1,15 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +buildconfig = "//build/config/BUILDCONFIG.gn" diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..40e691379fdb548eb9a6292775b15262bfa1c51d --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,68 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +group("maple") { + deps = [ "${MAPLEALL_ROOT}:maple" ] +} + +group("irbuild") { + deps = [ "${MAPLEALL_ROOT}:irbuild" ] +} + +group("hir2mpl") { + deps = [ "${HIR2MPL_ROOT}:hir2mpl" ] +} + +group("hir2mplUT") { + deps = [ "${HIR2MPL_ROOT}/test:hir2mplUT" ] +} + +group("maple-rt") { + deps = [ "${MAPLE_MRT_ROOT}:maple-rt" ] +} + +group("ast2mpl") { + deps = [] + if (IS_AST2MPL_EXISTS == "1") { + deps = [ "${AST2MPL_ROOT}/src:ast2mpl" ] + } +} + +group("mapleallUT") { + deps = [ + "${MAPLEALL_ROOT}/test:mapleallUT", + ] +} + +group("maplegendef") { + exeTool = "-e" + rebase_path("${GN_BINARY_OUTPUT_DIRECTORY}/maplegen", root_build_dir) + mdDir = "-m" + rebase_path("${MAPLEALL_ROOT}/maple_be/include/ad/cortex_a55", root_build_dir) + outDir = "-o" + rebase_path("${MAPLE_BUILD_OUTPUT}/common/target", root_build_dir) + if (ASAN == 1) { + exec_script("${MAPLEALL_ROOT}/maple_be/mdgen/gendef.py", + [ + "-aLD_PRELOAD=${LLVMLIBDIR}/libclang_rt.asan-x86_64.so", + exeTool, + mdDir, + outDir, + ]) + } else { + exec_script("${MAPLEALL_ROOT}/maple_be/mdgen/gendef.py", + [ + exeTool, + mdDir, + outDir + ]) + } +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..f1e5b20f8152395af6c06f294c0275611b1abc89 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,51 @@ +FROM ubuntu:16.04 AS build-env +MAINTAINER https://www.openarkcompiler.cn + +# Setting up the build environment +RUN sed -i 's/archive.ubuntu.com/mirrors.163.com/g' /etc/apt/sources.list && \ + dpkg --add-architecture i386 && \ + apt-get -y update && \ + apt-get -y dist-upgrade && \ + apt-get -y install openjdk-8-jdk git-core build-essential zlib1g-dev libc6-dev-i386 g++-multilib gcc-multilib linux-libc-dev:i386 && \ + apt-get -y install gcc-5-aarch64-linux-gnu g++-5-aarch64-linux-gnu unzip tar curl && \ + apt-get -y install python3-paramiko python-paramiko python-requests && \ + mkdir -p /tools/ninja /tools/gn + +# 在国内请反注释下行, 因为容器也是个单独的系统,所以别用127.0.0.1 +#ENV http_proxy=http://192.168.3.81:1081 \ +# https_proxy=http://192.168.3.81:1081 + +RUN cd /tools && \ + curl -C - -LO http://releases.llvm.org/8.0.0/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz && \ + curl -LO https://github.com/ninja-build/ninja/releases/download/v1.9.0/ninja-linux.zip && \ + curl -LO http://tools.harmonyos.com/mirrors/gn/1523/linux/gn.1523.tar && \ + tar Jvxf /tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz -C /tools/ && \ + unzip /tools/ninja-linux.zip -d /tools/ninja/ && \ + tar xvf /tools/gn.1523.tar && \ + chmod a+x /tools/gn/gn && \ + rm /tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz /tools/ninja-linux.zip && \ + rm -rf /var/cache/apt/archives + +# copy source +COPY . /OpenArkCompiler +WORKDIR /OpenArkCompiler + +# create symbolic link +RUN mkdir -p /OpenArkCompiler/tools /OpenArkCompiler/tools/gn && \ + ln -s /tools/ninja /OpenArkCompiler/tools/ninja_1.9.0 && \ + ln -s /tools/gn/gn /OpenArkCompiler/tools/gn/gn && \ + ln -s /tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04 /OpenArkCompiler/tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04 + +# compile +RUN ["/bin/bash", "-c", "source build/envsetup.sh && make && ls -al "] + +# build final docker image +FROM ubuntu:16.04 +RUN sed -i 's/archive.ubuntu.com/mirrors.163.com/g' /etc/apt/sources.list && \ + apt-get -y update && \ + apt-get install -y openjdk-8-jdk curl vim && \ + rm -rf /var/cache/apt/archives +COPY --from=build-env /OpenArkCompiler/output /OpenArkCompiler +VOLUME /OpenArkCompiler +ENV PATH=/OpenArkCompiler/bin:$PATH +CMD maple -h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9f4db91c476ff7f37133a41af8e7179986fb354f --- /dev/null +++ b/Makefile @@ -0,0 +1,201 @@ +# +# Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +# Makefile for OpenArkCompiler +OPT := O2 +DEBUG := $(MAPLE_DEBUG) +INSTALL_DIR := $(MAPLE_BUILD_OUTPUT) +LIB_CORE_PATH := $(MAPLE_BUILD_OUTPUT)/libjava-core/host-x86_64-$(OPT) +MAPLE_BIN_DIR := $(MAPLE_ROOT)/src/mapleall/bin +MRT_ROOT := $(MAPLE_ROOT)/src/mrt +ANDROID_ROOT := $(MAPLE_ROOT)/android +MAJOR_VERSION := $(MAPLE_MAJOR_VERSION) +MINOR_VERSION := $(MAPLE_MINOR_VERSION) +RELEASE_VERSION := $(MAPLE_RELEASE_VERSION) +BUILD_VERSION := $(MAPLE_BUILD_VERSION) +GIT_REVISION := $(shell git log --pretty=format:"%H" -1) +MAST := 0 +ASAN := 0 +ifeq ($(DEBUG),0) + BUILD_TYPE := RELEASE +else + BUILD_TYPE := DEBUG +endif +HOST_ARCH := 64 +MIR_JAVA := 1 +GN := $(MAPLE_ROOT)/tools/gn/gn +NINJA := $(shell ls $(MAPLE_ROOT)/tools/ninja*/ninja | tail -1) +ifneq ($(findstring GC,$(OPT)),) + GCONLY := 1 +else + GCONLY := 0 +endif + +GN_OPTIONS := \ + GN_INSTALL_PREFIX="$(MAPLE_ROOT)" \ + GN_BUILD_TYPE="$(BUILD_TYPE)" \ + HOST_ARCH=$(HOST_ARCH) \ + MIR_JAVA=$(MIR_JAVA) \ + OPT="$(OPT)" \ + GCONLY=$(GCONLY) \ + TARGET="$(TARGET_PROCESSOR)" \ + MAJOR_VERSION="$(MAJOR_VERSION)" \ + MINOR_VERSION="$(MINOR_VERSION)" \ + RELEASE_VERSION="$(RELEASE_VERSION)" \ + BUILD_VERSION="$(BUILD_VERSION)" \ + GIT_REVISION="$(GIT_REVISION)" \ + MAST=$(MAST) \ + ASAN=$(ASAN) + +.PHONY: default +default: install + +.PHONY: directory +directory: + $(shell mkdir -p $(INSTALL_DIR)/bin;) + +.PHONY: install_patch +install_patch: + @bash build/third_party/patch.sh patch + +.PHONY: uninstall_patch +uninstall_patch: + @bash build/third_party/patch.sh unpatch + +.PHONY: maplegen +maplegen:install_patch + $(call build_gn, $(GN_OPTIONS), maplegen) + +.PHONY: maplegendef +maplegendef: maplegen + $(call build_gn, $(GN_OPTIONS), maplegendef) + +.PHONY: maple +maple: maplegendef + $(call build_gn, $(GN_OPTIONS), maple) + +.PHONY: irbuild +irbuild: install_patch + $(call build_gn, $(GN_OPTIONS), irbuild) + +.PHONY: mpldbg +mpldbg: + $(call build_gn, $(GN_OPTIONS), mpldbg) + +.PHONY: ast2mpl +ast2mpl: + $(call build_gn, $(GN_OPTIONS), ast2mpl) + +.PHONY: hir2mpl +hir2mpl: install_patch + $(call build_gn, $(GN_OPTIONS), hir2mpl) + +.PHONY: clang2mpl +clang2mpl: maple + (cd tools/clang2mpl; make setup; make; make install) + +.PHONY: hir2mplUT +hir2mplUT: + $(call build_gn, $(GN_OPTIONS) COV_CHECK=1, hir2mplUT) + +.PHONY: libcore +libcore: maple-rt + cd $(LIB_CORE_PATH); \ + $(MAKE) install OPT=$(OPT) DEBUG=$(DEBUG) + +.PHONY: maple-rt +maple-rt: java-core-def + $(call build_gn, $(GN_OPTIONS), maple-rt) + +.PHONY: mapleallUT +mapleallUT: install_patch + $(call build_gn, $(GN_OPTIONS), mapleallUT) + +.PHONY: java-core-def +java-core-def: install + mkdir -p $(LIB_CORE_PATH); \ + cp -rp $(MAPLE_ROOT)/libjava-core/* $(LIB_CORE_PATH)/; \ + cd $(LIB_CORE_PATH); \ + ln -f -s $(MAPLE_ROOT)/build/core/libcore.mk ./makefile; \ + $(MAKE) gen-def OPT=$(OPT) DEBUG=$(DEBUG) + +.PHONY: install +install: maple dex2mpl_install irbuild hir2mpl + $(shell mkdir -p $(INSTALL_DIR)/ops/linker/; \ + rsync -a -L $(MRT_ROOT)/maplert/linker/maplelld.so.lds $(INSTALL_DIR)/ops/linker/; \ + rsync -a -L $(MAPLE_ROOT)/build/java2d8 $(INSTALL_DIR)/bin; \ + rsync -a -L $(MAPLE_BIN_DIR)/java2jar $(INSTALL_DIR)/bin/; \ + cp -rf $(MAPLE_ROOT)/tools $(INSTALL_DIR)/../; \ + rsync -a -L $(MAPLE_ROOT)/src/hir2mpl/ast_input/clang/lib/sys/ $(INSTALL_DIR)/lib/include/;) + +.PHONY: all +all: install libcore + +.PHONY: dex2mpl_install +dex2mpl_install: directory + $(shell rsync -a -L $(MAPLE_BIN_DIR)/dex2mpl $(INSTALL_DIR)/bin/;) + +.PHONY: setup +setup: + (cd tools; ./setup_tools.sh) + +.PHONY: demo +demo: + test/maple_aarch64_with_hir2mpl.sh test/c_demo printHuawei 1 1 + test/maple_aarch64_with_clang2mpl.sh test/c_demo printHuawei 1 1 + +.PHONY: ctorture-ci +ctorture-ci: + (cd third_party/ctorture; git checkout .; git pull; ./ci.sh) + +.PHONY: ctorture +ctorture: + (cd third_party/ctorture; git checkout .; git pull; ./run.sh work.list) + +.PHONY: ctorture2 +ctorture2: + (cd third_party/ctorture; git checkout .; git pull; ./run.sh work.list hir2mpl) + +THREADS := 50 +ifneq ($(findstring test,$(MAKECMDGOALS)),) +TESTTARGET := $(MAKECMDGOALS) +ifdef TARGET +REALTARGET := $(TARGET) +else +REALTARGET := $(TESTTARGET) +endif +.PHONY: $(TESTTARGET) +${TESTTARGET}: + @python3 $(MAPLE_ROOT)/testsuite/driver/src/driver.py --target=$(REALTARGET) --run-path=$(MAPLE_ROOT)/output/$(MAPLE_BUILD_TYPE)/testsuite $(if $(MOD), --mod=$(MOD),) --j=$(THREADS) +endif + +.PHONY: cleanrsd +cleanrsd:uninstall_patch + @rm -rf libjava-core/libcore-all.* libjava-core/m* libjava-core/comb.* + +.PHONY: clean +clean: cleanrsd + @rm -rf $(MAPLE_BUILD_OUTPUT)/ + @rm -rf $(MAPLE_ROOT)/report.txt + +.PHONY: clobber +clobber: cleanrsd + @rm -rf output + +define build_gn + mkdir -p $(INSTALL_DIR); \ + $(GN) gen $(INSTALL_DIR) --args='$(1)' --export-compile-commands; \ + cd $(INSTALL_DIR); \ + $(NINJA) -v $(2); +endef diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000000000000000000000000000000000000..870f27a720326ec28ca5afd48ac9a87b4d16265f --- /dev/null +++ b/Readme.md @@ -0,0 +1,82 @@ +# OpenArkCompiler + +## Overview +----------------- +> Unified programming platform supporting multiple devices and languages + +OpenArkCompiler is Huawei's open source project. + +### Four Technical Features of OpenArkCompiler ### + +Compiles code of different languages into a set of executable files and efficiently executes the files in the running environment. +- Supports joint optimization of multiple languages and eliminates cross-language calling overhead. +- Achieves lightweight language runtime. +- Collaborates hardware and software to maximize hardware energy efficiency. +- Supports diversified terminal platforms. + +## Open Source Plan +**Open source compiler framework code** +- Time: August, 2019 +- Scope: Compiler IR and middle-end language implementation +- Benefits: + - Provides an open source framework for understanding the architecture and framework code of OpenArkCompiler. + - Allows developers to build a complete compiler toolchain that supports the compilation of Java samples (non-application). + +**Subsequent open source scope** +Open the front end, back end, and compilation optimization of compilers. Support the full compilation of Java programs and JavaScript applications. + +|Open Source Scope|March 2020 |May 2020 | +| ------------ | -------------------|--------------------- | +|Front end| Jbc front-end basic framework | Front-end full open source | +|Middle end |Weekly open source optimization phase | | +|Back end |Backend open source (O0) (aarch64)|Weekly open source optimization (O2) (aarch64)| +|Test framework|Test framework and basic Cases| | + +**Updating...** + +## How to use +- source build/envsetup.sh arm release + or +- source build/envsetup.sh arm debug +- make setup (In this step, you may need to configure the proxy or VPN to download all dependencies.) +- make +- make libcore +- make testall + +C example: +- make demo + +## OpenArkCompiler Incubator +- FutureWei Mapleall https://gitee.com/openarkcompiler-incubator/mapleall +- Maple Engine https://gitee.com/openarkcompiler-incubator/maple_engine +- Maple FrondEnd https://gitee.com/openarkcompiler-incubator/MapleFE +- Maple clang2mpl https://gitee.com/openarkcompiler-incubator/clang2mpl + +## Related Documents + +- Architecture Design Principles + - [MAPLE IR Design](doc/en/MapleIRDesign.md) + - [RC API](doc/en/RcApi.md) + - [Naive RC Insertion Principle](doc/en/NaiveRcInsertionDescription.md) + - [Virtual Table and Interface Table Design](doc/en/VtableItableDescription.md) + - [Phase Design](doc/en/CompilerPhaseDescription.md) + - [Application Manual of Maple General Modules](doc/en/DeveloperGuide4Utility.md) + + +- [Environment Configuration](doc/en/DevelopmentPreparation.md) + +- [Developer Guide](doc/en/DeveloperGuide.md) + +- [Programming Specifications](doc/en/ProgrammingSpecifications.md) + +- [Discussion of Pointer in C++ Programming](doc/en/CPPCodingTalkAboutPointer.md) + +## License +- [LICENSE](license/LICENSE) + +## Real-time Chat Channel +- [Discord-OpenArkCompiler](https://discord.gg/CJeJWQXxMP) +- 9:00 am - 10:30 am everyday, developers can discuss community issues in the voice channel "panel discussion" + +- [Discord-MapleFE](https://discord.gg/sBj3cc4GhM) +- we have weekly meeting about projects related to MapleFE diff --git a/Readme_zh.md b/Readme_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..a2aab5783752ad526e2a212a7374fd72ca03abbd --- /dev/null +++ b/Readme_zh.md @@ -0,0 +1,76 @@ +# OpenArkCompiler + +## 概述 +----------------- +> 面向多设备、支持多语言的统一编程平台。 + +OpenArkCompiler是来自华为方舟编译器的开源项目。 + +### OpenArkCompiler 四个技术特点 ### + +能够将不同语言代码编译成一套可执行文件,在运行环境中高效执行: +- 支持多语言联合优化、消除跨语言调用开销; +- 更轻量的语言运行时; +- 软硬协同充分发挥硬件能效; +- 支持多样化的终端设备平台 + +## 开源计划 +**编译器框架代码开源** +- 时间:2019年8月 +- 开源范围:编译器IR+中端语言实现 +- 开放能力: + - 框架开源供参考学习,了解方舟编译器架构及框架代码 + - 开发者可构建出完整编译器工具链,支持Java Sample程序编译(非应用) + +**后续开源范围** +陆续开源编译器前端、后端、编译优化;完整支持Java程序编译、JavaScript语言应用的编译等。 + +|开源范围 |2020年3月 |2020年5月 | +| ------------ | -------------------|--------------------- | +|编译器前端 |jbc前端基础框架 |前端全量开源 | +|编译器中端 |独立优化Phase每周持续开源 || +|编译器后端 |后端开源(O0) (aarch64)|独立优化按周开源(O2) (aarch64)| +|测试框架 |测试框架+基础用例开源| | + +**计划持续更新...** + +## 如何使用 +- source build/envsetup.sh arm release + 或 +- source build/envsetup.sh arm debug +- make setup (这一步可能需要配置代理或者vpn,才能将所有依赖下载下来) +- make +- make libcore +- make testall + +## 孵化器项目 +- FutureWei编译器分支 https://gitee.com/openarkcompiler-incubator/mapleall +- Maple Engine https://gitee.com/openarkcompiler-incubator/maple_engine + +## 相关文档 + +- 架构设计原理 + - [MAPLE IR Design](doc/en/MapleIRDesign.md) + - [RC API](doc/cn/RcApi.md) + - [Naive RC操作插入原理](doc/cn/NaiveRcInsertionDescription.md) + - [虚函数表和接口函数表设计介绍](doc/cn/VtableItableDescription.md) + - [Phase设计介绍](doc/cn/CompilerPhaseDescription.md) + - [Maple通用模块应用手册](doc/cn/DeveloperGuide4Utility.md) + +- [环境配置](doc/cn/DevelopmentPreparation.md) + +- [开发者指南](doc/cn/DeveloperGuide.md) + +- [编程规范](doc/cn/ProgrammingSpecifications.md) + +- [C++编程探讨之指针](doc/cn/CPPCodingTalkAboutPointer.md) + +## 许可证 +- [LICENSE](license/LICENSE) + +## 开发者交流频道 +- [Discord-OpenArkCompiler](https://discord.gg/CJeJWQXxMP) +- 每天上午9:00~10:30不定时在语音频道“panel disscussion”交流社区议题。 + +## 如何提交代码 +- [wiki](https://gitee.com/openarkcompiler/OpenArkCompiler/wikis/%E4%BB%A3%E7%A0%81%E6%8F%90%E4%BA%A4%E6%B5%81%E7%A8%8B?sort_id=2447213) diff --git a/Release.md b/Release.md new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/MapleFE/recdetect/build.sh b/build/build.sh similarity index 36% rename from src/MapleFE/recdetect/build.sh rename to build/build.sh index aa92897ffaa1b044f1d04b1656f09453074e554e..c88052b81a918ee150c5fe13d447f6d9964b1553 100755 --- a/src/MapleFE/recdetect/build.sh +++ b/build/build.sh @@ -1,39 +1,30 @@ -# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. -# -# OpenArkFE is licensed under the Mulan PSL v2. +#!/bin/bash +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. # You can use this software according to the terms and conditions of the Mulan PSL v2. # You may obtain a copy of Mulan PSL v2 at: -# -# http://license.coscl.org.cn/MulanPSL2 -# +# +# http://license.coscl.org.cn/MulanPSL2 +# # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR # FIT FOR A PARTICULAR PURPOSE. # See the Mulan PSL v2 for more details. -# - -#!/bin/bash - -# Usage: -# ./build.sh [LANG] # -# eg. ./build.sh java - -rm -rf $BUILDDIR/recdetect -rm -rf $BUILDDIR/recdetect/$1 - -rm -rf $1 -mkdir -p $1 - -cp ../$1/include/gen_*.h $1/ -cp ../$1/src/gen_*.cpp $1/ - -# The four generated files shouldn't be taken in. -rm -f $1/gen_recursion.h -rm -f $1/gen_recursion.cpp -rm -f $1/gen_lookahead.h -rm -f $1/gen_lookahead.cpp - -mkdir -p $BUILDDIR/recdetect -mkdir -p $BUILDDIR/recdetect/$1 -make LANG=$1 +set -e +source build/envsetup.sh arm release +make clean +option=$@ +model=$1 +if [ -z "$model" ];then + model="libcore" +fi +logfile_name=$(date +"%Y-%m-%d-%H-%M-%S") +logfile_path=${MAPLE_ROOT}/build/logs +date_str=$(date "+%Y-%m-%d %H:%M:%S") +echo "${date_str} $model INFO special log start" | tee ${logfile_path}/${logfile_name}.log +make ${option} | tee -a ${logfile_path}/${logfile_name}.log +date_str=$(date "+%Y-%m-%d %H:%M:%S") +echo "${date_str} $model INFO special log end" | tee -a ${logfile_path}/${logfile_name}.log diff --git a/build/config.gni b/build/config.gni new file mode 100644 index 0000000000000000000000000000000000000000..5db3bf2ce137c9fb04aad98a231669bab0537452 --- /dev/null +++ b/build/config.gni @@ -0,0 +1,42 @@ +# +# Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +# Toolchain setup + +CLANG_PATH = "${MAPLE_ROOT}/tools/clang+llvm-12.0.0-x86_64-linux-gnu-ubuntu-18.04" + +LLVMINC = "${CLANG_PATH}/include" +LLVMLIBDIR = "${CLANG_PATH}/lib" +CFE_SRC_DIR = "${MAPLE_ROOT}/../third-party/clang-10.0.0.src" +CFE_SRC_PATH = "${MAPLE_ROOT}/third_party/llvm-12.0.0.src/clang" + +# MapleFE path +MAPLE_PARSER_PATH = "" + +GCC_LINARO_PATH = "${MAPLE_ROOT}/tools/gcc-linaro-7.5.0" +NDK_PATH = "${MAPLE_ROOT}/tools/android-ndk-r21" + +GN_C_COMPILER = "${TOOL_BIN_PATH}/clang" +GN_CXX_COMPILER = "${TOOL_BIN_PATH}/clang++" +GN_AR_COMPILER = "${TOOL_BIN_PATH}/llvm-ar" +GN_RANLIB_COMPILER = "${TOOL_BIN_PATH}/llvm-ranlib" + +target_toolchain = "//build/toolchain:clang" +set_default_toolchain(target_toolchain) + +# Cross compile +GN_C_CROSS_COMPILER = "${GCC_LINARO_PATH}/bin/aarch64-linux-gnu-gcc" +GN_CXX_CROSS_COMPILER = "${GCC_LINARO_PATH}/bin/aarch64-linux-gnu-g++" +GN_AR_CROSS_COMPILER = "${GCC_LINARO_PATH}/bin/aarch64-linux-gnu-ar" +GN_RANLIB_CROSS_COMPILER = "${GCC_LINARO_PATH}/bin/aarch64-linux-gnu-ranlib" diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn new file mode 100755 index 0000000000000000000000000000000000000000..5f0817677a4d816c4b5fb220cfbbf7077d70e5dc --- /dev/null +++ b/build/config/BUILDCONFIG.gn @@ -0,0 +1,185 @@ +# This file is the master GN build configuration, all variables +# declare here will be implicitly global. +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +# List all the input args +declare_args() { + GN_INSTALL_PREFIX = "" + GN_BUILD_TYPE = "" + HOST_ARCH = 64 + MIR_JAVA = 1 + COV_CHECK = 0 + GCONLY = 0 + OPT = "O2" + TARGET = "" + MAJOR_VERSION = "" + MINOR_VERSION = "" + RELEASE_VERSION = "" + BUILD_VERSION = "" + GIT_REVISION = "" + MAST = 0 + ASAN = 0 +} + +# Define global args +MAPLE_ROOT = getenv("MAPLE_ROOT") +ANDROID_ROOT = "${MAPLE_ROOT}/android" +AOSP_ROOT = "${MAPLE_ROOT}/third_party/aosp_modified" +MAPLE_BUILD_TYPE = getenv("MAPLE_BUILD_TYPE") +MAPLE_BUILD_OUTPUT = getenv("MAPLE_BUILD_OUTPUT") +TOOL_BIN_PATH = getenv("TOOL_BIN_PATH") +QEMU_PATH = getenv("TOOL_BIN_PATH") +OLD_OS = getenv("OLD_OS") +if (OLD_OS == "1") { + DESIGNATOR="-Wno-gnu-designator" +} else { + DESIGNATOR="-Wno-c99-designator" +} + +DYNAMICLANG = true +RC_V2 = true +TEST_BENCHMARK = false +MEMORY_LEAK_CHECK = false +MARK_CYCLE_ROOTS = false + +OPENSOURCE_DEPS = "${MAPLE_ROOT}/src/mapleall/deplibs" +OPENSOURCE_OUTPUT = "${MAPLE_BUILD_OUTPUT}" +AST2MPL_ROOT = "${MAPLE_ROOT}/src/ast2mpl" +IS_AST2MPL_EXISTS = getenv("IS_AST2MPL_EXISTS") +MAPLEALL_ROOT = "${MAPLE_ROOT}/src" +MAPLEALL_ROOT = "${MAPLE_ROOT}/src/mapleall" +HIR2MPL_ROOT = "${MAPLE_ROOT}/src/hir2mpl" +MAPLE_MRT_ROOT = "${MAPLE_ROOT}/src/mrt" +THIRD_PARTY_ROOT = "${MAPLE_ROOT}/third_party" + +# Put all built library files under lib +GN_ARCHIVE_OUTPUT_DIRECTORY = "${MAPLE_BUILD_OUTPUT}/ar/host-x86_64-${OPT}" +GN_LIBRARY_OUTPUT_DIRECTORY = "${MAPLE_BUILD_OUTPUT}/lib" + +# Put all built binary files under bin +GN_BINARY_OUTPUT_DIRECTORY = "${MAPLE_BUILD_OUTPUT}/bin" + +import("${MAPLE_ROOT}/build/config.gni") + +# C/CXX Build flags +cflags = [] +cflags_cc = [] +cflags_c = [] +if (GN_BUILD_TYPE == "RELEASE") { + cflags_cc += [ + "-O2", + "-fno-strict-aliasing", + "-D_FORTIFY_SOURCE=2", + ] + cflags_c += [ + "-O2", + "-fno-strict-aliasing", + "-D_FORTIFY_SOURCE=2", + ] +} else if (GN_BUILD_TYPE == "DEBUG") { + cflags_cc += [ + "-O0", + "-g3", + "-ftrapv", + "-fstack-check", + ] + cflags_c += [ + "-O0", + "-g3", + "-ftrapv", + "-fstack-check", + ] + if (target_toolchain == "//build/toolchain:clang") { + cflags_c += ["-fno-limit-debug-info"] + cflags_cc += ["-fno-limit-debug-info"] + } +} else { + cflags_cc += [ + "-O2", + "-fno-strict-aliasing", + "-g", + ] + cflags_c += [ + "-O2", + "-fno-strict-aliasing", + "-g", + ] +} + +cflags_c += [ + "-Wall", + "-fstack-protector-strong", + "-fPIC", + "-fPIE", + "-fvisibility=hidden", + "-pipe", + "-Werror", + "-Wdate-time", + "-Wfloat-equal", + "${DESIGNATOR}", +] + +cflags_cc += [ + "-Wall", + "-fstack-protector-strong", + "-fPIC", + "-fPIE", + "-fvisibility=hidden", + "-pipe", + "-Wno-c99-designator", + "-Wno-range-loop-construct", + "-Werror", + "-Wdate-time", + "-Wfloat-equal", + "${DESIGNATOR}", +] + +if (HOST_ARCH == 64) { + cflags_c += [ "-m64" ] + cflags_cc += [ "-m64" ] +} else { + cflags_c += [ "-m32" ] + cflags_cc += [ "-m32" ] +} + +if (DYNAMICLANG) { + cflags_cc += [ "-DDYNAMICLANG" ] +} + +if (RC_V2) { + cflags_cc += [ "-DRC_NO_MMAP" ] +} + +if (TEST_BENCHMARK) { + cflags_cc += [ "-DTEST_BENCHMARK" ] +} + +if (MEMORY_LEAK_CHECK) { + cflags_cc += [ "-DMEMORY_LEAK_CHECK" ] +} + +if (MARK_CYCLE_ROOTS) { + cflags_cc += [ "-DMARK_CYCLE_ROOTS" ] +} + +cflags_cc += [ "-DMIR_FEATURE_FULL=1" ] + +if (MIR_JAVA == 1) { + cflags_cc += [ "-DMIR_JAVA=1" ] +} else { + TARGET = "vm" + cflags_cc += [ "-DMIR_JAVA=0" ] +} diff --git a/build/core/extra.mk b/build/core/extra.mk new file mode 100644 index 0000000000000000000000000000000000000000..2c8551bb9d37ec6804fdd10fc93fe96041a5a890 --- /dev/null +++ b/build/core/extra.mk @@ -0,0 +1,24 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +$(INIT_CXX_SRC): $(ADD_OBJS) + cp -f $< $@ + +ifeq ($(DEBUG), 0) +$(INIT_CXX_O) : $(INIT_CXX_SRC) + $(QEMU_CLANG_CPP) -O2 $(QEMU_CLANG_FLAGS) -c $^ -o $@ +else +$(INIT_CXX_O) : $(INIT_CXX_SRC) + $(QEMU_CLANG_CPP) -O0 -g3 $(QEMU_CLANG_FLAGS) -c $^ -o $@ +endif diff --git a/build/core/genmplt.mk b/build/core/genmplt.mk new file mode 100644 index 0000000000000000000000000000000000000000..89ffab5337c56eaa0627544a447f829ad793a60a --- /dev/null +++ b/build/core/genmplt.mk @@ -0,0 +1,16 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +$(LIB_CORE_MPLT): $(JBC2MPL_BIN) $(LIB_CORE_JAR) + $(JBC2MPL_BIN) -injar $(LIB_CORE_JAR) -output $(LIB_CORE_PATH) diff --git a/build/core/hir2mpl.mk b/build/core/hir2mpl.mk new file mode 100644 index 0000000000000000000000000000000000000000..e45502f68de5ae349e36d54b7787e27b6bca2506 --- /dev/null +++ b/build/core/hir2mpl.mk @@ -0,0 +1,17 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +$(APP_MPL): %.mpl : %.dex $(HIR2MPL_BIN) + $(HIR2MPL_BIN) $(HIR2MPL_FLAGS) $< + diff --git a/build/core/hir2mpl_test.mk b/build/core/hir2mpl_test.mk new file mode 100644 index 0000000000000000000000000000000000000000..de06e1b828e6ae748cf2d42be13b2c225249d0ef --- /dev/null +++ b/build/core/hir2mpl_test.mk @@ -0,0 +1,16 @@ +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +$(APP_MPL): %.mpl : %.dex $(HIR2MPL_BIN) + $(HIR2MPL_BIN) $(HIR2MPL_APP_FLAGS) $< diff --git a/build/core/java2dex.mk b/build/core/java2dex.mk new file mode 100644 index 0000000000000000000000000000000000000000..20dbe3122425e58a963a168f1e291e4706e23696 --- /dev/null +++ b/build/core/java2dex.mk @@ -0,0 +1,2 @@ +$(APP_DEX): %.dex : %.java $(wildcard $(JAR_LIBS_PATH)/*.java) + @bash $(JAVA2DEX) -o $(APP_DEX) $(JAVA2DEX_FLAGS) -i $(APP_JAVA):${EXTRA_JAVA_FILE} $< diff --git a/build/core/libcore.mk b/build/core/libcore.mk new file mode 100644 index 0000000000000000000000000000000000000000..84354068e26247d7c3f09e1fb1f75bad5313cd29 --- /dev/null +++ b/build/core/libcore.mk @@ -0,0 +1,88 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +APP := libcore-all +include $(MAPLE_BUILD_CORE)/maple_variables.mk +ifeq ($(DEBUG), 1) + MPLCG_FLAGS := $(MPLCG_FLAGS) --add-debug-trace +endif +include $(MAPLE_BUILD_CORE)/qemu_ar.mk + +ifeq ($(DEBUG), 0) + QEMU_CXX_FLAGS := -O2 -s +else + QEMU_CXX_FLAGS := -O0 -g3 +endif + +ifeq ($(DISABLE_RC_DUPLICATE), 1) + RC_FLAGS = -DDISABLE_RC_DUPLICATE=1 +else + RC_FLAGS = -DDISABLE_RC_DUPLICATE=0 +endif + +LINKER_QEMU_OPT := -fuse-ld=lld -rdynamic -Wl,-Bsymbolic -lpthread -ldl -L$(MAPLE_OUT)/lib/ -L$(MAPLE_ROOT)/third_party/icu/lib/aarch64-linux-gnu -licuuc + +$(APP_O): %.VtableImpl.o : %.VtableImpl.s + $(QEMU_CLANG_CPP) $(QEMU_CXX_FLAGS) $(QEMU_CLANG_FLAGS) $(RC_FLAGS) -c -o $@ $< + +$(APP_QEMU_SO): %.VtableImpl.qemu.so : %.VtableImpl.o $(INIT_CXX_O) $(qemu) + $(QEMU_CLANG_CPP) $(QEMU_CXX_FLAGS) $(QEMU_CLANG_FLAGS) $(RC_FLAGS) -shared -o $@ $(INIT_CXX_O) -Wl,--whole-archive $(qemu) -Wl,--no-whole-archive $(LINKER_QEMU_OPT) $< -Wl,-T $(LDS) + +include $(MAPLE_BUILD_CORE)/extra.mk +include $(MAPLE_BUILD_CORE)/mplcomb_dex.mk +include $(MAPLE_BUILD_CORE)/hir2mpl.mk + +$(APP_DEX): %.dex : $(D8) $(LIB_CORE_JAR) + $(D8) --min-api 39 --output . $(LIB_CORE_JAR) + mv classes.dex $(APP_DEX) + +.PHONY: gen-def +gen-def: $(APP_DEF) +$(APP_DEF): $(APP_S) + rsync -a -L $(APP_DEF) $(MAPLE_ROOT)/src/mrt/unified.macros.def + +.PHONY: install +install: libcore_so deplibs + $(shell mkdir -p $(MAPLE_OUT)/ops/host-x86_64-$(OPT); \ + mkdir -p $(MAPLE_OUT)/ops/third_party; \ + rsync -a -L ${MAPLE_ROOT}/src/mrt/codetricks ${MAPLE_ROOT}/output/tools/; \ + rsync -a -L $(MAPLE_OUT)/lib/$(OPT)/libcore-all.so $(MAPLE_OUT)/ops/host-x86_64-$(OPT); \ + rsync -a -L $(LIB_CORE_PATH)/mrt_module_init.o $(MAPLE_OUT)/ops/; \ + rsync -a -L $(LIB_CORE_PATH)/libcore-all.mplt $(MAPLE_OUT)/ops/; \ + rsync -a -L $(MAPLE_ROOT)/third_party/aosp_10.0.0_r35/libnativehelper $(MAPLE_OUT)/ops/; \ + rsync -a -L $(MAPLE_ROOT)/android/out/target/common/obj/JAVA_LIBRARIES $(MAPLE_OUT)/ops/third_party; \ + rsync -a -L $(MAPLE_ROOT)/third_party/libdex/prebuilts/aarch64-linux-gnu/libz.so.1.2.8 $(MAPLE_OUT)/ops/third_party/libz.so.1; \ + rsync -a -L $(MAPLE_ROOT)/third_party/icu/lib/aarch64-linux-gnu/* $(MAPLE_OUT)/ops/third_party/; \ + ) + +.PHONY: deplibs +deplibs: + $(shell rsync -a -L $(MAPLE_ROOT)/src/mrt/deplibs/*.so $(MAPLE_OUT)/ops/host-x86_64-$(OPT); \ + rsync -a -L $(MAPLE_ROOT)/src/mrt/bin/mplsh $(MAPLE_OUT)/ops/;) + +.PHONY: libcore_so +libcore_so: $(LIBCORE_SO_QEMU) +$(LIBCORE_SO_QEMU): $(APP_QEMU_SO) + mkdir -p $(MAPLE_OUT)/lib/$(OPT)/ + rsync -a -L $< $@ +clean: + @rm -f libcore-all.* + @rm -f *.mpl + @rm -f *.mplt + @rm -f *.groots.txt + @rm -f *.primordials.txt + @rm -rf comb.log + @rm -rf *.muid + @rm -f *.s + @rm -rf *.o diff --git a/build/core/link.mk b/build/core/link.mk new file mode 100644 index 0000000000000000000000000000000000000000..785af47bc93f0bcfd850de57c2b1bd888ac09b68 --- /dev/null +++ b/build/core/link.mk @@ -0,0 +1,2 @@ +${APP_SO}: %.so : %.VtableImpl.s $(CLANG_BIN) + ${TOOL_BIN_PATH}/clang++ -g3 -O2 -x assembler-with-cpp -march=armv8-a -target aarch64-linux-gnu -c $(APP_S) && ${TOOL_BIN_PATH}/clang++ $(APP_O) -L${OUT_ROOT}/${MAPLE_BUILD_TYPE}/ops/host-x86_64-O2 -g3 -O2 -march=armv8-a -target aarch64-linux-gnu -fPIC -shared -o $(APP_SO) ${OUT_ROOT}/${MAPLE_BUILD_TYPE}/ops/mrt_module_init.o -fuse-ld=lld -rdynamic -lcore-all -lcommon-bridge -Wl,-z,notext -Wl,-T${OUT_ROOT}/${MAPLE_BUILD_TYPE}/ops/linker/maplelld.so.lds diff --git a/build/core/maple_test.mk b/build/core/maple_test.mk new file mode 100644 index 0000000000000000000000000000000000000000..0e148680c16512659331a93f30851a6af97405c7 --- /dev/null +++ b/build/core/maple_test.mk @@ -0,0 +1,39 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +include $(MAPLE_BUILD_CORE)/maple_variables.mk + +test: APP_RUN +include $(MAPLE_BUILD_CORE)/qemu_run.mk +include $(MAPLE_BUILD_CORE)/link.mk +include $(MAPLE_BUILD_CORE)/mplcomb_dex.mk +include $(MAPLE_BUILD_CORE)/genmplt.mk +include $(MAPLE_BUILD_CORE)/hir2mpl_test.mk +include $(MAPLE_BUILD_CORE)/java2dex.mk + +.PHONY: clean +clean: + @rm -rf *.jar + @rm -f *.class + @rm -f *.mpl + @rm -f *.mplt + @rm -f *.s + @rm -f *.groots.txt + @rm -f *.primordials.txt + @rm -rf comb.log + @rm -rf *.muid + @rm -rf *.dex + @rm -rf *.def + @rm -rf *.so + @rm -rf *.o diff --git a/build/core/maple_variables.mk b/build/core/maple_variables.mk new file mode 100644 index 0000000000000000000000000000000000000000..87c8372d90c848b67f1bca0dfd5149fa7727aab2 --- /dev/null +++ b/build/core/maple_variables.mk @@ -0,0 +1,98 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +OPT := O2 +DEBUG := 0 +LIB_CORE_PATH := $(MAPLE_BUILD_OUTPUT)/libjava-core/host-x86_64-$(OPT) +LIB_CORE_JAR := $(LIB_CORE_PATH)/java-core.jar +LIB_CORE_MPLT := $(LIB_CORE_PATH)/java-core.mplt + +GCC_LINARO_PATH := $(MAPLE_ROOT)/tools/gcc-linaro-7.5.0 + +TARGETS := $(APP) +APP_JAVA := $(foreach APP, $(TARGETS), $(APP).java) +APP_DEX := $(foreach APP, $(TARGETS), $(APP).dex) +APP_CLASS := $(foreach APP, $(TARGETS), $(APP).class) +APP_JAR := $(foreach APP, $(TARGETS), $(APP).jar) +APP_MPL := $(foreach APP, $(TARGETS), $(APP).mpl) +APP_MPLT:=$(foreach APP, $(TARGETS), $(APP).mplt) +APP_S := $(foreach APP, $(TARGETS), $(APP).VtableImpl.s) +APP_DEF := $(foreach APP, $(TARGETS), $(APP).VtableImpl.macros.def) +APP_O := $(foreach APP, $(TARGETS), $(APP).VtableImpl.o) +APP_SO := $(foreach APP, $(TARGETS), $(APP).so) +APP_QEMU_SO := $(foreach APP, $(TARGETS), $(APP).VtableImpl.qemu.so) +APP_VTABLEIMPL_MPL := $(foreach APP, $(TARGETS), $(APP).VtableImpl.mpl) + +MAPLE_OUT := $(MAPLE_BUILD_OUTPUT) +JAVA2JAR := $(MAPLE_OUT)/bin/java2jar +JBC2MPL_BIN := $(MAPLE_OUT)/bin/jbc2mpl +MAPLE_BIN := $(MAPLE_OUT)/bin/maple +MPLCG_BIN := $(MAPLE_OUT)/bin/mplcg +JAVA2D8 := $(MAPLE_OUT)/bin/java2d8 +HIR2MPL_BIN := $(MAPLE_OUT)/bin/hir2mpl +JAVA2DEX := ${MAPLE_ROOT}/build/java2dex + +D8 := $(MAPLE_ROOT)/build/d8 +ADD_OBJS := $(MAPLE_ROOT)/src/mrt/maplert/src/mrt_module_init.c__ +INIT_CXX_SRC := $(LIB_CORE_PATH)/mrt_module_init.cpp +INIT_CXX_O := $(LIB_CORE_PATH)/mrt_module_init.o + +LDS := $(MAPLE_ROOT)/src/mrt/maplert/linker/maplelld.so.lds +DUPLICATE_DIR := $(MAPLE_ROOT)/src/mrt/codetricks/arch/arm64 + +QEMU_CLANG_CPP := $(TOOL_BIN_PATH)/clang++ + +QEMU_CLANG_FLAGS := -Wall -W -Werror -Wno-unused-command-line-argument -Wl,-z,now -fPIC -fstack-protector-strong \ + -fvisibility=hidden -std=c++14 -march=armv8-a + +QEMU_CLANG_FLAGS += -nostdlibinc \ + --gcc-toolchain=$(GCC_LINARO_PATH) \ + --sysroot=$(GCC_LINARO_PATH)/aarch64-linux-gnu/libc \ + -isystem $(GCC_LINARO_PATH)/aarch64-linux-gnu/include/c++/7.5.0 \ + -isystem $(GCC_LINARO_PATH)/aarch64-linux-gnu/include/c++/7.5.0/aarch64-linux-gnu \ + -isystem $(GCC_LINARO_PATH)/aarch64-linux-gnu/include/c++/7.5.0/backward \ + -isystem $(GCC_LINARO_PATH)/lib/gcc/aarch64-linux-gnu/7.5.0/include \ + -isystem $(GCC_LINARO_PATH)/lib/gcc/aarch64-linux-gnu/7.5.0/include-fixed \ + -isystem $(GCC_LINARO_PATH)/aarch64-linux-gnu/include \ + -isystem $(GCC_LINARO_PATH)/aarch64-linux-gnu/libc/usr/include \ + -target aarch64-linux-gnu + +ifeq ($(OPT),O2) + HIR2MPL_FLAGS := --rc + MPLME_FLAGS := --O2 --quiet + MPL2MPL_FLAGS := --O2 --quiet --regnativefunc --no-nativeopt --maplelinker + MPLCG_FLAGS := --O2 --quiet --no-pie --verbose-asm --gen-c-macro-def --maplelinker --duplicate_asm_list=$(DUPLICATE_DIR)/duplicateFunc.s + MPLCG_SO_FLAGS := --fpic +else ifeq ($(OPT),O0) + HIR2MPL_FLAGS := --rc + MPLME_FLAGS := --quiet + MPL2MPL_FLAGS := --quiet --regnativefunc --maplelinker + MPLCG_FLAGS := --quiet --no-pie --verbose-asm --gen-c-macro-def --maplelinker --duplicate_asm_list=$(DUPLICATE_DIR)/duplicateFunc.s + MPLCG_SO_FLAGS := --fpic +else ifeq ($(OPT),GC_O2) + HIR2MPL_FLAGS := + MPLME_FLAGS := --O2 --quiet --gconly + MPL2MPL_FLAGS := --O2 --quiet --regnativefunc --no-nativeopt --maplelinker + MPLCG_FLAGS := --O2 --quiet --no-pie --verbose-asm --gen-c-macro-def --maplelinker --duplicate_asm_list=$(DUPLICATE_DIR)/duplicateFunc.s --gconly + MPLCG_SO_FLAGS := --fpic +else ifeq ($(OPT),GC_O0) + HIR2MPL_FLAGS := + MPLME_FLAGS := --quiet --gconly + MPL2MPL_FLAGS := --quiet --regnativefunc --maplelinker + MPLCG_FLAGS := --quiet --no-pie --verbose-asm --gen-c-macro-def --maplelinker --duplicate_asm_list=$(DUPLICATE_DIR)/duplicateFunc.s --gconly + MPLCG_SO_FLAGS := --fpic +endif +HIR2MPL_APP_FLAGS := -mplt=${LIB_CORE_PATH}/libcore-all.mplt +MPLCOMBO_FLAGS := --run=me:mpl2mpl:mplcg --option="$(MPLME_FLAGS):$(MPL2MPL_FLAGS):$(MPLCG_FLAGS) $(MPLCG_SO_FLAGS)" +JAVA2DEX_FLAGS := -p ${OUT_ROOT}/${MAPLE_BUILD_TYPE}/ops/third_party/JAVA_LIBRARIES/core-oj_intermediates/classes.jar:${OUT_ROOT}/${MAPLE_BUILD_TYPE}/ops/third_party/JAVA_LIBRARIES/core-libart_intermediates/classes.jar diff --git a/build/core/mplcomb.mk b/build/core/mplcomb.mk new file mode 100644 index 0000000000000000000000000000000000000000..b0891618fb791f176635ee966b65b1155f5ebab6 --- /dev/null +++ b/build/core/mplcomb.mk @@ -0,0 +1,16 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +$(APP_S): %.VtableImpl.s : %.jar $(MAPLE_BIN) $(JBC2MPL_BIN) $(LIB_CORE_MPLT) + $(MAPLE_BIN) -$(OPT) --mplt $(LIB_CORE_MPLT) $< diff --git a/build/core/mplcomb_dex.mk b/build/core/mplcomb_dex.mk new file mode 100644 index 0000000000000000000000000000000000000000..94f477d038f4ca162e059afe5bbea7691989b042 --- /dev/null +++ b/build/core/mplcomb_dex.mk @@ -0,0 +1,16 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +$(APP_S): %.VtableImpl.s : %.mpl $(MAPLE_BIN) $(DUPLICATE_DIR)/duplicateFunc.s + $(MAPLE_BIN) --infile $< $(MPLCOMBO_FLAGS) --save-temps > comb.log 2>&1 diff --git a/build/core/qemu_ar.mk b/build/core/qemu_ar.mk new file mode 100644 index 0000000000000000000000000000000000000000..323357f226cc43f9229b53205b5a4cfbc583892e --- /dev/null +++ b/build/core/qemu_ar.mk @@ -0,0 +1,29 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +LIB_AR_PATH=$(MAPLE_OUT)/ar/host-x86_64-$(OPT) +LIB_RUNTIME=$(LIB_AR_PATH)/libmplcompiler-rt.a +LIB_ZTERP=$(LIB_AR_PATH)/libzterp.a +LIB_MRT=$(LIB_AR_PATH)/libmaplert.a +LIB_HUAWEISECUREC=$(LIB_AR_PATH)/libhuawei_secure_c.a +LIB_CORENATIVE=$(LIB_AR_PATH)/libcore-static-binding-jni.a +LIBDEXINTERFACE=$(LIB_AR_PATH)/libdexinterface.a +LIBCORE_SO_QEMU := $(MAPLE_OUT)/lib/$(OPT)/libcore-all.so +ifneq ($(findstring GC,$(OPT)),) + LIB_CORENATIVE_QEMU=$(MAPLE_ROOT)/src/mrt/deplibs/libcore-static-binding-jni-qemu.a +else + LIB_CORENATIVE_QEMU=$(MAPLE_ROOT)/src/mrt/deplibs/gc/libcore-static-binding-jni-qemu.a +endif + +qemu := $(LIB_RUNTIME) $(LIB_MRT) $(LIB_HUAWEISECUREC) $(LIB_CORENATIVE_QEMU) $(LIB_CORENATIVE) $(LIB_ZTERP) $(LIBDEXINTERFACE) diff --git a/build/core/qemu_run.mk b/build/core/qemu_run.mk new file mode 100644 index 0000000000000000000000000000000000000000..3572fea91d5ac8eeb3f6f27773b42f2fb49c0271 --- /dev/null +++ b/build/core/qemu_run.mk @@ -0,0 +1,2 @@ +APP_RUN: $(APP_SO) + ${TOOL_BIN_PATH}/qemu-aarch64 -L /usr/aarch64-linux-gnu -E LD_LIBRARY_PATH=${OUT_ROOT}/${MAPLE_BUILD_TYPE}/ops/third_party:${OUT_ROOT}/${MAPLE_BUILD_TYPE}/ops/host-x86_64-O2:./ ${OUT_ROOT}/${MAPLE_BUILD_TYPE}/ops/mplsh -Xbootclasspath:libcore-all.so -cp $(APP_SO) $(APP) diff --git a/build/d8 b/build/d8 new file mode 100755 index 0000000000000000000000000000000000000000..a3c0c08c419accdd314a53b80d6b59a2d6486fc0 --- /dev/null +++ b/build/d8 @@ -0,0 +1,24 @@ +#!/bin/bash +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under the Mulan PSL v1. +# You can use this software according to the terms and conditions of the Mulan PSL v1. +# You may obtain a copy of Mulan PSL v1 at: +# +# http://license.coscl.org.cn/MulanPSL +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v1 for more details. +# +jarfile=d8.jar +libdir=${MAPLE_ROOT}/third_party/d8/lib +jarpath="$libdir/$jarfile" + +# a max heap size of dx, can be overwrite +defaultHeapMax="-Xmx1024M" +javaOpts="${javaOpts} ${defaultHeapMax}" + +java $javaOpts -jar "$jarpath" "$@" diff --git a/build/envsetup.sh b/build/envsetup.sh new file mode 100644 index 0000000000000000000000000000000000000000..70e5e2f32172b23a4ca3aada4fc4a9a9ddebf204 --- /dev/null +++ b/build/envsetup.sh @@ -0,0 +1,213 @@ +#!/bin/bash +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +function print_usage { + echo " " + echo "usage: source envsetup.sh arm/ark/engine/riscv release/debug" + echo " " +} + +if [ "$#" -lt 2 ]; then + print_usage +# return +fi + +curdir=$(pwd) +export MAPLE_ROOT=${curdir} +export SPEC=${MAPLE_ROOT}/testsuite/c_test/spec_test +export LD_LIBRARY_PATH=${MAPLE_ROOT}/tools/gcc-linaro-7.5.0/aarch64-linux-gnu/libc/lib:${MAPLE_ROOT}/tools/clang+llvm-12.0.0-x86_64-linux-gnu-ubuntu-18.04/lib:${LD_LIBRARY_PATH} +export SPECPERLLIB=${SPEC}/bin/lib:${SPEC}/bin:${SPEC}/SPEC500-perlbench_r/data/all/input/lib:${SPEC}/SPEC500-perlbench_r/t/lib +export CASE_ROOT=${curdir}/testsuite +export OUT_ROOT=${curdir}/output +export ANDROID_ROOT=${curdir}/android +export MAPLE_BUILD_CORE=${MAPLE_ROOT}/build/core +if [ -d ${MAPLE_ROOT}/src/ast2mpl ]; then + export IS_AST2MPL_EXISTS=1 +else + export IS_AST2MPL_EXISTS=0 +fi +export GCOV_PREFIX=${MAPLE_ROOT}/report/gcda +export GCOV_PREFIX_STRIP=7 + +# display OS version +lsb_release -d + +export TOOL_BIN_PATH=${MAPLE_ROOT}/tools/bin +if [ -d ${MAPLE_ROOT}/testsuite/driver/.config ];then + rm -rf ${MAPLE_ROOT}/testsuite/driver/config + rm -rf ${MAPLE_ROOT}/testsuite/driver/src/api + rm -rf ${MAPLE_ROOT}/testsuite/driver/src/mode + cd ${MAPLE_ROOT}/testsuite/driver + ln -s -f .config config + cd ${MAPLE_ROOT}/testsuite/driver/src + ln -s -f .api api + ln -s -f .mode mode +fi + +cd ${MAPLE_ROOT} + +OS_VERSION=`lsb_release -r | sed -e "s/^[^0-9]*//" -e "s/\..*//"` +if [ "$OS_VERSION" = "16" ] || [ "$OS_VERSION" = "18" ]; then + export OLD_OS=1 +else + export OLD_OS=0 +fi + +# support multiple ARCH and BUILD_TYPE + +if [ $1 = "arm" ]; then + PLATFORM=aarch64 + USEOJ=0 +elif [ $1 = "riscv" ]; then + PLATFORM=riscv64 + USEOJ=0 +elif [ $1 = "engine" ]; then + PLATFORM=ark + USEOJ=1 +elif [ $1 = "ark" ]; then + PLATFORM=ark + USEOJ=1 +else + print_usage + return +fi + +if [ "$2" = "release" ]; then + TYPE=release + DEBUG=0 +elif [ "$2" = "debug" ]; then + TYPE=debug + DEBUG=1 +else + print_usage + return +fi + +export MAPLE_DEBUG=${DEBUG} +export TARGET_PROCESSOR=${PLATFORM} +export TARGET_SCOPE=${TYPE} +export USE_OJ_LIBCORE=${USEOJ} +export TARGET_TOOLCHAIN=clang +export MAPLE_BUILD_TYPE=${TARGET_PROCESSOR}-${TARGET_TOOLCHAIN}-${TARGET_SCOPE} +echo "Build: $MAPLE_BUILD_TYPE" +export MAPLE_BUILD_OUTPUT=${MAPLE_ROOT}/output/${MAPLE_BUILD_TYPE} +export MAPLE_EXECUTE_BIN=${MAPLE_ROOT}/output/${MAPLE_BUILD_TYPE}/bin +export TEST_BIN=${CASE_ROOT}/driver/script +export PATH=$PATH:${MAPLE_EXECUTE_BIN}:${TEST_BIN} + +# Enable Autocompletion for maple driver +if [ -f $MAPLE_ROOT/tools/maple_autocompletion.sh ]; then + source ${MAPLE_ROOT}/tools/maple_autocompletion.sh +fi + +if [ ! -f $MAPLE_ROOT/tools/qemu/usr/bin/qemu-aarch64 ] && [ "$OLD_OS" = "0" ]; then + echo " " + echo "!!! please run \"make setup\" to get proper qemu-aarch64" + echo " " +fi + +function mm +{ + THREADS=$(cat /proc/cpuinfo| grep "processor"| wc -l) + PWD=$(pwd) + num=${#CASE_ROOT} + let num++ + ALL_MODE_LIST=$(cd ${CASE_ROOT}/driver/src/mode; find -name "*.py" | xargs basename -s .py;) + TARGET=${PWD:${num}} + MODE= + + #mm MODE=O0 + if [ $# -lt 3 ] && [[ "x${1^^}" =~ ^xMODE=.* ]]; then + MODE=${1#*=} + MODE=${MODE^^} + python3 ${CASE_ROOT}/driver/src/driver.py --target=${TARGET} --mode=${MODE} --detail + elif [ $# -lt 3 ] && [[ `echo ${ALL_MODE_LIST[@]} | grep -w ${1^^}` ]] ; then + MODE=${1^^} + python3 ${CASE_ROOT}/driver/src/driver.py --target=${TARGET} --mode=${MODE} --detail + + #mm clean + elif [ $# -lt 3 ] && [ "x${1}" = "xclean" ]; then + python3 ${CASE_ROOT}/driver/src/driver.py --target=${TARGET} --clean --detail + + #mm save + elif [ $# = 1 ] && [ "x${1}" = "xsave" ]; then + python3 ${CASE_ROOT}/driver/src/driver.py --target=${TARGET} --save + + #mm testall + elif [ $# = 1 ] && [ -f ${CASE_ROOT}/driver/config/${1}.conf ]; then + TARGET=${1} + python3 ${CASE_ROOT}/driver/src/driver.py --target=${TARGET} --run-path=${OUT_ROOT}/host/test --j=${THREADS} + + #mm testall MODE=O0 + elif [ $# = 2 ] && [ -f ${CASE_ROOT}/driver/config/${1}.conf ]; then + if [[ "x${2^^}" =~ ^xMODE=.* ]]; then + MODE=${2#*=} + MODE=${MODE^^} + elif [[ `echo ${ALL_MODE_LIST[@]} | grep -w ${2^^}` ]] ; then + MODE=${2^^} + fi + TARGET=${1} + python3 ${CASE_ROOT}/driver/src/driver.py --target=${TARGET} --run-path=${OUT_ROOT}/host/test --mode=${MODE} --j=${THREADS} + + #mm app_test + elif [ $# = 1 ] && [ -d ${CASE_ROOT}/${1} ] + then + TARGET=${1} + python3 ${CASE_ROOT}/driver/src/driver.py --target=${TARGET} --run-path=${OUT_ROOT}/host/test --j=${THREADS} + + #mm app_test MODE=O2 + elif [ $# = 2 ] && [ -d ${CASE_ROOT}/${1} ]; then + if [[ "x${2^^}" =~ ^xMODE=.* ]]; then + MODE=${2#*=} + MODE=${MODE^^} + elif [[ `echo ${ALL_MODE_LIST[@]} | grep -w ${2^^}` ]] ; then + MODE=${2^^} + fi + TARGET=${1} + python3 ${CASE_ROOT}/driver/src/driver.py --target=${TARGET} --run-path=${OUT_ROOT}/host/test --mode=${MODE} --j=${THREADS} + + elif [ $# = 1 ] && [ "x${1,,}" = "x-h" -o "x${1,,}" = "x--help" ]; + then + cat < + + namespace art { + +@@ -115,11 +116,23 @@ + static_assert(IsAligned(kX86StackOverflowReservedBytes), "X86 gap not page aligned"); + static_assert(IsAligned(kX86_64StackOverflowReservedBytes), + "X86_64 gap not page aligned"); +- ++/* ++cflags += [ ++ "-DART_STACK_OVERFLOW_GAP_arm=8192", ++ "-DART_STACK_OVERFLOW_GAP_arm64=8192", ++ "-DART_STACK_OVERFLOW_GAP_mips=16384", ++ "-DART_STACK_OVERFLOW_GAP_mips64=16384", ++ "-DART_STACK_OVERFLOW_GAP_x86=16384", ++ "-DART_STACK_OVERFLOW_GAP_x86_64=20480", ++ "-DART_FRAME_SIZE_LIMIT=7400", ++ ] ++ */ ++/* + #if !defined(ART_FRAME_SIZE_LIMIT) + #error "ART frame size limit missing" + #endif +- ++*/ ++const uint32_t ART_FRAME_SIZE_LIMIT = 7400; + // TODO: Should we require an extra page (RoundUp(SIZE) + kPageSize)? + static_assert(ART_FRAME_SIZE_LIMIT < kArmStackOverflowReservedBytes, "Frame size limit too large"); + static_assert(ART_FRAME_SIZE_LIMIT < kArm64StackOverflowReservedBytes, +diff -ur art_aosp/libartbase/arch/instruction_set.h art/libartbase/arch/instruction_set.h +--- art_aosp/libartbase/arch/instruction_set.h 2021-01-29 11:00:02.202266487 +0800 ++++ art/libartbase/arch/instruction_set.h 2021-01-29 10:34:50.012986865 +0800 +@@ -227,19 +227,30 @@ + } + + namespace instruction_set_details { +- ++/* ++cflags += [ ++ "-DART_STACK_OVERFLOW_GAP_arm=8192", ++ "-DART_STACK_OVERFLOW_GAP_arm64=8192", ++ "-DART_STACK_OVERFLOW_GAP_mips=16384", ++ "-DART_STACK_OVERFLOW_GAP_mips64=16384", ++ "-DART_STACK_OVERFLOW_GAP_x86=16384", ++ "-DART_STACK_OVERFLOW_GAP_x86_64=20480", ++ "-DART_FRAME_SIZE_LIMIT=7400", ++ ] ++ */ ++ /* + #if !defined(ART_STACK_OVERFLOW_GAP_arm) || !defined(ART_STACK_OVERFLOW_GAP_arm64) || \ + !defined(ART_STACK_OVERFLOW_GAP_mips) || !defined(ART_STACK_OVERFLOW_GAP_mips64) || \ + !defined(ART_STACK_OVERFLOW_GAP_x86) || !defined(ART_STACK_OVERFLOW_GAP_x86_64) + #error "Missing defines for stack overflow gap" + #endif +- +-static constexpr size_t kArmStackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_arm; +-static constexpr size_t kArm64StackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_arm64; +-static constexpr size_t kMipsStackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_mips; +-static constexpr size_t kMips64StackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_mips64; +-static constexpr size_t kX86StackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_x86; +-static constexpr size_t kX86_64StackOverflowReservedBytes = ART_STACK_OVERFLOW_GAP_x86_64; ++*/ ++static constexpr size_t kArmStackOverflowReservedBytes = 8192; ++static constexpr size_t kArm64StackOverflowReservedBytes = 8192; ++static constexpr size_t kMipsStackOverflowReservedBytes = 16384; ++static constexpr size_t kMips64StackOverflowReservedBytes = 16384; ++static constexpr size_t kX86StackOverflowReservedBytes = 16384; ++static constexpr size_t kX86_64StackOverflowReservedBytes = 20480; + + NO_RETURN void GetStackOverflowReservedBytesFailure(const char* error_msg); + +diff -ur art_aosp/libartbase/base/arena_allocator.h art/libartbase/base/arena_allocator.h +--- art_aosp/libartbase/base/arena_allocator.h 2021-01-29 11:00:02.198266452 +0800 ++++ art/libartbase/base/arena_allocator.h 2021-01-29 10:34:50.012986865 +0800 +@@ -25,6 +25,7 @@ + #include "dchecked_vector.h" + #include "macros.h" + #include "memory_tool.h" ++#include + + namespace art { + +diff -ur art_aosp/libartbase/base/bit_vector.h art/libartbase/base/bit_vector.h +--- art_aosp/libartbase/base/bit_vector.h 2021-01-29 11:00:02.202266487 +0800 ++++ art/libartbase/base/bit_vector.h 2021-01-29 10:34:50.012986865 +0800 +@@ -19,7 +19,7 @@ + + #include + #include +- ++#include + #include "bit_utils.h" + #include "globals.h" + +diff -ur art_aosp/libartbase/base/file_magic.cc art/libartbase/base/file_magic.cc +--- art_aosp/libartbase/base/file_magic.cc 2021-01-29 11:00:02.198266452 +0800 ++++ art/libartbase/base/file_magic.cc 2021-01-29 10:34:50.012986865 +0800 +@@ -19,7 +19,7 @@ + #include + #include + #include +- ++#include + #include + #include + +diff -ur art_aosp/libartbase/base/file_utils.cc art/libartbase/base/file_utils.cc +--- art_aosp/libartbase/base/file_utils.cc 2021-01-29 11:00:02.198266452 +0800 ++++ art/libartbase/base/file_utils.cc 2021-01-29 10:34:50.012986865 +0800 +@@ -40,7 +40,7 @@ + + + #include +- ++#include + #include "android-base/stringprintf.h" + #include "android-base/strings.h" + +@@ -401,7 +401,7 @@ + &error_msg); + return (android_root != nullptr) + && (runtime_root != nullptr) +- && (std::string_view(android_root) != std::string_view(runtime_root)); ++ && (StringView(android_root) != StringView(runtime_root)); + } + + int DupCloexec(int fd) { +diff -ur art_aosp/libartbase/base/hiddenapi_stubs.h art/libartbase/base/hiddenapi_stubs.h +--- art_aosp/libartbase/base/hiddenapi_stubs.h 2021-01-29 11:00:02.198266452 +0800 ++++ art/libartbase/base/hiddenapi_stubs.h 2021-01-29 10:34:50.012986865 +0800 +@@ -18,11 +18,16 @@ + #define ART_LIBARTBASE_BASE_HIDDENAPI_STUBS_H_ + + #include +-#include ++#include "string_view_format.h" + + namespace art { + namespace hiddenapi { + ++const std::string kPublicApiStr = "public-api"; ++const std::string kSystemApiStr = "system-api"; ++const std::string kTestApiStr = "test-api"; ++const std::string kCorePlatformApiStr = "core-platform-api"; ++ + class ApiStubs { + public: + enum class Kind { +@@ -32,7 +37,7 @@ + kCorePlatformApi, + }; + +- static const std::string_view ToString(Kind api) { ++ static std::string ToString(Kind api) { + switch (api) { + case Kind::kPublicApi: + return kPublicApiStr; +@@ -45,16 +50,10 @@ + } + } + +- static bool IsStubsFlag(const std::string_view& api_flag_name) { ++ static bool IsStubsFlag(const std::string& api_flag_name) { + return api_flag_name == kPublicApiStr || api_flag_name == kSystemApiStr || + api_flag_name == kTestApiStr || api_flag_name == kCorePlatformApiStr; + } +- +- private: +- static constexpr std::string_view kPublicApiStr{"public-api"}; +- static constexpr std::string_view kSystemApiStr{"system-api"}; +- static constexpr std::string_view kTestApiStr{"test-api"}; +- static constexpr std::string_view kCorePlatformApiStr{"core-platform-api"}; + }; + + } // namespace hiddenapi +diff -ur art_aosp/libartbase/base/logging.cc art/libartbase/base/logging.cc +--- art_aosp/libartbase/base/logging.cc 2021-01-29 11:00:02.202266487 +0800 ++++ art/libartbase/base/logging.cc 2021-01-29 10:34:50.012986865 +0800 +@@ -23,6 +23,7 @@ + #include "aborting.h" + #include "os.h" + #include "unix_file/fd_file.h" ++#include + + // Headers for LogMessage::LogLine. + #ifdef ART_TARGET_ANDROID +diff -ur art_aosp/libartbase/base/memfd.cc art/libartbase/base/memfd.cc +--- art_aosp/libartbase/base/memfd.cc 2021-01-29 11:00:02.198266452 +0800 ++++ art/libartbase/base/memfd.cc 2021-01-29 10:34:50.016986900 +0800 +@@ -25,6 +25,7 @@ + #endif + + #include "macros.h" ++#include + + // When building for linux host, glibc in prebuilts does not include memfd_create system call + // number. As a temporary testing measure, we add the definition here. +diff -ur art_aosp/libartbase/base/os_linux.cc art/libartbase/base/os_linux.cc +--- art_aosp/libartbase/base/os_linux.cc 2021-01-29 11:00:02.202266487 +0800 ++++ art/libartbase/base/os_linux.cc 2021-01-29 10:34:50.016986900 +0800 +@@ -62,8 +62,7 @@ + CHECK(name != nullptr); + bool read_only = ((flags & O_ACCMODE) == O_RDONLY); + bool check_usage = !read_only && auto_flush; +- std::unique_ptr file( +- new File(name, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, check_usage)); ++ std::unique_ptr file(new File(name, flags, 0666, check_usage)); + if (!file->IsOpened()) { + return nullptr; + } +diff -ur art_aosp/libartbase/base/safe_copy.cc art/libartbase/base/safe_copy.cc +--- art_aosp/libartbase/base/safe_copy.cc 2021-01-29 11:00:02.202266487 +0800 ++++ art/libartbase/base/safe_copy.cc 2021-01-29 10:34:50.016986900 +0800 +@@ -56,10 +56,10 @@ + } + + src_iovs[iovecs_used].iov_base = const_cast(cur); +- if (!IsAlignedParam(cur, PAGE_SIZE)) { +- src_iovs[iovecs_used].iov_len = AlignUp(cur, PAGE_SIZE) - cur; ++ if (!IsAlignedParam(cur, sysconf(_SC_PAGE_SIZE))) { ++ src_iovs[iovecs_used].iov_len = AlignUp(cur, sysconf(_SC_PAGE_SIZE)) - cur; + } else { +- src_iovs[iovecs_used].iov_len = PAGE_SIZE; ++ src_iovs[iovecs_used].iov_len = sysconf(_SC_PAGE_SIZE); + } + + src_iovs[iovecs_used].iov_len = std::min(src_iovs[iovecs_used].iov_len, len); +diff -ur art_aosp/libartbase/base/scoped_flock.cc art/libartbase/base/scoped_flock.cc +--- art_aosp/libartbase/base/scoped_flock.cc 2021-01-29 11:00:02.202266487 +0800 ++++ art/libartbase/base/scoped_flock.cc 2021-01-29 10:34:50.016986900 +0800 +@@ -24,6 +24,7 @@ + + #include "file_utils.h" + #include "unix_file/fd_file.h" ++#include + + namespace art { + +diff -ur art_aosp/libartbase/base/string_view_cpp20.h art/libartbase/base/string_view_cpp20.h +--- art_aosp/libartbase/base/string_view_cpp20.h 2021-01-29 11:00:02.198266452 +0800 ++++ art/libartbase/base/string_view_cpp20.h 2021-01-29 10:34:50.016986900 +0800 +@@ -17,21 +17,21 @@ + #ifndef ART_LIBARTBASE_BASE_STRING_VIEW_CPP20_H_ + #define ART_LIBARTBASE_BASE_STRING_VIEW_CPP20_H_ + +-#include ++#include "string_view_format.h" + + namespace art { + +-// Replacement functions for std::string_view::starts_with(), ends_with() ++// Replacement functions for StringView::starts_with(), ends_with() + // which shall be available in C++20. + #if __cplusplus >= 202000L + #error "When upgrading to C++20, remove this error and file a bug to remove this workaround." + #endif + +-inline bool StartsWith(std::string_view sv, std::string_view prefix) { ++inline bool StartsWith(StringView sv, StringView prefix) { + return sv.substr(0u, prefix.size()) == prefix; + } + +-inline bool EndsWith(std::string_view sv, std::string_view suffix) { ++inline bool EndsWith(StringView sv, StringView suffix) { + return sv.size() >= suffix.size() && sv.substr(sv.size() - suffix.size()) == suffix; + } + +diff -ur art_aosp/libartbase/base/unix_file/fd_file.cc art/libartbase/base/unix_file/fd_file.cc +--- art_aosp/libartbase/base/unix_file/fd_file.cc 2021-01-29 11:00:02.202266487 +0800 ++++ art/libartbase/base/unix_file/fd_file.cc 2021-01-29 10:34:50.016986900 +0800 +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #if defined(__BIONIC__) + #include +diff -ur art_aosp/libartbase/base/utils.cc art/libartbase/base/utils.cc +--- art_aosp/libartbase/base/utils.cc 2021-01-29 11:00:02.202266487 +0800 ++++ art/libartbase/base/utils.cc 2021-01-29 10:34:50.016986900 +0800 +@@ -29,7 +29,6 @@ + #include "android-base/stringprintf.h" + #include "android-base/strings.h" + +-#include "bit_utils.h" + #include "os.h" + + #if defined(__APPLE__) +@@ -63,98 +62,6 @@ + using android::base::ReadFileToString; + using android::base::StringPrintf; + +-#if defined(__arm__) +- +-namespace { +- +-// Bitmap of caches to flush for cacheflush(2). Must be zero for ARM. +-static constexpr int kCacheFlushFlags = 0x0; +- +-// Number of retry attempts when flushing cache ranges. +-static constexpr size_t kMaxFlushAttempts = 4; +- +-int CacheFlush(uintptr_t start, uintptr_t limit) { +- // The signature of cacheflush(2) seems to vary by source. On ARM the system call wrapper +- // (bionic/SYSCALLS.TXT) has the form: int cacheflush(long start, long end, long flags); +- int r = cacheflush(start, limit, kCacheFlushFlags); +- if (r == -1) { +- CHECK_NE(errno, EINVAL); +- } +- return r; +-} +- +-bool TouchAndFlushCacheLinesWithinPage(uintptr_t start, uintptr_t limit, size_t attempts) { +- CHECK_LT(start, limit); +- CHECK_EQ(RoundDown(start, kPageSize), RoundDown(limit - 1, kPageSize)) << "range spans pages"; +- // Declare a volatile variable so the compiler does not elide reads from the page being touched. +- volatile uint8_t v = 0; +- for (size_t i = 0; i < attempts; ++i) { +- // Touch page to maximize chance page is resident. +- v = *reinterpret_cast(start); +- +- if (LIKELY(CacheFlush(start, limit) == 0)) { +- return true; +- } +- } +- return false; +-} +- +-} // namespace +- +-bool FlushCpuCaches(void* begin, void* end) { +- // This method is specialized for ARM as the generic implementation below uses the +- // __builtin___clear_cache() intrinsic which is declared as void. On ARMv7 flushing the CPU +- // caches is a privileged operation. The Linux kernel allows these operations to fail when they +- // trigger a fault (e.g. page not resident). We use a wrapper for the ARM specific cacheflush() +- // system call to detect the failure and potential erroneous state of the data and instruction +- // caches. +- // +- // The Android bug for this is b/132205399 and there's a similar discussion on +- // https://reviews.llvm.org/D37788. This is primarily an issue for the dual view JIT where the +- // pages where code is executed are only ever RX and never RWX. When attempting to invalidate +- // instruction cache lines in the RX mapping after writing fresh code in the RW mapping, the +- // page may not be resident (due to memory pressure), and this means that a fault is raised in +- // the midst of a cacheflush() call and the instruction cache lines are not invalidated and so +- // have stale code. +- // +- // Other architectures fair better for reasons such as: +- // +- // (1) stronger coherence between the data and instruction caches. +- // +- // (2) fault handling that allows flushing/invalidation to continue after +- // a missing page has been faulted in. +- +- // In the common case, this flush of the complete range succeeds. +- uintptr_t start = reinterpret_cast(begin); +- const uintptr_t limit = reinterpret_cast(end); +- if (LIKELY(CacheFlush(start, limit) == 0)) { +- return true; +- } +- +- // A rare failure has occurred implying that part of the range (begin, end] has been swapped +- // out. Retry flushing but this time grouping cache-line flushes on individual pages and +- // touching each page before flushing. +- uintptr_t next_page = RoundUp(start + 1, kPageSize); +- while (start < limit) { +- uintptr_t boundary = std::min(next_page, limit); +- if (!TouchAndFlushCacheLinesWithinPage(start, boundary, kMaxFlushAttempts)) { +- return false; +- } +- start = boundary; +- next_page += kPageSize; +- } +- return true; +-} +- +-#else +- +-bool FlushCpuCaches(void* begin, void* end) { +- __builtin___clear_cache(reinterpret_cast(begin), reinterpret_cast(end)); +- return true; +-} +- +-#endif +- + pid_t GetTid() { + #if defined(__APPLE__) + uint64_t owner; +diff -ur art_aosp/libartbase/base/utils.h art/libartbase/base/utils.h +--- art_aosp/libartbase/base/utils.h 2021-01-29 11:00:02.198266452 +0800 ++++ art/libartbase/base/utils.h 2021-01-29 10:34:50.016986900 +0800 +@@ -113,8 +113,15 @@ + // Sleep forever and never come back. + NO_RETURN void SleepForever(); + +-// Flush CPU caches. Returns true on success, false if flush failed. +-WARN_UNUSED bool FlushCpuCaches(void* begin, void* end); ++inline void FlushDataCache(void* begin, void* end) { ++ __builtin___clear_cache(reinterpret_cast(begin), reinterpret_cast(end)); ++} ++ ++inline void FlushInstructionCache(void* begin, void* end) { ++ // Same as FlushInstructionCache for lack of other builtin. __builtin___clear_cache ++ // flushes both caches. ++ __builtin___clear_cache(reinterpret_cast(begin), reinterpret_cast(end)); ++} + + template + constexpr PointerSize ConvertToPointerSize(T any) { +diff -ur art_aosp/libartpalette/system/palette_fake.cc art/libartpalette/system/palette_fake.cc +--- art_aosp/libartpalette/system/palette_fake.cc 2021-01-29 11:01:59.615297526 +0800 ++++ art/libartpalette/system/palette_fake.cc 2021-01-29 10:34:50.016986900 +0800 +@@ -21,7 +21,7 @@ + + #include + #include // For ATTRIBUTE_UNUSED +- ++#include "string_view_format.h" + #include "palette_system.h" + + enum PaletteStatus PaletteGetVersion(int32_t* version) { +@@ -54,7 +54,7 @@ + } + + enum PaletteStatus PaletteWriteCrashThreadStacks(/*in*/ const char* stacks, size_t stacks_len) { +- LOG(INFO) << std::string_view(stacks, stacks_len); ++ LOG(INFO) << StringView(stacks, stacks_len); + return PaletteStatus::kOkay; + } + +diff -ur art_aosp/libdexfile/dex/compact_dex_file.cc art/libdexfile/dex/compact_dex_file.cc +--- art_aosp/libdexfile/dex/compact_dex_file.cc 2021-01-29 11:02:31.435577410 +0800 ++++ art/libdexfile/dex/compact_dex_file.cc 2021-01-29 10:34:50.016986900 +0800 +@@ -19,6 +19,8 @@ + #include "base/leb128.h" + #include "code_item_accessors-inl.h" + #include "dex_file-inl.h" ++#include ++#include + + namespace art { + +diff -ur art_aosp/libdexfile/dex/compact_offset_table.h art/libdexfile/dex/compact_offset_table.h +--- art_aosp/libdexfile/dex/compact_offset_table.h 2021-01-29 11:02:32.119583426 +0800 ++++ art/libdexfile/dex/compact_offset_table.h 2021-01-29 10:34:50.016986900 +0800 +@@ -28,7 +28,7 @@ + public: + // This value is coupled with the leb chunk bitmask. That logic must also be adjusted when the + // integer is modified. +- static constexpr size_t kElementsPerIndex = 16; ++ static constexpr std::size_t kElementsPerIndex = 16; + + // Leb block format: + // [uint16_t] 16 bit mask for what indexes actually have a non zero offset for the chunk. +@@ -61,7 +61,7 @@ + uint32_t* out_table_offset); + + // 32 bit aligned for the offset table. +- static constexpr size_t kAlignment = sizeof(uint32_t); ++ static constexpr std::size_t kAlignment = sizeof(uint32_t); + }; + + } // namespace art +diff -ur art_aosp/libdexfile/dex/descriptors_names.cc art/libdexfile/dex/descriptors_names.cc +--- art_aosp/libdexfile/dex/descriptors_names.cc 2021-01-29 11:02:30.463568859 +0800 ++++ art/libdexfile/dex/descriptors_names.cc 2021-01-29 10:34:50.016986900 +0800 +@@ -21,6 +21,8 @@ + + #include "base/macros.h" + #include "dex/utf-inl.h" ++#include ++#include + + namespace art { + +diff -ur art_aosp/libdexfile/dex/dex_file.cc art/libdexfile/dex/dex_file.cc +--- art_aosp/libdexfile/dex/dex_file.cc 2021-01-29 11:02:29.831563300 +0800 ++++ art/libdexfile/dex/dex_file.cc 2021-01-29 10:34:50.016986900 +0800 +@@ -400,7 +400,7 @@ + } + + // Given a signature place the type ids into the given vector +-bool DexFile::CreateTypeList(std::string_view signature, ++bool DexFile::CreateTypeList(StringView signature, + dex::TypeIndex* return_type_idx, + std::vector* param_type_idxs) const { + if (signature[0] != '(') { +diff -ur art_aosp/libdexfile/dex/dex_file.h art/libdexfile/dex/dex_file.h +--- art_aosp/libdexfile/dex/dex_file.h 2021-01-29 11:02:29.947564321 +0800 ++++ art/libdexfile/dex/dex_file.h 2021-01-29 10:34:50.016986900 +0800 +@@ -19,7 +19,7 @@ + + #include + #include +-#include ++#include "string_view_format.h" + #include + + #include +@@ -262,7 +262,7 @@ + const char* StringDataAndUtf16LengthByIdx(dex::StringIndex idx, uint32_t* utf16_length) const; + + const char* StringDataByIdx(dex::StringIndex idx) const; +- std::string_view StringViewByIdx(dex::StringIndex idx) const; ++ StringView StringViewByIdx(dex::StringIndex idx) const; + + // Looks up a string id for a given modified utf8 string. + const dex::StringId* FindStringId(const char* string) const; +@@ -480,7 +480,7 @@ + } + + // Given a signature place the type ids into the given vector, returns true on success +- bool CreateTypeList(std::string_view signature, ++ bool CreateTypeList(StringView signature, + dex::TypeIndex* return_type_idx, + std::vector* param_type_idxs) const; + +diff -ur art_aosp/libdexfile/dex/dex_file-inl.h art/libdexfile/dex/dex_file-inl.h +--- art_aosp/libdexfile/dex/dex_file-inl.h 2021-01-29 11:02:30.975573364 +0800 ++++ art/libdexfile/dex/dex_file-inl.h 2021-01-29 10:34:50.016986900 +0800 +@@ -28,14 +28,15 @@ + #include "dex_instruction_iterator.h" + #include "invoke_type.h" + #include "standard_dex_file.h" ++#include "string_view_format.h" + + namespace art { + +-inline std::string_view StringViewFromUtf16Length(const char* utf8_data, size_t utf16_length) { ++inline StringView StringViewFromUtf16Length(const char* utf8_data, size_t utf16_length) { + size_t utf8_length = LIKELY(utf8_data[utf16_length] == 0) // Is ASCII? + ? utf16_length + : utf16_length + strlen(utf8_data + utf16_length); +- return std::string_view(utf8_data, utf8_length); ++ return StringView(utf8_data, utf8_length); + } + + inline int32_t DexFile::GetStringLength(const dex::StringId& string_id) const { +@@ -71,10 +72,10 @@ + return StringDataAndUtf16LengthByIdx(idx, &unicode_length); + } + +-inline std::string_view DexFile::StringViewByIdx(dex::StringIndex idx) const { ++inline StringView DexFile::StringViewByIdx(dex::StringIndex idx) const { + uint32_t unicode_length; + const char* data = StringDataAndUtf16LengthByIdx(idx, &unicode_length); +- return data != nullptr ? StringViewFromUtf16Length(data, unicode_length) : std::string_view(""); ++ return data != nullptr ? StringViewFromUtf16Length(data, unicode_length) : StringView(""); + } + + inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const { +diff -ur art_aosp/libdexfile/dex/dex_file_loader.h art/libdexfile/dex/dex_file_loader.h +--- art_aosp/libdexfile/dex/dex_file_loader.h 2021-01-29 11:02:31.547578394 +0800 ++++ art/libdexfile/dex/dex_file_loader.h 2021-01-29 10:34:50.016986900 +0800 +@@ -19,6 +19,7 @@ + + #include + #include ++#include + #include + #include + +diff -ur art_aosp/libdexfile/dex/dex_file_verifier.cc art/libdexfile/dex/dex_file_verifier.cc +--- art_aosp/libdexfile/dex/dex_file_verifier.cc 2021-01-29 11:02:29.603561296 +0800 ++++ art/libdexfile/dex/dex_file_verifier.cc 2021-01-29 10:34:50.016986900 +0800 +@@ -17,7 +17,7 @@ + #include "dex_file_verifier.h" + + #include +- ++#include + #include + + #include "android-base/stringprintf.h" +diff -ur art_aosp/libdexfile/dex/signature.cc art/libdexfile/dex/signature.cc +--- art_aosp/libdexfile/dex/signature.cc 2021-01-29 11:02:32.579587471 +0800 ++++ art/libdexfile/dex/signature.cc 2021-01-29 10:34:50.020986935 +0800 +@@ -57,11 +57,11 @@ + return strcmp(return_type, "V") == 0; + } + +-bool Signature::operator==(std::string_view rhs) const { ++bool Signature::operator==(StringView rhs) const { + if (dex_file_ == nullptr) { + return false; + } +- std::string_view tail(rhs); ++ StringView tail(rhs); + if (!StartsWith(tail, "(")) { + return false; // Invalid signature + } +@@ -69,7 +69,7 @@ + const TypeList* params = dex_file_->GetProtoParameters(*proto_id_); + if (params != nullptr) { + for (uint32_t i = 0; i < params->Size(); ++i) { +- std::string_view param(dex_file_->StringByTypeIdx(params->GetTypeItem(i).type_idx_)); ++ StringView param(dex_file_->StringByTypeIdx(params->GetTypeItem(i).type_idx_)); + if (!StartsWith(tail, param)) { + return false; + } +diff -ur art_aosp/libdexfile/dex/signature.h art/libdexfile/dex/signature.h +--- art_aosp/libdexfile/dex/signature.h 2021-01-29 11:02:30.347567837 +0800 ++++ art/libdexfile/dex/signature.h 2021-01-29 10:34:50.020986935 +0800 +@@ -19,7 +19,7 @@ + + #include + #include +-#include ++#include "string_view_format.h" + + #include + +@@ -49,7 +49,7 @@ + return !(*this == rhs); + } + +- bool operator==(std::string_view rhs) const; ++ bool operator==(StringView rhs) const; + + private: + Signature(const DexFile* dex, const dex::ProtoId& proto) : dex_file_(dex), proto_id_(&proto) { +diff -ur art_aosp/libdexfile/dex/signature-inl.h art/libdexfile/dex/signature-inl.h +--- art_aosp/libdexfile/dex/signature-inl.h 2021-01-29 11:02:32.063582932 +0800 ++++ art/libdexfile/dex/signature-inl.h 2021-01-29 10:34:50.020986935 +0800 +@@ -36,13 +36,13 @@ + uint32_t lhs_shorty_len; // For a shorty utf16 length == mutf8 length. + const char* lhs_shorty_data = dex_file_->StringDataAndUtf16LengthByIdx(proto_id_->shorty_idx_, + &lhs_shorty_len); +- std::string_view lhs_shorty(lhs_shorty_data, lhs_shorty_len); ++ StringView lhs_shorty(lhs_shorty_data, lhs_shorty_len); + { + uint32_t rhs_shorty_len; + const char* rhs_shorty_data = + rhs.dex_file_->StringDataAndUtf16LengthByIdx(rhs.proto_id_->shorty_idx_, + &rhs_shorty_len); +- std::string_view rhs_shorty(rhs_shorty_data, rhs_shorty_len); ++ StringView rhs_shorty(rhs_shorty_data, rhs_shorty_len); + if (lhs_shorty != rhs_shorty) { + return false; // Shorty mismatch. + } +@@ -56,7 +56,7 @@ + return false; // Return type mismatch. + } + } +- if (lhs_shorty.find('L', 1) != std::string_view::npos) { ++ if (lhs_shorty.find('L', 1) != StringView::npos) { + const dex::TypeList* params = dex_file_->GetProtoParameters(*proto_id_); + const dex::TypeList* rhs_params = rhs.dex_file_->GetProtoParameters(*rhs.proto_id_); + // We found a reference parameter in the matching shorty, so both lists must be non-empty. +diff -ur art_aosp/libdexfile/dex/standard_dex_file.cc art/libdexfile/dex/standard_dex_file.cc +--- art_aosp/libdexfile/dex/standard_dex_file.cc 2021-01-29 11:02:31.491577900 +0800 ++++ art/libdexfile/dex/standard_dex_file.cc 2021-01-29 10:34:50.020986935 +0800 +@@ -20,6 +20,8 @@ + #include "base/leb128.h" + #include "code_item_accessors-inl.h" + #include "dex_file-inl.h" ++#include ++#include + + namespace art { + +diff -ur art_aosp/libdexfile/external/include/art_api/dex_file_support.h art/libdexfile/external/include/art_api/dex_file_support.h +--- art_aosp/libdexfile/external/include/art_api/dex_file_support.h 2021-01-29 11:02:33.379594509 +0800 ++++ art/libdexfile/external/include/art_api/dex_file_support.h 2021-01-29 10:34:50.020986935 +0800 +@@ -22,7 +22,7 @@ + #include + #include + #include +-#include ++#include "string_view_format.h" + #include + #include + +@@ -46,7 +46,7 @@ + } + explicit DexString(const char* str = "") + : ext_string_(MakeExtDexFileString(str, std::strlen(str))) {} +- explicit DexString(std::string_view str) ++ explicit DexString(StringView str) + : ext_string_(MakeExtDexFileString(str.data(), str.size())) {} + ~DexString() { g_ExtDexFileFreeString(ext_string_); } + +@@ -68,10 +68,10 @@ + } + size_t length() const { return size(); } + +- operator std::string_view() const { ++ operator StringView() const { + size_t len; + const char* chars = g_ExtDexFileGetString(ext_string_, &len); +- return std::string_view(chars, len); ++ return StringView(chars, len); + } + + private: diff --git a/build/third_party/llvm_001.patch b/build/third_party/llvm_001.patch new file mode 100644 index 0000000000000000000000000000000000000000..d09e4adbb13564ddd32431836209f7e8241a190c --- /dev/null +++ b/build/third_party/llvm_001.patch @@ -0,0 +1,659 @@ +diff -ur llvm/include/llvm/BinaryFormat/Dwarf.def llvm_mod/include/llvm/BinaryFormat/Dwarf.def +--- llvm/include/llvm/BinaryFormat/Dwarf.def 2021-08-05 10:44:22.675885701 +0800 ++++ llvm_mod/include/llvm/BinaryFormat/Dwarf.def 2021-08-05 10:53:17.888077533 +0800 +@@ -17,7 +17,7 @@ + defined HANDLE_DW_VIRTUALITY || defined HANDLE_DW_DEFAULTED || \ + defined HANDLE_DW_CC || defined HANDLE_DW_LNS || defined HANDLE_DW_LNE || \ + defined HANDLE_DW_LNCT || defined HANDLE_DW_MACRO || \ +- defined HANDLE_DW_MACRO_GNU || defined HANDLE_MACRO_FLAG || \ ++ defined HANDLE_MACRO_FLAG || \ + defined HANDLE_DW_RLE || defined HANDLE_DW_LLE || \ + (defined HANDLE_DW_CFA && defined HANDLE_DW_CFA_PRED) || \ + defined HANDLE_DW_APPLE_PROPERTY || defined HANDLE_DW_UT || \ +@@ -88,10 +88,6 @@ + #define HANDLE_DW_MACRO(ID, NAME) + #endif + +-#ifndef HANDLE_DW_MACRO_GNU +-#define HANDLE_DW_MACRO_GNU(ID, NAME) +-#endif +- + #ifndef HANDLE_MACRO_FLAG + #define HANDLE_MACRO_FLAG(ID, NAME) + #endif +@@ -841,18 +837,6 @@ + HANDLE_DW_MACRO(0x0b, define_strx) + HANDLE_DW_MACRO(0x0c, undef_strx) + +-// GNU .debug_macro extension. +-HANDLE_DW_MACRO_GNU(0x01, define) +-HANDLE_DW_MACRO_GNU(0x02, undef) +-HANDLE_DW_MACRO_GNU(0x03, start_file) +-HANDLE_DW_MACRO_GNU(0x04, end_file) +-HANDLE_DW_MACRO_GNU(0x05, define_indirect) +-HANDLE_DW_MACRO_GNU(0x06, undef_indirect) +-HANDLE_DW_MACRO_GNU(0x07, transparent_include) +-HANDLE_DW_MACRO_GNU(0x08, define_indirect_alt) +-HANDLE_DW_MACRO_GNU(0x09, undef_indirect_alt) +-HANDLE_DW_MACRO_GNU(0x0a, transparent_include_alt) +- + // DWARF v5 Macro header flags. + HANDLE_MACRO_FLAG(0x01, OFFSET_SIZE) + HANDLE_MACRO_FLAG(0x02, DEBUG_LINE_OFFSET) +@@ -909,7 +893,7 @@ + HANDLE_DW_CFA(0x16, val_expression) + // Vendor extensions: + HANDLE_DW_CFA_PRED(0x1d, MIPS_advance_loc8, SELECT_MIPS64) +-HANDLE_DW_CFA_PRED(0x2d, GNU_window_save, SELECT_SPARC) ++//HANDLE_DW_CFA_PRED(0x2d, GNU_window_save, SELECT_SPARC) + HANDLE_DW_CFA_PRED(0x2d, AARCH64_negate_ra_state, SELECT_AARCH64) + HANDLE_DW_CFA_PRED(0x2e, GNU_args_size, SELECT_X86) + +@@ -1002,7 +986,6 @@ + #undef HANDLE_DW_LNE + #undef HANDLE_DW_LNCT + #undef HANDLE_DW_MACRO +-#undef HANDLE_DW_MACRO_GNU + #undef HANDLE_MACRO_FLAG + #undef HANDLE_DW_RLE + #undef HANDLE_DW_LLE +diff -ur llvm/include/llvm/BinaryFormat/Dwarf.h llvm_mod/include/llvm/BinaryFormat/Dwarf.h +--- llvm/include/llvm/BinaryFormat/Dwarf.h 2021-08-05 10:44:22.675885701 +0800 ++++ llvm_mod/include/llvm/BinaryFormat/Dwarf.h 2021-08-05 10:53:21.308129313 +0800 +@@ -1,4 +1,4 @@ +-//===-- llvm/BinaryFormat/Dwarf.h ---Dwarf Constants-------------*- C++ -*-===// ++//===-- Dwarf.h ---Dwarf Constants-------------*- C++ -*-===// + // + // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + // See https://llvm.org/LICENSE.txt for license information. +@@ -19,21 +19,6 @@ + #ifndef LLVM_BINARYFORMAT_DWARF_H + #define LLVM_BINARYFORMAT_DWARF_H + +-#include "llvm/ADT/Optional.h" +-#include "llvm/Support/Compiler.h" +-#include "llvm/Support/DataTypes.h" +-#include "llvm/Support/ErrorHandling.h" +-#include "llvm/Support/Format.h" +-#include "llvm/Support/FormatVariadicDetails.h" +-#include "llvm/ADT/Triple.h" +- +-#include +- +-namespace llvm { +-class StringRef; +- +-namespace dwarf { +- + //===----------------------------------------------------------------------===// + // DWARF constants as gleaned from the DWARF Debugging Information Format V.5 + // reference manual http://www.dwarfstd.org/. +@@ -43,7 +28,7 @@ + // enumeration base type. + + enum LLVMConstants : uint32_t { +- // LLVM mock tags (see also llvm/BinaryFormat/Dwarf.def). ++ // LLVM mock tags (see also Dwarf.def). + DW_TAG_invalid = ~0U, // Tag for invalid results. + DW_VIRTUALITY_invalid = ~0U, // Virtuality for invalid results. + DW_MACINFO_invalid = ~0U, // Macinfo type for invalid results. +@@ -84,7 +69,7 @@ + + enum Tag : uint16_t { + #define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND) DW_TAG_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_TAG_lo_user = 0x4080, + DW_TAG_hi_user = 0xffff, + DW_TAG_user_base = 0x1000 ///< Recommended base for user tags. +@@ -97,39 +82,38 @@ + #define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR, KIND) \ + case DW_TAG_##NAME: \ + return (KIND == DW_KIND_TYPE); +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + } + } + + /// Attributes. + enum Attribute : uint16_t { + #define HANDLE_DW_AT(ID, NAME, VERSION, VENDOR) DW_AT_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_AT_lo_user = 0x2000, + DW_AT_hi_user = 0x3fff, + }; + + enum Form : uint16_t { + #define HANDLE_DW_FORM(ID, NAME, VERSION, VENDOR) DW_FORM_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_FORM_lo_user = 0x1f00, ///< Not specified by DWARF. + }; + + enum LocationAtom { + #define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR) DW_OP_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_OP_lo_user = 0xe0, + DW_OP_hi_user = 0xff, +- DW_OP_LLVM_fragment = 0x1000, ///< Only used in LLVM metadata. +- DW_OP_LLVM_convert = 0x1001, ///< Only used in LLVM metadata. +- DW_OP_LLVM_tag_offset = 0x1002, ///< Only used in LLVM metadata. +- DW_OP_LLVM_entry_value = 0x1003, ///< Only used in LLVM metadata. +- DW_OP_LLVM_implicit_pointer = 0x1004, ///< Only used in LLVM metadata. ++ DW_OP_LLVM_fragment = 0x1000, ///< Only used in LLVM metadata. ++ DW_OP_LLVM_convert = 0x1001, ///< Only used in LLVM metadata. ++ DW_OP_LLVM_tag_offset = 0x1002, ///< Only used in LLVM metadata. ++ DW_OP_LLVM_entry_value = 0x1003, ///< Only used in LLVM metadata. + }; + + enum TypeKind : uint8_t { + #define HANDLE_DW_ATE(ID, NAME, VERSION, VENDOR) DW_ATE_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_ATE_lo_user = 0x80, + DW_ATE_hi_user = 0xff + }; +@@ -146,7 +130,7 @@ + enum EndianityEncoding { + // Endianity attribute values + #define HANDLE_DW_END(ID, NAME) DW_END_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_END_lo_user = 0x40, + DW_END_hi_user = 0xff + }; +@@ -167,26 +151,25 @@ + + enum VirtualityAttribute { + #define HANDLE_DW_VIRTUALITY(ID, NAME) DW_VIRTUALITY_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_VIRTUALITY_max = 0x02 + }; + + enum DefaultedMemberAttribute { + #define HANDLE_DW_DEFAULTED(ID, NAME) DW_DEFAULTED_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_DEFAULTED_max = 0x02 + }; + + enum SourceLanguage { + #define HANDLE_DW_LANG(ID, NAME, LOWER_BOUND, VERSION, VENDOR) \ + DW_LANG_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_LANG_lo_user = 0x8000, + DW_LANG_hi_user = 0xffff + }; + + inline bool isCPlusPlus(SourceLanguage S) { +- bool result = false; + // Deliberately enumerate all the language options so we get a warning when + // new language options are added (-Wswitch) that'll hopefully help keep this + // switch up-to-date when new C++ versions are added. +@@ -195,8 +178,7 @@ + case DW_LANG_C_plus_plus_03: + case DW_LANG_C_plus_plus_11: + case DW_LANG_C_plus_plus_14: +- result = true; +- break; ++ return true; + case DW_LANG_C89: + case DW_LANG_C: + case DW_LANG_Ada83: +@@ -235,68 +217,8 @@ + case DW_LANG_BORLAND_Delphi: + case DW_LANG_lo_user: + case DW_LANG_hi_user: +- result = false; +- break; +- } +- +- return result; +-} +- +-inline bool isFortran(SourceLanguage S) { +- bool result = false; +- // Deliberately enumerate all the language options so we get a warning when +- // new language options are added (-Wswitch) that'll hopefully help keep this +- // switch up-to-date when new Fortran versions are added. +- switch (S) { +- case DW_LANG_Fortran77: +- case DW_LANG_Fortran90: +- case DW_LANG_Fortran95: +- case DW_LANG_Fortran03: +- case DW_LANG_Fortran08: +- result = true; +- break; +- case DW_LANG_C89: +- case DW_LANG_C: +- case DW_LANG_Ada83: +- case DW_LANG_C_plus_plus: +- case DW_LANG_Cobol74: +- case DW_LANG_Cobol85: +- case DW_LANG_Pascal83: +- case DW_LANG_Modula2: +- case DW_LANG_Java: +- case DW_LANG_C99: +- case DW_LANG_Ada95: +- case DW_LANG_PLI: +- case DW_LANG_ObjC: +- case DW_LANG_ObjC_plus_plus: +- case DW_LANG_UPC: +- case DW_LANG_D: +- case DW_LANG_Python: +- case DW_LANG_OpenCL: +- case DW_LANG_Go: +- case DW_LANG_Modula3: +- case DW_LANG_Haskell: +- case DW_LANG_C_plus_plus_03: +- case DW_LANG_C_plus_plus_11: +- case DW_LANG_OCaml: +- case DW_LANG_Rust: +- case DW_LANG_C11: +- case DW_LANG_Swift: +- case DW_LANG_Julia: +- case DW_LANG_Dylan: +- case DW_LANG_C_plus_plus_14: +- case DW_LANG_RenderScript: +- case DW_LANG_BLISS: +- case DW_LANG_Mips_Assembler: +- case DW_LANG_GOOGLE_RenderScript: +- case DW_LANG_BORLAND_Delphi: +- case DW_LANG_lo_user: +- case DW_LANG_hi_user: +- result = false; +- break; ++ return false; + } +- +- return result; + } + + enum CaseSensitivity { +@@ -310,7 +232,7 @@ + enum CallingConvention { + // Calling convention codes + #define HANDLE_DW_CC(ID, NAME) DW_CC_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_CC_lo_user = 0x40, + DW_CC_hi_user = 0xff + }; +@@ -338,20 +260,20 @@ + /// Line Number Standard Opcode Encodings. + enum LineNumberOps : uint8_t { + #define HANDLE_DW_LNS(ID, NAME) DW_LNS_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + }; + + /// Line Number Extended Opcode Encodings. + enum LineNumberExtendedOps { + #define HANDLE_DW_LNE(ID, NAME) DW_LNE_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_LNE_lo_user = 0x80, + DW_LNE_hi_user = 0xff + }; + + enum LineNumberEntryFormat { + #define HANDLE_DW_LNCT(ID, NAME) DW_LNCT_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_LNCT_lo_user = 0x2000, + DW_LNCT_hi_user = 0x3fff, + }; +@@ -368,36 +290,28 @@ + /// DWARF v5 macro information entry type encodings. + enum MacroEntryType { + #define HANDLE_DW_MACRO(ID, NAME) DW_MACRO_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_MACRO_lo_user = 0xe0, + DW_MACRO_hi_user = 0xff + }; + +-/// GNU .debug_macro macro information entry type encodings. +-enum GnuMacroEntryType { +-#define HANDLE_DW_MACRO_GNU(ID, NAME) DW_MACRO_GNU_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" +- DW_MACRO_GNU_lo_user = 0xe0, +- DW_MACRO_GNU_hi_user = 0xff +-}; +- + /// DWARF v5 range list entry encoding values. + enum RnglistEntries { + #define HANDLE_DW_RLE(ID, NAME) DW_RLE_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + }; + + /// DWARF v5 loc list entry encoding values. + enum LoclistEntries { + #define HANDLE_DW_LLE(ID, NAME) DW_LLE_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + }; + + /// Call frame instruction encodings. + enum CallFrameInfo { + #define HANDLE_DW_CFA(ID, NAME) DW_CFA_##NAME = ID, + #define HANDLE_DW_CFA_PRED(ID, NAME, ARCH) DW_CFA_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_CFA_extended = 0x00, + + DW_CFA_lo_user = 0x1c, +@@ -433,20 +347,20 @@ + /// ObjCPropertyAttribute::Kind! + enum ApplePropertyAttributes { + #define HANDLE_DW_APPLE_PROPERTY(ID, NAME) DW_APPLE_PROPERTY_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + }; + + /// Constants for unit types in DWARF v5. + enum UnitType : unsigned char { + #define HANDLE_DW_UT(ID, NAME) DW_UT_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_UT_lo_user = 0x80, + DW_UT_hi_user = 0xff + }; + + enum Index { + #define HANDLE_DW_IDX(ID, NAME) DW_IDX_##NAME = ID, +-#include "llvm/BinaryFormat/Dwarf.def" ++#include "Dwarf.def" + DW_IDX_lo_user = 0x2000, + DW_IDX_hi_user = 0x3fff + }; +@@ -465,7 +379,7 @@ + } + } + +-inline bool isUnitType(dwarf::Tag T) { ++inline bool isUnitType(Tag T) { + switch (T) { + case DW_TAG_compile_unit: + case DW_TAG_type_unit: +@@ -502,275 +416,6 @@ + DW_hash_function_djb = 0u + }; + +-// Constants for the GNU pubnames/pubtypes extensions supporting gdb index. +-enum GDBIndexEntryKind { +- GIEK_NONE, +- GIEK_TYPE, +- GIEK_VARIABLE, +- GIEK_FUNCTION, +- GIEK_OTHER, +- GIEK_UNUSED5, +- GIEK_UNUSED6, +- GIEK_UNUSED7 +-}; +- + enum GDBIndexEntryLinkage { GIEL_EXTERNAL, GIEL_STATIC }; + +-/// \defgroup DwarfConstantsDumping Dwarf constants dumping functions +-/// +-/// All these functions map their argument's value back to the +-/// corresponding enumerator name or return an empty StringRef if the value +-/// isn't known. +-/// +-/// @{ +-StringRef TagString(unsigned Tag); +-StringRef ChildrenString(unsigned Children); +-StringRef AttributeString(unsigned Attribute); +-StringRef FormEncodingString(unsigned Encoding); +-StringRef OperationEncodingString(unsigned Encoding); +-StringRef AttributeEncodingString(unsigned Encoding); +-StringRef DecimalSignString(unsigned Sign); +-StringRef EndianityString(unsigned Endian); +-StringRef AccessibilityString(unsigned Access); +-StringRef DefaultedMemberString(unsigned DefaultedEncodings); +-StringRef VisibilityString(unsigned Visibility); +-StringRef VirtualityString(unsigned Virtuality); +-StringRef LanguageString(unsigned Language); +-StringRef CaseString(unsigned Case); +-StringRef ConventionString(unsigned Convention); +-StringRef InlineCodeString(unsigned Code); +-StringRef ArrayOrderString(unsigned Order); +-StringRef LNStandardString(unsigned Standard); +-StringRef LNExtendedString(unsigned Encoding); +-StringRef MacinfoString(unsigned Encoding); +-StringRef MacroString(unsigned Encoding); +-StringRef GnuMacroString(unsigned Encoding); +-StringRef RangeListEncodingString(unsigned Encoding); +-StringRef LocListEncodingString(unsigned Encoding); +-StringRef CallFrameString(unsigned Encoding, Triple::ArchType Arch); +-StringRef ApplePropertyString(unsigned); +-StringRef UnitTypeString(unsigned); +-StringRef AtomTypeString(unsigned Atom); +-StringRef GDBIndexEntryKindString(GDBIndexEntryKind Kind); +-StringRef GDBIndexEntryLinkageString(GDBIndexEntryLinkage Linkage); +-StringRef IndexString(unsigned Idx); +-StringRef FormatString(DwarfFormat Format); +-StringRef FormatString(bool IsDWARF64); +-StringRef RLEString(unsigned RLE); +-/// @} +- +-/// \defgroup DwarfConstantsParsing Dwarf constants parsing functions +-/// +-/// These functions map their strings back to the corresponding enumeration +-/// value or return 0 if there is none, except for these exceptions: +-/// +-/// \li \a getTag() returns \a DW_TAG_invalid on invalid input. +-/// \li \a getVirtuality() returns \a DW_VIRTUALITY_invalid on invalid input. +-/// \li \a getMacinfo() returns \a DW_MACINFO_invalid on invalid input. +-/// +-/// @{ +-unsigned getTag(StringRef TagString); +-unsigned getOperationEncoding(StringRef OperationEncodingString); +-unsigned getVirtuality(StringRef VirtualityString); +-unsigned getLanguage(StringRef LanguageString); +-unsigned getCallingConvention(StringRef LanguageString); +-unsigned getAttributeEncoding(StringRef EncodingString); +-unsigned getMacinfo(StringRef MacinfoString); +-unsigned getMacro(StringRef MacroString); +-/// @} +- +-/// \defgroup DwarfConstantsVersioning Dwarf version for constants +-/// +-/// For constants defined by DWARF, returns the DWARF version when the constant +-/// was first defined. For vendor extensions, if there is a version-related +-/// policy for when to emit it, returns a version number for that policy. +-/// Otherwise returns 0. +-/// +-/// @{ +-unsigned TagVersion(Tag T); +-unsigned AttributeVersion(Attribute A); +-unsigned FormVersion(Form F); +-unsigned OperationVersion(LocationAtom O); +-unsigned AttributeEncodingVersion(TypeKind E); +-unsigned LanguageVersion(SourceLanguage L); +-/// @} +- +-/// \defgroup DwarfConstantsVendor Dwarf "vendor" for constants +-/// +-/// These functions return an identifier describing "who" defined the constant, +-/// either the DWARF standard itself or the vendor who defined the extension. +-/// +-/// @{ +-unsigned TagVendor(Tag T); +-unsigned AttributeVendor(Attribute A); +-unsigned FormVendor(Form F); +-unsigned OperationVendor(LocationAtom O); +-unsigned AttributeEncodingVendor(TypeKind E); +-unsigned LanguageVendor(SourceLanguage L); +-/// @} +- +-Optional LanguageLowerBound(SourceLanguage L); +- +-/// The size of a reference determined by the DWARF 32/64-bit format. +-inline uint8_t getDwarfOffsetByteSize(DwarfFormat Format) { +- switch (Format) { +- case DwarfFormat::DWARF32: +- return 4; +- case DwarfFormat::DWARF64: +- return 8; +- } +- llvm_unreachable("Invalid Format value"); +-} +- +-/// A helper struct providing information about the byte size of DW_FORM +-/// values that vary in size depending on the DWARF version, address byte +-/// size, or DWARF32/DWARF64. +-struct FormParams { +- uint16_t Version; +- uint8_t AddrSize; +- DwarfFormat Format; +- +- /// The definition of the size of form DW_FORM_ref_addr depends on the +- /// version. In DWARF v2 it's the size of an address; after that, it's the +- /// size of a reference. +- uint8_t getRefAddrByteSize() const { +- if (Version == 2) +- return AddrSize; +- return getDwarfOffsetByteSize(); +- } +- +- /// The size of a reference is determined by the DWARF 32/64-bit format. +- uint8_t getDwarfOffsetByteSize() const { +- return dwarf::getDwarfOffsetByteSize(Format); +- } +- +- explicit operator bool() const { return Version && AddrSize; } +-}; +- +-/// Get the byte size of the unit length field depending on the DWARF format. +-inline uint8_t getUnitLengthFieldByteSize(DwarfFormat Format) { +- switch (Format) { +- case DwarfFormat::DWARF32: +- return 4; +- case DwarfFormat::DWARF64: +- return 12; +- } +- llvm_unreachable("Invalid Format value"); +-} +- +-/// Get the fixed byte size for a given form. +-/// +-/// If the form has a fixed byte size, then an Optional with a value will be +-/// returned. If the form is always encoded using a variable length storage +-/// format (ULEB or SLEB numbers or blocks) then None will be returned. +-/// +-/// \param Form DWARF form to get the fixed byte size for. +-/// \param Params DWARF parameters to help interpret forms. +-/// \returns Optional value with the fixed byte size or None if +-/// \p Form doesn't have a fixed byte size. +-Optional getFixedFormByteSize(dwarf::Form Form, FormParams Params); +- +-/// Tells whether the specified form is defined in the specified version, +-/// or is an extension if extensions are allowed. +-bool isValidFormForVersion(Form F, unsigned Version, bool ExtensionsOk = true); +- +-/// Returns the symbolic string representing Val when used as a value +-/// for attribute Attr. +-StringRef AttributeValueString(uint16_t Attr, unsigned Val); +- +-/// Returns the symbolic string representing Val when used as a value +-/// for atom Atom. +-StringRef AtomValueString(uint16_t Atom, unsigned Val); +- +-/// Describes an entry of the various gnu_pub* debug sections. +-/// +-/// The gnu_pub* kind looks like: +-/// +-/// 0-3 reserved +-/// 4-6 symbol kind +-/// 7 0 == global, 1 == static +-/// +-/// A gdb_index descriptor includes the above kind, shifted 24 bits up with the +-/// offset of the cu within the debug_info section stored in those 24 bits. +-struct PubIndexEntryDescriptor { +- GDBIndexEntryKind Kind; +- GDBIndexEntryLinkage Linkage; +- PubIndexEntryDescriptor(GDBIndexEntryKind Kind, GDBIndexEntryLinkage Linkage) +- : Kind(Kind), Linkage(Linkage) {} +- /* implicit */ PubIndexEntryDescriptor(GDBIndexEntryKind Kind) +- : Kind(Kind), Linkage(GIEL_EXTERNAL) {} +- explicit PubIndexEntryDescriptor(uint8_t Value) +- : Kind( +- static_cast((Value & KIND_MASK) >> KIND_OFFSET)), +- Linkage(static_cast((Value & LINKAGE_MASK) >> +- LINKAGE_OFFSET)) {} +- uint8_t toBits() const { +- return Kind << KIND_OFFSET | Linkage << LINKAGE_OFFSET; +- } +- +-private: +- enum { +- KIND_OFFSET = 4, +- KIND_MASK = 7 << KIND_OFFSET, +- LINKAGE_OFFSET = 7, +- LINKAGE_MASK = 1 << LINKAGE_OFFSET +- }; +-}; +- +-template struct EnumTraits : public std::false_type {}; +- +-template <> struct EnumTraits : public std::true_type { +- static constexpr char Type[3] = "AT"; +- static constexpr StringRef (*StringFn)(unsigned) = &AttributeString; +-}; +- +-template <> struct EnumTraits
: public std::true_type { +- static constexpr char Type[5] = "FORM"; +- static constexpr StringRef (*StringFn)(unsigned) = &FormEncodingString; +-}; +- +-template <> struct EnumTraits : public std::true_type { +- static constexpr char Type[4] = "IDX"; +- static constexpr StringRef (*StringFn)(unsigned) = &IndexString; +-}; +- +-template <> struct EnumTraits : public std::true_type { +- static constexpr char Type[4] = "TAG"; +- static constexpr StringRef (*StringFn)(unsigned) = &TagString; +-}; +- +-template <> struct EnumTraits : public std::true_type { +- static constexpr char Type[4] = "LNS"; +- static constexpr StringRef (*StringFn)(unsigned) = &LNStandardString; +-}; +- +-template <> struct EnumTraits : public std::true_type { +- static constexpr char Type[3] = "OP"; +- static constexpr StringRef (*StringFn)(unsigned) = &OperationEncodingString; +-}; +- +-inline uint64_t computeTombstoneAddress(uint8_t AddressByteSize) { +- return std::numeric_limits::max() >> (8 - AddressByteSize) * 8; +-} +- +-} // End of namespace dwarf +- +-/// Dwarf constants format_provider +-/// +-/// Specialization of the format_provider template for dwarf enums. Unlike the +-/// dumping functions above, these format unknown enumerator values as +-/// DW_TYPE_unknown_1234 (e.g. DW_TAG_unknown_ffff). +-template +-struct format_provider::value>> { +- static void format(const Enum &E, raw_ostream &OS, StringRef Style) { +- StringRef Str = dwarf::EnumTraits::StringFn(E); +- if (Str.empty()) { +- OS << "DW_" << dwarf::EnumTraits::Type << "_unknown_" +- << llvm::format("%x", E); +- } else +- OS << Str; +- } +-}; +-} // End of namespace llvm +- + #endif diff --git a/build/third_party/patch.sh b/build/third_party/patch.sh new file mode 100644 index 0000000000000000000000000000000000000000..647ba0f34807bfaa40c99d440c44170c4f04cb95 --- /dev/null +++ b/build/third_party/patch.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +THIRD_PARTY_PATH=$MAPLE_ROOT/third_party +TOOLS_PATH=$MAPLE_ROOT/build/third_party +AOSP_PATH=$THIRD_PARTY_PATH/aosp_10.0.0_r35 +AOSP_GN_PATH=$TOOLS_PATH/aosp_gn +LLVM_PATH=$THIRD_PARTY_PATH/llvm-12.0.0.src +MODIFIED_AOSP_PATH=$THIRD_PARTY_PATH/aosp_modified +MODIFIED_LLVM_PATH=$THIRD_PARTY_PATH/llvm_modified + +function install_patch { + if [ -d $MODIFIED_AOSP_PATH ];then + echo "Already Patched." + exit 0 + fi + + echo "Preparing the build environment..." + + #backup source code + cd $THIRD_PARTY_PATH + cp -rH $AOSP_PATH $MODIFIED_AOSP_PATH + cp -rH $LLVM_PATH $MODIFIED_LLVM_PATH + + #patch + cd $MODIFIED_AOSP_PATH + patch -p0 < $TOOLS_PATH/system_001.patch + patch -p0 < $TOOLS_PATH/art_001.patch + mkdir -p include/ + cp -r ${MAPLE_ROOT}/src/hir2mpl/bytecode_input/dex/include/string_view_format.h include/ + + cd $MODIFIED_LLVM_PATH + patch -p0 < $TOOLS_PATH/llvm_001.patch + + #add third_party gn + cp -f $AOSP_GN_PATH/art/libdexfile/BUILD.gn $MODIFIED_AOSP_PATH/art/libdexfile/ + cp -f $AOSP_GN_PATH/system/core/libziparchive/BUILD.gn $MODIFIED_AOSP_PATH/system/core/libziparchive/ + cp -f $AOSP_GN_PATH/system/core/base/BUILD.gn $MODIFIED_AOSP_PATH/system/core/base/ +} + + +function uninstall_patch { + rm -rf $MODIFIED_AOSP_PATH $MODIFIED_LLVM_PATH +} + +function main { + if [ "x$1" == "xpatch" ]; then + install_patch + fi + + if [ "x$1" == "xunpatch" ]; then + uninstall_patch + fi + cd $MAPLE_ROOT +} + + +main $@ diff --git a/build/third_party/system_001.patch b/build/third_party/system_001.patch new file mode 100644 index 0000000000000000000000000000000000000000..a9c5aa77f2859f45158071c39b3f98980dcaa0ce --- /dev/null +++ b/build/third_party/system_001.patch @@ -0,0 +1,476 @@ +diff -ur system_aosp/core/base/cmsg.cpp system/core/base/cmsg.cpp +--- system_aosp/core/base/cmsg.cpp 2021-01-29 10:43:34.145594722 +0800 ++++ system/core/base/cmsg.cpp 2021-01-29 10:36:40.905961768 +0800 +@@ -21,7 +21,7 @@ + #include + #include + #include +- ++#include + #include + + #include +@@ -33,7 +33,7 @@ + const std::vector& fds) { + size_t cmsg_space = CMSG_SPACE(sizeof(int) * fds.size()); + size_t cmsg_len = CMSG_LEN(sizeof(int) * fds.size()); +- if (cmsg_space >= PAGE_SIZE) { ++ if (cmsg_space >= sysconf(_SC_PAGE_SIZE)) { + errno = ENOMEM; + return -1; + } +@@ -75,7 +75,7 @@ + fds->clear(); + + size_t cmsg_space = CMSG_SPACE(sizeof(int) * max_fds); +- if (cmsg_space >= PAGE_SIZE) { ++ if (cmsg_space >= sysconf(_SC_PAGE_SIZE)) { + errno = ENOMEM; + return -1; + } +diff -ur system_aosp/core/base/include/android-base/logging.h system/core/base/include/android-base/logging.h +--- system_aosp/core/base/include/android-base/logging.h 2021-01-29 10:43:34.145594722 +0800 ++++ system/core/base/include/android-base/logging.h 2021-01-29 10:36:40.905961768 +0800 +@@ -81,7 +81,7 @@ + + enum LogSeverity { + VERBOSE, +- DEBUG, ++ DEBUG_S, + INFO, + WARNING, + ERROR, +@@ -181,7 +181,7 @@ + // Note: DO NOT USE DIRECTLY. This is an implementation detail. + #define SEVERITY_LAMBDA(severity) ([&]() { \ + using ::android::base::VERBOSE; \ +- using ::android::base::DEBUG; \ ++ using ::android::base::DEBUG_S; \ + using ::android::base::INFO; \ + using ::android::base::WARNING; \ + using ::android::base::ERROR; \ +@@ -248,7 +248,7 @@ + // Logs a message to logcat with the specified log ID on Android otherwise to + // stderr. If the severity is FATAL it also causes an abort. + // Use an expression here so we can support the << operator following the macro, +-// like "LOG(DEBUG) << xxx;". ++// like "LOG(DEBUG_S) << xxx;". + #define LOG_TO(dest, severity) LOGGING_PREAMBLE(severity) && LOG_STREAM_TO(dest, severity) + + // A variant of LOG that also logs the current errno value. To be used when +diff -ur system_aosp/core/base/include/android-base/strings.h system/core/base/include/android-base/strings.h +--- system_aosp/core/base/include/android-base/strings.h 2021-01-29 10:43:34.145594722 +0800 ++++ system/core/base/include/android-base/strings.h 2021-01-29 10:36:40.905961768 +0800 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include "string_view_format.h" + + namespace android { + namespace base { +@@ -56,17 +57,17 @@ + extern template std::string Join(const std::vector&, const std::string&); + + // Tests whether 's' starts with 'prefix'. +-bool StartsWith(std::string_view s, std::string_view prefix); +-bool StartsWith(std::string_view s, char prefix); +-bool StartsWithIgnoreCase(std::string_view s, std::string_view prefix); ++bool StartsWith(StringView s, StringView prefix); ++bool StartsWith(StringView s, char prefix); ++bool StartsWithIgnoreCase(StringView s, StringView prefix); + + // Tests whether 's' ends with 'suffix'. +-bool EndsWith(std::string_view s, std::string_view suffix); +-bool EndsWith(std::string_view s, char suffix); +-bool EndsWithIgnoreCase(std::string_view s, std::string_view suffix); ++bool EndsWith(StringView s, StringView suffix); ++bool EndsWith(StringView s, char suffix); ++bool EndsWithIgnoreCase(StringView s, StringView suffix); + + // Tests whether 'lhs' equals 'rhs', ignoring case. +-bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs); ++bool EqualsIgnoreCase(StringView lhs, StringView rhs); + + } // namespace base + } // namespace android +diff -ur system_aosp/core/base/logging.cpp system/core/base/logging.cpp +--- system_aosp/core/base/logging.cpp 2021-01-29 10:43:34.145594722 +0800 ++++ system/core/base/logging.cpp 2021-01-29 10:36:40.905961768 +0800 +@@ -16,10 +16,11 @@ + + #if defined(_WIN32) + #include ++#include "android-base/threads.h" + #endif + + #include "android-base/logging.h" +- ++#include + #include + #include + #include +@@ -167,7 +168,7 @@ + static constexpr int kLogSeverityToKernelLogLevel[] = { + [android::base::VERBOSE] = 7, // KERN_DEBUG (there is no verbose kernel log + // level) +- [android::base::DEBUG] = 7, // KERN_DEBUG ++ [android::base::DEBUG_S] = 7, // KERN_DEBUG_S + [android::base::INFO] = 6, // KERN_INFO + [android::base::WARNING] = 4, // KERN_WARNING + [android::base::ERROR] = 3, // KERN_ERROR +@@ -310,7 +311,7 @@ + gMinimumLogSeverity = VERBOSE; + continue; + case 'd': +- gMinimumLogSeverity = DEBUG; ++ gMinimumLogSeverity = DEBUG_S; + continue; + case 'i': + gMinimumLogSeverity = INFO; +diff -ur system_aosp/core/base/mapped_file.cpp system/core/base/mapped_file.cpp +--- system_aosp/core/base/mapped_file.cpp 2021-01-29 10:43:34.145594722 +0800 ++++ system/core/base/mapped_file.cpp 2021-01-29 10:36:40.905961768 +0800 +@@ -76,7 +76,7 @@ + if (base_ != nullptr) UnmapViewOfFile(base_); + if (handle_ != nullptr) CloseHandle(handle_); + #else +- if (base_ != nullptr) munmap(base_, size_ + offset_); ++ if (base_ != nullptr) munmap(base_, size_); + #endif + + base_ = nullptr; +diff -ur system_aosp/core/base/strings.cpp system/core/base/strings.cpp +--- system_aosp/core/base/strings.cpp 2021-01-29 10:43:34.145594722 +0800 ++++ system/core/base/strings.cpp 2021-01-29 10:36:40.905961768 +0800 +@@ -87,32 +87,32 @@ + template std::string Join(const std::vector&, const std::string&); + template std::string Join(const std::vector&, const std::string&); + +-bool StartsWith(std::string_view s, std::string_view prefix) { ++bool StartsWith(StringView s, StringView prefix) { + return s.substr(0, prefix.size()) == prefix; + } + +-bool StartsWith(std::string_view s, char prefix) { ++bool StartsWith(StringView s, char prefix) { + return !s.empty() && s.front() == prefix; + } + +-bool StartsWithIgnoreCase(std::string_view s, std::string_view prefix) { ++bool StartsWithIgnoreCase(StringView s, StringView prefix) { + return s.size() >= prefix.size() && strncasecmp(s.data(), prefix.data(), prefix.size()) == 0; + } + +-bool EndsWith(std::string_view s, std::string_view suffix) { ++bool EndsWith(StringView s, StringView suffix) { + return s.size() >= suffix.size() && s.substr(s.size() - suffix.size(), suffix.size()) == suffix; + } + +-bool EndsWith(std::string_view s, char suffix) { ++bool EndsWith(StringView s, char suffix) { + return !s.empty() && s.back() == suffix; + } + +-bool EndsWithIgnoreCase(std::string_view s, std::string_view suffix) { ++bool EndsWithIgnoreCase(StringView s, StringView suffix) { + return s.size() >= suffix.size() && + strncasecmp(s.data() + (s.size() - suffix.size()), suffix.data(), suffix.size()) == 0; + } + +-bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs) { ++bool EqualsIgnoreCase(StringView lhs, StringView rhs) { + return lhs.size() == rhs.size() && strncasecmp(lhs.data(), rhs.data(), lhs.size()) == 0; + } + +diff -ur system_aosp/core/include/cutils/android_filesystem_config.h system/core/include/cutils/android_filesystem_config.h +--- system_aosp/core/include/cutils/android_filesystem_config.h 2021-01-29 10:43:42.185665405 +0800 ++++ system/core/include/cutils/android_filesystem_config.h 2021-01-29 10:36:40.909961804 +0800 +@@ -144,6 +144,7 @@ + /* The range 2900-2999 is reserved for OEM, and must never be + * used here */ + #define AID_OEM_RESERVED_START 2900 ++#define AID_HDB 2901 /* access hdbservice */ + #define AID_OEM_RESERVED_END 2999 + + /* The 3000 series are intended for use as supplemental group id's only. +@@ -161,6 +162,38 @@ + + /* The range 5000-5999 is also reserved for OEM, and must never be used here. */ + #define AID_OEM_RESERVED_2_START 5000 ++ ++/* Huawei Extend AID */ ++/* ++ * 1. ALL huawei extend AID should add VENDOR prefix,e.g. AID_VENDOR_XXXX ++ * 2. If the added AID was used in vendor partition only, Add it to config.fs ++ * vendor/huawei/chipset_common/config/common/config.fs ++ * 3. Huawei AID range: ++ * AID used in system partition: 5501-5900 ++ * AID used in vendor partiton only: 5900-5999 ++ * 4. wiki: http://3ms.huawei.com/hi/group/2844405/wiki_5160709.html?for_statistic_from=creation_group_wiki ++*/ ++ ++#define AID_VENDOR_HDB 5501 /* access hdbservice*/ ++ ++#define AID_VENDOR_DSM 5502 /* dsm access */ ++ ++#define AID_VENDOR_HWHFD 5503 /* Huawei kernel hot fix daemon */ ++ ++#define AID_VENDOR_SKYTONE 5504 /* access skytone */ ++ ++#define AID_VENDOR_ACT_RCS 5505 /* access device actr */ ++ ++#define AID_VENDOR_ODMF 5506 /* access AI model files */ ++ ++#define AID_VENDOR_INSTALLER 5507 /* access installer files */ ++ ++#define AID_VENDOR_HBS 5508 /* access hbs data */ ++ ++#define AID_DSM 5509 /* dsm access */ ++ ++#define AID_VENDOR_FACEID 5510 /* acess faceid */ ++ + #define AID_OEM_RESERVED_2_END 5999 + + #define AID_EVERYBODY 9997 /* shared between all apps in the same profile */ +diff -ur system_aosp/core/include/cutils/fs.h system/core/include/cutils/fs.h +--- system_aosp/core/include/cutils/fs.h 2021-01-29 10:43:42.185665405 +0800 ++++ system/core/include/cutils/fs.h 2021-01-29 10:36:40.909961804 +0800 +@@ -45,6 +45,14 @@ + */ + extern int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid); + ++/* DTS2016051401335 AR000485VM FixUid l00214442 20160514 begin */ ++/* ++ * Ensure that directory exists with given mode and owners. If it exists ++ * with a different mode or owners, they are fixed to match the given values recursively. ++ */ ++extern int fs_prepare_dir_fixup_recursive(const char* path, mode_t mode, uid_t uid, gid_t gid, int allow_fixup); ++/* DTS2016051401335 AR000485VM FixUid l00214442 20160514 end */ ++ + /* + * Ensure that directory exists with given mode and owners. If it exists + * with different owners, they are not fixed and -1 is returned. +diff -ur system_aosp/core/include/cutils/trace.h system/core/include/cutils/trace.h +--- system_aosp/core/include/cutils/trace.h 2021-01-29 10:43:42.185665405 +0800 ++++ system/core/include/cutils/trace.h 2021-01-29 10:36:40.909961804 +0800 +@@ -18,7 +18,6 @@ + #define _LIBS_CUTILS_TRACE_H + + #include +-#include + #include + #include + #include +@@ -88,7 +87,7 @@ + #elif ATRACE_TAG > ATRACE_TAG_VALID_MASK + #error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h + #endif +- ++using namespace std; + /** + * Opens the trace file for writing and reads the property for initial tags. + * The atrace.tags.enableflags property sets the tags to trace. +diff -ur system_aosp/core/include/log/log_id.h system/core/include/log/log_id.h +--- system_aosp/core/include/log/log_id.h 2021-01-29 10:43:42.185665405 +0800 ++++ system/core/include/log/log_id.h 2021-01-29 10:36:40.909961804 +0800 +@@ -58,6 +58,8 @@ + log_id_t android_name_to_log_id(const char* logName); + const char* android_log_id_to_name(log_id_t log_id); + ++int __hwlog_setparam(int paramid, const char *val); ++ + #ifdef __cplusplus + } + #endif +diff -ur system_aosp/core/include/private/android_filesystem_config.h system/core/include/private/android_filesystem_config.h +--- system_aosp/core/include/private/android_filesystem_config.h 2021-01-29 10:43:42.185665405 +0800 ++++ system/core/include/private/android_filesystem_config.h 2021-01-29 10:36:40.909961804 +0800 +@@ -144,6 +144,7 @@ + /* The range 2900-2999 is reserved for OEM, and must never be + * used here */ + #define AID_OEM_RESERVED_START 2900 ++#define AID_HDB 2901 /* access hdbservice */ + #define AID_OEM_RESERVED_END 2999 + + /* The 3000 series are intended for use as supplemental group id's only. +@@ -161,6 +162,38 @@ + + /* The range 5000-5999 is also reserved for OEM, and must never be used here. */ + #define AID_OEM_RESERVED_2_START 5000 ++ ++/* Huawei Extend AID */ ++/* ++ * 1. ALL huawei extend AID should add VENDOR prefix,e.g. AID_VENDOR_XXXX ++ * 2. If the added AID was used in vendor partition only, Add it to config.fs ++ * vendor/huawei/chipset_common/config/common/config.fs ++ * 3. Huawei AID range: ++ * AID used in system partition: 5501-5900 ++ * AID used in vendor partiton only: 5900-5999 ++ * 4. wiki: http://3ms.huawei.com/hi/group/2844405/wiki_5160709.html?for_statistic_from=creation_group_wiki ++*/ ++ ++#define AID_VENDOR_HDB 5501 /* access hdbservice*/ ++ ++#define AID_VENDOR_DSM 5502 /* dsm access */ ++ ++#define AID_VENDOR_HWHFD 5503 /* Huawei kernel hot fix daemon */ ++ ++#define AID_VENDOR_SKYTONE 5504 /* access skytone */ ++ ++#define AID_VENDOR_ACT_RCS 5505 /* access device actr */ ++ ++#define AID_VENDOR_ODMF 5506 /* access AI model files */ ++ ++#define AID_VENDOR_INSTALLER 5507 /* access installer files */ ++ ++#define AID_VENDOR_HBS 5508 /* access hbs data */ ++ ++#define AID_DSM 5509 /* dsm access */ ++ ++#define AID_VENDOR_FACEID 5510 /* acess faceid */ ++ + #define AID_OEM_RESERVED_2_END 5999 + + #define AID_EVERYBODY 9997 /* shared between all apps in the same profile */ +diff -ur system_aosp/core/include/utils/Flattenable.h system/core/include/utils/Flattenable.h +--- system_aosp/core/include/utils/Flattenable.h 2021-01-29 10:43:42.189665440 +0800 ++++ system/core/include/utils/Flattenable.h 2021-01-29 10:36:40.909961804 +0800 +@@ -47,12 +47,7 @@ + + template + static size_t align(void*& buffer) { +- static_assert(!(N & (N - 1)), "Can only align to a power of 2."); +- void* b = buffer; +- buffer = reinterpret_cast((uintptr_t(buffer) + (N-1)) & ~(N-1)); +- size_t delta = size_t(uintptr_t(buffer) - uintptr_t(b)); +- memset(b, 0, delta); +- return delta; ++ return align( const_cast(buffer) ); + } + + static void advance(void*& buffer, size_t& size, size_t offset) { +diff -ur system_aosp/core/include/utils/String8.h system/core/include/utils/String8.h +--- system_aosp/core/include/utils/String8.h 2021-01-29 10:43:42.189665440 +0800 ++++ system/core/include/utils/String8.h 2021-01-29 10:36:40.909961804 +0800 +@@ -58,6 +58,9 @@ + explicit String8(const char16_t* o, size_t numChars); + explicit String8(const char32_t* o); + explicit String8(const char32_t* o, size_t numChars); ++ //fix bug of sogou input method ++ explicit String8(unsigned short const* o); ++ //fix bug of sogou input method + ~String8(); + + static inline const String8 empty(); +diff -ur system_aosp/core/liblog/include/log/log_id.h system/core/liblog/include/log/log_id.h +--- system_aosp/core/liblog/include/log/log_id.h 2021-01-29 10:43:56.097787709 +0800 ++++ system/core/liblog/include/log/log_id.h 2021-01-29 10:36:40.909961804 +0800 +@@ -58,6 +58,8 @@ + log_id_t android_name_to_log_id(const char* logName); + const char* android_log_id_to_name(log_id_t log_id); + ++int __hwlog_setparam(int paramid, const char *val); ++ + #ifdef __cplusplus + } + #endif +diff -ur system_aosp/core/liblog/include_vndk/log/log_id.h system/core/liblog/include_vndk/log/log_id.h +--- system_aosp/core/liblog/include_vndk/log/log_id.h 2021-01-29 10:43:56.097787709 +0800 ++++ system/core/liblog/include_vndk/log/log_id.h 2021-01-29 10:36:40.909961804 +0800 +@@ -58,6 +58,8 @@ + log_id_t android_name_to_log_id(const char* logName); + const char* android_log_id_to_name(log_id_t log_id); + ++int __hwlog_setparam(int paramid, const char *val); ++ + #ifdef __cplusplus + } + #endif +diff -ur system_aosp/core/liblog/liblog.map.txt system/core/liblog/liblog.map.txt +--- system_aosp/core/liblog/liblog.map.txt 2021-01-29 10:43:56.097787709 +0800 ++++ system/core/liblog/liblog.map.txt 2021-01-29 10:36:40.909961804 +0800 +@@ -63,6 +63,7 @@ + __android_log_security; # apex + android_log_reset; #vndk + android_log_parser_reset; #vndk ++ __hwlog_setparam; + }; + + LIBLOG_PRIVATE { +diff -ur system_aosp/core/libutils/include/utils/Flattenable.h system/core/libutils/include/utils/Flattenable.h +--- system_aosp/core/libutils/include/utils/Flattenable.h 2021-01-29 10:44:02.421843310 +0800 ++++ system/core/libutils/include/utils/Flattenable.h 2021-01-29 10:36:40.909961804 +0800 +@@ -47,12 +47,7 @@ + + template + static size_t align(void*& buffer) { +- static_assert(!(N & (N - 1)), "Can only align to a power of 2."); +- void* b = buffer; +- buffer = reinterpret_cast((uintptr_t(buffer) + (N-1)) & ~(N-1)); +- size_t delta = size_t(uintptr_t(buffer) - uintptr_t(b)); +- memset(b, 0, delta); +- return delta; ++ return align( const_cast(buffer) ); + } + + static void advance(void*& buffer, size_t& size, size_t offset) { +diff -ur system_aosp/core/libutils/include/utils/String8.h system/core/libutils/include/utils/String8.h +--- system_aosp/core/libutils/include/utils/String8.h 2021-01-29 10:44:02.421843310 +0800 ++++ system/core/libutils/include/utils/String8.h 2021-01-29 10:36:40.909961804 +0800 +@@ -58,6 +58,9 @@ + explicit String8(const char16_t* o, size_t numChars); + explicit String8(const char32_t* o); + explicit String8(const char32_t* o, size_t numChars); ++ //fix bug of sogou input method ++ explicit String8(unsigned short const* o); ++ //fix bug of sogou input method + ~String8(); + + static inline const String8 empty(); +diff -ur system_aosp/core/libziparchive/zip_archive.cc system/core/libziparchive/zip_archive.cc +--- system_aosp/core/libziparchive/zip_archive.cc 2021-01-29 10:44:10.001909933 +0800 ++++ system/core/libziparchive/zip_archive.cc 2021-01-29 10:36:40.913961839 +0800 +@@ -33,6 +33,7 @@ + + #include + #include ++#include "string_view_format.h" + + #if defined(__APPLE__) + #define lseek64 lseek +@@ -103,8 +104,8 @@ + + static uint32_t ComputeHash(const ZipString& name) { + #if !defined(_WIN32) +- return std::hash{}( +- std::string_view(reinterpret_cast(name.name), name.name_length)); ++ return std::hash{}( ++ StringView(reinterpret_cast(name.name), name.name_length)); + #else + // Remove this code path once the windows compiler knows how to compile the above statement. + uint32_t hash = 0; +diff -ur system_aosp/core/libziparchive/zip_archive_private.h system/core/libziparchive/zip_archive_private.h +--- system_aosp/core/libziparchive/zip_archive_private.h 2021-01-29 10:44:10.001909933 +0800 ++++ system/core/libziparchive/zip_archive_private.h 2021-01-29 10:36:40.913961839 +0800 +@@ -138,7 +138,7 @@ + + /** + * More space efficient string representation of strings in an mmaped zipped file than +- * std::string_view or ZipString. Using ZipString as an entry in the ZipArchive hashtable wastes ++ * StringView or ZipString. Using ZipString as an entry in the ZipArchive hashtable wastes + * space. ZipString stores a pointer to a string (on 64 bit, 8 bytes) and the length to read from + * that pointer, 2 bytes. Because of alignment, the structure consumes 16 bytes, wasting 6 bytes. + * ZipStringOffset stores a 4 byte offset from a fixed location in the memory mapped file instead +diff -ur system_aosp/core/libziparchive/zip_writer.cc system/core/libziparchive/zip_writer.cc +--- system_aosp/core/libziparchive/zip_writer.cc 2021-01-29 10:44:10.001909933 +0800 ++++ system/core/libziparchive/zip_writer.cc 2021-01-29 10:36:40.913961839 +0800 +@@ -358,7 +358,7 @@ + CHECK(z_stream_->avail_out != 0); + + // Prepare the input. +- z_stream_->next_in = reinterpret_cast(data); ++ z_stream_->next_in = (unsigned char *)(data); + z_stream_->avail_in = len; + + while (z_stream_->avail_in > 0) { diff --git a/build/toolchain/BUILD.gn b/build/toolchain/BUILD.gn new file mode 100755 index 0000000000000000000000000000000000000000..00a3f708a9f91ea0f1dbf3e8d212fa55154be348 --- /dev/null +++ b/build/toolchain/BUILD.gn @@ -0,0 +1,202 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +toolchain("clang") { + tool("cc") { + depfile = "{{output}}.d" + command = "${GN_C_COMPILER} {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -MD -MT {{output}} -MF $depfile -o {{output}} -c {{source}}" + depsformat = "gcc" + description = "Building C object {{output}}" + outputs = [ + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", + ] + } + + tool("cxx") { + depfile = "{{output}}.d" + command = "${GN_CXX_COMPILER} {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -MD -MT {{output}} -MF $depfile -o {{output}} -c {{source}}" + depsformat = "gcc" + description = "Building CXX object {{output}}" + outputs = [ + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", + ] + } + + tool("asm") { + depfile = "{{output}}.d" + + #command = "${GN_C_COMPILER} -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}}${extra_asmflags} -c {{source}} -o {{output}}" + command = "${GN_CXX_COMPILER} {{defines}} {{include_dirs}} {{asmflags}} -MD -MT {{output}} -MF $depfile -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "ASM {{output}}" + outputs = [ + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", + ] + } + + tool("alink") { + rspfile = "{{output}}.rsp" + rspfile_content = "{{inputs}}" + command = "rm -f {{output}} && ${GN_AR_COMPILER} qc {{output}} ${rspfile_content} && ${GN_RANLIB_COMPILER} {{output}}" + description = "AR {{target_output_name}}{{output_extension}}" + outputs = [ + "{{output_dir}}/{{target_output_name}}{{output_extension}}", + ] + default_output_extension = ".a" + default_output_dir = "${GN_ARCHIVE_OUTPUT_DIRECTORY}" + } + + tool("solink") { + soname = "{{target_output_name}}{{output_extension}}" + sofile = "{{output_dir}}/$soname" + rspfile = soname + ".rsp" + + #command = "${GN_CXX_COMPILER} -shared {{ldflags}} -o $soname -Wl,-soname=$soname @$rspfile {{libs}}" + rspfile_content = "{{inputs}} {{solibs}} {{libs}}" + command = "${GN_CXX_COMPILER} -fuse-ld=lld {{ldflags}} -o $sofile -shared -Wl,-soname=$soname ${rspfile_content}" + description = "SOLINK $soname" + + # Use this for {{output_extension}} expansions unless a target manually + # overrides it (in which case {{output_extension}} will be what the target + # specifies). + default_output_extension = ".so" + outputs = [ + sofile, + ] + link_output = sofile + depend_output = sofile + + #output_prefix = "" + default_output_dir = "${GN_LIBRARY_OUTPUT_DIRECTORY}/${OPT}" + restat = true + } + + tool("link") { + outfile = "${GN_BINARY_OUTPUT_DIRECTORY}/{{target_output_name}}{{output_extension}}" + rspfile = "$outfile.rsp" + rspfile_content = "{{inputs}}" + if (GN_BUILD_TYPE == "RELEASE") { + command = "${GN_CXX_COMPILER} -s -fuse-ld=lld {{ldflags}} -o $outfile -Wl,--start-group ${rspfile_content} {{libs}} -Wl,--end-group {{solibs}}" + } else { + command = "${GN_CXX_COMPILER} -fuse-ld=lld {{ldflags}} -o $outfile -Wl,--start-group ${rspfile_content} {{libs}} -Wl,--end-group {{solibs}}" + } + description = "LINK $outfile" + rspfile_content = "{{inputs}}" + outputs = [ + outfile, + ] + } + + tool("stamp") { + command = "touch {{output}}" + description = "STAMP {{output}}" + } + + tool("copy") { + command = "cp -af {{source}} {{output}}" + description = "COPY {{source}} {{output}}" + } +} + +toolchain("cross_compile") { + tool("cc") { + depfile = "{{output}}.d" + command = "${GN_C_CROSS_COMPILER} {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -MD -MT {{output}} -MF $depfile -o {{output}} -c {{source}}" + depsformat = "gcc" + description = "Building C object {{output}}" + outputs = [ + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", + ] + } + + tool("cxx") { + depfile = "{{output}}.d" + command = "${GN_CXX_CROSS_COMPILER} {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -MD -MT {{output}} -MF $depfile -o {{output}} -c {{source}}" + depsformat = "gcc" + description = "Building CXX object {{output}}" + outputs = [ + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", + ] + } + + tool("asm") { + depfile = "{{output}}.d" + command = "${GN_CXX_CROSS_COMPILER} {{defines}} {{include_dirs}} {{asmflags}} -MD -MT {{output}} -MF $depfile -c {{source}} -o {{output}}" + depsformat = "gcc" + description = "ASM {{output}}" + outputs = [ + "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o", + ] + } + + tool("alink") { + rspfile = "{{output}}.rsp" + rspfile_content = "{{inputs}}" + command = "rm -f {{output}} && ${GN_AR_CROSS_COMPILER} qc {{output}} ${rspfile_content} && ${GN_RANLIB_CROSS_COMPILER} {{output}}" + description = "AR {{target_output_name}}{{output_extension}}" + rspfile_content = "{{inputs}}" + outputs = [ + "{{output_dir}}/{{target_output_name}}{{output_extension}}", + ] + default_output_extension = ".a" + default_output_dir = "${GN_ARCHIVE_OUTPUT_DIRECTORY}" + } + + tool("solink") { + soname = "{{target_output_name}}{{output_extension}}" + sofile = "{{output_dir}}/$soname" + rspfile = soname + ".rsp" + rspfile_content = "{{inputs}} {{solibs}} {{libs}}" + command = "${GN_CXX_CROSS_COMPILER} {{ldflags}} -o $sofile -shared -Wl,-soname=$soname ${rspfile_content}" + description = "SOLINK $soname" + + # Use this for {{output_extension}} expansions unless a target manually + # overrides it (in which case {{output_extension}} will be what the target + # specifies). + default_output_extension = ".so" + outputs = [ + sofile, + ] + link_output = sofile + depend_output = sofile + + #output_prefix = "" + default_output_dir = "${GN_LIBRARY_OUTPUT_DIRECTORY}/${OPT}" + restat = true + } + + tool("link") { + outfile = "${GN_BINARY_OUTPUT_DIRECTORY}/{{target_output_name}}{{output_extension}}" + rspfile = "$outfile.rsp" + rspfile_content = "{{inputs}}" + + #command = "${GN_CXX_CROSS_COMPILER} {{ldflags}} -o $outfile @$rspfile {{solibs}} {{libs}}" + command = "${GN_CXX_CROSS_COMPILER} {{ldflags}} -o $outfile ${rspfile_content} {{solibs}} {{libs}}" + description = "LINK $outfile" + rspfile_content = "{{inputs}}" + outputs = [ + outfile, + ] + } + + tool("stamp") { + command = "touch {{output}}" + description = "STAMP {{output}}" + } + + tool("copy") { + command = "cp -af {{source}} {{output}}" + description = "COPY {{source}} {{output}}" + } +} diff --git a/build/tools/common/bis.sh b/build/tools/common/bis.sh new file mode 100755 index 0000000000000000000000000000000000000000..644ff36e9bda6025369a3547bcf65c7bfbfbf640 --- /dev/null +++ b/build/tools/common/bis.sh @@ -0,0 +1,75 @@ + +good_dir=$1 +bad_dir=$2 +src_list=src_list.log +pwd=$PWD +cd $bad_dir +sed 's/ /\n/g' obj.list > $pwd/$src_list +cd - +file_lenth=`sed -n '$=' $src_list` + +function get_src_list() { + min=$1 + max=$2 + line_number=1 + src=" " + cat $src_list | while read line + do + if [ "${line_number}" -ge "${min}" ]&&[ "${line_number}" -le "${max}" ]; + then + src=${src}${bad_dir}"/"${line}" " + else + src=${src}${good_dir}"/"${line}" " + fi + if [ $line_number -eq $file_lenth ];then + echo "${src}" + fi + line_number=`expr $line_number + 1` + done +} + +cur_max=`sed -n '$=' $src_list` +cur_min=1 +last_max=$cur_max +while true +do +cur_src=`echo $(get_src_list $cur_min $cur_max)` +echo $file_lenth +bash run.sh $cur_src + +if [ $? -eq 0 ];then + +if [ $cur_min -eq $cur_max ];then +cur_min=$last_max +cur_max=$last_max +cur_src=`echo $(get_src_list $cur_min $cur_max)` +break +fi + +cur_min=$cur_max +cur_max=${last_max} + +else +if [ $cur_min -eq $cur_max ];then +cur_src=`echo $(get_src_list $cur_min $cur_max)` +break +fi +last_max=$cur_max +cur_max=$(((${cur_max}+${cur_min})/2)) +fi +echo "===================================" +echo "cur_min" $cur_min +echo "cur_max" $cur_max +echo "===================================" + +done + +bash run.sh $cur_src +if [ $? -eq 0 ];then + echo "bad src not found" +else + echo "==================================" + echo "bad src found:" + head -$cur_min $src_list | tail -1 + echo "==================================" +fi diff --git a/build/tools/common/bisfunc.sh b/build/tools/common/bisfunc.sh new file mode 100755 index 0000000000000000000000000000000000000000..8ad515db2dd2e18e671da73c64fca2fbe3cd9258 --- /dev/null +++ b/build/tools/common/bisfunc.sh @@ -0,0 +1,132 @@ +#!/bin/bash +bad_mpl="" +good_dir="" +bad_dir="" +candidate_type="object" +src_list=src_list.log +pwd=${PWD} +twd=${pwd}/temp_dir +LINARO=${MAPLE_ROOT}/tools/gcc-linaro-7.5.0 +fileName="" + +function parse_args() { + while [ $# -ne 0 ]; do + case "$1" in + *.mpl) + bad_mpl=$1 + candidate_type="mpl" + fileName=${bad_mpl%\.mpl*} + ;; + *) + if [ -d "$1" ]; then + good_dir=$1 + shift + bad_dir=$1 + else + echo "no such directory ""$1" + exit 1 + fi + ;; + esac + shift + done +} + +function get_cur_func_list() { + echo > ${twd}/temp_func.list + min=$1 + max=$2 + line_number=1 + src=" " + cat ${twd}/$src_list | while read line + do + if [ "${line_number}" -ge "${min}" ]&&[ "${line_number}" -le "${max}" ]; + then + echo ${line} >> ${twd}/temp_func.list + fi + line_number=`expr $line_number + 1` + done +} + +function compileMpl() { + #echo "cur parto2list:" + #cat temp_func.list | lolcat + $MAPLE_ROOT/output/aarch64-clang-release/bin/maple --partO2=${twd}/temp_func.list --run=me:mpl2mpl:mplcg --option="--O2 --quiet: --O2 --quiet: --O2 --quiet --no-pie --verbose-asm" ${twd}/$bad_mpl &> comb.log + $LINARO/bin/aarch64-linux-gnu-gcc -O2 -std=c99 -o ${twd}/${fileName}.o -c ${twd}/${fileName}.s +} + +function asmMpl() { + cat temp_func.list + python3 replace_func.py good.s bad.s ${twd}/temp_func.list > ${twd}/newgood.s + $LINARO/bin/aarch64-linux-gnu-gcc -O2 -std=c99 -o ${twd}/${fileName}.o -c ${twd}/newgood.s +} + +function main() { + rm -rf ${twd} + cp -r $good_dir ${twd} + cp run.sh ${twd}/ + #cp replace_func.py ${twd}/ + #cp good.s ${twd}/ + #cp bad.s ${twd}/ + if [ "$candidate_type" == "mpl" ]; then + grep -E "func &.*{$" $good_dir/$bad_mpl | awk '{print $2}' | sed 's/&//g' > ${twd}/$src_list + else + sed 's/ /\n/g' $good_dir/obj.list > $twd/$src_list + fi + + obj_list=`sed 's/ /\n/g' $good_dir/obj.list` + cd ${twd} + file_length=`sed -n '$=' $src_list` + + cur_min=1 + cur_max=$file_length + last_max=$cur_max + while true + do + get_cur_func_list $cur_min $cur_max + #echo $file_length + + echo "===================================" + echo "cur_min" $cur_min + echo "cur_max" $cur_max + + #asmMpl + compileMpl + bash run.sh $obj_list + + if [ $? -eq 0 ];then + echo -e "\033[32mSUCCESS \033[0m" + if [ $cur_min -eq $cur_max ];then + cur_min=$last_max + cur_max=$last_max + get_cur_func_list $cur_min $cur_max + break + fi + cur_min=$cur_max + cur_max=${last_max} + else + echo -e "\033[31mFAILED \033[0m" + if [ $cur_min -eq $cur_max ];then + get_cur_func_list $cur_min $cur_max + break + fi + last_max=$cur_max + cur_max=$(((${cur_max}+${cur_min})/2)) + fi + echo "===================================" + done + + #asmMpl + compileMpl + echo "===================================" + bash run.sh $obj_list + if [ $? -eq 0 ];then + echo "bad func not found" + else + echo "bad func found:" + head -$cur_min $src_list | tail -1 + fi +} + +parse_args $@ +main \ No newline at end of file diff --git a/build/tools/common/maplec b/build/tools/common/maplec new file mode 100755 index 0000000000000000000000000000000000000000..673500285d33bc9876a82d75892952c0f00f6028 --- /dev/null +++ b/build/tools/common/maplec @@ -0,0 +1,260 @@ +#!/bin/bash +src_file_path="" +target_name="" +file_name="" +option="" +obj_list="" +src_list="" +pre_process=true +compile=true +assemble=true +link=true +out="" +std="-std=gnu99" +list_mode="false" + +# config fe compiler +use_hir2mpl=true +use_clang2mpl=false +# config maple optimization level +use_O2=true +# config mpl or bpl +use_bpl=false + +if [ "$use_bpl" == "true" ];then + WHIRL_OPT="" + suffix="bpl" +else + WHIRL_OPT="-a" + suffix="mpl" +fi + +# preifx directories +OPENSOURCE_OUT=$MAPLE_ROOT/output +MAPLE_BIN=$OPENSOURCE_OUT/aarch64-clang-release/bin +TOOLS_ROOT=$MAPLE_ROOT/tools +TOOLS_BIN=$TOOLS_ROOT/bin +LINARO=$TOOLS_ROOT/gcc-linaro-7.5.0 +GCC=$LINARO/bin/aarch64-linux-gnu-gcc + +# compile flags +ISYSTEM_FLAGS="-isystem $LINARO/aarch64-linux-gnu/libc/usr/include -isystem $LINARO/lib/gcc/aarch64-linux-gnu/7.5.0/include" + +# maple options +O2="--O2 --quiet:--O2 --quiet:--O2 --quiet --verbose-asm --verbose-cg" +O0="--O0 --quiet --verbose-asm --verbose-cg" + +# whole cmd of maplec.sh +SELF_CMD="${0} ${@}" + +while [ $# -ne 0 ]; do + case "$1" in + -O2) + use_O2=true + ;; + -O0) + use_O2=false + ;; + -hir2mpl) + use_hir2mpl=true + use_clang2mpl=false + ;; + -clang2mpl) + use_hir2mpl=false + use_clang2mpl=true + ;; + --list) + shift + list_mode=true + src_list="$1" + ;; + -v) + exit 0 + ;; + -b) + WHIRL_OPT="" + suffix="bpl" + ;; + -o) + shift + out="-o $1" + ;; + -I) + shift + option=$option"-I $1 " + ;; + -isystem) + shift + ISYSTEM_FLAGS="-isystem $1 "$ISYSTEM_FLAGS + ;; + -c) + link=false + ;; + -S) + assemble=false + link=false + ;; + -E) + compile=false + assemble=false + link=false + ;; + -include) + shift + option=$option"-include $1 " + ;; + -gcc) + shift + GCC=$1 + ;; + -Werror) + ;; + -fno-pic) + O2=$O2" --no-fpic" + O0=$O0" --no-fpic" + ;; + -ffunction-sections) + O2=$O2" --function-sections" + O0=$O0" --function-sections" + ;; + -mgeneral-regs-only) + O2=$O2" --general-reg-only" + O0=$O0" --general-reg-only" + ;; + -f*) + ;; + -*) + option=$option"$1"" " + ;; + *.c) + src_file_path="$1" + ;; + *.mpl) + src_file_path="$1" + pre_process=false + ;; + *.s) + src_file_path="$1" + pre_process=false + compile=false + ;; + *.o) + obj_list=$obj_list"$1"" " + pre_process=false + compile=false + assemble=false + link=true + ;; + esac + shift +done + +# flags for clang +CLANG_COMMON_FLAGS="-U __SIZEOF_INT128__ $ISYSTEM_FLAGS" +CLANGFE_FLAGS="-cc1 ${std} -emit-llvm -triple aarch64-linux-gnu -D__clang__ -D__BLOCKS__ $CLANG_COMMON_FLAGS -fgnu89-inline" +CLANG2MPL_FLAGS="--target=aarch64-linux-elf -Wno-return-type -U__SIZEOF_INT128__" +CLANG_FLAGS="--target=aarch64 $CLANG_COMMON_FLAGS -emit-ast" + +function color_print() { + # default -S 1050 -F 0.01 + echo -e $1 #| lolcat -S 1050 -F 0.01 +} + +function excecute() { + outputFile=$target_name + echo "${@}" && echo "" + "${@}" 1>/dev/null 2>$outputFile || { + echo "" >> "$outputFile" && cat $outputFile + echo -e "FAILED:" "$@" | tee -a $outputFile + echo "" | tee -a "$outputFile" + echo -e "[whole compile cmd]: "$SELF_CMD >> "$outputFile" + echo "" >> "$outputFile" && echo "" >> "$outputFile" + exit 1; + } + echo "" +} + +function hir2mpl() { + # generate .ast + color_print "Starting ast for $src_file_path:" + excecute $TOOLS_BIN/clang $CLANG_FLAGS $option $src_file_path -o $file_name.ast + # generate .mpl + color_print "Starting hir2mpl for $src_file_path:" + excecute $MAPLE_BIN/hir2mpl $file_name.ast +} + +function clangfe() { + # generate .B + color_print "Starting clangfe for $src_file_path:" + excecute $OPEN64BIN/clangfe $CLANGFE_FLAGS $option $src_file_path + # generate .mpl + color_print "Starting whirl2mpl for $src_file_path:" + excecute $OPEN64BIN/whirl2mpl $WHIRL_OPT $file_name.B +} + +function clang2mpl() { + # generate .mpl + color_print "Starting clang2mpl for $src_file_path:" + excecute $MAPLE_BIN/clang2mpl --ascii "$src_file_path" -- $CLANG2MPL_FLAGS $option +} + +function c_to_mpl() { + [ "$use_clang2mpl" == "true" ] && clang2mpl && return + [ "$use_hir2mpl" == "true" ] && hir2mpl && return + clangfe +} + +function maple_to_asm() { + color_print "Starting maplecomb for $src_file_path:" + run_exe=mplcg + maple_option=$O0 + [ "$use_O2" == "true" ] && run_exe="me:mpl2mpl:mplcg" && maple_option=$O2 + excecute $MAPLE_BIN/maple "--run=$run_exe" "--option=$maple_option" "${file_name}.${suffix}" --save-temps +} + +function asm_to_obj() { + color_print "Starting asm for $src_file_path:" + excecute $GCC -std=c99 $option -c "${file_name}.s" $out + echo "" +} + +function init() { + src_file_path=$(realpath $src_file_path) + target_name=${src_file_path##*/}".err" + file_name=${src_file_path%\.*} +} + +function c_to_asm() { + init + # generate .mpl + c_to_mpl + # generate .s + maple_to_asm + # generate .o + asm_to_obj +} + +function link() { + target_name=${out##* }".err" + echo -e $obj_list > obj.list + echo -e $GCC ${std} $option $obj_list $out > link.cmd + color_print "Starting Link ${out##* }:" + excecute $GCC ${std} $obj_list $option $out +} + +function asm_list() { + cat $src_list | grep "\.c" | while read line + do + src_file_path=`echo ${line} | awk '{print $NF}'` + c_to_asm + done +} + +init +[ "$pre_process" == "true" ] && c_to_mpl +[ "$compile" == "true" ] && maple_to_asm +[ "$assemble" == "true" ] && asm_to_obj +[ "$link" == "true" ] && link + +rm $target_name +exit 0 diff --git a/build/tools/common/replace_func.py b/build/tools/common/replace_func.py new file mode 100755 index 0000000000000000000000000000000000000000..32dd095547c529cbb898068a4649618a5230f379 --- /dev/null +++ b/build/tools/common/replace_func.py @@ -0,0 +1,151 @@ +#!/usr/bin/python3 +import sys +import os +import re + +funclist=[] +funcMap={} +buffer='' + +class AsmFunc: + funcName = '' + start = 0 + end = 0 + funcId = 0 + totalLine = 0 + realLine = 0 + blankLine = 0 + varRegLine = 0 + aliasLine = 0 + commentLine = 0 + funcInfo = 7 + locLine = 0 + otherLine = 0 + source = '' + locList =[] + + def __str__(self): + return '\n'.join(['%s:%s' % item for item in self.__dict__.items()]) + def calc(self): + self.totalLine = self.end - self.start - 1 + self.realLine = self.totalLine - 1 - self.funcInfo - self.blankLine - self.varRegLine - self.aliasLine - self.locLine - self.commentLine + + +def binarySearch (arr, l, r, x): + while l <= r: + mid = int(l + (r - l)/2) + # 元素整好的中间位置 + if arr[mid] == x: + return mid + # 元素小于中间位置的元素,只需要再比较左边的元素 + elif arr[mid] > x: + r = mid-1 + # 元素大于中间位置的元素,只需要再比较右边的元素 + else: + l = mid+1 + # 不存在 + return -1 + +def readFunclist(file): + global funclist + with open(file, "r") as f: + for func in f: + funclist.append(func.strip()) + funclist.sort() + +def isMatch(name): + global funclist + index = binarySearch(funclist, 0, len(funclist) - 1, name) + if index != -1: + return True + return False + +def exportToFile(list, file): + f = open(file, "a+") + i = 0 + while i < len(list): + f.write(list[i].source) + i += 1 + f.close() + +def processAsm(mpl): + global funcMap + with open(mpl, "r") as f: + infunc = False + match = False + flag = False + curfunc = AsmFunc() + for ori_line in f: + line = ori_line.strip() + if not match: + if line.endswith("%function"): + funcName = line.split()[1][:-1] + match=isMatch(funcName) + if match: + func = AsmFunc() + func.funcName = funcName + funcMap[funcName] = func + curfunc = func + continue + else: + if not infunc: + if line == curfunc.funcName + ":": + infunc = True + curfunc.source += ori_line + else: + curfunc.source += ori_line + if line.endswith(curfunc.funcName + ", .-" + curfunc.funcName): + infunc = False + match = False + +def repaceGood(mpl): + global funcMap + with open(mpl, "r") as f: + infunc = False + match = False + curfunc = AsmFunc() + for ori_line in f: + line = ori_line.strip() + if not match: + print(ori_line, end='') + if line.endswith("%function"): + funcName = line.split()[1][:-1] + match=isMatch(funcName) + if match: + func = AsmFunc() + func.funcName = funcName + curfunc = func + continue + else: + if not infunc: + if line == curfunc.funcName + ":": + print(funcMap[curfunc.funcName].source, end='') + infunc = True + else: + print(ori_line, end='') + else: + if line.endswith(curfunc.funcName + ", .-" + curfunc.funcName): + infunc = False + match = False + +def main(): + if len(sys.argv) < 4 : + print("args count less than 4") + return + global file1 + good = sys.argv[1] + bad = sys.argv[2] + readFunclist(sys.argv[3]) + if os.path.isfile(bad): + processAsm(bad) + else: + print("file not found") + if os.path.isfile(good): + repaceGood(good) + else: + print("file not found") + + +if __name__ == "__main__": + main() + diff --git a/build/tools/spec/bis.sh b/build/tools/spec/bis.sh new file mode 120000 index 0000000000000000000000000000000000000000..5eaf823ba64478e16393288c6c6e72c1b9269495 --- /dev/null +++ b/build/tools/spec/bis.sh @@ -0,0 +1 @@ +../common/bis.sh \ No newline at end of file diff --git a/build/tools/spec/bisfunc.sh b/build/tools/spec/bisfunc.sh new file mode 120000 index 0000000000000000000000000000000000000000..49fcfec73350cbd8807e54fbcc38dcf05a97e2cd --- /dev/null +++ b/build/tools/spec/bisfunc.sh @@ -0,0 +1 @@ +../common/bisfunc.sh \ No newline at end of file diff --git a/build/tools/spec/clang2mpl.cfg b/build/tools/spec/clang2mpl.cfg new file mode 100644 index 0000000000000000000000000000000000000000..76d8c154208451f5e42ea9817a237ba0f7c12c9d --- /dev/null +++ b/build/tools/spec/clang2mpl.cfg @@ -0,0 +1,687 @@ +#------------------------------------------------------------------------------ +# SPEC CPU2017 config file for: gcc / g++ / gfortran on Linux x86 +#------------------------------------------------------------------------------ +# +# Usage: (1) Copy this to a new name +# cd $SPEC/config +# cp Example-x.cfg myname.cfg +# (2) Change items that are marked 'EDIT' (search for it) +# +# SPEC tested this config file with: +# Compiler version(s): 4.4.7, 4.9.2, 5.2.0, 6.3.0, 7.2.1, 8.1.0 +# Operating system(s): Oracle Linux Server 6.5 and 7.4 / +# Red Hat Enterprise Linux Server 6.5 and 7.4 +# Hardware: Xeon +# +# If your system differs, this config file might not work. +# You might find a better config file at http://www.spec.org/cpu2017/results +# +# Known Limitations with GCC 4 +# +# (1) Possible problem: compile time messages +# error: unrecognized command line option '...' +# Recommendation: Use a newer version of the compiler. +# If that is not possible, remove the unrecognized +# option from this config file. +# +# (2) Possible problem: run time errors messages +# 527.cam4_r or 627.cam4_s *** Miscompare of cam4_validate.txt +# Recommendation: Use a newer version of the compiler. +# If that is not possible, try reducing the optimization. +# +# +# Compiler issues: Contact your compiler vendor, not SPEC. +# For SPEC help: http://www.spec.org/cpu2017/Docs/techsupport.html +#------------------------------------------------------------------------------ + + +#--------- Label -------------------------------------------------------------- +# Arbitrary string to tag binaries (no spaces allowed) +# Two Suggestions: # (1) EDIT this label as you try new ideas. +%define label maplec # (2) Use a label meaningful to *you*. + + +#--------- Preprocessor ------------------------------------------------------- +%ifndef %{bits} # EDIT to control 32 or 64 bit compilation. Or, +% define bits 64 # you can set it on the command line using: +%endif # 'runcpu --define bits=nn' + +%ifndef %{build_ncpus} # EDIT to adjust number of simultaneous compiles. +% define build_ncpus 8 # Or, you can set it on the command line: +%endif # 'runcpu --define build_ncpus=nn' + +# Don't change this part. +%define os LINUX +%if %{bits} == 64 +% define model -m64 +%elif %{bits} == 32 +% define model -m32 +%else +% error Please define number of bits - see instructions in config file +%endif +%if %{label} =~ m/ / +% error Your label "%{label}" contains spaces. Please try underscores instead. +%endif +%if %{label} !~ m/^[a-zA-Z0-9._-]+$/ +% error Illegal character in label "%{label}". Please use only alphanumerics, underscore, hyphen, and period. +%endif + + + +#--------- Global Settings ---------------------------------------------------- +# For info, see: +# https://www.spec.org/cpu2017/Docs/config.html#fieldname +# Example: https://www.spec.org/cpu2017/Docs/config.html#tune + +command_add_redirect = 1 +flagsurl = $[top]/config/flags/gcc.xml +ignore_errors = 1 +iterations = 1 +label = %{label}-m%{bits} +line_width = 1020 +log_line_width = 1020 +makeflags = --jobs=%{build_ncpus} +mean_anyway = 1 +output_format = txt,html,cfg,pdf,csv +preenv = 1 +reportable = 0 +tune = base + + +#--------- How Many CPUs? ----------------------------------------------------- +# Both SPECrate and SPECspeed can test multiple chips / cores / hw threads +# - For SPECrate, you set the number of copies. +# - For SPECspeed, you set the number of threads. +# See: https://www.spec.org/cpu2017/Docs/system-requirements.html#MultipleCPUs +# +# q. How many should I set? +# a. Unknown, you will have to try it and see! +# +# To get you started, some suggestions: +# +# copies - This config file defaults to testing only 1 copy. You might +# try changing it to match the number of cores on your system, +# or perhaps the number of virtual CPUs as reported by: +# grep -c processor /proc/cpuinfo +# Be sure you have enough memory. See: +# https://www.spec.org/cpu2017/Docs/system-requirements.html#memory +# +# threads - This config file sets a starting point. You could try raising +# it. A higher thread count is much more likely to be useful for +# fpspeed than for intspeed. +# +intrate,fprate: + copies = 1 # EDIT to change number of copies (see above) +intspeed,fpspeed: + threads = 4 # EDIT to change number of OpenMP threads (see above) + +%ifndef %{gcc_dir} +% define gcc_dir /gcc_dir-is-not-used/tools/gcc-linaro-7.5.0 # EDIT (see above) +%endif + +#------- Compilers ------------------------------------------------------------ +default: +# EDIT: The parent directory for your compiler. +# Do not include the trailing /bin/ +# Do not include a trailing slash +# Examples: +# 1 On a Red Hat system, you said +# 'yum install devtoolset-7' +# Use: % define gcc_dir /opt/rh/devtoolset-7/root/usr +# +# 2 You built GCC in: /disk1/mybuild/gcc-8.1.0/bin/gcc +# Use: % define gcc_dir /disk1/mybuild/gcc-8.1.0 +# +# 3 You want: /usr/bin/gcc +# Use: % define gcc_dir /usr +# WARNING: See section +# "Known Limitations with GCC 4" +# + LINARO = $MAPLE_ROOT/tools/gcc-linaro-7.5.0 + CC = $(MAPLE_ROOT)/build/tools/spec/maplec -clang2mpl + CXX = $(LINARO)/bin/aarch64-linux-gnu-g++ -std=c++03 + FC = $(LINARO)/bin/aarch64-linux-gnu-gfortran + # How to say "Show me your version, please" + CC_VERSION_OPTION = -v + CXX_VERSION_OPTION = -v + FC_VERSION_OPTION = -v + + QEMU_RUN = $MAPLE_ROOT/tools/bin/qemu-aarch64 -L $LINARO/aarch64-linux-gnu/libc + +default: +%if %{bits} == 64 + sw_base_ptrsize = 64-bit + sw_peak_ptrsize = 64-bit +%else + sw_base_ptrsize = 32-bit + sw_peak_ptrsize = 32-bit +%endif + + +#--------- Portability -------------------------------------------------------- +default: # data model applies to all benchmarks +%if %{bits} == 32 + # Strongly recommended because at run-time, operations using modern file + # systems may fail spectacularly and frequently (or, worse, quietly and + # randomly) if a program does not accommodate 64-bit metadata. + EXTRA_PORTABILITY = -D_FILE_OFFSET_BITS=64 +%else + EXTRA_PORTABILITY = -DSPEC_LP64 +%endif + +# Benchmark-specific portability (ordered by last 2 digits of bmark number) + +500.perlbench_r,600.perlbench_s: #lang='C' +%if %{bits} == 32 +% define suffix IA32 +%else +% define suffix X64 +%endif + PORTABILITY = -DSPEC_%{os}_%{suffix} + +502.gcc_r: #lang='c' + CPORTABILITY = -DHAVE_ALLOCA_H + +521.wrf_r,621.wrf_s: #lang='F,C' + CPORTABILITY = -DSPEC_CASE_FLAG + FPORTABILITY = -fconvert=big-endian + +523.xalancbmk_r,623.xalancbmk_s: #lang='CXX' + PORTABILITY = -DSPEC_%{os} + +526.blender_r: #lang='CXX,C' + PORTABILITY = -funsigned-char -DSPEC_LINUX + +527.cam4_r,627.cam4_s: #lang='F,C' + PORTABILITY = -DSPEC_CASE_FLAG + +628.pop2_s: #lang='F,C' + CPORTABILITY = -DSPEC_CASE_FLAG + FPORTABILITY = -fconvert=big-endian + + +#-------- Tuning Flags common to Base and Peak -------------------------------- + +# +# Speed (OpenMP and Autopar allowed) +# +%if %{bits} == 32 + intspeed,fpspeed: + # + # Many of the speed benchmarks (6nn.benchmark_s) do not fit in 32 bits + # If you wish to run SPECint2017_speed or SPECfp2017_speed, please use + # + # runcpu --define bits=64 + # + fail_build = 1 +%else + intspeed,fpspeed: + EXTRA_OPTIMIZE = -fopenmp -lgomp -DSPEC_OPENMP + fpspeed: + # + # 627.cam4 needs a big stack; the preENV will apply it to all + # benchmarks in the set, as required by the rules. + # + preENV_OMP_STACKSIZE = 120M +%endif + + +#-------- Baseline Tuning Flags ---------------------------------------------- +# +# EDIT if needed -- Older GCC might not support some of the optimization +# switches here. See also 'About the -fno switches' below. +# +default=base: # flags for all base + OPTIMIZE = + +intrate,intspeed=base: # flags for integer base + EXTRA_COPTIMIZE = +# Notes about the above +# - 500.perlbench_r/600.perlbench_s needs -fno-strict-aliasing. +# - 502.gcc_r/602.gcc_s needs -fgnu89-inline or -z muldefs +# - For 'base', all benchmarks in a set must use the same options. +# - Therefore, all base benchmarks get the above. See: +# www.spec.org/cpu2017/Docs/runrules.html#BaseFlags +# www.spec.org/cpu2017/Docs/benchmarks/500.perlbench_r.html +# www.spec.org/cpu2017/Docs/benchmarks/502.gcc_r.html + + +#-------- Peak Tuning Flags ---------------------------------------------- +default=peak: + basepeak = yes # if you develop some peak tuning, remove this line. + # + # ----------------------- + # About the -fno switches + # ----------------------- + # + # For 'base', this config file (conservatively) disables some optimizations. + # You might want to try turning some of them back on, by creating a 'peak' + # section here, with individualized benchmark options: + # + # 500.perlbench_r=peak: + # OPTIMIZE = this + # 502.gcc_r=peak: + # OPTIMIZE = that + # 503.bwaves_r=peak: + # OPTIMIZE = other .....(and so forth) + # + # If you try it: + # - You must remove the 'basepeak' option, above. + # - You will need time and patience, to diagnose and avoid any errors. + # - perlbench is unlikely to work with strict aliasing + # - Some floating point benchmarks may get wrong answers, depending on: + # the particular chip + # the version of GCC + # other optimizations enabled + # -m32 vs. -m64 + # - See: http://www.spec.org/cpu2017/Docs/config.html + # - and: http://www.spec.org/cpu2017/Docs/runrules.html + + +#------------------------------------------------------------------------------ +# Tester and System Descriptions - EDIT all sections below this point +#------------------------------------------------------------------------------ +# For info about any field, see +# https://www.spec.org/cpu2017/Docs/config.html#fieldname +# Example: https://www.spec.org/cpu2017/Docs/config.html#hw_memory +#------------------------------------------------------------------------------- + +#--------- EDIT to match your version ----------------------------------------- +default: + sw_compiler001 = C/C++/Fortran: Version 7.2.1 of GCC, the + sw_compiler002 = GNU Compiler Collection + +#--------- EDIT info about you ------------------------------------------------ +# To understand the difference between hw_vendor/sponsor/tester, see: +# https://www.spec.org/cpu2017/Docs/config.html#test_sponsor +intrate,intspeed,fprate,fpspeed: # Important: keep this line + hw_vendor = My Corporation + tester = My Corporation + test_sponsor = My Corporation + license_num = nnn (Your SPEC license number) +# prepared_by = # Ima Pseudonym # Whatever you like: is never output + + +#--------- EDIT system availability dates ------------------------------------- +intrate,intspeed,fprate,fpspeed: # Important: keep this line + # Example # Brief info about field + hw_avail = # Nov-2099 # Date of LAST hardware component to ship + sw_avail = # Nov-2099 # Date of LAST software component to ship + +#--------- EDIT system information -------------------------------------------- +intrate,intspeed,fprate,fpspeed: # Important: keep this line + # Example # Brief info about field +# hw_cpu_name = # Intel Xeon E9-9999 v9 # chip name + hw_cpu_nominal_mhz = # 9999 # Nominal chip frequency, in MHz + hw_cpu_max_mhz = # 9999 # Max chip frequency, in MHz +# hw_disk = # 9 x 9 TB SATA III 9999 RPM # Size, type, other perf-relevant info + hw_model = # TurboBlaster 3000 # system model name +# hw_nchips = # 99 # number chips enabled + hw_ncores = # 9999 # number cores enabled + hw_ncpuorder = # 1-9 chips # Ordering options + hw_nthreadspercore = # 9 # number threads enabled per core + hw_other = # TurboNUMA Router 10 Gb # Other perf-relevant hw, or "None" + +# hw_memory001 = # 999 GB (99 x 9 GB 2Rx4 PC4-2133P-R, # The 'PCn-etc' is from the JEDEC +# hw_memory002 = # running at 1600 MHz) # label on the DIMM. + + hw_pcache = # 99 KB I + 99 KB D on chip per core # Primary cache size, type, location + hw_scache = # 99 KB I+D on chip per 9 cores # Second cache or "None" + hw_tcache = # 9 MB I+D on chip per chip # Third cache or "None" + hw_ocache = # 9 GB I+D off chip per system board # Other cache or "None" + + fw_bios = # American Megatrends 39030100 02/29/2016 # Firmware information +# sw_file = # ext99 # File system +# sw_os001 = # Linux Sailboat # Operating system +# sw_os002 = # Distribution 7.2 SP1 # and version + sw_other = # TurboHeap Library V8.1 # Other perf-relevant sw, or "None" +# sw_state = # Run level 99 # Software state. + +# Note: Some commented-out fields above are automatically set to preliminary +# values by sysinfo +# https://www.spec.org/cpu2017/Docs/config.html#sysinfo +# Uncomment lines for which you already know a better answer than sysinfo + +__HASH__ +500.perlbench_r=base=maple_test-m64: +# Last updated 2021-05-10 10:36:40 +opthash=1b55f44e78c515229834a282ce9d3013fee214077130f5cc6c8d469cce53274c +baggage= +compiler_version=\ +@eNp9VE1v2zAMvftX+NYNteK26ZIigA9Z6hYD0qZI3e0YyBLtqJUlTx+J08N++2Qnjr202MWC+Cjy\ +kXy0P5utfsbL5x+Lx9XiKXHHxHvRTOR+ahk3iAlfl0D0wJst5vN4lqzuZ7MotFqFKRNhTsgRmCeL\ +1a/l9OkpXu4dOEtrh7C6Ga1G14gzYSuUCxuOQ24k2ipclqC8xd3dfDG9XSXT5X2crB6nD/FzJDal\ +qZCQAk7x2/hu+jJPoksvwSoHM/FP43szKTKWWwXU3zKznviDQagVCUlr99HGR6jGUPmWb0BpJkV0\ +9pJaYaw/HnwbXKChbW6Xfy5vBhfXZ61/al0AHmWMwyQMmzr1GisIqSR1tWgcLuPp7UM8+G5z7V6B\ +wCkHxLHILc5BRyTAFAfk/DzIZZAqlgc0yKQyCotApq+k/iAHu7elgoxVTTfb/HWKAr9KhQ60kRR8\ +1/jKXOECaZvVb9C4ZzvEOW0U6ug1NdAeXSbeQKFaBBSxGnDThAoIZeo43QMnaWudEG4pUOQmYqAy\ +XSSzVoCpjkqpWbWPcxLj4Ch4r12plEa7lpSdiXBJMIfIEe/zTLWhpKoQBTeazwDDCoh2oNsOUsiw\ +ddLuPHDKIgHb7nHdGyvYbwvIDQNIXQ5lusE2Zn+AYtnun3xFWXX3ktvcLc/x3mYtGbRE9E4bKNB7\ +10lkGkmfIIcItTbc+CNsjeyshQvKsCLrHsUtKCWPiqlBNLyK2OhmdLS5iovRdXttgrhkrgptomJ4\ +FTgwKKrh1UmiPlUr3CxAuD6QHsks4xLTQyG6t8c9sRBLMaKKuR72xrsG8uZ+PJECDljX/o36PqjW\ +AWvpaH5i32f9gHhJo0G/kBT4xG+U6LlF8g8rtN94/8t/9v+r7/0FuibFEg== +compile_options=\ +@eNrVU21r2zAQ/u5fIfxdccdGWUJdsB0l8eZEwrIh2xfhOkqqLZaD5IS1v34n56UtDFpGv1RgfLq3\ +R3fP3aLVuKl+y7XaStTuOtVqO/JsZ1TdCbPXK2XEQRq1fgj9T74HogWX0L8aDK+ufc9L6JyNkB/s\ +rQnulA42dY3cwbZbhfVw6MTm+gvCNcLtGWDQIjzmjCTwW4xJXE5BYCTPREJzgnA6gG+lbBekFKR6\ +V+mgUI3EM5VLe9bMinmGWWWsNKCSf7rASBDsTtam0itIOaZlnBHBs4jPCBcOMY2y8OqELqKyoIKX\ +jOWEc0EZWcwZ2EQW5VMiJmlG+OXqboLTMk+I0/VXOplwUog4LXgINSK8QZh+hoIrU9+HuurUAV60\ +1i3ea1utJRi6e+ya0KjHqm8FOto7IyXetu0OH2TdtUY9SnQ6p7dm6aJciqWDOcUcScLVVlVWaYBe\ +b/T+6xArvVVaPotkLujGtntTy1vfS0YoScJXKTs60vgbZUXov+DP94DzhJWTLJpysL3ksrfGZJHM\ +xMXhw5Pre3SEoBPpPP1JoKL3ZLpvGKN5EcVplhY/zh194rxHJ8sij6CJT494fQr61MfAfwIwlxtg\ +vr9lh4/Kd5/x/x3wm/buFySyt85/26DLwlzmFKF+iLPxW6b9g/IL9c2jYga5Yrdp2+ZUMi3d1j5b\ +2b8rRMvz +exehash=1c69320bf26365e65e5b19b87fd09bbfdf73b3d6257845446d6001048f92fd40 + +619.lbm_s=base=maplec-m64: +# Last updated 2021-05-12 16:29:02 +opthash=7affc07e1d7c5ca4633093daa05c20102ce1dec866120559a921160cddd58e76 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNqVUG1rgzAY/J5fEfLd2kEZTGpBY2ZdowlW2csXaV1kbmpE7WD/ftG+Ci1sIZCH3OVyd4GstHLz\ +JbK8EFDWXS6r1gBt1+RplzS76j1vkm/R5NmPie4QUGOrKCaaTh6mMwQAZj43INI/ZCn0dlfp27zS\ +y01diBRqasuj6ERCzVlzgtUROMSOXTVQK3RJ8szCFWWWAy+XlslaVGV9eJUwTgKfD8j+gvL7GYTz\ +Vu6aVCwQwAbE2LzqZA8y+4nxyEQjWwgo+5jHj9Ry1wobWxxQmwR4mZwIY88IMAOSlyi0lMPI8703\ +okhXvQ9ieypnYWTZHvWi1+OfQx4EqBesbvX5p37mcvsp0q5d9JyiPPNPkSEc+qDOrbL+kUjp+Fa0\ +TKhn9+UU5UGaxX3RFy3/AtPTsPg= +exehash=4796f3d722b9339855ae459928ddcee0650c458340a971fc905fa5338976c68c + +505.mcf_r=base=maplec-m64: +# Last updated 2021-05-12 17:04:02 +opthash=cd00cc44466c7c00fcb0a07a84b8bdec510af969b5da706b722633229c2d2efc +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNqNkF1PgzAYhe/7K5reM2aiJpKxBApuaKENH4leNRt2EQWKFEz89xYEdYsa3zRpk3PanvNEsjaq\ +3bM4FKWAsukKWSsLqK4t8o63ff1QtPxVtMXhzUZnCOij0hYbLRdXywsEAKYhsyAyH2UlTNXX5r6o\ +zWrXlCKHhl5yfnQhoeElzMd6izzfzTYQGoFqRM5flGy7SeVOllKeZIzFfpJwyvwoZPBkJithl+cQ\ +rpTs21ysEcAWxNj+McuHSN0bylIbHQVDQBfALLsmzibR2nHIUXX9CG85nh3/TD1e9e/S2OGMxqnj\ +BiRI7+cfxvQIkCC6/Y3fyazk/knknVoPBMrqi8ZnFQjHnsT7A0LopFtOAncoUlaTn2YDlW9I3gG2\ +95r+ +exehash=806db0e68b5994ed49999cc86262dbea2e13c31853d3ba087eb2f180c940ee06 + +502.gcc_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=2839b1967320158040c55387a370c4661288143e5e404dc55ea5be68a750538d +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNq1kV9PgzAUxd/5FE3fGdM4E5exBLoOqqxtBhh9ajbWxSrQScHEby/g8M+ivnnTpjc5J7f9nVJd\ +2sXmSe5VLoE+1EqXZmqZulJZLaqm3KlKvMhK7V9deAattjWtxYXj0dV4Ai0LsRWfAug86EI6pimd\ +rSqdYnPIZQbsdulh6EgDexFzjNqDLrCfBsAmo247qszyZif73hxkJp6NruqjXUzG50PrpQkTccr5\ +GsexYBzTFW81QkWAurmhd4sFYnRJAhGC0zoOifjlBQAzo5sqk3NooSlAyP2R4F1k/jXjiQu/4UCr\ +xUY8XUZeELfad7Re9TFFoRgM/8ra34fvkrUnOFsnnk8iktwPz+qRoRURevPbV53UTG8fZVabeRdb\ +XnxG+MEPQB9OtPgjuZWXhCIifoefF0c/S7sov+T4BmRTt5k= +exehash=0 + +520.omnetpp_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=be6e4dd67b5187b3cefa0f68d2b9d0de0da20ab650fd3c3ee25c7e2e09cbff32 +baggage= +compiler_version=\ +*IENYWENfVkVSU0lPTl9PUFRJT046Ci9iaW4vc2g6IENDOiBjb21tYW5kIG5vdCBmb3VuZAo= +compile_options=\ +@eNq1UNFOgzAUfe9XNH1nzkRNJGMJlLqhHW2gjfjUTOgSFCgBZuLfW3E45rv3pTfnnt57zolN49T7\ +d30oKw1NO5Sm6V3QD12ZD6o7NkXZqQ/dlYdPD10jYNveUjy0XNwvbxEAmO24CxHG0MmhY6YVCwOd\ +MOXEwmEckkBuoBP1ZX2s9oPprlr7FLqdY7avTaEr++E5ElsVExHIiIYkOW1SvhRMpZLzhKSpYpzE\ +Ow7PdWJRfncD4ao3xy7XawSwC3GWeVbh1LPgkXHhoQvBCFgbmMsH6m9SO7sUP04DEuOtmgj/4WY8\ +QzKR+IqzRPhBRCPxMqkZrSFAo/jpJ/E/tTKvbzof+vUcPDuEcAyAhr9Z0JDJ7xxmIXwBBSCXiw== +exehash=0 + +523.xalancbmk_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=a5f92e3f29c9a9dc5714dc66815a936b3270df34bf15c51d6007f825c19a3bfd +baggage= +compiler_version=\ +*IENYWENfVkVSU0lPTl9PUFRJT046Ci9iaW4vc2g6IENDOiBjb21tYW5kIG5vdCBmb3VuZAo= +compile_options=\ +@eNrtU9FumzAUfecrLL8TuqmbtKip5ICX0tnYwmaiTxZ1aEVHcIVJ1f59HZhTsk1969ssIZ17z8G6\ +3HPITBfuql/1XdPWwDwOjensMrBD3+hB9ftu2/Tqqe6bu5cV/AQDB62TrODZ4tvZFxgEMaN8CWAc\ +g1CD0PgrFgaEieDYtZMswetiAxxCnKuMKXmVY5QI1ygRQZlKM4qpomKjCEMJzkGYLtzzXPe6tvoN\ +RVuzO62iZvfYzlq2ep5V+6FpI2rviam2bu4o7Wi9M/3LnxLZV53VZtJo0z0dBFVbdTpqOt3ut7Ub\ +lefsWpWUcJSLw4jHRiFT4suJFL4UqDyPZ8VnjxNGPfyJSJogyca33HWqENhvBAuBNtgvZdynQoVk\ +ShSc545VjOOMcnA4v3mSZkV50uBfzwG4sGbvPvkSBvESxGW5cpZ5zNbXjMsVPHEQBs7XmBffCdoI\ +x526ObJrnMVXyl1w1Pw3+GMMHtfNWS7ROiWpvPF+TG6PLC5ljtQ/NS4AMHDKH9OP+nb+isyFuX2o\ +9WAvwVx1zAQAY2RIMqXn/ZlGISsOuZqF6hW+xlPZ +exehash=0 + +525.x264_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=17555907b69668487c703e8ad30fdca935346ca79afa0bfdc1ae288920733ee3 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNrtkt9vgjAQx9/5K5q+I+rUbUZMAJmyIW34kcynBrFu3YCagsb990PEDc22V/dA06TX3l179+nX\ +4amchO90zWIK+CZnPM2GUpYLFuVEbNMVE2RHBVt/qLADpcLMihAVtlv37T6U0DEDrLkALAlf6C6M\ +2SrMKel3+0NJMtAcDwFUXnlClWybKkuWKkm4iWkE5GLy05stDuSJh02jWJyJqQdTIFvxikZ8RTIR\ +KSwtoq19d9A7bGumQve5CLP6ScSThKfVfUQLfES8AGPX9DyCsOnM8ZlPX/gmciemq7b3ne5Nrz+4\ +vQOXo0qw8aAHwCjjWxHRMZSMITAM9cf+jk6kPyLsq/CsWSgVUAwcPNja1Ct8542XXt10jBk5BVyR\ +RFmN+ey7GsHI9TXdsi1/cSq6BAIl23KefvvmizHiyzca5dn4ADVOvgF/0QGgRGdP/uA61/wZsS39\ +ACdOqngUHEDXKNfVWREUjSgbUf4bUZZMGkk2kryuJD8BghRXuw== +exehash=0 + +531.deepsjeng_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=c9d27d3cf5376f585e57a3f2a29ee65eb5a8ddb7a1042d47749d036bb8f42043 +baggage= +compiler_version=\ +*IENYWENfVkVSU0lPTl9PUFRJT046Ci9iaW4vc2g6IENDOiBjb21tYW5kIG5vdCBmb3VuZAo= +compile_options=\ +@eNqNkF9PgzAUxd/7KW76zjKTxUQylkBbJ1poQyFhT41il9Q/1AAz8dvb4ZDNJ+/T7T2nvb/T3LXB\ +++Or2ds3A+5jsK7tQ9QPnW0G3R3aZ9vpT9PZ/VeErzDybe8tEV4ubpYrjBARmQwBEwJBA4Gbnlg4\ +CKiSzI9pTllSbY/nLOZcZywTxe4k67gqhVaVlAVTSgvJ8kzCXCcXl9crgHXvDl1jNhiREEhdR37t\ +1IvkXsgywhcUGHk2IqtbHm+V1y6JRjVhObnTs+GfiONdVpdFrKUoyjhJeVruphUjL0Y8zR9+/uZP\ +rd3Ti2mGfnM+nLEBxlSc/gbkVFTHcGfJvgF3B3iC +exehash=0 + +541.leela_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=c715a7e7b712428302fadbd8205a3f5ff13d2a99dbcb03cfef4de14ebb0dbb76 +baggage= +compiler_version=\ +*IENYWENfVkVSU0lPTl9PUFRJT046Ci9iaW4vc2g6IENDOiBjb21tYW5kIG5vdCBmb3VuZAo= +compile_options=\ +@eNp9kE9LxDAQxe/5FEPuKSuoYNkutElcq9kktCnUU9CahfqnkbYr+O2NdevuenBOw5uXmd+L9B15\ +e3hx2/bVgX8fW98NMRrGvm1G2++6p7a3H65vt58JPsMotEOwJHgRXS0uMEJUbXQMmFIgDRA/r4g8\ +EFZqHmQmGc+qNZA82ms2rYyyZaV1wcvSKs3lRsOh9i6hL88BloPf9Y1bYURjoHWdhFtzr7JbpU2C\ +T05jFICorq5Fui7D7BRjmmZc0hs7G/7nmh7w2hSp1aowaZaL3NzPeydIjEQu735+4U8t/eOza8Zh\ +dSweWAGmKIL9phJMVd+JjuJ8ASVmcYc= +exehash=0 + +548.exchange2_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=7c95017cd71c6e94420e5cb70d3cc0a48a81eb16a8246cb031329e6470ab6a5c +baggage= +compiler_version=\ +*IEZDX1ZFUlNJT05fT1BUSU9OOgovYmluL3NoOiBmOTA6IGNvbW1hbmQgbm90IGZvdW5kCg== +compile_options=\ +@eNq9kEtPhDAUhff8iqZ7yJioCWSYhEcZ0Q5teCS6apQpSX3QhjJG/fUWBhmcuLab3vae2/OdZrK1\ +3x5feCNeOZCqF7LVnqX7TtQ96w7tXnTsnXei+fThBbRMqY3EhyvHXV1By0oo9QDUitdKATsuKIrM\ +lsUorLbTmQVVSVhRUZqjomCEomxHf3qYXl+CtZaHruYbYMu5dhqlxBffO437AS1jEtEqwcG28OGZ\ +zdgNURbdsF+CP31HMbov84BRkpdBmOK0fJhHBhxoRWQ3pGrcFbDrAWr6GEeCmc+oPJBE/qA61iS8\ +JbQ0Ty1H/hsdp9ndhH621vLpmde93iwvT6AAjClwfEqEY1INeRZhvgFuXpvb +exehash=0 + +557.xz_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=34d1fd17d5aa193e0a6a2c6e3f3472c24b4e41ed9de1aafdefcd23008f8b6564 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNrtk1tPwyAUx9/7KQjvXTcvUxdr0gtu1a6QXsz0hXQMHVrK0nZG/fSy6Uw7L59AAhz+nMNJzvmF\ +SJWmzJ/4vSg4UKtGqLIeGXVTCdbQal0uREWfeSXuX204gIY+1jrEhv3eWX8IDcPDUzIC0Foqya16\ +XVpzUVoyXxWcAVNPtUvaU8D0E4I8bSIfudn4U1MnSzF1b1OEYx/Fdv9lcHB4dDw8OdUBE+cGUQ9H\ +l8GYTuzB7skUTWmAd2p210mVZITEKEkoJiiaEmAGPb3qFWdUckmF2qhlbh5oy5SUqtSHQsyLN5lb\ ++Uq01GZryW/RbMnZU0vXQurKWxcLXjR5J2FLVHn5wJla8Arsj896QjI8AuC8VuuK8QtoeCPgefaP\ +3f5wYvcKk9SGndZDQyPySHYZOuNE+7oYtl4XRd6EdgL+ufBq2xs0S2OHEhynjhuEQXr71aENHmiE\ +QXT92xfYG+dq/shZU190WH+BAmBLMfT/QBz6ONsAbtF9B8AAJ6o= +exehash=0 + +999.specrand_ir=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=2b6f45155529ef0ee94c19b9445375b5551207252ee5fb82fdcb9fe4f6f19a4c +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNp9kFFLwzAUhd/zK0Leu04UwbIO2rTOamzC1oI+lS7LMLomJWkF/72xo2KLermQwDm5+c7NtfKa\ ++k0c5UlA3XZSKxsA2xnJu8r06iBN9S6MPH6E6AIBd7XOEqLl4mZ5iQDA9JEFEPkvuhG+7ZW/l8pv\ +6vYkOPRc63HoQkMv2bEUuyNP0rjcQC+zreCmVgeP66bRCs7r/KIi7PoKwpXVveFijQAOIMbhr5+e\ +RRrfU1aEaEKAgCPFrLwl0WbntCnNoMZpju+q0TDHGyzpU7GNKka3RRRnJCuex0kDJQIkyx/+Wsis\ +Vnr/Knhn15PI37wQDmFI8k9SktDyK+ePkJ/hnoeM +exehash=0 + +519.lbm_r=base=maplec-m64: +# Last updated 2021-05-12 17:29:14 +opthash=55e637b326098960c2f25abcffd8e22854b4464b6ae2619ebf92ce74d672f662 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNp9kF9PgzAUxd/7KZq+M2aiJpKxBApuaKENlESfmg27WAW68MfEb2/ZcMoyvWnSNufc9nduomur\ +2rzLnSol1PtO6bp1QNs1quhE09cvqhEfslG7TxddIWCOrbG4aD67m98gADCNmQOR/aorabd9bW9V\ +bVebfSkLaJmlvx+daWgFGQux2ZIg9PPVeBdezqnIcsbSMMsEZWESM3heo5ew22sIF63um0IuEcAO\ +xNi9+P1RpP4DZdxFExYEDDNm+T3xVpnRplwH1Q8TvBYTw0XQgzl84qknGE2550ck4s+nloEXARIl\ +j38N6awWevsmi65dDpnL6if/CR7CQzIS/BM79vhakMgf2Mtq9NN8mMOvIXwB6zCRCQ== +exehash=95e543602be6b0de89f9afd90aacb45d06bb7b32f0f2295d9571e3c9a893f901 + +511.povray_r=base=maplec-m64: +# Last updated 2021-05-19 14:10:44 +opthash=6681316d90fcef5a8ec9d57d1ec3590b7d32c00621a8f461b30ed5b709bb4dc3 +baggage= +compiler_version=\ +@eNq9VUtv2zAMvvtX6NYNqaKmj7QJ4MNgBNuAYCnabOstkGXGViNLmiQ3bg/77ZPtuPaaDANWrJc4\ +FB8f+YmkUHR3F62+zW5uPy++rBbXS/+ZBijaP/tquUxRXHDhMJfIamB2GESL+XwWLVcfoygkmcqB\ +PGY5yakWsFIapFWFYUB6f51SwpKUMSy4pEbhy+HF8ITEXBJKDcvG55WiKHEqC5wOBs8Q8+Vi9f3m\ +w/X17Ob1UMMhETyGElil30cmjalwCm8N1RpMsKQmBTdFe7ZBpOSap4WBBG25y6boqMnPsW2KK8YS\ +K+gDkK0yG6sp22lyugFsQAC1sBoRK6m2mXJ1xsOUu59d1vj0ZDQZjk4Ja6GO0O2n2Xwe1tXE1GYI\ +4woc55qF/wK/qi1JY08SsC7hhvDx1Rhr1hXbwazNW+CkuX4TGN9s1PYlkXgp4ZbGArx9nBfJWlDt\ +D0E2Z051gs1odf2NvyqqEWGiSCDBvmcclK4zleIZxz5aBzl+8uF7YPZe3GMoGWjHlbSdZ5VWIfmP\ +ArCK74H1gvqCNmAaejB/kbqvnZWlrzvrHNhk0hOEYlRA2BDyHLJ1TCAu0p5CybT+acvw7ioNpWpl\ +rUVP4nYntRnlhXC8KXkXcc1LzJTxPGF6cYavzi4ux5M/q8/PzkeTNnw1jSE1+cMVpp2LywzQxIZa\ +WV52xzV05XGoTMdzCB/hBeFc+sbxXON1IVl1IS1ww7W/QqOUe02P7kLY/S3U65PXgvxtEA6sQM8M\ +6/VIBmzjn4BwF7p3oXGVvTO/DQeVaUFTsCE7ZoPB8dpfn6HyuBmaOpnw0DBmyrqDCldv3/AQRdqA\ +75D/SU6wrNsJ5SoBMUV1UwV+S6MHMLZqifq1QO/m9cJG/jFEvaX9HgW/AHQUm+k= +compile_options=\ +@eNrtlFFPwjAQx9/3KZq+Lt1mRI2EkcA2ER1bw7YEn5pRCkyhxXYY+fZuAxTUxAcToskuWXrJXde7\ +37X/QHC0TJ/YNFswIFZ5JrhqaiqXGc2JXPNJJskLk9l0Y8MzqBWuKlJsaBnXVgNqmhMOcBNAcy6W\ +zNzMl+YyXS0YESvGlVhLyswDNxdiocwZpWiR8VQKdGVcGJY5zriZppLOLxtlYP2KZnyNZroOSkMq\ +n9hU161zgChAYl+lIQByI+w5xRK4XjfpAdSfSsFzxieFO04VKxaj+NSKUfKshMx3W0gniUMSJRgP\ +vSgiIfaCAQYftsvy8WUDgNa2+jbUnCZwRiP7NN3ujwu7dyGObXjUPNQK6g5ObvxOLypixyCqaNcL\ +nFuyT/gVmep/3igedggOh3Gn2/f78cP+2AoT/HoTykYrPvR0g/txfI79bYXb4H9B7feD+5M9uk/W\ +EuNHRnPVPgL+TguACqXvnvKV+G6YlGM7mFktTLUw1cJUC9OfE6Y3nDbadw== +exehash=0f4659ece5065638b9268e65a56d231636b83a05ae00d17df9bf1a2ae7112f8b + +538.imagick_r=base=maplec-m64: +# Last updated 2021-05-31 19:30:05 +opthash=54a10f343892c95817762d047800af2eccb783c0e3ff864fcef7d0ae46bd6135 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNrtkdFqgzAUhu/zFCH3agdlMKkFja51iyZohO0qtC5lbmqK0cHeftbqtpatDzAWAgk5fw7f/59Y\ +1Ua1eZW7opRQ7dtC1doGum2KvBVNVz8VjXiTTbF7d9AVAv1V9xIHzcyb2RwBgGnEbIisZ1VJS3e1\ +tS1qq9rsS5lDo99qamoqaPgpC3B/xH7gZStohOb4JtyMU5FmjCVBmgrKgjhi8HyNWsKu5xAutOqa\ +XC4RwDbE2PkR4Vik3h1l3EEnPAj03Jhlt8RdpX3tlG2oekGM12ISXIYdPgQPPHEFowl3vZCE/HHq\ +OzAjQML4/rewztZCbV9k3urlwXdZfWXwaQDCwR3xL1iPXL4WJPQO/GU16ml2yOJbEP9D/AND/ABB\ +Sw9g +exehash=facef3555a82b36cc7e8d92e422f6bffa9ea772e21800b4dd646cd8aa6e6eb36 + +500.perlbench_r=base=maplec-m64: +# Last updated 2021-06-02 10:59:30 +opthash=907b382deeffec61ac5b9a27df38c7435aa5d83bcabdd7e546b4199881462251 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNrVUtFqgzAUffcrgu/WDkZhZQ40TatbaoKJ0D0Fa1OWrWpJ7Nj+ftG1doWOPU+U3HvO8YZ77k2b\ +2quKN7lVOwmafaua2kwd02pVtkIf6o3S4l1qtf0M3BvXsaGxksAdj+7GE9dxIFnSKXD9l6aSvjnU\ +/lrVflXsd7IEnn2bU9FRA7wZowjaI52hKF/YgKIMC0gyBLxkZL+NMq2fEBuV+6L2uaqkF6tMmhMS\ +8yX2aKGN1BaSH62vpQ3MXpa6qDe25IzkEUaC4ZDFiInuxiTEwfh4uwhzTgTLKc0QY4JQlC6p5QQO\ +swUS8wQjNqRdJhjJM4g6rE/JfM4QF1HCWTC5BcNzLI+TNF+J1cCcYNoh96Y56FI+uA6cAgiDq7Z9\ +kyR6JJQH7oWHrmO9hjSf43DBLHfpZ89GKIWxGAT/3uC+KUoyHkYJTvjzqeuz0b0CrXgWiqs62kms\ ++um3Nf1jhvfN+lWWrXnoBLvqLB7GAkA/Mzz7baB/t2B/X4Y8tlDUzW1XHSuSvNuBHwvwBanrEMs= +exehash=51357adb393d1e80ce358878f264dc9f58399d0c7c71acd7c4834ae0d4c6d3e4 + +600.perlbench_s=base=maplec-m64: +# Last updated 2021-07-08 13:59:25 +opthash=4a435f7f3d851ba39439680b2f6c3962466eabafd26d686251cc537e642df2bf +baggage= +compiler_version=\ +@eNo9T0FugzAQvOcVfIC6h6qHSjmAWYIlB1s2VLlZBLaqVcCWoVWfX7ttcljtzOxoZzej1LyC0ky0\ +RsgutpcDeXcLkmuwI5Jl8DMS4XEtwgd1i7czBnL9tPNEdufmjWwexz/bmOWVlkBjayso+1MEEhQ3\ +VCjIcvYQa7LbTpiIaPTDSjq7YN5YhdtNabozz+UQNgxRwu+dBIwgpYRhneLKSvQlB6N5oRvQJiWy\ +gh8f48jwQp3A1IyDvtPEjBa9opC0XyrqWkNnStbp4/PT/92Gs7a/mEsS3lx8efG3iZDQnuXdJ5Pl\ +6/ADa+5hBw== +compile_options=\ +@eNrVUk2PmzAQvfMrLO6EVKp6iJaVwHGCWxNbYKR0LxYhjkoXMLJJ1f77DqTJ7kp72u1lEYj5eH4z\ +fjM70wdd9ahPTauRGcbG9G7ludE29ajsuT82Vv3Stjn9ifxPvgemAwjYi+Vy6Xse5plYIT/8YTod\ +HuCUDrtqaHXIB93H9hGbbgBqGx7OTXsMR2NaF7pB1xdYjQJ4zbXywqBgXQiC4bdbk6TcgiFIzhTm\ +OUEBXcB3bNwYUg5WPVR9KJtOB2mTa3eNpDJjgais0xZC+vcYWg3GVNVW/REo17xMGFEFi4uUFGqq\ +SGMWLSGlWJxvidpQRoqbO3mq4GWOyRSbXb7ZFESqhMoi+vIZ3Z7LBRSju3Kv9nMmOBlQoxuuOS7I\ +LhPPwWLC3TlztrW+9z28QhhHb1f1wsCTr1zIyH8hse/BvLAoNyzeFpB7KfecTcgOp+oG+BD6z40L\ +nss4oYzK79ebPc3B9/gKkb3MY9Bf0ow+EAC9OpmZ7AJ9lVJMbED87V2b/6aVuTOHn7oe3f2Eabsn\ +ituAEZqnz9bv2p//qia0k8UyhdPJtFFt969DXk7b+Ww1/wKvBF+R +exehash=d2d00cc9f02ff885cbbaa84d0ca4c454e358751556a1d406920eb0d884eddc13 + +602.gcc_s=base=maplec-m64: +# Last updated 2021-07-08 14:13:46 +opthash=2b044efddeb93a2f639d7b416bfe4d7dffc256240a57f0bb58e0d756048efe18 +baggage= +compiler_version=\ +@eNo1jVEPgiAAhN/9FfwBorXmQ2+GpGwFLMtXlkjLBUKo/f6w8uF2d9t3O4CxrMm5opxJLi7Rdgl6\ +OKtREzqlkb15oxH3us/CEzvrO6MDaqbOtGh0zgxo8Fr9MAVgXgmCo7Gc7K8FgHQ1C3W9MlOrv3nm\ +5WtwYfzjMl1vYqRMFnjelllNJObsQAtZAnh38dz6BeaCsJNY2lGkWwDfyQcMLD2L +compile_options=\ +@eNqlUdFOgzAUfe9XNH1nTGP2QDYT6BhUgZKNGfWl2VgXcUCxBRP/3gJDt8QHdU2b3vSec2/vOZEo\ +jWJz4Pss51BUdSZKZQFVyyytmWzKXSbZO5fZ/mOGrhDQodIQHY/G4zECANMwtiAyX0TBza1mcbPY\ +VDk3acVLWx6wKCpdWprbJst3Zi1ErkxV8bSHpdDQWwydRwIa81XsYn1Fc9dZe9Ago/aYWZnmzY53\ +cctnb0rI+ghnk/G1DknEPNxyffvBZZhGC+IxH54uYy/0x4pqINLYjcK4y/QPQTy5gXCqRCNTfosA\ +tiDGs/8P2Fegzh2Nkxk6mxYBLR2O14vA9lY6dz55l3XcCPtsAFwsBQLUgu5jsrT14AkJybOry/4o\ +Sde+h8Z0mdgOCUjyNPyykwmBgET3F7n/K2+mYvvK01rdtpi8+MZ/KQlhJ3Mwv8ioP2ijm4V24rOA\ +OK0xeXHsT9etyScOfwKElQZx +exehash=fbf53d23cd71f67cdb1656653f9f52d792b67aecc01a767deb20944e23e43b6a + +625.x264_s=base=maplec-m64: +# Last updated 2021-07-08 14:14:34 +opthash=d40a7799bcf65d95bfb5aa310bda263a121e6e86a0a7c7cbe07f1d48ebad6dd9 +baggage= +compiler_version=\ +@eNpNjkkKwjAYhfeeIhcIv0OtIrjoEKSgTahVcBXaNGIwaUJapce3ooKrN/DxeChJ+JkUx4zmnLJy\ +lM0EbtZIqL0SEkzltATqZBv5e2KNU1p6qB9KN9BbqzvonBQfTCCcHhlJRslTEp92CGe6kcI2vPMC\ +VDsC2TAPg3f8syCH3lfdfyOsMbb97vHoVFIeX0pCi5QU2+kwmy+CZbhaI3y14zXjfiRlJD+wX9qz\ +MED4OXkB41NIsA== +compile_options=\ +@eNrtU9FugjAUfecrmr5j1Tm3EDUBZNoNKFFM5l6IYs2YlJIWF/f3K6ibJnvYZvawhIakl97Te9tz\ +enye6WyxoeskpYDnRcIzaWiyEElcRGKbrRIRvVKRrN/6sAU1FUoFUXGj2WxCTbOJFxgAomfOKFqq\ +XRSxRZ5SRHKamWJjc5ar0gItt0m6QgXnqUQyp/EeFgNdffzYucGBPpwGjq0mf+hYsxHQcbqiMV9F\ +UsQoyRQa79rdTvl7EiK6K8RCnq7EnDGeHepF5iwkkTUPHTIZOpN+c9dqX3Wuuze34HToa66OzfLj\ +LhI4vhdUmf2CG3Q7APQk34qYDqBmG8C2+7+//r4Cse5JEPbhGRdQU8TawezONUdTlTvnpcpajm+P\ +oyPgj4mCGjGA8xhOTEVLiD385KimXxJWHW4PDcgkNC3s4nB+vENFItRc7D9c9HK+pVyPL19oXMhB\ +iUnZJ/6DZwAqEdzhRTL+gBvVzDPDceRiq5QtZYf+ZFY+gRP9a3PV5qrNVZurNldtrv9lrnet0yqr +exehash=49c2c4c7a717f1d6c11fb7bb9ebeeebca2e5dafe6288d3b0f1112ec42afbf549 + +605.mcf_s=base=maplec-m64: +# Last updated 2021-07-08 14:27:49 +opthash=5a9bcfb51f44556d7b0f1d91dc12b533c8271e4d495bdde702718e8c126d2e5c +baggage= +compiler_version=\ +@eNo1jdEKwiAYhe/3FL6A/BDRRXfLSQxKZW7dSjNHkqbp6vkz1q4O55wPPkSIutBOtpwpLvoS+wru\ +wRsYk9UG/DU6AzyaZ50eJPhonUkwvq27wRyCy5Cj0QumEcZ64xFupKCkBGvoYTgi3P4Y9cohzf9T\ +1UPPlRyE6KiUxUzZWSA8hSLycYXWeWknsdsi/Km+tk04/Q== +compile_options=\ +@eNqtUV1vgjAUfe+vuOk74pZlD0RNoDJlQ9oIJNteGsWaMYGyFpfs36+gRE32sGX2pTf3nvtxzolk\ +ZZWrndjmhQBZN7mstIN0o/Ks4WpfbXLFP4XKt19jfIORCbWBmHgwHA4xQoQumAPYfpOlsNemS9jl\ +qi6ETWtRuWpHZFmb0cpe7/NiYzdSFtrWtcgOsAwsK7stwTKB7PcPJFjTmPnEfNHU99IZgBW0TfxD\ +S9Ucq9xNE8rjlLGlH8ecMj9aMDh71laaI8q6x58Qx0TI7u8ARlruVSYmGBEHCBn/l8xhDvUeKUvG\ ++IIZRkYswtKH0J3FpnbJsqt6fkTmnPSIX9LGiDrgPydL1ySSYBG8+qb5R/7dlgOU0WXiekEYJC/9\ +MZ0mGIVB9HQFW+E3dozk+l1kjZ60mOLUdJINoNM0nF7Bmz/oZFYu3GTOw8BrrSjK4xU0bX09M/Ub\ +hGoAkA== +exehash=92eb0a99ad04eb8d3409b9a0638b2e87a9e31d34990aac67a88b4a3bcd2accb3 + diff --git a/build/tools/spec/cross-gcc.cfg b/build/tools/spec/cross-gcc.cfg new file mode 100644 index 0000000000000000000000000000000000000000..361d657c6ff5ca93312d99121afd3271bfdd4d67 --- /dev/null +++ b/build/tools/spec/cross-gcc.cfg @@ -0,0 +1,496 @@ +#------------------------------------------------------------------------------ +# SPEC CPU2017 config file for: gcc / g++ / gfortran on Linux x86 +#------------------------------------------------------------------------------ +# +# Usage: (1) Copy this to a new name +# cd $SPEC/config +# cp Example-x.cfg myname.cfg +# (2) Change items that are marked 'EDIT' (search for it) +# +# SPEC tested this config file with: +# Compiler version(s): 4.4.7, 4.9.2, 5.2.0, 6.3.0, 7.2.1, 8.1.0 +# Operating system(s): Oracle Linux Server 6.5 and 7.4 / +# Red Hat Enterprise Linux Server 6.5 and 7.4 +# Hardware: Xeon +# +# If your system differs, this config file might not work. +# You might find a better config file at http://www.spec.org/cpu2017/results +# +# Known Limitations with GCC 4 +# +# (1) Possible problem: compile time messages +# error: unrecognized command line option '...' +# Recommendation: Use a newer version of the compiler. +# If that is not possible, remove the unrecognized +# option from this config file. +# +# (2) Possible problem: run time errors messages +# 527.cam4_r or 627.cam4_s *** Miscompare of cam4_validate.txt +# Recommendation: Use a newer version of the compiler. +# If that is not possible, try reducing the optimization. +# +# +# Compiler issues: Contact your compiler vendor, not SPEC. +# For SPEC help: http://www.spec.org/cpu2017/Docs/techsupport.html +#------------------------------------------------------------------------------ + + +#--------- Label -------------------------------------------------------------- +# Arbitrary string to tag binaries (no spaces allowed) +# Two Suggestions: # (1) EDIT this label as you try new ideas. +%define label gcc # (2) Use a label meaningful to *you*. + + +#--------- Preprocessor ------------------------------------------------------- +%ifndef %{bits} # EDIT to control 32 or 64 bit compilation. Or, +% define bits 64 # you can set it on the command line using: +%endif # 'runcpu --define bits=nn' + +%ifndef %{build_ncpus} # EDIT to adjust number of simultaneous compiles. +% define build_ncpus 8 # Or, you can set it on the command line: +%endif # 'runcpu --define build_ncpus=nn' + +# Don't change this part. +%define os LINUX +%if %{bits} == 64 +% define model -m64 +%elif %{bits} == 32 +% define model -m32 +%else +% error Please define number of bits - see instructions in config file +%endif +%if %{label} =~ m/ / +% error Your label "%{label}" contains spaces. Please try underscores instead. +%endif +%if %{label} !~ m/^[a-zA-Z0-9._-]+$/ +% error Illegal character in label "%{label}". Please use only alphanumerics, underscore, hyphen, and period. +%endif + + + +#--------- Global Settings ---------------------------------------------------- +# For info, see: +# https://www.spec.org/cpu2017/Docs/config.html#fieldname +# Example: https://www.spec.org/cpu2017/Docs/config.html#tune + +command_add_redirect = 1 +flagsurl = $[top]/config/flags/gcc.xml +ignore_errors = 1 +iterations = 1 +label = %{label}-m%{bits} +line_width = 1020 +log_line_width = 1020 +makeflags = --jobs=%{build_ncpus} +mean_anyway = 1 +output_format = txt,html,cfg,pdf,csv +preenv = 1 +reportable = 0 +tune = base + + +#--------- How Many CPUs? ----------------------------------------------------- +# Both SPECrate and SPECspeed can test multiple chips / cores / hw threads +# - For SPECrate, you set the number of copies. +# - For SPECspeed, you set the number of threads. +# See: https://www.spec.org/cpu2017/Docs/system-requirements.html#MultipleCPUs +# +# q. How many should I set? +# a. Unknown, you will have to try it and see! +# +# To get you started, some suggestions: +# +# copies - This config file defaults to testing only 1 copy. You might +# try changing it to match the number of cores on your system, +# or perhaps the number of virtual CPUs as reported by: +# grep -c processor /proc/cpuinfo +# Be sure you have enough memory. See: +# https://www.spec.org/cpu2017/Docs/system-requirements.html#memory +# +# threads - This config file sets a starting point. You could try raising +# it. A higher thread count is much more likely to be useful for +# fpspeed than for intspeed. +# +intrate,fprate: + copies = 1 # EDIT to change number of copies (see above) +intspeed,fpspeed: + threads = 4 # EDIT to change number of OpenMP threads (see above) + + +#------- Compilers ------------------------------------------------------------ +default: +# EDIT: The parent directory for your compiler. +# Do not include the trailing /bin/ +# Do not include a trailing slash +# Examples: +# 1 On a Red Hat system, you said +# 'yum install devtoolset-7' +# Use: % define gcc_dir /opt/rh/devtoolset-7/root/usr +# +# 2 You built GCC in: /disk1/mybuild/gcc-8.1.0/bin/gcc +# Use: % define gcc_dir /disk1/mybuild/gcc-8.1.0 +# +# 3 You want: /usr/bin/gcc +# Use: % define gcc_dir /usr +# WARNING: See section +# "Known Limitations with GCC 4" +# +%ifndef %{gcc_dir} +% define gcc_dir /home/yhm/maple_opensource/opensource/tools/gcc-linaro-7.5.0 # EDIT (see above) +%endif + +# EDIT if needed: the preENV line adds library directories to the runtime +# path. You can adjust it, or add lines for other environment variables. +# See: https://www.spec.org/cpu2017/Docs/config.html#preenv +# and: https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html + SPECLANG = %{gcc_dir}/bin/ + CC = $(SPECLANG)aarch64-linux-gnu-gcc -std=c99 + CXX = $(SPECLANG)aarch64-linux-gnu-g++ -std=c++03 + FC = /usr/bin/aarch64-linux-gnu-gfortran-7 + # How to say "Show me your version, please" + CC_VERSION_OPTION = -v + CXX_VERSION_OPTION = -v + FC_VERSION_OPTION = -v + +default: +%if %{bits} == 64 + sw_base_ptrsize = 64-bit + sw_peak_ptrsize = 64-bit +%else + sw_base_ptrsize = 32-bit + sw_peak_ptrsize = 32-bit +%endif + + +#--------- Portability -------------------------------------------------------- +default: # data model applies to all benchmarks +%if %{bits} == 32 + # Strongly recommended because at run-time, operations using modern file + # systems may fail spectacularly and frequently (or, worse, quietly and + # randomly) if a program does not accommodate 64-bit metadata. + EXTRA_PORTABILITY = -D_FILE_OFFSET_BITS=64 +%else + EXTRA_PORTABILITY = -DSPEC_LP64 +%endif + +# Benchmark-specific portability (ordered by last 2 digits of bmark number) + +500.perlbench_r,600.perlbench_s: #lang='C' +%if %{bits} == 32 +% define suffix IA32 +%else +% define suffix X64 +%endif + PORTABILITY = -DSPEC_%{os}_%{suffix} + +521.wrf_r,621.wrf_s: #lang='F,C' + CPORTABILITY = -DSPEC_CASE_FLAG + FPORTABILITY = -fconvert=big-endian + +523.xalancbmk_r,623.xalancbmk_s: #lang='CXX' + PORTABILITY = -DSPEC_%{os} + +526.blender_r: #lang='CXX,C' + PORTABILITY = -funsigned-char -DSPEC_LINUX + +527.cam4_r,627.cam4_s: #lang='F,C' + PORTABILITY = -DSPEC_CASE_FLAG + +628.pop2_s: #lang='F,C' + CPORTABILITY = -DSPEC_CASE_FLAG + FPORTABILITY = -fconvert=big-endian + + +#-------- Tuning Flags common to Base and Peak -------------------------------- + +# +# Speed (OpenMP and Autopar allowed) +# +%if %{bits} == 32 + intspeed,fpspeed: + # + # Many of the speed benchmarks (6nn.benchmark_s) do not fit in 32 bits + # If you wish to run SPECint2017_speed or SPECfp2017_speed, please use + # + # runcpu --define bits=64 + # + fail_build = 1 +%else + intspeed,fpspeed: + EXTRA_OPTIMIZE = -fopenmp -DSPEC_OPENMP + fpspeed: + # + # 627.cam4 needs a big stack; the preENV will apply it to all + # benchmarks in the set, as required by the rules. + # + preENV_OMP_STACKSIZE = 120M +%endif + + +#-------- Baseline Tuning Flags ---------------------------------------------- +# +# EDIT if needed -- Older GCC might not support some of the optimization +# switches here. See also 'About the -fno switches' below. +# +default=base: # flags for all base + OPTIMIZE = -g -O3 -fno-pie -fno-unsafe-math-optimizations -fno-tree-loop-vectorize + +intrate,intspeed=base: # flags for integer base + EXTRA_COPTIMIZE = -fno-strict-aliasing -fgnu89-inline +# Notes about the above +# - 500.perlbench_r/600.perlbench_s needs -fno-strict-aliasing. +# - 502.gcc_r/602.gcc_s needs -fgnu89-inline or -z muldefs +# - For 'base', all benchmarks in a set must use the same options. +# - Therefore, all base benchmarks get the above. See: +# www.spec.org/cpu2017/Docs/runrules.html#BaseFlags +# www.spec.org/cpu2017/Docs/benchmarks/500.perlbench_r.html +# www.spec.org/cpu2017/Docs/benchmarks/502.gcc_r.html + + +#-------- Peak Tuning Flags ---------------------------------------------- +default=peak: + basepeak = yes # if you develop some peak tuning, remove this line. + # + # ----------------------- + # About the -fno switches + # ----------------------- + # + # For 'base', this config file (conservatively) disables some optimizations. + # You might want to try turning some of them back on, by creating a 'peak' + # section here, with individualized benchmark options: + # + # 500.perlbench_r=peak: + # OPTIMIZE = this + # 502.gcc_r=peak: + # OPTIMIZE = that + # 503.bwaves_r=peak: + # OPTIMIZE = other .....(and so forth) + # + # If you try it: + # - You must remove the 'basepeak' option, above. + # - You will need time and patience, to diagnose and avoid any errors. + # - perlbench is unlikely to work with strict aliasing + # - Some floating point benchmarks may get wrong answers, depending on: + # the particular chip + # the version of GCC + # other optimizations enabled + # -m32 vs. -m64 + # - See: http://www.spec.org/cpu2017/Docs/config.html + # - and: http://www.spec.org/cpu2017/Docs/runrules.html + + +#------------------------------------------------------------------------------ +# Tester and System Descriptions - EDIT all sections below this point +#------------------------------------------------------------------------------ +# For info about any field, see +# https://www.spec.org/cpu2017/Docs/config.html#fieldname +# Example: https://www.spec.org/cpu2017/Docs/config.html#hw_memory +#------------------------------------------------------------------------------- + +#--------- EDIT to match your version ----------------------------------------- +default: + sw_compiler001 = C/C++/Fortran: Version 7.2.1 of GCC, the + sw_compiler002 = GNU Compiler Collection + +#--------- EDIT info about you ------------------------------------------------ +# To understand the difference between hw_vendor/sponsor/tester, see: +# https://www.spec.org/cpu2017/Docs/config.html#test_sponsor +intrate,intspeed,fprate,fpspeed: # Important: keep this line + hw_vendor = My Corporation + tester = My Corporation + test_sponsor = My Corporation + license_num = nnn (Your SPEC license number) +# prepared_by = # Ima Pseudonym # Whatever you like: is never output + + +#--------- EDIT system availability dates ------------------------------------- +intrate,intspeed,fprate,fpspeed: # Important: keep this line + # Example # Brief info about field + hw_avail = # Nov-2099 # Date of LAST hardware component to ship + sw_avail = # Nov-2099 # Date of LAST software component to ship + +#--------- EDIT system information -------------------------------------------- +intrate,intspeed,fprate,fpspeed: # Important: keep this line + # Example # Brief info about field +# hw_cpu_name = # Intel Xeon E9-9999 v9 # chip name + hw_cpu_nominal_mhz = # 9999 # Nominal chip frequency, in MHz + hw_cpu_max_mhz = # 9999 # Max chip frequency, in MHz +# hw_disk = # 9 x 9 TB SATA III 9999 RPM # Size, type, other perf-relevant info + hw_model = # TurboBlaster 3000 # system model name +# hw_nchips = # 99 # number chips enabled + hw_ncores = # 9999 # number cores enabled + hw_ncpuorder = # 1-9 chips # Ordering options + hw_nthreadspercore = # 9 # number threads enabled per core + hw_other = # TurboNUMA Router 10 Gb # Other perf-relevant hw, or "None" + +# hw_memory001 = # 999 GB (99 x 9 GB 2Rx4 PC4-2133P-R, # The 'PCn-etc' is from the JEDEC +# hw_memory002 = # running at 1600 MHz) # label on the DIMM. + + hw_pcache = # 99 KB I + 99 KB D on chip per core # Primary cache size, type, location + hw_scache = # 99 KB I+D on chip per 9 cores # Second cache or "None" + hw_tcache = # 9 MB I+D on chip per chip # Third cache or "None" + hw_ocache = # 9 GB I+D off chip per system board # Other cache or "None" + + fw_bios = # American Megatrends 39030100 02/29/2016 # Firmware information +# sw_file = # ext99 # File system +# sw_os001 = # Linux Sailboat # Operating system +# sw_os002 = # Distribution 7.2 SP1 # and version + sw_other = # TurboHeap Library V8.1 # Other perf-relevant sw, or "None" +# sw_state = # Run level 99 # Software state. + +# Note: Some commented-out fields above are automatically set to preliminary +# values by sysinfo +# https://www.spec.org/cpu2017/Docs/config.html#sysinfo +# Uncomment lines for which you already know a better answer than sysinfo + +__HASH__ +500.perlbench_r=base=maple_test-m64: +# Last updated 2021-05-10 10:36:40 +opthash=1b55f44e78c515229834a282ce9d3013fee214077130f5cc6c8d469cce53274c +baggage= +compiler_version=\ +@eNp9VE1v2zAMvftX+NYNteK26ZIigA9Z6hYD0qZI3e0YyBLtqJUlTx+J08N++2Qnjr202MWC+Cjy\ +kXy0P5utfsbL5x+Lx9XiKXHHxHvRTOR+ahk3iAlfl0D0wJst5vN4lqzuZ7MotFqFKRNhTsgRmCeL\ +1a/l9OkpXu4dOEtrh7C6Ga1G14gzYSuUCxuOQ24k2ipclqC8xd3dfDG9XSXT5X2crB6nD/FzJDal\ +qZCQAk7x2/hu+jJPoksvwSoHM/FP43szKTKWWwXU3zKznviDQagVCUlr99HGR6jGUPmWb0BpJkV0\ +9pJaYaw/HnwbXKChbW6Xfy5vBhfXZ61/al0AHmWMwyQMmzr1GisIqSR1tWgcLuPp7UM8+G5z7V6B\ +wCkHxLHILc5BRyTAFAfk/DzIZZAqlgc0yKQyCotApq+k/iAHu7elgoxVTTfb/HWKAr9KhQ60kRR8\ +1/jKXOECaZvVb9C4ZzvEOW0U6ug1NdAeXSbeQKFaBBSxGnDThAoIZeo43QMnaWudEG4pUOQmYqAy\ +XSSzVoCpjkqpWbWPcxLj4Ch4r12plEa7lpSdiXBJMIfIEe/zTLWhpKoQBTeazwDDCoh2oNsOUsiw\ +ddLuPHDKIgHb7nHdGyvYbwvIDQNIXQ5lusE2Zn+AYtnun3xFWXX3ktvcLc/x3mYtGbRE9E4bKNB7\ +10lkGkmfIIcItTbc+CNsjeyshQvKsCLrHsUtKCWPiqlBNLyK2OhmdLS5iovRdXttgrhkrgptomJ4\ +FTgwKKrh1UmiPlUr3CxAuD6QHsks4xLTQyG6t8c9sRBLMaKKuR72xrsG8uZ+PJECDljX/o36PqjW\ +AWvpaH5i32f9gHhJo0G/kBT4xG+U6LlF8g8rtN94/8t/9v+r7/0FuibFEg== +compile_options=\ +@eNrVU21r2zAQ/u5fIfxdccdGWUJdsB0l8eZEwrIh2xfhOkqqLZaD5IS1v34n56UtDFpGv1RgfLq3\ +R3fP3aLVuKl+y7XaStTuOtVqO/JsZ1TdCbPXK2XEQRq1fgj9T74HogWX0L8aDK+ufc9L6JyNkB/s\ +rQnulA42dY3cwbZbhfVw6MTm+gvCNcLtGWDQIjzmjCTwW4xJXE5BYCTPREJzgnA6gG+lbBekFKR6\ +V+mgUI3EM5VLe9bMinmGWWWsNKCSf7rASBDsTtam0itIOaZlnBHBs4jPCBcOMY2y8OqELqKyoIKX\ +jOWEc0EZWcwZ2EQW5VMiJmlG+OXqboLTMk+I0/VXOplwUog4LXgINSK8QZh+hoIrU9+HuurUAV60\ +1i3ea1utJRi6e+ya0KjHqm8FOto7IyXetu0OH2TdtUY9SnQ6p7dm6aJciqWDOcUcScLVVlVWaYBe\ +b/T+6xArvVVaPotkLujGtntTy1vfS0YoScJXKTs60vgbZUXov+DP94DzhJWTLJpysL3ksrfGZJHM\ +xMXhw5Pre3SEoBPpPP1JoKL3ZLpvGKN5EcVplhY/zh194rxHJ8sij6CJT494fQr61MfAfwIwlxtg\ +vr9lh4/Kd5/x/x3wm/buFySyt85/26DLwlzmFKF+iLPxW6b9g/IL9c2jYga5Yrdp2+ZUMi3d1j5b\ +2b8rRMvz +exehash=1c69320bf26365e65e5b19b87fd09bbfdf73b3d6257845446d6001048f92fd40 + +500.perlbench_r=base=gcc-m64: +# Last updated 2021-05-13 10:18:46 +opthash=4a1fc46ed4b7dc5c387a83a4c8727837cdc03d41f8bddf80c915370e9e6911bd +baggage= +compiler_version=\ +@eNq9VUtv2zAMvudX6NYNraKmj7QJ4MMQBNuAYAnabDsasszYamRJ06Nxd9hvn2zHtddmGLBuvcSh\ ++PjITySFZrP4y/zm9uPyU7xcrcNnOvhsucxQ4rlwmEtkNTA7HMyWi8V8to7fz2YRyVUBxHpJoPCc\ +FFQLiJUGaZU3DEjvr1NKWJIxhgWX1Ch8NbwcnpKES0KpYfn4olL4EmfS42D2iLNYL+OvN+9Wq/nN\ +P8IbDongCZTAKv1zeNKYCqfwzlCtwQzW1GTgpuiZ7WCm5IZn3kCKdtzlU3TUJOnYLsMVd6kV9B7I\ +Tpmt1ZTtNQXdAjYggFqIR8RKqm2uXJ3xMOPuR5c1PjsdTYajM8JaqCN0+2G+WER1NQm1OcK4AseF\ +ZtHfwMe1JWnsSQrWpdwQPr4eY826YjuYjXkNnKzQrwITOo7aviTSIKXc0kRAsE8Kn24E1eEQZHPm\ +VCfYnFbX3/grXw0LEz6FFIeecVC6zlSKRxz7YB0U+HsI3wOzd+IOQ8lAO66k7TyrtLzk3zxgldwB\ +6wUNBW3BNPRg/iT1UDsry1B33jmwyaQnCMWogKgh5DFk65hC4rOeQsms/mnLCO4qi6RqZa1FT+J2\ +L7UZFV443pS8j7jhJWbKBJ4wvTzH1+eXV+PJ79UX5xejSRu+msaImuL+GtPOxeUGaGojrSwvu+Ma\ +uvI4VKbjBUQP8IRwLkPjBK7xxktWXUgL3HAdrtAo5V7So/sQ9vkW6vXJS0H+NAgHVmBghvV6JAe2\ +DY9BtA/du9Ckyt6ZX4aDyszTDGzETtjx8ckmXJ+h8qQZmjqZ6NAw5sq6gwpXb9/oEEXaQOiQ/0nO\ +YF23EypUCmKK6qYahC2N7sHYqiXq1wK9WdQLG4VnEfWW9ls0+Alw/ZnQ +compile_options=\ +@eNrVVG1r2zAQ/u5fIfxdcca6bAl1wXaUxJsTCb9Ati/CdZREmy0ZyS5df/1kO0lTGAxGKVRgfKd7\ +eaS757SRAlb5L7bnJQOybrgUembpRvGioaoVO67oA1N8/9u1P9iWEbVxce3xaDqe2JYV4DWZAds5\ +yoo5uhUOq1ruVHldMiprJrRsVcGcK7GRstTOoShgyUWuJPw8+jQaO/dcOHmuiuPkpjO0j/AgWmjc\ +QLegbnZuMZ0CWAAozwcdSQDnCUGB+W3myM+WRiAojmiAYwRgODLfjuvGCbGRijoXTsorBlc8Zvq8\ +s0rXESS50kyZLfbYOIoZQdesULnYmZRznPkRoknkJSuU0A4x9CJ3fEKnXpZimmSExChJKCZosybG\ +RiMvXiK6CCOUXNROownO4gB1e72KF4sEpdQP08Sd3JjbHgDEHwHcCwlrzgahFTrfM9Os5gi7+1f8\ +Ke+rAAZ7oxiDpZQ1fGBFIxV/YuC0TseMwk22pdsO4RQz9BnmJc81FwZ1b4r+ZQq5MC1gV5GkC7od\ +OnhnW8EMBIH7Zl0fALH/FZPUtV9QwLYM/QKSLSJvmRjbSzr0Vh9tghW9OLx7ftgWngFTiXAd/kDm\ +Rq9Elr5WBMep54dRmH4/F/OZNj0w2qaxZ+r3jP9vIvWph8C/ApAut4H59pYvyaC95qT975jdyvuf\ +JpG+6/zLClzG9sJyAPoRiOZvOXPvj2WmRGsvXZlcfjfqZXWqGs66Z+PqzfgDFjQx9g== +exehash=6baceb9eb267d444c46c4c9f978e50063408522981011f9ac78e7db729fc8926 + +519.lbm_r=base=gcc-m64: +# Last updated 2021-05-13 10:35:31 +opthash=d0595b41acba249b4b15e2950cf3b949e9504a149adac9800b3de173849eacd9 +baggage= +compiler_version=\ +@eNq9VUtv2zAMvudX6NYNraKmj7QJ4MMQBNuAYAnabDsasszYamRJ06Nxd9hvn2zHtddmGLBuvcSh\ ++PjITySFZrP4y/zm9uPyU7xcrcNnOvhsucxQ4rlwmEtkNTA7HMyWi8V8to7fz2YRyVUBxHpJoPCc\ +FFQLiJUGaZU3DEjvr1NKWJIxhgWX1Ch8NbwcnpKES0KpYfn4olL4EmfS42D2iLNYL+OvN+9Wq/nN\ +P8IbDongCZTAKv1zeNKYCqfwzlCtwQzW1GTgpuiZ7WCm5IZn3kCKdtzlU3TUJOnYLsMVd6kV9B7I\ +Tpmt1ZTtNQXdAjYggFqIR8RKqm2uXJ3xMOPuR5c1PjsdTYajM8JaqCN0+2G+WER1NQm1OcK4AseF\ +ZtHfwMe1JWnsSQrWpdwQPr4eY826YjuYjXkNnKzQrwITOo7aviTSIKXc0kRAsE8Kn24E1eEQZHPm\ +VCfYnFbX3/grXw0LEz6FFIeecVC6zlSKRxz7YB0U+HsI3wOzd+IOQ8lAO66k7TyrtLzk3zxgldwB\ +6wUNBW3BNPRg/iT1UDsry1B33jmwyaQnCMWogKgh5DFk65hC4rOeQsms/mnLCO4qi6RqZa1FT+J2\ +L7UZFV443pS8j7jhJWbKBJ4wvTzH1+eXV+PJ79UX5xejSRu+msaImuL+GtPOxeUGaGojrSwvu+Ma\ +uvI4VKbjBUQP8IRwLkPjBK7xxktWXUgL3HAdrtAo5V7So/sQ9vkW6vXJS0H+NAgHVmBghvV6JAe2\ +DY9BtA/du9Ckyt6ZX4aDyszTDGzETtjx8ckmXJ+h8qQZmjqZ6NAw5sq6gwpXb9/oEEXaQOiQ/0nO\ +YF23EypUCmKK6qYahC2N7sHYqiXq1wK9WdQLG4VnEfWW9ls0+Alw/ZnQ +compile_options=\ +@eNq9UlFPgzAQfudXNH3vmNFptsgSYKgoo82ARH1pkHVbFVrSglF/vWXM6RIfdffSu97lu7vvvlgK\ +VOUvbMVLBmTdcCn0xNKN4kVDVSuWXNFXpvjq3YEn0DKuNiUOHA7GwxG0LB/PyQRAeyMrZutW2Kxq\ +uV3ldcmorJnQslUFs3+4jZSlttdFgUouciXRxWA0GNpPXNh5rorN+VmXaN/QWrTIlIHOkG6WTjEe\ +A1QAJL8GHUiAZgkJfPPEs8DLrncxdbMU0yQjZBEkCcUkiOfEoKwBwqcArYRENWe90wqdr5ghodmg\ +DrfiH/kWHfT5RjGGSilr9MqKRir+wcCh7XpG5PwMgMt+zSm0/Anwfedo1PQNsXeLSerAA56gZW7k\ +k+wqcq8TkzvkbJv1gti/oQcFv5IILTwBpkM4Dx8DU/lHjG5nCO7ThUsJXqSuF0Zh+rCfpKMWWlEY\ +3x1Ta33055q5lE/P5ldPO/Sy+pbR/l4AbI8ZzY6pnn+6q9lj7qY3NAq9TllltVsNZ51Kf0j0E2qG\ +c4o= +exehash=b17469e48480b17716b457cef173dcb01bb9f937e33f10bfda3c01e7cce63d3b + +538.imagick_r=base=gcc-m64: +# Last updated 2021-05-13 15:27:38 +opthash=2f48a899d3d456bed03183b03581d9905efa460c559864a9e038739267957e43 +baggage= +compiler_version=\ +@eNq9VUtv2zAMvudX6NYNraKmj7QJ4MMQBNuAYAnabDsasszYamRJ06Nxd9hvn2zHtddmGLBuvcSh\ ++PjITySFZrP4y/zm9uPyU7xcrcNnOvhsucxQ4rlwmEtkNTA7HMyWi8V8to7fz2YRyVUBxHpJoPCc\ +FFQLiJUGaZU3DEjvr1NKWJIxhgWX1Ch8NbwcnpKES0KpYfn4olL4EmfS42D2iLNYL+OvN+9Wq/nN\ +P8IbDongCZTAKv1zeNKYCqfwzlCtwQzW1GTgpuiZ7WCm5IZn3kCKdtzlU3TUJOnYLsMVd6kV9B7I\ +Tpmt1ZTtNQXdAjYggFqIR8RKqm2uXJ3xMOPuR5c1PjsdTYajM8JaqCN0+2G+WER1NQm1OcK4AseF\ +ZtHfwMe1JWnsSQrWpdwQPr4eY826YjuYjXkNnKzQrwITOo7aviTSIKXc0kRAsE8Kn24E1eEQZHPm\ +VCfYnFbX3/grXw0LEz6FFIeecVC6zlSKRxz7YB0U+HsI3wOzd+IOQ8lAO66k7TyrtLzk3zxgldwB\ +6wUNBW3BNPRg/iT1UDsry1B33jmwyaQnCMWogKgh5DFk65hC4rOeQsms/mnLCO4qi6RqZa1FT+J2\ +L7UZFV443pS8j7jhJWbKBJ4wvTzH1+eXV+PJ79UX5xejSRu+msaImuL+GtPOxeUGaGojrSwvu+Ma\ +uvI4VKbjBUQP8IRwLkPjBK7xxktWXUgL3HAdrtAo5V7So/sQ9vkW6vXJS0H+NAgHVmBghvV6JAe2\ +DY9BtA/du9Ckyt6ZX4aDyszTDGzETtjx8ckmXJ+h8qQZmjqZ6NAw5sq6gwpXb9/oEEXaQOiQ/0nO\ +YF23EypUCmKK6qYahC2N7sHYqiXq1wK9WdQLG4VnEfWW9ls0+Alw/ZnQ +compile_options=\ +@eNrtVE1vozAQvfMrLN8NWTXtKlGpBIS27BJsBZDaXixKncRdsJENVbe/fg0ku81lT2lO8cVjz2g+\ +3jy9RApUF7/YmlcMyKblUui5pVvFy5aqTrxwRd+Y4uvfLvwGLWNqE+LCiT2bTKFlBXhJ5gA6W1kz\ +R3fCYXXHnbpoKkZlw4SWnSqZ88lspay0sylLVHFRKIm+25f2xHnmwikKVW6vpr2je0cb0SETBvqD\ +dPvilrMZQCVAct+oLQFapCQMzJUsQj+/Ayiyd3/UyzNM05yQVZimFJMwWRKTaQMQvgBoLSRqOBuN\ +TuhizQwQ7Rb1uWv+UQwVwOhvFWOokrJBb6xspeIfDByeXc2YXE0BuB5HvYFWMAdB4J4MnrEg9n9g\ +krnwACtomT0FJL+NvbvU+A5xG7x+mAT3dB/wfyChhefAVImW0VNooo+E6tBH+JCtPErwKvP8KI6y\ +x327A7zQiqPk5yk5N76Ozptr+fxqfvVNn72q/1Hp784AGBYaL07JoC/aq5lj6WX3NI78nl1VvRsN\ +5z1TP9H0LClnSTlLyllSjigpfwDZpdRT +exehash=eee9c4547d70bbcff53dd938e8d24d3492bdaa0d41abdbc0912925aae18bf1d5 + +507.cactuBSSN_r=base=gcc-m64: +# Last updated 2021-05-19 10:35:36 +opthash=89a6bfc2a18191e165ebb9999593cbcfd3b1e3234d8c08585230a52bdafd0e27 +baggage= +compiler_version=\ +@eNrtVltv2zYYffev0Fs6JLTiJnFiA3roPO8CeEuQulvfDIr6LDGmSJaX2NlDf/soSrJUW06LBOuA\ +wS+2SX73yzkOJh8/ThZ/Tu/f/3b7x+L2bu6+xr1g0nH38/7dB015GsSWMoMoD7QEovu9ye1sNp3M\ +F79MJlGYiRzCpywPcywZLIQEroVVBMLWTyME02FKCGKUYyXQdf+qfx7GlIcYK5INL4sHu0Eptyg9\ +Pd26mM1vF3/dv7u7m96/3lW/HzIawwZI8b7vOSxFmRForbCUoHpzrFIw42BPtjcRfElTqyAJ1tRk\ +4+CkjM+QdYqKiiWa4UcI10KttMSkesnxCpACBljDYhBqjqXOhPER91NqPjdRo7fng1F/8DYktauT\ +4P2v09ks8tnEWGcBQoVzlEsSvcT9wkuGpXyYgDYJVSEd3gyRJE2yjZul+h5+0lx+Fzdu2LBun1ji\ +TgnVOGbg5OPcJkuGpbsEXt4Z0Rx0hov2l/rCFitCmE0gQW5mDGxMI8rZ1o9+0gZy9Lcz33KmH9gD\ +gg0BaajgutEswrKcfrKARPwApGXUJbQCVZYH0Z3QXe5ks3F5Z40CGY1aByYIZhCVBdmarBUTiG3a\ +ehA89R91Gk5dpBEX9VlK1jpRXZ3qiHLLDC1Triwu6QYRoVydEL66QDcXV9fD0eHny4vLwag2X2xj\ +hFX+eINwo2IyBTjRkRSabppr77rQ6ErT0ByiJ9gpOOVucFyt0dJyUjSkdlzW2rVQCWFeM6OVCb2P\ +Qq05ea2Try1CBwS6ypDWjGRAVo4Cosp0q6FxEb1RXywH5qnFKeiInJHT07Ola5/C/KxcGh9M1LWM\ +mdCm88F49I26SiQVuAn5N4vTm/txCnKRABsHfqh6DqWDR1C6GAnPFsGbmQfswJFh0ALtH4L/iDwJ\ +OZLnkTyP5HkkzyN5Hsnz/0yeVqtDJFgVD113c2Gh6XrliY4ooXUXnb2UyhxRakUa3gnQ43bNV2mV\ +f3TyIbbc2LAqgC8HurD+cvB5cNM/vzxp9sbZYdGSMhiHoY/eo2eYCE/G6Dq8n7776fdp/0eb6u6R\ +wgn2Y5WKs2Q7Ww4TSfGB3EtrLJyDLa476zl+EApVgSPB2ZOXFanCOdJ2Weig6w5kP4i01R8JNznb\ +XnwTEexilNPbsdHJGCUSvBi8u+DOm05giR08tiRwTCMO6+cJqMUznyxOcmyy7ltXXCldqxpzktmU\ +8uZcRyApdDPkYRQ/RBF1HGtQSqhn0awEpc3NcLGDLx6TOu6fhaRynqoZ3N9pJ1MPRt3y/aWtJL4V\ +fb6+gw6J/gGx5MUB +compile_options=\ +@eNrNVd1umzAYvecpLG4jh1TLWiUqlfhLx0oABZCy3VjUMYk3sCMD1dqnn4GmC1qjdVLK5hvbfAd9\ +x+cc2T5nsEi/k4zmBPB9RTkr50pZCYorJGq2oQI9EEGzR129UBW5LCVEVyfj2WSqKooVLMM5ULUd\ +L4j2uCu0It3nBPE9YSWvBSba0bLiPC+1LcYwpywVHF6NP44n2j1lWpoKvLucNoX6B9yyGm5HI9AM\ +WFYbHY9Gkw8AYgD5geWYA2hHoWPJybcdM7l93iMjiQMUJWG4cqIIBaHjL0MAXcpwXm+IRFlWYDvt\ +HN8h240M03OQBMcr14r1CwC3AAayXcY43FPSLWpWphmRYlU72FAo6FPaEgFdvRKEwJzzPXwguOKC\ +PhFwGM/EvPByCsB1p8aNqlhzYK3X+jDqHdoF5ucgjHW1J6aqSBetMFl4xm0ka31h26rp+NYn1AO8\ +qvQRWHY74N+uvqoEcyAZukv3qyP/PJMXLS1nHa8MFAar2DBdz42/vJyksUZ9zzRjfOTHbHbuLJ87\ +sX/MraUPIVPXa8jIngrs/xDLuhSndMu4qETK4NXvwfp1kr/jfDIjvSAsmiC8hViHHtDKxStWLv61\ +lZ7r3w32Xnb7s18N1/z+m/xa3vSuihc3AWit9uzBHrZ3srM9RJA0aT2K6k+WW+Ko +exehash=63bc323d25366ddc5092f5d594b9e1caa8da1a2fac4e5ece4e8311cc4282a03a + diff --git a/build/tools/spec/gcc.cfg b/build/tools/spec/gcc.cfg new file mode 100644 index 0000000000000000000000000000000000000000..f264f2b95e3cf4d79cdeafe417ca1637635b522a --- /dev/null +++ b/build/tools/spec/gcc.cfg @@ -0,0 +1,461 @@ +#------------------------------------------------------------------------------ +# SPEC CPU2017 config file for: gcc / g++ / gfortran on Linux x86 +#------------------------------------------------------------------------------ +# +# Usage: (1) Copy this to a new name +# cd $SPEC/config +# cp Example-x.cfg myname.cfg +# (2) Change items that are marked 'EDIT' (search for it) +# +# SPEC tested this config file with: +# Compiler version(s): 4.4.7, 4.9.2, 5.2.0, 6.3.0, 7.2.1, 8.1.0 +# Operating system(s): Oracle Linux Server 6.5 and 7.4 / +# Red Hat Enterprise Linux Server 6.5 and 7.4 +# Hardware: Xeon +# +# If your system differs, this config file might not work. +# You might find a better config file at http://www.spec.org/cpu2017/results +# +# Known Limitations with GCC 4 +# +# (1) Possible problem: compile time messages +# error: unrecognized command line option '...' +# Recommendation: Use a newer version of the compiler. +# If that is not possible, remove the unrecognized +# option from this config file. +# +# (2) Possible problem: run time errors messages +# 527.cam4_r or 627.cam4_s *** Miscompare of cam4_validate.txt +# Recommendation: Use a newer version of the compiler. +# If that is not possible, try reducing the optimization. +# +# +# Compiler issues: Contact your compiler vendor, not SPEC. +# For SPEC help: http://www.spec.org/cpu2017/Docs/techsupport.html +#------------------------------------------------------------------------------ + + +#--------- Label -------------------------------------------------------------- +# Arbitrary string to tag binaries (no spaces allowed) +# Two Suggestions: # (1) EDIT this label as you try new ideas. +%define label gcc # (2) Use a label meaningful to *you*. + + +#--------- Preprocessor ------------------------------------------------------- +%ifndef %{bits} # EDIT to control 32 or 64 bit compilation. Or, +% define bits 64 # you can set it on the command line using: +%endif # 'runcpu --define bits=nn' + +%ifndef %{build_ncpus} # EDIT to adjust number of simultaneous compiles. +% define build_ncpus 8 # Or, you can set it on the command line: +%endif # 'runcpu --define build_ncpus=nn' + +# Don't change this part. +%define os LINUX +%if %{bits} == 64 +% define model -m64 +%elif %{bits} == 32 +% define model -m32 +%else +% error Please define number of bits - see instructions in config file +%endif +%if %{label} =~ m/ / +% error Your label "%{label}" contains spaces. Please try underscores instead. +%endif +%if %{label} !~ m/^[a-zA-Z0-9._-]+$/ +% error Illegal character in label "%{label}". Please use only alphanumerics, underscore, hyphen, and period. +%endif + + + +#--------- Global Settings ---------------------------------------------------- +# For info, see: +# https://www.spec.org/cpu2017/Docs/config.html#fieldname +# Example: https://www.spec.org/cpu2017/Docs/config.html#tune + +command_add_redirect = 1 +flagsurl = $[top]/config/flags/gcc.xml +ignore_errors = 1 +iterations = 1 +label = %{label}-m%{bits} +line_width = 1020 +log_line_width = 1020 +makeflags = --jobs=%{build_ncpus} +mean_anyway = 1 +output_format = txt,html,cfg,pdf,csv +preenv = 1 +reportable = 0 +tune = base + + +#--------- How Many CPUs? ----------------------------------------------------- +# Both SPECrate and SPECspeed can test multiple chips / cores / hw threads +# - For SPECrate, you set the number of copies. +# - For SPECspeed, you set the number of threads. +# See: https://www.spec.org/cpu2017/Docs/system-requirements.html#MultipleCPUs +# +# q. How many should I set? +# a. Unknown, you will have to try it and see! +# +# To get you started, some suggestions: +# +# copies - This config file defaults to testing only 1 copy. You might +# try changing it to match the number of cores on your system, +# or perhaps the number of virtual CPUs as reported by: +# grep -c processor /proc/cpuinfo +# Be sure you have enough memory. See: +# https://www.spec.org/cpu2017/Docs/system-requirements.html#memory +# +# threads - This config file sets a starting point. You could try raising +# it. A higher thread count is much more likely to be useful for +# fpspeed than for intspeed. +# +intrate,fprate: + copies = 1 # EDIT to change number of copies (see above) +intspeed,fpspeed: + threads = 4 # EDIT to change number of OpenMP threads (see above) + + +#------- Compilers ------------------------------------------------------------ +default: +# EDIT: The parent directory for your compiler. +# Do not include the trailing /bin/ +# Do not include a trailing slash +# Examples: +# 1 On a Red Hat system, you said +# 'yum install devtoolset-7' +# Use: % define gcc_dir /opt/rh/devtoolset-7/root/usr +# +# 2 You built GCC in: /disk1/mybuild/gcc-8.1.0/bin/gcc +# Use: % define gcc_dir /disk1/mybuild/gcc-8.1.0 +# +# 3 You want: /usr/bin/gcc +# Use: % define gcc_dir /usr +# WARNING: See section +# "Known Limitations with GCC 4" +# +%ifndef %{gcc_dir} +% define gcc_dir /home/sun/emui/maple_opensource/opensource/tools/gcc-linaro-7.5.0 # EDIT (see above) +%endif + +# EDIT if needed: the preENV line adds library directories to the runtime +# path. You can adjust it, or add lines for other environment variables. +# See: https://www.spec.org/cpu2017/Docs/config.html#preenv +# and: https://gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html + SPECLANG = %{gcc_dir}/bin/ + CC = $(SPECLANG)aarch64-linux-gnu-gcc -std=c99 + CXX = $(SPECLANG)g++ -std=c++03 %{model} + FC = $(SPECLANG)gfortran %{model} + # How to say "Show me your version, please" + CC_VERSION_OPTION = -v + CXX_VERSION_OPTION = -v + FC_VERSION_OPTION = -v + +default: +%if %{bits} == 64 + sw_base_ptrsize = 64-bit + sw_peak_ptrsize = 64-bit +%else + sw_base_ptrsize = 32-bit + sw_peak_ptrsize = 32-bit +%endif + + +#--------- Portability -------------------------------------------------------- +default: # data model applies to all benchmarks +%if %{bits} == 32 + # Strongly recommended because at run-time, operations using modern file + # systems may fail spectacularly and frequently (or, worse, quietly and + # randomly) if a program does not accommodate 64-bit metadata. + EXTRA_PORTABILITY = -D_FILE_OFFSET_BITS=64 +%else + EXTRA_PORTABILITY = -DSPEC_LP64 +%endif + +# Benchmark-specific portability (ordered by last 2 digits of bmark number) + +500.perlbench_r,600.perlbench_s: #lang='C' +%if %{bits} == 32 +% define suffix IA32 +%else +% define suffix X64 +%endif + PORTABILITY = -DSPEC_%{os}_%{suffix} + +521.wrf_r,621.wrf_s: #lang='F,C' + CPORTABILITY = -DSPEC_CASE_FLAG + FPORTABILITY = -fconvert=big-endian + +523.xalancbmk_r,623.xalancbmk_s: #lang='CXX' + PORTABILITY = -DSPEC_%{os} + +526.blender_r: #lang='CXX,C' + PORTABILITY = -funsigned-char -DSPEC_LINUX + +527.cam4_r,627.cam4_s: #lang='F,C' + PORTABILITY = -DSPEC_CASE_FLAG + +628.pop2_s: #lang='F,C' + CPORTABILITY = -DSPEC_CASE_FLAG + FPORTABILITY = -fconvert=big-endian + + +#-------- Tuning Flags common to Base and Peak -------------------------------- + +# +# Speed (OpenMP and Autopar allowed) +# +%if %{bits} == 32 + intspeed,fpspeed: + # + # Many of the speed benchmarks (6nn.benchmark_s) do not fit in 32 bits + # If you wish to run SPECint2017_speed or SPECfp2017_speed, please use + # + # runcpu --define bits=64 + # + fail_build = 1 +%else + intspeed,fpspeed: + EXTRA_OPTIMIZE = -fopenmp -DSPEC_OPENMP + fpspeed: + # + # 627.cam4 needs a big stack; the preENV will apply it to all + # benchmarks in the set, as required by the rules. + # + preENV_OMP_STACKSIZE = 120M +%endif + + +#-------- Baseline Tuning Flags ---------------------------------------------- +# +# EDIT if needed -- Older GCC might not support some of the optimization +# switches here. See also 'About the -fno switches' below. +# +default=base: # flags for all base + OPTIMIZE = -O2 -fno-pie -fno-unsafe-math-optimizations -fno-tree-loop-vectorize + +intrate,intspeed=base: # flags for integer base + EXTRA_COPTIMIZE = -fno-strict-aliasing -fgnu89-inline +# Notes about the above +# - 500.perlbench_r/600.perlbench_s needs -fno-strict-aliasing. +# - 502.gcc_r/602.gcc_s needs -fgnu89-inline or -z muldefs +# - For 'base', all benchmarks in a set must use the same options. +# - Therefore, all base benchmarks get the above. See: +# www.spec.org/cpu2017/Docs/runrules.html#BaseFlags +# www.spec.org/cpu2017/Docs/benchmarks/500.perlbench_r.html +# www.spec.org/cpu2017/Docs/benchmarks/502.gcc_r.html + + +#-------- Peak Tuning Flags ---------------------------------------------- +default=peak: + basepeak = yes # if you develop some peak tuning, remove this line. + # + # ----------------------- + # About the -fno switches + # ----------------------- + # + # For 'base', this config file (conservatively) disables some optimizations. + # You might want to try turning some of them back on, by creating a 'peak' + # section here, with individualized benchmark options: + # + # 500.perlbench_r=peak: + # OPTIMIZE = this + # 502.gcc_r=peak: + # OPTIMIZE = that + # 503.bwaves_r=peak: + # OPTIMIZE = other .....(and so forth) + # + # If you try it: + # - You must remove the 'basepeak' option, above. + # - You will need time and patience, to diagnose and avoid any errors. + # - perlbench is unlikely to work with strict aliasing + # - Some floating point benchmarks may get wrong answers, depending on: + # the particular chip + # the version of GCC + # other optimizations enabled + # -m32 vs. -m64 + # - See: http://www.spec.org/cpu2017/Docs/config.html + # - and: http://www.spec.org/cpu2017/Docs/runrules.html + + +#------------------------------------------------------------------------------ +# Tester and System Descriptions - EDIT all sections below this point +#------------------------------------------------------------------------------ +# For info about any field, see +# https://www.spec.org/cpu2017/Docs/config.html#fieldname +# Example: https://www.spec.org/cpu2017/Docs/config.html#hw_memory +#------------------------------------------------------------------------------- + +#--------- EDIT to match your version ----------------------------------------- +default: + sw_compiler001 = C/C++/Fortran: Version 7.2.1 of GCC, the + sw_compiler002 = GNU Compiler Collection + +#--------- EDIT info about you ------------------------------------------------ +# To understand the difference between hw_vendor/sponsor/tester, see: +# https://www.spec.org/cpu2017/Docs/config.html#test_sponsor +intrate,intspeed,fprate,fpspeed: # Important: keep this line + hw_vendor = My Corporation + tester = My Corporation + test_sponsor = My Corporation + license_num = nnn (Your SPEC license number) +# prepared_by = # Ima Pseudonym # Whatever you like: is never output + + +#--------- EDIT system availability dates ------------------------------------- +intrate,intspeed,fprate,fpspeed: # Important: keep this line + # Example # Brief info about field + hw_avail = # Nov-2099 # Date of LAST hardware component to ship + sw_avail = # Nov-2099 # Date of LAST software component to ship + +#--------- EDIT system information -------------------------------------------- +intrate,intspeed,fprate,fpspeed: # Important: keep this line + # Example # Brief info about field +# hw_cpu_name = # Intel Xeon E9-9999 v9 # chip name + hw_cpu_nominal_mhz = # 9999 # Nominal chip frequency, in MHz + hw_cpu_max_mhz = # 9999 # Max chip frequency, in MHz +# hw_disk = # 9 x 9 TB SATA III 9999 RPM # Size, type, other perf-relevant info + hw_model = # TurboBlaster 3000 # system model name +# hw_nchips = # 99 # number chips enabled + hw_ncores = # 9999 # number cores enabled + hw_ncpuorder = # 1-9 chips # Ordering options + hw_nthreadspercore = # 9 # number threads enabled per core + hw_other = # TurboNUMA Router 10 Gb # Other perf-relevant hw, or "None" + +# hw_memory001 = # 999 GB (99 x 9 GB 2Rx4 PC4-2133P-R, # The 'PCn-etc' is from the JEDEC +# hw_memory002 = # running at 1600 MHz) # label on the DIMM. + + hw_pcache = # 99 KB I + 99 KB D on chip per core # Primary cache size, type, location + hw_scache = # 99 KB I+D on chip per 9 cores # Second cache or "None" + hw_tcache = # 9 MB I+D on chip per chip # Third cache or "None" + hw_ocache = # 9 GB I+D off chip per system board # Other cache or "None" + + fw_bios = # American Megatrends 39030100 02/29/2016 # Firmware information +# sw_file = # ext99 # File system +# sw_os001 = # Linux Sailboat # Operating system +# sw_os002 = # Distribution 7.2 SP1 # and version + sw_other = # TurboHeap Library V8.1 # Other perf-relevant sw, or "None" +# sw_state = # Run level 99 # Software state. + +# Note: Some commented-out fields above are automatically set to preliminary +# values by sysinfo +# https://www.spec.org/cpu2017/Docs/config.html#sysinfo +# Uncomment lines for which you already know a better answer than sysinfo + +__HASH__ +500.perlbench_r=base=maple_test-m64: +# Last updated 2021-05-10 10:36:40 +opthash=1b55f44e78c515229834a282ce9d3013fee214077130f5cc6c8d469cce53274c +baggage= +compiler_version=\ +@eNp9VE1v2zAMvftX+NYNteK26ZIigA9Z6hYD0qZI3e0YyBLtqJUlTx+J08N++2Qnjr202MWC+Cjy\ +kXy0P5utfsbL5x+Lx9XiKXHHxHvRTOR+ahk3iAlfl0D0wJst5vN4lqzuZ7MotFqFKRNhTsgRmCeL\ +1a/l9OkpXu4dOEtrh7C6Ga1G14gzYSuUCxuOQ24k2ipclqC8xd3dfDG9XSXT5X2crB6nD/FzJDal\ +qZCQAk7x2/hu+jJPoksvwSoHM/FP43szKTKWWwXU3zKznviDQagVCUlr99HGR6jGUPmWb0BpJkV0\ +9pJaYaw/HnwbXKChbW6Xfy5vBhfXZ61/al0AHmWMwyQMmzr1GisIqSR1tWgcLuPp7UM8+G5z7V6B\ +wCkHxLHILc5BRyTAFAfk/DzIZZAqlgc0yKQyCotApq+k/iAHu7elgoxVTTfb/HWKAr9KhQ60kRR8\ +1/jKXOECaZvVb9C4ZzvEOW0U6ug1NdAeXSbeQKFaBBSxGnDThAoIZeo43QMnaWudEG4pUOQmYqAy\ +XSSzVoCpjkqpWbWPcxLj4Ch4r12plEa7lpSdiXBJMIfIEe/zTLWhpKoQBTeazwDDCoh2oNsOUsiw\ +ddLuPHDKIgHb7nHdGyvYbwvIDQNIXQ5lusE2Zn+AYtnun3xFWXX3ktvcLc/x3mYtGbRE9E4bKNB7\ +10lkGkmfIIcItTbc+CNsjeyshQvKsCLrHsUtKCWPiqlBNLyK2OhmdLS5iovRdXttgrhkrgptomJ4\ +FTgwKKrh1UmiPlUr3CxAuD6QHsks4xLTQyG6t8c9sRBLMaKKuR72xrsG8uZ+PJECDljX/o36PqjW\ +AWvpaH5i32f9gHhJo0G/kBT4xG+U6LlF8g8rtN94/8t/9v+r7/0FuibFEg== +compile_options=\ +@eNrVU21r2zAQ/u5fIfxdccdGWUJdsB0l8eZEwrIh2xfhOkqqLZaD5IS1v34n56UtDFpGv1RgfLq3\ +R3fP3aLVuKl+y7XaStTuOtVqO/JsZ1TdCbPXK2XEQRq1fgj9T74HogWX0L8aDK+ufc9L6JyNkB/s\ +rQnulA42dY3cwbZbhfVw6MTm+gvCNcLtGWDQIjzmjCTwW4xJXE5BYCTPREJzgnA6gG+lbBekFKR6\ +V+mgUI3EM5VLe9bMinmGWWWsNKCSf7rASBDsTtam0itIOaZlnBHBs4jPCBcOMY2y8OqELqKyoIKX\ +jOWEc0EZWcwZ2EQW5VMiJmlG+OXqboLTMk+I0/VXOplwUog4LXgINSK8QZh+hoIrU9+HuurUAV60\ +1i3ea1utJRi6e+ya0KjHqm8FOto7IyXetu0OH2TdtUY9SnQ6p7dm6aJciqWDOcUcScLVVlVWaYBe\ +b/T+6xArvVVaPotkLujGtntTy1vfS0YoScJXKTs60vgbZUXov+DP94DzhJWTLJpysL3ksrfGZJHM\ +xMXhw5Pre3SEoBPpPP1JoKL3ZLpvGKN5EcVplhY/zh194rxHJ8sij6CJT494fQr61MfAfwIwlxtg\ +vr9lh4/Kd5/x/x3wm/buFySyt85/26DLwlzmFKF+iLPxW6b9g/IL9c2jYga5Yrdp2+ZUMi3d1j5b\ +2b8rRMvz +exehash=1c69320bf26365e65e5b19b87fd09bbfdf73b3d6257845446d6001048f92fd40 + +500.perlbench_r=base=gcc-m64: +# Last updated 2021-05-13 10:18:46 +opthash=4a1fc46ed4b7dc5c387a83a4c8727837cdc03d41f8bddf80c915370e9e6911bd +baggage= +compiler_version=\ +@eNq9VUtv2zAMvudX6NYNraKmj7QJ4MMQBNuAYAnabDsasszYamRJ06Nxd9hvn2zHtddmGLBuvcSh\ ++PjITySFZrP4y/zm9uPyU7xcrcNnOvhsucxQ4rlwmEtkNTA7HMyWi8V8to7fz2YRyVUBxHpJoPCc\ +FFQLiJUGaZU3DEjvr1NKWJIxhgWX1Ch8NbwcnpKES0KpYfn4olL4EmfS42D2iLNYL+OvN+9Wq/nN\ +P8IbDongCZTAKv1zeNKYCqfwzlCtwQzW1GTgpuiZ7WCm5IZn3kCKdtzlU3TUJOnYLsMVd6kV9B7I\ +Tpmt1ZTtNQXdAjYggFqIR8RKqm2uXJ3xMOPuR5c1PjsdTYajM8JaqCN0+2G+WER1NQm1OcK4AseF\ +ZtHfwMe1JWnsSQrWpdwQPr4eY826YjuYjXkNnKzQrwITOo7aviTSIKXc0kRAsE8Kn24E1eEQZHPm\ +VCfYnFbX3/grXw0LEz6FFIeecVC6zlSKRxz7YB0U+HsI3wOzd+IOQ8lAO66k7TyrtLzk3zxgldwB\ +6wUNBW3BNPRg/iT1UDsry1B33jmwyaQnCMWogKgh5DFk65hC4rOeQsms/mnLCO4qi6RqZa1FT+J2\ +L7UZFV443pS8j7jhJWbKBJ4wvTzH1+eXV+PJ79UX5xejSRu+msaImuL+GtPOxeUGaGojrSwvu+Ma\ +uvI4VKbjBUQP8IRwLkPjBK7xxktWXUgL3HAdrtAo5V7So/sQ9vkW6vXJS0H+NAgHVmBghvV6JAe2\ +DY9BtA/du9Ckyt6ZX4aDyszTDGzETtjx8ckmXJ+h8qQZmjqZ6NAw5sq6gwpXb9/oEEXaQOiQ/0nO\ +YF23EypUCmKK6qYahC2N7sHYqiXq1wK9WdQLG4VnEfWW9ls0+Alw/ZnQ +compile_options=\ +@eNrVVG1r2zAQ/u5fIfxdcca6bAl1wXaUxJsTCb9Ati/CdZREmy0ZyS5df/1kO0lTGAxGKVRgfKd7\ +eaS757SRAlb5L7bnJQOybrgUembpRvGioaoVO67oA1N8/9u1P9iWEbVxce3xaDqe2JYV4DWZAds5\ +yoo5uhUOq1ruVHldMiprJrRsVcGcK7GRstTOoShgyUWuJPw8+jQaO/dcOHmuiuPkpjO0j/AgWmjc\ +QLegbnZuMZ0CWAAozwcdSQDnCUGB+W3myM+WRiAojmiAYwRgODLfjuvGCbGRijoXTsorBlc8Zvq8\ +s0rXESS50kyZLfbYOIoZQdesULnYmZRznPkRoknkJSuU0A4x9CJ3fEKnXpZimmSExChJKCZosybG\ +RiMvXiK6CCOUXNROownO4gB1e72KF4sEpdQP08Sd3JjbHgDEHwHcCwlrzgahFTrfM9Os5gi7+1f8\ +Ke+rAAZ7oxiDpZQ1fGBFIxV/YuC0TseMwk22pdsO4RQz9BnmJc81FwZ1b4r+ZQq5MC1gV5GkC7od\ +OnhnW8EMBIH7Zl0fALH/FZPUtV9QwLYM/QKSLSJvmRjbSzr0Vh9tghW9OLx7ftgWngFTiXAd/kDm\ +Rq9Elr5WBMep54dRmH4/F/OZNj0w2qaxZ+r3jP9vIvWph8C/ApAut4H59pYvyaC95qT975jdyvuf\ +JpG+6/zLClzG9sJyAPoRiOZvOXPvj2WmRGsvXZlcfjfqZXWqGs66Z+PqzfgDFjQx9g== +exehash=6baceb9eb267d444c46c4c9f978e50063408522981011f9ac78e7db729fc8926 + +519.lbm_r=base=gcc-m64: +# Last updated 2021-05-13 10:35:31 +opthash=d0595b41acba249b4b15e2950cf3b949e9504a149adac9800b3de173849eacd9 +baggage= +compiler_version=\ +@eNq9VUtv2zAMvudX6NYNraKmj7QJ4MMQBNuAYAnabDsasszYamRJ06Nxd9hvn2zHtddmGLBuvcSh\ ++PjITySFZrP4y/zm9uPyU7xcrcNnOvhsucxQ4rlwmEtkNTA7HMyWi8V8to7fz2YRyVUBxHpJoPCc\ +FFQLiJUGaZU3DEjvr1NKWJIxhgWX1Ch8NbwcnpKES0KpYfn4olL4EmfS42D2iLNYL+OvN+9Wq/nN\ +P8IbDongCZTAKv1zeNKYCqfwzlCtwQzW1GTgpuiZ7WCm5IZn3kCKdtzlU3TUJOnYLsMVd6kV9B7I\ +Tpmt1ZTtNQXdAjYggFqIR8RKqm2uXJ3xMOPuR5c1PjsdTYajM8JaqCN0+2G+WER1NQm1OcK4AseF\ +ZtHfwMe1JWnsSQrWpdwQPr4eY826YjuYjXkNnKzQrwITOo7aviTSIKXc0kRAsE8Kn24E1eEQZHPm\ +VCfYnFbX3/grXw0LEz6FFIeecVC6zlSKRxz7YB0U+HsI3wOzd+IOQ8lAO66k7TyrtLzk3zxgldwB\ +6wUNBW3BNPRg/iT1UDsry1B33jmwyaQnCMWogKgh5DFk65hC4rOeQsms/mnLCO4qi6RqZa1FT+J2\ +L7UZFV443pS8j7jhJWbKBJ4wvTzH1+eXV+PJ79UX5xejSRu+msaImuL+GtPOxeUGaGojrSwvu+Ma\ +uvI4VKbjBUQP8IRwLkPjBK7xxktWXUgL3HAdrtAo5V7So/sQ9vkW6vXJS0H+NAgHVmBghvV6JAe2\ +DY9BtA/du9Ckyt6ZX4aDyszTDGzETtjx8ckmXJ+h8qQZmjqZ6NAw5sq6gwpXb9/oEEXaQOiQ/0nO\ +YF23EypUCmKK6qYahC2N7sHYqiXq1wK9WdQLG4VnEfWW9ls0+Alw/ZnQ +compile_options=\ +@eNq9UlFPgzAQfudXNH3vmNFptsgSYKgoo82ARH1pkHVbFVrSglF/vWXM6RIfdffSu97lu7vvvlgK\ +VOUvbMVLBmTdcCn0xNKN4kVDVSuWXNFXpvjq3YEn0DKuNiUOHA7GwxG0LB/PyQRAeyMrZutW2Kxq\ +uV3ldcmorJnQslUFs3+4jZSlttdFgUouciXRxWA0GNpPXNh5rorN+VmXaN/QWrTIlIHOkG6WTjEe\ +A1QAJL8GHUiAZgkJfPPEs8DLrncxdbMU0yQjZBEkCcUkiOfEoKwBwqcArYRENWe90wqdr5ghodmg\ +DrfiH/kWHfT5RjGGSilr9MqKRir+wcCh7XpG5PwMgMt+zSm0/Anwfedo1PQNsXeLSerAA56gZW7k\ +k+wqcq8TkzvkbJv1gti/oQcFv5IILTwBpkM4Dx8DU/lHjG5nCO7ThUsJXqSuF0Zh+rCfpKMWWlEY\ +3x1Ta33055q5lE/P5ldPO/Sy+pbR/l4AbI8ZzY6pnn+6q9lj7qY3NAq9TllltVsNZ51Kf0j0E2qG\ +c4o= +exehash=b17469e48480b17716b457cef173dcb01bb9f937e33f10bfda3c01e7cce63d3b + +538.imagick_r=base=gcc-m64: +# Last updated 2021-06-01 19:42:39 +opthash=f82ded290c3df58b7c2eebd89f6f9377bf6eeeea69047f4bcaf68dd02039245c +baggage= +compiler_version=\ +@eNq9VUtv2zAMvudX6NYNraKmj7QJ4MMQBNuAYAnabDsasszYamRJ06Nxd9hvn2zHtddmGLBuvcSh\ ++PjITySFZrP4y/zm9uPyU7xcrcNnOvhsucxQ4rlwmEtkNTA7HMyWi8V8to7fz2YRyVUBxHpJoPCc\ +FFQLiJUGaZU3DEjvr1NKWJIxhgWX1Ch8NbwcnpKES0KpYfn4olL4EmfS42D2iLNYL+OvN+9Wq/nN\ +P8IbDongCZTAKv1zeNKYCqfwzlCtwQzW1GTgpuiZ7WCm5IZn3kCKdtzlU3TUJOnYLsMVd6kV9B7I\ +Tpmt1ZTtNQXdAjYggFqIR8RKqm2uXJ3xMOPuR5c1PjsdTYajM8JaqCN0+2G+WER1NQm1OcK4AseF\ +ZtHfwMe1JWnsSQrWpdwQPr4eY826YjuYjXkNnKzQrwITOo7aviTSIKXc0kRAsE8Kn24E1eEQZHPm\ +VCfYnFbX3/grXw0LEz6FFIeecVC6zlSKRxz7YB0U+HsI3wOzd+IOQ8lAO66k7TyrtLzk3zxgldwB\ +6wUNBW3BNPRg/iT1UDsry1B33jmwyaQnCMWogKgh5DFk65hC4rOeQsms/mnLCO4qi6RqZa1FT+J2\ +L7UZFV443pS8j7jhJWbKBJ4wvTzH1+eXV+PJ79UX5xejSRu+msaImuL+GtPOxeUGaGojrSwvu+Ma\ +uvI4VKbjBUQP8IRwLkPjBK7xxktWXUgL3HAdrtAo5V7So/sQ9vkW6vXJS0H+NAgHVmBghvV6JAe2\ +DY9BtA/du9Ckyt6ZX4aDyszTDGzETtjx8ckmXJ+h8qQZmjqZ6NAw5sq6gwpXb9/oEEXaQOiQ/0nO\ +YF23EypUCmKK6qYahC2N7sHYqiXq1wK9WdQLG4VnEfWW9ls0+Alw/ZnQ +compile_options=\ +@eNrtVE1vozAQvfMrLN8N6SrbKlGpBIS27BJsBZC6e7EodRq3YCMbqm5+/RpI2ubSU5tTfPHgGebj\ +zdNLpEB18czWvGJANi2XQs8t3SpetlR14oEr+sIUX/9z4Rm0jKlNiAsn9mwyhZYV4CWZA+hsZM0c\ +3QmH1R136qKpGJUNE1p2qmTOB7OVstLOY1miiotCSXRh/7Qnzj0XTlGocnM+7R3dK3oUHTJhoD9I\ +tw9uOZsBVAIk943aEqBFSsLAXMki9PMbgCJ790a9PMM0zQlZhWlKMQmTJTGZ8A+A1kKihrPR6IQu\ +1syg0G5Qn7jm22JID0Z/qxhDlZQNemFlKxXf7n7kwjTKwOHZFY/J+RSAy3HmK2gFcxAE7tFwGgti\ +/xcmmQsPQIOWWVhA8uvYu0mN7xDAweuHSXBL9wGfIwotPAemSrSM/oYm+qvhHRoK77KVRwleZZ4f\ +xVH2Z9/3gDO04ij5fUwWjl/fx6RLef9kIvRVX6aq38n1tkUAhhXHi2Ny6rs3bQZaetktjSO/J15V\ +72bEeU/iDww+yc5Jdk6yc5KdI8vOf2Dz8Is= +exehash=5fecfa5494e0b35756916f9e524fafee9ba36469de705f9e33ee6082bdf1d8bc + diff --git a/build/tools/spec/maplec b/build/tools/spec/maplec new file mode 120000 index 0000000000000000000000000000000000000000..0d46bbe86784244a11ac16fcbfe9e9b01a5f94da --- /dev/null +++ b/build/tools/spec/maplec @@ -0,0 +1 @@ +../common/maplec \ No newline at end of file diff --git a/build/tools/spec/mplfe.cfg b/build/tools/spec/mplfe.cfg new file mode 100644 index 0000000000000000000000000000000000000000..523eccea9e626bf2d1bf86c003f9ee2498354621 --- /dev/null +++ b/build/tools/spec/mplfe.cfg @@ -0,0 +1,643 @@ +#------------------------------------------------------------------------------ +# SPEC CPU2017 config file for: gcc / g++ / gfortran on Linux x86 +#------------------------------------------------------------------------------ +# +# Usage: (1) Copy this to a new name +# cd $SPEC/config +# cp Example-x.cfg myname.cfg +# (2) Change items that are marked 'EDIT' (search for it) +# +# SPEC tested this config file with: +# Compiler version(s): 4.4.7, 4.9.2, 5.2.0, 6.3.0, 7.2.1, 8.1.0 +# Operating system(s): Oracle Linux Server 6.5 and 7.4 / +# Red Hat Enterprise Linux Server 6.5 and 7.4 +# Hardware: Xeon +# +# If your system differs, this config file might not work. +# You might find a better config file at http://www.spec.org/cpu2017/results +# +# Known Limitations with GCC 4 +# +# (1) Possible problem: compile time messages +# error: unrecognized command line option '...' +# Recommendation: Use a newer version of the compiler. +# If that is not possible, remove the unrecognized +# option from this config file. +# +# (2) Possible problem: run time errors messages +# 527.cam4_r or 627.cam4_s *** Miscompare of cam4_validate.txt +# Recommendation: Use a newer version of the compiler. +# If that is not possible, try reducing the optimization. +# +# +# Compiler issues: Contact your compiler vendor, not SPEC. +# For SPEC help: http://www.spec.org/cpu2017/Docs/techsupport.html +#------------------------------------------------------------------------------ + + +#--------- Label -------------------------------------------------------------- +# Arbitrary string to tag binaries (no spaces allowed) +# Two Suggestions: # (1) EDIT this label as you try new ideas. +%define label maplec # (2) Use a label meaningful to *you*. + + +#--------- Preprocessor ------------------------------------------------------- +%ifndef %{bits} # EDIT to control 32 or 64 bit compilation. Or, +% define bits 64 # you can set it on the command line using: +%endif # 'runcpu --define bits=nn' + +%ifndef %{build_ncpus} # EDIT to adjust number of simultaneous compiles. +% define build_ncpus 8 # Or, you can set it on the command line: +%endif # 'runcpu --define build_ncpus=nn' + +# Don't change this part. +%define os LINUX +%if %{bits} == 64 +% define model -m64 +%elif %{bits} == 32 +% define model -m32 +%else +% error Please define number of bits - see instructions in config file +%endif +%if %{label} =~ m/ / +% error Your label "%{label}" contains spaces. Please try underscores instead. +%endif +%if %{label} !~ m/^[a-zA-Z0-9._-]+$/ +% error Illegal character in label "%{label}". Please use only alphanumerics, underscore, hyphen, and period. +%endif + + + +#--------- Global Settings ---------------------------------------------------- +# For info, see: +# https://www.spec.org/cpu2017/Docs/config.html#fieldname +# Example: https://www.spec.org/cpu2017/Docs/config.html#tune + +command_add_redirect = 1 +flagsurl = $[top]/config/flags/gcc.xml +ignore_errors = 1 +iterations = 1 +label = %{label}-m%{bits} +line_width = 1020 +log_line_width = 1020 +makeflags = --jobs=%{build_ncpus} +mean_anyway = 1 +output_format = txt,html,cfg,pdf,csv +preenv = 1 +reportable = 0 +tune = base + + +#--------- How Many CPUs? ----------------------------------------------------- +# Both SPECrate and SPECspeed can test multiple chips / cores / hw threads +# - For SPECrate, you set the number of copies. +# - For SPECspeed, you set the number of threads. +# See: https://www.spec.org/cpu2017/Docs/system-requirements.html#MultipleCPUs +# +# q. How many should I set? +# a. Unknown, you will have to try it and see! +# +# To get you started, some suggestions: +# +# copies - This config file defaults to testing only 1 copy. You might +# try changing it to match the number of cores on your system, +# or perhaps the number of virtual CPUs as reported by: +# grep -c processor /proc/cpuinfo +# Be sure you have enough memory. See: +# https://www.spec.org/cpu2017/Docs/system-requirements.html#memory +# +# threads - This config file sets a starting point. You could try raising +# it. A higher thread count is much more likely to be useful for +# fpspeed than for intspeed. +# +intrate,fprate: + copies = 1 # EDIT to change number of copies (see above) +intspeed,fpspeed: + threads = 4 # EDIT to change number of OpenMP threads (see above) + +%ifndef %{gcc_dir} +% define gcc_dir /gcc_dir-is-not-used/tools/gcc-linaro-7.5.0 # EDIT (see above) +%endif + +#------- Compilers ------------------------------------------------------------ +default: +# EDIT: The parent directory for your compiler. +# Do not include the trailing /bin/ +# Do not include a trailing slash +# Examples: +# 1 On a Red Hat system, you said +# 'yum install devtoolset-7' +# Use: % define gcc_dir /opt/rh/devtoolset-7/root/usr +# +# 2 You built GCC in: /disk1/mybuild/gcc-8.1.0/bin/gcc +# Use: % define gcc_dir /disk1/mybuild/gcc-8.1.0 +# +# 3 You want: /usr/bin/gcc +# Use: % define gcc_dir /usr +# WARNING: See section +# "Known Limitations with GCC 4" +# + LINARO = $MAPLE_ROOT/tools/gcc-linaro-7.5.0 + CC = $(MAPLE_ROOT)/build/tools/spec/maplec + CXX = $(LINARO)/bin/aarch64-linux-gnu-g++ -std=c++03 + FC = $(LINARO)/bin/aarch64-linux-gnu-gfortran + # How to say "Show me your version, please" + CC_VERSION_OPTION = -v + CXX_VERSION_OPTION = -v + FC_VERSION_OPTION = -v + + QEMU_RUN = $MAPLE_ROOT/tools/bin/qemu-aarch64 -L $LINARO/aarch64-linux-gnu/libc + +default: +%if %{bits} == 64 + sw_base_ptrsize = 64-bit + sw_peak_ptrsize = 64-bit +%else + sw_base_ptrsize = 32-bit + sw_peak_ptrsize = 32-bit +%endif + + +#--------- Portability -------------------------------------------------------- +default: # data model applies to all benchmarks +%if %{bits} == 32 + # Strongly recommended because at run-time, operations using modern file + # systems may fail spectacularly and frequently (or, worse, quietly and + # randomly) if a program does not accommodate 64-bit metadata. + EXTRA_PORTABILITY = -D_FILE_OFFSET_BITS=64 +%else + EXTRA_PORTABILITY = -DSPEC_LP64 +%endif + +# Benchmark-specific portability (ordered by last 2 digits of bmark number) + +500.perlbench_r,600.perlbench_s: #lang='C' +%if %{bits} == 32 +% define suffix IA32 +%else +% define suffix X64 +%endif + PORTABILITY = -DSPEC_%{os}_%{suffix} + +502.gcc_r: #lang='c' + CPORTABILITY = -DHAVE_ALLOCA_H + +521.wrf_r,621.wrf_s: #lang='F,C' + CPORTABILITY = -DSPEC_CASE_FLAG + FPORTABILITY = -fconvert=big-endian + +523.xalancbmk_r,623.xalancbmk_s: #lang='CXX' + PORTABILITY = -DSPEC_%{os} + +526.blender_r: #lang='CXX,C' + PORTABILITY = -funsigned-char -DSPEC_LINUX + +527.cam4_r,627.cam4_s: #lang='F,C' + PORTABILITY = -DSPEC_CASE_FLAG + +628.pop2_s: #lang='F,C' + CPORTABILITY = -DSPEC_CASE_FLAG + FPORTABILITY = -fconvert=big-endian + + +#-------- Tuning Flags common to Base and Peak -------------------------------- + +# +# Speed (OpenMP and Autopar allowed) +# +%if %{bits} == 32 + intspeed,fpspeed: + # + # Many of the speed benchmarks (6nn.benchmark_s) do not fit in 32 bits + # If you wish to run SPECint2017_speed or SPECfp2017_speed, please use + # + # runcpu --define bits=64 + # + fail_build = 1 +%else + intspeed,fpspeed: + EXTRA_OPTIMIZE = -fopenmp -lgomp -DSPEC_OPENMP + fpspeed: + # + # 627.cam4 needs a big stack; the preENV will apply it to all + # benchmarks in the set, as required by the rules. + # + preENV_OMP_STACKSIZE = 120M +%endif + + +#-------- Baseline Tuning Flags ---------------------------------------------- +# +# EDIT if needed -- Older GCC might not support some of the optimization +# switches here. See also 'About the -fno switches' below. +# +default=base: # flags for all base + OPTIMIZE = + +intrate,intspeed=base: # flags for integer base + EXTRA_COPTIMIZE = +# Notes about the above +# - 500.perlbench_r/600.perlbench_s needs -fno-strict-aliasing. +# - 502.gcc_r/602.gcc_s needs -fgnu89-inline or -z muldefs +# - For 'base', all benchmarks in a set must use the same options. +# - Therefore, all base benchmarks get the above. See: +# www.spec.org/cpu2017/Docs/runrules.html#BaseFlags +# www.spec.org/cpu2017/Docs/benchmarks/500.perlbench_r.html +# www.spec.org/cpu2017/Docs/benchmarks/502.gcc_r.html + + +#-------- Peak Tuning Flags ---------------------------------------------- +default=peak: + basepeak = yes # if you develop some peak tuning, remove this line. + # + # ----------------------- + # About the -fno switches + # ----------------------- + # + # For 'base', this config file (conservatively) disables some optimizations. + # You might want to try turning some of them back on, by creating a 'peak' + # section here, with individualized benchmark options: + # + # 500.perlbench_r=peak: + # OPTIMIZE = this + # 502.gcc_r=peak: + # OPTIMIZE = that + # 503.bwaves_r=peak: + # OPTIMIZE = other .....(and so forth) + # + # If you try it: + # - You must remove the 'basepeak' option, above. + # - You will need time and patience, to diagnose and avoid any errors. + # - perlbench is unlikely to work with strict aliasing + # - Some floating point benchmarks may get wrong answers, depending on: + # the particular chip + # the version of GCC + # other optimizations enabled + # -m32 vs. -m64 + # - See: http://www.spec.org/cpu2017/Docs/config.html + # - and: http://www.spec.org/cpu2017/Docs/runrules.html + + +#------------------------------------------------------------------------------ +# Tester and System Descriptions - EDIT all sections below this point +#------------------------------------------------------------------------------ +# For info about any field, see +# https://www.spec.org/cpu2017/Docs/config.html#fieldname +# Example: https://www.spec.org/cpu2017/Docs/config.html#hw_memory +#------------------------------------------------------------------------------- + +#--------- EDIT to match your version ----------------------------------------- +default: + sw_compiler001 = C/C++/Fortran: Version 7.2.1 of GCC, the + sw_compiler002 = GNU Compiler Collection + +#--------- EDIT info about you ------------------------------------------------ +# To understand the difference between hw_vendor/sponsor/tester, see: +# https://www.spec.org/cpu2017/Docs/config.html#test_sponsor +intrate,intspeed,fprate,fpspeed: # Important: keep this line + hw_vendor = My Corporation + tester = My Corporation + test_sponsor = My Corporation + license_num = nnn (Your SPEC license number) +# prepared_by = # Ima Pseudonym # Whatever you like: is never output + + +#--------- EDIT system availability dates ------------------------------------- +intrate,intspeed,fprate,fpspeed: # Important: keep this line + # Example # Brief info about field + hw_avail = # Nov-2099 # Date of LAST hardware component to ship + sw_avail = # Nov-2099 # Date of LAST software component to ship + +#--------- EDIT system information -------------------------------------------- +intrate,intspeed,fprate,fpspeed: # Important: keep this line + # Example # Brief info about field +# hw_cpu_name = # Intel Xeon E9-9999 v9 # chip name + hw_cpu_nominal_mhz = # 9999 # Nominal chip frequency, in MHz + hw_cpu_max_mhz = # 9999 # Max chip frequency, in MHz +# hw_disk = # 9 x 9 TB SATA III 9999 RPM # Size, type, other perf-relevant info + hw_model = # TurboBlaster 3000 # system model name +# hw_nchips = # 99 # number chips enabled + hw_ncores = # 9999 # number cores enabled + hw_ncpuorder = # 1-9 chips # Ordering options + hw_nthreadspercore = # 9 # number threads enabled per core + hw_other = # TurboNUMA Router 10 Gb # Other perf-relevant hw, or "None" + +# hw_memory001 = # 999 GB (99 x 9 GB 2Rx4 PC4-2133P-R, # The 'PCn-etc' is from the JEDEC +# hw_memory002 = # running at 1600 MHz) # label on the DIMM. + + hw_pcache = # 99 KB I + 99 KB D on chip per core # Primary cache size, type, location + hw_scache = # 99 KB I+D on chip per 9 cores # Second cache or "None" + hw_tcache = # 9 MB I+D on chip per chip # Third cache or "None" + hw_ocache = # 9 GB I+D off chip per system board # Other cache or "None" + + fw_bios = # American Megatrends 39030100 02/29/2016 # Firmware information +# sw_file = # ext99 # File system +# sw_os001 = # Linux Sailboat # Operating system +# sw_os002 = # Distribution 7.2 SP1 # and version + sw_other = # TurboHeap Library V8.1 # Other perf-relevant sw, or "None" +# sw_state = # Run level 99 # Software state. + +# Note: Some commented-out fields above are automatically set to preliminary +# values by sysinfo +# https://www.spec.org/cpu2017/Docs/config.html#sysinfo +# Uncomment lines for which you already know a better answer than sysinfo + +__HASH__ +500.perlbench_r=base=maple_test-m64: +# Last updated 2021-05-10 10:36:40 +opthash=1b55f44e78c515229834a282ce9d3013fee214077130f5cc6c8d469cce53274c +baggage= +compiler_version=\ +@eNp9VE1v2zAMvftX+NYNteK26ZIigA9Z6hYD0qZI3e0YyBLtqJUlTx+J08N++2Qnjr202MWC+Cjy\ +kXy0P5utfsbL5x+Lx9XiKXHHxHvRTOR+ahk3iAlfl0D0wJst5vN4lqzuZ7MotFqFKRNhTsgRmCeL\ +1a/l9OkpXu4dOEtrh7C6Ga1G14gzYSuUCxuOQ24k2ipclqC8xd3dfDG9XSXT5X2crB6nD/FzJDal\ +qZCQAk7x2/hu+jJPoksvwSoHM/FP43szKTKWWwXU3zKznviDQagVCUlr99HGR6jGUPmWb0BpJkV0\ +9pJaYaw/HnwbXKChbW6Xfy5vBhfXZ61/al0AHmWMwyQMmzr1GisIqSR1tWgcLuPp7UM8+G5z7V6B\ +wCkHxLHILc5BRyTAFAfk/DzIZZAqlgc0yKQyCotApq+k/iAHu7elgoxVTTfb/HWKAr9KhQ60kRR8\ +1/jKXOECaZvVb9C4ZzvEOW0U6ug1NdAeXSbeQKFaBBSxGnDThAoIZeo43QMnaWudEG4pUOQmYqAy\ +XSSzVoCpjkqpWbWPcxLj4Ch4r12plEa7lpSdiXBJMIfIEe/zTLWhpKoQBTeazwDDCoh2oNsOUsiw\ +ddLuPHDKIgHb7nHdGyvYbwvIDQNIXQ5lusE2Zn+AYtnun3xFWXX3ktvcLc/x3mYtGbRE9E4bKNB7\ +10lkGkmfIIcItTbc+CNsjeyshQvKsCLrHsUtKCWPiqlBNLyK2OhmdLS5iovRdXttgrhkrgptomJ4\ +FTgwKKrh1UmiPlUr3CxAuD6QHsks4xLTQyG6t8c9sRBLMaKKuR72xrsG8uZ+PJECDljX/o36PqjW\ +AWvpaH5i32f9gHhJo0G/kBT4xG+U6LlF8g8rtN94/8t/9v+r7/0FuibFEg== +compile_options=\ +@eNrVU21r2zAQ/u5fIfxdccdGWUJdsB0l8eZEwrIh2xfhOkqqLZaD5IS1v34n56UtDFpGv1RgfLq3\ +R3fP3aLVuKl+y7XaStTuOtVqO/JsZ1TdCbPXK2XEQRq1fgj9T74HogWX0L8aDK+ufc9L6JyNkB/s\ +rQnulA42dY3cwbZbhfVw6MTm+gvCNcLtGWDQIjzmjCTwW4xJXE5BYCTPREJzgnA6gG+lbBekFKR6\ +V+mgUI3EM5VLe9bMinmGWWWsNKCSf7rASBDsTtam0itIOaZlnBHBs4jPCBcOMY2y8OqELqKyoIKX\ +jOWEc0EZWcwZ2EQW5VMiJmlG+OXqboLTMk+I0/VXOplwUog4LXgINSK8QZh+hoIrU9+HuurUAV60\ +1i3ea1utJRi6e+ya0KjHqm8FOto7IyXetu0OH2TdtUY9SnQ6p7dm6aJciqWDOcUcScLVVlVWaYBe\ +b/T+6xArvVVaPotkLujGtntTy1vfS0YoScJXKTs60vgbZUXov+DP94DzhJWTLJpysL3ksrfGZJHM\ +xMXhw5Pre3SEoBPpPP1JoKL3ZLpvGKN5EcVplhY/zh194rxHJ8sij6CJT494fQr61MfAfwIwlxtg\ +vr9lh4/Kd5/x/x3wm/buFySyt85/26DLwlzmFKF+iLPxW6b9g/IL9c2jYga5Yrdp2+ZUMi3d1j5b\ +2b8rRMvz +exehash=1c69320bf26365e65e5b19b87fd09bbfdf73b3d6257845446d6001048f92fd40 + +600.perlbench_s=base=maplec-m64: +# Last updated 2021-05-12 15:35:30 +opthash=3cf993256ffc5aaeca4f7b92e3300c53cdd5a2bdb530ca54cfd558466978ed44 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNrVUsGOmzAQvfMVlu+EVKpWarSsBMQJbg22sJHSXiyWOKrbgJFNqvbva0iT3ZWyl2ovi0DMzHu8\ +wW+mNH3YNT/VQR8VMMOoTe9WgRutbkdpT/1eW/lLWX34E8MPMPCh85QYLheflncwCDJasBWA0XfT\ +qcid+uhR91HXDEfVgtDf5iK6MCBcc4Yy/yrXKK23PmCoIjKjFQIhXvhnr90YYeqjdmj6SOhOhbmu\ +lLtUclGQkDXWKetL6vcYWeUDN6jWNv3eS65pnRIkOUl4jricOuKExEsPSZJUWyQ3mCB+TadMclpX\ +GZpqc0o3G46ETLHg8d1HcL3OB5AEl/VO7mYkPJhB9d1wwShDZcGek9nEu3fmZFv1AINsBbIsvmnY\ +GaTpZ8pEDF+4BwPvcsbqDUm23GMvnZzRFJVZLq+Ed2Ht/OOMViJJMcHi6+VkTxbDgK4A2okq8dYK\ +XOBvyJNumj6Lnak3Jdmk5oW/vLav/zXoe/P4Q7Wje5g4x+5J4jo7AObBkvVrU39TD3ynIhG5/zqd\ +9uDY/WtO62mnni3UX8u2Jz8= +exehash=2d8e7986845a1a99ef89f93cd339b6da23b7cfe2fc85ca3e8925db6f58260583 + +619.lbm_s=base=maplec-m64: +# Last updated 2021-05-12 16:29:02 +opthash=7affc07e1d7c5ca4633093daa05c20102ce1dec866120559a921160cddd58e76 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNqVUG1rgzAY/J5fEfLd2kEZTGpBY2ZdowlW2csXaV1kbmpE7WD/ftG+Ci1sIZCH3OVyd4GstHLz\ +JbK8EFDWXS6r1gBt1+RplzS76j1vkm/R5NmPie4QUGOrKCaaTh6mMwQAZj43INI/ZCn0dlfp27zS\ +y01diBRqasuj6ERCzVlzgtUROMSOXTVQK3RJ8szCFWWWAy+XlslaVGV9eJUwTgKfD8j+gvL7GYTz\ +Vu6aVCwQwAbE2LzqZA8y+4nxyEQjWwgo+5jHj9Ry1wobWxxQmwR4mZwIY88IMAOSlyi0lMPI8703\ +okhXvQ9ieypnYWTZHvWi1+OfQx4EqBesbvX5p37mcvsp0q5d9JyiPPNPkSEc+qDOrbL+kUjp+Fa0\ +TKhn9+UU5UGaxX3RFy3/AtPTsPg= +exehash=4796f3d722b9339855ae459928ddcee0650c458340a971fc905fa5338976c68c + +605.mcf_s=base=maplec-m64: +# Last updated 2021-05-12 17:02:05 +opthash=f8c9b30b6e77a4a59a777237ddaf5842ad1c2a8ae410864ef1a31d5c27b9ec03 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNqVUV1rgzAUfc+vCHm3drANJrWgada6qQk1wraX0LqUualxxg7275fa2g9ooQuBhHtObs45N1aV\ +VS6+5CovJFR1m6tKO0C3TZ61ollX73kjfmSTr35ddIOAuWpDcdFw8DC8QwBgGjEHIvtDldLW68pe\ +5pVdLupCZtAyW/VNBwpak4QRbI54Qvx0CqEV6Fpm4lurpt2hwks5FUnK2JwkiaCMxBGDR8taqVpW\ +Zd3zD4xdIWT3txCOtFo3mRwjgB2IsXtW4Rak/hNl3EUnchEwtjBLH0NvmhjsVHqH+iTGM4F7xpVe\ +EKAOJC987pkCD6LgjZjHZ011v2ypjM655wdhwF97MZ1RBMIgfr40AHhNcCO1/JRZq8cbTlEe+Pss\ +IOyCCieXUvyHI9Mn8vhMhIG/Ca0od61pupnAUfx/9bTCPg== +exehash=c4863fbc60ab23589893d59f3b7f8b19f77ca751d2a775ef1905cd68a80904ea + +505.mcf_r=base=maplec-m64: +# Last updated 2021-05-12 17:04:02 +opthash=cd00cc44466c7c00fcb0a07a84b8bdec510af969b5da706b722633229c2d2efc +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNqNkF1PgzAYhe/7K5reM2aiJpKxBApuaKENH4leNRt2EQWKFEz89xYEdYsa3zRpk3PanvNEsjaq\ +3bM4FKWAsukKWSsLqK4t8o63ff1QtPxVtMXhzUZnCOij0hYbLRdXywsEAKYhsyAyH2UlTNXX5r6o\ +zWrXlCKHhl5yfnQhoeElzMd6izzfzTYQGoFqRM5flGy7SeVOllKeZIzFfpJwyvwoZPBkJithl+cQ\ +rpTs21ysEcAWxNj+McuHSN0bylIbHQVDQBfALLsmzibR2nHIUXX9CG85nh3/TD1e9e/S2OGMxqnj\ +BiRI7+cfxvQIkCC6/Y3fyazk/knknVoPBMrqi8ZnFQjHnsT7A0LopFtOAncoUlaTn2YDlW9I3gG2\ +95r+ +exehash=806db0e68b5994ed49999cc86262dbea2e13c31853d3ba087eb2f180c940ee06 + +502.gcc_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=2839b1967320158040c55387a370c4661288143e5e404dc55ea5be68a750538d +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNq1kV9PgzAUxd/5FE3fGdM4E5exBLoOqqxtBhh9ajbWxSrQScHEby/g8M+ivnnTpjc5J7f9nVJd\ +2sXmSe5VLoE+1EqXZmqZulJZLaqm3KlKvMhK7V9deAattjWtxYXj0dV4Ai0LsRWfAug86EI6pimd\ +rSqdYnPIZQbsdulh6EgDexFzjNqDLrCfBsAmo247qszyZif73hxkJp6NruqjXUzG50PrpQkTccr5\ +GsexYBzTFW81QkWAurmhd4sFYnRJAhGC0zoOifjlBQAzo5sqk3NooSlAyP2R4F1k/jXjiQu/4UCr\ +xUY8XUZeELfad7Re9TFFoRgM/8ra34fvkrUnOFsnnk8iktwPz+qRoRURevPbV53UTG8fZVabeRdb\ +XnxG+MEPQB9OtPgjuZWXhCIifoefF0c/S7sov+T4BmRTt5k= +exehash=0 + +520.omnetpp_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=be6e4dd67b5187b3cefa0f68d2b9d0de0da20ab650fd3c3ee25c7e2e09cbff32 +baggage= +compiler_version=\ +*IENYWENfVkVSU0lPTl9PUFRJT046Ci9iaW4vc2g6IENDOiBjb21tYW5kIG5vdCBmb3VuZAo= +compile_options=\ +@eNq1UNFOgzAUfe9XNH1nzkRNJGMJlLqhHW2gjfjUTOgSFCgBZuLfW3E45rv3pTfnnt57zolN49T7\ +d30oKw1NO5Sm6V3QD12ZD6o7NkXZqQ/dlYdPD10jYNveUjy0XNwvbxEAmO24CxHG0MmhY6YVCwOd\ +MOXEwmEckkBuoBP1ZX2s9oPprlr7FLqdY7avTaEr++E5ElsVExHIiIYkOW1SvhRMpZLzhKSpYpzE\ +Ow7PdWJRfncD4ao3xy7XawSwC3GWeVbh1LPgkXHhoQvBCFgbmMsH6m9SO7sUP04DEuOtmgj/4WY8\ +QzKR+IqzRPhBRCPxMqkZrSFAo/jpJ/E/tTKvbzof+vUcPDuEcAyAhr9Z0JDJ7xxmIXwBBSCXiw== +exehash=0 + +523.xalancbmk_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=a5f92e3f29c9a9dc5714dc66815a936b3270df34bf15c51d6007f825c19a3bfd +baggage= +compiler_version=\ +*IENYWENfVkVSU0lPTl9PUFRJT046Ci9iaW4vc2g6IENDOiBjb21tYW5kIG5vdCBmb3VuZAo= +compile_options=\ +@eNrtU9FumzAUfecrLL8TuqmbtKip5ICX0tnYwmaiTxZ1aEVHcIVJ1f59HZhTsk1969ssIZ17z8G6\ +3HPITBfuql/1XdPWwDwOjensMrBD3+hB9ftu2/Tqqe6bu5cV/AQDB62TrODZ4tvZFxgEMaN8CWAc\ +g1CD0PgrFgaEieDYtZMswetiAxxCnKuMKXmVY5QI1ygRQZlKM4qpomKjCEMJzkGYLtzzXPe6tvoN\ +RVuzO62iZvfYzlq2ep5V+6FpI2rviam2bu4o7Wi9M/3LnxLZV53VZtJo0z0dBFVbdTpqOt3ut7Ub\ +lefsWpWUcJSLw4jHRiFT4suJFL4UqDyPZ8VnjxNGPfyJSJogyca33HWqENhvBAuBNtgvZdynQoVk\ +ShSc545VjOOMcnA4v3mSZkV50uBfzwG4sGbvPvkSBvESxGW5cpZ5zNbXjMsVPHEQBs7XmBffCdoI\ +x526ObJrnMVXyl1w1Pw3+GMMHtfNWS7ROiWpvPF+TG6PLC5ljtQ/NS4AMHDKH9OP+nb+isyFuX2o\ +9WAvwVx1zAQAY2RIMqXn/ZlGISsOuZqF6hW+xlPZ +exehash=0 + +525.x264_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=17555907b69668487c703e8ad30fdca935346ca79afa0bfdc1ae288920733ee3 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNrtkt9vgjAQx9/5K5q+I+rUbUZMAJmyIW34kcynBrFu3YCagsb990PEDc22V/dA06TX3l179+nX\ +4amchO90zWIK+CZnPM2GUpYLFuVEbNMVE2RHBVt/qLADpcLMihAVtlv37T6U0DEDrLkALAlf6C6M\ +2SrMKel3+0NJMtAcDwFUXnlClWybKkuWKkm4iWkE5GLy05stDuSJh02jWJyJqQdTIFvxikZ8RTIR\ +KSwtoq19d9A7bGumQve5CLP6ScSThKfVfUQLfES8AGPX9DyCsOnM8ZlPX/gmciemq7b3ne5Nrz+4\ +vQOXo0qw8aAHwCjjWxHRMZSMITAM9cf+jk6kPyLsq/CsWSgVUAwcPNja1Ct8542XXt10jBk5BVyR\ +RFmN+ey7GsHI9TXdsi1/cSq6BAIl23KefvvmizHiyzca5dn4ADVOvgF/0QGgRGdP/uA61/wZsS39\ +ACdOqngUHEDXKNfVWREUjSgbUf4bUZZMGkk2kryuJD8BghRXuw== +exehash=0 + +531.deepsjeng_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=c9d27d3cf5376f585e57a3f2a29ee65eb5a8ddb7a1042d47749d036bb8f42043 +baggage= +compiler_version=\ +*IENYWENfVkVSU0lPTl9PUFRJT046Ci9iaW4vc2g6IENDOiBjb21tYW5kIG5vdCBmb3VuZAo= +compile_options=\ +@eNqNkF9PgzAUxd/7KW76zjKTxUQylkBbJ1poQyFhT41il9Q/1AAz8dvb4ZDNJ+/T7T2nvb/T3LXB\ +++Or2ds3A+5jsK7tQ9QPnW0G3R3aZ9vpT9PZ/VeErzDybe8tEV4ubpYrjBARmQwBEwJBA4Gbnlg4\ +CKiSzI9pTllSbY/nLOZcZywTxe4k67gqhVaVlAVTSgvJ8kzCXCcXl9crgHXvDl1jNhiREEhdR37t\ +1IvkXsgywhcUGHk2IqtbHm+V1y6JRjVhObnTs+GfiONdVpdFrKUoyjhJeVruphUjL0Y8zR9+/uZP\ +rd3Ti2mGfnM+nLEBxlSc/gbkVFTHcGfJvgF3B3iC +exehash=0 + +541.leela_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=c715a7e7b712428302fadbd8205a3f5ff13d2a99dbcb03cfef4de14ebb0dbb76 +baggage= +compiler_version=\ +*IENYWENfVkVSU0lPTl9PUFRJT046Ci9iaW4vc2g6IENDOiBjb21tYW5kIG5vdCBmb3VuZAo= +compile_options=\ +@eNp9kE9LxDAQxe/5FEPuKSuoYNkutElcq9kktCnUU9CahfqnkbYr+O2NdevuenBOw5uXmd+L9B15\ +e3hx2/bVgX8fW98NMRrGvm1G2++6p7a3H65vt58JPsMotEOwJHgRXS0uMEJUbXQMmFIgDRA/r4g8\ +EFZqHmQmGc+qNZA82ms2rYyyZaV1wcvSKs3lRsOh9i6hL88BloPf9Y1bYURjoHWdhFtzr7JbpU2C\ +T05jFICorq5Fui7D7BRjmmZc0hs7G/7nmh7w2hSp1aowaZaL3NzPeydIjEQu735+4U8t/eOza8Zh\ +dSweWAGmKIL9phJMVd+JjuJ8ASVmcYc= +exehash=0 + +548.exchange2_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=7c95017cd71c6e94420e5cb70d3cc0a48a81eb16a8246cb031329e6470ab6a5c +baggage= +compiler_version=\ +*IEZDX1ZFUlNJT05fT1BUSU9OOgovYmluL3NoOiBmOTA6IGNvbW1hbmQgbm90IGZvdW5kCg== +compile_options=\ +@eNq9kEtPhDAUhff8iqZ7yJioCWSYhEcZ0Q5teCS6apQpSX3QhjJG/fUWBhmcuLab3vae2/OdZrK1\ +3x5feCNeOZCqF7LVnqX7TtQ96w7tXnTsnXei+fThBbRMqY3EhyvHXV1By0oo9QDUitdKATsuKIrM\ +lsUorLbTmQVVSVhRUZqjomCEomxHf3qYXl+CtZaHruYbYMu5dhqlxBffO437AS1jEtEqwcG28OGZ\ +zdgNURbdsF+CP31HMbov84BRkpdBmOK0fJhHBhxoRWQ3pGrcFbDrAWr6GEeCmc+oPJBE/qA61iS8\ +JbQ0Ty1H/hsdp9ndhH621vLpmde93iwvT6AAjClwfEqEY1INeRZhvgFuXpvb +exehash=0 + +557.xz_r=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=34d1fd17d5aa193e0a6a2c6e3f3472c24b4e41ed9de1aafdefcd23008f8b6564 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNrtk1tPwyAUx9/7KQjvXTcvUxdr0gtu1a6QXsz0hXQMHVrK0nZG/fSy6Uw7L59AAhz+nMNJzvmF\ +SJWmzJ/4vSg4UKtGqLIeGXVTCdbQal0uREWfeSXuX204gIY+1jrEhv3eWX8IDcPDUzIC0Foqya16\ +XVpzUVoyXxWcAVNPtUvaU8D0E4I8bSIfudn4U1MnSzF1b1OEYx/Fdv9lcHB4dDw8OdUBE+cGUQ9H\ +l8GYTuzB7skUTWmAd2p210mVZITEKEkoJiiaEmAGPb3qFWdUckmF2qhlbh5oy5SUqtSHQsyLN5lb\ ++Uq01GZryW/RbMnZU0vXQurKWxcLXjR5J2FLVHn5wJla8Arsj896QjI8AuC8VuuK8QtoeCPgefaP\ +3f5wYvcKk9SGndZDQyPySHYZOuNE+7oYtl4XRd6EdgL+ufBq2xs0S2OHEhynjhuEQXr71aENHmiE\ +QXT92xfYG+dq/shZU190WH+BAmBLMfT/QBz6ONsAbtF9B8AAJ6o= +exehash=0 + +999.specrand_ir=base=maplec-m64: +# Last updated 2021-05-12 17:24:36 +opthash=2b6f45155529ef0ee94c19b9445375b5551207252ee5fb82fdcb9fe4f6f19a4c +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNp9kFFLwzAUhd/zK0Leu04UwbIO2rTOamzC1oI+lS7LMLomJWkF/72xo2KLermQwDm5+c7NtfKa\ ++k0c5UlA3XZSKxsA2xnJu8r06iBN9S6MPH6E6AIBd7XOEqLl4mZ5iQDA9JEFEPkvuhG+7ZW/l8pv\ +6vYkOPRc63HoQkMv2bEUuyNP0rjcQC+zreCmVgeP66bRCs7r/KIi7PoKwpXVveFijQAOIMbhr5+e\ +RRrfU1aEaEKAgCPFrLwl0WbntCnNoMZpju+q0TDHGyzpU7GNKka3RRRnJCuex0kDJQIkyx/+Wsis\ +Vnr/Knhn15PI37wQDmFI8k9SktDyK+ePkJ/hnoeM +exehash=0 + +519.lbm_r=base=maplec-m64: +# Last updated 2021-05-12 17:29:14 +opthash=55e637b326098960c2f25abcffd8e22854b4464b6ae2619ebf92ce74d672f662 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNp9kF9PgzAUxd/7KZq+M2aiJpKxBApuaKENlESfmg27WAW68MfEb2/ZcMoyvWnSNufc9nduomur\ +2rzLnSol1PtO6bp1QNs1quhE09cvqhEfslG7TxddIWCOrbG4aD67m98gADCNmQOR/aorabd9bW9V\ +bVebfSkLaJmlvx+daWgFGQux2ZIg9PPVeBdezqnIcsbSMMsEZWESM3heo5ew22sIF63um0IuEcAO\ +xNi9+P1RpP4DZdxFExYEDDNm+T3xVpnRplwH1Q8TvBYTw0XQgzl84qknGE2550ck4s+nloEXARIl\ +j38N6awWevsmi65dDpnL6if/CR7CQzIS/BM79vhakMgf2Mtq9NN8mMOvIXwB6zCRCQ== +exehash=95e543602be6b0de89f9afd90aacb45d06bb7b32f0f2295d9571e3c9a893f901 + +511.povray_r=base=maplec-m64: +# Last updated 2021-05-19 14:10:44 +opthash=6681316d90fcef5a8ec9d57d1ec3590b7d32c00621a8f461b30ed5b709bb4dc3 +baggage= +compiler_version=\ +@eNq9VUtv2zAMvvtX6NYNqaKmj7QJ4MNgBNuAYCnabOstkGXGViNLmiQ3bg/77ZPtuPaaDANWrJc4\ +FB8f+YmkUHR3F62+zW5uPy++rBbXS/+ZBijaP/tquUxRXHDhMJfIamB2GESL+XwWLVcfoygkmcqB\ +PGY5yakWsFIapFWFYUB6f51SwpKUMSy4pEbhy+HF8ITEXBJKDcvG55WiKHEqC5wOBs8Q8+Vi9f3m\ +w/X17Ob1UMMhETyGElil30cmjalwCm8N1RpMsKQmBTdFe7ZBpOSap4WBBG25y6boqMnPsW2KK8YS\ +K+gDkK0yG6sp22lyugFsQAC1sBoRK6m2mXJ1xsOUu59d1vj0ZDQZjk4Ja6GO0O2n2Xwe1tXE1GYI\ +4woc55qF/wK/qi1JY08SsC7hhvDx1Rhr1hXbwazNW+CkuX4TGN9s1PYlkXgp4ZbGArx9nBfJWlDt\ +D0E2Z051gs1odf2NvyqqEWGiSCDBvmcclK4zleIZxz5aBzl+8uF7YPZe3GMoGWjHlbSdZ5VWIfmP\ +ArCK74H1gvqCNmAaejB/kbqvnZWlrzvrHNhk0hOEYlRA2BDyHLJ1TCAu0p5CybT+acvw7ioNpWpl\ +rUVP4nYntRnlhXC8KXkXcc1LzJTxPGF6cYavzi4ux5M/q8/PzkeTNnw1jSE1+cMVpp2LywzQxIZa\ +WV52xzV05XGoTMdzCB/hBeFc+sbxXON1IVl1IS1ww7W/QqOUe02P7kLY/S3U65PXgvxtEA6sQM8M\ +6/VIBmzjn4BwF7p3oXGVvTO/DQeVaUFTsCE7ZoPB8dpfn6HyuBmaOpnw0DBmyrqDCldv3/AQRdqA\ +75D/SU6wrNsJ5SoBMUV1UwV+S6MHMLZqifq1QO/m9cJG/jFEvaX9HgW/AHQUm+k= +compile_options=\ +@eNrtlFFPwjAQx9/3KZq+Lt1mRI2EkcA2ER1bw7YEn5pRCkyhxXYY+fZuAxTUxAcToskuWXrJXde7\ +37X/QHC0TJ/YNFswIFZ5JrhqaiqXGc2JXPNJJskLk9l0Y8MzqBWuKlJsaBnXVgNqmhMOcBNAcy6W\ +zNzMl+YyXS0YESvGlVhLyswDNxdiocwZpWiR8VQKdGVcGJY5zriZppLOLxtlYP2KZnyNZroOSkMq\ +n9hU161zgChAYl+lIQByI+w5xRK4XjfpAdSfSsFzxieFO04VKxaj+NSKUfKshMx3W0gniUMSJRgP\ +vSgiIfaCAQYftsvy8WUDgNa2+jbUnCZwRiP7NN3ujwu7dyGObXjUPNQK6g5ObvxOLypixyCqaNcL\ +nFuyT/gVmep/3igedggOh3Gn2/f78cP+2AoT/HoTykYrPvR0g/txfI79bYXb4H9B7feD+5M9uk/W\ +EuNHRnPVPgL+TguACqXvnvKV+G6YlGM7mFktTLUw1cJUC9OfE6Y3nDbadw== +exehash=0f4659ece5065638b9268e65a56d231636b83a05ae00d17df9bf1a2ae7112f8b + +538.imagick_r=base=maplec-m64: +# Last updated 2021-05-31 19:30:05 +opthash=54a10f343892c95817762d047800af2eccb783c0e3ff864fcef7d0ae46bd6135 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNrtkdFqgzAUhu/zFCH3agdlMKkFja51iyZohO0qtC5lbmqK0cHeftbqtpatDzAWAgk5fw7f/59Y\ +1Ua1eZW7opRQ7dtC1doGum2KvBVNVz8VjXiTTbF7d9AVAv1V9xIHzcyb2RwBgGnEbIisZ1VJS3e1\ +tS1qq9rsS5lDo99qamoqaPgpC3B/xH7gZStohOb4JtyMU5FmjCVBmgrKgjhi8HyNWsKu5xAutOqa\ +XC4RwDbE2PkR4Vik3h1l3EEnPAj03Jhlt8RdpX3tlG2oekGM12ISXIYdPgQPPHEFowl3vZCE/HHq\ +OzAjQML4/rewztZCbV9k3urlwXdZfWXwaQDCwR3xL1iPXL4WJPQO/GU16ml2yOJbEP9D/AND/ABB\ +Sw9g +exehash=facef3555a82b36cc7e8d92e422f6bffa9ea772e21800b4dd646cd8aa6e6eb36 + +500.perlbench_r=base=maplec-m64: +# Last updated 2021-06-02 10:59:30 +opthash=907b382deeffec61ac5b9a27df38c7435aa5d83bcabdd7e546b4199881462251 +baggage= +compiler_version=\ +*IENDX1ZFUlNJT05fT1BUSU9OOgo= +compile_options=\ +@eNrVUtFqgzAUffcrgu/WDkZhZQ40TatbaoKJ0D0Fa1OWrWpJ7Nj+ftG1doWOPU+U3HvO8YZ77k2b\ +2quKN7lVOwmafaua2kwd02pVtkIf6o3S4l1qtf0M3BvXsaGxksAdj+7GE9dxIFnSKXD9l6aSvjnU\ +/lrVflXsd7IEnn2bU9FRA7wZowjaI52hKF/YgKIMC0gyBLxkZL+NMq2fEBuV+6L2uaqkF6tMmhMS\ +8yX2aKGN1BaSH62vpQ3MXpa6qDe25IzkEUaC4ZDFiInuxiTEwfh4uwhzTgTLKc0QY4JQlC6p5QQO\ +swUS8wQjNqRdJhjJM4g6rE/JfM4QF1HCWTC5BcNzLI+TNF+J1cCcYNoh96Y56FI+uA6cAgiDq7Z9\ +kyR6JJQH7oWHrmO9hjSf43DBLHfpZ89GKIWxGAT/3uC+KUoyHkYJTvjzqeuz0b0CrXgWiqs62kms\ ++um3Nf1jhvfN+lWWrXnoBLvqLB7GAkA/Mzz7baB/t2B/X4Y8tlDUzW1XHSuSvNuBHwvwBanrEMs= +exehash=51357adb393d1e80ce358878f264dc9f58399d0c7c71acd7c4834ae0d4c6d3e4 + diff --git a/build/tools/spec/replace_func.py b/build/tools/spec/replace_func.py new file mode 120000 index 0000000000000000000000000000000000000000..8da5f589b021dd54b47a6da164e7197c75f79024 --- /dev/null +++ b/build/tools/spec/replace_func.py @@ -0,0 +1 @@ +../common/replace_func.py \ No newline at end of file diff --git a/doc/cn/CPPCodingTalkAboutPointer.md b/doc/cn/CPPCodingTalkAboutPointer.md new file mode 100644 index 0000000000000000000000000000000000000000..d8be304b8ec099fbd7f614cb0a300b5028f16dd1 --- /dev/null +++ b/doc/cn/CPPCodingTalkAboutPointer.md @@ -0,0 +1,266 @@ +# C++编程探讨之指针 + +# 背景 + +`C/C++`中指针的使用具有极大的灵活性,伴随着的是更多的安全风险,同时这也对程序员提出了更高的要求。本文将讨论裸指针在`C/C++`中当如何被使用,乃至最终确立一种编码范式。 + +# 裸指针vs引用 + +## 成员访问 + +当访问对象成员时,裸指针存在为空的场景(指针的有效性由闭合对象或函数从逻辑上自保证),所以必须检查非法指针。而引用必定非空。 + +## 做容器成员 + +引用从`C++`语义中,表达的是别名关系,理论上不占内存(实际中规中矩的编译器对于引用的内部实现是指针)。引用本身不是对象,这点与指针不同,指针可以作为各容器成员,而引用不行。 + +# 裸指针vs智能指针 + +## 堆对象销毁 + +```c++ +class Int { + ... + private: + int data; +} + +void test(int* in) { + Int* tmp = new Int(); + ... + goto LABEL; + ... + + delete tmp; +LABEL: +} +``` + +对于资源(堆对象、栈对象、文件资源等)的使用,遵循**“谁申请,谁释放”**的原则(RAII),这样可以最大限度的降低资源泄露的可能。 + +裸指针的`new`与`delete`之间往往会包含一段处理逻辑以及子函数调用,中间的处理逻辑可能发生异常、跳转等动作(中间的处理逻辑的行为不会由当前对象越权限制,超出`new`行为的管辖范围),而跳过资源的释放,从而造成资源泄露(如示例中`test`函数中`tmp`对象)。 + +智能指针改造为`auto tmp = std::make_unique();`,构造对象`tmp`时,即绑定其`delete`行为,退出当前作用域销毁,而避免了资源泄露的可能。 + +## 管理权vs使用权 + +```c++ +int* delete(int* in); +``` + +管理权:拥有销毁、重建对象的权利 + +使用权:拥有访问、修改对象的权利 + +如上示例所示,当使用裸指针传递参数时,由于其隐含了转移所有权的属性(可能转移所有权,亦可能没有),入参`in`以及出参均无法确定行使了**管理权**还是**使用权**。调用此函数将需要额外补充信息:`in`是否会被`delete`函数销毁?返回值是否需要调用者销毁? + +```c++ +std::unique_ptr delete(std::unique_ptr& in); +``` + +使用智能指针将在接口中明确表达参数的角色,如`std::unique_ptr& in`代表`delete`函数享有其**使用权**,函数返回值代表`delete`函数转移所有权。 + +# 指针使用范式 + +## `new`创建的对象,必须立即绑定其销毁方式 + +错误示例: + +```c++ +Object* obj = new Object(); +... +delete obj; +``` + +正确示例: + +```c++ +std::unique_ptr obj = std::make_unique(new Object()); +``` + +## 申请的资源,必须立即绑定其释放方式 + +错误示例: + +```c++ +FILE* file = open("xxx.txt"); +... +file->close(); +``` + +正确示例(本例比较通用,最佳方式应用类封装`open`): + +```c++ +template +class ResourceGuard { + public: + ResourceGuard(T* _obj, Func _func) : obj(_obj), func(_func) {} + + ~ResourceGuard() { obj.func(); } + private: + T* obj; + Func func; +} + +FILE* file = open("xxx.txt"); +auto fileGuard = ResourceGuard>(file, FILE::close); +... +``` + +## 确定不为空的场景,使用引用而非指针 + +错误示例: + +```c++ +void func1(int* in) { + if (in == nullptr) return; + ... +} + +void func2() { + int* p = nullptr; + ... + if (p != nullptr) { + func1(p); + } +} +``` + +正确示例: + +```c++ +void func1(int& in) { + ... +} + +void func2() { + int* p = nullptr; + ... + if (p != nullptr) { + func1(*p); + } +} +``` + +## 作为容器成员(不具管理权),确定不为空时,使用封装的引用容器,而非指针 + +错误示例: + +```c++ +void func(std::vector& in) { + for (auto *p : in) { + if (p == nullptr) { + continue; + } + ... + } +} +``` + +正确示例: + +```c++ +template +class Ref { + public: + Ref() = delete; + Ref(T& ref) : data(&ref) {} + + ... + + operator T() const noexcept { + return *data; + } + + private: + T* data; +} + +template +using ref_vector = std::vector>; +void func(ref_vector& in) { + for (auto p : in) { + int& data = p; + ... + } +} +``` + +## 作为容器成员(具备管理权),使用具有管理生命周期的容器,而非指针容器 + +错误示例: + +```c++ +std::vector data; +... +for (auto *p : data) { + delete p; +} +``` + +正确示例: + +```c++ +template +class ptr_vector { + public: + ~ptr_vector() { + for (auto *p : data) { + delete p; + } + } + + private: + std::vector data; +} + +ptr_vector data; +... +``` + +## 显示转移对象管理权,明确对象使用权 + +`C++11`新增了`move`语义,并废弃`auto_ptr`而使用需显示转移所有权的`unique_ptr`,使得栈对象和堆对象的生命周期管理方式可以进行统一。 + +栈对象转移示例: + +```c++ +std::vector func() { + std::vector data; + data.push_back(0); + return std::move(data); +} +``` + +模糊的堆对象转移示例: + +```c++ +Object* func() { + std::unique_ptr data = std::make_unique(new Object); + Object& rData = ToRef(data); + rData.push_back(0); + return data.release(); +} +``` + +明晰的的堆对象转移示例: + +```c++ +std::unique_ptr func() { + std::unique_ptr data = std::make_unique(new Object); + Object& rData = ToRef(data); + rData.push_back(0); + return std::move(data); +} +``` + +## 应当使用指针场景 + +1. 第三方库函数传入或传出指针,但必须在调用前一刻使用`unique_ptr.get()`或`unique_ptr.release()`构建入参,出参也必须在拿到后立即使用`unique_ptr`接住或判空并转引用。 +2. 作为容器成员(不具管理权),使用场景中有空指针设计,但必须在使用前立即判空并转引用,不支持指针扩散。 + +# 备注 + +上述的`Ref`、`ref_vector`已开发完成,`Ref`由于`operator.`无法被重载,所以定义为`SafePtr`。 + +上述的`ResourceGuard`、`ptr_vector`正在开发中,文中主要为示意。 diff --git a/doc/cn/CompilerPhaseDescription.md b/doc/cn/CompilerPhaseDescription.md new file mode 100644 index 0000000000000000000000000000000000000000..3bd1244dac0613fb660ec67930f0caa46e0bf328 --- /dev/null +++ b/doc/cn/CompilerPhaseDescription.md @@ -0,0 +1,155 @@ +### 方舟编译器phase层次结构 + +目前phase主要有两类:module phase和function phase。在其他层次的IR上的phase可以通过继承自MaplePhase完成。MaplePhase在特定的IR层次上完成优化或者进行程序分析。 + +##### MapleModulePhase + +如果一个phase继承自MapleModulePhase,说明这个phase需要在整个module上进行转换;module phase也可以调用更低层次的MaplePhase。 + +##### MapleFunctionPhase + +```c++ + template + class MapleFunctionPhase : public MaplePhase +``` + +不同于MapleModulePhase,MapleFunctionPhase是一个模板类,主要是因为Maple中有不同层次的函数级IR。中端的优化phase和后端的优化phase都是该类的派生类。 + +### phase的内存管理 + +方舟编译器的phasemanager可以对内存进行有效的管理,以便每个phase可以保留可能被其他phase依赖的分析结果;以及丢弃失效的结果。每个phasemanager中提供一个AnalysisDataManager类(多线程时,每个线程对应一个AnalysisDataManager)用来存储分析结果。为了实现这个功能,每个phase需要实现GetAnalysisDependence函数。如下: + +```c++ + void ::GetAnalysisDependence(maple::AnalysisDep &aDep) const { + aDep.AddRequired(); // 配置当前phase需要依赖的phase。 + aDep.AddPreserved(); // 配置当前phase执行完成后,需要保留的分析结果。 + aDep.SetPreservedAll(); // 保留所有的分析结果。 +} +``` + +#### 分析phase + +分析phase中的GetPhasesMempool函数返回的mempool来自于AnalysisDataManager。分析phase的内存池中分配的对象,只有在被其他phase设置为需要丢弃;或者当前phasemanager结束时,才会被释放。否则会一直存在于当前phasemanager中。如果有些信息仅仅是在分析phase内部局部使用,那么可以将其分配在临时内存池中,通过ApplyTempMemPool函数获取一个临时的内存池。 + +#### 转化phase + +对于转化phase,GetPhasesMempool和ApplyTempMemPool获取的内存池类似,都会在该phase结束后进行释放。**如果一个转化phase不实现GetAnalysisDependence,则意味着phase结束后会把当前phase所在的phasemanager中的所有现存分析phase的结果删掉**。 + + + +**If a transform phase does not implement the GetAnalysisDependence method, it defaults to not having any prerequisite phases, and invalidating all phases information in analysisDataManager.** Transfrom phase default to be assumed to invalid all ananlysis results. + +### 快速开始 + +假设我们要在中端实现一个叫做“MEHello”的`转化`phase。 + +- 1 新增两个文件 + +me_hello_opt.h: + +```c++ +#ifndef MAPLE_ME_INCLUDE_ME_HELLO_OPT_H +#define MAPLE_ME_INCLUDE_ME_HELLO_OPT_H +#include "me_function.h" // 使用MeFunction +#include "maple_phase.h" // 使用MAPLE_FUNC_PHASE_DECLARE宏 +namespace maple { + +// 对于转化phase,尽量使用这个宏。 +MAPLE_FUNC_PHASE_DECLARE(MEHello, MeFunction) +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_HELLO_OPT_H + +``` + +me_hello_opt.cpp: + +```c++ +#include "me_hello_opt.h" +// 将该phase对应的phasemanager头文件引入进来,可以方便地使用其他phase的分析结果。 +#include "me_phase_manager.h" + +namespace maple { + +// 您需要清楚地知道,当前的phase依赖什么分析结果,以及会破坏什么分析结果。 +void MEHello::GetAnalysisDependence(maple::AnalysisDep &aDep) const { + aDep.AddRequired(); // phasemanager会保证MEDominace这个phase的分析结果在当前phase中是可用的。 + aDep.SetPreservedAll(); // 表明了当前phase不会破坏任何分析结果。 +} + +// 这个函数的返回值表明了当前phase是否修改了IR,目前该返回值并未使用。 +bool MEHello::PhaseRun(maple::MeFunction &f) { + // 您可以通过这个宏来获取想要的分析结果,前提是在GetAnalysisDependence配置过,否则会报错。 + auto *dom = GET_ANALYSIS(MEDominance); + // 使用dom信息,做一些事情。。。 + LogInfo::MapleLogger() << "hello opt on function: " << f.GetName() << '\n'; + return false; +} + +} // namespace maple + +``` + +- 2 告知phasemanager,有新的phase加入了。 + - 2.1 将新phase的头文件(me_hello_opt.h) 添加至me_phase_manager.h + - 2.2 在me_phase_manager.cpp注册新的phase,如下: + +```c++ +MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEHdse, hdse) +// 后缀CANSKIP的宏表明了这个phase可以跳过。第一个参数是phase的实现类,第二个参数是phase的名字。 +// phase的名字可以用在多个选项中,如skip-phases,dump-phase(s),skip-after等等;同时配置哪些phase需要运行,也是用这个名字。 ++MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEHello, hello) +MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MELfoIVCanon, ivcanon) +``` + +- 3 配置需要运行的phase列表。 + x修改phase.def文件,如下: + +```c++ +... +ADDMAPLEMEPHASE("dse", MeOption::optLevel >= 2) +ADDMAPLEMEPHASE("hello", MeOption::optLevel >= 2) +ADDMAPLEMEPHASE("analyzector", JAVALANG) +... +``` + +- 4 把cpp文件加入到对应的build.gn中。 +- 5 编译工具链测试 + maple --run=me:mpl2mpl:mplcg --option="--O2 :--O2 --quiet:--O2 --quiet" test.mpl + 可以看到,我们新增的phase在dse之后正确地输出了预期的内容! + +``` +>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Optimizing Function < VEC_invariant_p_base_space id=5471 >--- +---Preparing Function < VEC_invariant_p_base_space > [1] --- +---Run Phase [ mecfgbuild ]--- +---Run Phase [ cfgOpt ]--- +---Run Phase [ loopcanon ]--- + ++ trigger phase [ dominance ] + ++ trigger phase [ identloops ] +---Run Phase [ splitcriticaledge ]--- +---Run Phase [ ssatab ]--- +---Run Phase [ aliasclass ]--- +---Run Phase [ ssa ]--- + ++ trigger phase [ dominance ] +---Run Phase [ dse ]--- + ++ trigger phase [ fsaa ] +---Run Phase [ hello ]--- +hello opt on function: VEC_invariant_p_base_space +---Run Phase [ hprop ]--- + ++ trigger phase [ irmapbuild ] +---Run Phase [ valueRangePropagation ]--- + ++ trigger phase [ identloops ] +---Run Phase [ hdse ]--- +---Run Phase [ epre ]--- + ++ trigger phase [ dominance ] + ++ trigger phase [ identloops ] + == epre invokes [ hdse ] == +---Run Phase [ rename2preg ]--- +---Run Phase [ lpre ]--- +---Run Phase [ storepre ]--- +---Run Phase [ copyprop ]--- +---Run Phase [ hdse ]--- +---Run Phase [ pregrename ]--- +---Run Phase [ bblayout ]--- +---Run Phase [ meemit ]--- + +``` diff --git a/doc/cn/DeveloperGuide.md b/doc/cn/DeveloperGuide.md new file mode 100644 index 0000000000000000000000000000000000000000..969f52b08816f29a9a796d8852ce78f9b60395ee --- /dev/null +++ b/doc/cn/DeveloperGuide.md @@ -0,0 +1,103 @@ +# 开发者指南 + +通过参考本文档,您可以下载编译器源码编译出OpenArkCompiler。同时,本文档也为开发者提供了源码静态检查指南。 + +## 源码下载 + +下载地址:,可以通过`Clone` or `Download`的方式下载openarkcompiler源码。 + + > 注:默认源码下载目录为openarkcompiler。 + +之后请按照《环境配置》文档完成您的开发环境准备。 + + +## 源码编译 + +在openarkcompiler目录下执行以下命令,编译出OpenArkCompiler,默认输出路径 openarkcompiler/output/TYPE/bin, TYPE: aarch64-clang-release。 + +``` +source build/envsetup.sh arm release +make setup +make +``` + +命令说明: + +- `source build/envsetup.sh arm release` 初始化环境,将OpenArkCompiler工具链路径openarkcompiler/output/TYPE/bin设置到环境变量中; +- `make` 编译OpenArkCompiler的Release版本; +- `make BUILD_TYPE=DEBUG` 编译OpenArkCompiler的Debug版本。 + +在openarkcompiler目录下执行以下命令,编译出OpenArkCompiler及maple runtime部分,默认输出路径 openarkcompiler/output/TYPE, TYPE: aarch64-clang-release。 + +``` +source build/envsetup.sh arm release +make setup +make libcore +``` + +命令说明: + +- `make libcore` 编译OpenArkCompiler及maple runtime部分的Release版本; +- `make libcore BUILD_TYPE=DEBUG` 编译OpenArkCompiler及maple runtime部分的Debug版本; + +此外,方舟编译器还提供了源码编译脚本,开发者也可以通过在openarkcompiler目录下执行该脚本,默认编译出OpenArkCompiler及maple runtime部分的Release版本。执行命令如下: + +``` +source build/build.sh +``` + +## Sample示例编译 + +当前编译方舟编译器Sample应用需要使用到Java基础库,我们以Android系统提供的Java基础库为例,展示Sample样例的编译过程。 + +**基础库准备** + +环境准备阶段已经通过AOSP获取到需要的libcore的jar文件。 + +**生成libjava-core.mplt文件** + +编译前,请先在openarkcompiler目录下创建libjava-core目录,拷贝java-core.jar到此目录下,在openarkcompiler目录执行以下命令: + +``` +source build/envsetup.sh arm release +make +cd libjava-core +jbc2mpl -injar java-core.jar -out libjava-core +``` + +执行完成后会在此目录下生成libjava-core.mplt文件。 + +**示例代码快速编译** + +示例代码位于openarkcompiler/samples目录。 + +以samples/helloworld/代码为例,在openarkcompiler/目录下执行以下命令: + +``` +source build/envsetup.sh arm release +make +cd samples/helloworld/ +make +``` + +## 源码静态检查 + +本部分内容将指导您使用clang-tidy进行源码静态检查。在对源码进行修改之后,对源码进行静态检查,可以检查源码是否符合编程规范,有效的提高代码质量。 + +静态源码检查之前,需要先编译出OpenArkCompiler。此后,以检查src/maple_driver源码为例,在openarkcompiler目录下执行以下命令: + +``` +cp output/TYPE/compile_commands.json ./ +./tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/share/clang/run-clang-tidy.py -clang-tidy-binary='./tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/bin/clang-tidy' -clang-apply-replacements-binary='./tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/bin/clang-apply-replacements' src/maple_driver/ +``` + +命令说明: + +- `cp output/TYPE/compile_commands.json ./` 将output/TYPE目录之下的compile_commands.json复制到当前目录之下,它是clang-tidy运行所需要的编译命令; + +- `./tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/share/clang/run-clang-tidy.py` 调用clang-tidy进行批量检查的脚本run-clang-tidy.py,其中 `./tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/`目录是之前配置的clang编译器的发行包主目录; `-clang-tidy-binary` 是指明clang-tidy的具体位置; `-clang-apply-replacements-binary` 是指明run-clang-tidy.py所依赖的clang-apply-replacements的位置; `src/maple_driver/` 是要进行源码检查的目录。 + +## 编译器注意事项 + +- 方舟编译器前端暂时不支持字节码校验,未符合dex、jbc语义的字节码输入可能造成编译器Crash。 +- 方舟编译器中后端暂时不支持IR中间件语法校验,未符合MapleIR语义的中间件输入可能造成编译器Crash。 diff --git a/doc/cn/DeveloperGuide4Utility.md b/doc/cn/DeveloperGuide4Utility.md new file mode 100644 index 0000000000000000000000000000000000000000..08045fc06352bcdc7acac72aac6e0796a4d9368d --- /dev/null +++ b/doc/cn/DeveloperGuide4Utility.md @@ -0,0 +1,431 @@ +# Maple通用模块应用手册 + +# Cast + +## `instance_of`与`safe_cast` + +`maple`对于`C++`的使用,原则上需要禁用`RTTI`,即禁用`dynamic_cast`。而由于编译器系统的复杂性,完全通过类设计来破除父类向子类转换的情况,反而会使得对象关系变得更加复杂,得不偿失。所以`maple`代码实现中便有了众多如下设计: + +```c++ +SubClass *sub = nullptr; +if (base.Type() == SubType) { + sub = static_cast(base); +} +``` + +通过设计某属性字段来实现父类与子类之间的关系绑定,从而达到与`dynamic_cast`相同的效果。 + +但此种写法仍有一些不足,首先`SubType`与`SubClass`之间隐藏有静态绑定关系,这由设计者决定,却需要调用者将两者关系显化,这会产生强依赖;其次,并不是所有场景都如类型比较这样直观,复杂的场景对于调用者来说更容易出错;最后,散落在各地的转换,将会埋下散弹式修改的问题。所以我们设计出了`safe_cast`,由设计者注册转换关系,调用者只需以`dynamic_cast`的方式调用即可 + +### 注册方式 + +通过`REGISTER_SAFE_CAST`宏来达成注册,声明如下: + +```c++ +#define REGISTER_SAFE_CAST(type, condition) +``` + +其中`type`为子类类型(假设为`B`),`condition`为匹配到`B`以及其子类所有场景的布尔表达式。示例如下: + +```c++ +class A; +class B : A; +class C : B; +REGISTER_SAFE_CAST(B, from.Kind() == B || from.Kind() == C); +REGISTER_SAFE_CAST(C, from.Kind() == C); +``` + +`from`为表达式传入的类型的形参名。 + +*注意:* + +*- 注册同时持了子类向父类转换以及父类向子类转换。* + +*- `condition`可以是任意的布尔表达式,但设计者应尽量使其符合继承关系,避免非继承关系的转换。* + +*- 对于复杂的`condition`使用`kind ==`表示一棵继承关系树是不明智的,需考虑优化,如:组织`kind`的范围、使用特定位标记等方式来达成快速匹配。* + +### 使用场景 + +1. 针对只做单个类型匹配的场景 + +```c++ +SubClass *sub = safe_cast(base); +if (sub == nullptr) { + // TODO +} +``` + +2. 针对多个类型匹配的场景 + +```c++ +if (instanceof(base)) { + auto *sub = static_cast(base); + // TODO +} else if (instanceof(base)) { + auto *sub = static_cast(base); + // TODO +} +... +``` + +*注意:* + +*- 对于`switch case`等已经正确识别类型的场景,使用`static_cast`即可。* + +*- `safe_cast`返回值永远是指针,外部识别是否转换成功。* + +*- 输入若为指针,`instance_of`与`safe_cast`都会做判空,所以`base`非空时优先传入引用* + +# Container + +## `Ptr` + +`Ptr`模拟了原生指针的行为,但切除了对数组操作的支持。 + +其通过在构造、赋值的操作中校验数据,使得指针对象仅在构造时需验证满足某特征,而传递和使用时均无需再次验证该特征,降低重复检查的开销。 + +```c++ +template +using PtrCheckerType = void (*)(const T*); + +template +constexpr void CheckNothing(const T*) {} + +template Check = CheckNothing> +class Ptr; +``` + +如上所示,`Ptr`的默认校验行为不做任何检查,通过 + +```c++ +template < typename T> +using XXXPtr = utils::Ptr>; +``` + +即可定义不同场景下的已经校验过的指针对象,统称安全指针。 + +*注:其由`safe_ptr`的诉求而扩展而来,但`safe_ptr`相对通用的`Ptr`场景更为复杂,因为其针对的是指针本身的合法性而非指针对象的特征。* + +## `safe_ptr` + +参见《CPPCodingTalkAboutPointer》中`Ref`的定义。由于`c++`中`operator.`无法进行重载,所以无法构建`Ref`对象,但可以定义与其等效的非空指针对象,即`safe_ptr`。 + +### 场景:数组、字典等容器成员 + +示例可见于《CPPCodingTalkAboutPointer》。 + +为了弥补`operator.`无法重载的问题,后续将扩展`Utility`中`ToRef`小工具的能力,保证指针无开销但安全转换为引用。其可能特化如下: + +```c++ +template +constexpr T &ToRef(safe_ptr ptr) { + return *ptr; +} +``` + +*注:对于使用频繁的容器,后续将封装`ref_xxx`系列的容器以取代`safe_ptr`这类使用场景。* + +### 场景:作为对象成员 + +此为`safe_ptr`开发出来后意外发掘的场景。 + +由于存在引用数据成员的类,编译器无法为其生成默认拷贝和转移,但很多场景下需要支持拷贝和转移能力,此时通常的做法是存储为指针成员。但指针成员将带来两个问题: + +1. 针对指针成员访问时需要去识别指针的合法性。 +2. 重构和演进都有可能从定义成员的角色方来改变其行为可空,而使用成员的角色方不一定会被告知,这可能会导致进一步的隐藏bug。 + +而使用`safe_ptr`代替裸指针,`safe_ptr`解引用处都使用`ToRef`来转引用(裸指针的`ToRef`有额外的开销),将会避免这样的问题。 + +*注意:`safe_ptr`设计为容器或对象成员,而不应用于函数传参,函数传参应使用`&`。* + +## `mpl_iterator` + +`mpl_iterator`原名为`iterator`,但由于和容器中`using iterator`重名,所以添加`mpl`前缀。 + +由于`ref_xxx`容器的设计,以及未来可能扩展small talk系列,重复的迭代器设计是个比较麻烦的问题,所以抽象出持续演进的统一迭代器容器,通过`mpl_iterator_traits`进行少量配置而快速实现新容器的迭代器。 + +当前基于`ref_vector`的迭代器诉求,设计`mpl_iterator_traits`的成员如下: + +```c++ +template +struct mpl_iterator_traits { + using iterator_category = typename std::iterator_traits::iterator_category; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using pointer = typename std::iterator_traits::pointer; + using reference = typename std::iterator_traits::reference; + + static reference operator_dereference(Iterator iter) { + return *iter; + }; + + static Iterator operator_arrow(Iterator iter) { + return iter; + } + + static reference operator_bracket(Iterator iter, difference_type n) { + return iter[n]; + } +}; + +``` + +## `ref_vector` + +参见《CPPCodingTalkAboutPointer》中`ref_vector`的定义。 + +使用指针数组:`std::vector` + +```c++ + int a = 0, b = 1; + + std::vector data; + data.push_back(&a); + data.push_back(&b); + ASSERT_EQ(*data[0], 0); + ASSERT_EQ(*data[1], 1); +``` + +重构为引用数组:`utils::ref_vector` +```c++ + int a = 0, b = 1; + + ref_vector data; + data.push_back(a); + data.push_back(b); + ASSERT_EQ(data[0], 0); + ASSERT_EQ(data[1], 1); +``` + +## `Index` + +`Index`的设计初衷为满足基础类型的静态安全。 + +如`GStrIdx`、`UStrIdx`、`U16StrIdx`三者在业务代码中会共同参与计算,包括其提供的接口也有比较高的相似性。它们底层均为`uint32`,若均定义为`uint32`那将是个灾难,调用者不得不得小心翼翼,但也很难避免传错数据。所以使静态类型互斥,由编译器来检查使用的正确性,将大大降低出错的几率。 + +定义一个静态类型方式非常简单,只要定义不同的Tag即可,如下: + +```c++ +class GStrTag; +using GStrIdx = utils::Index; + +class UStrTag; +using UStrIdx = utils::Index; + +class U16StrTag; +using U16StrIdx = utils::Index; +``` + +# Generalize Pattern + +## `ObjectFactory` + +`ObjectFactory`为针对抽象工厂的封装,用于解决以下问题: + +1. 消除代码中由`switch ... case`、`if ... else if ...`等构成的具有高圈复杂度的大函数,这类函数难以维护和扩展,且灵活度低。*(注意:应避免机械的性解决问题,需分析语义做好设计,如配合模板模式等,实现设计隔离而非仅仅代码隔离。)* + +2. 采用工厂将依赖反转,更容易将调用者和设计者、设计者和设计者之间隔离。 + +其应用方式如下示例: + +```c++ +// 定义Key,用于标记工厂将创建的产品类别 +enum class ObjectType { + kPlus, + kMinus +}; + +// 定义接口,所有产品应实现的接口协议 +class Base { + public: + virtual ~Base() = default; + virtual int32_t DoIt(int32_t lhs, int32_t rhs) const = 0; +}; + +// 定义工厂,使用ObjectType作为查找关键字,Base为接口协议,int32_t为所有产品构造函数的参数类型 +using TestObjectFactory = ObjectFactory; + +// Key,接口,工厂需要对注册者和调用者均可见,所以可能在.h文件中,可能在.cpp文件汇总 +// 产品只要保证能注册入工厂,可以在不同的.cpp文件中 +// 定义产品 +class ObjectPlus : public Base { + public: + // 定义工厂时所约定的构造函数 + explicit ObjectPlus(int32_t base) : base(base) {} + virtual ~ObjectPlus() = default; + + // 定义接口时的约定 + virtual int32_t DoIt(int32_t lhs, int32_t rhs) const override { + return base + lhs + rhs; + } + + private: + int32_t base; +}; + +// 定义产品,可能在另外的.cpp文件中 +class ObjectMinus : public Base { + public: + explicit ObjectMinus(int32_t base) : base(base) {} + virtual ~ObjectMinus() = default; + + virtual int32_t DoIt(int32_t lhs, int32_t rhs) const override { + return base + lhs - rhs; + } + + private: + int32_t base; +}; + +// 注册产品,注册产品的方式随着Key,接口,工厂,产品之间的分布以及加载可灵活处理,保证注册成功即可 +// 此处利用static变量初始化来确保注册 +bool RegisterObject() { + RegisterFactoryObject(); + RegisterFactoryObject(); +} +static auto testObjectFactory = RegisterObject(); + +TEST(TestFactory, ObjectFactory) { + // 获取产品对象,需要判空,本示例略 + auto obj = CreateProductObject(ObjectType::kPlus, 10); + ASSERT_EQ(obj->DoIt(1, 2), 13); + obj = CreateProductObject(ObjectType::kMinus, 10); + ASSERT_EQ(obj->DoIt(1, 2), 9); +} +``` + +## `FunctionFactory` + +`FunctionFactory`解决的问题与`ObjectFactory`类似,其主要为了简化抽象工厂的复杂性,对于大多数场景,`FunctionFactory`更容易编写和上手。 + +其应用方式如下示例: + +```c++ +// 定义Key,用于标记工厂将创建的产品类别 +enum class FunctionType { + kPlus, + kMinus +}; + +// 定义接口和工厂,使用FunctionType作为查找关键字,int32_t(int32_t, int32_t)为函数协议 +using TestFunctionFactory = FunctionFactory; + +// 定义产品 +int32_t Plus(int32_t lhs, int32_t rhs) { + return lhs + rhs; +} + +// 定义产品,可能在另外的.cpp文件中 +int32_t Minus(int32_t lhs, int32_t rhs) { + return lhs - rhs; +} + +// 注册产品,注册产品的方式随着Key,接口,工厂,产品之间的分布以及加载可灵活处理,保证注册成功即可 +// 此处利用单件模式来确保注册 +bool RegisterFunction() { + RegisterFactoryFunction(FunctionType::kPlus, Plus); + RegisterFactoryFunction(FunctionType::kMinus, Minus); +} +void AutoFunctionLoader() { + static auto testObjectFactor = RegisterFunction(); +} + +TEST(TestFactory, TestAll) { + // 加载产品 + AutoFunctionLoader(); + + // 获取产品对象,需要判空,本示例略 + auto func = CreateProductFunction(FunctionType::kPlus); + ASSERT_EQ(func(1, 2), 3); + func = CreateProductFunction(FunctionType::kMinus); + ASSERT_EQ(func(1, 2), -1); +} +``` + + +# Utility + +## `ToRef` + +针对方舟新增代码和重构代码中指针传参的场景,期望以引用的方式来替代,即确保所有指针均已经过校验,再以引用的方式传递给被调用的函数,被调用函数多数情况下不应承担函数参数中指针为空的风险以及判断的开销。 + +通常的写法为(示例中`DoIt`和`Run`可当做第三方接口,无法更改): + +```c++ +A *DoIt(B &b); +void Run(B *b) { + CHECK_NULL_FATAL(b); + // ... + A *a = DoIt(*b); + CHECK_NULL_FATAL(a); + a->Do; +} +``` + +期望多数指针获取即引用: + +```c++ +A *DoIt(B &b); +void Run(B *b) { + B &bRef = utils::ToRef(b); + // ... + A &a = utils::ToRef(DoIt(bRef)); + a.Do; +} +``` + +对于`b`仅单次使用,亦可以调整为: + +```c++ +A *DoIt(B &b); +void Run(B *b) { + // ... + A &a = utils::ToRef(DoIt(utils::ToRef(b))); + a.Do; +} +``` + +## `bit_field_v`&`lbit_field_v` + +使用bit位来标记状态开关组合,是一种既节约内存又能高效编码的设计方法。通常,在枚举定义或常量定义时,会有如下写法: + +```c++ +enum BBAttr : uint32 { + kBBAttrIsEntry = 0x02, + kBBAttrIsExit = 0x04, + kBBAttrWontExit = 0x08, + kBBAttrIsTry = 0x10, + kBBAttrIsTryEnd = 0x20, + kBBAttrIsJSCatch = 0x40, + kBBAttrIsJSFinally = 0x80, + kBBAttrIsCatch = 0x0100, + kBBAttrIsJavaFinally = 0x0200, + kBBAttrArtificial = 0x0400, + kBBAttrIsInLoop = 0x0800, + kBBAttrIsInLoopForEA = 0x1000 +}; +``` + +此设计很明显的欲用位来记录某些属性信息,但位信息比较隐晦,难以维护与阅读。 + +所以需要更加清晰的设计: + +```c++ +enum BBAttr : uint32 { + kBBAttrIsEntry = utils::bit_field_v<1>, + kBBAttrIsExit = utils::bit_field_v<2>, + kBBAttrWontExit = utils::bit_field_v<3>, + kBBAttrIsTry = utils::bit_field_v<4>, + kBBAttrIsTryEnd = utils::bit_field_v<5>, + kBBAttrIsJSCatch = utils::bit_field_v<6>, + kBBAttrIsJSFinally = utils::bit_field_v<7>, + kBBAttrIsCatch = utils::bit_field_v<8>, + kBBAttrIsJavaFinally = utils::bit_field_v<9>, + kBBAttrArtificial = utils::bit_field_v<10>, + kBBAttrIsInLoop = utils::bit_field_v<11>, + kBBAttrIsInLoopForEA = utils::bit_field_v<12> +}; +``` + +其中`bit_field_v`:`uint32`,`lbit_field_v`:`uint64`,未来将按需添加`sbit_field_v`:`uint16`以及`bbit_field_v`:`uint8`。 diff --git a/doc/cn/DevelopmentPreparation.md b/doc/cn/DevelopmentPreparation.md new file mode 100644 index 0000000000000000000000000000000000000000..8420fc48fdb4cef88e31c202e272cfb393c8449a --- /dev/null +++ b/doc/cn/DevelopmentPreparation.md @@ -0,0 +1,171 @@ +# 环境配置 + +## 硬件推荐配置 + +- 2 GHz 双核处理器或者更高等级 CPU + +- 2 GB 系统内存及以上 + +- 200GB 可用磁盘空间 + +## 开发环境推荐 + +您需要安装一个 64 位版本的 Ubuntu(Ubuntu 16.04,18.04,20.04 皆可) + +``` +sudo apt-get -y install clang llvm lld libelf-dev libssl-dev python qemu openjdk-8-jre-headless openjdk-8-jdk-headless cmake +sudo apt-get -y install git build-essential zlib1g-dev libc6-dev-i386 g++-multilib gcc-multilib linux-libc-dev:i386 + +Ubuntu 16.04: +sudo apt-get -y install gcc-5-aarch64-linux-gnu g++-5-aarch64-linux-gnu + +Ubuntu 18.04: +sudo apt-get -y install gcc-7-aarch64-linux-gnu g++-7-aarch64-linux-gnu + +Ubuntu 20.04: +sudo apt-get -y install gcc-9-aarch64-linux-gnu g++-9-aarch64-linux-gnu libncurses5 +``` + +## 自动安装工具 + +``` +source build/envsetup.sh arm release +make setup + +以下的步骤只是作为参考,需要的工具都已经在 "make setup" 一步自动安装完成。 +``` + +## 安装 Clang 编译器并完成配置(用于编译方舟编译器代码,20.04 已改为使用系统安装的 Clang) + +下载**clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04** (具体版本请根据系统版本确定) + +LLVM 下载地址:http://releases.llvm.org/download.html#10.0.0 + +解压并放置到`openarkcompiler/tools`目录 + +- 修改`openarkcompiler/build/envsetup.sh`文件,将`CLANG_PATH`变量配置为 clang 编译器所在路径,例如: + +``` +CLANG_PATH = "${MAPLE_ROOT}/tools/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04/bin" +``` + +其中${MAPLE_ROOT}为 openarkcompiler 源码根目录。 + +## 安装 Ninja、GN 并完成配置 + +下载**Ninja(v1.10.0)**及**GN(Linux Version)** + +Ninja 下载地址:https://github.com/ninja-build/ninja/releases + +GN 下载地址:https://gitee.com/xlnb/gn_binary + +将 GN 和 Ninja 可执行程序放置到`openarkcompiler/tools`目录,然后修改这两个文件为可执行: + +``` +cd openarkcompiler/tools +chmod 775 gn +chmod 775 ninja +``` + +打开`openarkcompiler/Makefile`文件,将 GN 和 NINJA 两个变量配置为 GN 和 Ninja 可执行程序所在路径。例如: + +``` +GN := ${MAPLE_ROOT}/tools/gn/gn +NINJA := ${MAPLE_ROOT}/tools/ninja/ninja +``` + +## 安装 gcc-linaro 并完成配置(用于交叉编译方舟编译器代码) + +下载**gcc-linaro-7.5.0-2019.12-i686_aarch64-linux-gnu** + +gcc-linaro-7.5.0 下载地址:https://releases.linaro.org/components/toolchain/binaries/latest-7/aarch64-linux-gnu/ + +解压并放置到`openarkcompiler/tools`目录,并将文件夹更名为`gcc-linaro-7.5.0`。 + +- 修改`openarkcompiler/build/config.gni`文件,将`GCC_LINARO_PATH`变量配置为 gcc-linaro-7.5.0 所在路径,例如: + +``` +GCC_LINARO_PATH = "${MAPLE_ROOT}/tools/gcc-linaro-7.5.0" +``` + +- 修改`openarkcompiler/build/core/maple_variables.mk`文件,将`GCC_LINARO_PATH`配置为 gcc-linaro-7.5.0 所在路径,例如: + +``` +GCC_LINARO_PATH := ${MAPLE_ROOT}/tools/gcc-linaro-7.5.0 +``` + +## 安装 android-ndk 并完成配置(用于编译方舟编译器代码) + +下载**android-ndk-r21b-linux-x86_64.zip** + +android-ndk-r21 下载地址:https://developer.android.google.cn/ndk/downloads/ + +解压并放置到 openarkcompiler/tools 目录,并将文件夹更名为`android-ndk-r21`。 + +- 修改`openarkcompiler/build/config.gni`文件,将`NDK_PATH`变量配置为 android-ndk-r21 所在路径,例如: + +``` +NDK_PATH = "${MAPLE_ROOT}/tools/android-ndk-r21" +``` + +- 修改`openarkcompiler/build/core/maple_variables.mk`文件,将`NDK_PATH`配置为 android-ndk-r21 所在路径,例如: + +``` +NDK_PATH := ${MAPLE_ROOT}/tools/android-ndk-r21 +``` + +## AOSP 运行环境依赖 + +当前编译方舟编译器 Sample 应用需要使用到 Java 基础库,我们通过 AOSP 来获取,请使用 Android-10.0.0_r35 版本,暂不支持 Android11 版本。 + +AOSP 下载地址:https://source.android.com/source/downloading/ + +下载 AOSP 并编译完成。 + +- 在 openarkcompiler 目录下新建链接`android/`,并链接到 AOSP 的根目录; +- 将`openarkcompiler/android/out/target/product/generic_arm64/obj/JAVA_LIBRARIES/core-all_intermediates/javalib.jar`拷贝到`openarkcompiler/libjava-core`目录,并命名为`java-core.jar`,同时码云上也提供了编译好的 libcore 的 jar 文件,你可以下载直接使用,下载链接`https://gitee.com/xlnb/aosp_core_bin`; +- 在 openarkcompiler/tools 下新建链接 gcc,并链接到 AOSP 的`openarkcompiler/android/prebuilts/gcc`; +- 在 openarkcompiler/tools 下新建链接 clang-r353983c,并链接到 AOSP 的`openarkcompiler/android/prebuilts/clang/host/linux-x86/clang-r353983c`; +- 修改`openarkcompiler/build/config.gni`和`openarkcompiler/build/core/maple_variables.mk`中`ANDROID_GCC_PATH`和`ANDROID_CLANG_PATH`两个变量,配置为上述 gcc 和 clang-r353982c 的所在路径,例如: + +config.gni + +``` +ANDROID_GCC_PATH = "${MAPLE_ROOT}/tools/gcc" +ANDROID_CLANG_PATH = "${MAPLE_ROOT}/tools/clang-r353983c" +``` + +maple_variables.mk + +``` +ANDROID_GCC_PATH := ${MAPLE_ROOT}/tools/gcc +ANDROID_GLANG_PATH := ${MAPLE_ROOT}/tools/clang-r353983c +``` + +## 构建工具依赖下载 + +### icu 下载并编译 + +当前用例编译需要 icu 动态库支持,请使用 icu56.1 版本。 + +icu 下载地址:http://site.icu-project.org/home + +下载 56.1 版本的 icu4c 并编译完成,生成`libicuuc.so`和`libicudata.so`,将两者放置到`openarkcompiler/third_party/icu/lib/aarch64-linux-gnu`路径下,并重命名为`libicuuc.so.56`和`libicudata.so.56`。 + +### libz 下载并编译 + +当前用例编译需要 libz.so 支持,请使用 1.2.8 版本。 + +libz 下载地址:https://zlib.net + +下载 1.2.8 版本的 libz.so,将其放置到`openarkcompiler/third_party/libdex/prebuilts/aarch64-linux-gnu/`路径下,并重命名为`libz.so.1.2.8`。 + +### r8 下载并编译 + +当前用例编译需要 d8.jar 支持,请使用 d8-1.5.13 版本。 + +r8 社区地址:https://r8.googlesource.com/r8 + +已经编译后的二进制:https://gitee.com/xlnb/r8-d81513/tree/master/d8/lib/d8.jar + +将 d8.jar 放置到`openarkcompiler/third_party/d8/lib/`目录 diff --git a/doc/cn/MapleDriverOverview.md b/doc/cn/MapleDriverOverview.md new file mode 100644 index 0000000000000000000000000000000000000000..ca6fbbe172b833f9314178a8d43f6a47421107ac --- /dev/null +++ b/doc/cn/MapleDriverOverview.md @@ -0,0 +1,46 @@ +# maple驱动程序概述 +## 简介 +本文档描述了maple驱动程序的当前状态。这包括设计、使用、目标和内部实施。 + +## 目标 +maple驱动程序旨在满足优秀编译器(如clang)的要求。换句话说,它应该是: +-灵活支持新功能 +-高效,开销低 +-易于使用 + +驱动程序开发的最终目标是完全支持gcc选项,并直接集成到CMake构建系统中。 + +## 设计和实现 + +### 设计概述 + +下图显示了maple驱动程序体系结构的重要组件以及它们之间的关系。红色组件表示基本的驱动程序部分(类、方法),蓝色组件是输出/输入数据结构,绿色组件是重要的帮助器类。 + +![](media/MapleDriverStructure.png) + +### 驱动程序阶段 + +驱动程序功能可分为五个阶段: + +**1.解析选项** + +首先检查输入命令行参数字符串的格式正确性,并将其转换为键值对,然后检查键是否在`OptionParser`的`usage`多映射(以前从帮助数据结构创建)中匹配。Option类还包含Descriptor数据结构,用一些附加数据描述选项参数所需的解析细节。然后解析参数。驱动程序希望了解所有可用选项。然后,结果将写入`OptionParser`类的`options`向量中。 + + +**2.填充MplOptions** + +解析输入后,根据结果填充`MplOptions`:首先确定运行类型为自动或者自定义(取决于`--run`选项),然后初始化输入文件并检查有效性。如果运行类型为自动maple驱动程序还将自行配置代码生成管道(您将接收汇编程序文件作为最终输出),具体取决于第一个输入文件的扩展名。然后处理其他选项,包括`--option`,其值必须包含所有编译阶段的选项,使用解析通用选项时相同方法和数据结构来解析值,结果将存放到`MplOptions`类的`exeOptions`映射中。然后,maple驱动程序尝试打开输入文件,如果成功,将进入下一阶段。 + +**3.编译器选择** + +上一阶段完成后,maple驱动程序触发`CompilerFactory`类构造函数,该构造函数创建受支持编译器的类,并将指向所有编译器的指针保存在`supportedCompilers`数据结构中。 + +**4.阶段特定选项构建** + +`CompilerFactory`调用选定编译器的`Compile`方法,该方法构造默认和自定义的选项并写入字符串中。主要的问题是命令从一种风格转换到另一种风格,一些驱动程序组件需要自己的方法正确运行,如`MplcgCompiler`;而另一些组件只使用几个选项,它们的主要目的是确定要调用的可执行文件的路径和传递它们的输入和输出参数,如`AsCompiler`。 + +但是,`MaplecombCompiler`和`MplcgCompiler`需要特殊的管道,它们不调用可执行文件给它们传递命令行,而是使用`MIRModule`、`mirParser`和`DriverRunner`类与输入文件交互。`MIRModule`是一种数据结构,其功能类似于`MplOptions`,`MaplecombCompiler`和`MplcgCompiler`会在其中存储关键数据(输入文件的名称、源语言等);`MIRParser`是为了解析maple IR; `DriverRunner`是一个协调器,它可以与以前的两个数据结构一起工作,同时还存储其负责的阶段的选项和编译中所需的其他数据。 + +**5.执行** + +之后,可执行文件的命令行和完整路径将重定向到`SafeExe`类的`Exe`方法,在那里它通过子进程处理和执行。如果是`MaplecombCompiler`和`MplcgCompiler`,则调用`DriverRunner`的`Run`方法,并将作业发布到阶段管理器。 \ No newline at end of file diff --git a/doc/cn/NaiveRcInsertionDescription.md b/doc/cn/NaiveRcInsertionDescription.md new file mode 100644 index 0000000000000000000000000000000000000000..cfd65561644fd7a017b5d22db865e4b8cbf7c80c --- /dev/null +++ b/doc/cn/NaiveRcInsertionDescription.md @@ -0,0 +1,174 @@ +# 朴素版RC操作插入原理 + +引用计数(Reference Counting, RC)是计算机编程语言中的一种内存管理技术,是指将资源(可以是对象、内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程。使用引用计数技术可以实现自动资源管理的目的。同时引用计数还可以指使用引用计数技术回收未使用资源的垃圾回收算法。朴素版RC(Naive RC)是一种简单直接的RC插入操作。 + + +Naive RC插入的基本原理 +====================== + +- 对象的引用计数的来源: + + - 堆内对象(其它对象、本身)的引用 + + - 栈上的引用(包含寄存器) + + - 静态、全局变量 + +- 引用计数操作的插入规则(编译器和运行时),对应上面的: + + - Object field的赋值,需要将field指向的新对象+1,原对象计数-1 + + - 读取对象到栈上局部变量(含寄存器),需要对读取的对象引用计数+1 + + - 局部变量Last Use后引用计数-1 + + - 返回对象,引用计数+1,补偿局部变量Last Use后-1 + +- 简单示例 + + - 插入前 + + ```cpp + class A { + static Object static_field; + Object instance_field; + A() { + static_field = new Object(); + } + } + Object foo(){ + A a = new A(); + bar(a, new Object()) + return a.instance_field; + } + void bar(A a, Object o) { + a.instance_field = o; + } + ``` + + - 插入后 + + ```cpp + class A { + A() { + local_var t = new Object(); // t是赋值给static_field过程中使用的临时变量 + old = static_field; + static_field = t; + IncRef(t); DecRef(old); // 更新堆上RC + DecRef(t); // 函数退出释放栈上RC + } + } + Object foo(){ + A a = new A(); + bar(a, new Object()); + locl_var t = a.instance_field; + IncRef(t) // 栈上变量引用RC+1 + IncRef(t) // 函数返回,返回值RC+1 + DecRef(a) // 函数退出释放栈上RC,释放a + DecRef(t) // 函数退出释放栈上RC + return t; + } + void bar(A a, Object o) { + old = a.instance_field + a.instance_field = o; + IncRef(o); DecRef(old); + } + ``` + + +- 引用计数函数MIntrinsicsId: + + - 基础函数 + 使用方法:使用IrMap中的CreateIntrinsicCallMeStmt创建IntrinsiccallMeStmt语句,并插入到RC需要加减之处。 + + - INTRN_MCCIncRef + + - INTRN_MCCDecRef + + - Load/Write函数 + 使用方法:Write函数使用IrMap中的CreateIntrinsicCallMeStmt创建IntrinsiccallMeStmt语句替换左值具有static、global、volatile等属性的iassign语句、Load函数使用CreateIntrinsicCallAssignedMeStmt创建IntrinsiccallMeStmt语句,并替换右值具有static、global、volatile等属性的dassign语句,Load/Write函数均具有IncRef操作。 + + - INTRN_MCCLoadRef + + - INTRN_MCCLoadRefS + + - INTRN_MCCLoadRefVol + + - INTRN_MCCLoadRefSVol + + - INTRN_MCCWrite + + - INTRN_MCCWriteS + + - INTRN_MCCWriteVol + + - INTRN_MCCWriteSVol + +RefVar IncRef 处理规则: +======================== + +- 赋值语句处理: + + - 按照左值(赋值语句中被赋值的变量)、右值(赋值语句中被引用的值)表达式不同处理 + + - 先处理右值:比如选择什么Load接口;不需要+1的右值(New、Call) + + - Global属性选择INTRN_MCCLoadRef + + - Static属性选择INTRN_MCCLoadRefS + + - Volatile属性选择INTRN_MCCLoadRefVol + + - 再处理左值:选择什么Write接口;是否需要保存老值等等 + + - Global属性选择INTRN_MCCWriteRef + + - Static属性选择INTRN_MCCWriteRefS + + - Volatile属性选择INTRN_MCCWriteRefVol + +- 返回值处理: + + - 返回值+1 + +- 局部变量处理: + + - 在当前函数退出前(异常、正常退出)引用计数减一 + +Rclowering处理流程: +==================== + +- 设置rclowering处理标志位 +- 标记localrefvar + +- rclowering预处理 + + - 标记需要RC操作的变量 + + - 需要标记DecRef的左值(赋值语句中被赋值的变量): + + - Ref变量 + + - 需要标记IncRef的右值(赋值语句中被引用的值或返回值等): + + - Return值 + + - Ref变量 + + - hrow Value的寄存器 + + - 清理栈变量 + +- rclowering处理 + + - 处理包含Ref类型变量的赋值语句 + + - DecRef原值 + + - IncRef新值,参照RefVar IncRef 处理规则 + +- rclowering后处理 + + - 在函数入口对参数做IncRef并标记为LocalRefVar属性 + + - 处理函数返回值, 属性为LocalRefVar,则InRef,其他参照RefVar IncRef处理规则右值部分 diff --git a/doc/cn/ProgrammingSpecifications.md b/doc/cn/ProgrammingSpecifications.md new file mode 100644 index 0000000000000000000000000000000000000000..2e80d28632387a41cc4d317cef5fa39ee27feecc --- /dev/null +++ b/doc/cn/ProgrammingSpecifications.md @@ -0,0 +1,3089 @@ + + 方舟编译器C++语言编程规范  + + + + + + + + + + + +| 章节 | 内容 | +| ------------------ | ---------------------------------------- | +| [0 前言](#c0) | [目的](#c0-1) [重点关注](#c0-2) [约定](#c0-3) [例外](#c0-4) | +| [1 原则](#c1) | [好代码的原则](#c1-1) [类和函数设计指导原则](#c1-2) [遵循C++ ISO标准](#c1-4)
[优先编译时检查错误](#c1-5) [使用命名空间来限定作用域](#c1-6) [优先使用C++特性而不是C特性](#c1-7) | +| [2 命名](#c2) | [通用命名](#c2-1) [文件命名](#c2-2) [函数命名](#c2-3) [类型命名](#c2-4) [变量命名](#c2-5) [宏、常量、枚举命名](#c2-6) | +| [3 格式](#c3) | [行宽](#c3-1) [缩进](#c3-2) [大括号](#c3-3) [函数声明和定义](#c3-4) [函数调用](#c3-5) [if语句](#c3-6) [循环语句](#c3-7) [switch语句](#c3-8) [表达式](#c3-9) [变量赋值](#c3-10)
[初始化](#c3-11) [指针和引用](#c3-12) [编译预处理](#c3-13) [空格和空行](#c3-14) [类](#c3-15) | +| [4 注释](#c4) | [注释风格](#c4-1) [文件头注释](#c4-2) [函数头注释](#c4-3) [代码注释](#c4-4) | +| [5 头文件](#c5) | [头文件职责](#c5-1) [头文件依赖](#c5-2) | +| [6 作用域](#c6) | [命名空间](#c6-1) [全局函数和静态成员函数](#c6-2) [全局变量](#c6-3) [全局常量和静态成员常量](#c6-4) | +| [7 类](#c7) | [构造、拷贝构造、赋值和析构函数](#c7-1) [继承](#c7-2) [多重继承](#c7-3) [重载](#c7-4) | +| [8 函数](#c8) | [函数设计](#c8-1) [内联函数](#c8-2) [函数参数](#c8-3) | +| [9 C++其他特性](#c9) | [常量与初始化](#c9-1) [表达式](#c9-2) [类型转换](#c9-3) [资源分配和释放](#c9-4) [标准库](#c9-5) [const的用法](#c9-6) [模板](#c9-7) [宏](#c9-8) [其他](#c9-9)| +| [10 现代C++特性](#c10) | [代码简洁性和安全性提升](#c10-1) [智能指针](#c10-2) [Lambda](#c10-3) [接口](#c10-4) | +| [11 安全编码规范](#c11) | [基本原则](#c11-1) [变量](#c11-2) [断言](#c11-3) [异常机制](#c11-4) [内存](#c11-5) [危险函数](#c11-6) | + +# 0 前言 + +## 目的 + +规则并不是完美的,通过禁止在特定情况下有用的特性,可能会对代码实现造成影响。但是我们制定规则的目的__“为了大多数程序员可以得到更多的好处”__, 如果在团队运作中认为某个规则无法遵循,希望可以共同改进该规则。 + +参考该规范之前,希望您具有相应的C++基础能力,而不是通过该文档来学习C++。 +1. 了解C++的ISO标准; +2. 熟知C++的基本语言特性,包括C++ 03/11/14/17相关特性; +3. 了解C++的标准库; + + +## 重点关注 +1. 约定C++的编程风格,比如命名,排版等。 +2. C++的模块化设计,如何设计头文件,类,接口和函数。 +3. C++相关特性的优秀实践,比如常量,类型转换,资源管理,模板等。 +4. 现代C++的优秀实践,包括C++11/14/17中可以提高代码可维护性,提高代码可靠性的相关约定。 + + +## 约定 +**规则**:编程时必须遵守的约定(must) + +**建议**:编程时应该遵守的约定(should) + +本规范适用通用C++标准, 如果没有特定的标准版本,适用所有的版本(C++03/11/14/17)。 + +## 例外 +无论是'规则'还是'建议',都必须理解该条目这么规定的原因,并努力遵守。 +但是,有些规则和建议可能会有例外。 + +在不违背总体原则,经过充分考虑,有充足的理由的前提下,可以适当违背规范中约定。 +例外破坏了代码的一致性,请尽量避免。'规则'的例外应该是极少的。 + +下列情况,应风格一致性原则优先: +**修改外部开源代码、第三方代码时,应该遵守开源代码、第三方代码已有规范,保持风格统一。** +**某些特定领域,优先参考其行业规范。** + +# 1 原则 + +## 好代码的原则 +我们参考Kent Beck的简单设计四原则来指导我们的如何写出优秀的代码,如何有效地判断我们的代码是优秀的。 +1. 通过所有测试(Passes its tests) +2. 尽可能消除重复 (Minimizes duplication) +3. 尽可能清晰表达 (Maximizes clarity) +4. 更少代码元素 (Has fewer elements) +5. 以上四个原则的重要程度依次降低。 + 这组定义被称做简单设计原则。 + +第一条强调的是外部需求,这是代码实现最重要的;第二点就是代码的模块架构设计,保证代码的正交性,保证代码更容易修改;第三点是代码的可阅读性,保证代码是容易阅读的;最后一点才是保证代码是简洁的,在简洁和表达力之间,我们更看重表达力。 + +## 类和函数设计指导原则 +C++是典型的面向对象编程语言,软件工程界已经有很多OOP原则来指导我们编写大规模的,高可扩展的,可维护性的代码: +- 高内聚,低耦合的基本原则:使程序模块的可重用性、移植性大大增强 +- SOLID原则:分别是单一原则、开闭原则、里氏替换原则、接口隔离原则、依赖倒置原则,遵循五大原则可以使程序低耦合,更加健壮 +- 迪米特法则:降低类之间的耦合 +- “Tell,Don’t ask”原则:一个对象应该命令其它对象做什么,而不是去查询其它对象的状态来决定做什么 +- 组合/聚合复用原则:尽量使用合成/聚合,不要使用类继承 + +## 遵循C++ ISO标准 +希望通过使用ISO C++标准的特性来编写C++代码,对于ISO标准中未定义的或者编译器实现的特性要谨慎使用,对于GCC等编译器的提供的扩展特性也需要谨慎使用,这些特性会导致代码的可移植性比较差。 + +注意:如果模块中需要使用相关的扩展特性来,那么尽可能将这些特性封装成独立的接口,并且可以通过编译选项关闭或者编译这些特性。对于这些扩展特性的使用,请模块制定特性编程指南来指导这些特性的使用。 + +## 优先编译时检查错误 +通过编译器来优先保证代码健壮性,而不是通过编写错误处理代码来处理编译就可以发现的异常,比如: + +- 通过const来保证数据的不变性,防止数据被无意修改。 +- 通过static_assert来进行编译时检查。 + +## 使用命名空间来限定作用域 +全局变量,全局常量和全局类型定义由于都属于全局作用域,在项目中,使用第三方库中容易出现冲突。 + +命名空间将作用域细分为独立的,具名的作用域,可有效地防止全局作用域的命名冲突。 +1. class,struct等都具有自己的类作用域。 +2. 具名的namespace可以实现类作用域更上层的作用域。 +3. 匿名namespace和static可以实现文件作用域。 + +对于没有作用域的宏变量,宏函数强烈建议不使用。 + +作用域的一些缺点: +1. 虽然可以通过作用域来区分两个命名相同的类型,但是还是具有迷惑性。 +2. 内联命名空间会让命名空间内部的成员摆脱限制,让人迷惑。 +3. 通过多重嵌套来定义namespace,会让完整的命名空间比较冗长。 + +所以,我们使用命名空间的建议如下: +- 对于变量,常量和类型定义尽可能使用namespace,减少全局作用域的冲突 +- 不要在头文件中使用using namespace +- 不要使用内联命名空间 +- 鼓励在.cpp文件中通过匿名namespace或者static来封装,防止不必要的定义通过API暴露出去。 + + +## 优先使用C++特性而不是C特性 +C++比起C语言更加类型安全,更加抽象。我们更推荐使用C++的语言特性来编程,比如使用string而不是`char*`, 使用vector而不是原生数组,使用namespace而不是static。 + + +# 2 命名 +## 通用命名 +常见命名风格有: +__驼峰风格(CamelCase)__ +大小写字母混用,单词连在一起,不同单词间通过单词首字母大写来分开。 +按连接后的首字母是否大写,又分: 大驼峰(UpperCamelCase)和小驼峰(lowerCamelCase) + +__内核风格(unix_like)__ +单词全小写,用下划线分割。 +如:'test_result' + +__匈牙利风格__ +在‘大驼峰’的基础上,加上前缀;前缀用于表达类型或用途。 +如:'uiSavedCount', 'bTested' + +### 规则2.1.1 标识符命名使用驼峰风格 +不考虑匈牙利命名,在内核风格与驼峰风格之间,根据存量代码的情况,我们选择驼峰风格。 + +| 类型 | 命名风格 | +| ------------------------------------------------------------ | ---------------------------------------- | +| 类类型,结构体类型,枚举类型,联合体类型等类型定义 | 大驼峰 | +| 函数(包括全局函数,作用域函数,成员函数) | 大驼峰(接口部分可加前缀,如XXX_函数名) | +| 全局变量(包括全局和命名空间域下的变量,类静态变量),局部变量,函数参数,类、结构体和联合体中的成员变量 | 小驼峰 | +| 常量(const),枚举值 | k+大小写混合 | +| 宏 | 大写+下划线 | +| 命名空间 | 全小写 | + +注意: +上表中__常量__是指全局作用域、namespace域、类的静态成员域下,以 const或constexpr 修饰的基本数据类型、枚举、字符串类型的变量。 +上表中__变量__是指除常量定义以外的其他变量,均使用小驼峰风格。 + +## 文件命名 +### 建议2.2.1 C++文件以.cpp结尾,头文件以.h结尾。文件名使用下划线小写风格。 + +目前业界还有一些其他的后缀的表示方法: + +- 头文件: .hh, .hpp, .hxx +- cpp文件:.cc, .cxx, .C + +对于本文档,我们默认使用.h和.cpp作为后缀。 + +文件名如下: +- database_connection.h +- database_connection.cpp + + +## 函数命名 +函数命名统一使用大驼峰风格,一般采用动词或者动宾结构。接口部分可加前缀,如XXX_函数名。 +```cpp +class List { + public: + void AddElement(const Element& element); + Element GetElement(const unsigned int index) const; + bool IsEmpty() const; + bool MCC_GetClass(); +}; + +namespace utils { +void DeleteUser(); +} +``` + +## 类型命名 + +类型命名采用大驼峰命名风格。 +所有类型命名——类、结构体、联合体、类型定义(typedef)、枚举——使用相同约定,例如: + +```cpp +// classes, structs and unions +class UrlTable { ... +class UrlTableTester { ... +struct UrlTableProperties { ... +union Packet { ... + +// typedefs +typedef std::map PropertiesMap; + +// enums +enum UrlTableErrors { ... +``` + +对于命名空间的命名,建议全小写: +```cpp +// namespace +namespace osutils { + +namespace fileutils { + +} + +} +``` + + +## 变量命名 +通用变量命名采用小驼峰,包括全局变量,函数形参,局部变量,成员变量。 +```cpp +std::string tableName; // Good: 推荐此风格 +std::string tablename; // Bad: 禁止此风格 +std::string path; // Good: 只有一个单词时,小驼峰为全小写 + +class Foo { + private: + std::string fileName; // 不添加任何作用域前缀或者后缀 +}; +``` + +## 宏、常量、枚举命名 +宏采用全大写,下划线连接的格式。常量、枚举值使用k+大小写混合。 +函数局部 const 常量和类的普通const成员变量,使用小驼峰命名风格。 + +```cpp +#define MAX(a, b) (((a) < (b)) ? (b) : (a)) // 仅对宏命名举例,并不推荐用宏实现此类功能 + +enum TintColor { // 注意,枚举类型名用大驼峰,其下面的取值是k+大小写混合 + kRed, + kDarkRed, + kGreen, + kLightGreen +}; + +int Func(...) { + const unsigned int bufferSize = 100; // 函数局部常量 + char *p = new char[bufferSize]; + ... +} + +namespace utils { +const unsigned int kFileSize = 200; // 全局常量 +} + +``` + +# 3 格式 +尽管有些编程的排版风格因人而异,但是我们强烈建议和要求使用统一的编码风格,以便所有人都能够轻松的阅读和理解代码,增强代码的可维护性。 + +## 行宽 + +### 建议3.1.1 行宽不超过 120 个字符 +建议每行字符数不要超过 120 个。如果超过120个字符,请选择合理的方式进行换行。 + +例外: +- 如果一行注释包含了超过120 个字符的命令或URL,则可以保持一行,以方便复制、粘贴和通过grep查找; +- 包含长路径的 #include 语句可以超出120 个字符,但是也需要尽量避免; +- 编译预处理中的error信息可以超出一行。 +预处理的 error 信息在一行便于阅读和理解,即使超过 120 个字符。 + +```cpp +#ifndef XXX_YYY_ZZZ +#error Header aaaa/bbbb/cccc/abc.h must only be included after xxxx/yyyy/zzzz/xyz.h, because xxxxxxxxxxxxxxxxxxxxxxxxxxxxx +#endif +``` + +## 缩进 + +### 规则3.2.1 使用空格进行缩进,每次缩进2个空格 +只允许使用空格(space)进行缩进,每次缩进为 2 个空格。 + + + + +## 大括号 +### 规则3.3.1 除函数外,使用 K&R 缩进风格 +函数左大括号跟随语句放行末。 +右大括号独占一行,除非后面跟着同一语句的剩余部分,如 do 语句中的 while,或者 if 语句的 else/else if,或者逗号、分号。 + +如: +```cpp +struct MyType { // 跟随语句放行末,前置1空格 + ... +}; + +int Foo(int a) { // 函数左大括号跟随语句放行末 + if (...) { + ... + } else { + ... + } +} +``` +推荐这种风格的理由: + +- 代码更紧凑; +- 相比另起一行,放行末使代码阅读节奏感上更连续; +- 符合后来语言的习惯,符合业界主流习惯; +- 现代集成开发环境(IDE)都具有代码缩进对齐显示的辅助功能,大括号放在行尾并不会对缩进和范围产生理解上的影响。 + + +对于空函数体,可以将大括号放在同一行: +```cpp +class MyClass { + public: + MyClass() : value(0) {} + + private: + int value; +}; +``` + +## 函数声明和定义 + +### 规则3.4.1 函数声明和定义的返回类型和函数名在同一行;函数参数列表超出行宽时要换行并合理对齐 +在声明和定义函数的时候,函数的返回值类型应该和函数名在同一行;如果行宽度允许,函数参数也应该放在一行;否则,函数参数应该换行,并进行合理对齐。 +参数列表的左圆括号总是和函数名在同一行,不要单独一行;右圆括号总是跟随最后一个参数。 + +换行举例: +```cpp +ReturnType FunctionName(ArgType paramName1, ArgType paramName2) { // Good:全在同一行 + ... +} + +ReturnType VeryVeryVeryLongFunctionName(ArgType paramName1, // 行宽不满足所有参数,进行换行 + ArgType paramName2, // Good:和上一行参数对齐 + ArgType paramName3) { + ... +} + +ReturnType LongFunctionName(ArgType paramName1, ArgType paramName2, // 行宽限制,进行换行 + ArgType paramName3, ArgType paramName4, ArgType paramName5) { // Good: 换行后 4 空格缩进 + ... +} + +ReturnType ReallyReallyReallyReallyLongFunctionName( // 行宽不满足第1个参数,直接换行 + ArgType paramName1, ArgType paramName2, ArgType paramName3) { // Good: 换行后 4 空格缩进 + ... +} +``` + +## 函数调用 +### 规则3.5.1 函数调用入参列表应放在一行,超出行宽换行时,保持参数进行合理对齐 +函数调用时,函数参数列表放在一行。参数列表如果超过行宽,需要换行并进行合理的参数对齐。 +左圆括号总是跟函数名,右圆括号总是跟最后一个参数。 + +换行举例: +```cpp +ReturnType result = FunctionName(paramName1, paramName2); // Good:函数参数放在一行 + +ReturnType result = FunctionName(paramName1, + paramName2, // Good:保持与上方参数对齐 + paramName3); + +ReturnType result = FunctionName(paramName1, paramName2, + paramName3, paramName4, paramName5); // Good:参数换行,4 空格缩进 + +ReturnType result = VeryVeryVeryLongFunctionName( // 行宽不满足第1个参数,直接换行 + paramName1, paramName2, paramName3); // 换行后,4 空格缩进 +``` + +如果函数调用的参数存在内在关联性,按照可理解性优先于格式排版要求,对参数进行合理分组换行。 +```cpp +// Good:每行的参数代表一组相关性较强的数据结构,放在一行便于理解 +int result = DealWithStructureLikeParams(left.x, left.y, // 表示一组相关参数 + right.x, right.y); // 表示另外一组相关参数 +``` + +## if语句 + +### 规则3.6.1 if语句必须要使用大括号 +我们要求if语句都需要使用大括号,即便只有一条语句。 + +理由: +- 代码逻辑直观,易读; +- 在已有条件语句代码上增加新代码时不容易出错; +- 对于在if语句中使用函数式宏时,有大括号保护不易出错(如果宏定义时遗漏了大括号)。 + +```cpp +if (objectIsNotExist) { // Good:单行条件语句也加大括号 + return CreateNewObject(); +} +``` +### 规则3.6.2 禁止 if/else/else if 写在同一行 +条件语句中,若有多个分支,应该写在不同行。 + +如下是正确的写法: + +```cpp +if (someConditions) { + DoSomething(); + ... +} else { // Good: else 与 if 在不同行 + ... +} +``` + +下面是不符合规范的案例: + +```cpp +if (someConditions) { ... } else { ... } // Bad: else 与 if 在同一行 +``` + +## 循环语句 +### 规则3.7.1 循环语句要求使用大括号 +和if语句类似,我们要求for/while循环语句必须加上的大括号,即使循环体是空的,或者循环语句只有一条。 + +```cpp +for (int i = 0; i < someRange; i++) { + DoSomething(); +} +``` + +如果循环体是空的,应该使用空的大括号,而不是使用单个分号。 单个分号容易被遗漏,也容易被误认为是循环语句中的一部分。 + +```cpp +for (int i = 0; i < someRange; i++) { } // Good: for循环体是空,使用大括号,而不是使用分号 + +while (someCondition) { } // Good:while循环体是空,使用大括号,而不是使用分号 + +while (someCondition) { + continue; // Good:continue表示空逻辑,可以使用大括号也可以不使用 +} + +``` + +坏的例子: +```cpp +for (int i = 0; i < someRange; i++) ; // Bad: for循环体是空,也不要只使用分号,要使用大括号 + +while (someCondition) ; // Bad:使用分号容易让人误解是while语句中的一部分 +``` + +## switch语句 +### 规则3.8.1 switch 语句的 case/default 要缩进一层 +switch 语句的缩进风格如下: +```cpp +switch (var) { + case 0: // Good: 缩进 + DoSomething1(); // Good: 缩进 + break; + case 1: { // Good: 带大括号格式 + DoSomething2(); + break; + } + default: + break; +} +``` + +```cpp +switch (var) { +case 0: // Bad: case 未缩进 + DoSomething(); + break; +default: // Bad: default 未缩进 + break; +} +``` + +## 表达式 + +### 建议3.9.1 表达式换行要保持换行的一致性 +较长的表达式,不满足行宽要求的时候,需要在适当的地方换行。 +例: + +// 假设下面第一行已经不满足行宽要求 +```cpp +if (currentValue > threshold && + someConditionsion) { + DoSomething(); + ... +} + +int result = reallyReallyLongVariableName1 + // Good + reallyReallyLongVariableName2; +``` +表达式换行后,注意保持合理对齐,或者4空格缩进。参考下面例子 + +```cpp +int sum = longVaribleName1 + longVaribleName2 + longVaribleName3 + + longVaribleName4 + longVaribleName5 + longVaribleName6; // Good: 4空格缩进 + +int sum = longVaribleName1 + longVaribleName2 + longVaribleName3 + + longVaribleName4 + longVaribleName5 + longVaribleName6; // Good: 保持对齐 +``` +## 变量赋值 + +### 规则3.10.1 多个变量定义和赋值语句不允许写在一行 +每行只有一个变量初始化的语句,更容易阅读和理解。 + +```cpp +int maxCount = 10; +bool isCompleted = false; +``` + +下面是不符合规范的示例: + +```cpp +int maxCount = 10; bool isCompleted = false; // Bad:多个变量初始化需要分开放在多行,每行一个变量初始化 +int x, y = 0; // Bad:多个变量定义需要分行,每行一个 + +int pointX; +int pointY; +... +pointX = 1; pointY = 2; // Bad:多个变量赋值语句放同一行 +``` +例外:for 循环头、if 初始化语句(C++17)、结构化绑定语句(C++17)中可以声明和初始化多个变量。这些语句中的多个变量声明有较强关联,如果强行分成多行会带来作用域不一致,声明和初始化割裂等问题。 + +## 初始化 +初始化包括结构体、联合体、及数组的初始化 + +### 规则3.11.1 初始化换行时要有缩进,并进行合理对齐 +结构体或数组初始化时,如果换行应保持4空格缩进。 +从可读性角度出发,选择换行点和对齐位置。 + +```cpp +const int rank[] = { + 16, 16, 16, 16, 32, 32, 32, 32, + 64, 64, 64, 64, 32, 32, 32, 32 +}; +``` + +## 指针与引用 +### 建议3.12.1 指针类型"* "跟随变量名或者类型,不要两边都留有或者都没有空格 + +指针命名: * 靠左靠右都可以,但是不要两边都有或者都没有空格。 + +```cpp +int* p = NULL; // Good +int *p = NULL; // Good +int*p = NULL; // Bad +int * p = NULL; // Bad +``` + +例外:当变量被 const 修饰时,"`*`" 无法跟随变量,此时也不要跟随类型。 +```cpp +char * const VERSION = "V100"; +``` + +例外:对于如` static_cast(somePointer)/(char*)/vector `中的场景,*与类型之间不加空格。 + +### 建议3.12.2 引用类型"& "跟随变量名或者类型,不要两边都留有或者都没有空格 + +引用命名: & 靠左靠右都可以,但是不要两边都有或者都没有空格。 + +```cpp +int i = 8; +int& p = i; // Good +int &p = i; // Good +int & p = i; // Bad +int&p = i; // Bad +``` + + +## 编译预处理 +### 规则3.13.1 编译预处理的"#"统一放在行首,嵌套编译预处理语句时,"#"不缩进 +编译预处理的"#"统一放在行首,即使编译预处理的代码是嵌入在函数体中的,"#"也应该放在行首。 + +```cpp +#if defined(__x86_64__) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) // Good:"#"放在行首 +#define ATOMIC_X86_HAS_CMPXCHG16B 1 // Good:"#"放在行首 +#else +#define ATOMIC_X86_HAS_CMPXCHG16B 0 +#endif + + +int FunctionName() { + if (someThingError) { + ... +#ifdef HAS_SYSLOG // Good:即便在函数内部,"#"也放在行首 + WriteToSysLog(); +#else + WriteToFileLog(); +#endif + } +} +``` +内嵌的预处理语句"#"不缩进 + +```cpp +#if defined(__x86_64__) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define ATOMIC_X86_HAS_CMPXCHG16B 1 // Good:区分层次,便于阅读 +#else +#define ATOMIC_X86_HAS_CMPXCHG16B 0 +#endif +``` + +## 空格和空行 +### 建议3.14.1 水平空格应该突出关键字和重要信息,避免不必要的留白 +水平空格应该突出关键字和重要信息,每行代码尾部不要加空格。总体规则如下: + +- if, switch, case, do, while, for等关键字之后加空格; +- 小括号内部的两侧,不要加空格; +- 大括号内部两侧有无空格,左右必须保持一致; +- 一元操作符(& * + ‐ ~ !)之后不要加空格; +- 二元操作符(= + ‐ < > * / % | & ^ <= >= == != )左右两侧加空格 +- 三目运算符(? :)符号两侧均需要空格 +- 前置和后置的自增、自减(++ --)和变量之间不加空格 +- 结构体成员操作符(. ->)前后不加空格 +- 逗号(,)前面不加空格,后面增加空格 +- 对于模板和类型转换(<>)和类型之间不要添加空格 +- 域操作符(::)前后不要添加空格 +- 冒号(:)前后根据情况来判断是否要添加空格 + +常规情况: +```cpp +void Foo(int b) { // Good:大括号前应该留空格 + +int i = 0; // Good:变量初始化时,=前后应该有空格,分号前面不要留空格 + +int buf[kBufSize] = {0}; // Good:大括号内两侧都无空格 +``` + +函数定义和函数调用: +```cpp +int result = Foo(arg1,arg2); + ^ // Bad: 逗号后面需要增加空格 + +int result = Foo( arg1, arg2 ); + ^ ^ // Bad: 函数参数列表的左括号后面不应该有空格,右括号前面不应该有空格 +``` + +指针和取地址 +```cpp +x = *p; // Good:*操作符和指针p之间不加空格 +p = &x; // Good:&操作符和变量x之间不加空格 +x = r.y; // Good:通过.访问成员变量时不加空格 +x = r->y; // Good:通过->访问成员变量时不加空格 +``` + +操作符: +```cpp +x = 0; // Good:赋值操作的=前后都要加空格 +x = -5; // Good:负数的符号和数值之前不要加空格 +++x; // Good:前置和后置的++/--和变量之间不要加空格 +x--; + +if (x && !y) // Good:布尔操作符前后要加上空格,!操作和变量之间不要空格 +v = w * x + y / z; // Good:二元操作符前后要加空格 +v = w * (x + z); // Good:括号内的表达式前后不需要加空格 + +int a = (x < y) ? x : y; // Good: 三目运算符, ?和:前后需要添加空格 +``` + +循环和条件语句: +```cpp +if (condition) { // Good:if关键字和括号之间加空格,括号内条件语句前后不加空格 + ... +} else { // Good:else关键字和大括号之间加空格 + ... +} + +while (condition) {} // Good:while关键字和括号之间加空格,括号内条件语句前后不加空格 + +for (int i = 0; i < someRange; ++i) { // Good:for关键字和括号之间加空格,分号之后加空格 + ... +} + +switch (condition) { // Good: switch 关键字后面有1空格 + case 0: // Good:case语句条件和冒号之间不加空格 + ... + break; + ... + default: + ... + break; +} +``` + +模板和转换 +```cpp +// 尖括号(< and >) 不与空格紧邻, < 前没有空格, > 和 ( 之间也没有. +vector x; +y = static_cast(x); + +// 在类型与指针操作符之间留空格也可以, 但要保持一致. +vector x; +``` + +域操作符 +```cpp +std::cout; // Good: 命名空间访问,不要留空格 + +int MyClass::GetValue() const {} // Good: 对于成员函数定义,不要留空格 +``` + +冒号 +```cpp +// 添加空格的场景 + +// Good: 类的派生需要留有空格 +class Sub : public Base { + +}; + +// 构造函数初始化列表需要留有空格 +MyClass::MyClass(int var) : someVar(var) { + DoSomething(); +} + +// 位域表示也留有空格 +struct XX { + char a : 4; + char b : 5; + char c : 4; +}; +``` + +```cpp +// 不添加空格的场景 + +// Good: 对于public:, private:这种类访问权限的冒号不用添加空格 +class MyClass { + public: + MyClass(int var); + private: + int someVar; +}; + +// 对于switch-case的case和default后面的冒号不用添加空格 +switch (value) { + case 1: + DoSomething(); + break; + default: + break; +} +``` + +注意:当前的集成开发环境(IDE)可以设置删除行尾的空格,请正确配置。 + +### 建议3.14.2 合理安排空行,保持代码紧凑 + +减少不必要的空行,可以显示更多的代码,方便代码阅读。下面有一些建议遵守的规则: +- 根据上下内容的相关程度,合理安排空行; +- 函数内部、类型定义内部、宏内部、初始化表达式内部,不使用连续空行 +- 不使用连续 **3** 个空行,或更多 +- 大括号内的代码块行首之前和行尾之后不要加空行。 + +```cpp +int Foo() { + ... +} + + +// Bad:两个函数定义间超过了一个空行 +int Bar() { + ... +} + + +if (...) { + // Bad:大括号内的代码块行首不要加入空行 + ... + // Bad:大括号内的代码块行尾不要加入空行 +} + +int Foo(...) { + // Bad:函数体内行首不要加空行 + ... +} +``` + +## 类 +### 规则3.15.1 类访问控制块的声明依次序是 public:, protected:, private:,每个都缩进 1 个空格 +```cpp +class MyClass : public BaseClass { + public: // 1空格缩进 + MyClass(); // 标准的2空格缩进 + explicit MyClass(int var); + ~MyClass() {} + + void SomeFunction(); + void SomeFunctionThatDoesNothing() { + } + + void SetVar(int var) { + someVar = var; + } + + int GetVar() const { + return someVar; + } + + private: + bool SomeInternalFunction(); + + int someVar; + int someOtherVar; +}; +``` + +在各个部分中,建议将类似的声明放在一起, 并且建议以如下的顺序: 类型 (包括 typedef, using 和嵌套的结构体与类), 常量, 工厂函数, 构造函数, 赋值运算符, 析构函数, 其它成员函数, 数据成员。 + + +### 规则3.15.2 构造函数初始化列表放在同一行或按四格缩进并排多行 +```cpp +// 如果所有变量能放在同一行: +MyClass::MyClass(int var) : someVar(var) { + DoSomething(); +} + +// 如果不能放在同一行, +// 必须置于冒号后, 并缩进4个空格 +MyClass::MyClass(int var) + : someVar(var), someOtherVar(var + 1) { // Good: 逗号后面留有空格 + DoSomething(); +} + +// 如果初始化列表需要置于多行, 需要逐行对齐 +MyClass::MyClass(int var) + : someVar(var), // 缩进4个空格 + someOtherVar(var + 1) { + DoSomething(); +} +``` + +# 4 注释 +一般的,尽量通过清晰的架构逻辑,好的符号命名来提高代码可读性;需要的时候,才辅以注释说明。 +注释是为了帮助阅读者快速读懂代码,所以要从读者的角度出发,__按需注释__。 + +注释内容要简洁、明了、无二义性,信息全面且不冗余。 + +__注释跟代码一样重要。__ +写注释时要换位思考,用注释去表达此时读者真正需要的信息。在代码的功能、意图层次上进行注释,即注释解释代码难以表达的意图,不要重复代码信息。 +修改代码时,也要保证其相关注释的一致性。只改代码,不改注释是一种不文明行为,破坏了代码与注释的一致性,让阅读者迷惑、费解,甚至误解。 + +## 注释风格 +在 C++ 代码中,使用` /* */`和` // `都是可以的。 +按注释的目的和位置,注释可分为不同的类型,如文件头注释、函数头注释、代码注释等等; +同一类型的注释应该保持统一的风格,建议: +1)文件头注释使用` /* */ `。 +2)同一文件内函数头注释、代码注释要使用相同的注释符,不可混用。 + +注意:__本文示例代码中,大量使用 '//' 后置注释只是为了更精确的描述问题,并不代表这种注释风格更好。__ + +## 文件头注释 +### 规则4.2.1 文件头注释必须包含版权许可 +```cpp +/* + * Copyright (c) [2019] [name of copyright holder] + * [Software Name] is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v1 for more details. + */ +``` + + + +## 函数头注释 +### 规则4.3.1 禁止空有格式的函数头注释 +并不是所有的函数都需要函数头注释; +函数签名无法表达的信息,加函数头注释辅助说明; + +函数头注释统一放在函数声明或定义上方,使用如下风格之一: +使用`//`写函数头 + +```cpp +// 单行函数头 +int Func1(void); + +// 多行函数头 +// 第二行 +int Func2(void); +``` + +使用`/* */`写函数头 +```cpp +/* 单行函数头 */ +int Func1(void); + +/* + * 另一种单行函数头 + */ +int Func2(void); + +/* + * 多行函数头 + * 第二行 + */ +int Func3(void); +``` +函数尽量通过函数名自注释,按需写函数头注释。 +不要写无用、信息冗余的函数头;不要写空有格式的函数头。 + +函数头注释内容可选,但不限于:功能说明、返回值,性能约束、用法、内存约定、算法实现、可重入的要求等等。 +模块对外头文件中的函数接口声明,其函数头注释,应当将重要、有用的信息表达清楚。 + +例: + +```cpp +/* + * 返回实际写入的字节数,-1表示写入失败 + * 注意,内存 buf 由调用者负责释放 + */ +int WriteString(const char *buf, int len); +``` + +坏的例子: +```cpp +/* + * 函数名:WriteString + * 功能:写入字符串 + * 参数: + * 返回值: + */ +int WriteString(const char *buf, int len); +``` +上面例子中的问题: + +- 参数、返回值,空有格式没内容 +- 函数名信息冗余 +- 关键的 buf 由谁释放没有说清楚 + +## 代码注释 +### 规则4.4.1 代码注释放于对应代码的上方或右边 +### 规则4.4.2 注释符与注释内容间要有1空格;右置注释与前面代码至少1空格 +代码上方的注释,应该保持对应代码一样的缩进。 +选择并统一使用如下风格之一: +使用`//` +```cpp + +// 这是单行注释 +DoSomething(); + +// 这是多行注释 +// 第二行 +DoSomething(); +``` + +使用`/*' '*/` +```cpp +/* 这是单行注释 */ +DoSomething(); + +/* + * 另一种方式的多行注释 + * 第二行 + */ +DoSomething(); +``` +代码右边的注释,与代码之间,至少留1空格,建议不超过4空格。 +通常使用扩展后的 TAB 键即可实现 1-4 空格的缩进。 + +选择并统一使用如下风格之一: + +```cpp +int foo = 100; // 放右边的注释 +int bar = 200; /* 放右边的注释 */ +``` +右置格式在适当的时候,上下对齐会更美观。 +对齐后的注释,离左边代码最近的那一行,保证1-4空格的间隔。 +例: + +```cpp +const int kConst = 100; /* 相关的同类注释,可以考虑上下对齐 */ +const int kAnotherConst = 200; /* 上下对齐时,与左侧代码保持间隔*/ +``` +当右置的注释超过行宽时,请考虑将注释置于代码上方。 + +### 规则4.4.3 不用的代码段直接删除,不要注释掉 +被注释掉的代码,无法被正常维护;当企图恢复使用这段代码时,极有可能引入易被忽略的缺陷。 +正确的做法是,不需要的代码直接删除掉。若再需要时,考虑移植或重写这段代码。 + +这里说的注释掉代码,包括用 /* */ 和 //,还包括 #if 0, #ifdef NEVER_DEFINED 等等。 + +### 建议4.4.1 代码尽量不要包含 TODO/TBD/FIXME 注释 +TODO/TBD 注释一般用来描述已知待改进、待补充的修改点 +FIXME 注释一般用来描述已知缺陷 +它们都应该有统一风格,方便文本搜索统一处理。如: + +```cpp +// TODO(): 补充XX处理 +// FIXME: XX缺陷 +``` + + +# 5 头文件 +## 头文件职责 +头文件是模块或文件的对外接口,头文件的设计体现了大部分的系统设计。 +头文件中适合放置接口的声明,不适合放置实现(内联函数除外)。对于cpp文件中内部才需要使用的函数、宏、枚举、结构定义等不要放在头文件中。 +头文件应当职责单一。头文件过于复杂,依赖过于复杂还是导致编译时间过长的主要原因。 + +### 建议5.1.1 每一个.cpp文件应有一个对应的.h文件,用于声明需要对外公开的类与接口 +通常情况下,每个.cpp文件都有一个相应的.h,用于放置对外提供的函数声明、宏定义、类型定义等。另外,可根据实际情况添加对应的.inline.h文件优化代码。 +如果一个.cpp文件不需要对外公布任何接口,则其就不应当存在。 +例外:__程序的入口(如main函数所在的文件),单元测试代码,动态库代码。__ + +示例: +```cpp +// Foo.h + +#ifndef FOO_H +#define FOO_H + +class Foo { + public: + Foo(); + void Fun(); + + private: + int value; +}; + +#endif +``` + +```cpp +// Foo.cpp +#include "Foo.h" + +namespace { // Good: 对内函数的声明放在.cpp文件的头部,并声明为匿名namespace或者static限制其作用域 +void Bar() { +} +} + +... + +void Foo::Fun() { + Bar(); +} +``` + +## 头文件依赖 +### 规则5.2.1 禁止头文件循环依赖 +头文件循环依赖,指 a.h 包含 b.h,b.h 包含 c.h,c.h 包含 a.h, 导致任何一个头文件修改,都导致所有包含了a.h/b.h/c.h的代码全部重新编译一遍。 +而如果是单向依赖,如a.h包含b.h,b.h包含c.h,而c.h不包含任何头文件,则修改a.h不会导致包含了b.h/c.h的源代码重新编译。 + +头文件循环依赖直接体现了架构设计上的不合理,可通过优化架构去避免。 + +### 规则5.2.2 禁止包含用不到的头文件 +用不到的头文件被包含的同时引入了不必要的依赖,增加了模块或单元之间的耦合度,只要该头文件被修改,代码就要重新编译。 + +很多系统中头文件包含关系复杂,开发人员为了省事起见,直接包含一切想到的头文件,甚至发布了一个god.h,其中包含了所有头文件,然后发布给各个项目组使用,这种只图一时省事的做法,导致整个系统的编译时间进一步恶化,并对后来人的维护造成了巨大的麻烦。 + +### 规则5.2.3 头文件应当自包含 +简单的说,自包含就是任意一个头文件均可独立编译。如果一个文件包含某个头文件,还要包含另外一个头文件才能工作的话,给这个头文件的用户增添不必要的负担。 + +示例: +如果a.h不是自包含的,需要包含b.h才能编译,会带来的危害: +每个使用a.h头文件的.cpp文件,为了让引入的a.h的内容编译通过,都要包含额外的头文件b.h。 +额外的头文件b.h必须在a.h之前进行包含,这在包含顺序上产生了依赖。 + + +### 规则5.2.4 头文件必须编写`#define`保护,防止重复包含 +为防止头文件被重复包含,所有头文件都应当使用 #define 保护;不要使用 #pragma once + +定义包含保护符时,应该遵守如下规则: +1)保护符使用唯一名称; +2)不要在受保护部分的前后放置代码或者注释,文件头注释除外。 + +示例:假定VOS工程的timer模块的timer.h,其目录为VOS/include/timer/Timer.h,应按如下方式保护: + +```cpp +#ifndef VOS_INCLUDE_TIMER_TIMER_H +#define VOS_INCLUDE_TIMER_TIMER_H +... +#endif +``` + +也可以不用像上面添加路径,但是要保证当前工程内宏是唯一的。 +```cpp +#ifndef TIMER_H +#define TIMER_H +... +#endif +``` + +### 建议5.2.1 禁止通过声明的方式引用外部函数接口、变量 +只能通过包含头文件的方式使用其他模块或文件提供的接口。 +通过 extern 声明的方式使用外部函数接口、变量,容易在外部接口改变时可能导致声明和定义不一致。 +同时这种隐式依赖,容易导致架构腐化。 + +不符合规范的案例: + +// a.cpp内容 +```cpp +extern int Fun(); // Bad: 通过extern的方式使用外部函数 + +void Bar() { + int i = Fun(); + ... +} +``` + +// b.cpp内容 +```cpp +int Fun() { + // Do something +} +``` +应该改为: + +// a.cpp内容 +```cpp +#include "b.h" // Good: 通过包含头文件的方式使用其他.cpp提供的接口 + +void Bar() { + int i = Fun(); + ... +} +``` + +// b.h内容 +```cpp +int Fun(); +``` + +// b.cpp内容 +```cpp +int Fun() { + // Do something +} +``` +例外,有些场景需要引用其内部函数,但并不想侵入代码时,可以 extern 声明方式引用。 +如: +针对某一内部函数进行单元测试时,可以通过 extern 声明来引用被测函数; +当需要对某一函数进行打桩、打补丁处理时,允许 extern 声明该函数。 + +### 规则5.2.5 禁止在extern "C"中包含头文件 +在 extern "C" 中包含头文件,有可能会导致 extern "C" 嵌套,部分编译器对 extern "C" 嵌套层次有限制,嵌套层次太多会编译错误。 + +在C,C++混合编程的情况下,在extern "C"中包含头文件,可能会导致被包含头文件的原有意图遭到破坏,比如链接规范被不正确地更改。 + +示例,存在a.h和b.h两个头文件: + +// a.h内容 +```cpp +... +#ifdef __cplusplus +void Foo(int); +#define A(value) Foo(value) +#else +void A(int) +#endif +``` +// b.h内容 +```cpp +... +#ifdef __cplusplus +extern "C" { +#endif + +#include "a.h" +void B(); + +#ifdef __cplusplus +} +#endif +``` + +使用C++预处理器展开b.h,将会得到 +```cpp +extern "C" { + void Foo(int); + void B(); +} +``` + +按照 a.h 作者的本意,函数 Foo 是一个 C++ 自由函数,其链接规范为 "C++"。 +但在 b.h 中,由于 `#include "a.h"` 被放到了 `extern "C"` 的内部,函数 Foo 的链接规范被不正确地更改了。 + +例外: +如果在 C++ 编译环境中,想引用纯C的头文件,这些C头文件并没有` extern "C"` 修饰。非侵入式的做法是,在 `extern "C"` 中去包含C头文件。 + +### 建议5.2.2尽量避免使用前置声明,而是通过`#include`来包含头文件 +前置声明(forward declaration)是类、函数和模板的纯粹声明,没伴随着其定义。 + +- 优点: + 1. 前置声明能够节省编译时间,多余的 #include 会迫使编译器展开更多的文件,处理更多的输入。 + 2. 前置声明能够节省不必要的重新编译的时间。 #include 使代码因为头文件中无关的改动而被重新编译多次。 +- 缺点: + 1. 前置声明隐藏了依赖关系,头文件改动时,用户的代码会跳过必要的重新编译过程。 + 2. 前置声明可能会被库的后续更改所破坏。前置声明函数或模板有时会妨碍头文件开发者变动其 API. 例如扩大形参类型,加个自带默认参数的模板形参等等。 + 3. 前置声明来自命名空间` std::` 的 symbol 时,其行为未定义(在C++11标准规范中明确说明)。 + 4. 前置声明了不少来自头文件的 symbol 时,就会比单单一行的 include 冗长。 + 5. 仅仅为了能前置声明而重构代码(比如用指针成员代替对象成员)会使代码变得更慢更复杂。 + 6. 很难判断什么时候该用前置声明,什么时候该用`#include`,某些场景下面前置声明和`#include`互换以后会导致意想不到的结果。 + +所以我们尽可能避免使用前置声明,而是使用#include头文件来保证依赖关系。 + +### 建议5.2.3 头文件包含顺序:首先是.cpp相应的.h文件,其它头文件按照稳定度排序 +使用标准的头文件包含顺序可增强可读性, 避免隐藏依赖,建议按照稳定度排序:cpp对应的头文件, C/C++标准库, 系统库的.h, 其他库的.h, 本项目内其他的.h。 + +举例,Foo.cpp中包含头文件的次序如下: +```cpp +#include "Foo/Foo.h" + +#include +#include + +#include +#include + +#include "platform/Base.h" +#include "platform/Framework.h" + +#include "project/public/Log.h" +``` +将Foo.h放在最前面可以保证当Foo.h遗漏某些必要的库,或者有错误时,Foo.cpp的构建会立刻中止,减少编译时间。 对于头文件中包含顺序也参照此建议。 + +例外: +平台特定代码需要条件编译,这些代码可以放到其它 includes 之后。 +```cpp +#include "foo/public/FooServer.h" + +#include "base/Port.h" // For LANG_CXX11. + +#ifdef LANG_CXX11 +#include +#endif // LANG_CXX11 +``` + +# 6 作用域 + +## 命名空间 +命名空间里的内容不缩进。 + +### 建议6.1.1 对于cpp文件中不需要导出的变量,常量或者函数,请使用匿名namespace封装或者用static修饰 +在C++ 2003标准规范中,使用static修饰文件作用域的变量,函数等被标记为deprecated特性,所以更推荐使用匿名namespace。 + +主要原因如下: +1. static在C++中已经赋予了太多的含义,静态函数成员变量,静态成员函数,静态全局变量,静态函数局部变量,每一种都有特殊的处理。 +2. static只能保证变量,常量和函数的文件作用域,但是namespace还可以封装类型等。 +3. 统一namespace来处理C++的作用域,而不需要同时使用static和namespace来管理。 +4. static修饰的函数不能用来实例化模板,而匿名namespace可以。 + +但是不要在 .h 中使用中使用匿名namespace或者static。 + +```cpp +// Foo.cpp + +namespace { +const int kMaxCount = 20; +void InternalFun(){}; +} + +void Foo::Fun() { + int i = kMaxCount; + + InternalFun(); +} + +``` + +### 规则6.1.1 不要在头文件中或者#include之前使用using导入命名空间 +说明:使用using导入命名空间会影响后续代码,易造成符号冲突,所以不要在头文件以及源文件中的#include之前使用using导入命名空间。 +示例: + +```cpp +// 头文件a.h +namespace namespacea { +int Fun(int); +} +``` + +```cpp +// 头文件b.h +namespace namespaceb { +int Fun(int); +} + +using namespace namespaceb; + +void G() { + Fun(1); +} +``` + +```cpp +// 源代码a.cpp +#include "a.h" +using namespace namespacea; +#include "b.h" + +void main() { + G(); // using namespace namespacea在#include “b.h”之前,引发歧义:namespacea::Fun,namespaceb::Fun调用不明确 +} +``` + +对于在头文件中使用using导入单个符号或定义别名,允许在模块自定义名字空间中使用,但禁止在全局名字空间中使用。 +```cpp +// foo.h + +#include +using fancy::string; // Bad,禁止向全局名字空间导入符号 + +namespace foo { +using fancy::string; // Good,可以在模块自定义名字空间中导入符号 +using MyVector = fancy::vector; // Good,C++11可在自定义名字空间中定义别名 +} +``` + + +### 规则6.1.2 禁止using namespace std; +说明:使用std前缀让代码更清楚,并且可以防止名字冲突。 + + +## 全局函数和静态成员函数 + +### 建议6.2.1 优先使用命名空间来管理全局函数,如果和某个class有直接关系的,可以使用静态成员函数 +说明:非成员函数放在名字空间内可避免污染全局作用域, 也不要用类+静态成员方法来简单管理全局函数。 如果某个全局函数和某个类有紧密联系, 那么可以作为类的静态成员函数。 + +如果你需要定义一些全局函数,给某个cpp文件使用,那么请使用匿名namespace来管理。 +```cpp +namespace mynamespace { +int Add(int a, int b); +} + +class File { + public: + static File CreateTempFile(const std::string& fileName); +}; +``` + +## 全局常量和静态成员常量 + +### 建议6.3.1 优先使用命名空间来管理全局常量,如果和某个class有直接关系的,可以使用静态成员常量 +说明:全局常量放在命名空间内可避免污染全局作用域, 也不要用类+静态成员常量来简单管理全局常量。 如果某个全局常量和某个类有紧密联系, 那么可以作为类的静态成员常量。 + +如果你需要定义一些全局常量,只给某个cpp文件使用,那么请使用匿名namespace来管理。 +```cpp +namespace mynamespace { +const int kMaxSize = 100; +} + +class File { + public: + static const std::string kName; +}; +``` + +## 全局变量 + +### 建议6.4.1 尽量避免使用全局变量,考虑使用单例模式 +说明:全局变量是可以修改和读取的,那么这样会导致业务代码和这个全局变量产生数据耦合。 +```cpp +int counter = 0; + +// a.cpp +counter++; + +// b.cpp +counter++; + +// c.cpp +cout << counter << endl; +``` + +使用单实例模式 +```cpp +class Counter { + public: + static Counter& GetInstance() { + static Counter counter; + return counter; + } // 单实例实现简单举例 + + void Increase() { + value++; + } + + void Print() const { + std::cout << value << std::endl; + } + + private: + Counter() : value(0) {} + + private: + int value; +}; + +// a.cpp +Counter::GetInstance().Increase(); + +// b.cpp +Counter::GetInstance().Increase(); + +// c.cpp +Counter::GetInstance().Print(); +``` + +实现单例模式以后,实现了全局唯一一个实例,和全局变量同样的效果,并且单实例提供了更好的封装性。 + +例外:有的时候全局变量的作用域仅仅是模块内部,这样进程空间里面就会有多个全局变量实例,每个模块持有一份,这种场景下是无法使用单例模式解决的。 + +# 7 类 + +如果仅有数据成员,使用结构体,其他使用类 + +## 构造,拷贝构造,赋值和析构函数 +构造,拷贝,移动和析构函数提供了对象的生命周期管理方法: +- 构造函数(constructor): `X()` +- 拷贝构造函数(copy constructor):`X(const X&)` +- 拷贝赋值操作符(copy assignment):`operator=(const X&)` +- 移动构造函数(move constructor):`X(X&&)` *C++11以后提供* +- 移动赋值操作符(move assignment):`operator=(X&&)` *C++11以后提供* +- 析构函数(destructor):`~X()` + +### 规则7.1.1 类的成员变量必须显式初始化 +说明:如果类有成员变量,没有定义构造函数,又没有定义默认构造函数,编译器将自动生成一个构造函数,但编译器生成的构造函数并不会对成员变量进行初始化,对象状态处于一种不确定性。 + +例外: +- 如果类的成员变量具有默认构造函数,那么可以不需要显式初始化。 + +示例:如下代码没有构造函数,私有数据成员无法初始化: +```cpp +class Message { + public: + void ProcessOutMsg() { + //… + } + private: + unsigned int msgID; + unsigned int msgLength; + unsigned char* msgBuffer; + std::string someIdentifier; +}; + +Message message; // message成员变量没有初始化 +message.ProcessOutMsg(); // 后续使用存在隐患 + +// 因此,有必要定义默认构造函数,如下: +class Message { + public: + Message() : msgID(0), msgLength(0) { + } + + void ProcessOutMsg() { + // … + } + + private: + unsigned int msgID; + unsigned int msgLength; + unsigned char* msgBuffer; + std::string someIdentifier; //具有默认构造函数,不需要显式初始化 +}; +``` + +### 建议7.1.1 成员变量优先使用声明时初始化(C++11)和构造函数初始化列表初始化 +说明:C++11的声明时初始化可以一目了然的看出成员初始值,应当优先使用。如果成员初始化值和构造函数相关,或者不支持C++11,则应当优先使用构造函数初始化列表来初始化成员。相比起在构造函数体中对成员赋值,初始化列表的代码更简洁,执行性能更好,而且可以对const成员和引用成员初始化。 + +```cpp +class Message { + public: + Message() : msgLength(0) { // Good,优先使用初始化列表 + msgBuffer = NULL; // Bad,不推荐在构造函数中赋值 + } + + private: + unsigned int msgID{0}; // Good,C++11中使用 + unsigned int msgLength; + unsigned char* msgBuffer; +}; +``` + +### 规则7.1.2 为避免隐式转换,将单参数构造函数声明为explicit +说明:单参数构造函数如果没有用explicit声明,则会成为隐式转换函数。 +示例: + +```cpp +class Foo { + public: + explicit Foo(const string& name): name(name) { + } + private: + string name; +}; + + +void ProcessFoo(const Foo& foo){} + +int main(void) { + std::string test = "test"; + ProcessFoo(test); // 编译不通过 + return 0; +} +``` + +上面的代码编译不通过,因为`ProcessFoo`需要的参数是Foo类型,传入的string类型不匹配。 + +如果将Foo构造函数的explicit关键字移除,那么调用`ProcessFoo`传入的string就会触发隐式转换,生成一个临时的Foo对象。往往这种隐式转换是让人迷惑的,并且容易隐藏Bug,得到了一个不期望的类型转换。所以对于单参数的构造函数是要求explicit声明。 + +### 规则7.1.3 如果不需要拷贝构造函数、赋值操作符 / 移动构造函数、赋值操作符,请明确禁止 +说明:如果用户不定义,编译器默认会生成拷贝构造函数和拷贝赋值操作符, 移动构造和移动赋值操作符(移动语义的函数C++11以后才有)。 +如果我们不要使用拷贝构造函数,或者赋值操作符,请明确拒绝: + +1.将拷贝构造函数或者赋值操作符设置为private,并且不实现: + +```cpp +class Foo { + private: + Foo(const Foo&); + Foo& operator=(const Foo&); +}; +``` +2.使用C++11提供的delete: + +```cpp +// 同时禁止, 使用C++11的delete +class Foo { + public: + Foo(Foo&&) = delete; + Foo& operator=(Foo&&) = delete; +}; +``` +3.静态方法类,禁用构造函数,防止创建实例 + +```cpp +class Helper { + public: + static bool DoSomething(); + + private: + Helper(); +}; +``` +4.单例类,禁用构造函数,拷贝构造函数,防止创建实例 + +```cpp +class Foo { + private: + static Foo *instance; + Foo() {} + Foo(const Foo &a); + Foo& operator=(const Foo &a); + public: + static Foo &Instance() { + if (!instance) { + instance = new Foo(); + } + return *instance; + } +}; +``` + +5.析构函数通过裸指针释放资源的,禁用拷贝构造、拷贝赋值,防止重复释放 + +```cpp +class Foo { + private: + FILE *fp; + Foo(const Foo &a); + Foo& operator=(const Foo &a); + public: + Foo() : fp(nullptr) {} + ~Foo() { + if (fp != nullptr) { + fclose(fp); + fp = nullptr; + } + } +}; + +Foo* Foo::instance = nullptr; +``` + +### 规则7.1.4 拷贝构造和拷贝赋值操作符应该是成对出现或者禁止 +拷贝构造函数和拷贝赋值操作符都是具有拷贝语义的,应该同时出现或者禁止。 + +```cpp +// 同时出现 +class Foo { + public: + ... + Foo(const Foo&); + Foo& operator=(const Foo&); + ... +}; + +// 同时default, C++11支持 +class Foo { + public: + Foo(const Foo&) = default; + Foo& operator=(const Foo&) = default; +}; + +// 同时禁止, C++11可以使用delete +class Foo { + private: + Foo(const Foo&); + Foo& operator=(const Foo&); +}; +``` + +### 规则7.1.5 移动构造和移动赋值操作符应该是成对出现或者禁止 +在C++11中增加了move操作,如果需要某个类支持移动操作,那么需要实现移动构造和移动赋值操作符。 + +移动构造函数和移动赋值操作符都是具有移动语义的,应该同时出现或者禁止。 +```cpp +// 同时出现 +class Foo { + public: + ... + Foo(Foo&&); + Foo& operator=(Foo&&); + ... +}; + +// 同时default, C++11支持 +class Foo { + public: + Foo(Foo&&) = default; + Foo& operator=(Foo&&) = default; +}; + +// 同时禁止, 使用C++11的delete +class Foo { + public: + Foo(Foo&&) = delete; + Foo& operator=(Foo&&) = delete; +}; +``` + +### 规则7.1.6 禁止在构造函数和析构函数中调用虚函数 +说明:在构造函数和析构函数中调用当前对象的虚函数,会导致未实现多态的行为。 +在C++中,一个基类一次只构造一个完整的对象。 + +示例:类Base是基类,Sub是派生类 +```cpp +class Base { + public: + Base(); + virtual void Log() = 0; // 不同的派生类调用不同的日志文件 +}; + +Base::Base() { // 基类构造函数 + Log(); // 调用虚函数Log +} + +class Sub : public Base { + public: + virtual void Log(); +}; +``` + +当执行如下语句: +`Sub sub;` +会先执行Sub的构造函数,但首先调用Base的构造函数,由于Base的构造函数调用虚函数Log,此时Log还是基类的版本,只有基类构造完成后,才会完成派生类的构造,从而导致未实现多态的行为。 +同样的道理也适用于析构函数。 + +### 建议7.1.2 类定义中的函数不要添加inline关键字 +说明:类定义中的函数默认是inline的。 + + +## 继承 + +### 规则7.2.1 基类的析构函数应该声明为virtual +说明:只有基类析构函数是virtual,通过多态调用的时候才能保证派生类的析构函数被调用。 + +示例:基类的析构函数没有声明为virtual导致了内存泄漏。 +```cpp +class Base { + public: + virtual std::string getVersion() = 0; + + ~Base() { + std::cout << "~Base" << std::endl; + } +}; +``` + +```cpp +class Sub : public Base { + public: + Sub() : numbers(nullptr) { + } + + ~Sub() { + delete[] numbers; + std::cout << "~Sub" << std::endl; + } + + int Init() { + const size_t numberCount = 100; + numbers = new (std::nothrow) int[numberCount]; + if (numbers == nullptr) { + return -1; + } + + ... + } + + std::string getVersion() { + return std::string("hello!"); + } +private: + int* numbers; +}; +``` + +```cpp +int main(int argc, char* args[]) { + Base* b = new Sub(); + + delete b; + return 0; +} +``` +由于基类Base的析构函数没有声明为virtual,当对象被销毁时,只会调用基类的析构函数,不会调用派生类Sub的析构函数,导致内存泄漏。 + + +### 规则7.2.2 禁止虚函数使用缺省参数值 +说明:在C++中,虚函数是动态绑定的,但函数的缺省参数却是在编译时就静态绑定的。这意味着你最终执行的函数是一个定义在派生类,但使用了基类中的缺省参数值的虚函数。为了避免虚函数重载时,因参数声明不一致给使用者带来的困惑和由此导致的问题,规定所有虚函数均不允许声明缺省参数值。 +示例:虚函数display缺省参数值text是由编译时刻决定的,而非运行时刻,没有达到多态的目的: +```cpp +class Base { + public: + virtual void Display(const std::string& text = "Base!") { + std::cout << text << std::endl; + } + + virtual ~Base(){} +}; + +class Sub : public Base { + public: + virtual void Display(const std::string& text = "Sub!") { + std::cout << text << std::endl; + } + + virtual ~Sub(){} +}; + +int main() { + Base* base = new Sub(); + Sub* sub = new Sub(); + + ... + + base->Display(); // 程序输出结果: Base! 而期望输出:Sub! + sub->Display(); // 程序输出结果: Sub! + + delete base; + delete sub; + return 0; +}; +``` + +### 规则7.2.3 禁止重新定义继承而来的非虚函数 +说明:因为非虚函数无法实现动态绑定,只有虚函数才能实现动态绑定:只要操作基类的指针,即可获得正确的结果。 + +示例: +```cpp +class Base { + public: + void Fun(); +}; + +class Sub : public Base { + public: + void Fun(); +}; + +Sub* sub = new Sub(); +Base* base = sub; + +sub->Fun(); // 调用子类的Fun +base->Fun(); // 调用父类的Fun +//... + +``` + +## 多重继承 +在实际开发过程中使用多重继承的场景是比较少的,因为多重继承使用过程中有下面的典型问题: +1. 菱形继承所带来的数据重复,以及名字二义性。因此,C++引入了virtual继承来解决这类问题; +2. 即便不是菱形继承,多个父类之间的名字也可能存在冲突,从而导致的二义性; +3. 如果子类需要扩展或改写多个父类的方法时,造成子类的职责不明,语义混乱; +4. 相对于委托,继承是一种白盒复用,即子类可以访问父类的protected成员, 这会导致更强的耦合。而多重继承,由于耦合了多个父类,相对于单根继承,这会产生更强的耦合关系。 + +多重继承具有下面的优点: +多重继承提供了一种更简单的组合来实现多种接口或者类的组装与复用。 + +所以,对于多重继承的只有下面几种情况下面才允许使用多重继承。 + +### 建议7.3.1 使用多重继承来实现接口分离与多角色组合 +如果某个类需要实现多重接口,可以通过多重继承把多个分离的接口组合起来,类似 scala 语言的 traits 混入。 + +```cpp +class Role1 {}; +class Role2 {}; +class Role3 {}; + +class Object1 : public Role1, public Role2 { + // ... +}; + +class Object2 : public Role2, public Role3 { + // ... +}; + +``` + +在C++标准库中也有类似的实现样例: +```cpp +class basic_istream {}; +class basic_ostream {}; + +class basic_iostream : public basic_istream, public basic_ostream { + +}; +``` + +## 重载 + +重载操作符要有充分理由,而且不要改变操作符原有语义,例如不要使用 ‘+’ 操作符来做减运算。 +操作符重载令代码更加直观,但也有一些不足: +- 混淆直觉,误以为该操作和内建类型一样是高性能的,忽略了性能降低的可能; +- 问题定位时不够直观,按函数名查找比按操作符显然更方便。 +- 重载操作符如果行为定义不直观(例如将‘+’ 操作符来做减运算),会让代码产生混淆。 +- 赋值操作符的重载引入的隐式转换会隐藏很深的bug。可以定义类似Equals()、CopyFrom()等函数来替代=,==操作符。 + + + +# 8 函数 +## 函数设计 +### 建议8.1.1 避免函数过长,函数不超过50行(非空非注释) +函数应该可以一屏显示完 (50行以内),只做一件事情,而且把它做好。 + +过长的函数往往意味着函数功能不单一,过于复杂,或过分呈现细节,未进行进一步抽象。 + +例外:某些实现算法的函数,由于算法的聚合性与功能的全面性,可能会超过50行。 + +即使一个长函数现在工作的非常好, 一旦有人对其修改, 有可能出现新的问题, 甚至导致难以发现的bug。 +建议将其拆分为更加简短并易于管理的若干函数,以便于他人阅读和修改代码。 + +## 内联函数 + +### 建议8.2.1 内联函数不超过10行(非空非注释) +**说明**:内联函数具有一般函数的特性,它与一般函数不同之处只在于函数调用的处理。一般函数进行调用时,要将程序执行权转到被调用函数中,然后再返回到调用它的函数中;而内联函数在调用时,是将调用表达式用内联函数体来替换。 + +内联函数只适合于只有 1~10 行的小函数。对一个含有许多语句的大函数,函数调用和返回的开销相对来说微不足道,也没有必要用内联函数实现,一般的编译器会放弃内联方式,而采用普通的方式调用函数。 + +如果内联函数包含复杂的控制结构,如循环、分支(switch)、try-catch 等语句,一般编译器将该函数视同普通函数。 +**虚函数、递归函数不能被用来做内联函数**。 + +## 函数参数 + +### 建议8.3.1 函数参数使用引用取代指针 + +**说明**:引用比指针更安全,因为它一定非空,且一定不会再指向其他目标;引用不需要检查非法的NULL指针。 + +选择 const 避免参数被修改,让代码阅读者清晰地知道该参数不被修改,可大大增强代码可读性。 + +### 建议8.3.2 使用强类型参数,避免使用void* +尽管不同的语言对待强类型和弱类型有自己的观点,但是一般认为c/c++是强类型语言,既然我们使用的语言是强类型的,就应该保持这样的风格。 +好处是尽量让编译器在编译阶段就检查出类型不匹配的问题。 + +使用强类型便于编译器帮我们发现错误,如下代码中注意函数 FooListAddNode 的使用: +```cpp +struct FooNode { + struct List link; + int foo; +}; + +struct BarNode { + struct List link; + int bar; +} + +void FooListAddNode(void *node) { // Bad: 这里用 void * 类型传递参数 + FooNode *foo = (FooNode *)node; + ListAppend(&fooList, &foo->link); +} + +void MakeTheList() { + FooNode *foo = nullptr; + BarNode *bar = nullptr; + ... + + FooListAddNode(bar); // Wrong: 这里本意是想传递参数 foo,但错传了 bar,却没有报错 +} +``` + +1. 可以使用模板函数来实现参数类型的变化。 +2. 可以使用基类指针来实现多态。 + +### 建议8.3.3 函数的参数个数不超过5个 +函数的参数过多,会使得该函数易于受外部变化的影响,从而影响维护工作。函数的参数过多同时也会增大测试的工作量。 + +如果超过可以考虑: +- 看能否拆分函数 +- 看能否将相关参数合在一起,定义结构体 + +# 9 C++其他特性 + +## 常量与初始化 + +不变的值更易于理解、跟踪和分析,所以应该尽可能地使用常量代替变量,定义值的时候,应该把const作为默认的选项。 + +### 建议9.1.1 不允许使用宏来表示常量 + +**说明**:宏是简单的文本替换,在预处理阶段时完成,运行报错时直接报相应的值;跟踪调试时也是显示值,而不是宏名;宏没有类型检查,不安全;宏没有作用域。 + +```cpp +#define MAX_MSISDN_LEN 20 // 不好 + +// C++请使用const常量 +const int kMaxMsisdnLen = 20; // 好 + +// 对于C++11以上版本,可以使用constexpr +constexpr int kMaxMsisdnLen = 20; +``` + +### 建议9.1.2 一组相关的整型常量应定义为枚举 + +**说明**:枚举比`#define`或`const int`更安全。编译器会检查参数值是否位于枚举取值范围内,避免错误发生。 + +```cpp +// 好的例子: +enum Week { + kSunday, + kMonday, + kTuesday, + kWednesday, + kThursday, + kFriday, + kSaturday +}; + +enum Color { + kRed, + kBlack, + kBlue +}; + +void ColorizeCalendar(Week today, Color color); + +ColorizeCalendar(kBlue, kSunday); // 编译报错,参数类型错误 + +// 不好的例子: +const int kSunday = 0; +const int kMonday = 1; + +const int kRed = 0; +const int kBlack = 1; + +bool ColorizeCalendar(int today, int color); +ColorizeCalendar(kBlue, kSunday); // 不会报错 +``` + +当枚举值需要对应到具体数值时,须在声明时显式赋值。否则不需要显式赋值,以避免重复赋值,降低维护(增加、删除成员)工作量。 + +```cpp +// 好的例子:S协议里定义的设备ID值,用于标识设备类型 +enum DeviceType { + kUnknown = -1, + kDsmp = 0, + kIsmg = 1, + kWapportal = 2 +}; +``` + + + +### 建议9.1.3 不允许使用魔鬼数字 +所谓魔鬼数字即看不懂、难以理解的数字。 + +魔鬼数字并非一个非黑即白的概念,看不懂也有程度,需要自行判断。 +例如数字 12,在不同的上下文中情况是不一样的: +type = 12; 就看不懂,但 `month = year * 12`; 就能看懂。 +数字 0 有时候也是魔鬼数字,比如 `status = 0`; 并不能表达是什么状态。 + +解决途径: +对于局部使用的数字,可以增加注释说明 +对于多处使用的数字,必须定义 const 常量,并通过符号命名自注释。 + +禁止出现下列情况: +没有通过符号来解释数字含义,如` const int kZero = 0` +符号命名限制了其取值,如 `const int kXxTimerInterval = 300`,直接使用`kXxTimerInterval `来表示该常量是定时器的时间间隔。 + +### 规则9.1.1 常量应该保证单一职责 + +**说明**:一个常量只用来表示一个特定功能,即一个常量不能有多种用途。 + +```cpp +// 好的例子:协议A和协议B,手机号(MSISDN)的长度都是20。 +const unsigned int kAMaxMsisdnLen = 20; +const unsigned int kBMaxMsisdnLen = 20; + +// 或者使用不同的名字空间: +namespace namespace1 { +const unsigned int kMaxMsisdnLen = 20; +} + +namespace namespace2 { +const unsigned int kMaxMsisdnLen = 20; +} +``` + +### 建议9.1.4 禁止用memcpy_s、memset_s初始化非POD对象 + +**说明**:`POD`全称是`Plain Old Data`,是C++ 98标准(ISO/IEC 14882, first edition, 1998-09-01)中引入的一个概念,`POD`类型主要包括`int`, `char`, `float`,`double`,`enumeration`,`void`,指针等原始类型以及聚合类型,不能使用封装和面向对象特性(如用户定义的构造/赋值/析构函数、基类、虚函数等)。 + +由于非POD类型比如非聚合类型的class对象,可能存在虚函数,内存布局不确定,跟编译器有关,滥用内存拷贝可能会导致严重的问题。 + +即使对聚合类型的class,使用直接的内存拷贝和比较,破坏了信息隐蔽和数据保护的作用,也不提倡`memcpy_s`、`memset_s`操作。 + +对于POD类型的详细说明请参见附录。 + + +## 表达式 + +### 规则9.2.1 switch语句要有default分支 +大部分情况下,switch语句中要有default分支,保证在遗漏case标签处理时能够有一个缺省的处理行为。 + +特例: +如果switch条件变量是枚举类型,并且 case 分支覆盖了所有取值,则加上default分支处理有些多余。 +现代编译器都具备检查是否在switch语句中遗漏了某些枚举值的case分支的能力,会有相应的warning提示。 + +```cpp +enum Color { + kRed = 0, + kBlue +}; + +// 因为switch条件变量是枚举值,这里可以不用加default处理分支 +switch (color) { + case kRed: + DoRedThing(); + break; + case kBlue: + DoBlueThing(); + ... + break; +} +``` + +### 建议9.2.1 表达式的比较,应当遵循左侧倾向于变化、右侧倾向于不变的原则 +当变量与常量比较时,如果常量放左边,如 if (MAX == v) 不符合阅读习惯,而 if (MAX > v) 更是难于理解。 +应当按人的正常阅读、表达习惯,将常量放右边。写成如下方式: +```cpp +if (value == MAX) { + +} + +if (value < MAX) { + +} +``` +也有特殊情况,如:`if (MIN < value && value < MAX)` 用来描述区间时,前半段是常量在左的。 + +不用担心将 '==' 误写成 '=',因为` if (value = MAX)` 会有编译告警,其他静态检查工具也会报错。让工具去解决笔误问题,代码要符合可读性第一。 + + +## 类型转换 + +避免使用类型分支来定制行为:类型分支来定制行为容易出错,是企图用C++编写C代码的明显标志。这是一种很不灵活的技术,要添加新类型时,如果忘记修改所有分支,编译器也不会告知。使用模板和虚函数,让类型自己而不是调用它们的代码来决定行为。 + +建议避免类型转换,我们在代码的类型设计上应该考虑到每种数据的数据类型是什么,而不是应该过度使用类型转换来解决问题。在设计某个基本类型的时候,请考虑: +- 是无符号还是有符号的 +- 是适合float还是double +- 是使用int8,int16,int32还是int64,确定整形的长度 + +但是我们无法禁止使用类型转换,因为C++语言是一门面向机器编程的语言,涉及到指针地址,并且我们会与各种第三方或者底层API交互,他们的类型设计不一定是合理的,在这个适配的过程中很容易出现类型转换。 + +例外:在调用某个函数的时候,如果我们不想处理函数结果,首先要考虑这个是否是你的最好的选择。如果确实不想处理函数的返回值,那么可以使用(void)转换来解决。 + +### 规则9.3.1 如果确定要使用类型转换,请使用有C++提供的类型转换,而不是C风格的类型转换 + +**说明**: + +C++提供的类型转换操作比C风格更有针对性,更易读,也更加安全,C++提供的转换有: +- 类型转换: +1. `dynamic_cast`:主要用于继承体系下行转换,`dynamic_cast`具有类型检查的功能,请做好基类和派生类的设计,避免使用dynamic_cast来进行转换。 +2. `static_cast`:和C风格转换相似可做值的强制转换,或上行转换(把派生类的指针或引用转换成基类的指针或引用)。该转换经常用于消除多重继承带来的类型歧义,是相对安全的。如果是纯粹的算数转换,那么请使用后面的大括号转换方式。 +3. `reinterpret_cast`:用于转换不相关的类型。`reinterpret_cast`强制编译器将某个类型对象的内存重新解释成另一种类型,这是一种不安全的转换,建议尽可能少用`reinterpret_cast`。 +4. `const_cast`:用于移除对象的`const`属性,使对象变得可修改,这样会破坏数据的不变性,建议尽可能少用。 + +- 算数转换: (C++11开始支持) + 对于那种算数转换,并且类型信息没有丢失的,比如float到double, int32到int64的转换,推荐使用大括号的初始方式。 +```cpp + double d{ someFloat }; + int64_t i{ someInt32 }; +``` + +### 建议9.3.1 避免使用`dynamic_cast` +1. `dynamic_cast`依赖于C++的RTTI, 让程序员在运行时识别C++类对象的类型。 +2. `dynamic_cast`的出现一般说明我们的基类和派生类设计出现了问题,派生类破坏了基类的契约,不得不通过`dynamic_cast`转换到子类进行特殊处理,这个时候更希望来改善类的设计,而不是通过`dynamic_cast`来解决问题。 + +### 建议9.3.2 避免使用`reinterpret_cast` + +**说明**:`reinterpret_cast`用于转换不相关类型。尝试用`reinterpret_cast`将一种类型强制转换另一种类型,这破坏了类型的安全性与可靠性,是一种不安全的转换。不同类型之间尽量避免转换。 + +### 建议9.3.3 避免使用`const_cast` + +**说明**:`const_cast`用于移除对象的`const`和`volatile`性质。 + +使用const_cast转换后的指针或者引用来修改const对象,行为是未定义的。 + +```cpp +// 不好的例子 +const int i = 1024; +int* p = const_cast(&i); +*p = 2048; // 未定义行为 +``` + +```cpp +// 不好的例子 +class Foo { + public: + Foo() : i(3) {} + + void Fun(int v) { + i = v; + } + + private: + int i; +}; + +int main(void) { + const Foo f; + Foo* p = const_cast(&f); + p->Fun(8); // 未定义行为 +} + +``` + + +## 资源分配和释放 + +### 规则9.4.1 单个对象释放使用delete,数组对象释放使用delete [] +说明:单个对象删除使用delete, 数组对象删除使用delete [],原因: + +- 调用new所包含的动作:从系统中申请一块内存,并调用此类型的构造函数。 +- 调用new[n]所包含的动作:申请可容纳n个对象的内存,并且对每一个对象调用其构造函数。 +- 调用delete所包含的动作:先调用相应的析构函数,再将内存归还系统。 +- 调用delete[]所包含的动作:对每一个对象调用析构函数,再释放所有内存 + +如果new和delete的格式不匹配,结果是未知的。对于非class类型, new和delete不会调用构造与析构函数。 + +错误写法: +```cpp +const int KMaxArraySize = 100; +int* numberArray = new int[KMaxArraySize]; +... +delete numberArray; +numberArray = NULL; +``` + +正确写法: +```cpp +const int KMaxArraySize = 100; +int* numberArray = new int[KMaxArraySize]; +... +delete[] numberArray; +numberArray = NULL; +``` + +## 标准库 + +STL标准模板库在不同模块使用程度不同,这里列出一些基本规则和建议。 + +### 规则9.5.1 不要保存std::string的c_str()返回的指针 + +说明:在C++标准中并未规定string::c_str()指针持久有效,因此特定STL实现完全可以在调用string::c_str()时返回一个临时存储区并很快释放。所以为了保证程序的可移植性,不要保存string::c_str()的结果,而是在每次需要时直接调用。 + +示例: + +```cpp +void Fun1() { + std::string name = "demo"; + const char* text = name.c_str(); // 表达式结束以后,name的生命周期还在,指针有效 + + // 如果中间调用了string的非const成员函数,导致string被修改,比如operator[], begin()等 + // 可能会导致text的内容不可用,或者不是原来的字符串 + name = "test"; + name[1] = '2'; + + // 后续使用text指针,其字符串内容不再是"demo" +} + +void Fun2() { + std::string name = "demo"; + std::string test = "test"; + const char* text = (name + test).c_str(); // 表达式结束以后,+号产生的临时对象被销毁,指针无效 + + // 后续使用text指针,其已不再指向合法内存空间 +} +``` +例外:在少数对性能要求非常高的代码中,为了适配已有的只接受const char*类型入参的函数,可以临时保存string::c_str()返回的指针。但是必须严格保证string对象的生命周期长于所保存指针的生命周期,并且保证在所保存指针的生命周期内,string对象不会被修改。 + + +### 建议9.5.1 使用std::string代替char* + +说明:使用string代替`char*`有很多优势,比如: +1. 不用考虑结尾的’\0’; +2. 可以直接使用+, =, ==等运算符以及其它字符串操作函数; +3. 不需要考虑内存分配操作,避免了显式的new/delete,以及由此导致的错误; + +需要注意的是某些stl实现中string是基于写时复制策略的,这会带来2个问题,一是某些版本的写时复制策略没有实现线程安全,在多线程环境下会引起程序崩溃;二是当与动态链接库相互传递基于写时复制策略的string时,由于引用计数在动态链接库被卸载时无法减少可能导致悬挂指针。因此,慎重选择一个可靠的stl实现对于保证程序稳定是很重要的。 + +例外: +当调用系统或者其它第三方库的API时,针对已经定义好的接口,只能使用`char*`。但是在调用接口之前都可以使用string,在调用接口时使用string::c_str()获得字符指针。 +当在栈上分配字符数组当作缓冲区使用时,可以直接定义字符数组,不要使用string,也没有必要使用类似`vector`等容器。 + +### 规则9.5.2 禁止使用auto_ptr +说明:在stl库中的std::auto_ptr具有一个隐式的所有权转移行为,如下代码: +```cpp +auto_ptr p1(new T); +auto_ptr p2 = p1; +``` +当执行完第2行语句后,p1已经不再指向第1行中分配的对象,而是变为NULL。正因为如此,auto_ptr不能被置于各种标准容器中。 +转移所有权的行为通常不是期望的结果。对于必须转移所有权的场景,也不应该使用隐式转移的方式。这往往需要程序员对使用auto_ptr的代码保持额外的谨慎,否则出现对空指针的访问。 +使用auto_ptr常见的有两种场景,一是作为智能指针传递到产生auto_ptr的函数外部,二是使用auto_ptr作为RAII管理类,在超出auto_ptr的生命周期时自动释放资源。 +对于第1种场景,可以使用std::shared_ptr来代替。 +对于第2种场景,可以使用C++11标准中的std::unique_ptr来代替。其中std::unique_ptr是std::auto_ptr的代替品,支持显式的所有权转移。 + +例外: +在C++11标准得到普遍使用之前,在一定需要对所有权进行转移的场景下,可以使用std::auto_ptr,但是建议对std::auto_ptr进行封装,并禁用封装类的拷贝构造函数和赋值运算符,以使该封装类无法用于标准容器。 + + +### 建议9.5.2 使用新的标准头文件 + +说明: +使用C++的标准头文件时,请使用``这样的,而不是``这种的。 + +## const的用法 +在声明的变量或参数前加上关键字 const 用于指明变量值不可被篡改 (如 `const int foo` ). 为类中的函数加上 const 限定符表明该函数不会修改类成员变量的状态 (如 `class Foo { int Bar(char c) const; };`)。 const 变量, 数据成员, 函数和参数为编译时类型检测增加了一层保障, 便于尽早发现错误。因此, 我们强烈建议在任何可能的情况下使用 const。 +有时候,使用C++11的constexpr来定义真正的常量可能更好。 + +### 规则9.6.1 对于指针和引用类型的形参,如果是不需要修改的,请使用const +不变的值更易于理解/跟踪和分析,把const作为默认选项,在编译时会对其进行检查,使代码更牢固/更安全。 +```cpp +class Foo; + +void PrintFoo(const Foo& foo); +``` + +### 规则9.6.2 对于不会修改成员变量的成员函数请使用const修饰 +尽可能将成员函数声明为 const。 访问函数应该总是 const。只要不修改数据成员的成员函数,都声明为const。 + +```cpp +class Foo { + public: + + // ... + + int PrintValue() const { // const修饰成员函数,不会修改成员变量 + std::cout << value << std::endl; + } + + int GetValue() const { // const修饰成员函数,不会修改成员变量 + return value; + } + + private: + int value; +}; +``` + +### 建议9.6.1 初始化后不会再修改的成员变量定义为const + +```cpp +class Foo { + public: + Foo(int length) : dataLength(length) {} + private: + const int dataLength; +}; +``` + +## 模板 + +模板能够实现非常灵活简洁的类型安全的接口,实现类型不同但是行为相同的代码复用。 + +模板编程的缺点: + +1. 模板编程所使用的技巧对于使用c++不是很熟练的人是比较晦涩难懂的。在复杂的地方使用模板的代码让人更不容易读懂,并且debug 和维护起来都很麻烦。 +2. 模板编程经常会导致编译出错的信息非常不友好: 在代码出错的时候, 即使这个接口非常的简单, 模板内部复杂的实现细节也会在出错信息显示. 导致这个编译出错信息看起来非常难以理解。 +3. 模板如果使用不当,会导致运行时代码过度膨胀。 +4. 模板代码难以修改和重构。模板的代码会在很多上下文里面扩展开来, 所以很难确认重构对所有的这些展开的代码有用。 + +所以, 建议__模板编程最好只用在少量的基础组件,基础数据结构上面__。并且使用模板编程的时候尽可能把__复杂度最小化__,尽量__不要让模板对外暴露__。最好只在实现里面使用模板, 然后给用户暴露的接口里面并不使用模板, 这样能提高你的接口的可读性。 并且你应该在这些使用模板的代码上写尽可能详细的注释。 + + +## 宏 +在C++语言中,我们强烈建议尽可能少使用复杂的宏 +- 对于常量定义,请按照前面章节所述,使用const或者枚举; +- 对于宏函数,尽可能简单,并且遵循下面的原则,并且优先使用内联函数,模板函数等进行替换。 + +```cpp +// 不推荐使用宏函数 +#define SQUARE(a, b) ((a) * (b)) + +// 请使用模板函数,内联函数等来替换。 +template T Square(T a, T b) { return a * b; } +``` + +如果需要使用宏,请参考C语言规范的相关章节。 +**例外**:一些通用且成熟的应用,如:对 new, delete 的封装处理,可以保留对宏的使用。 + + +## 其他 + +### 建议9.9.1 输出到文件时,尽量使用'\n'代替std::endl; +说明:std::endl会将缓冲区的内容flush到文件中,可能会影响性能。 + +# 10 现代C++特性 + +随着 ISO 在2011年发布 C++11 语言标准,以及2017年3月发布 C++17 ,现代C++(C++11/14/17等)增加了大量提高编程效率、代码质量的新语言特性和标准库。 +本章节描述了一些可以帮助团队更有效率的使用现代C++,规避语言陷阱的指导意见。 + +## 代码简洁性和安全性提升 +### 建议10.1.1 合理使用`auto` +**理由** + +* `auto`可以避免编写冗长、重复的类型名,也可以保证定义变量时初始化。 +* `auto`类型推导规则复杂,需要仔细理解。 +* 如果能够使代码更清晰,继续使用明确的类型,且只在局部变量使用`auto`。 + +**示例** + +```cpp +// 避免冗长的类型名 +std::map::iterator iter = m.find(val); +auto iter = m.find(val); + +// 避免重复类型名 +class Foo {...}; +Foo* p = new Foo; +auto p = new Foo; + +// 保证初始化 +int x; // 编译正确,没有初始化 +auto x; // 编译失败,必须初始化 +``` + +auto 的类型推导可能导致困惑: + +```cpp +auto a = 3; // int +const auto ca = a; // const int +const auto& ra = a; // const int& +auto aa = ca; // int, 忽略 const 和 reference +auto ila1 = { 10 }; // std::initializer_list +auto ila2{ 10 }; // std::initializer_list + +auto&& ura1 = x; // int& +auto&& ura2 = ca; // const int& +auto&& ura3 = 10; // int&& + +const int b[10]; +auto arr1 = b; // const int* +auto& arr2 = b; // const int(&)[10] +``` + +如果没有注意 `auto` 类型推导时忽略引用,可能引入难以发现的性能问题: + +```cpp +std::vector v; +auto s1 = v[0]; // auto 推导为 std::string,拷贝 v[0] +``` + +如果使用`auto`定义接口,如头文件中的常量,可能因为开发人员修改了值,而导致类型发生变化。 + +在循环中,考虑使用auto &和auto *去遍历复杂对象,以提升性能。 + +```cpp +for (auto &stmt : bb->GetStmtNodes()) { +... +} +``` + +### 规则10.1.1 在重写虚函数时请使用`override`关键字 +**理由** +`override`关键字保证函数是虚函数,且重写了基类的虚函数。如果子类函数与基类函数原型不一致,则产生编译告警。 + +如果修改了基类虚函数原型,但忘记修改子类重写的虚函数,在编译期就可以发现。也可以避免有多个子类时,重写函数的修改遗漏。 + +**示例** + +```cpp +class Base { + public: + virtual void Foo(); + void Bar(); +}; + +class Derived : public Base { + public: + void Foo() const override; // 编译失败: derived::Foo 和 base::Foo 原型不一致,不是重写 + void Foo() override; // 正确: derived::Foo 重写 base::Foo + void Bar() override; // 编译失败: base::Bar 不是虚函数 +}; +``` + +**总结** +1. 基类首次定义虚函数,使用`virtual`关键字 +2. 子类重写基类虚函数,使用`override`关键字 +3. 非虚函数,`virtual`和`override`都不使用 + +### 规则10.1.2 使用`delete`关键字删除函数 +**理由** +相比于将类成员函数声明为`private`但不实现,`delete`关键字更明确,且适用范围更广。 + +**示例** + +```cpp +class Foo { + private: + // 只看头文件不知道拷贝构造是否被删除 + Foo(const Foo&); +}; + +class Foo { + public: + // 明确删除拷贝赋值函数 + Foo& operator=(const Foo&) = delete; +}; +``` + +`delete`关键字还支持删除非成员函数 + +```cpp +template +void Process(T value); + +template<> +void Process(void) = delete; +``` + +### 规则10.1.3 使用`nullptr`,而不是`NULL`或`0` +**理由** +长期以来,C++没有一个代表空指针的关键字,这是一件很尴尬的事: + +```cpp +#define NULL ((void *)0) + +char* str = NULL; // 错误: void* 不能自动转换为 char* + +void(C::*pmf)() = &C::Func; +if (pmf == NULL) {} // 错误: void* 不能自动转换为指向成员函数的指针 +``` + +如果把`NULL`被定义为`0`或`0L`。可以解决上面的问题。 + +或者在需要空指针的地方直接使用`0`。但这引入另一个问题,代码不清晰,特别是使用`auto`自动推导: + +```cpp +auto result = Find(id); +if (result == 0) { // Find() 返回的是 指针 还是 整数? + // do something +} +``` + +`0`字面上是`int`类型(`0L`是`long`),所以`NULL`和`0`都不是指针类型。 +当重载指针和整数类型的函数时,传递`NULL`或`0`都调用到整数类型重载的函数: + +```cpp +void F(int); +void F(int*); + +F(0); // 调用 F(int),而非 F(int*) +F(NULL); // 调用 F(int),而非 F(int*) +``` + +另外,`sizeof(NULL) == sizeof(void*)`并不一定总是成立的,这也是一个潜在的风险。 + +总结: 直接使用`0`或`0L`,代码不清晰,且无法做到类型安全;使用`NULL`无法做到类型安全。这些都是潜在的风险。 + +`nullptr`的优势不仅仅是在字面上代表了空指针,使代码清晰,而且它不再是一个整数类型。 + +`nullptr`是`std::nullptr_t`类型,而`std::nullptr_t`可以隐式的转换为所有的原始指针类型,这使得`nullptr`可以表现成指向任意类型的空指针。 + +```cpp +void F(int); +void F(int*); +F(nullptr); // 调用 F(int*) + +auto result = Find(id); +if (result == nullptr) { // Find() 返回的是 指针 + // do something +} +``` + +### 建议10.1.2 使用`using`而非`typedef` +在`C++11`之前,可以通过`typedef`定义类型的别名。没人愿意多次重复`std::map>`这样的代码。 + +```cpp +typedef std::map> SomeType; +``` + +类型的别名实际是对类型的封装。而通过封装,可以让代码更清晰,同时在很大程度上避免类型变化带来的散弹式修改。 +在`C++11`之后,提供`using`,实现`声明别名(alias declarations)`: + +```cpp +using SomeType = std::map>; +``` + +对比两者的格式: + +```cpp +typedef Type Alias; // Type 在前,还是 Alias 在前 +using Alias = Type; // 符合'赋值'的用法,容易理解,不易出错 +``` + +如果觉得这点还不足以切换到`using`,我们接着看看`模板别名(alias template)`: + +```cpp +// 定义模板的别名,一行代码 +template +using MyAllocatorVector = std::vector>; + +MyAllocatorVector data; // 使用 using 定义的别名 + +template +class MyClass { + private: + MyAllocatorVector data_; // 模板类中使用 using 定义的别名 +}; +``` + +而`typedef`不支持带模板参数的别名,只能"曲线救国": + +```cpp +// 通过模板包装 typedef,需要实现一个模板类 +template +struct MyAllocatorVector { + typedef std::vector> type; +}; + +MyAllocatorVector::type data; // 使用 typedef 定义的别名,多写 ::type + +template +class MyClass { + private: + typename MyAllocatorVector::type data_; // 模板类中使用,除了 ::type,还需要加上 typename +}; +``` + +### 规则10.1.4 禁止使用std::move操作const对象 +从字面上看,`std::move`的意思是要移动一个对象。而const对象是不允许修改的,自然也无法移动。因此用`std::move`操作const对象会给代码阅读者带来困惑。 +在实际功能上,`std::move`会把对象转换成右值引用类型;对于const对象,会将其转换成const的右值引用。由于极少有类型会定义以const右值引用为参数的移动构造函数和移动赋值操作符,因此代码实际功能往往退化成了对象拷贝而不是对象移动,带来了性能上的损失。 + +**错误示例:** +```cpp +std::string gString; +std::vector gStringList; + +void func() { + const std::string myString = "String content"; + gString = std::move(myString); // bad:并没有移动myString,而是进行了复制 + const std::string anotherString = "Another string content"; + gStringList.push_back(std::move(anotherString)); // bad:并没有移动anotherString,而是进行了复制 +} +``` + +## 智能指针 +### 建议10.2.1 优先使用智能指针而不是原始指针管理资源 +**理由** +避免资源泄露。 + +**示例** + +```cpp +void Use(int i) { + auto p = new int {7}; // 不好: 通过 new 初始化局部指针 + auto q = std::make_unique(9); // 好: 保证释放内存 + if (i > 0) { + return; // 可能 return,导致内存泄露 + } + delete p; // 太晚了 +} +``` + +**例外** +在性能敏感、兼容性等场景可以使用原始指针。 + +### 规则10.2.1 优先使用`unique_ptr`而不是`shared_ptr` +**理由** +1. `shared_ptr`引用计数的原子操作存在可测量的开销,大量使用`shared_ptr`影响性能。 +2. 共享所有权在某些情况(如循环依赖)可能导致对象永远得不到释放。 +3. 相比于谨慎设计所有权,共享所有权是一种诱人的替代方案,但它可能使系统变得混乱。 + +### 规则10.2.2 使用`std::make_unique`而不是`new`创建`unique_ptr` +**理由** +1. `make_unique`提供了更简洁的创建方式 +2. 保证了复杂表达式的异常安全 + +**示例** + +```cpp +// 不好:两次出现 MyClass,重复导致不一致风险 +std::unique_ptr ptr(new MyClass(0, 1)); +// 好:只出现一次 MyClass,不存在不一致的可能 +auto ptr = std::make_unique(0, 1); +``` + +重复出现类型可能导致非常严重的问题,且很难发现: + +```cpp +// 编译正确,但new和delete不配套 +std::unique_ptr ptr(new uint8_t[10]); +std::unique_ptr ptr(new uint8_t); +// 非异常安全: 编译器可能按如下顺序计算参数: +// 1. 分配 Foo 的内存, +// 2. 构造 Foo, +// 3. 调用 Bar, +// 4. 构造 unique_ptr. +// 如果 Bar 抛出异常, Foo 不会被销毁,产生内存泄露。 +F(unique_ptr(new Foo()), Bar()); + +// 异常安全: 调用函数不会被打断. +F(make_unique(), Bar()); +``` + +**例外** +`std::make_unique`不支持自定义`deleter`。 +在需要自定义`deleter`的场景,建议在自己的命名空间实现定制版本的`make_unique`。 +使用`new`创建自定义`deleter`的`unique_ptr`是最后的选择。 + +### 规则10.2.3 使用`std::make_shared`而不是`new`创建`shared_ptr` +**理由** +使用`std::make_shared`除了类似`std::make_unique`一致性等原因外,还有性能的因素。 +`std::shared_ptr`管理两个实体: +* 控制块(存储引用计数,`deleter`等) +* 管理对象 + +`std::make_shared`创建`std::shared_ptr`,会一次性在堆上分配足够容纳控制块和管理对象的内存。而使用`std::shared_ptr(new MyClass)`创建`std::shared_ptr`,除了`new MyClass`会触发一次堆分配外,`std::shard_ptr`的构造函数还会触发第二次堆分配,产生额外的开销。 + +**例外** +类似`std::make_unique`,`std::make_shared`不支持定制`deleter` + +## Lambda +### 建议10.3.1 当函数不能工作时选择使用`lambda`(捕获局部变量,或编写局部函数) +**理由** +函数无法捕获局部变量或在局部范围内声明;如果需要这些东西,尽可能选择`lambda`,而不是手写的`functor`。 +另一方面,`lambda`和`functor`不会重载;如果需要重载,则使用函数。 +如果`lambda`和函数都可以的场景,则优先使用函数;尽可能使用最简单的工具。 + +**示例** + +```cpp +// 编写一个只接受 int 或 string 的函数 +// -- 重载是自然的选择 +void F(int); +void F(const string&); + +// 需要捕获局部状态,或出现在语句或表达式范围 +// -- lambda 是自然的选择 +vector v = LotsOfWork(); +for (int taskNum = 0; taskNum < max; ++taskNum) { + pool.Run([=, &v] {...}); +} +pool.Join(); +``` + +### 规则10.3.1 非局部范围使用`lambdas`,避免使用按引用捕获 +**理由** +非局部范围使用`lambdas`包括返回值,存储在堆上,或者传递给其它线程。局部的指针和引用不应该在它们的范围外存在。`lambdas`按引用捕获就是把局部对象的引用存储起来。如果这会导致超过局部变量生命周期的引用存在,则不应该按引用捕获。 + +**示例** + +```cpp +// 不好 +void Foo() { + int local = 42; + // 按引用捕获 local. + // 当函数返回后,local 不再存在, + // 因此 Process() 的行为未定义! + threadPool.QueueWork([&]{ Process(local); }); +} + +// 好 +void Foo() { + int local = 42; + // 按值捕获 local。 + // 因为拷贝,Process() 调用过程中,local 总是有效的 + threadPool.QueueWork([=]{ Process(local); }); +} +``` + +### 建议10.3.2 如果捕获`this`,则显式捕获所有变量 +**理由** +在成员函数中的`[=]`看起来是按值捕获。但因为是隐式的按值获取了`this`指针,并能够操作所有成员变量,数据成员实际是按引用捕获的,一般情况下建议避免。如果的确需要这样做,明确写出对`this`的捕获。 + +**示例** + +```cpp +class MyClass { + public: + void Foo() { + int i = 0; + + auto Lambda = [=]() { Use(i, data_); }; // 不好: 看起来像是拷贝/按值捕获,成员变量实际上是按引用捕获 + + data_ = 42; + Lambda(); // 调用 use(42); + data_ = 43; + Lambda(); // 调用 use(43); + + auto Lambda2 = [i, this]() { Use(i, data_); }; // 好,显式指定按值捕获,最明确,最少的混淆 + } + + private: + int data_ = 0; +}; +``` + +### 建议10.3.3 避免使用默认捕获模式 +**理由** +lambda表达式提供了两种默认捕获模式:按引用(&)和按值(=)。 +默认按引用捕获会隐式的捕获所有局部变量的引用,容易导致访问悬空引用。相比之下,显式的写出需要捕获的变量可以更容易的检查对象生命周期,减小犯错可能。 +默认按值捕获会隐式的捕获this指针,且难以看出lambda函数所依赖的变量是哪些。如果存在静态变量,还会让阅读者误以为lambda拷贝了一份静态变量。 +因此,通常应当明确写出lambda需要捕获的变量,而不是使用默认捕获模式。 + +**错误示例** +```cpp +auto func() { + int addend = 5; + static int baseValue = 3; + + return [=]() { // 实际上只复制了addend + ++baseValue; // 修改会影响静态变量的值 + return baseValue + addend; + }; +} +``` + +**正确示例** +```cpp +auto func() { + int addend = 5; + static int baseValue = 3; + + return [addend, baseValue = baseValue]() mutable { // 使用C++14的捕获初始化拷贝一份变量 + ++baseValue; // 修改自己的拷贝,不会影响静态变量的值 + return baseValue + addend; + }; +} +``` + +参考:《Effective Modern C++》:Item 31: Avoid default capture modes. + +## 接口 +### 建议10.4.1 不涉及所有权的场景,使用`T*`或`T&`作为参数,而不是智能指针 +**理由** +1. 只在需要明确所有权机制时,才通过智能指针转移或共享所有权. +2. 通过智能指针传递,限制了函数调用者必须使用智能指针(如调用者希望传递`this`)。 +3. 传递共享所有权的智能指针存在运行时的开销。 + +**示例** + +```cpp +// 接受任何 int* +void F(int*); + +// 只能接受希望转移所有权的 int +void G(unique_ptr); + +// 只能接受希望共享所有权的 int +void G(shared_ptr); + +// 不改变所有权,但需要特定所有权的调用者 +void H(const unique_ptr&); + +// 接受任何 int +void H(int&); + +// 不好 +void F(shared_ptr& w) { + // ... + Use(*w); // 只使用 w -- 完全不涉及生命周期管理 + // ... +}; +``` + + +# 11 安全编码规范 + +## 基本原则 + +1. 程序在处理外部数据时必须经过严格的合法性校验。编程人员在处理外部数据过程中必须时刻保持这种思维意 +识,不能做出任何外部数据符合预期的假设,外部数据必须经过严格判断后才能使用。编码人员必须在这种严 +酷的攻击环境下通过遵守这一原则保证程序的执行过程符合预期结果。 +2. 尽量减少代码的攻击面,代码的实现应该尽量简单,避免与外部环境做多余的数据交互,过多的攻击面增加了 +被攻击的概率,尽量避免将程序内部的数据处理过程暴露到外部环境。 +3. 通过防御性的编码策略来弥补潜在的编码人员的疏忽。粗心是人类的天性。由于外部环境的不确定性,以及编 +码人员的经验、习惯的差异,代码的执行过程很难达到完全符合预期设想的情况。因此在编码过程中必须采取 +防御性的策略,尽量缓解由于编码人员疏忽导致的缺陷。这些措施包括: + +- 变量声明应该赋予初值 +- 谨慎使用全局变量 +- 避免使用功能复杂、易用错的函数 +- 禁用易用错的编译器/操作系统的机制 +- 小心处理资源访问过程 +- 不要改变操作系统的运行环境(创建临时文件、修改环境变量、创建进程等) +- 严格的错误处理 +- 合理使用调试断言(ASSERT) + +## 变量 + +### 规则11.2.1 指针变量、表示资源描述符的变量、BOOL变量声明必须赋予初值 + +说明:变量声明赋予初值,可以避免由于编程人员的疏忽导致的变量未初始化引用。 + +正确示例: + +```cpp +SOCKET s = INVALID_SOCKET; +unsigned char *msg = nullptr; +int fd = -1; +``` + +错误示例:以下代码,由于变量声明未赋予初值,在最后free的时候出错。 + +```cpp +char *message; // 错误!必须声明为 char *message = nullptr; + +if (condition) { + message = (char *)malloc(len); +} + +if (message != nullptr) { + free(message); //如果condition未满足,会造成free未初始化的内存。 +} +``` + +### 规则11.2.2 指向资源句柄或描述符的变量,在资源释放后立即赋予新值 + +说明:资源释放后,对应的变量应该立即赋予新值,防止后续又被重新引用。如果释放语句刚好在变量作用域的最后一句,可以不进行赋值。 + +正确示例: + +```cpp +SOCKET s = INVALID_SOCKET; +... +closesocket(s); +s = INVALID_SOCKET; + +unsigned char *msg = nullptr; +... +free(msg); +msg = nullptr; +``` + +### 规则11.2.3 同一个函数内,局部变量所占用的空间不要过大 + +程序在运行期间,函数内的局部变量保存在栈中,栈的大小是有限的。如果申请过大的静态数组,可能导致出现运行 +出错。 建议在申请静态数组的时候,大小不超过0x1000。 + +下面的代码,buff申请过大,导致栈空间不够,程序发生stackoverflow异常。 + +```c++ +constexpr int MAX_BUF = 0x1000000; +int Foo() { + char buff[MAX_BUFF] = {0}; // Bad + ... +} +``` + +## 断言 + +### 断言使用原则 + +目前代码中有两种断言:一种是ASSERT,用于在DEBUG模式进行条件判定,条件不满足时程序直接退出;一种是CHECK_FATAL,用于检测运行时异常,条件不满足时程序直接退出。 + +适用用CHECK_FATAL的情况:主要是输入、资源申请等不受控情况。示例: + +```cpp +CHECK_FATAL(mplName.rfind(kMplSuffix) != std::string::npos, "File name %s does not contain .mpl", mplName.c_str()); // 文件名不符合要求 + +CHECK_FATAL(intrinCall->GetReturnVec().size() == 1, "INTRN_JAVA_FILL_NEW_ARRAY should have 1 return value"); // 逻辑约束不满足 + +CHECK_FATAL(func->GetParamSize() <= 0xffff, "Error:the argsize is too large"); // 输入合法性较验 + +void *MemPool::Malloc(size_t size) { + ... + CHECK_FATAL(b != nullptr, "ERROR: Malloc error"); // 内存申请失败 +} +``` + +适合用ASSERT的情况,用于bug定位,防御性编程。示例: + +```cpp +ASSERT(false, "should not be here"); + +ASSERT(false, "Unknown opcode for FoldIntConstComparison"); +``` + +### 建议11.3.1 上下文安全的指针,不用使用断言较验其是否为nullptr + +说明:编译器是离线编译工具,进程崩溃的影响相对在线服务要小很多,可以适当减少防御性编程方式。因此,并不是所有入参都需要较验空指针,而是通过上下文逻辑来判断是否需要较验空指针。逻辑上不可能为nullptr的入参,可以不用较验。确定需要较验的,参考断言使用原则。 + +### 建议11.3.2 上下文安全的数组下标,不用使用断言较验数组是否越界 + +说明:同空指针原则一样,通过逻辑来判断是否需要用断言进行数组越界较验。确定需要添加的,参考断言使用原则。 + +### 建议11.3.3 上下文安全的情况,不用使用断言较验整数溢出、截断、回绕 + +说明:加法或乘法导致的整数溢出,如果逻辑保证的,可以不用较验。整数类型转换也可能导致截断、回绕,如果是逻辑保证的,可以不用较验。确定需要较验的,参考断言使用原则。 + +如果希望容错,逻辑继续运行的,可以用条件语句进行较验。 + +### 规则11.3.1 运行时可能会导致的错误,严禁使用ASSERT断言 + +错误示例: + +```cpp +FILE *fp = fopen(path, "r"); +ASSERT(fp != nullptr, "nullptr check"); //错误用法:文件有可能打开失败 + +char *str = (char *)malloc(MAX_LINE); +ASSERT(str != nullptr, "nullptr check"); //错误用法:内存有可能分配失败 +ReadLine(fp, str); +``` + +### 规则11.3.2 严禁在断言内改变运行环境 + +说明:在程序正式发布阶段,断言不会被编译进去,为了确保调试版和正式版的功能一致性,严禁在断言中使用任何赋值、 +修改变量、资源操作、内存申请等操作。 + +例如,以下的断言方式是错误的: + +```cpp +ASSERT(i++ > 1000); // p1被修改 +ASSERT(close(fd) == 0); // fd被关闭 +``` + +## 异常机制 + +### 规则11.4.1 禁用C++异常机制 + +说明:严禁使用C++的异常机制,所有的错误都应该通过错误值在函数之间传递并做相应的判断, 而不应该通过异常机制进行错误处理。 + +编码人员必须完全掌控整个编码过程,建立攻击者思维,增强安全编码意识,主动把握有可能出错的环节。而使用C++异常机制进行错误处理,会削弱编码人员的安全意识。 + +异常机制会打乱程序的正常执行流程,使程序结构更加复杂,原先申请的资源可能会得不到有效清理。 + +异常机制导致代码的复用性降低,使用了异常机制的代码,不能直接给不使用异常机制的代码复用。 + +异常机制在实现上依赖于编译器、操作系统、处理器,使用异常机制,导致程序执行性能降低。 + +在二进制层面,程序被加载后,异常处理函数增加了程序的被攻击面,攻击者可以通过覆盖异常处理函数地址,达到 +攻击的效果。 + +## 内存 + +### 规则11.5.1 内存申请前,必须对申请内存大小进行合法性校验 + +内存申请的大小可能来自于外部数据,必须检查其合法性,防止过多地、非法地申请内存。不能申请0长度的内存。 +例如: +```cpp +int Foo(int size) { + if (size <= 0) { + //error + ... + } + ... + char *msg = (char *)malloc(size); + ... +} +``` + +### 规则11.5.2 内存分配后必须判断是否成功 + +```cpp +char *msg = (char *)malloc(size); +if (msg != nullptr) { + ... +} +``` + +## 危险函数 + +### 规则11.6.1 禁止使用内存操作类危险函数 +C标准的许多函数,没有将目标缓冲区的大小作为参数,并且未考虑到内存重叠、非法指针的情况,在使用中很容易引入缓冲区溢出等安全漏洞。 + +基于历史缓冲区溢出漏洞触发的情况统计,有很大一部分是因为调用了这些内存操作类函数但未考虑目标缓冲区大小而导致。 +以下列出了部分内存操作类危险函数: + +内存拷贝函数:memcpy(), wmemcpy(), memmove(), wmemmove() + +内存初始化函数:memset() + +字符串拷贝函数:strcpy(), wcscpy(),strncpy(), wcsncpy() + +字符串拼接函数:strcat(), wcscat(),strncat(), wcsncat() + +字符串格式化输出函数:sprintf(), swprintf(), vsprintf(), vswprintf(), snprintf(), vsnprintf() + +字符串格式化输入函数:scanf(), wscanf(), vscanf(), vwscanf(), fscanf(),fwscanf(),vfscanf(),vfwscanf(),sscanf(), swscanf(), vsscanf(), vswscanf() + +stdin流输入函数:gets() +请使用对应的安全函数(详细信息请参考huawei_secure_c)。 + +例外:在下列情况下,由于未涉及到外部数据处理,不存在被攻击的场景,内存操作完全在本函数内完成,不存在因外部控制而失败的可能性。 +如果使用安全函数反而造成代码的冗余,可以留用危险函数: + +(1)对固定长度的数组进行初始化,或对固定长度的结构体进行内存初始化: +```cpp +BYTE array[ARRAY_SIZE]; + +void Foo() { + char destBuff[BUFF_SIZE]; + ... + memset(array, c1, sizeof(array)); //对全局固定长度的数据赋值 + ... + memset(destBuff, c2, sizeof(destBuff)); //对局部固定长度的数据赋值 + ... +} + +typedef struct { + int type; + int data; +} Tag; + +Tag g_tag = {1, 2}; + +void Foo() { + Tag dest; + ... + memcpy((void *)&dest, (const void *)&g_tag, sizeof(Tag)); //对固定长度结构体赋值 + ... +} +``` + +(2)函数参数中有表示内存的参数,对该内存进行初始化: +```cpp +void Foo(BYTE *buff1, size_t len1, BYTE *buff2, size_t len2) { + ... + memset(buff1, 0, len1); //对buff1清0 + memset(buff2, 0, len2); //对buff2清0 + ... +} +``` + +(3)从堆中分配内存后,赋予初值: +```cpp +size_t len = ... +char *str = (char *)malloc(len); +if (str != nullptr) { + memset(str, 0, len); + ... +} +``` + +(4)根据源内存的大小进行同等大小的内存复制: +以下代码基于srcSize分配了一块相同大小的内存,并复制过去: +```cpp +BYTE *src = ... +size_t srcSize = ... +BYTE *destBuff = new BYTE[srcSize]; +memcpy(destBuff, src, srcSize); +``` + +以下代码根据源字符串的大小分配一块相同的内存,并复制过去: +```cpp +char *src = ... +size_t len = strlen(src); +if (len > BUFF_SIZE) { + ... +} +char *destBuff = new char[len + 1]; +strcpy(destBuff, src); +``` + +(5)源内存全部是静态字符串常量(编码时需要检查目标内存是否足够的存储空间): +以下代码直接将字符串常量“hello”复制到数组中: +```cpp +char destBuff[BUFF_SIZE]; +strcpy(destBuff, "hello"); +``` +以下代码对静态字符串常量进行拼接: +```cpp +const char *list[] = {"red","green","blue"}; +char destBuff[BUFF_SIZE]; +sprintf(destBuff, "hello %s", list[i]); +``` diff --git a/doc/cn/RcApi.md b/doc/cn/RcApi.md new file mode 100644 index 0000000000000000000000000000000000000000..7a3777a7c277ecef8771dea1b3f9048ee35ea8fa --- /dev/null +++ b/doc/cn/RcApi.md @@ -0,0 +1,524 @@ +RC API +---- + +引用计数(Reference Counting, RC)是计算机编程语言中的一种内存管理技术,是指将资源(可以是对象、内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程。使用引用计数技术可以实现自动资源管理的目的。同时引用计数还可以指使用引用计数技术回收未使用资源的垃圾回收算法。 + +由于需要支持RC操作,运行时为方舟编译器提供了如下API,以便其更好的生成相关代码。 + +## void MCC\_IncRef\_NaiveRCFast(address\_t obj) + +**功能说明:** + +将对象的RC值原子性的加一。 + +**入参说明:** + +obj, 堆对象指针。 + +**返回值:** + +无 + +## void MCC\_DecRef\_NaiveRCFast(address\_t obj) + +**功能说明:** + +将对象的RC值原子性的减一。 + +**入参说明:** + +obj, 堆对象指针。 + +**返回值:** + +无 + +## void MCC\_ClearLocalStackRef(address\_t \*addr) + +**功能说明:** + +用来清理线程栈上的局部引用(Local Reference)。当前编译框架下为支持异常和GC,此函数可以将对应栈地址上的局部引用清零,并将其老值的RC原子性的减一。 + +**入参说明:** + +addr, 栈上局部引用的地址。 + +**返回值:** + +无 + +## void MCC\_IncDecRef\_NaiveRCFast(address\_t incObj, address\_t decObj) + +**功能说明:** + +用来将incObj指向的对象的RC值原子性的加一和将decObj指向的对象的RC原子性的减一。 + +**入参说明:** + +incObj,需要将RC原子性加一的对象地址。 + +decObj,需要将RC原子性减一的对象地址。 + +**返回值:** + +无 + +## void MCC\_IncDecRefReset(address\_t incObj, address\_t \*decAddr) + +**功能说明:** + +将incObj指向的对象的RC值原子性的加一,并将栈地址指针decAddr存放的局部变量对象的RC原子性的减一,同时将栈地址指针decAddr指向的内存清零。 + +**入参说明:** + +incObj,需要将RC原子性加一的堆对象。 + +decAddr,栈上局部引用的地址。 + +**返回值:** + +无 + +## void MCC\_DecRefResetPair(address\_t \*decAddr0, address\_t \*decAddr1) + +**功能说明:** + +将所有参数指向的栈地址空间清零,并将对应包含的局部变量老值的RC原子性的减一。 + +**入参说明:** + +decAddr0和decAddr1,栈上局部引用的地址。 + +**返回值:** + +无 + +## void MCC\_SetObjectPermanent(address\_t obj) + +**功能说明:** + +将堆对象设置成永久存活的对象,调用之后obj对应的对象的RC会变成极大值。 + +**入参说明:** + +obj的堆对象地址。 + +**返回值:** + +无 + +## address\_t MCC\_LoadVolatileStaticField(address\_t \*fieldAddr) + +**功能说明:** + +从易失性(Volatile)静态变量中取值,并且将取到的堆对象的RC原子性的加一。 + +**入参说明:** + +fieldAddr,Volatile静态变量的地址。 + +**返回值:** + +返回Volatile静态变量的值。 + +## address\_t MCC\_LoadRefStatic(address\_t \*fieldAddr) + +**功能说明:** + +从静态变量中取值,并且将取到的堆对象的RC原子性的加一。 + +**入参说明:** + +fieldAddr,静态变量的地址。 + +**返回值:** + +返回静态变量的值。 + +## address\_t MCC\_LoadVolatileWeakField(address\_t obj, address\_t \*fieldAddr) + +**功能说明:** + +从Weak的Volatile字段中取值, 如果取到非空的堆对象,会将该对象的RC原子性的加一。 + +**入参说明:** + +obj,堆对象地址。 + +fieldAddr,标记为Weak的Volatile字段的地址 + +**返回值:** + +返回标记为Weak的Volatile字段中的值,有可能返回空对象指针。 + +## address\_t MCC\_LoadWeakField(address\_t obj, address\_t \*field\_addr) + +**功能说明:** + +从Weak的字段中取值,如果取到非空的堆对象,会将该对象的RC原子性的加一。 + +**入参说明:** + +obj,堆对象地址。 + +fieldAddr,标记为Weak的字段的地址 + +**返回值:** + +返回标记为Weak的字段中的值,有可能返回空对象指针。 + +## address\_t MCC\_LoadRefField\_NaiveRCFast(address\_t obj, address\_t \*fieldAddr) + +**功能说明:** + +从fieldAddr字段取值,并将取到的堆对象的RC原子性的加一。 + +**入参说明:** + +obj,堆对象地址。 + +fieldAddr,对象对应字段的地址 + +**返回值:** + +返回对象字段中存储的值。 + +## address\_t MCC\_LoadVolatileField(address\_t obj, address\_t \*fieldAddr) + +**功能说明:** + +从Volatile字段中取值,并将取到的堆对象的RC原子性的加一。 + +**入参说明:** + +obj,堆对象地址。 + +fieldAddr,对象对应Volatile字段的地址 + +**返回值:** + +返回对象Volatile字段中存储的值。 + +## void MCC\_WriteReferent(address\_t obj, address\_t value) + +**功能说明:** + +写入java.lang.ref.Reference的referent字段,如果取到非空的堆对象,会将该对象的RC原子性的加一。 + +**入参说明:** + +obj,java.lang.ref.Reference对象地址。 + +value,作为referent的堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteVolatileStaticFieldNoInc(address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向Volatile静态变量中写入堆对象,此调用不改变写入的堆对象的RC,但是会将静态变量存储的老值的RC原子性的减一。 + +**入参说明:** + +fieldAddr,Volatile静态变量的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteVolatileStaticFieldNoDec(address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向Volatile静态变量中写入堆对象,此调用会将新写入的堆对象value的RC原子性的加一,但是不将静态变量的老值减一。 + +**入参说明:** + +fieldAddr,Volatile静态变量的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteVolatileStaticFieldNoRC(address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向Volatile静态变量中写入堆对象,此调用不会改变写入的新值(value)的RC,也不会改变老值(fieldAddr存放的值)的RC。 + +**入参说明:** + +fieldAddr,Volatile静态变量的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteVolatileStaticField(address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向Volatile静态变量中写入堆对象,此调用会将新写入的堆对象value的RC原子性的加一,但是并将静态变量的老值的RC减一。 + +**入参说明:** + +fieldAddr,Volatile静态变量的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteRefFieldStaticNoInc(address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象普通静态变量字段中写入堆对象value,此调用不会将新写入的堆对象value的RC原子性的加一,但是会将其存储的老值的RC减一。 + +**入参说明:** + +fieldAddr,对象静态变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteRefFieldStaticNoDec(address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象普通静态变量字段中写入堆对象value,此调用会将新写入的堆对象value的RC原子性的加一,但是不会将其存储的老值的RC减一。 + +**入参说明:** + +fieldAddr,对象静态变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteRefFieldStaticNoRC(address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象普通静态变量字段中写入堆对象value,此调用不会将新写入的堆对象value的RC原子性的加一,也不会将其存储的老值的RC减一。 + +**入参说明:** + +fieldAddr,对象静态变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteRefFieldStatic(address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象普通静态变量字段中写入堆对象value,此调用会将新写入的堆对象value的RC原子性的加一,同时会将其存储的老值的RC减一。 + +**入参说明:** + +fieldAddr,对象静态变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteVolatileFieldNoInc(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象Volatile变量字段中写入堆对象value,此调用不会将新写入的堆对象value的RC原子性的加一,但是会将其存储的老值的RC减一。 + +**入参说明:** + +obj,对象的地址 + +fieldAddr,对象volatile变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteVolatileFieldNoDec(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象Volatile变量字段中写入堆对象value,此调用会将新写入的堆对象value的RC原子性的加一,但是不会并将其存储的老值的RC减一。 + +**入参说明:** + +obj,对象的地址 + +fieldAddr,对象volatile变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteVolatileFieldNoRC(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象Volatile变量字段中写入堆对象value,此调用不会将新写入的堆对象value的RC原子性的加一,也不会将其存储的老值的RC减一。 + +**入参说明:** + +obj,对象的地址 + +fieldAddr,对象volatile变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteVolatileField(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象Volatile变量字段中写入堆对象value,此调用会将新写入的堆对象value的RC原子性的加一,也会将其存储的老值的RC减一。 + +**入参说明:** + +obj,对象的地址 + +fieldAddr,对象volatile变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteRefFieldNoInc(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象普通变量字段中写入堆对象value,此调用不会将新写入的堆对象value的RC原子性的加一,但是会将其存储的老值的RC减一。 + +**入参说明:** + +obj,对象的地址 + +fieldAddr,对象普通变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteRefFieldNoDec(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象普通变量字段中写入堆对象value,此调用会将新写入的堆对象value的RC原子性的加一,但是不会将其存储的老值的RC减一。 + +**入参说明:** + +obj,对象的地址 + +fieldAddr,对象普通变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteRefFieldNoRC(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象普通变量字段中写入堆对象value,此调用不会将新写入的堆对象value的RC原子性的加一,也不会将其存储的老值的RC减一。 + +**入参说明:** + +obj,对象的地址 + +fieldAddr,对象普通变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteRefField(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象普通变量字段中写入堆对象value,此调用会将新写入的堆对象value的RC原子性的加一,也会将其存储的老值的RC减一。 + +**入参说明:** + +obj,对象的地址 + +fieldAddr,对象普通变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteVolatileWeakField(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象标记为Weak的volatile变量字段中写入堆对象value,此调用会将新写入的堆对象value的Weak RC原子性的加一,也会将其存储的老值的Weak RC减一。 + +**入参说明:** + +obj,对象的地址 + +fieldAddr,对象标记为Weak的volatile变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 + +## void MCC\_WriteWeakField(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**功能说明:** + +向对象标记为Weak的普通变量字段中写入堆对象value,此调用会将新写入的堆对象value的Weak RC原子性的加一,也会将其存储的老值的Weak RC减一。 + +**入参说明:** + +obj,对象的地址 + +fieldAddr,对象标记为Weak的普通变量字段的地址。 + +value,待写入堆对象地址 + +**返回值:** + +无。 diff --git a/doc/cn/VtableItableDescription.md b/doc/cn/VtableItableDescription.md new file mode 100644 index 0000000000000000000000000000000000000000..a7092d0f45a7042919897e16f92af2c3e576e575 --- /dev/null +++ b/doc/cn/VtableItableDescription.md @@ -0,0 +1,401 @@ +# 虚函数表和接口函数表设计介绍 + +## 虚函数表 + +方舟编译器会为每一个类生成一个虚方法表。在这个表中,会存储父类的虚方法,再加上子类的虚方法以及实现的接口类的Default方法。如果子类重载了父类的实现,那么在虚方法表中同样的位置,则会覆盖掉父类的方法。 + +下面,展示一个具体 的例子: + +```java +class A { + public int first() { + return 0; + } +} + +class B extends A { + public void foo() { + } + public int first() { + return 1; + } +} + +class C extends A { + public void bar() { + } + public int first() { + return 2; + } +} + +public class IsEmpty { + public static void main(String [] args) { + A x = new B(); + x.first(); + A y = new C() + y.first(); + } + + public void add(A x) { + x.first(); + } +} +``` + + + +方舟编译器生成的虚函数表的结构如下: + +A: +``` + _vtb_LA_3B: + .quad Ljava_2Flang_2FObject_3B_7Cclone_7C_28_29Ljava_2Flang_2FObject_3B - . + .quad Ljava_2Flang_2FObject_3B_7Cequals_7C_28Ljava_2Flang_2FObject_3B_29Z - . + .quad Ljava_2Flang_2FObject_3B_7Cfinalize_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CgetClass_7C_28_29Ljava_2Flang_2FClass_3B - . + .quad Ljava_2Flang_2FObject_3B_7ChashCode_7C_28_29I - . + .quad Ljava_2Flang_2FObject_3B_7Cnotify_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CnotifyAll_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CtoString_7C_28_29Ljava_2Flang_2FString_3B - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28J_29V - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28JI_29V - . + .quad LA_3B_7Cfirst_7C_28_29I - . +``` + +B: + +``` + __vtb_LB_3B: + .quad Ljava_2Flang_2FObject_3B_7Cclone_7C_28_29Ljava_2Flang_2FObject_3B - . + .quad Ljava_2Flang_2FObject_3B_7Cequals_7C_28Ljava_2Flang_2FObject_3B_29Z - . + .quad Ljava_2Flang_2FObject_3B_7Cfinalize_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CgetClass_7C_28_29Ljava_2Flang_2FClass_3B - . + .quad Ljava_2Flang_2FObject_3B_7ChashCode_7C_28_29I - . + .quad Ljava_2Flang_2FObject_3B_7Cnotify_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CnotifyAll_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CtoString_7C_28_29Ljava_2Flang_2FString_3B - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28J_29V - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28JI_29V - . + .quad LB_3B_7Cfirst_7C_28_29I - . + .quad LB_3B_7Cfoo_7C_28_29V - . +``` +C: +``` +__vtb_LC_3B: +前面11个和A和B一样 + … … + .quad LC_3B_7Cfirst_7C_28_29I - . + .quad LC_3B_7Cbar_7C_28_29V - . + +``` + +对比一下,我们可以发现: + +1. 所有的类都是继承自Object类,所以虚函数表的前面11个函数都是继承自Object,且和父类Object布局保持一致。 +2. 对于第12个函数,子类B覆盖了父类A,所以在同样的位置,父类是LA_3B_7Cfirst_7C_28_29I,子类是LB_3B_7Cfirst_7C_28_29I。类C继承至类A并重写了first函数,且实现了接口iD,所以12的位置为 LC_3B_7Cfirst_7C_28_29I,接口函数LiD_3B_7Csecond_7C_28_29I被放在了13的位置。 + +## 虚函数访问处理(编译时) + +因为要保持多态性,所以在编译时,不能确定具体调用是哪个函数。在当前例子里面体现在这个位置: + +```java +public class IsEmpty { + public static void main(String [] args) { + A x = new B(); + x.first(); + A y = new C(); + y.first(); + } + + public void add(A x) { + x.first(); + } +} +``` + + +像这种情况,我们编译时不能知道运行时调用的是B里面的first函数,还是C里面的first函数。 + +但是,因为first函数在A,B,C中布局一致,而这个例子当中first函数在vtab中的偏移是12,因此我们可以生成这样的访问代码:从相应的对象中拿到vtable指针,然后加上offset12。这样我们就能访问到正确的函数。 + +## 虚函数调用处理(运行时) + +在程序执行过程中,以(图1)为例,当遇到虚拟函数调用的时候,我们执行如下步骤: +1. 判断对象(this_指针)是哪个类的实例(在图1中,this是类C的实例); +2. 使用函数索引在对应类的虚拟函数表中查找; +3. 返回实际调用的函数指针。 + +![](media/javavmt.png) +
图1: Java虚拟函数调用的静态化
+ +## 接口函数表 + +Interface call类似于多重继承,比java单继承要复杂。多继承无法天然地确定唯一一个继承顺序。 + +在一个封闭的环境下,可以通过拓扑排序的方法确定一个顺序(iA,iB,iC)。好处是可以实现像虚函数表一样的访问方式来处理interface call。但是这样得到的一个类的itable会非常大,而且大部分是空洞。考虑到性能和代码大小,这种方法是不可用的。 + +![](media/Topology.png) + + +对于开放的环境,编译时刻是无法通过拓扑排序来确定一个顺序的,导致接口函数表里的方法顺序不固定,所以实际实现中没办法像虚函数调用一样实现一个顺序一致的方法表和访问形式为 offset 的访问机制。在编译时刻,可以确定一个类实现的所有接口,以及接口的继承关系。运行时对函数签名进行比较来确定需要调用的函数。因为字符串比较开销比较大,所以方舟编译器会在编译时刻对函数名字和签名进行哈希计算得出哈希值。运行时首先比较哈希值;如果哈希值相同,且不存在哈希冲突,则调用这个函数。如果存在哈希冲突,则进行函数名字和签名的比较,取得函数指针。 + +同时,考虑到运行时效率和 ROM 空间的原因,我们把 Itable 分成了两级表,第一级表为真正的 hash ,考虑到ROM空间的压力,我们把 hash 值设为23,然后,依据 hash 得到的值把函数地址填到这个值对应的位置上去(0~22)。如果我们一级 hash 表不发生冲突的话,那么在最后一个包含函数地址的位置之后的表项都是空白的,这样后面的表项可以被去掉而不需要占用空间。如果一级 hash 表发生冲突了,则在发生冲突的位置填0,然后在第23个 slot 的位置填上二级表的地址。 + +一级函数表结构如下: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
表序接口函数表项说明
0&Func 或 0对应Hash值的函数地址,没有则为0; 如果出现冲突,那么冲突的位置也为0,并且在第23个表项填上二级表的地址; 如果没有冲突,那么将最后一个有对应函数的hash值( n )之后的表项删除
1&Func 或 0
2&Func 或 0
...&Func 或 0
n&Func
23&itbC二级表的地址。如果一级表没有出现冲突,则该项不存在
+ + +二级函数表的结构如下: + +| 接口函数表项 | 说明 | +|----------------------|--------------------------------------------------| +| Size | 不冲突的接口函数表的大小 | +| 1 | 对齐站位作用,无实际意义 | +| Func1_sig | Func1签名的哈希值 | +| &Func1 | Fun1的地址 | +| Func2_sig | Func2签名的哈希值 | +| &Func2 | Func2的地址 | +| ...... | | +| Func3_sig和Func4_sig | Func3签名的哈希值和Func4签名的哈希值,两个值相同 | +| 1 | 表示冲突,因为func3和func4签名的哈希值一样 | +| …… | | +| Func3_sig | Func3签名 | +| &Func3 | Func3的地址 | +| Func4_sig | Func4签名 | +| &Func4 | Func4的地址 | +| …… | | + +## 接口函数调用: + +对于声明为如下形式的接口函数调用的情况,我们的调用过程如图2所示: + +```java +interface B { funcB(); } +interface C { funcC(); } +interface D { funcD(); } +Class A implements B, C, D {} +``` + +![](media/interface1.jpg) + +
图2:Java接口函数调用的静态化
+ + +如图2所示,在程序执行过程中,我们执行如下步骤: + +1. 判断对象(obj)是哪个类的实例,当前为类A的实例; +2. 根据hash值,在一级表中查找,存在则返回函数指针,如果对应位置为0,则通过二级表查找。在二级表中,使用函数签名的哈希值查找,如果找到就返回函数指针,否则用函数名查找; +3. 间接调用函数指针,并把相关的参数(args)传给间接调用。 + +下面,举一个具体的例子: + +这个IsEmpty类实现了接口A和B,每个接口中声明有两个方法。 + +```java +interface A{ + public int add(); + public int minus(); +} + +interface B{ + public int mult(); + public int div(); +} + +public class IsEmpty implements A, B { + public static void main(String[]args) { + } + + public void test(B x) { + x.mult(); + } + + public int add() { + return 6 + 3; + } + + public int minus() { + return 6 - 3; + } + + public int mult() { + return 6 * 3; + } + + public int div() { + return 6 / 3; + } +} +``` + +首先,我们来看一下 IsEmpty 的 itable 在 maple 代码里面是怎么样的: + +``` +var $__itb_LIsEmpty_3B fstatic <[24] <* void>> = [0, 0, 0, 0, 0, 0, 0, 0, addroffunc ptr &LIsEmpty_3B_7Cdiv_7C_28_29I, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, addroffunc ptr &LIsEmpty_3B_7Cadd_7C_28_29I, 0, 0, addrof ptr $__itabC_LIsEmpty_3B] + +var $__itbC_LIsEmpty_3B fstatic <[6] <* void>> = [2, 1, 0xb97, addroffunc ptr &LIsEmpty_3B_7Cmult_7C_28_29I, 0x1f7f, addroffunc ptr &LIsEmpty_3B_7Cminus_7C_28_29I] +``` + +对应的汇编结构: + +``` +__itb_LIsEmpty_3B: + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad LIsEmpty_3B_7Cdiv_7C_28_29I - . + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad LIsEmpty_3B_7Cadd_7C_28_29I - . + .quad 0 + .quad 0 + .quad __itabC_LIsEmpty_3B - . +``` +``` +__itbC_LIsEmpty_3B: + .quad 2 + .quad 1 + .quad 2967 + .quad LIsEmpty_3B_7Cmult_7C_28_29I - . + .quad 8063 + .quad LIsEmpty_3B_7Cminus_7C_28_29I - . +``` + +其中表项内容如下: + +1. 一级表中(__itb_LIsEmpty_3B),共23项,其中第9项和第20项为函数地址,第23项为二级表地址,由此可见一级表发生了冲突,从而需要二级表来确认具体的函数地址; + +2. 二级表中第一项为2,表示有2个不冲突的函数,第二项为1,起到对齐占位的作用,而后面4项分别为函数签名产生的hash值和对应的函数地址。 + +接下来我们看到这个例子里面,源码中test函数中会产生一个interface-call,对应的maple代码如下: + +``` +if (eq u1 u64 (regread u64 %4, constval u64 0)) { + callassigned &MCC_getFuncPtrFromItabSecondHash64 (regread ptr %3, constval u64 0xb97, conststr ptr "mult|()I") { regassign u64 %4} +} +icallassigned (regread u64 %4, regread ref %2) {} +``` + +可以看出调用逻辑是这样的: + +首先判断一级itable表当中hash值对应位置表项是否为空,如果不空则直接使用该地址;如果为空,则调用 getFuncPtrFromItabSecondHash64 函数。 + +getFuncPtrFromItabSecondHash64 函数有三个参数,itable 地址,函数 basename 对应的 hash 值,和函数的签名。完整的调用过程是先通过 classinfo 找到对应的 itable 地址,然后进行 hash 值的比对,如果比对成功且不冲突就能得到正确的地址;如果比对冲突,则直接使用 signature name 进行比对(字符串比对)。 + +这里所访问的 itable 和上面列出的 IsEmpty 的itable表项形式一致。 + +## Interface override + +Java 8中引入了 `Default` 函数。父类中的实现会覆盖接口中的Default函数;接口之间的Default函数需要根据接口的继承关系来确定Override。如下所示,类cA继承类cB实现了接口iD,在cB和iD中都有foo的实现。对于cA来说,foo的实现来自父类cB而不是接口iD。 + +```java + +interface iD { + public default void foo(){System.out.println("iD foo");} +} + +class cB { + public void foo(){System.out.println("cB foo");} +} + +class cA extends cB implements iD { +} + +public class IsEmpty { + public static void main(String [] args) { + iD obj = new cA(); + obj.foo(); + } +} +``` + + +如下所示,接口Parent和Son都定义了getValue。对于类Sson来说,getValue的实现来自Son,而不是来自Parent。 + +```java +interface Parent{ + default void getValue(){ + System.out.println("Parent getVatue……"); + } +} + +interface Son extends Parent{ + default void getValue(){ + System.out.println("OfInt getValue……") + } +} + +abstract class OfPrimitive implements Parent{ +} + +class SSon extends OfPrimitive implements Son{ +} + +public class Main { + static int get() { + return 1; + } + + public static void main(String[] args) { + Parent son = (Parent)new SSon(); + son.getValue(); + + SSon son2; + if(get()==1) { + son2 = new SSon(); + } + else son2 = new SSon(); + son2.getValue(); + } +} +``` diff --git a/doc/cn/media/MapleDriverStructure.png b/doc/cn/media/MapleDriverStructure.png new file mode 100644 index 0000000000000000000000000000000000000000..adc5f98ba54d4ffb4430cb3bbff37e8e45d06214 Binary files /dev/null and b/doc/cn/media/MapleDriverStructure.png differ diff --git a/doc/cn/media/Topology.png b/doc/cn/media/Topology.png new file mode 100644 index 0000000000000000000000000000000000000000..6967780a1ac7addf7811b4271bbf805c6d659027 Binary files /dev/null and b/doc/cn/media/Topology.png differ diff --git a/doc/cn/media/addphase.png b/doc/cn/media/addphase.png new file mode 100644 index 0000000000000000000000000000000000000000..ed9b5fbfccb5a30ba1ac877952c6b5372a43dafa Binary files /dev/null and b/doc/cn/media/addphase.png differ diff --git a/doc/cn/media/interface1.jpg b/doc/cn/media/interface1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7377546fc36b03b282e5d85d0a89fd274288f831 Binary files /dev/null and b/doc/cn/media/interface1.jpg differ diff --git a/doc/cn/media/javavmt.png b/doc/cn/media/javavmt.png new file mode 100644 index 0000000000000000000000000000000000000000..ef93f36923559321d0512a862ca9a1ff9d36a6b6 Binary files /dev/null and b/doc/cn/media/javavmt.png differ diff --git a/doc/en/CPPCodingTalkAboutPointer.md b/doc/en/CPPCodingTalkAboutPointer.md new file mode 100644 index 0000000000000000000000000000000000000000..2e822efaa531cc7c8b7785c8a9f07748ce6a08d5 --- /dev/null +++ b/doc/en/CPPCodingTalkAboutPointer.md @@ -0,0 +1,266 @@ +# Discussion of Pointer in C++ Programming + +# Background + +The use of pointers in `C/C++` is flexible and accompanied by many security risks, which poses higher requirements on programmers. This document will discuss how to use raw pointers in `C/C++` and ultimately establish a coding paradigm. + +# Raw Pointer vs Reference + +## Member access. + +When an object member is accessed, the raw pointer may be null (the validity of a pointer is logically ensured by a closed object or function). Therefore, invalid pointers must be checked, whereas the reference cannot be null and does not need to be checked. + +## Container members. + +In the semantics of `C++`, references express alias relationships, which do not occupy memory theoretically. (In practice, references are implemented internally as pointers in a compiler.) A reference is not an object in itself, which is different from a pointer. A pointer can be a container member, but a reference cannot. + +# Raw Pointer vs Smart Pointer + +## Destroy a heap object. + +```c++ +class Int { + ... +private: + int data; +} + +void test(int *in) { + Int* tmp = new Int(); + ... + goto LABEL; + ... + + delete tmp; +LABEL: +} +``` + +The use of resources (heap objects, stack objects, and file resources) complies with the principle that **"resources that are released in the same scope as they are acquired"** in Resource Acquisition Is Initialization (RAII), which minimizes the possibility of resource leakage. + +A segment of processing logic and sub-function calling are usually involved between `new` and `delete` of a raw pointer. The intermediate processing logic may encounter exceptions or jumps. (The current object will not go beyond authority to restrict the behavior of the intermediate processing logic, which exceeds the management scope of `new`.) The resource release is skipped due to exceptions or jumps, causing resource leakage (for example, the `tmp` object in the `test` function in the preceding example). + +The smart pointer is reconstructed to `auto tmp = std::make_unique();`. When the `tmp` object is constructed, the `delete` behavior is bound and the current scope is destroyed, preventing resource leakage. + +## Management permission vs use permission. + +```c++ +int *delete(int *in); +``` + +Management permission: Destroy and rebuild objects. + +Use permission: Access and modify objects. + +As shown in the preceding example, when a raw pointer is used to transfer parameters, the use of the **management permission** or **use permission** cannot be determined by the input parameter `in` and output parameter because the raw pointer implies an attribute of transferring the ownership (possibly or not). Additional information is required when this function is called: Will the `in` parameter be destroyed by the `delete` function? Does the return value need to be destroyed by the caller? + +```c++ +std::unique_ptr delete(std::unique_ptr &in); +``` + +A smart pointer is used to specify a role of a parameter in an interface. For example, `std::unique_ptr& in` indicates that the `delete` function has the **use permission**, and the return value indicates that the `delete` function transfers the ownership. + +# Pointer Normalization + +## A destruction method must be immediately bound to an object created by `new`. + +Bad example: + +```c++ +Object *obj = new Object(); +... +delete obj; +``` + +Good example: + +```c++ +std::unique_ptr obj = std::make_unique(); +``` + +## A release method must be immediately bound to the applied resources. + +Bad example: + +```c++ +FILE *file = open("xxx.txt"); +... +file->close(); +``` + +Good example: (This example is commonly used. The best way is to encapsulate an application class `open`.) + +```c++ +template +class ResourceGuard { + public: + ResourceGuard(T *_obj, Func _func) : obj(_obj), func(_func) {} + + ~ResourceGuard() { obj.func(); } + private: + T *obj; + Func func; +} + +FILE* file = open("xxx.txt"); +auto fileGuard = ResourceGuard>(file, FILE::close); +... +``` + +## Use a reference instead of a pointer when the value is not null. + +Bad example: + +```c++ +void func1(int *in) { + if (in == nullptr) return; + ... +} + +void func2() { + int *p = nullptr; + ... + if (p != nullptr) { + func1(p); + } +} +``` + +Good example: + +```c++ +void func1(int &in) { + ... +} + +void func2() { + int *p = nullptr; + ... + if (p != nullptr) { + func1(*p); + } +} +``` + +## As a container member (without the management permission), use an encapsulated reference container instead of a pointer when the value is not null. + +Bad example: + +```c++ +void func(std::vector &in) { + for (auto *p : in) { + if (p == nullptr) { + continue; + } + ... + } +} +``` + +Good example: + +```c++ +template +class Ref { + public: + Ref() = delete; + Ref(T &ref) : data(&ref) {} + + ... + + operator T() const noexcept { + return *data; + } + + private: + T *data; +} + +template +using ref_vector = std::vector>; +void func(ref_vector &in) { + for (auto p : in) { + int &data = p; + ... + } +} +``` + +## As a container member (with the management permission), use a container that has the lifecycle management permission instead of a pointer container. + +Bad example: + +```c++ +std::vector data; +... +for (auto *p : data) { + delete p; +} +``` + +Good example: + +```c++ +template +class ptr_vector { +public: + ~ptr_vector() { + for (auto *p : data) { + delete p; + } + } + +private: + std::vector data; +} + +ptr_vector data; +... +``` + +## Explicitly transfer an object management permission and specify an object use permission. + +`move` semantics is added to `C++11`, and `auto_ptr` is discarded. `unique_ptr` is used to explicitly transfer the ownership so that the lifecycle management methods of stack objects and heap objects can be unified. + +Example of stack object transfer: + +```c++ +std::vector func() { + std::vector data; + data.push_back(0); + return std::move(data); +} +``` + +Example of fuzzy heap object transfer: + +```c++ +Object *func() { + std::unique_ptr data = std::make_unique(); + Object &rData = ToRef(data); + rData.push_back(0); + return data.release(); +} +``` + +Example of clear heap object transfer: + +```c++ +std::unique_ptr func() { + std::unique_ptr data = std::make_unique(); + Object &rData = ToRef(data); + rData.push_back(0); + return std::move(data); +} +``` + +## Scenarios where pointers should be used. + +1. When a third-party library function transfers in or out a pointer, `unique_ptr.get()` or `unique_ptr.release()` must be used to construct input parameters before the function is called. After output parameters are obtained, `unique_ptr` must be used to catch or check whether the output parameters are null and convert the output parameters to references. +2. As a container member (without the management permission), a null pointer is designed in the application scenario. However, the null pointer must be checked and converted to a reference immediately before use. Pointer diffusion is not supported. + +# Remarks + +`Ref` and `ref_vector` have been developed. `Ref` is defined as `SafePtr` because `operator.` cannot be reloaded. + +The `ResourceGuard` and `ptr_vector` are being developed and are mainly used as examples in this document. diff --git a/doc/en/CompilerPhaseDescription.md b/doc/en/CompilerPhaseDescription.md new file mode 100644 index 0000000000000000000000000000000000000000..1d9870b21b9e96684973c1d9707298760fe9aae3 --- /dev/null +++ b/doc/en/CompilerPhaseDescription.md @@ -0,0 +1,152 @@ +### Hierarchy in maple phase +At the Current stage, there are two phases classes provided for inheritance. +Other level IR phase can be designed as a subclass of the MaplePhase class. +They perform the optimizations or generate analysis results on the specific IR level. + +##### The MapleModulePhase class + +If a phases is derived from MapleModulePhase, it indicates that this phase does transformation on the module. +It can run lower level IR phases manager as well. + +##### The MapleFunctionPhase class + +```c++ + template + class MapleFunctionPhase : public MaplePhase +``` + +In constrast to MapleFunctionPhase, it is template class due to different Function level IRs in Maple. +Both CodeGen Function level IR and MidEnd Function level IR derives this class. + +### Memory management for maple phase + +Maple phase management is able to manage memory so that each phase can keep the information required by other phases and discard useless information. Each phase manager provides an analysisDataManager (In multithreading, each threads provides an analysisDataMangers) which takes responsibility for storing analysis data. +To implement this functionality, the GetAnalysisDependence Method is required to be implemented be each phases. +```c++ + void ::GetAnalysisDependence(maple::AnalysisDep &aDep) const { + aDep.AddRequired(); // If a previous phase is requried to be executed + aDep.AddPreserved(); // preserve specific previous phase information + aDep.SetPreservedAll(); // preserve all previous phase information in analysisDataManager +} +``` +#### Analysis phase + +GetPhasesMempool() in Analysis phase provides mempool from analysisDataManager. +Any data that is put in analysis phase mempool is not deleted until it is declared to be discarded by other phases or the end of phase manager. +If information generated during analysis phase need to be deleted after this analysis phase, it can be put in Temp mempool in MaplePhase. + +#### Transfrom phase + +GetPhasesMempool() in Transform phase provides mempool which lives until this transformation finish. +**If a transform phase does not implement the GetAnalysisDependence method, it defaults to not having any prerequisite phases, and invalidating all phases information in analysisDataManager.** Transfrom phase default to be assumed to invalid all ananlysis results. + + +### Quick Start -- basic code + +An example for function level `transform` phase called 'MEHello' in me. +- 1 add two files: me_hello_opt.h and me_hello_opt.cpp + +content in me_hello_opt.h +```c++ +#ifndef MAPLE_ME_INCLUDE_ME_HELLO_OPT_H +#define MAPLE_ME_INCLUDE_ME_HELLO_OPT_H +#include "me_function.h" // in order to use MeFunction +#include "maple_phase.h" // in order to use the macro +namespace maple { + +// always use this macro when you work with a transform phase. +MAPLE_FUNC_PHASE_DECLARE(MEHello, MeFunction) +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_HELLO_OPT_H + +``` +content in me_hello_opt.cpp +```c++ +#include "me_hello_opt.h" +// include the corresponding phasemanager in order to use information from other phase. +#include "me_phase_manager.h" + +namespace maple { + +// you need always keep in mind that which analysis results are needed and which results will be destroyed. +void MEHello::GetAnalysisDependence(maple::AnalysisDep &aDep) const { + aDep.AddRequired(); // it is guaranteed that MEDominance's result is available in this phase. + aDep.SetPreservedAll(); // it means that this phase will not destroy any analysis results. +} + +// the return value of this function indicates that whether this phase +// has modified the IR of this function, for now we do not use this value. +bool MEHello::PhaseRun(maple::MeFunction &f) { + // you can use this macro to get the result which is configured as Required + // in GetAnalysisDependence; or an error will be reported. + auto *dom = GET_ANALYSIS(MEDominance); + // do something using dom info. + LogInfo::MapleLogger() << "hello opt on function: " << f.GetName() << '\n'; + return false; +} + +} // namespace maple + +``` +- 2 tell the phase manager to welcome a new phase. + - 2.1 add the header file(me_hello_opt.h) to me_phase_manager.h + - 2.2 register the phase in me_phase_manager.cpp, like this: +```c++ +MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEHdse, hdse) +// the macro suffix CANSKIP indicates that this phase can be skipped. +// first parameter tells the implement class and the second parameter is +// the phase name, which could be used in option like: dump-phase(s), +// skip-phases, skip-after; and it is used to configure the phase list that will run in phasemanager. ++MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MEHello, hello) +MAPLE_TRANSFORM_PHASE_REGISTER_CANSKIP(MELfoIVCanon, ivcanon) +``` + +- 3 add the new phase into run list. +modify the phase.def file, like this: +```c++ +... +ADDMAPLEMEPHASE("dse", MeOption::optLevel >= 2) +ADDMAPLEMEPHASE("hello", MeOption::optLevel >= 2) +ADDMAPLEMEPHASE("analyzector", JAVALANG) +... +``` +- 4 add the cpp file into corresponding build.gn file. +- 5 compile and test new phase. +maple --run=me:mpl2mpl:mplcg --option="--O2 :--O2 --quiet:--O2 --quiet" test.mpl +we can see that our new hello phase is performed after dse successfully. +``` +>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Optimizing Function < VEC_invariant_p_base_space id=5471 >--- +---Preparing Function < VEC_invariant_p_base_space > [1] --- +---Run Phase [ mecfgbuild ]--- +---Run Phase [ cfgOpt ]--- +---Run Phase [ loopcanon ]--- + ++ trigger phase [ dominance ] + ++ trigger phase [ identloops ] +---Run Phase [ splitcriticaledge ]--- +---Run Phase [ ssatab ]--- +---Run Phase [ aliasclass ]--- +---Run Phase [ ssa ]--- + ++ trigger phase [ dominance ] +---Run Phase [ dse ]--- + ++ trigger phase [ fsaa ] +---Run Phase [ hello ]--- +hello opt on function: VEC_invariant_p_base_space +---Run Phase [ hprop ]--- + ++ trigger phase [ irmapbuild ] +---Run Phase [ valueRangePropagation ]--- + ++ trigger phase [ identloops ] +---Run Phase [ hdse ]--- +---Run Phase [ epre ]--- + ++ trigger phase [ dominance ] + ++ trigger phase [ identloops ] + == epre invokes [ hdse ] == +---Run Phase [ rename2preg ]--- +---Run Phase [ lpre ]--- +---Run Phase [ storepre ]--- +---Run Phase [ copyprop ]--- +---Run Phase [ hdse ]--- +---Run Phase [ pregrename ]--- +---Run Phase [ bblayout ]--- +---Run Phase [ meemit ]--- + +``` \ No newline at end of file diff --git a/doc/en/DeveloperGuide.md b/doc/en/DeveloperGuide.md new file mode 100644 index 0000000000000000000000000000000000000000..7b604e2540d76f5c04f236e94ee23ebed3a2717e --- /dev/null +++ b/doc/en/DeveloperGuide.md @@ -0,0 +1,102 @@ +# Developer Guide + +By referring to this document, you can download the OpenArkCompiler source code to compile it. At the same time, this document also provide the guide of static code analysis to developers. + +## Prerequisites + +Prepare development environment by referring to Environment Configuration. + + +## Downloading Source Code + +Download address: . +You can download the OpenArkCompiler source code in `Clone` or `Download` mode. +> Note: The download directory of the source code is openarkcompiler by default. + + +## Compiling Source Code + + +Run the following command in the openarkcompiler directory to compile OpenArkCompiler. The output path is openarkcompiler/output/TYPE/bin, TYPE: aarch64-clang-release by default. + +``` +source build/envsetup.sh +make setup +make +``` +Command description: + +- `source build/envsetup.sh`: Initialize the environment and add the toolchain path openarkcompiler/output/bin of OpenArkCompiler to environment variables. +- `make`: Compile the release version of OpenArkCompiler. +- `make BUILD_TYPE=DEBUG`: Compile the debug version of OpenArkCompiler. + +Run the following command in the openarkcompiler directory to compile OpenArkCompiler and maple runtime. The output path is openarkcompiler/output/TYPE, TYPE: aarch64-clang-release by default. + +``` +source build/envsetup.sh arm release +make setup +make libcore +``` + +命令说明: + +- `make libcore` Compile the release version of OpenArkCompiler; +- `make libcore BUILD_TYPE=DEBUG` Compile the debug version of OpenArkCompiler; + +In addition, the OpenArkCompiler also provides a shell script which contains the command to compile OpenArkCompiler. The developer can run the script in the openarkcompiler directory to compile OpenArkCompiler. The command to run the script: + +``` +source build/build.sh +``` + +## Compiling Sample + +The Java basic library is required for OpenArkCompiler to compile a sample. The following uses the Java basic library provided by the Android OS to describe the sample compilation process. + +**Preparing basic library** + +- Download the Android code and compile it locally to obtain the libcore JAR package. The Android 9.0.0_r45 version is recommended. + +- Gitee also provides the compiled libcore JAR file. Download address: https://gitee.com/mirrors/java-core/ . + +**Generating the libjava-core.mplt file** + +Before compilation, create the libjava-core directory in the openarkcompiler directory, copy the java-core.jar file to the libjava-core directory, and run the following commands in the openarkcompiler directory: + +``` +source build/envsetup.sh +make +cd libjava-core +jbc2mpl -injar java-core.jar -out libjava-core +``` + +After the execution is complete, the libjava-core.mplt file is generated in the directory. + +**Compiling sample code** + +The sample code is in the openarkcompiler/samples directory. + +Take the samples/helloworld/ code as an example. Run the following command in the openarkcompiler/ directory: + +``` +source build/envsetup.sh +make +cd samples/helloworld/ +make +``` + +## Static code analysis + +This part will guide you to do the static code analysis by using the clang-tidy. After the code is changed, the static code analysis will check the coding specifications to improve the code quality. + +Before the static code analysis, we need compiled the OpenArkCompiler. After that, using the code of src/maple_driver as the tested directory, run the following commands in the openarkcompiler directory: + +``` +cp output/compile_commands.json ./ +./tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/share/clang/run-clang-tidy.py -clang-tidy-binary='./tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/bin/clang-tidy' -clang-apply-replacements-binary='./tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/bin/clang-apply-replacements' src/maple_driver/ +``` +Command description: + +- `cp output/compile_commands.json ./`: Copy the compile_commands.json in the output directory to the openarkcompiler directory, it is required by the clang-tidy, it contains the compile commands of OpenArkCompiler. + +- `./tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/share/clang/run-clang-tidy.py`: Call the run-clang-tidy.py which is the parallel clang-tidy runner. The `./tools/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-16.04/` directory is the directory of the release package of clang compiler. The `-clang-tidy-binary` set the path of clang-tidy binary. The `-clang-apply-replacements-binary` set the path of the clang-apply-replacements binary which is requried by the run-clang-tidy.py. The `src/maple_driver/` is the tested code directory. diff --git a/doc/en/DeveloperGuide4Utility.md b/doc/en/DeveloperGuide4Utility.md new file mode 100644 index 0000000000000000000000000000000000000000..d1262234c1b994a87719154a4f44881422282683 --- /dev/null +++ b/doc/en/DeveloperGuide4Utility.md @@ -0,0 +1,431 @@ +# Application Manual of Maple General Modules + +# Cast + +## `instance_of` and `safe_cast`. + +In principle, `RTTI`, that is, `dynamic_cast`, must be disabled for the use of `C++` in `maple`. The compiler system is complex. It will make the object relationship more complex to cast from a class object to a subclass object by class design. Therefore, the `maple` code implementation introduces the following designs: + +```c++ +SubClass *sub = nullptr; +if (base.Type() == SubType) { + sub = static_cast(base); +} +``` + +A property field is designed to implement the binding between a class and its subclass, achieving the same effect as `dynamic_cast`. + +However, this method has some disadvantages. First, whereas the binding relationship between `SubType` and `SubClass` is static and determined by the designer, the caller needs to make the relationship explicit, resulting in strong dependency. Second, not all scenarios are as intuitive as type comparison. Callers are prone to make mistakes in complex scenarios, causing shotgun surgery in later code rectification. Therefore, the `safe_cast` is designed. The designer registers the casting relationship. A caller only needs to call the `dynamic_cast` method. + +### Registration method. + +Use the `REGISTER_SAFE_CAST` macro to complete the registration. The declaration is as follows: + +```c++ +#define REGISTER_SAFE_CAST(type, condition) +``` + +`type` is a subclass type (assumed as `B`), and `condition` is a Boolean expression that matches `B` and all its subclasses. Example: + +```c++ +class A; +class B : A; +class C : B; +REGISTER_SAFE_CAST(B, from.Kind() == B || from.Kind() == C); +REGISTER_SAFE_CAST(C, from.Kind() == C); +``` + +`from` is a formal parameter name of a type transferred by an expression. + +*Note:* + +*- The registration supports the casting from a subclass to a class and from a class to a subclass.* + +*- `condition` can be any Boolean expression. However, the designer must ensure that it complies with the inheritance relationship to avoid casting of non-inheritance relationships.* + +*- For a complex `condition`, using `kind ==` to indicate an inheritance relationship tree is not recommended. Optimization needs to be considered. For example, the range of `kind` needs to be organized, and a specific bit flag needs to be used to achieve quick matching.* + +#### Application scenarios. + +1. For scenarios where only one type is matched: + +```c++ +SubClass *sub = safe_cast(base); +if (sub == nullptr) { + // TODO +} +``` + +2. For scenarios where multiple types are matched: + +```c++ +if (instanceof(base)) { + auto *sub = static_cast(base); + // TODO +} else if (instanceof(base)) { + auto *sub = static_cast(base); + // TODO +} +... +``` + +*Note:* + +*- In scenarios where types have been correctly identified, such as `switch case`, use `static_cast`.* + +*- The return value of `safe_cast` is always a pointer, indicating whether the casting is successful.* + +*- If the input is a pointer, both `instance_of` and `safe_cast` check whether the input is null. Therefore, if `base` is not null, the reference is preferentially transferred.* + +# Container + +## `Ptr` + +`Ptr` simulates the behavior of a native pointer, but removes support for array operations. + +In this method, data is validated in the construction and assignment operations, so that a feature of a pointer object needs to be validated only during construction, and does not need to be validated again during transfer and use, thereby reducing overheads of repeated check. + +```c++ +template +using PtrCheckerType = void (*)(const T*); + +template +constexpr void CheckNothing(const T*) {} + +template Check = CheckNothing> +class Ptr; +``` + +As shown in the preceding example, the default validation behavior of `Ptr` is not checked. + +```c++ +template < typename T> +using XXXPtr = utils::Ptr>; +``` + +In the preceding example, the validated pointer objects in different scenarios can be defined, which are called security pointers. + +*Note: The preceding behavior is extended based on the requirements of `safe_ptr`. However, `safe_ptr` is more complex than the common `Ptr` scenario because it is specific to the validity of a pointer rather than features of a pointer object.* + +## `safe_ptr` + +For details, see the definition of `Ref` in the CPPCodingTalkAboutPointer. The `operator.` in `c++` cannot be overloaded. As a result, the `Ref` object cannot be built. However, the `safe_ptr` object, which is a non-null pointer object equivalent to the `Ref` object, can be defined. + +### Scenario: Container members such as arrays and dictionaries. + +For details, see the CPPCodingTalkAboutPointer. + +To solve the problem that `operator.` cannot be overloaded, the `ToRef` tool capability in `Utility` will be extended, ensuring that the pointer does not have overhead and is securely casted into a reference. It may have the following features: + +```c++ +template +constexpr T &ToRef(safe_ptr ptr) { + return *ptr; +} +``` + +*Note: For containers that are frequently used, containers of the `ref_xxx` series will be encapsulated to replace the `safe_ptr` application scenarios.* + +### Scenario: Object members. + +This is an unexpected scenario discovered after `safe_ptr` is developed. + +The compiler cannot generate default copies and transfers for classes of reference data members. However, the copy and transfer capabilities are required in many scenarios. In this case, the common method is to store the classes as pointer members. However, pointer members bring the following problems: + +1. When a pointer member is accessed, the validity of the pointer needs to be identified. +2. The behavior can be controllable by defining member roles during refactoring and evolution. However, the role that uses the member may not be notified, which may further cause hidden bugs. + +If `safe_ptr` is used to replace a raw pointer and `ToRef` is used to convert the reference at the `safe_ptr` dereference position (`ToRef` of a raw pointer has extra overheads), the preceding problems can be avoided. + +*Note: `safe_ptr` is designed as a container or object member. `&` is used for transferring function parameters.* + +## `mpl_iterator` + +The original name of `mpl_iterator` is `iterator`, but the name is the same as that of `using iterator` in the container. Therefore, the `mpl` prefix is added. + +Taking the design of the `ref_xxx` container and possible expansion of the small talk series in the future into consideration, repeated iterator design is troublesome. Therefore, a unified iterator container that continuously evolves is abstracted, which uses `mpl_iterator_traits` to quickly implement the iterator of the new container with a few configurations. + +Based on the iterator requirements of `ref_vector`, members of `mpl_iterator_traits` are designed as follows: + +```c++ +template +struct mpl_iterator_traits { + using iterator_category = typename std::iterator_traits::iterator_category; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using pointer = typename std::iterator_traits::pointer; + using reference = typename std::iterator_traits::reference; + + static reference operator_dereference(Iterator iter) { + return *iter; + }; + + static Iterator operator_arrow(Iterator iter) { + return iter; + } + + static reference operator_bracket(Iterator iter, difference_type n) { + return iter[n]; + } +}; + +``` + +## `ref_vector` + +For details, see the definition of `ref_vector` in the CPPCodingTalkAboutPointer. + +Use the pointer array: `std::vector`. + +```c++ + int a = 0, b = 1; + + std::vector data; + data.push_back(&a); + data.push_back(&b); + ASSERT_EQ(*data[0], 0); + ASSERT_EQ(*data[1], 1); +``` + +Refactored as a reference array: `utils::ref_vector`. +```c++ + int a = 0, b = 1; + + ref_vector data; + data.push_back(a); + data.push_back(b); + ASSERT_EQ(data[0], 0); + ASSERT_EQ(data[1], 1); +``` + +## `Index` + +`Index` is designed to meet the static security requirements of basic types. + +For example, `GStrIdx`, `UStrIdx`, and `U16StrIdx` are involved in calculation in service code, and their interfaces are similar. Their bottom layers are `uint32`. If all formal parameters are defined as `uint32`, it will be a disaster. The caller must be careful, but it is difficult to avoid transferring incorrect data. So static type conflict is used and the compiler checks the correctness of the use, which will greatly reduce the errors. + +To define a static type, you only need to define different tags, as shown in the following example: + +```c++ +class GStrTag; +using GStrIdx = utils::Index; + +class UStrTag; +using UStrIdx = utils::Index; + +class U16StrTag; +using U16StrIdx = utils::Index; +``` + +# Generalize Pattern + +## `ObjectFactory` + +The `ObjectFactory` is an encapsulation for an abstract factory and is used to solve the following problems: + +1. Eliminate large functions with high cyclomatic complexity in code, such as `switch... case` and `if... else if...`. These functions are difficult to maintain and extend and have low flexibility.* (Note: Analyze semantics and design well instead of rigidly solving problems, for example, use template mode to implement design isolation instead of code isolation.)* + +2. The use of a factory will invert the dependency, making it easier to isolate the caller from the designer and the designer from each other. + +Example: + +```c++ +// Defines a key to mark the product type to be created by the factory. +enum class ObjectType { + kPlus, + kMinus +}; + +//Defines interfaces and interface protocols that all products must implement. +class Base { + public: + virtual ~Base() = default; + virtual int32_t DoIt(int32_t lhs, int32_t rhs) const = 0; +}; + +// Defines a factory by using ObjectType as the search keyword. Base indicates the interface protocol, and int32_t indicates the parameter type of all product constructor functions. +using TestObjectFactory = ObjectFactory; + +// Key, interface, and factory must be visible to both the registrant and caller. Therefore, the key may be in the .h file or summarized in the .cpp file. +// Products can be registered in different .cpp files as long as they can be registered in the factory. +// Defines a product. +class ObjectPlus : public Base { + public: + // Constructor function agreed upon during factory definition. + explicit ObjectPlus(int32_t base) : base(base) {} + virtual ~ObjectPlus() = default; + + // Conventions for defining interfaces. + virtual int32_t DoIt(int32_t lhs, int32_t rhs) const override { + return base + lhs + rhs; + } + + private: + int32_t base; +}; + +// Defines the product, which may be in another .cpp file. +class ObjectMinus : public Base { + public: + explicit ObjectMinus(int32_t base) : base(base) {} + virtual ~ObjectMinus() = default; + + virtual int32_t DoIt(int32_t lhs, int32_t rhs) const override { + return base + lhs - rhs; + } + + private: + int32_t base; +}; + +// Registers a product. The product registration mode varies depending on the distribution and loading of keys, interfaces, factories, and products. Ensure that the registration is successful. +// Initializes the static variable to ensure registration. +bool RegisterObject() { + RegisterFactoryObject(); + RegisterFactoryObject(); +} +static auto testObjectFactory = RegisterObject(); + +TEST(TestFactory, ObjectFactory) { + // Obtains a product object. Check whether the value is null. The example is omitted. + auto obj = CreateProductObject(ObjectType::kPlus, 10); + ASSERT_EQ(obj->DoIt(1, 2), 13); + obj = CreateProductObject(ObjectType::kMinus, 10); + ASSERT_EQ(obj->DoIt(1, 2), 9); +} +``` + +## `FunctionFactory` + +Similar to `ObjectFactory`, `FunctionFactory` is used to simplify the complexity of abstract factories. In most scenarios, `FunctionFactory` is easier to compile and use. + +Example: + +```c++ +// Defines a key to mark the product type to be created by the factory. +enum class FunctionType { + kPlus, + kMinus +}; + +// Defines the interface and factory by using the FunctionType as the search keyword and the int32_t(int32_t, int32_t) as the function protocol. +using TestFunctionFactory = FunctionFactory; + +// Defines a product. +int32_t Plus(int32_t lhs, int32_t rhs) { + return lhs + rhs; +} + +// Defines the product, which may be in another .cpp file. +int32_t Minus(int32_t lhs, int32_t rhs) { + return lhs - rhs; +} + +// Registers a product. The product registration mode varies depending on the distribution and loading of keys, interfaces, factories, and products. Ensure that the registration is successful. +// Uses the singleton pattern to ensure registration. +bool RegisterFunction() { + RegisterFactoryFunction(FunctionType::kPlus, Plus); + RegisterFactoryFunction(FunctionType::kMinus, Minus); +} +void AutoFunctionLoader() { + static auto testObjectFactor = RegisterFunction(); +} + +TEST(TestFactory, TestAll) { + // Loads the product. + AutoFunctionLoader(); + + // Obtains a product object. Check whether the value is null. The example is omitted. + auto func = CreateProductFunction(FunctionType::kPlus); + ASSERT_EQ(func(1, 2), 3); + func = CreateProductFunction(FunctionType::kMinus); + ASSERT_EQ(func(1, 2), -1); +} +``` + + +# Utility + +## `ToRef` + +In the scenario where pointers transfer parameters in the new code and refactored code of Ark Compiler, it is expected that all pointers are validated and then transferred to the called function in reference mode. In most cases, the called function should not bear the risk of null pointers in function parameters and the overhead of judgment. + +The common format is as follows (In the example, `DoIt` and `Run` can be used as third-party interfaces and cannot be changed): + +```c++ +A *DoIt(B &b); +void Run(B *b) { + CHECK_NULL_FATAL(b); + // ... + A *a = DoIt(*b); + CHECK_NULL_FATAL(a); + a->Do; +} +``` + +If most pointers are transferred into a reference type once obtained: + +```c++ +A *DoIt(B &b); +void Run(B *b) { + B &bRef = utils::ToRef(b); + // ... + A &a = utils::ToRef(DoIt(bRef)); + a.Do; +} +``` + +If `b` is used only once: + +```c++ +A *DoIt(B &b); +void Run(B *b) { + // ... + A &a = utils::ToRef(DoIt(utils::ToRef(b))); + a.Do; +} +``` + +## `bit_field_v`&`lbit_field_v` + +Using a bit to mark a state switch combination is a design method that saves memory and can be efficiently encoded. Generally, the enumeration definition or constant definition is written as follows: + +```c++ +enum BBAttr : uint32 { + kBBAttrIsEntry = 0x02, + kBBAttrIsExit = 0x04, + kBBAttrWontExit = 0x08, + kBBAttrIsTry = 0x10, + kBBAttrIsTryEnd = 0x20, + kBBAttrIsJSCatch = 0x40, + kBBAttrIsJSFinally = 0x80, + kBBAttrIsCatch = 0x0100, + kBBAttrIsJavaFinally = 0x0200, + kBBAttrArtificial = 0x0400, + kBBAttrIsInLoop = 0x0800, + kBBAttrIsInLoopForEA = 0x1000 +}; +``` + +This design is obviously intended to use bits to record some attribute information, but the bits are obscure and difficult to maintain and read. + +Therefore, a clearer design is required. + +```c++ +enum BBAttr : uint32 { + kBBAttrIsEntry = utils::bit_field_v<1>, + kBBAttrIsExit = utils::bit_field_v<2>, + kBBAttrWontExit = utils::bit_field_v<3>, + kBBAttrIsTry = utils::bit_field_v<4>, + kBBAttrIsTryEnd = utils::bit_field_v<5>, + kBBAttrIsJSCatch = utils::bit_field_v<6>, + kBBAttrIsJSFinally = utils::bit_field_v<7>, + kBBAttrIsCatch = utils::bit_field_v<8>, + kBBAttrIsJavaFinally = utils::bit_field_v<9>, + kBBAttrArtificial = utils::bit_field_v<10>, + kBBAttrIsInLoop = utils::bit_field_v<11>, + kBBAttrIsInLoopForEA = utils::bit_field_v<12> +}; +``` + +`bit_field_v`:`uint32` and `lbit_field_v`:`uint64` are supported. In the future, `sbit_field_v`:`uint16` and `bbit_field_v`:`uint8` will be added as required. diff --git a/doc/en/DevelopmentPreparation.md b/doc/en/DevelopmentPreparation.md new file mode 100644 index 0000000000000000000000000000000000000000..912e9653876f608fe98634ac787ffcdd36dd1aef --- /dev/null +++ b/doc/en/DevelopmentPreparation.md @@ -0,0 +1,72 @@ +## Environment Configuration + +## Recommended Hardware: + +- 2 GHz dual-core processor or higher + +- 2 GB system memory or higher + +- 200 GB available disk space + +## Recommended Development Environment + +Install a 64-bit Ubuntu (Ubuntu 16.04, 18.04 or 20.04 is required). + +``` +sudo apt-get -y install clang llvm lld libelf-dev libssl-dev python qemu openjdk-8-jre-headless openjdk-8-jdk-headless cmake +sudo apt-get -y install git build-essential zlib1g-dev libc6-dev-i386 g++-multilib gcc-multilib linux-libc-dev:i386 + +Ubuntu 16.04: +sudo apt-get -y install gcc-5-aarch64-linux-gnu g++-5-aarch64-linux-gnu + +Ubuntu 18.04: +sudo apt-get -y install gcc-7-aarch64-linux-gnu g++-7-aarch64-linux-gnu + +Ubuntu 20.04: +sudo apt-get -y install gcc-9-aarch64-linux-gnu g++-9-aarch64-linux-gnu libncurses5 +``` + +## Auto Installation of Tools + +``` +source build/envsetup.sh arm release +make setup + +Note: the following steps are for reference only. All required tools are installed during above "make setup" +``` + +## Installing and Configuring Clang (for Compiling the OpenArkCompiler Code) + +Download **clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04** +LLVM download address: http://releases.llvm.org/download.html#10.0.0 + +Place the downloaded files in the `openarkcompiler/tools` directory, open the `openarkcompiler/build/config.gni` file, and set the three variables `GN_C_COMPILER`, `GN_CXX_COMPILER`, and `GN_AR_COMPILER` to the path where Clang is located. For example: + +``` +GN_C_COMPILER = "${MAPLE_ROOT}/tools/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04/bin/clang" +GN_CXX_COMPILER = "${MAPLE_ROOT}/tools/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04/bin/clang++" +GN_AR_COMPILER = "${MAPLE_ROOT}/tools/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04/bin/llvm-ar" +``` + +${MAPLE_ROOT} is the root directory of the OpenArkCompiler source code. + +## Installing and configuring Ninja and GN + +Download **Ninja(v1.10.0)** and **GN(Linux Version)** +Ninja download address: https://github.com/ninja-build/ninja/releases +GN download address: https://gitee.com/xlnb/gn_binary + +Place the executable programs of GN and Ninja in the openarkcompiler/tools directory, modify these two files to be executable. + +``` +cd openarkcompiler/tools +chmod 775 gn +chmod 775 ninja +``` + +Open the openarkcompiler/Makefile file, and set the two variables GN and NINJA to the path where the executable programs of GN and Ninja are located. For example, + +``` +GN := ${MAPLE_ROOT}/tools/gn/gn +NINJA := ${MAPLE_ROOT}/tools/ninja/ninja +``` diff --git a/doc/en/MapleDriverOverview.md b/doc/en/MapleDriverOverview.md new file mode 100644 index 0000000000000000000000000000000000000000..6d29efbd0fdbcded50fc5ba54aec3b378f5bf417 --- /dev/null +++ b/doc/en/MapleDriverOverview.md @@ -0,0 +1,48 @@ +# Maple Driver Overview +## Introduction +This document describes current state of Maple Driver. This includes design, usage, goals and internal implementation. + +## Goals +The Maple driver is intended to meet requirements of a good compiler driver such as Clang. In other words it should be: +- Flexible to support new features +- Efficient with low overhead +- Easy to use + +The end goal of driver development is full support of gcc options with direct integration into the CMake build system. + +## Design and Implementation + +### Design overview + +The diagram below shows significant components of the Maple Driver architecture as well as their realtions to one another. The red components represent essential driver parts(classes, methods), the blue components are output/input data structures, the green components are important helper classes. + +![](media/MapleDriverStructure.png) + +### Driver stages + +The driver functionality can be divded into five stages: + +**1. Parsing options** + +The input command-line argument strings are firstly checked for correctness of format and transformed into pairs of key-value, keys are then checked for a match in `usages` multimap (previously created from a helper data structure) of `OptionParser`. The `Option` class also contains `Descriptor` data structure, describing required parsing details for option argument with some additional data. Then the argument is parsed. The driver expects to understand all available options. The result is then written in the `options` vector of the `OptionParser` class. + + +**2. Filling MplOptions** + +After parsing input, `MplOptions` is filled depending on the results: firstly the run type is decided to be either automatic or custom (depends on the presence of `--run` option), then input files are initialized and checked for validity. If the run type is automatic Maple Driver will also configure the code generation pipeline by itself(you will recieve assembler file as the final output), depending on the extension of the first input file. Then other options are handled, including `--option`, value of which must contain options for all phases of compilation, the value is parsed using the same methods and data structures that were used in parsing of general options, the results are pushed in map `exeOptions` of the `MplOptions` class. Then the Maple Driver attempts to open input file and in case of success moves on to the next stage. + +**3. Compiler Selection** + +Upon the completion of the previous stage Maple Driver triggers `CompilerFactory` class constructor, which creates classes of supported compilers and saves pointers to all of them in `supportedCompilers` data structure. + +**4. Phase specific option construction** + +`CompilerFactory` calls `Compile` methods of selected Compilers, during which default and user-determined options are constructed and written in a string. The main problem is the translation of commands from one style to another, some driver components, like `MplcgCompiler` require their own methods to work correctly, while others, like `AsCompiler` work with just a handful of options and their main purpose is to determine the path of the executable to call and pass on their input and output arguments. + +However, `MaplecombCompiler` and `MplcgCompiler` require special pipeline, they do not call executables and pass on command-line to them, but interact the with input file using `MIRModule`, `MIRParser` and `DriverRunner` classes. `MIRModule` is a data structure, purpose of which is similar to `MplOptions`, two previously mentioned compilers store crucial data in it (name of the input file, source language, etc.); `MIRParser` as the name implies exists to parse Maple IR; `DriverRunner` is an orchestrator that works with two previous data structures and also stores options for phases it is responsible for and other data, required in compilation. + +**5. Execute** + +After that the command-line and full path to executable is redirected to the `Exe` method of the `SafeExe` class, where it is handled and executed via child process. In case of `MaplecombCompiler` and `MplcgCompiler` the `Run` method of the `DriverRunner` is called and issues job to the Phase Manger. + + diff --git a/doc/en/MapleIRDesign.md b/doc/en/MapleIRDesign.md new file mode 100644 index 0000000000000000000000000000000000000000..ac0ca70085cb5c81e02c52c78786515f52f150f4 --- /dev/null +++ b/doc/en/MapleIRDesign.md @@ -0,0 +1,2616 @@ +``` +# +# Copyright (C) [2020-2021] Futurewei Technologies, Inc. All rights reverved. +# +# Licensed under the Mulan Permissive Software License v2. +# You can use this software according to the terms and conditions of the MulanPSL - 2.0. +# You may obtain a copy of MulanPSL - 2.0 at: +# +# https://opensource.org/licenses/MulanPSL-2.0 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the MulanPSL - 2.0 for more details. +# +``` + +MAPLE IR Specification +====================== + +Contents {#contents .TOC-Heading} +======== + +[1 Introduction 7](#introduction) + +[2 Program Representation in MAPLE IR 8](#program-representation-in-maple-ir) + +[2.1 Symbol Tables 9](#symbol-tables) + +[2.2 Primitive Types 9](#primitive-types) + +[2.3 Constants 10](#constants) + +[2.4 Identifiers (\$ % &) 10](#identifiers) + +[2.5 Pseudo-registers (%) 11](#pseudo-registers) + +[2.6 Special Registers (%%) 11](#special-registers) + +[2.7 Statement Labels (@) 11](#statement-labels) + +[2.8 Storage Accesses 11](#storage-accesses) + +[2.9 Aggregates 12](#aggregates) + +[2.9.1 Arrays 12](#arrays) + +[2.9.2 Structures 12](#structures) + +[3 Instruction Specification 13](#instruction-specification) + +[3.1 Storage Access Instructions 13](#storage-access-instructions) + +[3.1.1 dassign 13](#dassign) + +[3.1.2 dread 14](#dread) + +[3.1.3 iassign 14](#iassign) + +[3.1.4 iread 14](#iread) + +[3.1.5 iassignoff 14](#iassignoff) + +[3.1.6 iassignfpoff 14](#iassignfpoff) + +[3.1.7 iassignpcoff 14](#iassignpcoff) + +[3.1.8 ireadoff 15](#ireadoff) + +[3.1.9 ireadfpoff 15](#ireadfpoff) + +[3.1.10 ireadpcoff 15](#ireadpcoff) + +[3.1.11 regassign 15](#regassign) + +[3.1.12 regread 15](#regread) + +[3.2 Leaf Opcodes 15](#leaf-opcodes) + +[3.2.1 addrof 15](#addrof) + +[3.2.2 addroflabel 16](#addroflabel) + +[3.2.3 addroffunc 16](#addroffunc) + +[3.2.4 addroffpc 16](#addroffpc) + +[3.2.5 conststr 16](#conststr) + +[3.2.6 conststr16 16](#conststr16) + +[3.2.7 constval 16](#constval) + +[3.2.8 sizeoftype 16](#sizeoftype) + +[3.3 Unary Expression Opcodes 16](#unary-expression-opcodes) + +[3.3.1 abs 16](#abs) + +[3.3.2 bnot 17](#bnot) + +[3.3.3 extractbits 17](#extractbits) + +[3.3.4 iaddrof 17](#iaddrof) + +[3.3.5 lnot 17](#lnot) + +[3.3.6 neg 17](#neg) + +[3.3.7 recip 17](#recip) + +[3.3.8 sext 17](#sext) + +[3.3.9 sqrt 17](#sqrt) + +[3.3.10 zext 17](#zext) + +[3.4 Type Conversion Expression Opcodes 18](#type-conversion-expression-opcodes) + +[3.4.1 ceil 18](#ceil) + +[3.4.2 cvt 18](#cvt) + +[3.4.3 floor 18](#floor) + +[3.4.4 retype 18](#retype) + +[3.4.5 round 18](#round) + +[3.4.6 trunc 18](#trunc) + +[3.5 Binary Expression Opcodes 19](#binary-expression-opcodes) + +[3.5.1 add 19](#add) + +[3.5.2 ashr 19](#ashr) + +[3.5.3 band 19](#band) + +[3.5.4 bior 19](#bior) + +[3.5.5 bxor 19](#bxor) + +[3.5.6 cand 19](#cand) + +[3.5.7 cior 19](#cior) + +[3.5.8 cmp 19](#cmp) + +[3.5.9 cmpg 19](#cmpg) + +[3.5.10 cmpl 20](#cmpl) + +[3.5.11 depositbits 20](#depositbits) + +[3.5.12 div 20](#div) + +[3.5.13 eq 20](#eq) + +[3.5.14 ge 20](#ge) + +[3.5.15 gt 20](#gt) + +[3.5.16 land 20](#land) + +[3.5.17 lior 20](#lior) + +[3.5.18 le 20](#le) + +[3.5.19 lshr 20](#lshr) + +[3.5.20 lt 21](#lt) + +[3.5.21 max 21](#max) + +[3.5.22 min 21](#min) + +[3.5.23 mul 21](#mul) + +[3.5.24 ne 21](#ne) + +[3.5.25 rem 21](#rem) + +[3.5.26 shl 21](#shl) + +[3.5.27 sub 21](#sub) + +[3.6 Ternary Expression Opcodes 21](#ternary-expression-opcodes) + +[3.6.1 select 21](#select) + +[3.7 N-ary Expression Opcodes 22](#n-ary-expression-opcodes) + +[3.7.1 array 22](#array) + +[3.7.2 intrinsicop 22](#intrinsicop) + +[3.7.3 intrinsicopwithtype 22](#intrinsicopwithtype) + +[3.8 Control Flow Statements 22](#control-flow-statements) + +[3.8.1 Hierarchical control flow statements 22](#hierarchical-control-flow-statements) + +[3.8.1.1 doloop 23](#doloop) + +[3.8.1.2 dowhile 23](#dowhile) + +[3.8.1.3 foreachelem 23](#foreachelem) + +[3.8.1.4 if 23](#if) + +[3.8.1.5 while 23](#while) + +[3.8.2 Flat control flow statements 24](#flat-control-flow-statements) + +[3.8.2.1 brfalse 24](#brfalse) + +[3.8.2.2 brtrue 24](#brtrue) + +[3.8.2.3 goto 24](#goto) + +[3.8.2.4 igoto 24](#igoto) + +[3.8.2.5 multiway 24](#multiway) + +[3.8.2.6 return 24](#return) + +[3.8.2.7 switch 24](#switch) + +[3.8.2.8 rangegoto 25](#rangegoto) + +[3.8.2.9 indexgoto 25](#indexgoto) + +[3.9 Call Statements 25](#call-statements) + +[3.9.1 call 25](#call) + +[3.9.2 callinstant 26](#callinstant) + +[3.9.3 icall 26](#icall) + +[3.9.4 intrinsiccall 26](#intrinsiccall) + +[3.9.5 intrinsiccallwithtype 26](#intrinsiccallwithtype) + +[3.9.6 xintrinsiccall 26](#xintrinsiccall) + +[3.10 Java Call Statements 26](#java-call-statements) + +[3.10.1 virtualcall 26](#virtualcall) + +[3.10.2 superclasscall 26](#superclasscall) + +[3.10.3 interfacecall 26](#interfacecall) + +[3.11 Calls with Return Values Assigned 27](#calls-with-return-values-assigned) + +[3.11.1 callassigned 27](#callassigned) + +[3.12 Exceptions Handling 27](#exceptions-handling) + +[3.12.1 jstry 28](#jstry) + +[3.12.2 javatry 28](#javatry) + +[3.12.3 cpptry 29](#cpptry) + +[3.12.4 throw 29](#throw) + +[3.12.5 jscatch 29](#jscatch) + +[3.12.6 javacatch 29](#javacatch) + +[3.12.7 cppcatch 29](#cppcatch) + +[3.12.8 finally 29](#finally) + +[3.12.9 cleanuptry 30](#cleanuptry) + +[3.12.10 endtry 30](#endtry) + +[3.12.11 gosub 30](#gosub) + +[3.12.12 retsub 30](#retsub) + +[3.13 Memory Allocation and Deallocation 30](#memory-allocation-and-deallocation) + +[3.13.1 alloca 30](#alloca) + +[3.13.2 decref 31](#decref) + +[3.13.3 decrefreset 31](#decrefreset) + +[3.13.4 free 31](#free) + +[3.13.5 gcmalloc 31](#gcmalloc) + +[3.13.6 gcmallocjarray 31](#gcmallocjarray) + +[3.13.7 gcpermalloc 31](#gcpermalloc) + +[3.13.8 incref 32](#incref) + +[3.13.9 malloc 32](#malloc) + +[3.13.10 stackmalloc 32](#stackmalloc) + +[3.13.11 stackmallocjarray 32](#stackmallocjarray) + +[3.14 Other Statements 32](#other-statements) + +[3.14.1 assertge 32](#assertge) + +[3.14.2 assertlt 32](#assertlt) + +[3.14.3 assertnonnull 32](#assertnonnull) + +[3.14.4 eval 33](#eval) + +[3.14.5 checkpoint 33](#checkpoint) + +[3.14.6 membaracquire 33](#membaracquire) + +[3.14.7 membarrelease 33](#membarrelease) + +[3.14.8 membarfull 33](#membarfull) + +[3.14.9 syncenter 33](#syncenter) + +[3.14.10 syncexit 33](#syncexit) + +[4 Declaration Specification 34](#declaration-specification) + +[4.1 Module Declaration 34](#module-declaration) + +[4.1.1 entryfunc 34](#entryfunc) + +[4.1.2 flavor 34](#flavor) + +[4.1.3 globalmemmap 34](#globalmemmap) + +[4.1.4 globalmemsize 34](#globalmemsize) + +[4.1.5 globalwordstypetagged 34](#globalwordstypetagged) + +[4.1.6 globalwordsrefcounted 35](#globalwordsrefcounted) + +[4.1.7 id 35](#id) + +[4.1.8 import 35](#import) + +[4.1.9 importpath 35](#importpath) + +[4.1.10 numfuncs 35](#numfuncs) + +[4.1.11 srclang 35](#srclang) + +[4.2 Variable Declaration 35](#variable-declaration) + +[4.3 Pseudo-register Declarations 36](#pseudo-register-declarations) + +[4.4 Type Specification 36](#type-specification) + +[4.4.1 Incomplete Type Specification 37](#incomplete-type-specification) + +[4.5 Type Declaration 37](#type-declaration) + +[4.6 Java Class and Interface Declaration 38](#java-class-and-interface-declaration) + +[4.7 Function Declaration 39](#function-declaration) + +[4.7.1 funcsize 39](#funcsize) + +[4.7.2 framesize 39](#framesize) + +[4.7.3 moduleid 39](#moduleid) + +[4.7.4 upformalsize 39](#upformalsize) + +[4.7.5 formalwordstypetagged 40](#formalwordstypetagged) + +[4.7.6 formalwordsrefcounted 40](#formalwordsrefcounted) + +[4.7.7 localwordstypetagged 40](#localwordstypetagged) + +[4.7.8 localwordsrefcounted 40](#localwordsrefcounted) + +[4.8 Initializations 40](#initializations) + +[4.9 Type Parameters 41](#type-parameters) + +Introduction +============ + +MAPLE IR is an internal program representation to support program +compilation, analysis, optimization and execution. The name MAPLE comes +from the acronym "Multiple Architecture and Programming Language +Environment". Because information in the source program may be useful +for program analysis and optimization, MAPLE IR aims to provide +information about the source program that is as complete as possible. + +Program information is represented in two parts: the declaration part +for defining the program constructs and the execution part specifying +the program code. The former is often collectively referred to as the +symbol table, though there can be different types of tables. + +MAPLE IR is target-independent. It is not pre-disposed towards any +specific target processor or processor characteristic. + +MAPLE IR can be regarded as the ISA of a virtual machine (VM). The MAPLE +VM can be regarded as a general purpose processor that takes MAPLE IR as +input and directly executes the program portion of the MAPLE IR. + +MAPLE IR is the common representation for programs compiled from +different programming languages, which include general purpose languages +like C, C++, Java and Javascript. MAPLE IR is extensible. As additional +languages, including domain-specific languages, are compiled into MAPLE +IR, more constructs will be added to represent constructs unique to each +language. + +The compilation process can be viewed as a gradual lowering of the +program representation from high level human perceivable form to low +level machine executable form. MAPLE IR is capable of supporting all +known program analyses and optimizations, owing to its flexibility of +being able to represent program code at multiple semantic levels. At the +highest level, MAPLE IR exhibits more variety of program constructs, +corresponding to abstract language operations or constructs unique to +the language it is translated from. As a result, the code sequences at +the higher levels are shorter. Language or domain specific optimizations +are best performed at the higher levels. At the higher levels, there are +also constructs that are hierarchical in nature, like nested blocks and +expression trees. Nearly all program information is retained at the +highest level. + +As compilation proceeds, MAPLE IR is gradually lowered so that the +granularity of its operations corresponds more closely to the +instructions of a general purpose processor. The code sequences become +longer as many high-level constructs are disallowed. At the same time, +the program constructs become less hierarchical. It is at the lower +levels where general purpose optimizations are performed. In particular, +at the lowest level, MAPLE IR instructions map nearly one-to-one to the +machine instructions of the mainstream processor ISAs. This is where the +effects of optimizations at the IR level are maximized, as each +eliminated operation will have the corresponding effect on the target +machine. At the lowest level, all operations, including type conversion +operations, are explicitly expressed at the IR level so that they can be +optimized by the compiler. The lowest level of MAPLE IR is also its +executable form, where the program structure is flat to allow the +sequential form of program execution. Expression trees are laid out in +prefix form and they are evaluated by the execution engine using the +stack machine model. + +Program Representation in MAPLE IR +================================== + +The internal representation of MAPLE IR consists of tables for the +declaration part and tree nodes for the execution part. In the execution +part, each tree node represents one MAPLE IR instruction, and is just +large enough to store the instruction's contents. Externally, MAPLE IR +can exist in either binary or ASCII formats. The binary format is a +straightforward dump of the byte contents of the internal program data +structures. The ASCII form is editable, which implies that it is +possible to program in MAPLE IR directly. The ASCII form of MAPLE IR has +a layout similar to the C language. Declarations are followed by +executable code. Expressions are displayed in in-fix notation, using +parentheses to explicitly indicate the nesting relationships. + +The language front-end compiles a source file into a MAPLE IR file. +Thus, each MAPLE IR file corresponds to a compilation unit, referred to +as a *module*. A module is made up of declarations at the global scope. +Among the declarations are functions. Inside each function are +declarations at the local scope followed by the executable code of the +function. + +There are three kinds of executable nodes in MAPLE IR: + +1. Leaf nodes - Also called terminal nodes, these nodes denote a value + at execution time, which may be a constant or the value of a storage + unit. + +2. Expression nodes - An expression node performs an operation on its + operands to compute a result. Its result is a function of the values + of its operands and nothing else. Each operand can be either a leaf + node or another expression node. Expression nodes are the internal + nodes of expression trees. + +3. Statement nodes - These represent the flow of control. Execution + starts at the entry of the function and continues sequentially + statement by statement until a control flow statement is executed. + Apart from modifying control flow, statements can also modify data + storage in the program. A statement node has operands that can be + leaf, expression or statement nodes. + +In all the executable nodes, the opcode field specifies the operation of +the node, followed by additional field specification relevant to the +opcode. The operands for the node are specified inside parentheses +separated by commas. The general form is: + +``` + opcode fields (opnd0, opnd1, opnd2) +``` + +For example, the C statement \"a = b\" is translated to the **dassign** +node that assigns the right hand side operand b to a . + +``` + dassign $a (dread i32 $b) +``` + +In the declaration part, each declaration is a statement. Each +declaration or execution statement must start a new line, and each line +cannot contain more than one statement node. A statement node can occupy +more than one line. The character \'\#\' can appear anywhere to indicate +that the contents from the \'\#\' to the end of the line are comments. + +Symbol Tables +------------- + +Program information that is of declarative nature is stored in the +symbol table portion of the IR. Having the executable instructions refer +to the symbol tables reduces the amount of information that needs to be +stored in the executable instructions. For each declaration scope, there +is a main table called the Symbol Table that manages all the +user-defined names in that scope. This implies one global Symbol Table +and a local Symbol Table for each function declared in the file. The +various types of symbol entries correspond to the kinds of constructs +that can be assigned names, including: + +1. Types + +2. Variables + +3. Functions (either prototypes or with function bodies) + +In the ASCII format, the IR instructions refer to the various symbols by +their names. In the binary representation, the symbols are referred to +via their table indices.. + +Primitive Types +--------------- + +Primitive types can be regarded as pre-defined types supported by the +execution engine such that they can be directly operated on. They also +play a part in conveying the semantics of operations, as addresses are +distinct from unsigned integers. The number in the primitive type name +indicates the storage size in bits. + +The primitive types are: + +``` + no type - void + signed integers - i8, i16, i32, i64 + unsigned integers - u8, u16, u32, u64 + booleans- u1 + addresses - ptr, ref, a32, a64 + floating point numbers - f32, f64 + complex numbers - c64, c128 + aggregates - agg + javascript types: + dynany + dynu32 + dyni32 + dynundef + dynnull + dynhole + dynbool + dynptr + dynf64 + dynf32 + dynstr + dynob + SIMD types -- v2i64, v4i32, v8i16, v16i8, v2f64, v4f32 + unknown +``` + +An instruction that produces or operates on values must specify the +primitive type in the instruction, as the type is not necessarily +implied by the opcode. There is the distinction between result type and +operand type. Result type can be regarded as the type of the value as it +resides in a machine register, because arithmetic operations in the +mainstream processor architectures are mostly register-based. When an +instruction only specifies a single primitive type, the type specified +applies to both the operands and the result. In the case of instructions +where the operand and result types may differ, the primitive type +specified is the result type, and a second field is added to specify the +operand type. + +Some opcodes are applicable to non-primitive (or derived) types, as in +an aggregate assignment. When the type is derived, agg can be used. In +such cases, the data size can be found by looking up the type of the +symbol . + +The primitive types *ptr* and *ref* are the target-independent types for +addresses. *ref* conveys the additional semantics that the address is a +reference to a run-time managed block of memory or object in the heap. +Uses of ptr or ref instead of a32 or a64 allow the IR to be independent +of the target machine by not manifesting the size of addresses until the +later target-dependent compilation phases. + +The primitive type unknown is used by the language front-end when the +type of a field in an object has not been fully resolved because the +full definition resides in a different compilation unit. + +Constants +--------- + +Constants in MAPLE IR are always of one of the primitive types. + +Integer and address (pointer) types can be specified in decimal or in +hexadecimal using the 0x prefix. + +Floating point types can be specified in hexadecimal or as floating +point literal as in standard C. + +Single characters enclosed in single quotes can be used for i8 and u8 +constants. + +String literals are enclosed in double quotes. + +For the complex and SIMD types, the group of values are enclosed in +square brackets separated by commas. + +Identifiers (\$ % &) +-------------------- + +In ASCII MAPLE IR, standalone identifier names are regarded as keywords +of the MAPLE IR language. To refer to entries in the symbol tables, +identifier names must be prefixed. + +**\$** - Identifiers prefixed with \'\$\' are global variables and will +be looked up in the global Symbol Table. + +**%** - Identifiers prefixed with \'%\' are local variables and will be +looked up in the local Symbol Table. + +**&** - Identifiers prefixed with \'&\' are function or method names and +will be looked up in the Functions Table. The major purpose of these +prefixes is to avoid name clash with the keywords (opcode names, etc.) +in the IR. + +Pseudo-registers (%) +-------------------- + +Pseudo-registers can be regarded as local variables of a primitive type +whose addresses are never taken. They can be declared implicitly by +their appearances. The primitive type associated with a pseudo-register +is sticky. + +Because pseudo-registers can only be created to store primitive types, +the use of field IDs does not apply to them. Pseudo-registers are +referred to by the \'%\' prefix followed by a number. This distinguishes +them from other local variables that are not pseudo-registers, as their +names cannot start with a number. + +The compiler will promote variables to pseudo-registers. To avoid the +loss of high level type information when a variable is promoted to +pseudo-registers, reg declarations are used to provide the type +information associated with the pseudo-registers. + +Special Registers (%%) +---------------------- + +Special registers are registers with special meaning. They are all +specified using %% as prefix. **%%SP** is the stack pointer and **%%FP** +the frame pointer in referencing the stack frame of the current +function. **%%GP** is the global pointer used for addressing global +variables. **%%PC** is the program counter. **%%thrownval** stores the +thrown value after throwing an exception. + +Special registers **%%retval0**, **%%retval1**, **%%retval2**, etc. are +used for fetching the multiple values returned by a call. They are +overwritten by each call, and should only be read at most once after +each call. They can assume whatever is the type of the return value. + +Statement Labels (@) +-------------------- + +Label names are prefixed with \'@\' which serves to identify them. Any +statement beginning with a label name defines that label as referring to +that text position. Labels are only referred to locally by goto and +branch statements. + +Storage Accesses +---------------- + +Since MAPLE IR is target-independent, it does not exhibit any +pre-disposition as to how storage are allocated for the program +variables. It only applies rules defined by the language regarding +storage. + +In general, there are two distinct kinds of storage accesses: direct and +indirect. Direct accesses do not require any run-time computation to +determine the exact address location. Indirect accesses require address +arithmetic before the location can be determined. Indirect accesses are +associated with pointer dereferences and arrays. Direct accesses are +associated with scalar variables and fixed fields inside structures. + +Direct accesses can be mapped to pseudo-register if the variable or +field has no alias. Indirect accesses cannot be mapped to +pseudo-registers unless the computed address does not change. + +In MAPLE IR, **dassign** and **dread** are the opcodes for direct +assignments and direct references; **iassign** and **iread** are the +opcodes for indirect assignments and indirect references. + +Aggregates +---------- + +Aggregates (or composites) are either structures or arrays. They both +designate a grouping of storage elements. In structures, the storage +elements are designated by field names and can be of different types and +sizes. Classes and objects are special kinds of structures in +object-oriented programming languages. In arrays, the same storage +element is repeated a number of times and the elements are accessed via +index (or subscript). + +### Arrays + +Array subscripting designates address computation. Since making the +subscripts stand out facilitate data dependency analysis and other loop +oriented optimizations, MAPLE IR represents array subscripting using the +special **array** opcode, which returns the address resulting from the +subscripting operation. For example, \"a\[i\] = i\" is: +``` + # <* [10] i32> is pointer to array of 10 ints + iassign <* i32> ( + array a32 <* [10] i32> (addrof a32 $a, dread i32 $i), + dread i32 \$i) +``` + +and \"x = a\[i,j\]\" is: + + +``` + # <* [10] [10] i32 indicates pointer to a 10x10 matrix of ints + dassign $x ( + iread i32 <* i32> ( + array a32 <* [10] [10] i32> (addrof a32 $a, dread i32 $i, dread i32 $j))) +``` + +### Structures + +Fields in a structure can be accessed directly, but use of **dassign** +or **dread** on a structure would refer to the entire structure as an +aggregate. Thus, we extend **dassign**, **dread**, **iassign** and +**iread** to take an additional parameter called field-ID. + +In general, for a top level structure, unique field-IDs can be assigned +to all the fields contained inside the structure. Field-ID 0 is assigned +to the top level structure (the entire structure). Field-ID is also 0 if +it is not a structure. As each field is visited, the field-ID is +incremented by 1. If a field is a structure, that structure is assigned +a unique field-ID, and then field-ID assignments continue with the +fields inside the nested structure. If a field is an array, the array is +assigned only one field-ID. + +Note that if a structure exists both standalone and nested inside +another structure, the same field inside the structure will be assigned +different field-IDs because field-ID assignment always starts from the +top level structure. + +Three kinds of structures are supported: **struct**, **class** and +**interface**. + +A **struct** corresponds to the struct type in C, and is specified by +the **struct** keyword followed by a list of field declarations enclosed +by braces, as in: +``` + struct { + @f1 i32, + @f2 <$structz> } # $structz is the type name of another struct +``` +A **class** corresponds to the class type in Java, to provide single +inheritances. The syntax is the same as struct except for an additional +type name specified after the class keyword that specifies the class it +inherits from. Fields in the parent class are also referred to via +field-IDs, as if the first field of the derived class is the parent +class. In other words, the parent class is treated like a sub-structure. +``` + class <$classz> { # $classz is the parent of this class being defined + @f1 i32, + @f2 f32 } +``` +Unrelated to storage, structures can contain member function prototypes. +The list of member function prototypes must appear after all the fields +have been specified. Each member function name starts with &, which +indicates that it is a function prototype. The prototype specification +follows the same syntax as ordinary function prototypes. + +An **interface** corresponds to the interface type in Java, and has the +same form as class, except that it cannot be instantiated via a var +declaration, and fields declared inside it are always statically +allocated. More details are provided later in this document. + +Instruction Specification +========================= + +In MAPLE IR expression trees, we use parentheses or braces to +distinguish operands from the other fields of an instruction, to +facilitate visualization of the nested structure of MAPLE IR. The +expression operands of each instruction are always enclosed by +parentheses, using commas to separate the operands. Statement operands +are indicated via braces. + +Storage Access Instructions +--------------------------- + +A memory access instruction either loads a memory location to a register +for further processing, or store a value from register to memory. For +load instructions, the result type given in the instruction is the type +of the loaded value residing in register. If the memory location is of +size smaller than the register size, the value being loaded must be of +integer type, and there will be implicit zero- or sign-extension +depending on the signedness of the result type. + +### dassign + +syntax: dassign \ \ (\) + +\ is computed to return a value, which is then assigned to +variable \. If \ is not 0, then the variable must +be a structure, and the assignment only applies to the specified field. +If \ is of type agg, then the size of the structure must +match. If \ is a primitive integer type, the assigned +variable may be smaller, resulting in a truncation. If\ is +not specified, it is assumed to be 0. + +### dread + +syntax: dread \ \ \ + +Variable \ is read from its storage location. If the variable +is a structure, then \ should specify agg. If \ +is not 0, then the variable must be a structure, and instead of reading +the entire variable, only the specified field is read. If the field +itself is also a structure, then \ should also specify agg. +If \ is not specified, it is assumed to be 0. + +### iassign + +syntax: iassign \ \ (\, \) + +\ is computed to return an address. \ gives the high +level type of \ and must be a pointer type. \ is +computed to return a value, which is then assigned to the location +specified by \. If \ is not 0, then the computed +address must correspond to a structure, and the assignment only applies +to the specified field. If \ is of type agg, then the size of +the structure must match. The size of the location affected by the +assignment is determined by what \ points to. If \ is +a primitive integer type, the assigned location (according to what +\ points to) may be smaller, resulting in a truncation. If +\ is not specified, it is assumed to be 0. + +### iread + +syntax: iread \ \ \ (\) + +The content of the location specified by the address computed from the +address expression \ is read (dereferenced) as the given +primitive type. \ gives the high level type of \ and +must be a pointer type. If the content dereferenced is a structure (as +given by what \ points to), then \ should specify +agg. If \ is not 0, then \ must specify pointer to a +structure, and instead of reading the entire structure, only the +specified field is read. If the field itself is also a structure, then +\ should also specify agg. If \ is not specified, +it is assumed to be 0. + +### iassignoff + +syntax: iassignoff \ \ (\, +\) + +\ is computed to return a scalar value, which is then +assigned to the memory location formed by the addition of \ in +bytes to \. \ gives the type of the stored-to +location, which also specifies the size of the affected memory location. + +### iassignfpoff + +syntax: iassignfpoff \ \ (\) + +\ is computed to return a scalar value, which is then +assigned to the memory location formed by the addition of \ in +bytes to %%FP. \ gives the type of the stored-to location, +which also specifies the size of the affected memory location. This is +the same as iassignoff where its \ is %%FP. + +### iassignpcoff + +syntax: iassignpcoff \ \ (\) + +\ is computed to return a scalar value, which is then +assigned to the memory location formed by the addition of \ in +bytes to %%PC.  \ gives the type of the stored-to location, +which also specifies the size of the affected memory location + +### ireadoff + +syntax: ireadoff \ \ (\) + +\ must be of scalar type. \ in bytes is added to +\ to form the address of the memory location to be read as +the specified scalar type. + +### ireadfpoff + +syntax: ireadfpoff \ \ + +\ must be of scalar type. \ in bytes is added to +%%FP to form the address of the memory location to be read as the +specified scalar type. This is the same as ireadoff where its +\ is %%FP. + +### ireadpcoff + +syntax: ireadpcoff \ \ + +\ must be of scalar type.  \ in bytes is added to +%%PC to form the address location to be read as the specified scalar +type. + +### regassign + +syntax: regassign \ \ (\) + +\ is computed to return a scalar value, which is then +assigned to the pseudo or special register given by \. +\ gives the type of the register, which also specifies the +size of the value being assigned. + +### regread + +syntax: regread \ \ + +The given pseudo or special register is read in the scalar type +specified by \. + +Leaf Opcodes +------------ + +dread and regread are leaf opcodes for reading the contents of +variables. The following are additional leaf opcodes: + +### addrof + +syntax: addrof \ \ \ + +The address of the variable \ is returned. \ must +be either ptr, a32 or a64. If \ is not 0, then the variable +must be a structure, and the address of the specified field is returned +instead. + +### addroflabel + +syntax: addroflabel \ \ + +The text address of the label is returned. \ must be either +a32 or a64. + +### addroffunc + +syntax: addroffunc \ \ + +The text address of the function is returned. \ must be +either a32 or a64. + +### addroffpc + +syntax: addroffpc \ \ + +\ must be either a32 or a64.  \ in bytes is added +to %%PC to form the address value being returned. + +### conststr + +syntax: conststr \ \ + +The address of the string literal is returned. \ must be +either ptr, a32 or a64. The string must be stored in read-only memory. + +### conststr16 + +syntax: conststr16 \ \ + +The address of the string literal composed of 16-bit wide characters is +returned. \ must be either ptr, a32 or a64. The string must +be stored in read-only memory. + +### constval + +syntax: constval \ \ + +The specified constant value of the given primitive type is returned. +Since floating point values cannot be represented in ASCII without loss +of accuracy, they can be specified in hexadecimal form, in which case +\ indicates the floating point type. + +### sizeoftype + +syntax: sizeoftype \ \ + +The size in bytes of \ is returned as an integer constant value. +Since type size is in general target-dependent, use of this opcode +preserves the target independence of the program code. + +Unary Expression Opcodes +------------------------ + +These are opcodes with a single operand. + +### abs + +syntax: abs \ (\) + +The absolute value of the operand is returned. + +### bnot + +syntax: bnot \ (\ \ \ (\) + +The bitfield starting at bit position \ with \ number +of bits is extracted and then sign- or zero- extended to form the +primitive integer given by \. The operand must be of integer +type and must be large enough to contain the specified bitfield. + +### iaddrof + +syntax: iaddrof \ \ \(\) + +\ gives the high level type of \ and must be a +pointer type. The address of the pointed-to item is returned. +\ must be either ptr, a32 or a64. If \ is not 0, +then \ must specify a pointer to a structure, and the address of +the specified field in the structure is returned instead. This operation +is of no utility if \ is 0, as it will just return the +value of \. + +### lnot + +syntax: lnot \ (\) + +If the operand is not 0, 0 is returned. If the operand is 0, 1 is +returned. + +### neg + +syntax: neg \ (\) + +The operand value is negated and returned. + +### recip + +syntax: recip \ (\) + +The reciprocal of the operand is returned. \ must be a +floating-point type. + +### sext + +syntax: sext \ \ (\) + +Sign-extend the integer by treating the integer size as being \ +bits. This can be regarded as a special case of extractbits where the +bitfield is in the lowest bits. The primitive type \ +stays the same. + +### sqrt + +syntax: sqrt \ (\) + +The square root of the operand is returned. \ must be a +floating-point type. + +### zext + +syntax: zext \ \ (\) + +Zero-extend the integer by treating the integer size as being \ +bits. This can be regarded as a special case of extractbits where the +bitfield is in the lowest bits. The primitive type \ +stays the same. + +Type Conversion Expression Opcodes +---------------------------------- + +Type conversion opcodes are unary in nature. With the exception of +retype, they all require specifying both the from and to types in the +instruction. Conversions between integer types of different sizes +require the cvt opcode. + +Conversion between signed and unsigned integers of the same size does +not require any operation, not even retype. + +### ceil + +syntax: ceil \ \ (\) + +The floating point value is rounded towards positive infinity. + +### cvt + +syntax: cvt \ \ (\) + +Convert the operand\'s value from \ to \. This +instruction must not be used If the sizes of the two types are the same +and the conversion does not result in altering the bit contents. + +### floor + +syntax: floor \ \ (\) + +The floating point value is rounded towards negative infinity. + +### Retype + +syntax: retype \ \ (\) + +\ is converted to \ which has derived type \ +without changing any bits. The size of \ and \ must +be the same. \ may be of aggregate type. + +### round + +syntax: round \ \ (\) + +The floating point value is rounded to the nearest integer. + +### trunc + +syntax: trunc \ \ (\) + +The floating point value is rounded towards zero. + +Binary Expression Opcodes +------------------------- + +These are opcodes with two operands. + +### add + +syntax: add \ (\, \) + +Perform the addition of the two operands. + +### ashr + +syntax: ashr \ (\, \) + +Return \ with its bits shifted to the right by \ bits. +The high order bits shifted in are set according to the original sign +bit. + +### band + +syntax: band \ (\, \) + +Perform the bitwise AND of the two operands. + +### bior + +syntax: bior \ (\, \) + +Perform the bitwise inclusive OR of the two operands. + +### bxor + +syntax: bxor \ (\, \) + +Perform the bitwise exclusive OR of the two operands. + +### cand + +syntax: cand \ (\, \) + +Perform the logical AND of the two operands via short-circuiting. If +\ yields 0, \ is not to be evaluated. The result is +either 0 or 1. + +### cior + +syntax: cior \ (\, \) + +Perform the logical inclusive OR of the two operands via +short-circuiting. If \ yields 1, \ is not to be +evaluated. The result is either 0 or 1. + +### cmp + +syntax: cmp \ \ (\, \) + +Performs a comparison between \ and \. If the two +operands are equal, return 0. If \ is less than \, +return -1. Otherwise, return +1. + +### cmpg + +syntax: cmpg \ \ (\, \) + +Same as cmp, except 1 is returned if any operand is NaN. + +### cmpl + +syntax: cmpl \ \ (\, \) + +Same as cmp, except -1 is returned if any operand is NaN. + +### depositbits + +syntax: depositbits \ \ \ (\, +\) + +Creates a new integer value by depositing the value of \ into +the range of bits in \ that starts at bit position \ +and runs for \ bits. \ must be large enough to contain +the specified bitfield. + +Depending on the size of \ relative to the bitfield, there may +be truncation. The rest of the bits in \ remains unchanged. + +### div + +syntax: div \ (\, \) + +Perform \ divided by \ and return the result. + +### eq + +syntax: eq \ \ (\, \) + +If the two operands are equal, return 1. Otherwise, return 0. + +### ge + +syntax: ge \ \ (\, \) + +If \ is greater than or equal to \, return 1. Otherwise, +return 0. + +### gt + +syntax: ge \ \ (\, \) + +If \ is greater than \, return 1. Otherwise, return 0. + +### land + +syntax: land \ (\, \) + +Perform the logical AND of the two operands. The result is either 0 or +1. + +### lior + +syntax: lior \ (\, \) + +Perform the logical inclusive OR of the two operands. The result is +either 0 or 1. + +### le + +syntax: le \ \ (\, \) + +If \ is less than or equal to \, return 1. Otherwise, +return 0. + +### lshr + +syntax: lshr \ (\, \) + +Return \ with its bits shifted to the right by \ bits. +The high order bits shifted in are set to 0. + +### lt + +syntax: lt \ \ (\, \) + +If \ is less than \, return 1. Otherwise, return 0. + +### max + +syntax: max \ (\, \) + +Return the maximum of \ and \. + +### min + +syntax: min \ (\, \) + +Return the minimum of \ and \. + +### mul + +syntax: mul \ (\, \) + +Perform the multiplication of the two operands. + +### ne + +syntax: ne \ \ (\, \) + +If the two operands are not equal, return 1. Otherwise, return 0. + +### rem + +syntax: rem \ (\, \) + +Return the remainder when \ is divided by \. + +### shl + +syntax: shl \ (\, \) + +Return \ with its bits shifted to the left by \ bits. +The low order bits shifted in are set to 0. + +### sub + +syntax: sub \ (\, \) + +Subtract \ from \ and return the result. + +Ternary Expression Opcodes +-------------------------- + +These are opcodes with three operands. + +### select + +syntax: select \ (\, \, \) + +\ must be of integer type. \ and \ must be of +the type given by \. If \ is not 0, return +\. Otherwise, return \. + +N-ary Expression Opcodes +------------------------ + +These are opcodes that can have any number of operands. + +### array + +syntax: array \ \ \ (\, +\, . . . , \) + +\ is the base address of an array in memory. \ is +either 0 or 1, indicating bounds-checking needs not be performed or +needs to be performed respectively. \ gives the high-level +type of a pointer to the array. Return the address resulting from +row-major order multi-dimentional indexing operation, with the indices +represented by \ onwards. Since arrays must have at least one +dimension, this opcode must have at least two operands. + +### intrinsicop + +syntax: intrinsicop \ \ (\, \..., +\) + +\ indicates an intrinsic function that has no side effect +whose return value depends only on the arguments (a pure function), and +thus can be represented as an expression opcode. + +### intrinsicopwithtype + +syntax: intrinsicopwithtype \ \ \ +(\, \..., \) + +This is the same as intrinsicop except that it takes on an additional +high level type argument specified by \. + +Control Flow Statements +----------------------- + +Program control flows can be represented by either hierarchical +statement structures or a flat list of statements. Hierarchical +statement structures are mostly derived from constructs in the source +language. Flat control flow statements correspond more closely to +processor instructions. Thus, hierarchical statements exist only in high +level MAPLE IR. They are lowered to the flat control flow statements in +the course of compilation. + +A statement block is indicated by multiple statements enclosed inside +the braces \'{\' and \'}\'. Such statement blocks can appear any where +that a statement is allowed. In hierarchical statements, nested +statements are specified by such statement blocks. Statement blocks +should only associated with hierarchical control flow statements. + +In MAPLE IR, each statement must start on a new line. The use of +semicolon is not needed, or even allowed, to indicate the end of +statements. + +### Hierarchical control flow statements + +#### doloop + +syntax: +``` + doloop (, , ) { + } +``` + +\ specifies a local integer scalar variable with no alias. +\ must be an integer expression. \ is initialized +with \. \ must be a single comparison operation +representing the termination test. The loop body is represented by +\, which specifies the list of statements to be executed as +long as \ evaluates to true. After each execution of the +loop body, \ is incremented by \ and the loop is +tested again for termination. + +#### dowhile + +syntax: +``` + dowhile { + + } () +``` +Execute the loop body represented by \, and while +\ evaluates to non-zero, continue to execute \. +Since \ is tested at the end of the loop body, the loop body +is executed at least once. + +#### foreachelem + +syntax: +``` + foreach { + } +``` + +This is an abstract loop form where \ is an array-like +variable representing a collection of uniform elements, and \ +specifies a variable whose type is the element type of +\. The loop body is represented by \, +which specifies the list of statements to be repeated for each element +of \ expressed via \. This statement will be +lowered to a more concrete loop form based on the type of +\. + +#### if + +syntax: +``` + if () { + } + else { + } +``` +If \ evaluates to non-zero, control flow passes to the +\ statements. Otherwise, control flow passes to the +\ statements. If there is no else part, \"else { +\ }\" can be omitted. + +#### while + +syntax: +``` + while () { + } +``` +This implements the while loop. While \ evaluates to +non-zero, the list of statements represented by \ are +repeatedly executed. Since \ is tested before the first +execution, the loop body may execute zero times. + +### Flat control flow statements + +#### brfalse + +syntax: brfalse \ (\) + +If \ evaluates to 0, branch to \. Otherwise, fall +through. + +#### brtrue + +syntax: brtrue \ (\) + +If \ evaluates to non-0, branch to \. Otherwise, fall +through. + +#### goto + +syntax: goto \ + +Transfer control unconditionally to \. + +#### igoto + +syntax: igoto (\) + +\ must evaluate to the address of a label. Transfer control unconditionally to the evaluated label address. + +#### multiway + +syntax: +``` + multiway () { + (): goto + (): goto + ... + (): goto } +``` + +\ must be of type convertible to an integer or a string. +Following \ is a table of pairs of expression tags and +labels. When executed, it evaluates \ and then searches the +table for a match of the evaluated value of \ with the evaluated +value of each expression tag \ in the listed order. On a match, +control is transferred to the corresponding label. If no match is found, +control is transferred to \. The evaluation of the +expression tags must not incur side effect. Depending on the resolved +type of \, this statement will be lowered to either the switch +statement or a cascade of if statements. + +#### return + +syntax: return (\, . . ., \) + +Return from the current PU with the multiple return values given by the +operands. The list of operands can be empty, which corresponds to no +return value. The types of \ must be compatible with the list of +return types according to the declaration or prototype of the PU. + +#### switch + +syntax: +``` + switch () { + : goto + : goto + ... + : goto } +``` + +\ must be of integer type. After \, it specifies +a table of pairs of constant integer values (tags) and labels. When +executed, it searches the table for a match with the evaluated value of +\ and transfers control to the corresponding label. If no match +is found, control is transferred to \. There must not be +duplicate entries for the constant integer values. It is up to the +compiler backend to decide how to actually generate code for this +statement after analyzing the tag distribution in the table. + +#### rangegoto + +syntax: +``` + rangegoto ( { + : goto + : goto + ... + : goto } +``` + +This is the lowered form of switch that explicitly designates its +execution to be handled by the jump table mechanism. \ must be +of integer type. After \ follows a table of pairs of +constant integer values and labels. In searching the table for a match +during execution, the evaluated value of \ minus \ +is used during execution so as to cause transfer of control to the +corresponding label. There must be no gap in the constant integer values +specified, and a match is guaranteed within the range of specified +constant integer values, which means the code generator can omit +generation of out-of-range checks. There must be no duplicated entries +for the constant integer values. + +#### indexgoto + +syntax: indexgoto (\ \ + +This is only generated by the compiler as a result of lowering the +switch statement. \ is the name of a compiler-generated +symbol designating a static array, or jump table, which is statically +initialized to store labels. + +Each stored label marks the code corresponding to a switch case. +Execution of this instruction uses the evaluated value of \ to +index into this array and then transfers control to the label stored at +that array element. If the evaluated value of \ is less than 0 +or exceeds the number of entries in the jump table, the behavior is +undefined. + +Call Statements +--------------- + +There are various flavors of procedure invocation. Intrinsics are +library functions known to the compiler. + +### call + +syntax: call \ (\, \..., \) + +Invoke the function while passing the parameters given by the operands. + +### callinstant + +syntax: callinstant \ \ (\, +\..., \) + +Instantiate the given generic function according to instantiation vector +\ and then invoke the function while passing the +parameters given by the operands. + +### icall + +syntax: icall (\, \, \..., \) + +Invoke the function specified indirectly by \, passing the +parameters given by \ onwards. + +### intrinsiccall + +syntax: intrinsiccall \ (\, \..., \) + +Invoke the specified intrinsic defined by the compiler while passing the +parameters given by the operands. + +### intrinsiccallwithtype + +syntax: intrinsiccallwithtype \ \ (\, \..., +\) + +This is the same as intrinsiccall except that it takes on an additional +high level type argument specified by \. + +### xintrinsiccall + +syntax: xintrinsiccall \ (\, \..., +\) + +Invoke the intrinsic specified as an index into a user-defined intrinsic +table while passing the parameters given by the operands. + +Java Call Statements +-------------------- + +The following statements are used to represent Java member function +calls that are not yet resolved. + +### virtualcall + +syntax: virtualcall \ (\, \, \..., +\) + +\ is a pointer to an instance of a class. The class +hierarchy is searched using the specified \ to find the +appropriate virtual method to invoke. The invocation will pass the +remaining operands as parameters. + +### superclasscall + +syntax: superclasscall \ (\, \, \..., +\) + +This is the same as virtualcall except it will not use the class\'s own +virtual method, but the one in its closest superclass that defines the +virtual method. + +### interfacecall + +syntax: interfacecall \ (\, \, \..., +\) + +\ is a method defined in an interface. \ is a +pointer to an instance of a class the implements the interface. The +class is searched using the \ to find the corresponding +method to invoke. The invocation will pass the remaining operands as +parameters. + +There are also virtualcallinstant, superclasscallinstant and +interfacecallinstant for calling generic versions of the methods after +instantiating with the specified instantiation vector. The instantiation +vector is specified after \, as in the callinstant +instruction. + +Calls with Return Values Assigned +--------------------------------- + +MAPLE IR supports calls with any number of return values. All the +various call operations have a corresponding higher-level abstracted +variant such that a single call operation also specify how the multiple +function return values are assigned, without relying on separate +statements to read the %%retval registers. Only assignments to local +scalar variables, fields in local aggregates or pseudo-registers are +allowed. These operations have the same names with the suffix +\"assigned\" added. They are callassigned, callinstantassigned, +icallassigned, intrinsiccallassigned, intrinsiccallwithtypeassigned, +xintrinsiccallassigned, virtualcallassigned, virtualcallinstantassigned, +superclasscallassigned, superclasscallinstantassigned, +interfacecallassigned and interfacecallinstantassigned. Only +callassigned is defined here. The same extension applies to the +definitions of the rest of these call operations. + +### callassigned + +syntax: +``` + callassigned (, ..., ) { + dassign + dassign + ... + dassign } +``` + +Invoke the function passing the parameters given by the operands. After +returning from the call, the multiple return values are assigned to the +scalar variables listed in order. If a specified field-id is not 0, then +the corresponding variable must be an aggregate, and the assignment is +to the field corresponding to the field-id. If a field-id is absent, 0 +is implied. If \ is absent, it means the corresponding return +value is ignored by the caller. If a call has no return value, no +dassign should be listed. + +In the course of compilation, these call instructions may be lowered to +use the special registers %%retval0, retval1, %%retval2, etc. to +indicate how their return values are fetched and used. These special +registers are overwritten by each call. The same special register can +assume whatever is the type of the return value. Each special register +can be read only once after each call. + +Exceptions Handling +------------------- + +Described in this section are the various exception handling constructs +and operations. The try statement marks the entrance to a try block. The +catch statement marks the entrance to a catch block. The finally +statement marks the entrance to a finally block. The endtry statement +marks the end of the composite exception handling constructs that began +with the try. In addition, there are two special types of labels. +Handler labels are placed before catch statements, and finally labels +are placed before finally statements. Handler labels are distinguished +from ordinary labels via the prefix \"\@h@\", while finally labels use +the prefix \"\@f@\". These special labels explicitly shows the +correspondence of try, catch and finally to each other in each +try-catch-finally composite, without relying on block nesting. The +special register %%thrownval contains the value being thrown, which is +the operand of the throw operation that raised the current exception. + +Since different languages have exhibit different semantics or behavior +related to the exception handling constructs, the try and catch opcodes +have different variants distinguished by their language prefices. + +### jstry + +syntax: jstry \ \ + +Executing this statement indicates entry into a Javascript try block. +\ is 0 when there is no catch block associated with the +try. \ is 0 when there is no finally block associated +with the try. Any exception thrown inside this try block will transfer +control to these labels, unless another nested try block is entered. A +finally block if present must be executed to conclude the execution of +the try composite constructs regardless of whether exception is thrown +or not. + +There are three possible scenarios based on the way the +jstry-jscatch-finally composite is written: + +1. jstry-jscatch + +2. jstry-finally + +3. jstry-jscatch-finally + +For case 1, if an exception is thrown inside the try block, control is +transferred to the handler label that marks the catch statement and the +exception is regarded as having been handled. Program flow eventually +exits the try block with a goto statement to the label that marks the +endtry statement. If no exception is thrown, the try block is eventually +exited via a goto statement to the label that marks the endtry +statement. + +For case 2, if an exception is thrown inside the try block, control is +transferred to the finally label that marks the finally statement. But +the exception is regarded as not having been handled yet, and the search +for the throw\'s upper level handler starts. If no exception is thrown +in try block, program flow eventually exits the try block with a gosub +statement to the finally block. Execution in the finally block ends with +a retsub, which returns to the try block and the try block is then +exited via a goto statement to the label that marks the endtry +statement. + +For case 3, if an exception is thrown inside the try block, control is +transferred to the handler label that marks the catch statement as in +case 1. Execution in the catch block ends with a gosub statement to the +finally block. Execution in the finally block ends with a retsub, which +returns to the catch block and the catch block is then exited via a goto +statement to the label that marks the endtry statement. If no exception +is thrown in the try block, program flow eventually exits the try block +with a gosub statement to the finally block, and execution will continue +in the finally block until it executes a retsub, at which time it +returns to the try block and the try block is then exited via a goto +statement to the label that marks the endtry statement. + +### javatry + +syntax: javatry {\ \ . . . +\} + +This is the Java flavor of try, which can have more than one catch block +but no finally block. The entry labels for the catch blocks are listed +in order and enclosed in braces. + +### cpptry + +syntax: cpptry {\ \ . . . +\} + +This is the C++ flavor of try, which can have more than one catch block +but no finally block. The entry labels for the catch blocks are listed +in order and enclosed in braces. + +### throw + +syntax: throw (\) + +Raise a user-defined exception with the given exception value. If this +statement is nested within a try block, control is then transferred to +the label associated with the try, which is either a catch statement or +a finally statement. If this throw statement is nested within a catch +block, control is first transferred to the finally associated with the +catch if any, in which case the finally block will be executed. After it +finishes executing the finally block, the search for the throw\'s upper +level handler starts. If this throw statement is nested within a finally +block, the search for the throw\'s upper level handler starts right +away. If the throw is not nested inside any try block within a function, +the system will look for the first enclosing try block by unwinding the +call stack. If no try block is found, the program will terminate. Inside +the catch block, the thrown exception value can be accessed using the +special register %%thrownval. + +### jscatch + +syntax: \ jscatch + +This marks the start of the catch block associated with a try in +Javascript. The try block associated with this catch block is regarded +to have been exited and the exception is regarded as being handled. If +no exception is thrown inside the catch block, exit from the catch block +is effected by either a gosub statement to a finally label, if there is +a finally block, or a goto statement to endtry. + +### javacatch + +syntax: \ javacatch {\ \ \... \} + +This marks the start of a catch block in Java. The possible types of +thrown value that match this catch block are listed. If none of the +specified types corresponds to the type of the thrown value, control +will pass to the next javacatch. + +### cppcatch + +syntax: \ cppcatch \ + +This marks the start of a catch block in C++, in which each catch block +can only be matched by one type of thrown value. If specified type does +not correspond to the type of the thrown value, control will pass to the +next cppcatch. + +### finally + +syntax: \ finally + +This marks the start of the finally block in Javascript. The finally +block can be entered either via the execution of a gosub statement, or a +throw statement the finally\'s corresponding try block that has no catch +block, or a throw statement in the finally\'s corresponding catch block. +The exit from the finally block can be effected by the execution of +either a retsub or a throw statement in the finally block. If the exit +is via a retsub and if there is outstanding throw yet to be handled, the +search for the throw\'s upper level handler continues. + +### cleanuptry + +syntax: cleanuptry + +This statement is generated in situations where the control is going to +leave the try-catch-finally composite prematurely via jumps unrelated to +exception handling. This statement effects the cleanup work related to +exception handling for the current try-catch-finally composite in +Javascript. + +### endtry + +syntax: \ endtry + +This marks either the end of each try-catch-finally composite or the end +of each javatry block. + +### gosub + +syntax: gosub \ + +Transfer control to the finally block marked by \. This +also has the effect of exiting the try block or catch block which this +statement belongs. It is like a goto, except that the next instruction +is saved. Execution will transfer back to the next instruction when a +retsub statement is executed. This can also be thought of as a call, +except it uses label name instead of function name, and no passing of +parameter or return value is implied. This opcode is only generated from +Javascript. + +### retsub + +syntax: retsub + +This must only occur as the last instruction inside a finally block. If +there is no outstanding throw, control is transferred back to the +instruction following the last gosub executed. Otherwise the search for +the upper level exception handler continues. This opcode is only +generated from Javascript. + +Memory Allocation and Deallocation +---------------------------------- + +The following instructions are related to the allocation and +de-allocation of dynamic memory during program execution. The +instructions with \"gc\" as prefix are associated with languages with +managed runtime environments. + +### alloca + +syntax: alloca \ (\) + +This returns a pointer to the block of uninitialized memory allocated by +adjusting the function stack pointer %%SP, with size in bytes given by +\. This instruction must only appear as the right hand side of +an assignment operation. + +### decref + +syntax: decref (\) + +\ must be a dread or iread of a pointer that refers to an object +allocated in the run-time-managed part of the heap. It decrements the +reference count of the pointed-to object by 1. \ must be of +primitive type ref. + +### decrefreset + +syntax: decrefreset(\) + +\ must be the address of a pointer that refers to an object +allocated in the run-time-managed part of the heap. It decrements the +reference count of the pointed-to object by 1, and then reset the value +of the pointer to null by zeroing its memory location. + +### free + +syntax: free (\) + +The block of memory pointed to by \ is released so it can be +re-allocated by the system for other uses. + +### gcmalloc + +syntax: gcmalloc \ \ + +This requests the memory manager to allocate an object of type \ +with associated meta-data according to the requirements of the managed +runtime. The size of the object must be fixed at compilation time. As +this returns the pointer to the allocated block, this instruction must +only appear as the right hand side of an assignment operation. + +The managed runtime is responsible for its eventual deallocation. + +### gcmallocjarray + +syntax: gcmallocjarray \ \ +(\) + +This requests the memory manager to allocate a java array object as +given by \. The allocated storage must be large enough +to store the number of array elements as given by \. As this +returns the pointer to the allocated block, this instruction must only +appear as the right hand side of an assignment operation. + +The managed runtime is responsible for its eventual deallocation, and +the block size must remain fixed during its life time. + +### gcpermalloc + +syntax: gcpermalloc \ \ + +This requests the memory manager to allocate an object of type \ +in the permanent area of the heap which is not subject to deallocation. +The size of the object must be fixed at compilation time. As this +returns the pointer to the allocated block, this instruction must only +appear as the right hand side of an assignment operation + +### incref + +syntax: incref (\) + +\ must be a dread or iread of a pointer that refers to an object +allocated in the run-time managed part of the heap. It increments the +reference count of the pointed-to object\'s by 1. \ must be of +primitive type ref. + +### malloc + +syntax: malloc \ (\) + +This requests the system to allocate a block of uninitialized memory +with size in bytes given by \. As this returns the pointer to +the allocated block, this instruction must only appear as the right hand +side of an assignment operation. The block of memory remains unavailable +for re-use until it is explicitly freed via the free instruction. + +### stackmalloc + +syntax: stackmalloc \ \ + +This allocates an object of type \ on the function stack frame by +decrementing %%SP. The size of the object must be fixed at compilation +time. As this returns the pointer to the allocated block, this +instruction must only appear as the right hand side of an assignment +operation. + +### stackmallocjarray + +syntax: stackmallocjarray \ \ +(\) + +This allocates a java array object as given by \ on +the function stack frame by decrementing %%SP. The allocated storage +must be large enough to store the number of array elements as given by +\. As this returns the pointer to the allocated block, this +instruction must only appear as the right hand side of an assignment +operation. + +Other Statements +---------------- + +### assertge + +syntax: assertge (\, \) + +Raise an exception if \ is not greater than or equal to +\. This is used for checking if an array index is within range +during execution. \ and \ must be of the same type. + +### assertlt + +syntax: assertlt (\, \) + +Raise an exception if \ is not less than \. This is used +for checking if an array index is within range during execution. +\ and \ must be of the same type. + +### assertnonnull + +syntax: assertnonnull (\) + +Raise an exception if \ is a null pointer, corresponding to the +value 0. + +### eval + +syntax: eval (\) + +\ is evaluated but the result is thrown away. If \ +contains volatile references, this statement cannot be optimized away. + +### checkpoint + +syntax: checkpoint \ + +This instruction serves as a check point, such that when execution +reaches this instruction, it will trigger the indicated action. + +### membaracquire + +syntax: membaracquire + +This instruction acts as both a Load-to-Load barrier and a Load-to-Store +barrier: the order between any load instruction before it and any load +instruction after it must be strictly followed, and the order between +any load instruction before it and any store instruction after it must +be strictly followed. + +### membarrelease + +syntax: membarrelease + +This instruction acts as both a Load-to-Store barrier and a +Store-to-Store barrier: the order between any load instruction before it +and any store instruction after it must be strictly followed, and the +order between any store instruction before it and any store instruction +after it must be strictly followed. + +### membarfull + +syntax: membarfull + +This instruction acts as a barrier to any load or store instruction +before it and any load or store instruction after it. + +### syncenter + +syntax: syncenter (\) + +This instruction indicates entry to a region where the object pointed to +by the pointer \ needs to be synchronized for Java +multi-threading. This means at any time, there cannot be more than one +thread executing in a synchronized region of the same object. Any other +thread attempting to enter a synchronized region of the same object will +be blocked. For the compiler, it implies a barrier to the backward +movement (against the flow of control) of any operation that accesses +the object. + +### syncexit + +syntax: syncexit (\) + +This instruction indicates exit from a region where the object pointed +to by the pointer \ needs to be synchronized for Java +multi-threading. For the compiler, it implies a barrier to the forward +movement (along the flow of control) of any operation that accesses the +object. + +Declaration Specification +========================= + +In this section, we describes the various kinds of statements in the +declaration part of Maple IR. Internally, they are represented by data +structures organized into different kinds of tables. + +Type declarations can be huge and they are often shared by different +modules, MAPLE IR provides the *import* facility to avoid duplicating +type declarations in each MAPLE IR file. MAPLE IR files that store only +type information have .mplt as file suffix. They can then be imported +into each MAPLE IR files that need them via the **import** statement. + +Module Declaration +------------------ + +Each Maple IR file represents a program module, also called compilation +unit, that consists of various declarations at the global scope. The +following directives appear at the start of the Maple IR file and +provide information about the module: + +### entryfunc + +syntax: entryfunc \ + +This gives the name of the function defined in the module that will +serve as the single entry point for the module. + +### flavor + +syntax: flavor \ + +The IR flavor gives information as to how the IR was produced, which in +turn indicates the state of the compilation process. + +### globalmemmap + +syntax: globalmemmap = \[ \ \] + +This specifies the static initialization values of the global memory +block as a list of space-separated 32-bit integer constants. The amount +of initializations should correspond to the memory size given by +globalmemsize. + +### globalmemsize + +syntax: globalmemsize \ + +This gives the size of the global memory block for storing all global +static variables. + +### globalwordstypetagged + +syntax: globalwordstypetagged = \[ \ \] + +This specifies a bitvector initialized to the value specified by the +list of space-separated 32-bit integer constants. The Nth bit in this +bitvector is set to 1 if the Nth word in globalmemmap has a type tag, in +which case the type tag is at the (N+1)th word. + +### globalwordsrefcounted + +syntax: globalwordsrefcounted = \[ \ \] + +This specifies a bitvector initialized to the value specified by the +list of space-separated 32-bit integer constants. The Nth bit in this +bitvector is set to 1 if the Nth word in globalmemmap is a pointer to a +reference-counted dynamically allocated memory block. + +### id + +syntax: id \ + +This gives the unique module id assigned to the module. This id enables +the Maple virtual machine to handle the execution of program code +originating from multiple Maple IR modules. + +### import + +syntax: import \"\\" + +\ is the path name for a MAPLE IR file with suffix .mplt that +only stores type declarations. The contents of this file are imported. +This allows the same type declarations to be shared across multiple +files, and large volumes of type declarations to be organized by files. +Only one level of import is allowed, as .mplt files are not allowed to +have import statements. + +### importpath + +syntax: importpath \"\\" + +This specifies a directory path for the compiler to look for the +imported MAPLE IR files required to complete the compilation. This is +used only in the early compilation phases, before all types and symbol +names have been fully resolved. Each appearance only specifies one +specific path. + +### numfuncs + +syntax: numfuncs \ + +This gives the number of function definitions in the module, excluding +function prototypes. + +### srclang + +syntax: srclang \ + +This gives the source language that produces the Maple IR module. + +Variable Declaration +-------------------- + +syntax: var \ \ \ \ + +The keyword \'var\' designates a declaration statement for a variable. +\ specifies its name, prefixed by \'\$\' or \'%\' based on +whether its scope is global or local respectively. \ is +optional and can be extern, fstatic or pstatic. \ is the type +specification. \ is optional and specifies additional +attributes like volatile, const, alignment, etc. Examples: + +var \$x extern f32 volatile static + +syntax: tempvar \ \ \ +\ + +This is the same as **var** except that it conveys the additional +information that it is a compiler-generated temporary. + +Pseudo-register Declarations +---------------------------- + +syntax: reg \ \ + +The keyword \'reg\' designates a declaration statement for a +pseudo-register. \ specifies the pseudo-register prefixed by +\'%\'. \ is the high level type information. If a pseudo-register +is only of primitive type, its declaration is optional. This statement +is only allowed inside functions as pseudo-registers are of local scope. + +Type Specification +------------------ + +Types are either primitive or derived. Derived types are specified using +C-like tokens, except that the specification is always +right-associative, following a strictly left to right order. Derived +types are distinguished from primitive types by being enclosed in +angular brackets. Derived types can also be thought of as high-level +types. Examples: +``` + var %p <* i32> # pointer to a 32-bit integer + + var %a <[10] i32> # an array of 10 32-bit integers +``` +var %foo \ \# a pointer to a function that takes one i32 +parameter and returns an i32 value (func is a keyword) + +Additional nested angular brackets are not required, as there is no +ambiguity due to the right-associative rule. But the nested angular +brackets can be optionally inserted to aid readability. Thus, the +following two examples are equivalent: +``` + var %q <* <[10] i32>> # pointer to an array of 10 32-bit integers + + var %q <* [10] i32> # pointer to an array of 10 32-bit integers +``` +Inside a struct declaration, field names are prefixed by @. Though label +names also use @ as prefix, there is no ambiguity due to the usage +context between struct field declaration and label usage being distinct. +Example: +``` + var %s # a bitfield of 3 bits +``` +A union declaration has the same syntax as struct. In a union, all the +fields overlap with each other. + +The last field of a struct can be a flexible array member along the line +of the C99 standard, which is an array with variable number of elements. +It is specified with empty square brackets, as in: +``` + var %p <* struct{@f1 i32, + @f2 <[] u16>}> # a flexible array member with unsigned 16-bit integers as elements +``` +Structs with flexible array member as its last field can only be +dynamically allocated. Its actual size is fixed only at its allocation +during execution time, and cannot change during its life time. A struct +with flexible array member cannot be nested inside another aggregate. +During compilation, the flexible array member is regarded as having size +zero. + +Because its use is usually associated with managed runtime, a language +processor may introduce additional meta-data associated with the array. +In particular, there must be some language-dependent scheme to keep +track of the size of the array during execution time. + +When a type needs to be qualified by additional attributes for const, +volatile, restrict and various alignments, they follow the type that +they qualify. These attributes are not regarded as part of the type. If +these attributes are applied to a derived type, they must follow outside +the type angular brackets. Examples: +``` + var %x f64 volatile align(16) # %s is a f64 value that is volatile and + # aligned on 16 byte boundary + var %p <* f32> const volatile # %p is a pointer to a f32 value, and + # %p itself is const and volatile +``` +Alignments are specified in units of bytes and must be power of 2. +Alignment attributes must only be used to increase the natural +alignments of the types, to make the alignments more stringent. For +decreasing alignments, the generator of MAPLE IR must use smaller types +to achieve the effect of packing instead of relying on the align +attribute. + +### Incomplete Type Specification + +Languages like Java allow contents of any object to be referenced +without full definition of the object being available. Their full +contents are to be resolved from additional input files in later +compilation phases. MAPLE IR allows structs, classes and interfaces to +be declared incompletely so their specific contents can be referenced. +Instead of the struct, class and interface keywords, structincomplete, +classincomplete and interfaceincomplete should be used instead. + +Type Declaration +---------------- + +The purpose of type declaration is to associate type names with types so +they can be referred to via their names, thus avoiding repeated +specification of the details of the types. + +syntax: type \ \ + +Type names are also prefixed with either \'\$\' or \'%\' based on +whether the scope is global or local. Example: +``` + type $i32ptr <* i32> # the type $i32ptr is a pointer to i32 +``` +Primitive types are not allowed to be given a different type name. + +Attributes are not allowed in type declaration. + +Once a type name is defined, specifying the type name is equivalent to +specifying the derived type that it stands for. Thus, the use of a type +name should always be enclosed in angular brackets. + +Java Class and Interface Declaration +------------------------------------ + +A Java class designates more than a type, because the class name also +carries the attributes declared for the class. Thus, we support +declaration of Java classes via: + +syntax: javaclass \ \ \ + +\ must have \'\$\' as prefix as class names always have global +scope. For example: +``` + # a java class named "Puppy" with a single field "color" and attributes public and final + javaclass $Puppy public final +``` +A **javaclass** name should not be regarded as a type name as it +contains additional attribute information. It cannot be enclosed in +angular brackets as it cannot be referred to as a type. + +A java interface has the same form as the class type, being able to +extend another interface, but unlike class, an interface can extend +multiple interfaces. Another difference from class is that an interface +cannot be instantiated. Without instantiation, the data fields in +interfaces are always allocated statically. For example, +``` + interface <$interfaceA> { # this interface extends interfaceA + @s1 int32, # data fields inside interfaces always statically allocated + &method1(int32) f32 } # a method declaration +``` +MAPLE IR handles an interface declaration as a type declaration. Thus, +the above can be specified after the type keyword to be associated with +a type name. Separately, the **javainterface** keyword declares the +symbol associated with the interface: + +syntax: javainterface \ \ \ + +\ must have \'\$\' as prefix as interface names always have +global scope. For example: +``` + # $IFA is an interface with a single method &amethod + javainterface $IFA public static +``` +Again, a **javainterface** name should not be regarded as a type name, +as it is a symbol name. When a class implements an interface, it +specifies the **javainterface** name as part of its comma-separated +contents, as in: +``` + class <$PP> { &amethod(void) int32, # this class extends the $PP class, and + # &amethod is a member function of this class + $IFA } # this class implements the $IFA interface +``` +Function Declaration +-------------------- + +syntax: +``` + func ( + var , + ... + var ) , . . . { + + ... + } + +``` +\ provides various attributes about the function, like +static, extern, etc. The opening parentheses starts the parameter +declarations, which can be empty. Each \ is of the form of a +**var** or **reg** declaration declaring each incoming parameter. If the +last parameter is specified as \"\...\", it indicates the start of the +variable part of the arguments as in C. Following the parameter +declarations is a list of the multiple return types separated by commas. +If there is no return value, \ should specify void. Each +\ can be either primitive or derived. If no statement +follows the parentheses, then it is just a prototype declaration. + +### funcsize + +syntax: funcsize \ + +This directive appears inside the function block to give the Maple IR +code size of the function. + +### framesize + +syntax: framesize \ + +This directive appears inside the function block to give the stack frame +size of the function. + +### moduleid + +syntax: moduleid \ + +This directive appears inside the function to give the unique id of the +module which the function belongs to. + +### upformalsize + +syntax: upformalsize \ + +This directive appears inside the function block to give the size of +upformal segment that stores the formal parameters being passed above +the frame pointer %%FP. + +### formalwordstypetagged + +syntax: formalwordstypetagged = \[ \ \] + +This specifies a bitvector initialized to the value specified by the +list of space-separated 32-bit integer constants. The Nth bit in this +bitvector is set to 1 if the Nth word in the upformal segment has a type +tag, in which case the type tag is at the (N+1)th word. + +### formalwordsrefcounted + +syntax: formalwordsrefcounted = \[ \ \] + +This specifies a bitvector initialized to the value specified by the +list of space-separated 32-bit integer constants. The Nth bit in this +bitvector is set to 1 if the Nth word in the upformal segment is a +pointer to a reference-counted dynamically allocated memory block. + +### localwordstypetagged + +syntax: localwordstypetagged = \[ \ \] + +This specifies a bitvector initialized to the value specified by the +list of space-separated 32-bit integer constants. The Nth bit in this +bitvector is set to 1 if the -Nth word in the local stack frame has a +type tag, in which case the type tag is at the (-N+1)th word. + +### localwordsrefcounted + +syntax: localwordsrefcounted = \[ \ \] + +This specifies a bitvector initialized to the value specified by the +list of space-separated 32-bit integer constants. The Nth bit in this +bitvector is set to 1 if the -Nth word in the local stack frame is a +pointer to a reference-counted dynamically allocated memory block. + +Initializations +--------------- + +When there are initializations associated with a **var** declaration, +there is \'=\' after the **var** declaration, followed by the +initialization value. For aggregates, the list of initialization values +are enclosed by brackets \'\[\' and \'\]\', with the values separated by +commas. In arrays, the initialization values for the array elements are +listed one by one, and nested brackets must be used to correspond to +elements in each lower-order dimension. + +In specifying the initializations for a struct, inside the brackets, +field number followed by \'=\' must be used to specify the value for each +field explicitly. The fields\' initialization values can be listed in +arbitrary order. For nested structs, nested brackets must be used according +to the nesting relationship. Because a bracket is used for each sub-struct in +the nesting, the field number usage is relative to the sub-struct, and starts +at 1 for the first field of the sub-struct. Example: +``` + type %SS + var %s struct{@f1 i32, + @f2 <%SS>, + @f3:4 i32} = [ + 1 = 99, # field f1 is initialized to 99 + 2 = [1= 10.0f, 2=22.2f], + # fields f2.g1 and f2.g2 initialized to + # 10.0f and 22.2f respectively + 3 = 15 ] # field f3 (4 bits in size) has field number 3 in + # struct %s and is initialized to 15 +``` + Type Parameters +--------------- + +Also called generics or templates, type parameters allow derived types +and functions to be written without specifying the exact types in parts +of their contents. The type parameters can be instantiated to different +specific types later, thus enabling the code to be more widely +applicable, promoting software re-use. + +Type parameters and their instantiation can be handled completely by the +language front-ends. MAPLE IR provides representation for generic types +and generic functions and their instantiation so as to reduce the amount +of work in the language front-ends. A MAPLE IR file with type parameters +requires a front-end lowering phase to de-genericize the IR before the +rest of the MAPLE IR components can process the code. + +Type parameters are symbol names prefixed with \"!\", and can appear +anywhere that a type can appear. Each type or function definition can +have multiple type parameters, and each type parameter can appear more +than one time. Since type parameters are also types, they can only +appear inside the angular brackets \"\<\" and \"\>\", e.g. \. When +the definition of a derived type contains any type parameter, the type +becomes a generic type. When the definition of a function contains any +type parameter, the function becomes a generic function. A function +prototype cannot contain generic type. + +A generic type or generic function is marked with the generic attribute +to make them easier to be identified. A generic type or function is +instantiated by assigning specific non-generic types to each of its type +parameters. The instantiation is specified by a list of such assignments +separated by commas. We refer to this as an instantiation vector, which +is specified inside braces \"{\" and \"}\". In the case of the +instantiation of a generic type, the type parameter is immediately +followed by the instantiation vector. Example: +``` + type $apair , @f2 }> # $apair is a generic type + + var $x <$apair{!T=f32}> # the type of $x is $apair instantiated with + # f32 being assigned to the type parameter !T +``` +A generic function is instantiated by invoking it with an instantiation +vector. The instantiation vector immediately follows the name of the +generic function. Since the instantiation vector is regarded as type +information, it is further enclosed inside the angular brackets \"\<\" +and \"\>\". Invocation of generic functions must be via the opcodes +callinstant and callinstantassigned, which correspond to call and +callassigned respectively. Example: +``` + # &swap is a generic function to swap two parameters + func &swap (var %x \, var %y \) void { + var %z \ + dassign %z (dread agg %x) + dassiign %x (dread agg %y) + dassign %y (dread agg %z) + return + } + + ... + + # &swap is instantiated with type argument <$apair{!T=i32}>, + # itself an instantiated type + callinstant &swap<{!UU=<$apair{!T=i32}>}> ( + dread agg %a, + dread agg %b) +``` diff --git a/doc/en/NaiveRcInsertionDescription.md b/doc/en/NaiveRcInsertionDescription.md new file mode 100644 index 0000000000000000000000000000000000000000..f3d19b343de320220a26244510027991f6ee377e --- /dev/null +++ b/doc/en/NaiveRcInsertionDescription.md @@ -0,0 +1,175 @@ +# Naive RC Insertion Principle + +Reference Counting (RC) is a programming technique of storing the number of references to a resource, such as an object, a block of memory, disk space, and others, and releasing the resource when the number of references becomes 0. RC is used to achieve automatic resource management. RC also refers to a garbage collection algorithm that deallocates objects which are no longer referenced. Naive RC is a simplified RC. + + +Principle +====================== + +- RC sources: + + - Heap reference (other objects or itself) + + - Stack-based reference (including registers) + + - Static variable and global variable + +- RC Insertion rules (compiler and runtime): + + - If a value is assigned to a field, RC for the new object to which the field points is incremented and RC for the original object is decremented. + + - To read a local variable (including registers) on the stack, RC for the object to be read is incremented. + + - After last use, RC for the local variable is decremented. + + - If an object is returned, RC is incremented. After last use, RC for the compensated local variable is decremented. + +- Example + + - Before insertion + + ```cpp + class A { + static Object static_field; + Object instance_field; + A() { + static_field = new Object(); + } + } + Object foo(){ + A a = new A(); + bar(a, new Object()) + return a.instance_field; + } + void bar(A a, Object o) { + a.instance_field = o; + } + ``` + + - After insertion + + ```cpp + class A { + A() { + local_var t = new Object(); // t is a temporary variable assigned to the static_field process. + old = static_field; + static_field = t; + IncRef(t); DecRef(old); // RC is updated on the heap. + The DecRef(t); // The function exits and RC on the stack is released. + } + } + Object foo(){ + A a = new A(); + bar(a, new Object()); + locl_var t = a.instance_field; + IncRef(t) // RC for the variable on the stack is incremented. + The IncRef(t) // The function returns and RC for the returned value is incremented. + The DecRef(a) // The function exits and RC on the stack is released. + The DecRef(t) // The function exits and RC on the stack is released. + return t; + } + void bar(A a, Object o) { + old = a.instance_field + a.instance_field = o; + IncRef(o); DecRef(old); + } + ``` + + +- RC intrinsics: + + - Basic function + Method: The basic function uses CreateIntrinsicCallMeStmt in IrMap to create the IntrinsiccallMeStmt statement and insert it to the position where RC needs increment or decrement. + + - INTRN_MCCIncRef + + - INTRN_MCCDecRef + + - Load/Write function + Method: The Write function uses CreateIntrinsicCallMeStmt in IrMap to create the IntrinsiccallMeStmt statement and replace the iassign statement whose lvalue is static, global, or volatile. The Load function uses CreateIntrinsicCallAssignedMeStmt to create the IntrinsiccallMeStmt statement and replace the dassign statement whose rvalue is static, global, or volatile. The Load/Write function supports the IncRef operation. + + - INTRN_MCCLoadRef + + - INTRN_MCCLoadRefS + + - INTRN_MCCLoadRefVol + + - INTRN_MCCLoadRefSVol + + - INTRN_MCCWrite + + - INTRN_MCCWriteS + + - INTRN_MCCWriteVol + + - INTRN_MCCWriteSVol + +RefVar IncRef Processing Rules: +======================== + +- Assignment statement processing: + + - Process the statement based on the lvalue (variable value in the assignment statement) and rvalue (referenced value in the assignment statement) expressions. + + - First, process the rvalue. For example, select a load interface, or the rvalue (New, Call) that does not need RC increment. + + - Set Global to INTRN_MCCLoadRef. + + - Set Static to INTRN_MCCLoadRefS. + + - Set Volatile to INTRN_MCCLoadRefVol. + + - Then process the lvalue. For example, select a write interface, or save the old value or not. + + - Set Global to INTRN_MCCWriteRef. + + - Set Static to INTRN_MCCWriteRefS. + + - Set Volatile to INTRN_MCCWriteRefVol. + +- Return value processing: + + - Increment RC for the return value. + +- Local variable processing: + + - Decrement RC before the current function exits (normal or abnormal) + +Rclowering Processing Procedure: +==================== + +- Set the rclowering processing flag. +- Mark localrefvar. + +- Rclowering pre-processing + + - Mark variables that need RC. + + - Mark the lvalue as DecRef, that is, variable value in the assignment statement. + + - Ref variable + + - Mark the rvalue as IncRef, that is, referenced or return value in the assignment statement. + + - Return value + + - Ref variable + + - hrow Value register + + - Clear stack variables. + +- Rclowering processing + + - Process the assignment statement that contains the Ref variable. + + - DecRef original value + + - IncRef new value. For details, see RefVar IncRef processing rules. + +- Rclowering post-processing + + - Perform the IncRef operation on the parameter at the function entry and mark the parameter as LocalRefVar. + + - Process the return value of the function. If the attribute is LocalRefVar, then the InRef operation is performed. If not, see RefVar IncRef processing rules. + diff --git a/doc/en/ProgrammingSpecifications.md b/doc/en/ProgrammingSpecifications.md new file mode 100644 index 0000000000000000000000000000000000000000..be602470dc602a958c8fab045b8d849be108e80e --- /dev/null +++ b/doc/en/ProgrammingSpecifications.md @@ -0,0 +1,3077 @@ + + Ark Compiler C++ Coding Style Guide  + + + + + + + + + + + +| Chapter | Content | +| ------------------ | ---------------------------------------- | +| [0 About This Document](#c0) | [Purpose](#c0-1) [Key Points](#c0-2) [Conventions](#c0-3) [Exceptions](#c0-4) | +| [1 Principles](#c1) | [Principles of Good Code](#c1-1) [Class and Function Design Guidelines](#c1-2) [Follow C++ ISO Standards](#c1-4)
[Check Errors During Compilation](#c1-5) [Use Namespaces for Scoping](#c1-6) [Use C++ Features over C Features](#c1-7) | +| [2 Naming](#c2) | [General Naming Rules](#c2-1) [File Names](#c2-2) [Function Names](#c2-3) [Type Names](#c2-4) [Variable Names](#c2-5) [Macro, Constant, and Enumeration Names](#c2-6) | +| [3 Formatting](#c3) | [Line Length](#c3-1) [Indentation](#c3-2) [Braces](#c3-3) [Function Declarations and Definitions](#c3-4) [Function Calls](#c3-5) [if Statements](#c3-6) [Loop Statements](#c3-7) [Switch Statements](#c3-8) [Expressions](#c3-9) [Variable Assignment](#c3-10)
[Initialization](#c3-11) [Pointers and References](#c3-12) [Preprocessor Directives](#c3-13) [Whitespace](#c3-14) [Classes](#c3-15) | +| [4 Comments](#c4) | [Comment Style](#c4-1) [File Header Comments](#c4-2) [Function Header Comments](#c4-3) [Code Comments](#c4-4) | +| [5 Header Files](#c5) | [Header File Responsibility](#c5-1) [Header File Dependency](#c5-2) | +| [6 Scopes](#c6) | [Namespaces](#c6-1) [Global Functions and Static Member Functions](#c6-2) [Global Variables](#c6-3) [Global Constants and Static Member Constants](#c6-4) | +| [7 Classes](#c7) | [Constructors, Copy/Move Constructors, Copy/Move Assignment Operators, and Destructors](#c7-1) [Inheritance](#c7-2) [Multiple Inheritance](#c7-3) [Overloading](#c7-4) | +| [8 Functions](#c8) | [Function Design](#c8-1) [Inline Functions](#c8-2) [Function Parameters](#c8-3) | +| [9 Other C++ Features](#c9) | [Constants and Initialization](#c9-1) [Expressions](#c9-2) [Type Casting](#c9-3) [Resource Allocation and Release](#c9-4) [Standard Template Library](#c9-5) [Usage of const](#c9-6) [Templates](#c9-7) [Macros](#c9-8) [Others](#c9-9)| +| [10 Modern C++ Features](#c10) | [Code Simplicity and Security Improvement](#c10-1) [Smart Pointers](#c10-2) [Lambda](#c10-3) [Interfaces](#c10-4) | +| [11 Security Coding Specifications](#c11) | [Basic Principles](#c11-1) [Variables](#c11-2) [Assertions](#c11-3) [Exception Mechanisms](#c11-4) [Memory](#c11-5) [Dangerous Functions](#c11-6) | + +# 0 About This Document + +## Purpose + +Rules are not perfect. Disabling useful features in specific situations may affect implementation. However, the rules are formulated "to benefit most programmers". If a rule is found unhelpful or difficult to follow during team coding, please send feedback so we can improve it accordingly. + +Before referring to this guide, you are expected to have the following basic capabilities for C++. It is not for a beginner that wants to learn about C++. +1. Have a general knowledge of ISO standards for C++. +2. Be familiar with the basic features of C++, including those of C++ 03/11/14/17. +3. Have a general knowledge of the C++ Standard Library. + + +## Key Points +1. C++ programming style, such as naming and typesetting. +2. C++ modular design, including how to design header files, classes, interfaces, and functions. +3. Best practices of C++ features, including constants, type casting, resource management, and templates. +4. Best practices of modern C++, including conventions that can improve code maintainability and reliability in C++ 11/14/17. + + +## Conventions +**Rule**: a regulating principle that must be followed during programming. + +**Recommendation**: a guideline that must be considered during programming. + +This document is applicable to standard C++ versions (03/11/14/17) unless otherwise specified in the rule. + +## Exceptions +It is necessary to understand the reason for each 'rule' or 'recommendation' and to try and comply with them. +However, some rules and recommendations have exceptions. + +The only acceptable exceptions are those that do not violate the general principles and provide appropriate reasons for the exception. +Try to avoid exceptions because they affect the code consistency. Exceptions to 'Rules' should be very rare. + +The style consistency principle is preferred in the following cases: +**When you modify external open source or third-party code, the existing code specifications prevail.** +**For specific domains, the domain specifications prevail.** + +# 1 Principles + +## Principles of Good Code +We refer to Kent Beck's four rules of simple design to guide our coding and to identify good code. +1. Passes its tests +2. Minimizes duplication +3. Maximizes clarity +4. Has fewer elements +5. The importance of the preceding four rules decreases in sequence. + They are referred to as rules of simple design. + +The first point is the most important as it stresses external requirements. The second point refers to the modular design of code to ensure orthogonality and maintainability. The third point refers to code readability. The fourth point is code simplicity. Of course, we still emphasize expressiveness over simplicity. + +## Class and Function Design Guidelines +C++ is a typical object-oriented programming (OOP) language. The software engineering industry has developed many OOP principles to guide programmers in compiling large-scale, highly scalable, and maintainable code: +- Basic rule of high cohesion and low coupling: improves the reuse and portability of program modules. +- SOLID principles: consists of single responsibility, open–closed, Liskov substitution, interface segregation, and dependency inversion. The SOLID principles can make the program less coupled and more robust. +- Law of Demeter: reduces coupling between classes. +- "Tell, Don't ask": suggests that it is better to issue an object a command to perform some operation or logic, rather than to query its state and then take some action as a result. +- Composition/Aggregation Principle (CARP): favors composition/aggregation over class inheritance. + +## Follow C++ ISO Standards +It is hoped that C++ code is written using features compliant with ISO standards. Features that are not defined by ISO or those used in compilers must be used with caution. Extended features provided by compilers such as GCC must be used with caution too, because these features lead to poor portability. + +Note: If extended features are required by the product, encapsulate these features into independent interfaces and enable or disable these features through options on the interface. Develop programming manuals to instruct programmers on the use of these extended features. + +## Check Errors During Compilation +Use compilers to ensure code robustness instead of compiling error processing codes to handle exceptions. + +- Use const to ensure data consistency and prevent data from being modified unexpectedly. +- Run the static_assert command to check errors at compilation time. + +## Use Namespaces for Scoping +Global variables, global constants, and global type definitions belong to the global scope. Conflicts may occur when a third-party library is used in a project. + +Namespaces divide a scope into independent, name-specified scopes that can effectively prevent name conflicts within the global scope. +1. Classes and structs have their own scopes. +2. A named namespace can implement an upper-level scope, higher than a class scope. +3. Unnamed namespaces and the static keyword can be used to implement a file scope. + +We strongly recommend programmers not use global macro variables and functions, and instead place them inside a more restrictive scope. + +Scopes have the following disadvantages: +1. Although two types of the same name can be distinguished in different scopes, they are still confusing to readers. +2. An inline namespace allows its members to be treated as if they are members of the enclosing namespace, which is also confusing to readers. +3. A nested namespace definition can make names lengthy when the namespace needs to be referenced. + +Therefore, we recommended: +- For variables, constants, and type definitions, use namespaces as much as possible to reduce conflicts within the global scope. +- Do not use "using namespace" in header files. +- Do not use inline namespaces. +- Encapsulate definitions using unnamed namespaces or the static keyword in .cpp files to prevent leaking through APIs. + + +## Use C++ Features over C Features +C++ is more type safe and more abstract than C. It is recommended that you use C++ features for programming. For example, use strings instead of `char*`, use vectors instead of native arrays, and use namespaces instead of statically defined members. + + +# 2 Naming +## General Naming Rules +General naming styles include the following: +__CamelCase__ +CamelCase is the practice of writing compound words or phrases so that each word or abbreviation in the phrase begins with a capital letter, with no intervening spaces or punctuation. +There are two conventions: UpperCamelCase and lowerCamelCase. + +__Kernel Style (Unix-like)__ +Words are in lowercase and are separated with underscores (_). +'test_result' + +__Hungarian Style__ +Add a prefix to UpperCamelCase. The prefix indicates the type or usage. +'uiSavedCount ', or ' bTested' + +### Rule 2.1.1 Use the CamelCase style for identifier names. +The Hungarian style is not considered for identifier names, and we choose the CamelCase style over the Kernel style. + +| Type | Naming Style | +| ------------------------------------------------------------ | ---------------------------------------- | +| Class Type, Struct Type, Enumeration Type, and Union Type Definitions | UpperCamelCase | +| Functions (Including Global Functions, Scope Functions, and Member Functions) | UpperCamelCase (You can add a prefix to an interface. XXX_FunctionName) | +| Global Variables (Including Variables of the Global and Namespace Scopes, Namespace Variables, and Class Static Variables), Local Variables, Function Parameters, and Class, Struct, and Union Member Variables | lowerCamelCase | +| Constant, Enumerated Value | k+CamelCase | +| Macro | All caps, separated with underscores (_) | +| Namespace | All in lowercase | + +Note: +__Constant__ indicates the variables of the basic, enumeration, or character string type modified by const or constexpr in the global scope, the namespace scope, and the scope of a static member of a class. +__Variable__ indicates the variables excluding those defined in Constant. These variables use the lowerCamelCase style. + +## File Names +### Recommendation 2.2.1 Use .cpp as the C++ file name extension and .h as the header file name extension. Use Kernel style for file names. + +At present, there are some other file name extensions used by programmers: + +- Header files: .hh, .hpp, .hxx +- Implementation files: .cc, .cxx, .C + +This document uses .h and .cpp extensions. + +File names are as follows: +- database_connection.h +- database_connection.cpp + + +## Function Names +Functions are named in UpperCamelCase. Generally, the verb or verb-object structure is used. You can add a prefix to an interface. XXX_FunctionName +```cpp +class List { + public: + void AddElement(const Element& element); + Element GetElement(const unsigned int index) const; + bool IsEmpty() const; + bool MCC_GetClass(); +}; + +namespace utils { +void DeleteUser(); +} +``` + +## Type Names + +Types are named in the UpperCamelCase style. +All types, such as classes, structs, unions, typedefs, and enumerations, use the same conventions. + +```cpp +// classes, structs and unions +class UrlTable { ... +class UrlTableTester { ... +struct UrlTableProperties { ... +union Packet { ... + +// typedefs +typedef std::map PropertiesMap; + +// enums +enum UrlTableErrors { ... +``` + +For namespace naming, UpperCamelCase is recommended. +```cpp +// namespace +namespace osutils { + +namespace fileutils { + +} + +} +``` + + +## Variable Names +General variables are named in lowerCamelCase, including global variables, function parameters, local variables, and member variables. +```cpp +std::string tableName; // Good: Recommended style. +std::string tablename; // Bad: Forbidden style. +std::string path; // Good: When there is only one word, lowerCamelCase (all lowercase) is used. + +class Foo { + private: + std::string fileName; // Do not add a prefix or suffix that identifies the scope. +}; +``` + +## Macro, Constant, and Enumeration Names +For macros, use all caps separated with underscores (_). For constants and enumerated values, use k+CamelCase. +Local constants and ordinary const member variables use the lowerCamelCase naming style. + +```cpp +#define MAX(a, b) (((a) < (b)) ? (b) : (a)) // Example of naming a macro only. + +enum TintColor { // Note: Enumerated types are named in the UpperCamelCase style, while their values are in k+CamelCase style. + kRed, + kDarkRed, + kGreen, + kLightGreen +}; + +int Func(...) { + const unsigned int bufferSize = 100; // Local variable + char *p = new char[bufferSize]; + ... +} + +namespace utils { +const unsigned int kFileSize = 200; // Global variable +} + +``` + +# 3 Formatting +While programming styles coexist to meet different requirements, we strongly recommend that you use a standardized coding style in the same project so that everyone can easily read and understand the code and the code can be easily maintained. + +## Line Length + +### Recommendation 3.1.1 Each line of code should contain a maximum of 120 characters. +It is recommended that the number of characters in each line not exceed 120. If the line of code exceeds the permitted length, wrap the line appropriately. + +Exception: +- If a one-line comment contains a command or URL of more than 120 characters, you can keep the line for ease in using copy, paste, and search using the grep command. +- The length of an #include statement can contain a long path exceeding 120 characters, but this should be avoided if possible. +- The error information in preprocessor directives can exceed the permitted length. +Put the error information of preprocessor directives in one line to facilitate reading and understanding even if the line contains more than 120 characters. + +```cpp +#ifndef XXX_YYY_ZZZ +#error Header aaaa/bbbb/cccc/abc.h must only be included after xxxx/yyyy/zzzz/xyz.h, because xxxxxxxxxxxxxxxxxxxxxxxxxxxxx +#endif +``` + +## Indentation + +### Rule 3.2.1 Use spaces to indent and indent two spaces at a time. +Only spaces can be used for indentation. Two spaces are indented each time. + + + + +## Braces +### Rule 3.3.1 Use the K&R indentation writing style except for functions. +The left brace of the function is placed at the end of the statement. +The right brace starts a new line and nothing else is placed on the line, unless it is followed by the remaining part of the same statement, for example, "while" in the do statement, "else" or "else if" in the if statement, a comma, and a semicolon. + + +```cpp +struct MyType { // Follow the statement to the end, and indent one space. + ... +}; + +int Foo(int a) { // The left brace of the function is placed at the end of the statement. + if (...) { + ... + } else { + ... + } +} +``` + + +- Code is more compact. +- Placing the brace at the end of the statement makes the code more continuous in reading rhythm than starting a new line. +- This style complies with mainstream norms and habits of programming languages. +- Most modern IDEs have an automatic code indentation, alignment and display. Placing the brace at the end of a line does not impact understanding. + + +If no function body is inside the braces, the braces can be put on the same line. +```cpp +class MyClass { + public: + MyClass() : value(0) {} + + private: + int value; +}; +``` + +## Function Declarations and Definitions + +### Rule 3.4.1 The return type and the function name of a function declaration or definition must be on the same line. When the length of the function parameter list exceeds the permitted length, a line break is required and parameters must be aligned appropriately. +When a function is declared or defined, the return value type of the function should be on the same line as the function name. If the line length permits, the function parameters should be placed on the same line. Otherwise, the function parameters should be wrapped and properly aligned. +The left parenthesis of a parameter list should always be on the same line as the function name. The right parenthesis always follows the last parameter. + +The following is an example of line breaks: +```cpp +ReturnType FunctionName(ArgType paramName1, ArgType paramName2) { // Good: All are on the same line. + ... +} + +ReturnType VeryVeryVeryLongFunctionName(ArgType paramName1, // Each added parameter starts on a new line because the line length limit is exceeded. + ArgType paramName2, // Good: Aligned with the previous parameter + ArgType paramName3) { + ... +} + +ReturnType LongFunctionName(ArgType paramName1, ArgType paramName2, // The parameters are wrapped because the line length limit is exceeded. + ArgType paramName3, ArgType paramName4, ArgType paramName5) { // Good: After the line break, 4 spaces are used for indentation. + ... +} + +ReturnType ReallyReallyReallyReallyLongFunctionName( // The line length cannot accommodate even the first parameter, and a line break is required. + ArgType paramName1, ArgType paramName2, ArgType paramName3) { // Good: After the line break, 4 spaces are used for indentation. + ... +} +``` + +## Function Calls +### Rule 3.5.1 A function call parameter list should be placed on one line. When the parameter list exceeds the line length and requires a line break, the parameters should be properly aligned. +The left parenthesis always follows the function name, and the right parenthesis always follows the last parameter. + + +The following is an example of line breaks: +```cpp +ReturnType result = FunctionName(paramName1, paramName2); // Good: All function parameters are on one line. + +ReturnType result = FunctionName(paramName1, + paramName2, // Good: Aligned with the previous parameter. + paramName3); + +ReturnType result = FunctionName(paramName1, paramName2, + paramName3, paramName4, paramName5); // Good: Parameters are wrapped. After the line break, 4 spaces are used for indentation. + +ReturnType result = VeryVeryVeryLongFunctionName( // The line length cannot accommodate even the first parameter, and a line break is required. + paramName1, paramName2, paramName3); // After the line break, 4 spaces are used for indentation. +``` + +If some of the parameters called by a function are associated with each other, you can group them for better understanding. +```cpp +// Good: The parameters in each line represent a group of data structures with a strong correlation. They are placed on one line for ease of understanding. +int result = DealWithStructureLikeParams(left.x, left.y, // A group of related parameters. + right.x, right.y); // Another group of related parameters. +``` + +## if Statements + +### Rule 3.6.1 Use braces to include an if statement. +We require that all if statements use braces, even if there is only one statement. + + +- The logic is intuitive and easy to read. +- It is less prone to mistakes when new code is added to the existing if statement. +- If function-like macros are used in a conditional statement, it is less prone to mistakes (in case the braces are missing when macros are defined). + +```cpp +if (objectIsNotExist) { // Good: Braces are added to a single-line conditional statement. + return CreateNewObject(); +} +``` +### Rule 3.6.2 Place if, else, and else if keywords on separate lines. +If there are multiple branches in a conditional statement, they should be placed on separate lines. + +Good example: + +```cpp +if (someConditions) { + DoSomething(); + ... +} else { // Good: Put the if and else keywords on separate lines. + ... +} +``` + +Bad example: + +```cpp +if (someConditions) { ... } else { ... } // Bad: The if and else keywords are put on the same line. +``` + +## Loop Statements +### Rule 3.7.1 Use braces after loop statements. +Similar to if statements, we require that the for and while loop statements contain braces, even if the loop body is empty or there is only one loop statement. + +```cpp +for (int i = 0; i < someRange; i++) { + DoSomething(); +} +``` + +If the loop body is empty, use empty braces instead of a single semicolon. A single semicolon is easy to miss or incorrectly regarded as a part of the loop statement. + +```cpp +for (int i = 0; i < someRange; i++) { } // Good: The for loop body is empty. Braces should be used, instead of semicolons (;). + +while (someCondition) { } // Good: The while loop body is empty. Braces should be used, instead of semicolons (;). + +while (someCondition) { + continue; // Good: The continue keyword highlights the end of the empty loop. Braces are optional in this case. +} + +``` + +Bad example: +```cpp +for (int i = 0; i < someRange; i++) ; // Bad: The for loop body is empty. Braces are mandatory. + +while (someCondition) ; // Bad: Using a semicolon here will make people misunderstand that it is a part of the while statement and not the end to it. +``` + +## Switch Statements +### Rule 3.8.1 Indent case and default in a switch statement with four spaces. +This rule includes the requirement to further indent all content encased by a case or the default case. +```cpp +switch (var) { + case 0: // Good: Indented + DoSomething1(); // Good: Indented + break; + case 1: { // Good: Braces are added. + DoSomething2(); + break; + } + default: + break; +} +``` + +```cpp +switch (var) { +case 0: // Bad: case is not indented. + DoSomething(); + break; +default: // Bad: default is not indented. + break; +} +``` + +## Expressions + +### Recommendation 3.9.1 Keep a consistent line break style for expressions. +A long expression that does not meet the line length requirement must be wrapped appropriately. + + +// Assume that the first line exceeds the length limit. +```cpp +if (currentValue > threshold && + someConditionsion) { + DoSomething(); + ... +} + +int result = reallyReallyLongVariableName1 + // Good + reallyReallyLongVariableName2; +``` +After an expression is wrapped, ensure that the lines are aligned appropriately or indented with 4 spaces. See the following example. + +```cpp +int sum = longVaribleName1 + longVaribleName2 + longVaribleName3 + + longVaribleName4 + longVaribleName5 + longVaribleName6; // Good: Indented with 4 spaces. + +int sum = longVaribleName1 + longVaribleName2 + longVaribleName3 + + longVaribleName4 + longVaribleName5 + longVaribleName6; // Good: The lines are aligned. +``` +## Variable Assignment + +### Rule 3.10.1 Multiple variable definitions and assignment statements cannot be written on one line. +Each line should have only one variable initialization statement. It is easier to read and understand. + +```cpp +int maxCount = 10; +bool isCompleted = false; +``` + +Bad example: + +```cpp +int maxCount = 10; bool isCompleted = false; // Bad: Multiple variable initialization statements must be separated on different lines. Each variable initialization statement occupies one line. +int x, y = 0; // Bad: Multiple variable definitions must be separated on different lines. Each definition occupies one line. + +int pointX; +int pointY; +... +pointX = 1; pointY = 2; // Bad: Multiple variable assignment statements must be separated on different lines. +``` +Exception: Multiple variables can be declared and initialized in the for loop header, if initialization statement (C++17), and structured binding statement (C++17). Multiple variable declarations in these statements have strong associations. Forcible division into multiple lines may cause problems such as scope inconsistency and separation of declaration from initialization. + +## Initialization +Initialization is applicable to structs, unions, and arrays. + +### Rule 3.11.1 When an initialization list is wrapped, ensure that the line after the break is indented and aligned properly. +If a structure or array initialization list is wrapped, the line after the break is indented with four spaces. +Choose the wrap location and alignment style for best comprehension. + +```cpp +const int rank[] = { + 16, 16, 16, 16, 32, 32, 32, 32, + 64, 64, 64, 64, 32, 32, 32, 32 +}; +``` + +## Pointers and References +### Recommendation 3.12.1 The pointer type "`*`" follows a variable name. There is one space between variable name and type. + +```cpp +int *p = nullptr; // Good +``` + +Exception: When a variable is modified by const or restrict, "`*`" cannot follow the variable or type. +```cpp +char * const VERSION = "V100"; +``` + +### Recommendation 3.12.2 The reference type "`&`" follows a variable name. There is one space between variable name and type. +```cpp +int i = 8; + +int &p = i; // Good +``` + +## Preprocessor Directives +### Rule 3.13.1 The number sign "#" that starts a preprocessor directive must be at the beginning of the line and is not indented in nested preprocessor directives. +The number sign "#" that starts a preprocessor directive must be at the beginning of the line even through the preprocessor directive is inside a function. + +```cpp +#if defined(__x86_64__) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) // Good: "#" is at the beginning of the line. +#define ATOMIC_X86_HAS_CMPXCHG16B 1 // Good: "#" is at the beginning of the line. +#else +#define ATOMIC_X86_HAS_CMPXCHG16B 0 +#endif + + +int FunctionName() { + if (someThingError) { + ... +#ifdef HAS_SYSLOG // Good: Even in the function body, "#" is at the beginning of the line. + WriteToSysLog(); +#else + WriteToFileLog(); +#endif + } +} +``` +The nested preprocessor directives starting with "#" is not indented. + +```cpp +#if defined(__x86_64__) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define ATOMIC_X86_HAS_CMPXCHG16B 1 // Good: Wrapped for easier comprehension. +#else +#define ATOMIC_X86_HAS_CMPXCHG16B 0 +#endif +``` + +## Whitespace +### Rule 3.14.1 Ensure that horizontal spaces are used to highlight keywords and important information, and avoid unnecessary whitespace. +Horizontal spaces are used to highlight keywords and important information. Spaces are not allowed at the end of each code line. The general rules are as follows: + +- Add spaces after keywords such as if, switch, case, do, while, and for. +- Do not add spaces after the left parenthesis or before the right parenthesis. +- For expressions enclosed by braces, either add a space on either side or avoid a space on either side. +- Do not add spaces after unary operators (& * + - ~ !). +- Add a space to the left and right sides of each binary operator (= + - < > * / % | & ^ <= >= == !=). +- Add spaces to the left and right sides of a ternary operator (? :). +- Do not add spaces between a prefix or suffix increment (++) or decrement (--) operator and a variable. +- Do not add spaces before or after a struct member operator (. ->). +- Do not add spaces before commas. Add spaces after commas. +- Do not add spaces between a template or type conversion operator (<>) and a type. +- Do not add spaces before or after a domain operator (::). +- Determine whether to add spaces before and after a colon (:) based on the situation. + +In normal cases: +```cpp +void Foo(int b) { // Good: A space is before the left brace. + +int i = 0; // Good: During variable initialization, there should be spaces before and after =. Do not leave a space before the semicolon. + +int buf[kBufSize] = {0}; // Good: Spaces are not allowed in braces. +``` + +Function definition and call: +```cpp +int result = Foo(arg1,arg2); + ^ // Bad: Function arguments must be separated by spaces for explicit display. + +int result = Foo( arg1, arg2 ); + ^ ^ // Bad: There cannot be spaces after the left parenthesis or before the right parenthesis. +``` + +Pointer and Address Operator +```cpp +x = *p; // Good: There is no space between the operator * and the pointer p. +p = &x; // Good: There is no space between the operator & and the variable x. +x = r.y; // Good: When a member variable is accessed through the operator (.), no space is added. +x = r->y; // Good: When a member variable is accessed through the operator (->), no space is added. +``` + +Other Operators: +```cpp +x = 0; // Good: There is a space before and after the assignment operator (=). +x = -5; // Good: There is no space between the minus sign (–) and the number. +++x; // Good: Do not add spaces between a prefix or suffix increment (++) or decrement (--) operator and a variable. +x--; + +if (x && !y) // Good: There is a space before and after the Boolean operator. There is no space between the ! operator and the variable. +v = w * x + y / z; // Good: There is a space before and after the binary operator. +v = w * (x + z); // Good: There is no space before or after the expression in the parentheses. + +int a = (x < y) ? x : y; // Good: Ternary operator. There is a space before and after ? and : +``` + +Loops and Conditional Statements: +```cpp +if (condition) { // Good: There is a space between the if keyword and the left parenthesis, and no space before or after the conditional statement in the parentheses. + ... +} else { // Good: There is a space between the else keyword and the left brace. + ... +} + +while (condition) {} // Good: There is a space between the while keyword and the left parenthesis. There is no space before or after the conditional statement in the parentheses. + +for (int i = 0; i < someRange; ++i) { // Good: There is a space between the for keyword and the left parenthesis, and after the semicolons. + ... +} + +switch (condition) { // Good: There is a space after the switch keyword. + case 0: // Good: There is no space between the case condition and the colon. + ... + break; + ... + default: + ... + break; +} +``` + +Templates and Conversions +```cpp +// Angle brackets (< and >) are not adjacent to space. There is no space before < or between > and (. +vector x; +y = static_cast(x); + +// There can be a space between the type and the pointer operator. Keep the spacing style consistent. +vector x; +``` + +Scope Operators +```cpp +std::cout; // Good: Namespace access. Do not leave spaces. + +int MyClass::GetValue() const {} // Good: Do not leave spaces in the definition of member functions. +``` + +Colons +```cpp +// Scenarios when space is required. + +// Good: Add a space before or after the colon in a derived class definition. +class Sub : public Base { + +}; + +// Add a space before and after the colon for the initialization list of a constructor function. +MyClass::MyClass(int var) : someVar(var) { + DoSomething(); +} + +// Add a space before and after the colon in a bit-field. +struct XX { + char a : 4; + char b : 5; + char c : 4; +}; +``` + +```cpp +// Scenarios when space is not required. + +// Good: // No space is added before or after the colon next to a class access permission (public or private). +class MyClass { + public: + MyClass(int var); + private: + int someVar; +}; + +// No space is added before or after the colon in a switch statement. +switch (value) { + case 1: + DoSomething(); + break; + default: + break; +} +``` + +Note: Currently, all IDEs support automatic deletion of spaces at the end of a line. Please configure your IDE correctly. + +### Recommendation 3.14.2 Use blank lines only when necessary to keep code compact. + +There must be as few blank lines as possible so that more code can be displayed for easy reading. Recommendations: +- Add blank lines according to the correlation between lines. +- Consecutive blank lines are not allowed inside functions, type definitions, macros, and initialization expressions. +- A maximum of **two** consecutive blank lines can be used. +-.Do not add blank lines on the first and last lines of a code block. + +```cpp +int Foo() { + ... +} + + +// Bad: More than one blank lines are used between two function definitions. +int Bar() { + ... +} + + +if (...) { + // Bad: Do not add blank lines on the first and last lines of a code block. + ... + // Bad: Do not add blank lines on the first and last lines of a code block. +} + +int Foo(...) { + // Bad: Do not add blank lines before the first statement in a function body. + ... +} +``` + +## Classes +### Rule 3.15.1 Class access specifier declarations are in the sequence: public, protected, private. Indent each specifier with one space. +```cpp +class MyClass : public BaseClass { + public: // Indented with 1 space. + MyClass(); // Indented with 2 spaces. + explicit MyClass(int var); + ~MyClass() {} + + void SomeFunction(); + void SomeFunctionThatDoesNothing() { + } + + void SetVar(int var) { + someVar = var; + } + + int GetVar() const { + return someVar; + } + + private: + bool SomeInternalFunction(); + + int someVar; + int someOtherVar; +}; +``` + +In each part, it is recommended that similar statements be put together in the following order: Type (including typedef, using, nested structs and classes), Constant, Factory Function, Constructor, Assignment Operator, Destructor, Other Member Function, and Data Member. + + +### Rule 3.15.2 The constructor initialization list must be on the same line or wrapped and aligned with four spaces of indentation. +```cpp +// If all variables can be placed on the same line: +MyClass::MyClass(int var) : someVar(var) { + DoSomething(); +} + +// If the variables cannot be placed on the same line: +// Wrapped at the colon and indented with four spaces. +MyClass::MyClass(int var) + : someVar(var), someOtherVar(var + 1) { // Good: Add a space after the comma. + DoSomething(); +} + +// If an initialization list needs to be placed in multiple lines, put each member on a separate line and align between lines. +MyClass::MyClass(int var) + : someVar(var), // Indented with 4 spaces. + someOtherVar(var + 1) { + DoSomething(); +} +``` + +# 4 Comments +Generally, clear architecture and good naming are recommended to improve code readability, and comments are provided only when necessary. +Comments are used to help readers quickly understand code. Therefore, comments should be provided __for the sake of readers__. + +Comments must be concise, clear, and unambiguous, ensuring that information is complete and not redundant. + +__Comments are as important as code.__ +When writing a comment, you need to step into the reader's shoes and use comments to express what the reader really needs. Comments are used to express the function and intention of code, rather than repeating the code. +When modifying the code, ensure that the comments are consistent with the modified code. It is not polite to modify only code and keep the old comments, which will undermine the consistency between code and comments, and may confuse or even mislead readers. + +## Comment Style +In C++ code, both ` /* */` and ` // ` can be used for commenting. +Comments can be classified into different types, such as file header comments, function header comments, and code comments. This is based on their purposes and positions. +Comments of the same type must keep a consistent style. +(1) Use ` /* */ ` for file header comments. +(2) The style of function header comments and code comments in the same file must be consistent. + +Note: __Example code in this document uses comments in the '//' format only to better describe the rules and recommendations. This does not mean this comment format is better.__ + +## File Header Comments +### Rule 4.2.1 File header comments must contain the copyright notice. +```cpp +/* + * Copyright (c) [2019] [name of copyright holder] + * [Software Name] is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * http://license.coscl.org.cn/MulanPSL + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR + * PURPOSE. + * See the Mulan PSL v1 for more details. + */ +``` + + + +## Function Header Comments +### Rule 4.3.1 Function header comments with no content are forbidden. +Not all functions need function header comments. +For information that cannot be described by function signatures, add function header comments. + +Function header comments are placed above the function declaration or definition. Use one of the following styles: +Use `//` to start the function header. + +```cpp +// Single-line function header +int Func1(void); + +// Multi-line function header +// Second line +int Func2(void); +``` + +Use `/* */` to start the function header. +```cpp +/* single-line function header */ +int Func1(void); + +/* + * Another single-line function header + */ +int Func2(void); + +/* + * Multi-line function header + * Second line + */ +int Func3(void); +``` +Use function names to describe functions, and add function header comments if necessary. +Do not write useless or redundant function headers. Do not write empty function headers with no content. + +The function header comment content will depend on the function and includes but is not limited to: a function description, return value, performance constraints, usage comments, memory conventions, algorithm implementation, reentering requirements. +In the function interface declaration in the external header file, the function header comment should clearly describe important and useful information. + +Good example: + +```cpp +/* + * The number of written bytes is returned. If -1 is returned, the write operation failed. + * Note that, the memory buffer should be released by the caller. + */ +int WriteString(const char *buf, int len); +``` + +Bad example: +```cpp +/* + * Function name: WriteString + * Function: Write a character string. + * Parameters: + * Return value: + */ +int WriteString(const char *buf, int len); +``` +Problems: + +- The 'Parameters' and 'Return value' have no content. +- The function name comment is redundant. +- The most important thing, that is, who needs to release the buffer, is not clearly stated. + +## Code Comments +### Rule 4.4.1 Code comments are placed above or to the right of the corresponding code. +### Rule 4.4.2 There must be a space between the comment character and the comment content. At least one space is required between the comment and code if the comment is placed to the right of code. +Comments placed above the code should be indented the same as that of the code. +Use one of the following styles: +Use `//`. +```cpp + +// Single-line comment +DoSomething(); + +// Multi-line comment +// Second line +DoSomething(); +``` + +Use `/*' '*/`. +```cpp +/* Single-line comment */ +DoSomething(); + +/* + * Multi-line comment in another mode + * Second line + */ +DoSomething(); +``` +Leave at least one space between the code and the comment on the right. It is recommended that no more than four spaces be left. +You can use the Tab key to indent 1–4 spaces, set this in your IDE or editor. + +Use one of the following styles: + +```cpp +int foo = 100; // Comment on the right +int bar = 200; /* Comment on the right */ +``` +It is more appealing sometimes when the comment is placed on the right of code and the comments are aligned vertically. +After the alignment, ensure that the comment is still 1–4 spaces away from the widest line of code. +Example: + +```cpp +const int kConst = 100; /* Related comments of the same type can be aligned vertically. */ +const int kAnotherConst = 200; /* Leave spaces after code to align comments vertically.*/ +``` +When the comment on the right exceeds the line width, consider placing the comment above the code. + +### Rule 4.4.3 Delete unused code segments. Do not comment them out. +Code that is commented out cannot be maintained normally. When you attempt to restore the code, it is very likely to introduce easy to overlook defects. +The correct method is to delete unnecessary code directly. If necessary, consider porting or rewriting the code. + +Here, commenting out the removal of code from compilation without actually deleting it. This is done using /* */, //, #if 0, #ifdef NEVER_DEFINED, and so on. + +### Recommendation 4.4.1 Try not to contain a TODO/TBD/FIXME comment in code. +TODO/TBD comments are used to describe required improvements and supplements. +FIXME comments are used to describe defects that need fixing. +They should have a standardized style, which facilitates text search. + +```cpp +// TODO(): XX +// FIXME: XX +``` + + +# 5 Header Files +## Header File Responsibility +A header file is an external interface of a module or file. The design of a header file shows most of the system design. +The interface declaration for most functions is more suitable placed in the header file, but implementation (except inline functions) cannot be placed in the header file. Functions, macros, enumerations, and structure definitions that need to be used in .cpp files cannot be placed in the header file. +The header responsibility should be simple. A too complex header file will make dependencies complex and cause a long compilation time. + +### Recommendation 5.1.1 Each .cpp file should have a .h file with the same name. The file is used to declare the classes and interfaces that need to be exposed externally. +Generally, each .cpp file has a corresponding .h file. This .cpp file is used to store the function declarations, macro definitions, and class definitions that are to be disclosed externally. In addition, corresponding .inline.h files can be added based on sit requirements to optimize code. +If a .cpp file does not need to open any interface externally, it should not exist. +Exception: __An entry point (for example, the file where the main function is located), unit tests, and dynamic library code.__ + +Example: +```cpp +// Foo.h + +#ifndef FOO_H +#define FOO_H + +class Foo { + public: + Foo(); + void Fun(); + + private: + int value; +}; + +#endif +``` + +```cpp +// Foo.cpp +#include "Foo.h" + +namespace { // Good: The declaration of the internal function is placed in the header of the .cpp file, and has been limited to the unnamed namespace or static scope. +void Bar() { +} +} + +... + +void Foo::Fun() { + Bar(); +} +``` + +## Header File Dependency +### Rule 5.2.1 Header file cyclic dependency is forbidden. +Cyclic dependency of header files means that a.h contains b.h, b.h contains c.h, and c.h contains a.h. If any header file is modified, all code containing a.h, b.h, and c.h needs to be recompiled. +For a unidirectional dependency, for example, a.h contains b.h, b.h contains c.h, and c.h does not contain any header file, modifying a.h does not mean that we need to recompile the source code for b.h or c.h. + +The cyclic dependency of header files directly reflects the unreasonable architecture design, which can be avoided by optimizing the architecture. + +### Rule 5.2.2 Do not include unnecessary header files. +The inclusion of header files that are not used will cause unnecessary dependency, which increases the coupling between modules or units. As long as a header file is modified, the code needs to be recompiled. + +In many systems, the inclusion relationships of header files are complex. To save time, developers may directly include all header files in their files, or even release a god.h file that contains all header files to project teams. This will cause a great time in compilation and great trouble in maintenance. + +### Rule 5.2.3 Header files should be self-contained. +Simply, self-containing means that any header file can be compiled independently. For a file containing a header file, unnecessary burdens are added to users if the file cannot work unless the header file contains another header file. + +For example, if the a.h header file is not self-contained, but must contain b.h, it will cause: + +Each .cpp file that uses the a.h header file must include the additional b.h header file to ensure that the a.h content can be compiled. +The additional b.h header file must be included before a.h, which has a dependency in the inclusion order. + + +### Rule 5.2.4 Header files must have `#define` guards to prevent multiple inclusion. +To prevent header files from being included multiple times, all header files should be protected by #define. Do not use #pragma once. + +When defining a protection character, comply with the following rules: +(1) The protection character uses a unique name. +(2) Do not place code or comments (except for file header comments) before or after the protected part. + +Example: Assume that the timer.h file of the timer module of the VOS project is in the VOS/include/timer/Timer.h directory. Perform the following operations to protect the timer.h file: + +```cpp +#ifndef VOS_INCLUDE_TIMER_TIMER_H +#define VOS_INCLUDE_TIMER_TIMER_H +... +#endif +``` + +You do not need to add a path as shown in the preceding example, but you need to ensure that the macro in the current project is unique. +```cpp +#ifndef TIMER_H +#define TIMER_H +... +#endif +``` + +### Recommendation 5.2.1 It is prohibited to reference external function interfaces and variables in declaration mode. +Interfaces provided by other modules or files can be used only by including header files. +Using external function interfaces and variables in extern declaration mode may cause inconsistency between declarations and definitions when external interfaces are changed. +In addition, this implicit dependency may cause architecture corruption. + +Cases that do not comply with specifications: + +// a.cpp content +```cpp +extern int Fun(); // Bad: Use external functions in extern mode. + +void Bar() { + int i = Fun(); + ... +} +``` + +// b.cpp content +```cpp +int Fun() { + // Do something +} +``` +It should be changed to: + +// a.cpp content +```cpp +#include "b.h" // Good: Use the interface provided by other .cpp by including its corresponding header file. + +void Bar() { + int i = Fun(); + ... +} +``` + +// b.h content +```cpp +int Fun(); +``` + +// b.cpp content +```cpp +int Fun() { + // Do something +} +``` +In some scenarios, if the internal functions need to be referenced with no intrusion to the code, the extern declaration mode can be used. +For example: +When performing unit testing on an internal function, you can use the extern declaration to reference the function to be tested. +When a function needs to be stubbed or patched, the function can be declared using extern. + +### Rule 5.2.5 Do not include header files in extern "C". +If a header file is included in extern "C", extern "C" may be nested. Some compilers restrict the nesting level of extern "C". If there are too many nested layers, compilation errors may occur. + +When C and C++ programmings are used together and if extern "C" includes a header file, the original intent behind the header file may be hindered. For example, when the link specifications are modified incorrectly. + +Example: Assume that there are two header files, a.h and b.h. + +// a.h content +```cpp +... +#ifdef __cplusplus +void Foo(int); +#define A(value) Foo(value) +#else +void A(int) +#endif +``` +// b.h content +```cpp +... +#ifdef __cplusplus +extern "C" { +#endif + +#include "a.h" +void B(); + +#ifdef __cplusplus +} +#endif +``` + +Use the C++ preprocessor to expand b.h. The following information is displayed: +```cpp +extern "C" { + void Foo(int); + void B(); +} +``` + +According to the author of a.h, the function Foo is a C++ free function following the "C++" link specification. +However, because `#include "a.h"` is placed inside `extern "C"` in b.h, the link specification of function Foo is changed incorrectly. + +Exception: +In the C++ compilation environment, if you want to reference the header file of pure C, the C header files must not include `extern "C"`. The non-intrusive approach is to include the C header file in `extern "C"`. + +### Recommendation 5.2.2 Use `#include` instead of a forward declaration to include header files. +A forward declaration is for the declaration of classes, functions, and templates and is not meant for its definition. + +- Pros: + 1. Forward declarations can save compilation time. Unnecessary #includes force the compiler to open more files and process more input. + 2. Forward declarations can save unnecessary recompilation time. The use of #include will force your code to be recompiled for multiple times due to unrelated changes in header files. +- Cons: + 1. Forward declarations hide dependency relationship. When a header file is modified, user code will skip the necessary recompilation process. + 2. A forward declaration may be broken by subsequent changes to the library. Forward declarations of functions and templates sometimes prevent header file developers from changing APIs. For example, widening a formal parameter type, adding a formal template parameter with a default value, and so on. + 3. Forward declaration of symbols from the namespace `std::` is seen as undefined behavior (as specified in the C++ 11 standard specification). + 4. Forward declaration of multiple symbols from a header file can be more verbose than simply including (#include) the header. + 5. Structuring code only for forward declaration (for example, using pointer members instead of object members) can make the code more complex and slower. + 6. It is difficult to determine whether a forward declaration or `#include` is needed. In some scenarios, replacing `#include` with a forward declaration may cause unexpected results. + +Therefore, we should avoid using forward declarations as much as possible. Instead, we use the #include statement to include a header file and ensure dependency. + +### Recommendation 5.2.3 Include headers in the following sequence: .h file corresponding to the .cpp file > other header files according to their stability. +Using standard header file inclusion sequence can enhance readability and avoid hidden dependencies. The recommended header file inclusion priority is: the header file corresponding to the .cpp file > C/C++ standard libraries > .h files from used system libraries > .h files from other libraries > other .h files in the project. + +For example, the sequence of the header files in Foo.cpp is as follows: +```cpp +#include "Foo/Foo.h" + +#include +#include + +#include +#include + +#include "platform/Base.h" +#include "platform/Framework.h" + +#include "project/public/Log.h" +``` +Placing the Foo.h file at the top ensures that when the Foo.h file misses some necessary libraries or an error occurs, the Foo.cpp build is terminated immediately, reducing the compilation time. For the sequence of header files, refer to this suggestion. + +Exception: +Platform-specific code requires conditional compilation. The code can be placed after other "includes". +```cpp +#include "foo/public/FooServer.h" + +#include "base/Port.h" // For LANG_CXX11. + +#ifdef LANG_CXX11 +#include +#endif // LANG_CXX11 +``` + +# 6 Scopes + +## Namespaces +The content of a namespace is not indented. + +### Recommendation 6.1.1 Use an unnamed namespace to encapsulate or use static to modify variables, constants, or functions that do not need to be exported from the .cpp file. +In the C++ 2003 standard, using static to modify the external availability of functions and variables was marked as deprecated. Therefore, unnamed namespaces are the recommended method. + +The main reasons are as follows: +1. There are too many meanings for static in C++: static function member variable, static member function, static global variable, and static function local variable. Each of them has special processing. +2. Static can only be used to define variables, constants, and functions that are not referenced outside the current .cpp file, while namespaces can also be used to encapsulate types. +3. Use a namespace to process the scope of C++ instead of using both static and namespaces. +4. Unnamed namespaces rather than functions modified by static can be used to instantiate templates. + +Do not use unnamed namespaces or static in header files. + +```cpp +// Foo.cpp + +namespace { +const int kMaxCount = 20; +void InternalFun(){}; +} + +void Foo::Fun() { + int i = kMaxCount; + + InternalFun(); +} + +``` + +### Rule 6.1.1 Do not use "using" to import a namespace in header files or before #include statements. +Note: Using "using" to import a namespace will affect subsequent code and may cause symbol conflicts. Therefore, do not use "using" to import a namespace in a header file or before #include in a source file. +Example: + +```cpp +// Header file a.h +namespace namespacea { +int Fun(int); +} +``` + +```cpp +// Header file b.h +namespace namespaceb { +int Fun(int); +} + +using namespace namespaceb; + +void G() { + Fun(1); +} +``` + +```cpp +// Source code a.cpp +#include "a.h" +using namespace namespacea; +#include "b.h" + +void main() { + G(); // using namespace namespacea is before #include "b.h", which will cause the following issues: The calling of namespacea::Fun and namespaceb::Fun is not clear. +} +``` + +Using "using" to import a symbol or define an alias in a header file is allowed in customized namespaces of modules, but is prohibited in the global namespace. +```cpp +// foo.h + +#include +using fancy::string; // Bad: It is prohibited to import symbols to global namespaces. + +namespace foo { +using fancy::string; // Good: Symbols can be imported in customized namespaces of modules. +using MyVector = fancy::vector; // Good: In C++11, aliases can be defined in customized namespaces. +} +``` + + +### Rule 6.1.2 Do not use "using namespace std". +Note: The std:: prefix can make code clear and avoid naming conflicts. + + +## Global Functions and Static Member Functions + +### Recommendation 6.2.1 Preferentially use namespaces to manage global functions. If global functions are closely related to a class, you can use static member functions. +Note: Placing non-member functions in a namespace avoids polluting the global scope. Do not use "class + static member function" to simply manage global functions. If a global function is closely tied to a class, it can be used as a static member function of the class. + +If you need to define some global functions for a .cpp file, use unnamed namespaces for management. +```cpp +namespace mynamespace { +int Add(int a, int b); +} + +class File { + public: + static File CreateTempFile(const std::string& fileName); +}; +``` + +## Global Constants and Static Member Constants + +### Recommendation 6.3.1 Preferentially use namespaces to manage global constants. If global constants are closely related to a class, you can use static member constants. +Note: Placing global constants in a namespace avoids polluting the global scope. Do not use "class + static member constant" to simply manage global constants. If a global constant is closely tied to a class, it can be used as a static member constant of the class. + +If you need to define some global constants only for a .cpp file, use unnamed namespaces for management. +```cpp +namespace mynamespace { +const int kMaxSize = 100; +} + +class File { + public: + static const std::string kName; +}; +``` + +## Global Variables + +### Recommendation 6.4.1 Do not use global variables. Use the singleton pattern instead. +Note: Global variables can be modified and read, which causes data coupling between the business code and the global variable. +```cpp +int counter = 0; + +// a.cpp +counter++; + +// b.cpp +counter++; + +// c.cpp +cout << counter << endl; +``` + +Singleton +```cpp +class Counter { + public: + static Counter& GetInstance() { + static Counter counter; + return counter; + } // Simple example of a singleton implementation + + void Increase() { + value++; + } + + void Print() const { + std::cout << value << std::endl; + } + + private: + Counter() : value(0) {} + + private: + int value; +}; + +// a.cpp +Counter::GetInstance().Increase(); + +// b.cpp +Counter::GetInstance().Increase(); + +// c.cpp +Counter::GetInstance().Print(); +``` + +After the singleton is implemented, there is a unique global instance, which can functions as a global variable. In addition, singleton provides better encapsulation. + +Exception: In some cases, the scope of a global variable is only inside a module. Multiple instances of the same global variable may exist in the process space, and each module holds one copy. In this case, a singleton cannot be used as it is limited to one instance. + +# 7 Classes + +Use a struct only for passive objects that carry data; everything else is a class. + +## Constructors, Copy/Move Constructors, Copy/Move Assignment Operators, and Destructors +Constructors, copy/move constructors, copy/move assignment operators, and destructors provide lifetime management methods for objects. +- Constructor: `X()` +- Copy constructor: `X(const X&)` +- Copy assignment operator: `operator=(const X&)` +- Move constructor: `X (X&&)` *Provided in versions later than C++ 11*. +- Move assignment operator: `operator=(X&&)` *Provided in versions later than C++ 11*. +- Destructor: `~X()` + +### Rule 7.1.1 The member variables of a class must be initialized explicitly. +Note: If a class has member variables but no constructors and default constructors are defined, the compiler will automatically generate a constructor, which will not initialize member variables. The object status is uncertain. + +Exception: +- If the member variables of a class have a default constructor, explicit initialization is not required. + +Example: The following code has no constructor, and private data members cannot be initialized: +```cpp +class Message { + public: + void ProcessOutMsg() { + //… + } + private: + unsigned int msgID; + unsigned int msgLength; + unsigned char* msgBuffer; + std::string someIdentifier; +}; + +Message message; // The message member variable is not initialized. +message.ProcessOutMsg(); // Potential risks exist in subsequent use. + +// Therefore, it is necessary to define the default constructor as follows: +class Message { + public: + Message() : msgID(0), msgLength(0) { + } + + void ProcessOutMsg() { + // … + } + + private: + unsigned int msgID; + unsigned int msgLength; + unsigned char* msgBuffer; + std::string someIdentifier; // The member variable has a default constructor. Therefore, explicit initialization is not required. +}; +``` + +### Recommendation 7.1.1 Initialization during declaration (C++ 11) and initialization using the constructor initialization list are preferred for member variables. +Note: Initialization during declaration (C++11) is preferred because initialized values of member variables can be easily understood. If initialized values of certain member variables are relevant to constructors, or C++ 11 is not supported, the constructor initialization list should be used preferentially to initialize these member variables. Compared with the assignment statements in constructors, code of the constructor initialization list is simpler and has higher performance, and can be used to initialize constant and reference members. + +```cpp +class Message { + public: + Message() : msgLength(0) { // Good: The constructor initialization list is preferred. + msgBuffer = NULL; // Bad: Values cannot be assigned in constructors. + } + + private: + unsigned int msgID{0}; // Good: used in C++11. + unsigned int msgLength; + unsigned char* msgBuffer; +}; +``` + +### Rule 7.1.2 Declare single-parameter constructors as explicit to prevent implicit conversion. +Note: If a single-parameter constructor is not declared as explicit, it will become an implicit conversion function. +Example: + +```cpp +class Foo { + public: + explicit Foo(const string& name): name(name) { + } + private: + string name; +}; + + +void ProcessFoo(const Foo& foo){} + +int main(void) { + std::string test = "test"; + ProcessFoo(test); // Compiling failed. + return 0; +} +``` + +The preceding code fails to be compiled because the parameter required by `ProcessFoo` is of the Foo type, which mismatch with the input string type. + +If the explicit keyword of the Foo constructor is removed, implicit conversion is triggered and a temporary Foo object is generated when `ProcessFoo` is called with the string parameter. Usually, this implicit conversion is confusing and bugs are apt to be hidden, due to unexpected type conversion. Therefore, single-parameter constructors require explicit declaration. + +### Rule 7.1.3 If copy/move constructors and copy/move assignment operators are not needed, clearly prohibit them. +Note: If users do not define it, the compiler will generate copy/move constructors and copy/move assignment operators (move semantic functions will be available in versions later than C++ 11). +If we do not use copy constructors or copy assignment operators, explicitly delete them. + +1. Set copy constructors or copy assignment operators to private and do not implement them. + +```cpp +class Foo { + private: + Foo(const Foo&); + Foo& operator=(const Foo&); +}; +``` +2. Use delete provided by C++ 11. + +```cpp +// Copy constructors and copy assignment operators are forbidden together. Use delete provided by C++ 11. +class Foo { + public: + Foo(Foo&&) = delete; + Foo& operator=(Foo&&) = delete; +}; +``` +3. For static method class, disable constructors to prevent instances from being created. + +```cpp +class Helper { + public: + static bool DoSomething(); + + private: + Helper(); +}; +``` +4. For singleton class, disable constructors and copy constructors to prevent instances from being created. + +```cpp +class Foo { + private: + static Foo *instance; + Foo() {} + Foo(const Foo &a); + Foo& operator=(const Foo &a); + public: + static Foo &Instance() { + if (!instance) { + instance = new Foo(); + } + return *instance; + } +}; +``` + +5. For destructors that release resources by raw pointers, disable copy constructions and copy assignment operators to prevent repeated release. + +```cpp +class Foo { + private: + FILE *fp; + Foo(const Foo &a); + Foo& operator=(const Foo &a); + public: + Foo() : fp(nullptr) {} + ~Foo() { + if (fp != nullptr) { + fclose(fp); + fp = nullptr; + } + } +}; + +Foo* Foo::instance = nullptr; +``` + +### Rule 7.1.4 Copy constructors and copy assignment operators should be implemented or forbidden together. +Both copy constructors and copy assignment operators provide copy semantics. They should be implemented or forbidden together. + +```cpp +// Copy constructors and copy assignment operators are implemented together. +class Foo { + public: + ... + Foo(const Foo&); + Foo& operator=(const Foo&); + ... +}; + +// Copy constructors and copy assignment operators are both set to default, as supported by C++ 11. +class Foo { + public: + Foo(const Foo&) = default; + Foo& operator=(const Foo&) = default; +}; + +// Copy constructors and copy assignment operators are forbidden together. You can use delete provided by C++ 11. +class Foo { + private: + Foo(const Foo&); + Foo& operator=(const Foo&); +}; +``` + +### Rule 7.1.5 Move constructors and move assignment operators should be implemented or forbidden together. +The move operation is added in C++ 11. If a class is required to support the move operation, move constructors and move assignment operators need to be implemented. + +Both move constructors and move assignment operators provide move semantics. They should be implemented or forbidden together. +```cpp +// Move constructors and move assignment operators are implemented together. +class Foo { + public: + ... + Foo(Foo&&); + Foo& operator=(Foo&&); + ... +}; + +// Move constructors and move assignment operators are both set to default, as supported by C++ 11. +class Foo { + public: + Foo(Foo&&) = default; + Foo& operator=(Foo&&) = default; +}; + +// Move constructors and move assignment operators are forbidden together. Use delete provided by C++ 11. +class Foo { + public: + Foo(Foo&&) = delete; + Foo& operator=(Foo&&) = delete; +}; +``` + +### Rule 7.1.6 It is prohibited to call virtual functions in constructors and destructors. +Note: Calling a virtual function of the current object in a constructor or destructor will cause behavior of non-polymorphism. +In C++, a base class constructs only one complete object at a time. + +Example: Base indicates the base class, and Sub indicates the derived class. +```cpp +class Base { + public: + Base(); + virtual void Log() = 0; // Different derived classes call different log files. +}; + +Base::Base() { // Base class constructor + Log(); // Call the virtual function log. +} + +class Sub : public Base { + public: + virtual void Log(); +}; +``` + +When running the following statement: +`Sub sub;` +The constructor of the derived class is executed first. However, the constructor of the base class is called first. Because the constructor of the base class calls the virtual function log, the log is in the base class version. The derived class is constructed only after the base class is constructed. As a result, behavior of non-polymorphism are caused. +This also applies to destructors. + +### Recommendation 7.1.2 Do not add the inline keyword to functions in the class definition. +Note: By default, functions in the class definition are inline. + + +## Inheritance + +### Rule 7.2.1 Destructors of the base class should be declared as virtual. +Note: Destructors of the derived class can be called during polymorphism invocation only when destructors of the base class are virtual. + +Example: There will be memory leak if destructors of the base class are not declared as virtual. +```cpp +class Base { + public: + virtual std::string getVersion() = 0; + + ~Base() { + std::cout << "~Base" << std::endl; + } +}; +``` + +```cpp +class Sub : public Base { + public: + Sub() : numbers(nullptr) { + } + + ~Sub() { + delete[] numbers; + std::cout << "~Sub" << std::endl; + } + + int Init() { + const size_t numberCount = 100; + numbers = new (std::nothrow) int[numberCount]; + if (numbers == nullptr) { + return -1; + } + + ... + } + + std::string getVersion() { + return std::string("hello!"); + } +private: + int* numbers; +}; +``` + +```cpp +int main(int argc, char* args[]) { + Base* b = new Sub(); + + delete b; + return 0; +} +``` +Because destructors of the base class are not declared as virtual, only destructors of the base class are called when an object is destroyed. Destructors of the derived class Sub are not called. As a result, a memory leak occurs. + + +### Rule 7.2.2 Do not use default parameter values for virtual functions. +Note: In C++, virtual functions are dynamically bound, but the default parameters of functions are statically bound during compilation. This means that the function you finally execute is a virtual function that is defined in the derived class but uses the default parameter value in the base class. To avoid confusion and other problems caused by inconsistent default parameter declarations during overriding of virtual functions, it is prohibited to declare default parameter values for all virtual functions. +Example: The default value of parameter "text" of the virtual function "Display" is determined at compilation time instead of runtime, which does not fit with polymorphism. +```cpp +class Base { + public: + virtual void Display(const std::string& text = "Base!") { + std::cout << text << std::endl; + } + + virtual ~Base(){} +}; + +class Sub : public Base { + public: + virtual void Display(const std::string& text = "Sub!") { + std::cout << text << std::endl; + } + + virtual ~Sub(){} +}; + +int main() { + Base* base = new Sub(); + Sub* sub = new Sub(); + + ... + + base->Display(); // The program output is as follows: Base! The expected output is as follows: Sub! + sub->Display(); // The program output is as follows: Sub! + + delete base; + delete sub; + return 0; +}; +``` + +### Rule 7.2.3 Do not redefine inherited non-virtual functions. +Note: Non-virtual functions cannot be dynamically bound (only virtual functions can be dynamically bound). You can obtain the correct result by operating the pointer of the base class. + +Example: +```cpp +class Base { + public: + void Fun(); +}; + +class Sub : public Base { + public: + void Fun(); +}; + +Sub* sub = new Sub(); +Base* base = sub; + +sub->Fun(); // Call Fun of the derived class. +base->Fun(); // Call Fun of the base class. +//... + +``` + +## Multiple Inheritance +In the actual development process, multiple inheritance scenarios are seldom used because the following typical problems may occur: +1. Data duplication and name ambiguity caused by "diamond" inheritance. Therefore, C++ introduces virtual inheritance to solve these problems. +2. In addition to "diamond" inheritance, names of multiple base classes may also conflict with each other, resulting in name ambiguity. +3. If a derived class needs to be extended or needs to override methods of multiple base classes, the responsibilities of the derived classes are unclear and semantics are muddled. +4. Compared with delegation, inheritance is seen as white box reuse, that is, a derived class can access the protected members of the base class, which leads to more coupling. Multiple inheritance, due to the coupling of multiple base classes, leads to even more coupling. + +Multiple inheritance has the following advantages: +Multiple inheritance provides a simpler method for assembling and reusing multiple interfaces or classes. + +Therefore, multiple inheritance can be used only in the following cases: + +### Recommendation 7.3.1 Use multiple inheritance to implement interface separation and multi-role combination. +If a class requires multiple interfaces, combine multiple separated interfaces by using multiple inheritance. This is similar to the Traits mixin of the Scala language. + +```cpp +class Role1 {}; +class Role2 {}; +class Role3 {}; + +class Object1 : public Role1, public Role2 { + // ... +}; + +class Object2 : public Role2, public Role3 { + // ... +}; + +``` + +The C++ standard library has a similar implementation example: +```cpp +class basic_istream {}; +class basic_ostream {}; + +class basic_iostream : public basic_istream, public basic_ostream { + +}; +``` + +## Overloading + +Overload operators should be used when there are sufficient reasons, and they do not change the original perception of the operators. For example, do not use the plus sign (+) to perform subtraction. +Operator overloading can make code more intuitive but has some disadvantages: +- It is often mistaken that the operation is as fast as a built-in operator, which has no performance degradation. +- There is no naming to aid debugging. It is more convenient to search by function name than by operator. +- Overloading operators can cause confusion if behavior definitions are not intuitive (for example, if the "+" operator is used for subtraction). +- The implicit conversion caused by the overloading of assignment operators may lead to entrenched bugs. Functions such as Equals () and CopyFrom () can be defined to replace the = and == operators. + + + +# 8 Functions +## Function Design +### Recommendation 8.1.1 Avoid long functions and ensure that each function contains no more than 50 lines (non-null and non-comment). +A function should be displayed on one screen (no longer than 50 lines). It should do only one thing, and do it well. + +Long functions often mean that the functions are too complex to implement more than one function, or overly detailed but not further abstracted. + +Exception: Some implementation algorithm functions may be longer than 50 lines due to algorithm convergence and functional comprehensiveness. + +Even if a long function works very well now, once someone modifies it, new problems may occur, even causing bugs that are difficult to discover. +It is recommended that you split a long function into several functions that are simpler and easier to manage, facilitating code comprehension and modification. + +## Inline Functions + +### Recommendation 8.2.1 An inline function cannot exceed 10 lines. +**Note**: An inline function has the same characteristics of a normal function. The difference between an inline function and a normal function lies in the processing of function calls. When a general function is called, the program execution right is transferred to the called function, and then returned to the function that calls it. When an inline function is called, the invocation expression is replaced with an inline function body. + +Inline functions are only suitable for small functions with only 1-10 lines. For a large function that contains many statements, the function call and return overheads are relatively trivial and do not need to be implemented by an inline function. Most compilers may abandon the inline mode and use the common method to call the function. + +If an inline function contains complex control structures, such as loop, branch (switch), and try-catch statements, the compiler may regard the function as a common function. +**Virtual functions and recursive functions cannot be used as inline functions**. + +## Function Parameters + +### Recommendation 8.3.1 Use a reference instead of a pointer for function parameters. + +**Note**: A reference is more secure than a pointer because it is not empty and does not point to other targets. Using a reference stops the need to check for illegal null pointers. + +Use const to avoid parameter modification, so that readers can clearly know that a parameter is not going to be modified. This greatly enhances code readability. + +### Recommendation 8.3.2 Use strongly typed parameters. Do not use void*. +While different languages have their own views on strong typing and weak typing, it is generally believed that C/C++ is a strongly typed language. Since we use such a strongly typed language, we should keep this style. +An advantage of this is the compiler can find type mismatch problems at the compilation stage. + +Using strong typing helps the compiler find more errors for us. Pay attention to the usage of the FooListAddNode function in the following code: +```cpp +struct FooNode { + struct List link; + int foo; +}; + +struct BarNode { + struct List link; + int bar; +} + +void FooListAddNode(void *node) { // Bad: Here, the void * type is used to transfer parameters. + FooNode *foo = (FooNode *)node; + ListAppend(&fooList, &foo->link); +} + +void MakeTheList() { + FooNode *foo = nullptr; + BarNode *bar = nullptr; + ... + + FooListAddNode(bar); // Wrong: In this example, the foo parameter was supposed to be transferred, but the bar parameter is accidentally transferred instead. However, no error is reported. +} +``` + +1. You can use the template function to change the parameter type. +2. A base class pointer can be used to implement polymorphism. + +### Recommendation 8.3.3 A function can have a maximum of five parameters. +If a function has too many parameters, it is apt to be affected by external changes, and therefore maintenance is affected. Too many parameters will also increase the testing workload. + +If a function has more than five parameters, you can: +- Split the function. +- Combine related parameters into a struct. + +# 9 Other C++ Features + +## Constants and Initialization + +Unchanged values are easier to understand, trace, and analyze. Therefore, use constants instead of variables as much as possible. When defining values, use const as a default. + +### Recommendation 9.1.1 Do not use macros to replace constants. + +**Note**: Macros are a simple text replacement that is completed in the preprocessing phase. When an error is reported, the corresponding value is reported. During tracing and debugging, the value is also displayed instead of the macro name. A macro does not support type checking and is insecure. A macro has no scope. + +```cpp +#define MAX_MSISDN_LEN 20 // Bad + +// Use the const constant in C++. +const int kMaxMsisdnLen = 20; // Good + +// In versions later than C++ 11, constexpr can be used. +constexpr int kMaxMsisdnLen = 20; +``` + +### Recommendation 9.1.2 A group of related integer constants must be defined as an enumeration. + +**Note**: Enumerations are more secure than `#define` or `const int`. The compiler checks whether a parameter value is within the enumerated value range to avoid errors. + +```cpp +// Good example: +enum Week { + kSunday, + kMonday, + kTuesday, + kWednesday, + kThursday, + kFriday, + kSaturday +}; + +enum Color { + kRed, + kBlack, + kBlue +}; + +void ColorizeCalendar(Week today, Color color); + +ColorizeCalendar(kBlue, kSunday); // Compilation error. The parameter type is incorrect. + +// Bad example: +const int kSunday = 0; +const int kMonday = 1; + +const int kRed = 0; +const int kBlack = 1; + +bool ColorizeCalendar(int today, int color); +ColorizeCalendar(kBlue, kSunday); // No error is reported. +``` + +When an enumeration value needs to correspond to a specific value, explicit value assignment is required during declaration. Otherwise, do not assign explicit values. This will prevent repeated assignment and reduce the maintenance workload (when adding and deleting members). + +```cpp +// Good example: Device ID defined in the S protocol. It is used to identify a device type. +enum DeviceType { + kUnknown = -1, + kDsmp = 0, + kIsmg = 1, + kWapportal = 2 +}; +``` + + + +### Recommendation 9.1.3 Magic numbers cannot be used. +So-called magic numbers are the numbers that are unintelligible and difficult to understand. + +Some numbers can be understood based on context. +For example, you may understand the number 12 in certain contexts. +type = 12; is not intelligible (and a magic number), but `month = year * 12`; can be understood, so we wouldn't really class this as a magic number. +The number 0 is often seen as a magic number. For example, `status = 0`; cannot truly express any status information. + +Solution: +Comments can be added for numbers that are used locally. +For the numbers that are used multiple times, you must define them as constants and give them descriptive names. + +The following cases are forbidden: +No symbol is used to explain the meaning of a number, for example, `const int kZero = 0`. +The symbol name limits the value. For example, in`const int kXxTimerInterval = 300`, Use `kXxTimerInterval` instead. + +### Rule 9.1.1 Ensure that a constant has only one responsibility. + +**Note**: A constant is used for only a specific function, that is, a constant cannot be used for multiple purposes. + +```cpp +// Good example: For protocol A and protocol B, the length of the MSISDN is 20. +const unsigned int kAMaxMsisdnLen = 20; +const unsigned int kBMaxMsisdnLen = 20; + +// Or use different namespaces: +namespace namespace1 { +const unsigned int kMaxMsisdnLen = 20; +} + +namespace namespace2 { +const unsigned int kMaxMsisdnLen = 20; +} +``` + +### Recommendation 9.1.4 Do not use memcpy_s or memset_s to initialize non-POD objects. + +**Note**: `POD` is short for `Plain Old Data`, which is a concept introduced in the C++ 98 standard (ISO/IEC 14882, first edition, 1998-09-01). The `POD` types include the original types and aggregate types such as `int`, `char`, `float`, `double`, `enumeration`, `void`, and pointer. Encapsulation and object-oriented features cannot be used (for example, user-defined constructors, assignment operators, destructors, base classes, and virtual functions). + +For non-POD classes, such as class objects of non-aggregate types, virtual functions may exist. Memory layout is uncertain, and is related to the compiler. Misuse of memory copies may cause serious problems. + +Even if a class of the aggregate type is directly copied and compared, and any functions hiding information or protecting data are destroyed, the `memcpy_s` and `memset_s` operations are not recommended. + +For details about the POD type, see the appendix. + + +## Expressions + +### Rule 9.2.1 A switch statement must have a default branch. +In most cases, a switch statement requires a default branch to ensure that there is a default action when the case tag is missing. + +Exception: +If the switch condition variables are enumerated and the case branch covers all values, the default branch is redundant. +Modern compilers can check which case branches are missing in the switch statement and provide an advanced warning. + +```cpp +enum Color { + kRed = 0, + kBlue +}; + +// The switch condition variables are enumerated. Therefore, you do not need to add a default branch. +switch (color) { + case kRed: + DoRedThing(); + break; + case kBlue: + DoBlueThing(); + ... + break; +} +``` + +### Recommendation 9.2.1 When comparing expressions, follow the principle that the left side tends to change and the right side tends to remain unchanged. +When a variable is compared with a constant, placing the constant on the left, for example, if (MAX == v), does not comply with reading habits and if (MAX > v) is more difficult to understand. +The constant should be placed on the right according to common reading and expression conventions. The expression is written as follows: +```cpp +if (value == MAX) { + +} + +if (value < MAX) { + +} +``` +There are special cases: for example, if the expression `if (MIN < value && value < MAX)` is used to describe a range, the first half, as a constant, should be placed on the left. + +You do not need to worry about writing '==' as '=' because a compilation alarm will be generated for `if (value = MAX)` and an error will be reported by other static check tools. Use the tool to solve such writing errors and ensure that the code must be readable. + + +## Type Casting + +Do not use type branches to customize behavior. Type branch customization behavior is prone to errors and is an obvious sign of attempting to compile C code using C++. This is very inflexible technology. If you forget to modify all branches when adding a new type to a compiler, you will not be notified. Use templates and virtual functions to let the type define itself rather than letting the calling side determine behavior. + +It is recommended that type casting be avoided. We should consider the data type of each type of data in the code design instead of overusing type casting to solve type conflicts. When designing a basic type, consider the following: +- Whether it is unsigned or signed? +- Is it suitable for float or double? +- Should you use int8, int16, int32, or int64 bit lengths? + +However, we cannot prohibit the use of type casting because the C++ language is a machine-oriented programming language, involving pointer addresses, and we interact with various third-party or underlying APIs. Their type design may not be reasonable and type casting tends to occur in the adaptation process. + +Exception: When calling a function, if we do not want to process the result of the function, first consider whether this is your best choice. If you do not want to process the return value of the function, cast it to void. + +### Rule 9.3.1 If type casting is required, use the type casting provided by the C++ instead of the C style. + +**Note**: + +The type casting provided by C++ is more targeted, easy to read, and more secure than the C style. C++ provides the following types of casting: +- Type casting: +1. `dynamic_cast`: It is used to inherit the downstream transformation of the system. `dynamic_cast` has the type check function. Design the base class and derived class to avoid using dynamic_cast for casting. +2. `static_cast`: It is similar to the C style casting, which can be used to convert a value, or to convert the pointer or reference of a derived class into a base class pointer or reference. This casting is often used to eliminate type ambiguity brought on by multiple inheritance, which is relatively safe. If it is a pure arithmetic conversion, use the braces as stated in the following text. +3. `reinterpret_cast`: It is used to convert irrelevant types. `reinterpret_cast` forces the compiler to reinterpret the memory of a certain type of objects into another type, which is an unsafe conversion. It is recommended that `reinterpret_cast` be used as little as possible. +4. `const_cast`: It is used to remove the `const` attribute of an object so that the object can be modified. It is recommended that `const_cast` be used as little as possible. + +- Arithmetic conversion: (Supported by C++ 11 and later versions) + If the type information is not lost, for example, the casting from float to double, or from int32 to int64, the initial mode of braces is recommended. +```cpp + double d{ someFloat }; + int64_t i{ someInt32 }; +``` + +### Recommendation 9.3.1 Avoid using `dynamic_cast`. +1. `dynamic_cast` depends on the RTTI of C++ so that the programmer can identify the type of the object in C++ at run time. +2. `dynamic_cast` indicates that a problem occurs in the design of the base class and derived class. The derived class destroys the contract of the base class and it is necessary to use `dynamic_cast` to convert the class to a subclass for special processing. In this case, it is more desirable to improve the design of the class, instead of using `dynamic_cast` to solve the problem. + +### Recommendation 9.3.2 Avoid using `reinterpret_cast`. + +**Note**: `reinterpret_cast` is used to convert irrelevant types. Trying to use `reinterpret_cast` to force a type to another type destroys the security and reliability of the type and is an insecure casting method. Avoid casting between different types. + +### Recommendation 9.3.3 Avoid using `const_cast`. + +**Note**: The `const_cast` command is used to remove the `const` and `volatile` properties of an object. + +The action of using a pointer or reference after the const_cast conversion to modify the const property of an object is undefined. + +```cpp +// Bad example: +const int i = 1024; +int* p = const_cast(&i); +*p = 2048; // The action is undefined. +``` + +```cpp +// Bad example: +class Foo { + public: + Foo() : i(3) {} + + void Fun(int v) { + i = v; + } + + private: + int i; +}; + +int main(void) { + const Foo f; + Foo* p = const_cast(&f); + p->Fun(8); // The action is undefined. +} + +``` + + +## Resource Allocation and Release + +### Rule 9.4.1 When a single object is released, delete is used. When an array object is released, delete [] is used. +Note: Delete is used to delete a single object, and delete [] is used to delete an array object. Reason: + +- new: Apply for memory from the system and call the corresponding constructor to initialize an object. +- new[n]: Apply for memory for n objects and call the constructor n times for each object to initialize them. +- delete: Call the corresponding destructor first and release the memory of an object. +- delete[]: Call the corresponding destructor for each object and release their memory. + +If the usage of new and delete does not match this format, the results are unknown. For a non-class type, new and delete will not call the constructor or destructor. + +The incorrect format is as follows: +```cpp +const int KMaxArraySize = 100; +int* numberArray = new int[KMaxArraySize]; +... +delete numberArray; +numberArray = NULL; +``` + +The correct format is as follows: +```cpp +const int KMaxArraySize = 100; +int* numberArray = new int[KMaxArraySize]; +... +delete[] numberArray; +numberArray = NULL; +``` + +## Standard Template Library + +The standard template library (STL) varies between modules. The following table lists some basic rules and suggestions. + +### Rule 9.5.1 Do not save the pointer returned by c_str () of std::string. + +Note: The C++ standard does not specify that the string::c_str () pointer is permanently valid. Therefore, the STL implementation used can return a temporary storage area and release it quickly when calling string::c_str (). Therefore, to ensure the portability of the program, do not save the result of string::c_str (). Instead, call it directly. + +Example: + +```cpp +void Fun1() { + std::string name = "demo"; + const char* text = name.c_str(); // After the expression ends, the life cycle of name is still in use and the pointer is valid. + + // If a non-const member function (such as operator[] and begin()) of the string type is invoked and the string is therefore modified, + // the text content may become unavailable or may not be the original character string. + name = "test"; + name[1] = '2'; + + // When the text pointer is used next time, the string is no longer "demo". +} + +void Fun2() { + std::string name = "demo"; + std::string test = "test"; + const char* text = (name + test).c_str(); // After the expression ends, the temporary object generated by the + operator may be destroyed, and the pointer may be invalid. + + // When the text pointer is used next time, it no longer points to the valid memory space. +} +``` +Exception: In rare cases where high performance coding is required , you can temporarily save the pointer returned by string::c_str() to match the existing functions which support only the input parameters of the const char* type. However, you should ensure that the life cycle of the string object is longer than that of the saved pointer, and that the string object is not modified within the life cycle of the saved pointer. + + +### Recommendation 9.5.1 Use std::string instead of char*. + +Note: Using string instead of `char*` has the following advantages: +1. There is no need to consider the null character '\0' at the end. +2. You can directly use operators such as +, =, and ==, and other character string operation functions. +3. No need to consider memory allocation operations. This helps avoid explicit usage of new and delete and the resulting errors. + +Note that in some STL implementations, string is based on the copy-on-write policy, which causes two problems. One is that the copy-on-write policy of some versions does not implement thread security, and the program breaks down in multi-threaded environments. Second, dangling pointers may be caused when a dynamic link library transfers the string based on the copy-on-write policy, due to the fact that reference count cannot be reduced when the library is unloaded. Therefore, it is important to select a reliable STL implementation to ensure the stability of the program. + +Exceptions: +When an API of a system or other third-party libraries is called, only `char*` can be used for defined interfaces. However, before calling the interfaces, you can use string. When calling the interfaces, you can use string::c_str () to obtain the character pointer. +When a character array is allocated as a buffer on the stack, you can directly define the character array without using string or containers such as `vector`. + +### Rule 9.5.2 Do not use auto_ptr. +Note: The std::auto_ptr in the STL library has an implicit ownership transfer behavior. The code is as follows: +```cpp +auto_ptr p1(new T); +auto_ptr p2 = p1; +``` +After the second line of statements is executed, p1 does not point to the object allocated in line 1 and becomes NULL. Therefore, auto_ptr cannot be placed in any standard containers. +This ownership transfer behavior is not expected. In scenarios where ownership must be transferred, implicit transfer should not be used. This often requires the programmer to keep extra attention on code that uses auto_ptr , otherwise access to a null pointer will occur. +There are two common scenarios for using auto_ptr . One is to transfer it as a smart pointer to outside of the function that generates the auto_ptr , and the other is to use auto_ptr as the RAII management class. Resources are automatically released when the lifecycle of auto_ptr expires. +In the first scenario, you can use std::shared_ptr instead. +In the second scenario, you can use std::unique_ptr in the C++ 11 standard. std::unique_ptr is a substitute for std::auto_ptr and supports explicit ownership transfer. + +Exceptions: +Before the C++ 11 standard is widely used, std::auto_ptr can be used in scenarios where ownership needs to be transferred. However, it is recommended that std::auto_ptr be encapsulated. The copy constructor and assignment operator of the encapsulation class should not be used, so that the encapsulation class cannot be used in a standard container. + + +### Recommendation 9.5.2 Use the new standard header files. + +Note: +When using the standard header file of C++, use `` instead of ``. + +## Usage of const +Add the keyword const before the declared variable or parameter (example: `const int foo`) to prevent the variable from being tampered with. Add the const qualifier to the function in the class (example: `class Foo {int Bar (char c) const;} ;`) to make sure the function does not modify the status of the class member variable. const variables, data members, functions, and parameters ensure that the type detection during compilation is accurate and errors are found as soon as possible. Therefore, we strongly recommend that const be used in any possible case. +Sometimes it is better to use constexpr of C++ 11 to define real constants. + +### Rule 9.6.1 For formal parameters of pointer and reference types, if the parameters do not need to be modified, use const. +Unchanged values are easier to understand, trace, and analyze. const is used as the default option and is checked during compilation to make the code more secure and reliable. +```cpp +class Foo; + +void PrintFoo(const Foo& foo); +``` + +### Rule 9.6.2 For member functions that do not modify member variables, use const. +Declare the member function as const whenever possible. The access function should always be const. So long as the function of a member is not modified, the function is declared with const. + +```cpp +class Foo { + public: + + // ... + + int PrintValue() const // const’s usage here modifies member functions and does not modify member variables. + std::cout << value << std::endl; + } + + int GetValue() const // and again here. + return value; + } + + private: + int value; +}; +``` + +### Recommendation 9.6.1 Member variables that will not be modified after initialization should be defined as constants. + +```cpp +class Foo { + public: + Foo(int length) : dataLength(length) {} + private: + const int dataLength; +}; +``` + +## Templates + +Template programming allows for extremely flexible interfaces that are type safe and high performance, enabling reuse of code of different types but with the same behavior. + +The disadvantages of template programming are as follows: + +1. The techniques used in template programming are often obscure to anyone but language experts. Code that uses templates in complicated ways is often unreadable, and is hard to debug or maintain. +2. Template programming often leads to extremely poor compiler time error messages: even if an interface is simple, complicated implementation details become visible when the user does something wrong. +3. If the template is not properly used, the code will be over expanded during runtime. +4. It is difficult to modify or refactor the template code. The template code is expanded in multiple contexts, and it is hard to verify that the transformation makes sense in all of them. + +Therefore, it is recommended that __template programming be used only in a small number of basic components and basic data structure__. When using the template programming, minimize the __complexity as much as possible__, and __avoid exposing the template__. It is better to hide programming as an implementation detail whenever possible, so that user-facing headers are readable. And you should write sufficiently detailed comments for code that uses templates. + + +## Macros +In the C++ language, it is strongly recommended that complex macros be used as little as possible. +- For constant definitions, use `const` or `enum` as stated in the preceding sections. +- For macro functions, try to be as simple as possible, comply with the following principles, and use inline functions and template functions for replacement. + +```cpp +// The macro function is not recommended. +#define SQUARE(a, b) ((a) * (b)) + +// Use the template function and inline function as a replacement. +template T Square(T a, T b) { return a * b; } +``` + +For details about how to use macros, see the related chapters about the C language specifications. +**Exception**: For some common and mature applications, for example, encapsulation for new and delete, the use of macros can be retained. + + +## Others + +### Recommendation 9.9.1 Use '\n' instead of std::endl when exporting objects to a file. +Note: std::endl flushes content in the buffer to a file, which may affect the performance. + +# 10 Modern C++ Features + +As the ISO released the C++ 11 language standard in 2011 and released the C++ 17 in March 2017, the modern C++ (C++ 11/14/17) adds a large number of new language features and standard libraries that improve programming efficiency and code quality. +This chapter describes some guidelines for modern C++ use, to avoid language pitfalls. + +## Code Simplicity and Security Improvement +### Recommendation 10.1.1 Use `auto` properly. + + +* `auto` can help you avoid writing verbose, repeated type names, and can also ensure initialization when variables are defined. +* The `auto` type deduction rules are complex and need to be read carefully. +* If using `auto` makes the code clearer, use a specific type of it and use it only for local variables. + +**Example** + +```cpp +// Avoid verbose type names. +std::map::iterator iter = m.find(val); +auto iter = m.find(val); + +// Avoid duplicate type names. +class Foo {...}; +Foo* p = new Foo; +auto p = new Foo; + +// Ensure that the initialization is successful. +int x; // The compilation is correct but the variable is not initialized. +auto x; // The compilation failed. Initialization is needed. +``` + +`auto` type deduction may cause the following problems: + +```cpp +auto a = 3; // int +const auto ca = a; // const int +const auto& ra = a; // const int& +auto aa = ca; // int, const and reference are neglected. +auto ila1 = { 10 }; // std::initializer_list +auto ila2{ 10 }; // std::initializer_list + +auto&& ura1 = x; // int& +auto&& ura2 = ca; // const int& +auto&& ura3 = 10; // int&& + +const int b[10]; +auto arr1 = b; // const int* +auto& arr2 = b; // const int(&)[10] +``` + +If you do not pay attention to `auto` type deduction and ignore the reference, hard-to-find performance problems may be created. + +```cpp +std::vector v; +auto s1 = v[0]; // auto deduction changes s1 to std::string in order to copy v[0]. +``` + +If the `auto` is used to define an interface, such as a constant in the header file, it may be possible that the type has changed because the developer has modified the value. + +In a loop, consider using auto & and auto * to traverse complex objects to improve performance. + +```cpp +for (auto &stmt : bb->GetStmtNodes()) { +... +} +``` + +### Rule 10.1.1 Use the keyword `override` when rewriting virtual functions. + +The keyword `override` ensures that the function is a virtual function and an overridden virtual function of the base class. If the subclass function is different from the base class function prototype, a compilation alarm is generated. + +If you modify the prototype of a base class virtual function but forget to modify the virtual function overridden by the subclass, you can find inconsistency during compilation. You can also avoid forgetting to modify the overridden function when there are multiple subclasses. + +**Example** + +```cpp +class Base { + public: + virtual void Foo(); + void Bar(); +}; + +class Derived : public Base { + public: + void Foo() const override; // Compilation failed: derived::Foo is different from that of the prototype of base::Foo and is not overridden. + void Foo() override; // Compilation successful: derived::Foo overrode base::Foo. + void Bar() override; // Compilation failed: base::Bar is not a virtual function. +}; +``` + +**Summary** +1. When defining the virtual function for the first time based on the base class, use the keyword `virtual`. +2. When the subclass overrides the base class’ virtual function, use the keyword `virtual`. +3. For the non-virtual function, do not use `virtual` or `override`. + +### Rule: 10.1.2 Use the keyword delete to `delete` functions. + +The `delete` keyword is clearer and the application scope is wider than a class member function that is declared as private and not implemented. + +**Example** + +```cpp +class Foo { + private: + // Whether the copy structure is deleted or not is unknown because usually only the header file is checked. + Foo(const Foo&); +}; + +class Foo { + public: + // Explicitly delete the copy assignment operator. + Foo& operator=(const Foo&) = delete; +}; +``` + +The `delete` keyword can also be used to delete non-member functions. + +```cpp +template +void Process(T value); + +template<> +void Process(void) = delete; +``` + +### Rule 10.1.3 Use `nullptr` instead of `NULL` or `0`. + +For a long time, C++ has not had a keyword that represents a null pointer, which is embarrassing: + +```cpp +#define NULL ((void *)0) + +char* str = NULL; // Error: void* cannot be automatically converted to char*. + +void(C::*pmf)() = &C::Func; +if (pmf == NULL) {} // Error: void* cannot be automatically converted to the pointer that points to the member function. +``` + +If `NULL` is defined as `0` or `0L`, the above problems can be solved. + +Alternatively, use `0` directly in places where null pointers are required. However, another problem occurs. The code is not clear, especially when the `auto` is used for automatic deduction. + +```cpp +auto result = Find(id); +if (result == 0) { // Does Find() return a pointer or an integer? + // do something +} +``` + +Literally `0` is of the `int` type (`0L` is the `long` type). Therefore, neither `NULL` nor `0` is a pointer type. +When a function of the pointer or integer type is overloaded, `NULL` or `0` calls only the overloaded pointer function. + +```cpp +void F(int); +void F(int*); + +F(0); // Call F(int) instead of F(int*). +F(NULL); // Call F(int) instead of F(int*). +``` + +In addition, `sizeof(NULL) == sizeof(void*)` does not always make sense, which is a potential risk. + +Summary: If `0` or `0L` is directly used, the code is not clear and type security cannot be ensured. If `NULL` is used, the type security cannot be ensured. These are all potential risks. + +`nullptr` has many advantages. It literally represents the null pointer and makes the code clearer. More to the point, it is no longer an integer type. + +`nullptr` is of the `std::nullptr_t` type. `std::nullptr_t` can be implicitly converted into all original pointer types, so that `nullptr` can represent a null pointer that points to any type. + +```cpp +void F(int); +void F(int*); +F(nullptr); // Call F(int*). + +auto result = Find(id); +if (result == nullptr) { // Find() returns a pointer. + // do something +} +``` + +### Recommendation 10.1.2 Use `using` instead of `typedef`. +For versions earlier than `C++11`, you can define the alias of the type by using `typedef`. No one wants to repeat code like `std::map>`. + +```cpp +typedef std::map> SomeType; +``` + +Using alias for the type is actually encapsulating the type. This encapsulation makes the code clearer, and to a large extent avoids the bulk modification caused by the type change. +For versions later than `C++ 11`, `using` is provided to implement `alias declarations`: + +```cpp +using SomeType = std::map>; +``` + +Compare the two formats: + +```cpp +typedef Type Alias; // It cannot be told whether Type or Alias is at the front. +using Alias = Type; // The format confirms to the assignment rule. It is easy to understand and helps reduce errors. +``` + +If this is not enough to prove the advantages of `using`, the alias template may be a better example: + +```cpp +//: Only one line of code is need to define an alias for a template. +template +using MyAllocatorVector = std::vector>; + +MyAllocatorVector data; // An alias for a template defined with "using". + +template +class MyClass { + private: + MyAllocatorVector data_; // Another. +}; +``` + +`typedef` does not support alias templates and they have to be hacked in. + +```cpp +// A template is used for packaging typedef. Therefore, a template class is needed. +template +struct MyAllocatorVector { + typedef std::vector> type; +}; + +MyAllocatorVector::type data; // ::type needs to be added when using typedef to define an alias. + +template +class MyClass { + private: + typename MyAllocatorVector::type data_; // For a template class, typename is also needed in addition to ::type. +}; +``` + +### Rule 10.1.4 Do not use std::move to operate the const object. +Literally, `std::move` means moving an object. The const object cannot be modified and cannot be moved. Therefore, using `std::move` to operate the const object may confuse code readers. +Regarding actual functions, `std::move` converts an object to the rvalue reference type. It can convert the const object to the rvalue reference of const. Because few types define the move constructor and the move assignment operator that use the const rvalue reference as the parameter, the actual function of code is often degraded to object copy instead of object movement, which brings performance loss. + +**Bad example:** +```cpp +std::string gString; +std::vector gStringList; + +void func() { + const std::string myString = "String content"; + gString = std::move(myString); // Bad: myString is not moved. Instead, it is copied. + const std::string anotherString = "Another string content"; + gStringList.push_back(std::move(anotherString)); // Bad: anotherString is not moved. Instead, it is copied. +} +``` + +## Smart Pointers +### Recommendation 10.2.1 Preferentially use the smart pointer instead of the raw pointer to manage resources. + +Avoid resource leakage. + +**Example**: + +```cpp +void Use(int i) { + auto p = new int {7}; // Bad: Initializing local pointers with new. + auto q = std::make_unique(9); // Good: Guarantee that memory is released. + if (i > 0) { + return; // Return and possible leak. + } + delete p; // Too late to salvage. +} +``` + +**Exception:** +Raw pointers can be used in scenarios such as performance sensitivity and compatibility. + +### Rule 10.2.1 Use `unique_ptr` instead of `shared_ptr`. + +1. Using `shared_ptr` a lot has an overhead (atomic operations on the `shared_ptr`s reference count have a measurable cost). +2. Shared ownership in some cases (such as circular dependency) may create objects that can never be released. +3. Shared ownership can be an attractive alternative to careful ownership design but it may obfuscate the design of a system. + +### Rule 10.2.2 Use `std::make_unique` instead of `new` to create `unique_ptr`. + +1. `make_uniqe` provides a simpler creation method. +2. `make_uniqe` ensures the exception safety of complex expressions. + +**Example** + +```cpp +// Bad: MyClass appears twice, which carries a risk of inconsistency. +std::unique_ptr ptr(new MyClass(0, 1)); +// Good: MyClass appears once and there is no possibility of inconsistency. +auto ptr = std::make_unique(0, 1); +``` + +Recurrence of types may cause serious problems, and it is difficult to find them: + +```cpp +// The code compiles fine, but new and delete usage does not match. +std::unique_ptr ptr(new uint8_t[10]); +std::unique_ptr ptr(new uint8_t); +// No exception safety: The compiler may calculate parameters in the following order: +// 1. Allocate the memory of Foo. +// 2. Construct Foo. +// 3. Call Bar. +// 4. Construct unique_ptr. +// If Bar throws an exception, Foo is not destroyed and a memory leak occurs. +F(unique_ptr(new Foo()), Bar()); + +// Exception safety: Calling of function is not interrupted. +F(make_unique(), Bar()); +``` + +**Exception:** +`std::make_unique` does not support user-defined `deleter`. +In the scenario where the `deleter` needs to be customized, it is recommended that `make_unique` of the customized version be implemented in its own namespace. +`Using `new` to create `unique_ptr` with the user-defined `deleter` is the last choice. + +### Rule 10.2.3 Create `shared_ptr` by using `std::make_shared` instead of `new`. + +In addition to the consistency factor similar to that in `std::make_unique` when using `std::make_shared`, performance is also a factor to consider. +`std::shared_ptr` manages two entities: +* Control block (storing reference count, `deleter`, etc.) +Managed objects + +When `std::make_shared` creates `std::shared_ptr`, it allocates sufficient memory for storing control blocks and managed objects on the heap at a time. When `std::shared_ptr(new MyClass)`is used to create `std::shared_ptr`, except that `new MyClass` triggers a heap allocation, the constructor function of `std::shard_ptr` triggers the second heap allocation, resulting in extra overhead. + +**Exception:** +Similar to `std::make_unique`, `std::make_shared` does not support `deleter` customization. + +## Lambda +### Recommendation 10.3.1 Use `lambda` to capture local variables or write local functions when normal functions do not work. + +Functions cannot capture local variables or be declared at local scope. If you need those things, choose `lambda` instead of handwritten `functor`. +On the other hand, `lambda` and `functor` objects do not overload. If overload is required, use a function. +If both `lambda` and functions work, a function is preferred. Use the simplest tool. + +**Example** + +```cpp +// Write a function that accepts only an int or string. +// -- Overloading is natural. +void F(int); +void F(const string&); + +// The local state needs to be captured or appear in the statement or expression range. +// -- A lambda is natural. +vector v = LotsOfWork(); +for (int taskNum = 0; taskNum < max; ++taskNum) { + pool.Run([=, &v] {...}); +} +pool.Join(); +``` + +### Rule 10.3.1 Avoid capturing by reference in lambdas that will be used nonlocally. + +When used in non-local scope, `lambdas` includes returned values which are stored on the heap, or passed to other threads. Local pointers and references should not outlive their scope. Capturing by reference in `lambdas` indicates storing a reference to a local object. If this leads to a reference that exceeds the local variable lifecycle, capturing by reference should not be used. + +**Example** + +```cpp +// Bad +void Foo() { + int local = 42; + // Capture a reference to a local variable. + // After the function returns results, local no longer exists, + // Process() call will have undefined behavior. + threadPool.QueueWork([&]{ Process(local); }); +} + +Good +void Foo() { + int local = 42; + // Capture a copy of local. + // Since a copy of local is made, it will be always available for the call. + threadPool.QueueWork([=]{ Process(local); }); +} +``` + +### Recommendation 10.3.2 All variables are explicitly captured if `this` is captured. + +The `[=]` in the member function seems to indicate capturing by value but actually it is capturing data members by reference because it captures the invisible `this` pointer by value. Generally, it is recommended that capturing by reference be avoided. If it is necessary to do so, write `this` explicitly. + +**Example** + +```cpp +class MyClass { + public: + void Foo() { + int i = 0; + + auto Lambda = [=]() { Use(i, data_); }; // Bad: It looks like coping or capturing by value but member variables are actually captured by reference. + + data_ = 42; + Lambda(); // Call use(42); + data_ = 43; + Lambda(); // Call use(43); + + auto Lambda2 = [i, this]() { Use(i, data_); }; // Good: the most explicit and least confusing method. + } + + private: + int data_ = 0; +}; +``` + +### Recommendation 10.3.3 Avoid default capture modes. + +The lambda expression provides two default capture modes: by-reference (&) and by-value (=). +By default, the "by-reference" capture mode will implicitly capture the reference of all local variables, which will easily lead to dangling references. By contrast, explicitly writing variables that need to be captured can make it easier to check the life cycle of an object and reduce the possibility of making a mistake +By default, the "by-value” capture mode will implicitly capture this pointer, and it is difficult to find out which variables the lambda function depends on. If a static variable exists, the reader mistakenly considers that the lambda has copied a static variable. +Therefore, it is required to clearly state the variables that lambda needs to capture, instead of using the default capture mode. + +**Bad example:** +```cpp +auto func() { + int addend = 5; + static int baseValue = 3; + + return [=]() { // Only addend is actually copied. + ++baseValue; // The modification will affect the value of the static variable. + return baseValue + addend; + }; +} +``` + +**Good example:** +```cpp +auto func() { + int addend = 5; + static int baseValue = 3; + + return [addend, baseValue = baseValue]() mutable { // Uses the C++14 capture initialization to copy a variable. + ++baseValue; // Modifying the copy of a static variable does not affect the value of the static variable. + return baseValue + addend; + }; +} +``` + +Reference: Effective Modern C++: Item 31: Avoid default capture modes. + +## Interfaces +### Recommendation 10.4.1 Use `T*` or `T&` arguments instead of a smart pointer in scenarios where ownership is not involved. + +1. Passing a smart pointer to transfer or share ownership should only be used when the ownership mechanism is explicitly required. +2. Passing a smart pointer (for example, passing the `this` smart pointer) restricts the use of a function to callers using smart pointers. +3. Passing a shared smart pointer adds a runtime performance cost. + +**Example**: + +```cpp +// Accept any int*. +void F(int*); + +// Accept only integers for which you want to transfer ownership. +void G(unique_ptr); + +// Accept only integers for which you want to share ownership. +void G(shared_ptr); + +// Does not need to change the ownership but requires ownership of the caller. +void H(const unique_ptr&); + +// Accept any int. +void H(int&); + +//Bad example +void F(shared_ptr& w) { + // ... + Use(*w); // When only w is used, lifecycle management is not required. + // ... +}; +``` + + +# 11 Secure Coding Standard + +## Basic Principles + +1. Programs must strictly verify external data. During external data processing, programmers must keep this in mind and not make any assumption that external data meets expectations. External data must be strictly checked before being used. + Programmers must abide by this principle in the complex attack environment to ensure that the program execution process is in line with expected results. + +2. The attack surface of code must be minimized. The code implementation should be as simple as possible to avoid unnecessary data exchange with external environments. Excess attack surfaces will increase the attack probability. Therefore, avoid exposing internal data processing of programs to external environments. + +3. Defensive coding strategies must be used to compensate for potential negligence of programmers. Every man is liable to error. Due to uncertainties of external environments and the differences in the experience and habits of programmers, it is hard for the code execution process to fully meet expectations. + Therefore, defensive strategies must be adopted in the coding process to minimize the defects caused by the negligence of programmers. + The measures include: + +- Defining an initial value for the declaration of variables. +- Exercise caution in using global variables. +- Avoid using complex and error-prone functions. +- Do not use error-prone mechanisms of compilers/operating systems. +- Deal with the resource access process carefully. +- Do not change the runtime environment of the operating system. For example, do not create temporary files, modify environment variables, or create processes. +- Rectify errors strictly. +- Use the debugging assertion (ASSERT) properly. + +## Variables + +### Rule 11.2.1: Define an initial value for the declaration of pointer variables, variables indicating resource descriptors, or BOOL variables. + +Note: Defining an initial value for the declaration of variables can prevent programmers from referencing uninitialized variables. + +Good example: + +```cpp +SOCKET s = INVALID_SOCKET; +unsigned char *msg = nullptr; +int fd = -1; +``` + +Bad example: In the following code, no initial value is defined for the declaration of variables. As a result, an error occurs in the free step. + +```cpp +char *message; // Error! char *message = nullptr; is required. + +if (condition) { + message = (char *)malloc(len); +} + +if (message != nullptr) { + free(message); //If the condition is not met, the uninitialized memory will be freed. +} +``` + +### Rule 11.2.2: Assign a new value to the variable pointing to a resource handle or descriptor immediately after the resource is freed. + +Note: After a resource is freed, a new value must be immediately assigned to the corresponding variable to prevent the re-reference of the variable. If the release statement is in the last line of the scope, you do not need to assign a new value. + +Good example: + +```cpp +SOCKET s = INVALID_SOCKET; +... +closesocket(s); +s = INVALID_SOCKET; + +unsigned char *msg = nullptr; +... +free(msg); +msg = nullptr; +``` + +### Rule 11.2.3: Ensure that local variables in a function do not take up too much space. + +When a program is running, the local variables in the function are stored in the stack, and the stack size is limited. If a large static array is requested, an error may occur. + It is recommended that the size of the static array not exceed 0x1000. + +In the following code, buff requests a large stack but the stack space is insufficient. As a result, stack overflow occurs in the program. + +```c++ +constexpr int MAX_BUF = 0x1000000; +int Foo() { + char buff[MAX_BUFF] = {0}; // Bad + ... +} +``` + +## Assertions + +### Principles + +Assertions in code consist of ASSERT and CHECK_FATAL. ASSERT is used to determine conditions in DEBUG mode. If conditions are not met, the program exits directly. CHECK_FATAL is used to detect exceptions during program running. If the conditions are not met, the program exits. + +CHECK_FATAL is applicable to scenarios where the input and resource application are not under control. Example: + +```cpp +CHECK_FATAL(mplName.rfind(kMplSuffix) != std::string::npos, "File name %s does not contain .mpl", mplName.c_str()); // The file name does not meet the requirements. + +CHECK_FATAL(intrinCall->GetReturnVec().size() == 1, "INTRN_JAVA_FILL_NEW_ARRAY should have 1 return value"); // The logic restriction is not met. + +CHECK_FATAL(func->GetParamSize() <= 0xffff, "Error:the argsize is too large"); // The validity is verified. + +void *MemPool::Malloc(size_t size) { + ... + CHECK_FATAL(b != nullptr, "ERROR: Malloc error"); // Failed to apply for memory. +} +``` + +ASSERT is applicable to scenarios where you want to locate bugs in the defensive programming mode. Example: + +```cpp +ASSERT(false, "should not be here"); + +ASSERT(false, "Unknown opcode for FoldIntConstComparison"); +``` + +### Recommendation 11.3.1 Do not use ASSERT to verify whether a pointer with security context is nullptr. + +Note: The compiler is an offline compilation tool. The impact of process breakdown is much less than that of online services. Therefore, the defensive programming mode should be reduced. Not all input parameters require null pointer verification. Instead, the context logic is used to determine whether null pointer verification is required. An input parameter without the nullptr logic does not need to be verified. For details, see the assertion usage principles. + +### Recommendation 11.3.2 Do not use ASSERT to verify whether a data array with security context exceeds the threshold. + +Note: Similar to the null pointer rule, the context logic is used to determine whether to use assertions for out-of-threshold array verification. For details, see the assertion usage principles. + +### Recommendation 11.3.3 Do not use ASSERT to verify integer overflow, truncation, or wraparound in the case of context security. + +Note: In terms of integer overflow caused by addition or multiplication, verification is not required with the context logic guaranteed. In terms of integer truncation and wraparound caused by type conversion, verification is not required with the context logic guaranteed. For details, see the assertion usage principles. + +To ensure that fault tolerance and logic continue to run, you can use conditional statements for verification. + +### Rule 11.3.1 Do not use ASSERT to verify errors that may occur during program runtime. + +Bad example: + +```cpp +FILE *fp = fopen(path, "r"); +ASSERT(fp != nullptr, "nullptr check"); //Incorrect code: Opening the file may fail. + +char *str = (char *)malloc(MAX_LINE); +ASSERT(str != nullptr, "nullptr check"); //Incorrect code: Memory allocation may fail. +ReadLine(fp, str); +``` + +### Rule 11.3.2 Do not modify the runtime environment in ASSERT. + +Note: In the formal release stage of a program, ASSERT is not compiled. To ensure the function consistency between the debugging version and formal version, do not perform any operation, such as value assignment, variable modification, resource operation, or memory application, in ASSERT. + + +In the following code, ASSERT configuration is incorrect. + +```cpp +ASSERT(i++ > 1000); // p1 is modified. +ASSERT(close(fd) == 0); // fd is closed. +``` + +## Exception Mechanisms + +### Rule 11.4.1 Do not use the C++ exception mechanism. + +Note: Do not use the exception mechanism of C++. All errors must be transferred between functions and judged using error values, but not be handled using the exception mechanism. + +Programmers must fully control the entire coding process, build the attacker mindset, enhance secure coding awareness, and attach importance to procedures with potential errors. Using the C++ exception mechanism to handle errors, however, will weaken the security awareness of programmers because it will: + +Disrupt program execution, making the program structure more complex and used resources not cleared. + +Reduce the reusability of code. The code that uses the exception mechanism cannot be reused by the code that does not use the exception mechanism. + +Depend on the compiler, operating system, and processor. The execution performance of the program will deteriorate if the exception mechanism is used. + +Increase the attack surface of a program in the binary layer after the program is loaded. The attacker can overwrite the abnormal processing function address to launch an attack. + + +## Memory + +### Rule 11.5.1: Verify the requested memory size before requesting memory. + +The requested memory size may come from external data and must be verified to prevent memory abuse. The requested memory size must not be 0. +Example: +```cpp +int Foo(int size) { + if (size <= 0) { + //error + ... + } + ... + char *msg = (char *)malloc(size); + ... +} +``` + +### Rule 11.5.2: Check whether memory allocation is successful. + +```cpp +char *msg = (char *)malloc(size); +if (msg != nullptr) { + ... +} +``` + +## Dangerous Functions + +### Rule 11.6.1: Do not use dangerous functions related to memory operations. +Many C functions do not use the destination buffer size as a parameter or consider memory overlapping and invalid pointers. As a result, security vulnerabilities such as buffer overflow may be caused. + +The historical statistics about buffer overflow vulnerabilities show that a majority of the vulnerabilities are caused by memory operation functions that do not consider the destination buffer size. +The following lists the dangerous functions related to memory operations: + +Memory copy functions: memcpy(), wmemcpy(), memmove(), wmemmove() + +Memory initialization function: memset() + +String copy functions: strcpy(), wcscpy(),strncpy(), wcsncpy() + +String concatenation functions: strcat(), wcscat(),strncat(), wcsncat() + +Formatted string output functions: sprintf(), swprintf(), vsprintf(), vswprintf(), snprintf(), vsnprintf() + +Formatted string input functions: scanf(), wscanf(), vscanf(), vwscanf(), fscanf(),fwscanf(),vfscanf(),vfwscanf(),sscanf(), swscanf(), vsscanf(), vswscanf() + +stdin stream-input function: gets() +Use safe functions. For details, see huawei_secure_c. + +Exceptions: In the following cases, external data processing is not involved, and no attack risks exist. Memory operations are complete in this function, and there is no possibility of failure. +Using safe functions causes redundant code, and therefore dangerous functions can be used in these cases. + +(1) Initialize a fixed-length array, or initialize the memory of the structure with a fixed length: +```cpp +BYTE array[ARRAY_SIZE]; + +void Foo() { + char destBuff[BUFF_SIZE]; + ... + memset(array, c1, sizeof(array)); //Assign values to global fixed-length data. + ... + memset(destBuff, c2, sizeof(destBuff)); //Assign values to partial fixed-length data. + ... +} + +typedef struct { + int type; + int data; +} Tag; + +Tag g_tag = {1, 2}; + +void Foo() { + Tag dest; + ... + memcpy((void *)&dest, (const void *)&g_tag, sizeof(Tag)); //Assign values to fixed-length structure. + ... +} +``` + +(2) Initialize memory if function parameters include memory parameters. +```cpp +void Foo(BYTE *buff1, size_t len1, BYTE *buff2, size_t len2) { + ... + memset(buff1, 0, len1); //Clear buff1. + memset(buff2, 0, len2); //Clear buff2. + ... +} +``` + +(3) Assign an initial value after allocating memory from the heap. +```cpp +size_t len = ... +char *str = (char *)malloc(len); +if (str != nullptr) { + memset(str, 0, len); + ... +} +``` + +(4) Copy memory with the same size as the source memory size. +The following code copies a memory block with the same size as srcSize: +```cpp +BYTE *src = ... +size_t srcSize = ... +BYTE *destBuff = new BYTE[srcSize]; +memcpy(destBuff, src, srcSize); +``` + +The following code copies a memory block with the same size as the source character string: +```cpp +char *src = ... +size_t len = strlen(src); +if (len > BUFF_SIZE) { + ... +} +char *destBuff = new char[len + 1]; +strcpy(destBuff, src); +``` + +(5) The source memory stores static character string constants only. (Check whether the destination memory is sufficient during encoding.) +The following code directly copies the string constant "hello" to the array: +```cpp +char destBuff[BUFF_SIZE]; +strcpy(destBuff, "hello"); +``` +The following code concatenates static character string constants: +```cpp +const char *list[] = {"red","green","blue"}; +char destBuff[BUFF_SIZE]; +sprintf(destBuff, "hello %s", list[i]); +``` + diff --git a/doc/en/RcApi.md b/doc/en/RcApi.md new file mode 100644 index 0000000000000000000000000000000000000000..c3568ac28b1e4ab326e3d2b1d00b43507968f8bb --- /dev/null +++ b/doc/en/RcApi.md @@ -0,0 +1,525 @@ +RC API +---- + +Reference counting (RC) is a programming technique of storing the number of references to a resource, such as an object, a block of memory, disk space, and others, and releasing the resource when the number of references becomes 0. RC is used to achieve automatic resource management. RC also refers to a garbage collection algorithm that deallocates objects which are no longer referenced. + +To support RC, OpenArkCompiler provides the following APIs for better code generation. + +## void MCC\_IncRef\_NaiveRCFast(address\_t obj) + +**Function:** + +Increments RC of the object. + +**Input parameter:** + +obj: pointer of the heap object + +**Return value:** + +None + +## void MCC\_DecRef\_NaiveRCFast(address\_t obj) + +**Function:** + +Decrements RC of the object. + +**Input parameter:** + +obj: pointer of the heap object + +**Return value:** + +None + +## void MCC\_ClearLocalStackRef(address\_t \*addr) + +**Function:** + +Clears local reference on the thread stack and decrements RC for the stored reference. + +**Input parameter:** + +addr: address of the local reference on the thread stack + +**Return value:** + +None + +## void MCC\_IncDecRef\_NaiveRCFast(address\_t incObj, address\_t decObj) + +**Function:** + +Increments RC for the object to which incObj points and decrements RC for the object to which decObj points. + +**Input parameter:** + +incObj: address of the object whose RC needs increment + +incObj: address of the object whose RC needs decrement + +**Return value:** + +None + +## void MCC\_IncDecRefReset(address\_t incObj, address\_t \*decAddr) + +**Function:** + +Increments RC for the object to which incObj points, decrements RC for the local variable object stored on the stack address pointer decAddr, and clears the memory to which the stack address pointer decAddr points. + +**Input parameter:** + +incObj: heap object whose RC needs increment + +decAddr: address of the local reference on the stack + +**Return value:** + +None + +## void MCC\_DecRefResetPair(address\_t \*decAddr0, address\_t \*decAddr1) + +**Function:** + +Clears the stack address space to which all parameters point, and decrements RC for the old value of the local variable. + +**Input parameter:** + +decAddr0 and decAddr1: addresses of the local reference on the stack + +**Return value:** + +None + +## void MCC\_SetObjectPermanent(address\_t obj) + +**Function:** + +Sets a heap object to be permanently valid. After being invoked, RC for the object reaches the maximum value. + +**Input parameter:** + +obj: address of the heap object + +**Return value:** + +None + +## address\_t MCC\_LoadVolatileStaticField(address\_t \*fieldAddr) + +**Function:** + +Obtains the value of the volatile static variable and increments RC for the fetched heap object. + +**Input parameter:** + +fieldAddr: address of the volatile static variable + +**Return value:** + +Returns the value of the volatile static variable. + +## address\_t MCC\_LoadRefStatic(address\_t \*fieldAddr) + +**Function:** + +Obtains the value of the static variable and increments RC for the fetched heap object. + +**Input parameter:** + +fieldAddr: address of the static variable + +**Return value** + +Returns the value of the static variable. + +## address\_t MCC\_LoadVolatileWeakField(address\_t obj, address\_t \*fieldAddr) + +**Function:** + +Obtains the value of the volatile variable marked by the weak annotation. If a non-null heap object is obtained, RC for the object will be incremented. + +**Input parameter:** + +obj: address of the heap object + +fieldAddr: address of the volatile variable marked as weak + +**Return value:** + +Returns the value of the volatile variable marked as weak. A null object pointer may be returned. + +## address\_t MCC\_LoadWeakField(address\_t obj, address\_t \*field\_addr) + +**Function:** + +Obtains the value of the variable marked by the weak annotation. If a non-null heap object is obtained, RC for the object will be incremented. + +**Input parameter:** + +obj: address of the heap object + +fieldAddr: address of the variable marked as weak + +**Return value:** + +Returns the value of the variable marked as weak. A null object pointer may be returned. + +## address\_t MCC\_LoadRefField\_NaiveRCFast(address\_t obj, address\_t \*fieldAddr) + +**Function:** + +Obtains the value of the fieldAddr variable, and increments RC for the obtained heap object. + +**Input parameter:** + +obj: address of the heap object + +fieldAddr: address of the variable + +**Return value:** + +Returns the value of the variable. + +## address\_t MCC\_LoadVolatileField(address\_t obj, address\_t \*fieldAddr) + +**Function:** + +Obtains the value of the volatile variable, and increments RC for the fetched heap object. + +**Input parameter:** + +obj: address of the heap object + +fieldAddr: address of the volatile variable + +**Return value:** + +Returns the value of the volatile variable. + +## void MCC\_WriteReferent(address\_t obj, address\_t value) + +**Function:** + +Store an object to the referent field of a java.lang.ref.Reference object. If a non-null heap object is obtained, RC for the object is incremented. + +**Input parameter:** + +obj: address of java.lang.ref.Reference + +value: address of the heap object + +**Return value:** + +None + +## void MCC\_WriteVolatileStaticFieldNoInc(address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the volatile static variable. This does not change RC for the heap object, but decrements RC for the old value of the static variable. + +**Input parameter:** + +fieldAddr: address of the volatile static variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteVolatileStaticFieldNoDec(address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the volatile static variable. This increments RC for the heap object, but does not decrement RC for the old value of the static variable. + +**Input parameter:** + +fieldAddr: address of the volatile static variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteVolatileStaticFieldNoRC(address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the volatile static variable. This does not change RC for the new value (value) or the old value (value of fieldAddr). + +**Input parameter:** + +fieldAddr: address of the volatile static variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteVolatileStaticField(address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the volatile static variable. This increments RC for the heap object, and decrements RC for the old value of the static variable. + +**Input parameter:** + +fieldAddr: address of the volatile static variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteRefFieldStaticNoInc(address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the static variable. This does not increment RC for the heap object, but decrements RC for the old value of the static variable. + +**Input parameter:** + +fieldAddr: address of the static variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteRefFieldStaticNoDec(address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the static variable. This increments RC for the heap object, but does not decrement RC for the old value of the static variable. + +**Input parameter:** + +fieldAddr: address of the static variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteRefFieldStaticNoRC(address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the static variable. This does not increment RC for the heap object or decrement RC for the old value of the static variable. + +**Input parameter:** + +fieldAddr: address of the static variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteRefFieldStatic(address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the static variable. This increments RC for the heap object, and decrements RC for the old value of the static variable. + +**Input parameter:** + +fieldAddr: address of the static variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteVolatileFieldNoInc(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the volatile variable. This does not increment RC for the heap object, but decrements RC for the old value of the volatile variable. + +**Input parameter:** + +obj: address of the object + +fieldAddr: address of the volatile variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteVolatileFieldNoDec(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the volatile variable. This increments RC for the heap object, but does not decrement RC for the old value of the volatile variable. + +**Input parameter:** + +obj: address of the object + +fieldAddr: address of the volatile variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteVolatileFieldNoRC(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the volatile variable. This does not increment RC for the heap object or decrement RC for the old value of the volatile variable. + +**Input parameter:** + +obj: address of the object + +fieldAddr: address of the volatile variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteVolatileField(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the volatile variable. This increments RC for the heap object, and decrements RC for the old value of the volatile variable. + +**Input parameter:** + +obj: address of the object + +fieldAddr: address of the volatile variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteRefFieldNoInc(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the variable. This does not increment RC for the heap object, but decrements RC for the old value of the variable. + +**Input parameter:** + +obj: address of the object + +fieldAddr: address of the variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteRefFieldNoDec(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the variable. This increments RC for the heap object, but does not decrement RC for the old value of the variable. + +**Input parameter:** + +obj: address of the object + +fieldAddr: address of the variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteRefFieldNoRC(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the variable. This does not increment RC for the heap object or decrement RC for the old value of the variable. + +**Input parameter:** + +obj: address of the object + +fieldAddr: address of the variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteRefField(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the variable. This increments RC for the heap object, and decrements RC for the old value of the variable. + +**Input parameter:** + +obj: address of the object + +fieldAddr: address of the variable + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteVolatileWeakField(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the volatile variable marked by Weak annotation. This increments RC for the heap object, and decrements RC for the old value of the volatile variable. + +**Input parameter:** + +obj: address of the object + +fieldAddr: field of the volatile variable marked by the weak annotation + +value: address of the heap object to be written + +**Return value:** + +None + +## void MCC\_WriteWeakField(address\_t obj, address\_t \*fieldAddr, address\_t value) + +**Function:** + +Writes a heap object to the variable marked by the weak annotation. This increments RC for the heap object, and decrements RC for the old value of the variable. + +**Input parameter:** + +obj: address of the object + +fieldAddr: field of the variable which marked by weak annotation + +value: address of the heap object to be written + +**Return value:** + +None + diff --git a/doc/en/VtableItableDescription.md b/doc/en/VtableItableDescription.md new file mode 100644 index 0000000000000000000000000000000000000000..aa01bca9736393114700781a35bb5150b9009ebe --- /dev/null +++ b/doc/en/VtableItableDescription.md @@ -0,0 +1,376 @@ +# Virtual Table and Interface Table Design + +## Virtual Table + +OpenArkCompiler generates a virtual table for each class. A virtual table of one class consists of virtual functions of its super classs, virtual functions of the current class, and default functions of the interfaces which the current class implements. If function of the current class override function of its superclass, the function of its superclass will be replaced by the function of the current class in the virtual table of the current class. + +The following is a specific example: + +```java +class A { + public int first() { + return 0; + } +} + +class B extends A { + public void foo() { + } + public int first() { + return 1; + } +} + +class C extends A { + public void bar() { + } + public int first() { + return 2; + } +} + +public class IsEmpty { + public static void main(String [] args) { + A x = new B(); + x.first(); + A y = new C() + y.first(); + } + + public void add(A x) { + x.first(); + } +} +``` + + + +The structure of the virtual table generated by OpenArkCompiler is as follows: + +A: +``` + _vtb_LA_3B: + .quad Ljava_2Flang_2FObject_3B_7Cclone_7C_28_29Ljava_2Flang_2FObject_3B - . + .quad Ljava_2Flang_2FObject_3B_7Cequals_7C_28Ljava_2Flang_2FObject_3B_29Z - . + .quad Ljava_2Flang_2FObject_3B_7Cfinalize_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CgetClass_7C_28_29Ljava_2Flang_2FClass_3B - . + .quad Ljava_2Flang_2FObject_3B_7ChashCode_7C_28_29I - . + .quad Ljava_2Flang_2FObject_3B_7Cnotify_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CnotifyAll_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CtoString_7C_28_29Ljava_2Flang_2FString_3B - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28J_29V - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28JI_29V - . + .quad LA_3B_7Cfirst_7C_28_29I - . +``` + +B: + +``` + __vtb_LB_3B: + .quad Ljava_2Flang_2FObject_3B_7Cclone_7C_28_29Ljava_2Flang_2FObject_3B - . + .quad Ljava_2Flang_2FObject_3B_7Cequals_7C_28Ljava_2Flang_2FObject_3B_29Z - . + .quad Ljava_2Flang_2FObject_3B_7Cfinalize_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CgetClass_7C_28_29Ljava_2Flang_2FClass_3B - . + .quad Ljava_2Flang_2FObject_3B_7ChashCode_7C_28_29I - . + .quad Ljava_2Flang_2FObject_3B_7Cnotify_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CnotifyAll_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7CtoString_7C_28_29Ljava_2Flang_2FString_3B - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28_29V - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28J_29V - . + .quad Ljava_2Flang_2FObject_3B_7Cwait_7C_28JI_29V - . + .quad LB_3B_7Cfirst_7C_28_29I - . + .quad LB_3B_7Cfoo_7C_28_29V - . +``` +C: +``` +__vtb_LC_3B: +The first 11 functions are the same as those of A and B. + … … + .quad LC_3B_7Cfirst_7C_28_29I - . + .quad LC_3B_7Cbar_7C_28_29V - . + +``` + +Comparison shows that: + +1. All classes inherit from the object class. Therefore, the first 11 functions in the virtual table are inherited from the object class, and the layout is the same as that of the object class. +2. For function 12, function 12 of the subclass B overrides function 12 of the superclass A. Therefore, in the same position, the virtual table of class A is LA_3B_7Cfirst_7C_28_29I and the virtual table of class B is LB_3B_7Cfirst_7C_28_29I. Class C inherits from Class A and overrides the first function. In addition, the iD interface is implemented. Therefore, LC_3B_7Cfirst_7C_28_29I lies on position 12, and LiD_3B_7Csecond_7C_28_29I lies on position 13. + +## Virtual Function Invocation (During Compilation) + +For virtual call, we cannot determine which function is called during compilation. The following is an example: + +```java +public class IsEmpty { + public static void main(String [] args) { + A x = new B(); + x.first(); + A y = new C(); + y.first(); + } + + public void add(A x) { + x.first(); + } +} +``` + + +In this case, we are not sure whether the first function in B or C is called during compilation. + +However, the layout of the first function in A, B, and C is the same. In this example, the offset of the first function in the virtual table is 12. Therefore, we can access the function by obtaining the virtual table pointer from the corresponding object and add offset 12 to the pointer. +## Virtual Function Invocation (Running) + +In a program execution process, as shown in Figure 1, if a virtual function is called, we perform the following steps: +1. Determine the instance class of the object (this_ pointer). In Figure 1, this is the instance of class C. +2. Search the virtual table of the corresponding class using the function index. +3. Return the function pointer that is actually called. + +![](media/javavmt.png) +
Figure 1: Static calling of Java virtual function
+ +## Interface Table + +Interface call is similar as multiple inheritance and is more complex than Java single inheritance. For multiple inheritance, a unique inheritance order cannot be determined naturally. + +In a closed environment, a sequence (iA, iB, iC) can be determined through topology sorting. The advantage is that interface call can be processed in a way similar as that of a virtual table. However, the interface table of a class obtained in this way will be very large with few data. This approach is not available considering performance and code size. + +![](media/Topology.png) + + +In an open environment, a sequence cannot be determined through topology sorting during compilation. As a result, the sequence of functions in the interface table is not fixed. Therefore, in actual implementation, it is unlikely to achieve a function table with a consistent sequence and an access mechanism by offset. During compilation, we can determine all interfaces implemented by a class and the inheritance relationship of the interfaces. During running, the function signatures can be compared to determine which function needs to be called. As string comparison causes overhead, OpenArkCompiler calculates the hash value of the function name and signature during compilation. First, compare the hash values. If they are the same, and no hash conflict exists, the function is called. If a hash conflict occurs, OpenArkCompiler compares the function name with signature and obtain the function pointer. + +In addition, considering running efficiency and ROM size, we divide the interface table into two levels of tables. Level 1 is the real hash table. We set the hash value to 23, and enter the function address in the position corresponding to the hash value (0-C22). If no conflict occurs in the level 1 hash table, the entries following the last position that contains the function address are blank. In this way, the subsequent entries can be deleted without occupying space. If a conflict occurs in the level-2 hash table, enter 0 in the position where the conflict occurs, and then enter the address of the level-2 hash table in entry 23. + +The structure of the level-1 table is as follows: + +| Sequence | Interface Table Entry | Description +|----|------------|---------------------------------------------| +| 0 | &Func or 0 | Function address corresponding to the hash value. If no function address exists, the value is 0. If a conflict occurs, the conflict position is also 0, and the level-2 table address is entered in entry 23. If no conflict occurs, the entries after the last value (n) with a corresponding function are deleted.| +| 1 | &Func or 0 | +| 2 | &Func or 0 | +| ... | &Func or 0 | +|n | &Func | +| 23 | &itbC | Address of the level-2 table If no conflict occurs in the level-1 table, this entry does not exist. | + + +The structure of the level-2 function table is as follows: + +| Interface Table Entry | Description | +|----------------------|--------------------------------------------------| +| Size | Size of the interface table that does not conflict | +| 1 | Align the site position. Meaningless | +| Func1_sig | Func1 signature hash value | +| &Func1 | Fun1 address | +| Func2_sig | Func2 signature hash value| +| &Func2 | Func2 address | +| ...... | | +| Func3_sig and Func4_sig | Func3 signature and Func4 signature hash values. The two values are the same. | +| 1 | Indicates a conflict as Func3 and Func4 signature harsh values are the same. | +| ...... | | +| Func3_sig | Func3 signature | +| &Func3 | Func3 address | +| Func4_sig | Func4 signature | +| &Func4 | Func4 address | +| ...... | | + +## Interface Function Calling: + +Figure 2 shows the process of calling an interface function that is declared as follows: + +```java +interface B { funcB(); } +interface C { funcC(); } +interface D { funcD(); } +Class A implements B, C, D {} +``` + +![](media/interface1.jpg) + +
Figure 2: Static calling of Java interface function
+ + +As shown in Figure 2, in a program execution process, we perform the following steps: + +1. Determine the class instance of the object. Here, the object is the instance of class A. +2. In the level-1 table, search for the address based on the harsh value. If the address exists, the function pointer is returned. If the value is 0, search the level-2 table. In the level-2 table, search for the address using the signature hash value. If the address is found, the function pointer is returned. Otherwise, use the function name to search the table. +3. Indirectly invoke the function pointer and transfer related parameter (args) to the indirect invocation. + +The following is a specific example: + +The IsEmpty class implements interfaces A and B. Each interface declares two functions. + +```java +interface A{ + public int add(); + public int minus(); +} + +interface B{ + public int mult(); + public int div(); +} + +public class IsEmpty implements A, B { + public static void main(String[]args) { + } + + public void test(B x) { + x.mult(); + } + + public int add() { + return 6 + 3; + } + + public int minus() { + return 6 - 3; + } + + public int mult() { + return 6 * 3; + } + + public int div() { + return 6 / 3; + } +} +``` + +The interface table of IsEmpty is in the maple code is as follows: + +``` +var $__itb_LIsEmpty_3B fstatic <[24] <* void>> = [0, 0, 0, 0, 0, 0, 0, 0, addroffunc ptr &LIsEmpty_3B_7Cdiv_7C_28_29I, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, addroffunc ptr &LIsEmpty_3B_7Cadd_7C_28_29I, 0, 0, addrof ptr $__itabC_LIsEmpty_3B] + +var $__itbC_LIsEmpty_3B fstatic <[6] <* void>> = [2, 1, 0xb97, addroffunc ptr &LIsEmpty_3B_7Cmult_7C_28_29I, 0x1f7f, addroffunc ptr &LIsEmpty_3B_7Cminus_7C_28_29I] +``` + +Corresponding assembly structure: + +``` +__itb_LIsEmpty_3B: + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad LIsEmpty_3B_7Cdiv_7C_28_29I - . + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad 0 + .quad LIsEmpty_3B_7Cadd_7C_28_29I - . + .quad 0 + .quad 0 + .quad __itabC_LIsEmpty_3B - . +``` +``` +__itbC_LIsEmpty_3B: + .quad 2 + .quad 1 + .quad 2967 + .quad LIsEmpty_3B_7Cmult_7C_28_29I - . + .quad 8063 + .quad LIsEmpty_3B_7Cminus_7C_28_29I - . +``` + +The entry content is as follows: + +1. In the level-1 table (__itb_LIsEmpty_3B), there are 23 entries in total, where entry 9 and entry 12 are function addresses, and entry 23 is the level-2 table address. Therefore, a conflict occurs in the level-1 table, and a specific function address needs to be confirmed in the level-2 table. + +2. In the level-2 table, the first entry is 2, indicating that there are two functions that do not conflict with each other. The second entry is 1, which is used for alignment and placeholder. The last four entries are the hash values generated by the function signature and the corresponding function addresses. + +In the following example, the test function in the source code generates interface-call. The corresponding maple code is as follows: + +``` +if (eq u1 u64 (regread u64 %4, constval u64 0)) { + callassigned &MCC_getFuncPtrFromItabSecondHash64 (regread ptr %3, constval u64 0xb97, conststr ptr "mult|()I") { regassign u64 %4} +} +icallassigned (regread u64 %4, regread ref %2) {} +``` + +The calling logic is as follows: + +Check whether the entry corresponding to the hash value in the level-1 interface table is null. If not, use the address. If yes, call the getFuncPtrFromItabSecondHash64 function. + +The getFuncPtrFromItabSecondHash64 function has three parameters: interface table address, hash value of the basename function, and the function signature. The complete calling process is as follows: Find the corresponding interface table address based on classinfo and compare the hash values. If the comparison is successful, and no conflict occurs, the correct address can be obtained. If a conflict occurs, compare the signature names (character string comparison). + +The format of the accessed interface table is the same as that of IsEmpty. + +## Interface override + +The `Default` function is introduced in Java 8. The implementation in the superclass overrides the default function of the interface. Override depends on the inheritance relationship between interfaces. As shown in the following figure, the cA class inherits the cB class to implement the iD interface. The foo function is implemented in both the cB class and iD interface. For the cA class, the implementation of the foo function depends on the superclass cB rather than the iD interface. + +```java + +interface iD { + public default void foo(){System.out.println("iD foo");} +} + +class cB { + public void foo(){System.out.println("cB foo");} +} + +class cA extends cB implements iD { +} + +public class IsEmpty { + public static void main(String [] args) { + iD obj = new cA(); + obj.foo(); + } +} +``` + + +As shown in the following figure, the getValue function is defined in both parent and son interfaces. For the Sson calss, the implementation of the getValue function depends on the son interface rather than the parent interface. + +```java +interface Parent{ + default void getValue(){ + System.out.println("Parent getVatue......"); + } +} + +interface Son extends Parent{ + default void getValue(){ + System.out.println("OfInt getValue......") + } +} + +abstract class OfPrimitive implements Parent{ +} + +class SSon extends OfPrimitive implements Son{ +} + +public class Main { + static int get() { + return 1; + } + + public static void main(String[] args) { + Parent son = (Parent)new SSon(); + son.getValue(); + + SSon son2; + if(get()==1) { + son2 = new SSon(); + } + else son2 = new SSon(); + son2.getValue(); + } +} +``` + diff --git a/doc/en/media/MapleDriverStructure.png b/doc/en/media/MapleDriverStructure.png new file mode 100644 index 0000000000000000000000000000000000000000..adc5f98ba54d4ffb4430cb3bbff37e8e45d06214 Binary files /dev/null and b/doc/en/media/MapleDriverStructure.png differ diff --git a/doc/en/media/Topology.png b/doc/en/media/Topology.png new file mode 100644 index 0000000000000000000000000000000000000000..6967780a1ac7addf7811b4271bbf805c6d659027 Binary files /dev/null and b/doc/en/media/Topology.png differ diff --git a/doc/en/media/addphase.png b/doc/en/media/addphase.png new file mode 100644 index 0000000000000000000000000000000000000000..049560035bd8b661454107d4be2498f3bc9d06b9 Binary files /dev/null and b/doc/en/media/addphase.png differ diff --git a/doc/en/media/interface1.jpg b/doc/en/media/interface1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7377546fc36b03b282e5d85d0a89fd274288f831 Binary files /dev/null and b/doc/en/media/interface1.jpg differ diff --git a/doc/en/media/javavmt.png b/doc/en/media/javavmt.png new file mode 100644 index 0000000000000000000000000000000000000000..ef93f36923559321d0512a862ca9a1ff9d36a6b6 Binary files /dev/null and b/doc/en/media/javavmt.png differ diff --git a/license/LICENSE b/license/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..9e32cdef1625daed25cf365c865f01050877cff3 --- /dev/null +++ b/license/LICENSE @@ -0,0 +1,127 @@ + 木兰宽松许可证, 第2版 + + 木兰宽松许可证, 第2版 + 2020年1月 http://license.coscl.org.cn/MulanPSL2 + + + 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: + + 0. 定义 + + “软件”是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 + + “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 + + “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 + + “法人实体”是指提交贡献的机构及其“关联实体”。 + + “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 + + 1. 授予版权许可 + + 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 + + 2. 授予专利许可 + + 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 + + 3. 无商标许可 + + “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 + + 4. 分发限制 + + 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 + + 5. 免责声明与责任限制 + + “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 + + 6. 语言 + “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 + + 条款结束 + + 如何将木兰宽松许可证,第2版,应用到您的软件 + + 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: + + 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; + + 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; + + 3, 请将如下声明文本放入每个源文件的头部注释中。 + + Copyright (c) [Year] [name of copyright holder] + [Software Name] is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. + + + Mulan Permissive Software License,Version 2 + + Mulan Permissive Software License,Version 2 (Mulan PSL v2) + January 2020 http://license.coscl.org.cn/MulanPSL2 + + Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: + + 0. Definition + + Software means the program and related documents which are licensed under this License and comprise all Contribution(s). + + Contribution means the copyrightable work licensed by a particular Contributor under this License. + + Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. + + Legal Entity means the entity making a Contribution and all its Affiliates. + + Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. + + 1. Grant of Copyright License + + Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. + + 2. Grant of Patent License + + Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. + + 3. No Trademark License + + No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. + + 4. Distribution Restriction + + You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. + + 5. Disclaimer of Warranty and Limitation of Liability + + THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + 6. Language + + THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. + + END OF THE TERMS AND CONDITIONS + + How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software + + To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: + + i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; + + ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; + + iii Attach the statement to the appropriate annotated syntax at the beginning of each source file. + + + Copyright (c) [Year] [name of copyright holder] + [Software Name] is licensed under Mulan PSL v2. + You can use this software according to the terms and conditions of the Mulan PSL v2. + You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 + THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + See the Mulan PSL v2 for more details. diff --git a/license/ThirdPartyOpenSourceSoftwareNotice b/license/ThirdPartyOpenSourceSoftwareNotice new file mode 100644 index 0000000000000000000000000000000000000000..ab3019730241e2616919a552300ecb8205d64aba --- /dev/null +++ b/license/ThirdPartyOpenSourceSoftwareNotice @@ -0,0 +1,483 @@ +OPEN SOURCE SOFTWARE NOTICE + +Please note we provide an open source software notice along with this product and/or this product firmware (in the following just “this product”). The open source software licenses are granted by the respective right holders. And the open source licenses prevail all other license information with regard to the respective open source software contained in the product, including but not limited to End User Software Licensing Agreement. This notice is provided on behalf of Huawei Technologies Co. Ltd. and any of its local subsidiaries which may have provided this product to you in your local country. + +Warranty Disclaimer + +THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. + +Copyright Notice and License Texts + +Software: LLVM 10.0.0 + +Copyright notice: +Copyright 2015 Google Inc. All rights reserved. +Copyright 2018 Google Inc. All rights reserved. +Copyright 2016 Ismael Jimenez Martinez. All rights reserved. +Copyright 2017 Roman Lebedev. All rights reserved. +Copyright 2011 The Go Authors. All rights reserved. +Copyright (c) 2012 Alexandre K. I. de Mendonca ,Paulo Pizarro +Copyright (c) 2012 Alexandre K. I. de Mendonca +Copyright (c) 2013 Imagination Technologies +Copyright (c) 2013 Imagination Technologies Ltd. +Copyright (c) 2014,2015 Advanced Micro Devices, Inc. +Copyright (c) 1998 Cygnus Solutions +Copyright (c) 2004 Simon Posnjak +Copyright (c) 2005 Axis Communications AB +Copyright (C) 2007 Free Software Foundation, Inc. +Copyright (c) 2012 Anthony Green +Copyright (c) 1996-2003 Red Hat, Inc. +Copyright (c) 2011-2019 by the contributors listed in CREDITS.TXT +Copyright 2008, Google Inc. +Copyright 2005, Google Inc. +Copyright 2007, Google Inc. +Copyright 2008 Google Inc. +Copyright (c) 2000, 2007 Software AG +Copyright (c) 2008 Red Hat, Inc +Copyright (c) 2015 Advanced Micro Devices, Inc. +Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT +Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT +Copyright (c) 2019 The LLVM Developers +Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,to any person obtaining a copy of this software and associated documentation +Copyright (c) 2014 Advanced Micro Devices, Inc. +Copyright (c) 2014, 2015 Advanced Micro Devices, Inc. +Copyright (c) 2013 Victor Oliveira +Copyright (c) 2013 Jesse Towner +Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +Copyright (c) 2016 Aaron Watry +Copyright (c) 2016 Aaron Watry +Copyright (c) 2011-2014 by the contributors listed in CREDITS.TXT +Copyright © 2012 Peter Harris +Copyright (c) 2007, 2009, 2010 Red Hat, Inc. +Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc +Copyright (c) 2011 Plausible Labs Cooperative, Inc. +Copyright (c) 1996 Red Hat, Inc. +Copyright (c) 1999, 2007, 2008 Red Hat, Inc. +Copyright (c) 2011, 2012 Anthony Green +Copyright (c) 1996, 1998, 2007 Red Hat, Inc. +Copyright (c) 1999, 2008 Red Hat, Inc. +Copyright (c) 1996, 1998 Red Hat, Inc. +Copyright (c) 2012 Anthony Green +Copyright (c) 1998, 2001, 2007, 2008 Red Hat, Inc. +Copyright (C) 2012-2015 Free Software Foundation, Inc. +Copyright (C) 2013-2015 Free Software Foundation, Inc. +Copyright (c) 2009-2019 Polly Team +Copyright (c) 1996-2014 Anthony Green, Red Hat, Inc and others. +Copyright (c) 2013 Mentor Graphics. +Copyright (c) 2007-2019 University of Illinois at Urbana-Champaign. +Copyright (c) 2014 Red Hat, Inc. +Copyright (C) 2011, 2012, 2013 Anthony Green +Copyright (C) 2007 Free Software Foundation, Inc +Copyright (c) 1996 Red Hat, Inc. +Copyright (c) 2009, 2010, 2011, 2012 ARM Ltd. +Copyright (c) 2013 Synopsys, Inc. (www.synopsys.com) +Copyright (c) 2013 Synopsys, Inc. (www.synopsys.com) +Copyright (c) 2011 Timothy Wall +Copyright (c) 2011 Anthony Green +Copyright (c) 2011 Free Software Foundation +Copyright (c) 1998, 2008, 2011 Red Hat, Inc. +Copyright (c) 2010 CodeSourcery +Copyright (c) 2011 Anthony Green +Copyright (c) 2009 Bradley Smith +Copyright (C) 2004 Anthony Green +Copyright (C) 2007 Free Software Foundation, Inc. +Copyright (C) 2008 Red Hat, Inc. +Copyright (c) 1996-2004 Red Hat, Inc. +Copyright (c) 1998, 2007, 2008, 2012 Red Hat, Inc. +Copyright (c) 2000 Hewlett Packard Company +Copyright (c) 2000 Hewlett Packard Company +Copyright (c) 2004 Renesas Technology +Copyright (c) 2008 Red Hat, Inc. +Copyright (c) 2004 Renesas Technology. +Copyright (c) 2013 Miodrag Vallat. +Copyright (c) 2012, 2013 Xilinx, Inc +Copyright (c) 2012, 2013 Xilinx, Inc +Copyright (c) 2008 David Daney +Copyright (c) 1996, 2007, 2008, 2011 Red Hat, Inc. +Copyright (C) 2012, 2013 Anthony Green +Copyright (c) 2012, 2013 Anthony Green +Copyright (c) 2014 Sebastian Macke +Copyright (c) 2014 Sebastian Macke +(c) 2011 Anthony Green +(c) 2008 Red Hat, Inc. +(c) 2006 Free Software Foundation, Inc. +(c) 2003-2004 Randolph Chung +Copyright (c) 1998 Geoffrey Keating +Copyright (C) 2013 IBM +Copyright (C) 2011 Anthony Green +Copyright (C) 2011 Kyle Moffett +Copyright (C) 2008 Red Hat, Inc +Copyright (C) 2007, 2008 Free Software Foundation, Inc +Copyright (c) 1998 Geoffrey Keating +Copyright (C) 2007, 2008, 2010 Free Software Foundation, Inc +Copyright (C) 1998 Geoffrey Keating +Copyright (C) 2001 John Hornkvist +Copyright (C) 2002, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. +Copyright (C) 2013 IBM +Copyright (c) 2002-2008, 2012 Kaz Kojima +Copyright (c) 2008 Red Hat, Inc. +Copyright (c) 2012 Anthony Green +Copyright (c) 2003, 2004, 2006, 2007, 2012 Kaz Kojima +Copyright (c) 2008 Anthony Green +Copyright (c) 2011, 2013 Anthony Green +Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc. +Copyright (c) 2012 Tilera Corp. +Copyright (c) 2012 Tilera Corp. +Copyright (c) 20011 Anthony Green +Copyright (c) 2008, 2010 Red Hat, Inc. +Copyright (c) 2002, 2007 Bo Thorsen +Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc. +Copyright (c) 2002 Ranjit Mathew +Copyright (c) 2002 Bo Thorsen +Copyright (c) 2002 Roger Sayle +Copyright (C) 2008, 2010 Free Software Foundation, Inc. +Copyright (c) 2013 The Written Word, Inc. +Copyright (c) 2011 Anthony Green +Copyright (c) 2012, 2014 Anthony Green +Copyright (c) 1996-2003, 2010 Red Hat, Inc. +Copyright (C) 2008 Free Software Foundation, Inc. +Copyright (c) 2014 Red Hat, Inc. +Copyright (c) 2013 Tensilica, Inc. +Copyright (c) 2013 Tensilica, Inc. +Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,2007, 2008, 2009 Free Software Foundation, Inc. +Copyright 2009 The Go Authors. All rights reserved. +Copyright 2012 The Go Authors. All rights reserved. +Copyright 2009 The Go Authors. All rights reserved. +Copyright 2014 The Go Authors. All rights reserved. +Copyright 2013 The Go Authors. All rights reserved. +Copyright 2010 The Go Authors. All rights reserved. +Copyright 2012 The Go Authors. All rights reserved. +Copyright (c) 2009 The Go Authors. All rights reserved. +Copyright 2014 The Go Authors. All rights reserved. +Copyright 2015 The Go Authors. All rights reserved. +Copyright 2009, 2010 The Go Authors. All rights reserved. +Copyright 2013 The Go Authors. All rights reserved. +Copyright 2001-2004 Unicode, Inc. +Copyright (C) 2004 eXtensible Systems, Inc. +Copyright (c) 2001 Alexander Peslyak and it is hereby released to the general public under the following terms: +Copyright (C) 2012-2016, Yann Collet. +Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign. +Copyright (c) 2013-2014, Pexpect development team +Copyright (c) 2012, Noah Spurrier +Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT +Copyright 2015, Google Inc. +Copyright (c) 1999-2003 Steve Purcell +Copyright (c) 2003-2010 Python Software Foundation +Copyright (c) 1999-2007 Apple Inc. All rights reserved. +Copyright (c) 2017-2019 by the contributors listed in CREDITS.TXT +Copyright (c) 2010 Apple Inc. +Copyright (c) 2013-2016, Pexpect development team +Copyright (c) 2010-2015 Benjamin Peterson +Copyright 2004 Free Software Foundation, Inc. +Copyright 2006, Google Inc. +Copyright (c) 2007-2018 University of Illinois at Urbana-Champaign. +Copyright 2013, Google Inc. +Copyright (c) 2009 Google Inc. All rights reserved. +Copyright (c) 2006 Kirill Simonov +Copyright © 2006-2009 Steven J. Bethard . +Copyright 2008-2009 Katholieke Universiteit Leuven +Copyright 2006-2007 Universiteit Leiden +Copyright 2012,2014 Ecole Normale Superieure +Copyright 2013 Ecole Normale Superieure +Copyright 2017 Sven Verdoolaege +Copyright 2011 INRIA Saclay +Copyright 2011 Sven Verdoolaege +Copyright 2012-2014 Ecole Normale Superieure +Copyright 2014 INRIA Rocquencourt +Copyright 2010 INRIA Saclay +Copyright 2012 Ecole Normale Superieure +Copyright 2012-2013 Ecole Normale Superieure +Copyright 2016 Sven Verdoolaege +Copyright 2010-2011 INRIA Saclay +Copyright 2016 INRIA Paris +Copyright 2005-2007 Universiteit Leiden +Copyright 2012 Universiteit Leiden +Copyright 2014 Ecole Normale Superieure +Copyright 2015 INRIA Paris-Rocquencourt +Copyright 2014-2015 INRIA Rocquencourt +Copyright 2015-2016 Sven Verdoolaege +Copyright 2013-2014 Ecole Normale Superieure +Copyright 2016-2017 Sven Verdoolaege +Copyright 2018 Sven Verdoolaege +Copyright 2016-2017 Tobias Grosser +Copyright 2015 INRIA Paris-Rocquencourt +Copyright (C) 1996-2015 Free Software Foundation, Inc. +Copyright (c) 2012 Qualcomm Innovation Center, Inc. All rights reserved. +Copyright (C) 2002-2007 Michael J. Fromberger, All Rights Reserved. +Copyright (c) 1992, 1993 UNIX International, Inc. +Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved. +Copyright (c) 1994 +Copyright (c) 1992, 1993, 1994 Henry Spencer. +Copyright (c) 1992, 1993, 1994 +Copyright (c) 1992 Henry Spencer. +Copyright (c) 1992, 1993 +Copyright (c) 1998 Todd C. Miller +Copyright (C) 2012-2016, Yann Collet +Copyright (c) 1997-2019 Intel Corporation +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT +Copyright 2012 INRIA Paris-Rocquencourt +Copyright 2012 Ecole Normale Superieure +Copyright 2015 Sven Verdoolaege +Copyright (C) Microsoft Corporation. All rights reserved. +Copyright 2003 Google Inc. +Copyright 2009 Google Inc. +Copyright 2016, 2017 Tobias Grosser. All rights reserved. +Copyright 2011 Sven Verdoolaege. All rights reserved. +Copyright 2011,2015 Sven Verdoolaege. All rights reserved. + +License: 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: +You must give any other recipients of the Work or Derivative Works a copy of this License; and +You must cause any modified files to carry prominent notices stating that You changed the files; and +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 +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 + +License:University of Illinois/NCSA Open Source License +Copyright (c) All rights reserved. +Developed by: + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +• Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. +• Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. +• Neither the names of , nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. + +License:The MIT License +Copyright (c) +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + + + +Software: Android 10.0.0_r2 + +Copyright notice: +Copyright (c) 2005-2020, The Android Open Source Project + +License: Apache License V2.0 + + 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. + +THIS OFFER IS VALID FOR THREE YEARS FROM THE MOMENT WE DISTRIBUTED THE PRODUCT OR FIRMWARE. diff --git a/samples/exceptiontest/Arith.java b/samples/exceptiontest/Arith.java new file mode 100644 index 0000000000000000000000000000000000000000..893f452074a96f9251f8ab6b01bcd83050f361ce --- /dev/null +++ b/samples/exceptiontest/Arith.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +public class Arith { + private static native void raise_sigfpe(); + + public static int TestMain( int c ) { + int r = 0; + try { + r += 1; + if( c > 0 ) + raise_sigfpe(); + else if ( c == 0 ) { + r += 103; + throw new ArithmeticException(); + } + r += 3; + } catch( ArithmeticException e ) { + r += 100; + } + return r; + } + + public static void main(String[] args) { + System.out.println(TestMain(-5)); + System.out.println(TestMain(0)); + } +} diff --git a/samples/exceptiontest/Makefile b/samples/exceptiontest/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..061f116d0a5cfb94e95955f707fea94fe505daf0 --- /dev/null +++ b/samples/exceptiontest/Makefile @@ -0,0 +1,16 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +APP = Arith +include $(MAPLE_BUILD_CORE)/maple_test.mk diff --git a/samples/helloworld/HelloWorld.java b/samples/helloworld/HelloWorld.java new file mode 100644 index 0000000000000000000000000000000000000000..a002960377e6d7728decb9f111625bc301e864e4 --- /dev/null +++ b/samples/helloworld/HelloWorld.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +public class HelloWorld { + public static void main(String[] args) { + System.out.println("Hello World!"); + } +} + diff --git a/samples/helloworld/Makefile b/samples/helloworld/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..77580165d82941ec9b348ed15fed0ce311721b58 --- /dev/null +++ b/samples/helloworld/Makefile @@ -0,0 +1,16 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +APP = HelloWorld +include $(MAPLE_BUILD_CORE)/maple_test.mk diff --git a/samples/iteratorandtemplate/IteratorAndTemplateTest.java b/samples/iteratorandtemplate/IteratorAndTemplateTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bb0cd3f3b6186b0414e4585cbbb91c568dacc0fb --- /dev/null +++ b/samples/iteratorandtemplate/IteratorAndTemplateTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +import java.util.*; +public class IteratorAndTemplateTest { + public static void main(String args[]) { + testIterator(); + testTemplate(); + } + + public static void testIterator(){ + AbstractCollection l = new ArrayList(); + l.add(new String("Hello")); + l.add(new String(" World")); + System.out.println(l.size()); + System.out.println(l.toString()); + } + + public static void testTemplate(){ + List wholeChain = new ArrayList(); + wholeChain.add(1); + wholeChain.add(2); + for (Integer i : wholeChain) { + System.out.println(i); + } + } +} + diff --git a/samples/iteratorandtemplate/Makefile b/samples/iteratorandtemplate/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..93802205e8ac460bb8d55d927d681b8e8620b023 --- /dev/null +++ b/samples/iteratorandtemplate/Makefile @@ -0,0 +1,16 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +APP = IteratorAndTemplateTest +include $(MAPLE_BUILD_CORE)/maple_test.mk diff --git a/samples/polymorphismtest/InterfaceTest.java b/samples/polymorphismtest/InterfaceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2df75fe2d722d335775ac194bff17f836b138e7b --- /dev/null +++ b/samples/polymorphismtest/InterfaceTest.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +interface Inter { + public default void foo() { + System.out.println("Inter.foo()"); + } +} + +class Base implements Inter { + public void foo() { + System.out.println("Base.foo()"); + } +} + +class Derived extends Base { + public void foo() { + System.out.println("Derived.foo()"); + } +} + +public class InterfaceTest { + public static void main(String[] args) { + Derived o1 = new Derived(); + o1.foo(); + Base o2 = new Derived(); + o2.foo(); + Inter o3 = new Derived(); + o3.foo(); + } +} diff --git a/samples/polymorphismtest/Makefile b/samples/polymorphismtest/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..aa9a53434063a40b1f813d3b244521f25c6afbbe --- /dev/null +++ b/samples/polymorphismtest/Makefile @@ -0,0 +1,16 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +APP = InterfaceTest +include $(MAPLE_BUILD_CORE)/maple_test.mk diff --git a/samples/rccycletest/Makefile b/samples/rccycletest/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c93d70d8f68ec451b48f8eb0e5c6355106cefe81 --- /dev/null +++ b/samples/rccycletest/Makefile @@ -0,0 +1,16 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +APP = RCCycleTest +include $(MAPLE_BUILD_CORE)/maple_test.mk diff --git a/samples/rccycletest/RCCycleTest.java b/samples/rccycletest/RCCycleTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c8794429e207e58c5ac14247c567492414da7a16 --- /dev/null +++ b/samples/rccycletest/RCCycleTest.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +class Test_A { + Test_B bb; + void genCycle() { + Test_B b = new Test_B(); + bb = b; + b.aa = this; + } +} + +class Test_B { + Test_A aa; +} + +public class RCCycleTest { + public static void main (String []args) { + Test_A a = new Test_A(); + a.genCycle(); + if (a.bb == null) { + System.out.println("class B is collected"); + } else { + System.out.println("class B is not collected"); + } + } +} diff --git a/samples/threadtest/Makefile b/samples/threadtest/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7b98e1ec3fd25777e2a39abdb6aced671a2e6688 --- /dev/null +++ b/samples/threadtest/Makefile @@ -0,0 +1,16 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +APP = ThreadTest +include $(MAPLE_BUILD_CORE)/maple_test.mk diff --git a/samples/threadtest/ThreadTest.java b/samples/threadtest/ThreadTest.java new file mode 100644 index 0000000000000000000000000000000000000000..522947b67468088295faba0c455f1e284d05fd02 --- /dev/null +++ b/samples/threadtest/ThreadTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +public class ThreadTest { + static volatile long flag = 0L; + static int number = 0; + static class FirstThread extends Thread { + public void run() { + while(flag != Long.MAX_VALUE) { + } + System.out.println(number); + } + } + static class SecondThread extends Thread { + public void run() { + number = 42; + flag = Long.MAX_VALUE; + } + } + + public static void main(String args[]) { + FirstThread t1 = new FirstThread(); + SecondThread t2 = new SecondThread(); + t1.start(); + t2.start(); + try { + t1.join(); + t2.join(); + } catch (InterruptedException e) { + System.out.println("INTERRUPTED_MESSAGE"); + } + System.out.println("OK"); + } +} diff --git a/src/MapleFE/.gitignore b/src/MapleFE/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..533695ff01a419af9567d36b8d2cf41970296906 --- /dev/null +++ b/src/MapleFE/.gitignore @@ -0,0 +1,25 @@ +output/ +*.output +*.out +*.bak +*.swo +*.swp +*.mpl +*.js +*.dot +*.png +*.out.ts +*.ts.ast +*.java.ast +gdbfile +test/typescript/**/*.cpp +test/typescript/**/*.h +test/typescript/**/*.log +test/TypeScript/ +test/msts_failed.txt +test/msts_passed.txt +test/typescript/ms_tests/*.ts +test/typescript/ms_tests/LICENSE.txt +test/typescript/unit_tests/temp.ts +test/typescript/unit_tests/perf.data +test/typescript/unit_tests/perf.data.old diff --git a/src/MapleFE/Makefile b/src/MapleFE/Makefile index c3c89b4319bc3779fa06f6319ae45d34f165095a..f1dbcac61dd5bed54e947fda4a6c6be58a2144c1 100644 --- a/src/MapleFE/Makefile +++ b/src/MapleFE/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# Copyright (C) [2020-2021] Futurewei Technologies, Inc. All rights reverved. # # OpenArkFE is licensed under the Mulan PSL v2. # You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -14,37 +14,64 @@ include Makefile.in -TARGS = autogen shared recdetect ladetect java2mpl +TARGS = autogen shared recdetect ladetect astopt java2mpl ast2mpl ts2ast ast2cpp c2ast obfuscate # create BUILDDIR first $(shell $(MKDIR_P) $(BUILDDIR)) -java2mpl: autogen recdetect ladetect shared - $(MAKE) LANG=java -C java +ifeq ($(SRCLANG),java) + TARGET := java2ast ast2mpl +else ifeq ($(SRCLANG),typescript) + TARGET := ts2ast ast2cpp obfuscate +else ifeq ($(SRCLANG),c) + TARGET := c2ast +endif -recdetect: autogen shared - (cd recdetect; ./build.sh java) - (cd $(BUILDDIR)/recdetect; ./recdetect) +all: $(TARGET) + +java2ast: autogen recdetect ladetect shared + $(MAKE) LANG=$(SRCLANG) -C $(SRCLANG) + +ts2ast: autogen recdetect ladetect shared + $(MAKE) LANG=$(SRCLANG) -C $(SRCLANG) + +c2ast: autogen recdetect ladetect shared astopt + $(MAKE) LANG=$(SRCLANG) -C $(SRCLANG) + +recdetect: autogen shared ladetect + $(MAKE) LANG=$(SRCLANG) -C recdetect ladetect: autogen shared - (cd ladetect; ./build.sh java) - (cd $(BUILDDIR)/ladetect; ./ladetect) + $(MAKE) LANG=$(SRCLANG) -C ladetect + +ast2mpl: astopt java2ast + $(MAKE) -C ast2mpl + +astopt: shared recdetect ladetect + $(MAKE) -C astopt + +ast2cpp: astopt ts2ast + $(MAKE) -C ast2cpp + +obfuscate: astopt ts2ast ast2cpp + $(MAKE) -C tools/obfuscate shared: autogen - $(MAKE) LANG=java -C shared + $(MAKE) -C shared autogen: - $(MAKE) LANG=java -C autogen - (cd $(BUILDDIR)/autogen; ./autogen) + $(MAKE) -C autogen mapleall: ./scripts/build_mapleall.sh -test: autogen - $(MAKE) LANG=java -C test +test: + $(MAKE) LANG=$(SRCLANG) -C test -testall: - (cd test; ./runtests.pl all) +testms: + $(MAKE) LANG=$(SRCLANG) -C test testms + +testall: test test1: @cp test/java2mpl/t1.java . @@ -55,12 +82,14 @@ test1: clean: rm -rf $(BUILDDIR) -clobber: clean - rm -rf java/include/gen_*.h java/src/gen_*.cpp ladetect/java recdetect/java +clobber: + rm -rf output + +r: rebuild rebuild: make clobber - make -j8 + make -j -.PHONY: $(TARGS) +.PHONY: $(TARGS) test diff --git a/src/MapleFE/Makefile.in b/src/MapleFE/Makefile.in index 0902fbd1540ecc1bbcf4887df41e44c3f94f50d2..9ec2c1ca5240a2d01be9d271ec8a04b1c6abbcb3 100644 --- a/src/MapleFE/Makefile.in +++ b/src/MapleFE/Makefile.in @@ -1,17 +1,17 @@ CXX = clang++ -CC = gcc +CC = clang AR = ar rcs FLAVOR = gnu LD = clang++ -CXXFLAGS = -O0 -g3 -Wall -std=c++17 -DDEBUG +CXXFLAGS = -O0 -g3 -Wall -std=c++17 -DDEBUG -fPIC LFLAGS=-std=c++17 +LANG=java MKDIR_P = mkdir -p MAPLELIBPATH:=$(MAPLE_ROOT)/OpenArkCompiler/output/aarch64-clang-debug/lib/64 -MAPLELIBPATH1:=$(MAPLE_ROOT)/OpenArkCompiler/output/aarch64-clang-debug/ar -MAPLELIBS := -L $(MAPLELIBPATH) -L $(MAPLELIBPATH1) -lmplir -loption_parser -lmpl2mpl -lmplutil -lmempool -lHWSecureC -ldriver_option +MAPLELIBS := -L $(MAPLELIBPATH) -lmplir -loption_parser -lmplphase -lmplutil -lmempool -lmpl2mpl -lHWSecureC -ldriver_option -lmplir -loption_parser -ldriver_option MAPLEALL_INC = -I $(MAPLEALL_SRC)/maple_ir/include \ -I $(MAPLEALL_SRC)/mempool/include \ diff --git a/src/MapleFE/README b/src/MapleFE/README index 5a495962a12a54b48f9929ffbba1e88b224f33e3..9446b57ff2979767e8ab7b069dae94f732af269f 100644 --- a/src/MapleFE/README +++ b/src/MapleFE/README @@ -28,32 +28,35 @@ have our own frontend, which could be easier to handle new languages. [Preparation] -Before start building MapleFE, please download mapleall from the open ark compiler incubator, -https://gitee.com/openarkcompiler-incubator/mapleall -Follow the instruction of mapleall and build the necessary libraries. -Once you are done, please update the lib and include paths in MapleFE/shared/src/Makefile accordingly. +https://gitee.com/openarkcompiler/OpenArkCompiler/blob/master/doc/en/DevelopmentPreparation.md +Follow the instruction in "Recommended Development Environment" section to get tools installed + +The following packages also need to be installed: +```bash +sudo apt install -y clang-tools-10 clang-format-10 python3 python3-pip libyaml-cpp-dev nodejs npm +pip3 install pyyaml +sudo npm install -g typescript@latest +``` [How to build] -1. source envsetup.sh -2. make mapleall. +1. source envsetup.sh [java|typescript] +2. make mapleall This step is to build mapleall (Maple IR related libraries). If you have done it once, you dont need do it again unless you changed the code in mapleall. 3. make -4. If you are working at Java frontend, you will see output/java/java2mpl. This is the executable +4. If you are working at Java frontend, you will see output/java/java/java2mpl. This is the executable frontend. +4. If you are working at Typescript frontend, you will see output/typescript/bin/ts2ast. This is the executable + frontend. You can also see output/typescript/bin/ast2cpp, which translate AST to cpp source code. [How to test] -1. cd test -2. ./runtests.pl all - -or -1. make testall +1. make test run a single test, say t1.java: 1. cd test 2. make t1 -You can find all Java test cases in test/java2mpl. Right now only java test cases -are used. +You can find all Java test cases in test/java. +You can find all Typescript test cases in test/typescript. diff --git a/src/MapleFE/TODO b/src/MapleFE/TODO new file mode 100644 index 0000000000000000000000000000000000000000..a24e602d81cb144fd26df0dec6da3ddad3914cc7 --- /dev/null +++ b/src/MapleFE/TODO @@ -0,0 +1,4 @@ +1. Implement language specific lexer through overriding. Right now some functions are in shared lexer + template literal related code +2. Implement language specific through overriding. Right now semi-coloning skipping is in shared parser. + See code in Parser::TraverseToken() diff --git a/src/MapleFE/ast2cpp/Makefile b/src/MapleFE/ast2cpp/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..34428253a1698e6d7154d16969f3816729268ebf --- /dev/null +++ b/src/MapleFE/ast2cpp/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +include ../Makefile.in + +all: + $(MAKE) -C src + +clean: + rm -rf $(BUILDDIR)/ast2cpp + +test: + $(MAKE) -C ../test p + +.PHONY: $(TARGS) + diff --git a/src/MapleFE/ast2cpp/README.md b/src/MapleFE/ast2cpp/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/MapleFE/ast2cpp/include/a2c_util.h b/src/MapleFE/ast2cpp/include/a2c_util.h new file mode 100644 index 0000000000000000000000000000000000000000..9ec86c37a25dcc7ed52239d67e1fea36dad3227f --- /dev/null +++ b/src/MapleFE/ast2cpp/include/a2c_util.h @@ -0,0 +1,45 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +////////////////////////////////////////////////////////////////////////////////////////////// +// This is the interface to translate AST to C++ +////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef __A2C_UTIL_HEADER__ +#define __A2C_UTIL_HEADER__ + +#include +#include +#include "gen_astvisitor.h" + +namespace maplefe { + +// To collect all filenames for imported modules +class ImportedFiles : public AstVisitor { + public: + ModuleNode *mModule; + std::vector mFilenames; + public: + ImportedFiles(ModuleNode *m) : mModule(m) {} + + // A helper function to get the target filename of an ImportNode + std::string GetTargetFilename(TreeNode *node); + + ImportNode *VisitImportNode(ImportNode *node); + ExportNode *VisitExportNode(ExportNode *node); +}; + +} +#endif diff --git a/src/MapleFE/ast2cpp/include/ast2cpp.h b/src/MapleFE/ast2cpp/include/ast2cpp.h new file mode 100644 index 0000000000000000000000000000000000000000..9687592f296f1a5c117f3dab2a54a4164bff7b09 --- /dev/null +++ b/src/MapleFE/ast2cpp/include/ast2cpp.h @@ -0,0 +1,62 @@ +/* +* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +////////////////////////////////////////////////////////////////////////////////////////////// +// This is the interface to translate AST to C++ +////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef __AST2CPP_HEADER__ +#define __AST2CPP_HEADER__ + +#include "astopt.h" +#include "ast_handler.h" +#include "ast_module.h" + +namespace maplefe { + +class A2C : public AstOpt { +private: + AST_Handler *mASTHandler; + unsigned mFlags; + unsigned mIndexImported; + +public: + explicit A2C(AST_Handler *h, unsigned flags) : + AstOpt(h, flags), + mASTHandler(h), + mFlags(flags), + mIndexImported(0) {} + ~A2C() = default; + + void EmitTS(); + bool LoadImportedModules(); + + // return 0 if successful + // return non-zero if failed + int ProcessAST(); +}; + +class CppHandler { +private: + AST_Handler *mASTHandler; + unsigned mFlags; + +public: + CppHandler(AST_Handler *h, unsigned f) : mASTHandler(h), mFlags(f) {} + bool EmitCxxFiles(); +}; + +} +#endif diff --git a/src/MapleFE/ast2cpp/include/cpp_declaration.h b/src/MapleFE/ast2cpp/include/cpp_declaration.h new file mode 100644 index 0000000000000000000000000000000000000000..352a0006bc51c858d06c97b5bd1a24562cb4e327 --- /dev/null +++ b/src/MapleFE/ast2cpp/include/cpp_declaration.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. + * + * OpenArkFE is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef __CPPDECL_HEADER__ +#define __CPPDECL_HEADER__ + +#include +#include "ast_handler.h" +#include "cpp_emitter.h" + +namespace maplefe { + +class CppDecl : public CppEmitter { +private: + std::set mImportedModules; + std::string mDefinitions; + std::string mInits; + +public: + CppDecl(Module_Handler *h) : CppEmitter(h) {} + CppDecl() : CppDecl(nullptr) {} + + std::string Emit() { + return EmitTreeNode(GetASTModule()); + } + + void AddImportedModule(const std::string& module); + bool IsImportedModule(const std::string& module); + + void AddDefinition(const std::string& def) { mDefinitions += def; } + std::string GetDefinitions() { return mDefinitions; } + void AddInit(const std::string& init) { mInits += init; } + std::string GetInits() { return mInits; } + + std::string EmitUserTypeNode(UserTypeNode *node) override; + std::string EmitBinOperatorNode(BinOperatorNode *node) override; + std::string EmitIdentifierNode(IdentifierNode *node) override; + std::string EmitDeclNode(DeclNode *node) override; + std::string EmitFieldNode(FieldNode *node) override; + std::string EmitArrayLiteralNode(ArrayLiteralNode *node) override; + std::string EmitCondBranchNode(CondBranchNode *node) override; + std::string EmitForLoopNode(ForLoopNode *node) override; + std::string EmitWhileLoopNode(WhileLoopNode *node) override; + std::string EmitDoLoopNode(DoLoopNode *node) override; + std::string EmitAssertNode(AssertNode *node) override; + std::string EmitCallNode(CallNode *node) override; + std::string EmitFunctionNode(FunctionNode *node) override; + std::string EmitPrimTypeNode(PrimTypeNode *node) override; + std::string EmitModuleNode(ModuleNode *node) override; + std::string EmitClassNode(ClassNode *node) override; + + std::string EmitNumIndexSigNode(NumIndexSigNode *node) override; + std::string EmitStrIndexSigNode(StrIndexSigNode *node) override; + + std::string EmitNewNode(NewNode *node) override; + std::string EmitStructNode(StructNode *node) override; + std::string EmitTypeAliasNode(TypeAliasNode* node) override; + std::string EmitLiteralNode(LiteralNode* node) override; + std::string EmitArrayTypeNode(ArrayTypeNode *node) override; + + std::string GetTypeString(TreeNode *node, TreeNode *child = nullptr); + std::string EmitTSEnum(StructNode *node); + std::string EmitInterface(StructNode *node); + + void CollectFuncArgInfo(TreeNode* node); + std::string ConstructArray(ArrayLiteralNode* node, int dim, std::string type); + std::string ConstructArrayAny(ArrayLiteralNode* node); +}; + +inline bool IsVarInitStructLiteral(DeclNode* node) { + return node->GetInit() && + node->GetInit()->IsTypeIdClass() && + node->GetInit()->IsStructLiteral(); +} + +inline bool IsVarInitClass(DeclNode* node) { + return node->GetInit() && + node->GetInit()->IsTypeIdClass() && + node->GetInit()->IsIdentifier(); +} + +template +bool HasAttrStatic(T* node) { + for (unsigned i = 0; i < node->GetAttrsNum(); ++i) { + std::string s = Emitter::GetEnumAttrId(node->GetAttrAtIndex(i)); + if (s.compare("static ") == 0) + return true; + } + return false; +} + +} // namespace maplefe +#endif diff --git a/src/MapleFE/ast2cpp/include/cpp_definition.h b/src/MapleFE/ast2cpp/include/cpp_definition.h new file mode 100644 index 0000000000000000000000000000000000000000..ab4c1b077356d1a8b6d1ac7f80797a6e58a25583 --- /dev/null +++ b/src/MapleFE/ast2cpp/include/cpp_definition.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. + * + * OpenArkFE is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef __CPPDEFINITIONEMITTER_HEADER__ +#define __CPPDEFINITIONEMITTER_HEADER__ + +#include "ast_handler.h" +#include "cpp_emitter.h" +#include "cpp_declaration.h" + +namespace maplefe { + +class CppDef : public CppEmitter { +public: + CppDecl &mCppDecl; + bool mIsInit; + bool mIsGenerator; + + CppDef(Module_Handler *h, CppDecl &d) : CppEmitter(h), mCppDecl(d), mIsInit(false), mIsGenerator(false) {} + + std::string Emit() { + return EmitTreeNode(GetASTModule()); + } + + std::string EmitIdentifierNode(IdentifierNode *node) override; + std::string EmitImportNode(ImportNode *node) override; + std::string EmitXXportAsPairNode(XXportAsPairNode *node) override; + std::string EmitExportNode(ExportNode *node) override; + std::string EmitUnaOperatorNode(UnaOperatorNode *node) override; + std::string EmitBinOperatorNode(BinOperatorNode *node) override; + std::string EmitBlockNode(BlockNode *node) override; + std::string EmitDeclNode(DeclNode *node) override; + std::string EmitFieldNode(FieldNode *node) override; + std::string EmitArrayLiteralNode(ArrayLiteralNode *node) override; + std::string EmitTemplateLiteralNode(TemplateLiteralNode *node) override; + std::string EmitLiteralNode(LiteralNode *node) override; + std::string EmitCondBranchNode(CondBranchNode *node) override; + std::string EmitBreakNode(BreakNode *node) override; + std::string EmitContinueNode(ContinueNode *node) override; + std::string EmitForLoopNode(ForLoopNode *node) override; + std::string EmitSwitchNode(SwitchNode *node) override; + std::string EmitCallNode(CallNode *node) override; + std::string EmitFunctionNode(FunctionNode *node) override; + std::string EmitTypeOfNode(TypeOfNode *node) override; + std::string EmitModuleNode(ModuleNode *node) override; + std::string EmitPrimTypeNode(PrimTypeNode *node) override; + std::string EmitPrimArrayTypeNode(PrimArrayTypeNode *node) override; + std::string EmitNewNode(NewNode *node) override; + std::string EmitArrayElementNode(ArrayElementNode *node) override; + std::string EmitTypeAliasNode(TypeAliasNode* node) override; + std::string EmitInstanceOfNode(InstanceOfNode *node) override; + std::string EmitDeclareNode(DeclareNode *node) override; + std::string EmitAsTypeNode(AsTypeNode *node) override; + std::string EmitNamespaceNode(NamespaceNode *node) override; + std::string EmitRegExprNode(RegExprNode *node); + std::string EmitStructNode(StructNode *node) override; + std::string EmitStructLiteralNode(StructLiteralNode* node) override; + std::string EmitWhileLoopNode(WhileLoopNode *node) override; + std::string EmitYieldNode(YieldNode *node) override; + std::string& HandleTreeNode(std::string &str, TreeNode *node) override; + + std::string EmitClassProps(TreeNode *node); + std::string EmitFuncScopeVarDecls(FunctionNode *node); + std::string EmitCppCtor(ClassNode* node); + std::string EmitCtorInstance(ClassNode *c); + std::string EmitDefaultCtor(ClassNode *c); + std::string EmitBracketNotationProp(ArrayElementNode* ae, OprId binOpId, bool isLhs, bool& isDynProp); + TypeId GetTypeIdFromDecl(TreeNode* id); + bool IsClassField(ArrayElementNode* node, std::string propKey); + std::string GetTypeForTemplateArg(TreeNode* node); + TreeNode* FindDeclType(TreeNode* node); + std::string GetThisParamObjType(TreeNode *node); + + std::string ConstructArray(ArrayLiteralNode* node, int dim, std::string type); + std::string ConstructArrayAny(ArrayLiteralNode* node); + std::string GenObjectLiteral(TreeNode* var, std::string varName, TreeNode* idType, StructLiteralNode* n); + std::string GenDirectFieldInit(std::string varName, StructLiteralNode* node); +}; + +} // namespace maplefe +#endif diff --git a/src/MapleFE/ast2cpp/include/cpp_emitter.h b/src/MapleFE/ast2cpp/include/cpp_emitter.h new file mode 100644 index 0000000000000000000000000000000000000000..ec2f269dba259ae718c2db3d18ca98b74b05c500 --- /dev/null +++ b/src/MapleFE/ast2cpp/include/cpp_emitter.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. + * + * OpenArkFE is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef __CPPEMITTER_HEADER__ +#define __CPPEMITTER_HEADER__ + +#include "ast_module.h" +#include "emitter.h" + +namespace maplefe { + +// Class CppEmitter includes all functionalities which are common for Cpp definition and declaration +class CppEmitter : public Emitter { + +public: + CppEmitter(Module_Handler *h) : Emitter(h) {} + + std::string GetIdentifierName(TreeNode *node); + bool IsInNamespace(TreeNode *node); + std::string GetNamespace(TreeNode *node); + std::string GetQualifiedName(IdentifierNode *node); + bool IsClassId(TreeNode *node); + bool IsVarTypeClass(TreeNode* var); + void InsertEscapes(std::string& str); + bool IsGenerator(TreeNode *node); + FunctionNode* GetGeneratorFunc(TreeNode *node); + void GetArrayTypeInfo(ArrayLiteralNode* node, int& numDim, std::string& type); + std::string FunctionHeader(FunctionNode* node, std::string retType); + std::string GetClassName(TreeNode* node); +}; + +} // namespace maplefe +#endif diff --git a/src/MapleFE/ast2cpp/include/emitter.h b/src/MapleFE/ast2cpp/include/emitter.h new file mode 100644 index 0000000000000000000000000000000000000000..f8447db75616fe3886cdee9d83e863082a074955 --- /dev/null +++ b/src/MapleFE/ast2cpp/include/emitter.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. + * + * OpenArkFE is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef __EMITTER_HEADER__ +#define __EMITTER_HEADER__ + +#include "ast.h" +#include "ast_attr.h" +#include "ast_module.h" +#include "ast_type.h" + +#include "ast_handler.h" +#include "gen_astdump.h" +using namespace std::string_literals; + +namespace maplefe { + +class Emitter { + +protected: + using Precedence = unsigned char; + Precedence mPrecedence; + + Module_Handler *mHandler; + +public: + Emitter(Module_Handler *h) : mHandler(h) {} + + std::string Emit(const char *title); + std::string GetEnding(TreeNode *n); + std::string Clean(std::string &s); + std::string GetBaseFilename(); + std::string GetModuleName(const char *p = nullptr); + std::string GetModuleName(TreeNode *node); + + Module_Handler *GetModuleHandler() { return mHandler; } + ModuleNode *GetASTModule() { return mHandler->GetASTModule(); } + + virtual std::string EmitAnnotationNode(AnnotationNode *node); + virtual std::string EmitAsTypeNode(AsTypeNode *node); + virtual std::string EmitIdentifierNode(IdentifierNode *node); + virtual std::string EmitFunctionNode(FunctionNode *node); + virtual std::string EmitUserTypeNode(UserTypeNode *node); + virtual std::string EmitComputedNameNode(ComputedNameNode *node); + virtual std::string EmitPackageNode(PackageNode *node); + virtual std::string EmitXXportAsPairNode(XXportAsPairNode *node); + virtual std::string EmitDeclareNode(DeclareNode *node); + virtual std::string EmitExportNode(ExportNode *node); + virtual std::string EmitImportNode(ImportNode *node); + virtual std::string EmitUnaOperatorNode(UnaOperatorNode *node); + virtual std::string EmitBinOperatorNode(BinOperatorNode *node); + virtual std::string EmitTerOperatorNode(TerOperatorNode *node); + virtual std::string EmitTypeAliasNode(TypeAliasNode *node); + virtual std::string EmitConditionalTypeNode(ConditionalTypeNode *node); + virtual std::string EmitTypeParameterNode(TypeParameterNode *node); + virtual std::string EmitBlockNode(BlockNode *node); + virtual std::string EmitNewNode(NewNode *node); + virtual std::string EmitDeleteNode(DeleteNode *node); + virtual std::string EmitAnnotationTypeNode(AnnotationTypeNode *node); + virtual std::string EmitDimensionNode(DimensionNode *node); + virtual std::string EmitDeclNode(DeclNode *node); + virtual std::string EmitCastNode(CastNode *node); + virtual std::string EmitParenthesisNode(ParenthesisNode *node); + virtual std::string EmitFieldNode(FieldNode *node); + virtual std::string EmitArrayElementNode(ArrayElementNode *node); + virtual std::string EmitArrayLiteralNode(ArrayLiteralNode *node); + virtual std::string EmitBindingElementNode(BindingElementNode *node); + virtual std::string EmitBindingPatternNode(BindingPatternNode *node); + virtual std::string EmitNumIndexSigNode(NumIndexSigNode *node); + virtual std::string EmitStrIndexSigNode(StrIndexSigNode *node); + virtual std::string EmitStructNode(StructNode *node); + virtual std::string EmitFieldLiteralNode(FieldLiteralNode *node); + virtual std::string EmitStructLiteralNode(StructLiteralNode *node); + virtual std::string EmitNamespaceNode(NamespaceNode *node); + virtual std::string EmitVarListNode(VarListNode *node); + virtual std::string EmitExprListNode(ExprListNode *node); + virtual std::string EmitTemplateLiteralNode(TemplateLiteralNode *node); + virtual std::string EmitLiteralNode(LiteralNode *node); + virtual std::string EmitRegExprNode(RegExprNode *node); + virtual std::string EmitThrowNode(ThrowNode *node); + virtual std::string EmitCatchNode(CatchNode *node); + virtual std::string EmitFinallyNode(FinallyNode *node); + virtual std::string EmitTryNode(TryNode *node); + virtual std::string EmitExceptionNode(ExceptionNode *node); + virtual std::string EmitReturnNode(ReturnNode *node); + virtual std::string EmitYieldNode(YieldNode *node); + virtual std::string EmitCondBranchNode(CondBranchNode *node); + virtual std::string EmitBreakNode(BreakNode *node); + virtual std::string EmitContinueNode(ContinueNode *node); + virtual std::string EmitForLoopNode(ForLoopNode *node); + virtual std::string EmitWhileLoopNode(WhileLoopNode *node); + virtual std::string EmitDoLoopNode(DoLoopNode *node); + virtual std::string EmitSwitchLabelNode(SwitchLabelNode *node); + virtual std::string EmitSwitchCaseNode(SwitchCaseNode *node); + virtual std::string EmitSwitchNode(SwitchNode *node); + virtual std::string EmitAssertNode(AssertNode *node); + virtual std::string EmitCallNode(CallNode *node); + virtual std::string EmitInterfaceNode(InterfaceNode *node); + virtual std::string EmitClassNode(ClassNode *node); + virtual std::string EmitPassNode(PassNode *node); + virtual std::string EmitLambdaNode(LambdaNode *node); + virtual std::string EmitInstanceOfNode(InstanceOfNode *node); + virtual std::string EmitTypeOfNode(TypeOfNode *node); + virtual std::string EmitKeyOfNode(KeyOfNode *node); + virtual std::string EmitInferNode(InferNode *node); + virtual std::string EmitInNode(InNode *node); + virtual std::string EmitIsNode(IsNode *node); + virtual std::string EmitAwaitNode(AwaitNode *node); + virtual std::string EmitNameTypePairNode(NameTypePairNode *node); + virtual std::string EmitTupleTypeNode(TupleTypeNode *node); + virtual std::string EmitTripleSlashNode(TripleSlashNode *node); + virtual std::string EmitModuleNode(ModuleNode *node); + virtual std::string EmitAttrNode(AttrNode *node); + virtual std::string EmitArrayTypeNode(ArrayTypeNode *node); + virtual std::string EmitFunctionTypeNode(FunctionTypeNode *node); + virtual std::string EmitPrimTypeNode(PrimTypeNode *node); + virtual std::string EmitPrimArrayTypeNode(PrimArrayTypeNode *node); + + virtual std::string EmitTreeNode(TreeNode *node); + virtual std::string& HandleTreeNode(std::string &str, TreeNode *node); + + static void Replace(std::string &str, const char *o, const char *n, int cnt = 0); + static std::string GetEnumTypeId(TypeId k); + //static const char *GetEnumSepId(SepId k); + static const char *GetEnumOprId(OprId k); + //static const char *GetEnumLitId(LitId k); + static std::string GetEnumAttrId(AttrId k); + //static const char *GetEnumImportProperty(ImportProperty k); + //static const char *GetEnumOperatorProperty(OperatorProperty k); + static std::string GetEnumDeclProp(DeclProp k); + //static const char *GetEnumStructProp(StructProp k); + //static const char *GetEnumForLoopProp(ForLoopProp k); + //static const char *GetEnumLambdaProperty(LambdaProperty k); + const char *GetEnumTripleSlashProp(TripleSlashProp k); + std::string &AddParentheses(std::string &str, TreeNode *node); + +}; + +} // namespace maplefe +#endif diff --git a/src/MapleFE/ast2cpp/include/helper.h b/src/MapleFE/ast2cpp/include/helper.h new file mode 100644 index 0000000000000000000000000000000000000000..0eb8e89843ecb23e65507e68955a116bbc319deb --- /dev/null +++ b/src/MapleFE/ast2cpp/include/helper.h @@ -0,0 +1,143 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __HELPER_H__ +#define __HELPER_H__ + +#include +#include +#include +#include +#include +#include "massert.h" +#include "ast.h" +#include "typetable.h" +#include "emitter.h" + +using namespace std::string_literals; + +namespace maplefe { +extern std::string GeneratorFn_start; +extern std::string GeneratorFn_return; + +extern std::unordered_mapTypeIdToJSType; +extern std::unordered_mapTypeIdToJSTypeCXX; +extern TypeId hlpGetTypeId(TreeNode* node); +extern std::string GenClassFldAddProp(std::string, std::string, std::string, std::string, std::string); +extern std::string FunctionClassDecl(std::string retType, std::string funcName, unsigned nodeId); +extern std::string GeneratorClassDecl(std::string funcName, unsigned nodeId); +extern std::string GeneratorClassDef(std::string ns, std::string funcName, unsigned nodeId); +extern std::string tab(int n); +extern bool IsClassMethod(TreeNode* node); +extern std::string GetClassOfAssignedFunc(TreeNode* node); +extern std::string GenAnonFuncName(TreeNode* node); +inline std::string ClsName(std::string func) { return "Cls_"s + func; } +inline std::string GeneratorName(std::string func) { return "Generator_"s + func; } +inline std::string GeneratorFuncName(std::string func) { return "GeneratorFunc_"s + func; } +extern std::string hlpGetJSValTypeStr(TypeId typeId); +extern std::string ArrayCtorName(int dim, std::string type); +extern bool IsBuiltinObj(std::string name); +extern std::string ObjectTypeStr(std::string name); +extern std::string GeneratorFuncHeader(std::string cls, unsigned nodeId); +extern std::string FunctionParams(unsigned nodeId, bool handleThis, bool argsOnly = false, bool byRef = false, bool fdInit = false, bool capture = false); + +class GeneratorLabels { +private: + unsigned GenLoopId = 0; + unsigned GenYieldId= 0; +public: + std::string NextLoopLabel(void) { + std::string label = "_loop_" + std::to_string(++GenLoopId); + return label; + } + std::string NextYieldLabel(void) { + std::string label = "_yield_" + std::to_string(++GenYieldId); + return label; + } + void ResetLabels(void) { + GenLoopId = 0; + GenYieldId = 0; + } +}; + +class FuncTable { +private: + std::unordered_map TopLevelFunc; // map nodeId to TreeNode* + std::set TopLevelFuncNm; // name of top level func or name of var assigned top level func + std::set ImportedFields; + std::set StaticMembers; + + // map of FunctionNode node id to vector of function arg info (pair of arg type and name) + std::unordered_map>> args; + +public: + FuncTable() {} + ~FuncTable() {} + + // Check if node is top level function + void AddTopLevelFunc(TreeNode* node) { + assert(node->IsFunction()); + if (!static_cast(node)->IsConstructor()) + TopLevelFunc[node->GetNodeId()] = node; + } + bool IsTopLevelFunc(TreeNode* node) { + assert(node->IsFunction()); + std::unordered_map::iterator it; + it = TopLevelFunc.find(node->GetNodeId()); + return(it != TopLevelFunc.end()); + } + + // Check if name is top level func + void AddNameIsTopLevelFunc(std::string name) { + TopLevelFuncNm.insert(name); // name can be 1st level func, or func typed var + } + bool IsTopLevelFuncName(std::string& name) { + return(TopLevelFuncNm.find(name) != TopLevelFuncNm.end()); + } + + // Check if string (xxx::yyy) is an Imported field + std::string& AddFieldIsImported(std::string field) { + ImportedFields.insert(field); + return(field); + } + bool IsImportedField(std::string& field) { + return(ImportedFields.find(field) != ImportedFields.end()); + } + + // Check if a class member (field or method) is static + std::string& AddMemberIsStatic(std::string field) { + StaticMembers.insert(field); + return(field); + } + bool IsStaticMember(std::string& field) { + return(StaticMembers.find(field) != StaticMembers.end()); + } + + // Function arg info + void AddArgInfo(unsigned nodeId, std::string type, std::string name) { + args[nodeId].push_back(std::pair(type, name)); + } + std::vector> GetArgInfo(unsigned nodeId) { + return args[nodeId]; + } + +}; + +extern FuncTable hFuncTable; +extern GeneratorLabels GenFnLabels; + +} +#endif // __HELPER_H__ + diff --git a/src/MapleFE/ast2cpp/runtime/include/builtins.h b/src/MapleFE/ast2cpp/runtime/include/builtins.h new file mode 100644 index 0000000000000000000000000000000000000000..af0fe8f50dd34f39cf5912d7ed54593be4ce5748 --- /dev/null +++ b/src/MapleFE/ast2cpp/runtime/include/builtins.h @@ -0,0 +1,233 @@ +/* + * Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. + * + * OpenArkFE is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef __BUILTINS_H__ +#define __BUILTINS_H__ + +#include + +namespace t2crt { + +template +class Record : public Object { + public: + std::unordered_map records; + Record() {} + ~Record() {} + Record(Function* ctor, Object* proto) : Object(ctor, proto) {} + Record(Function* ctor, Object* proto, std::vector props) : Object(ctor, proto, props) {} +}; + +template +class Array : public Object { + public: + std::vector elements; + Array(Function* ctor, Object* proto): Object(ctor, proto) {} + Array(Function* ctor, Object* proto, std::initializer_list l): Object(ctor, proto), elements(l) {} + + T& operator[](int i) {return elements[i];} + void operator = (const std::vector &v) { elements = v; } + long size() { return elements.size(); } + + // Output array to string (recurses if multi-dim array via ostream output operator overload in t2cpp.cpp) + std::string Dump (void) override { + std::stringstream ss; + std::streambuf* old = std::cout.rdbuf(ss.rdbuf()); + if (elements.empty()) + std::cout << "[]"; + else { + std::cout << "[ "; + auto i = elements.begin(), e = elements.end(); + std::cout << *i++; + for (; i != e; ++i) + std::cout << ", " << *i; + std::cout << " ]"; + } + std::cout.rdbuf(old); + return ss.str(); + } + + // Put JS Array.prototype props as static fields and methods in this class + // and add to proplist of Array_ctor.prototype object on system init. + + class Ctor: public Function { + public: + Ctor(Function* ctor, Object* proto, Object* prototype_proto) : Function(ctor, proto, prototype_proto) {} + Array* _new() { + return new Array(this, this->prototype); + } + Array* _new(std::initializer_listl) { + return new Array(this, this->prototype, l); + } + }; + static Ctor ctor; +}; + +// Create ctor func for 1,2,3 dimension array of given type +// note: must be in sync with format generated by ArrayCtorName in helper.h +#define ARR_CTOR_DEF(type) \ + template <> \ + Array::Ctor Array::ctor = Array::Ctor(&Function::ctor, Function::ctor.prototype, Object::ctor.prototype); \ + template <> \ + Array*>::Ctor Array*>::ctor = Array*>::Ctor(&Function::ctor, Function::ctor.prototype, Object::ctor.prototype); \ + template <> \ + Array*>*>::Ctor Array*>*>::ctor = Array*>*>::Ctor(&Function::ctor, Function::ctor.prototype, Object::ctor.prototype); + +class JSON : public Object { + // TODO +}; + +class RegExp : public Object { + // TODO +public: + RegExp(Function* ctor, Object* proto): Object(ctor, proto) { } + RegExp(Function* ctor, Object* proto, std::string src): Object(ctor, proto) { source = src; } + ~RegExp(){} + std::string source; // text of the pattern + std::string Dump(void) override { return source; } + + class Ctor : public Function { + public: + Ctor(Function* ctor, Object* proto, Object* prototype_proto) : Function(ctor, proto, prototype_proto) { } + RegExp* _new(std::string src) {return new RegExp(this, this->prototype, src);} + virtual const char* __GetClassName() const {return "RegExp ";} + }; + static Ctor ctor; +}; + +class Number : public Object { +public: + // TODO + class Ctor : public Function { + public: + Ctor(Function* ctor, Object* proto, Object* prototype_proto) : Function(ctor, proto, prototype_proto) { } + virtual const char* __GetClassName() const {return "Number ";} + }; + static Ctor ctor; +}; + + +// 20.5 Error objects for execptions +class Error : public Object { + // TODO +}; + +// JavaScript generators and generator functions +// - The builtin GeneratorFunction is the constructor for all generator functions. +// - Generator functions are called directly to return generators (with closure). +// - Generators are iterators that calls corresponding generator function with +// data captured in closure to iterate for results. + +// ecma-262 section references are based on ecma-262 edition 12.0 + +// ecma262 27.1.1.5 IteratorResult interface: +struct IteratorResult : public Object { + bool done; // status of iterator next() call + JS_Val value; // done=false: current iteration element value + // done=true: return value of the iterator, undefined if none returned + IteratorResult() : done(true), value(undefined) { + this->AddProp("done", t2crt::ClassFld(&IteratorResult::done).NewProp(this, t2crt::TY_CXX_Bool)); + this->AddProp("value", t2crt::ClassFld(&IteratorResult::value).NewProp(this, t2crt::TY_CXX_Any)); + } + IteratorResult(bool done, JS_Val val) : done(done), value(val) { } + ~IteratorResult() { } +}; + +// ecma262 27.1.1.1 Iterable interface: +// To be iterable, an object or one of the objects up its prototype chain must +// have a property with a @@iterator key ([Symbol.iterator], the value of +// which is a function that returns iterators (i.e objects with Iterator interace +// methods next/return/throw). +// +// Note: For iterable objects such as arrays and strings, [Symbol.iterator]() +// returns a new iteraor object. But for the intrinsic object %IteratorPrototype% +// (27.1.2.1) it returns the current iterator instance, which +// means for all iterators, [Sumbol.iterator]() returns itself. + +// ecma262 27.1.2.1 %IteratorPrototype%: +// 1) All objects that implement iterator interface also inherit from %IteratorPrototype% +// 2) %IteratorPrototype% provides shared props for all iterator objects +// 3) %IteratorPrototype%[Symbol.iterator]() = this (current iterator instance) - used in for loops +class IteratorProto : public Object { +public: + IteratorResult _res; + IteratorProto(Function* ctor, Object* proto) : Object(ctor, proto) { } + ~IteratorProto() { } + // note: the arg on an iterator's 1st next() call is ignored per spec 27.5.1.2 + virtual IteratorResult* next (JS_Val* arg = nullptr) { return &_res; } + virtual IteratorResult* _return(JS_Val* val = nullptr) { return &_res; } + virtual IteratorResult* _throw(Error exception) { return &_res; } + + // TODO: %IteratorPrototype%[Symbol.iterator]() = this (current iterator instance) +}; + +// 27.5.1 Generator Prototype Object +// - in ecma edition 11: named %GeneratorPrototype% (25.4.1) +// - in ecma edition 12: named %GeneratorFunction.prototype.prototype% (27.5.1) but +// labelled as %GeneratoPrototype% in 27.3 Figure 5. +// Label corrected in version at tc39. +class GeneratorProto : public IteratorProto { +public: + GeneratorProto(Function* ctor, Object* proto) : IteratorProto(ctor, proto) { } + ~GeneratorProto() { } + void* _yield = nullptr; // pointer to yield label to resume execution + bool _finished = false; // flag if generator is in finished state + bool _firstNext = true; // flag if first next has been called on iterator (27.5.1.2) + + IteratorResult* _return(JS_Val* arg = nullptr) override { + _finished = true; + if (arg != nullptr) { + _res.value = *arg; + } + return &_res; + } +}; + +// 27.3.1 GeneratorFunction Constructor +class GeneratorFunc : public Function::Ctor { +public: + GeneratorFunc(Function* ctor, Object* proto, Object* prototype_proto, Function* prototype_obj) : Function::Ctor(ctor, proto, prototype_proto, prototype_obj) { } + ~GeneratorFunc() {} +}; + +// 27.3.3 GeneratorFunction Prototype Obejct +// - in ecma edition 11: named %Generator% (25.2.3) +// - in ecma edition 12: named %GeneratorFunction.prorotype% (27.3.3) but +// labelled as %Generator% in 27.3 Figure 5. +// Label corrected in tc39 version. +class GeneratorFuncPrototype : public Function { +public: + GeneratorFuncPrototype(Function* ctor, Object* proto, Object* prototype_proto) : Function(ctor, proto, prototype_proto) { } +}; + +// Generator related intrinsic objects. (ecma 27.3) +// IteratorPrototype: It is not a prototype object of any constructor func, but holds shared properties for iterators +// GeneratorFunction: A builtin function used as the constructor for generator functions. +// Generator: (GeneratorFuncion.prototype in edition 12.0) is the prototype object of GeneratorFunction, +// It is a special object used as both prototype object and constructor - as prototype for sharing +// properties between generator functions, and as constructor whose prototype object (GeneratorPrototype +// in edition 11) holds shared properties for generators (i.e. instances returned by generator functions. +extern IteratorProto IteratorPrototype; +extern GeneratorFunc GeneratorFunction; +extern GeneratorFuncPrototype Generator; +extern Object* GeneratorPrototype; + +} // namespace t2crt + + +using t2crt::Record; +using t2crt::JSON; +using t2crt::RegExp; +#endif // __BUILTINS_H__ diff --git a/src/MapleFE/ast2cpp/runtime/include/ts2cpp.h b/src/MapleFE/ast2cpp/runtime/include/ts2cpp.h new file mode 100644 index 0000000000000000000000000000000000000000..cdf48d2d55cc3ac65f17f6585192b2efbcd8fb25 --- /dev/null +++ b/src/MapleFE/ast2cpp/runtime/include/ts2cpp.h @@ -0,0 +1,510 @@ +/* + * Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. + * + * OpenArkFE is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef __TS2CPP_RT_HEADER__ +#define __TS2CPP_RT_HEADER__ + +#include +#include +#include +#include +#include +#include +#include + +using namespace std::string_literals; + +namespace t2crt { + +using std::to_string; + +inline std::string to_string(std::string t) {return t;} + +class Object; +class Function; +template +class Array; + +// JS types for props +#define TY_CXX 0x20 +typedef enum JS_Type : uint8_t { + TY_None = 0, // Placeholder for non-existing property + TY_Undef, // "undefined" + TY_Null, // "object" + TY_Bool, // "boolean" + TY_Long, // "number" + TY_Double, // "number" + TY_BigInt, // "bigint" + TY_String, // "string" + TY_Symbol, // "symbol" + TY_Function, // "function" + TY_Object, // "object" + TY_Array, + TY_Any, // JS_Val::x.field points to a JS_Val + TY_LAST, + TY_CXX_Undef = TY_Undef | TY_CXX, + TY_CXX_Null, + TY_CXX_Bool, + TY_CXX_Long, + TY_CXX_Double, + TY_CXX_BigInt, + TY_CXX_String, + TY_CXX_Symbol, + TY_CXX_Function, + TY_CXX_Object, + TY_CXX_Array, + TY_CXX_Any, // JS_Val::x.field points to a JS_Val + TY_CXX_LAST, +} JS_Type; + +struct JS_Val { + union { + void* field; // used by compiler genereted fields only + bool val_bool; + int64_t val_long; + double val_double; + void* val_bigint; + std::string* val_string; // JS string primitive (not JS String object) + Object* val_obj; // for function, object (incl. String objects) + Function* val_func; // for function + } x; + JS_Type type; + + bool IsCxxProp() { return type & TY_CXX; } // true if a cxx field + bool IsNone() { return type == TY_None; } + bool IsNull() { return type & TY_Null; } + bool IsUndef() { return type & TY_Undef; } + + JS_Val() { x.val_long = 0l; type = TY_Undef; } + JS_Val(int64_t l, JS_Type t, bool c) { x.val_long = l; type = t; } + JS_Val(bool b) { x.val_bool = b; type = TY_Bool; } + JS_Val(int64_t l) { x.val_long = l; type = TY_Long; } + JS_Val(double d) { x.val_double = d; type = TY_Double; } + JS_Val(Object* o) { x.val_obj = o; type = TY_Object; } + JS_Val(Object* o, JS_Type t) { x.val_obj = o; type = t; } + JS_Val(Function* o){ x.val_func = o; type = TY_Function; } + JS_Val(std::string* s) { x.val_string = s; type = TY_String; } + JS_Val(std::string s) { x.val_string = new std::string(s); type = TY_String; } + JS_Val(const char* s) { x.val_string = new std::string(s); type = TY_String; } + JS_Val(int i) { x.val_long = i; type = TY_Long; } + JS_Val(JS_Type jstype, bool v) { x.val_long = (int64_t)v; type = jstype; } + // Prop directly generated as class fields when TS is compiled into CPP + JS_Val(JS_Type jstype, void* field) { x.field = field; type = static_cast(jstype|TY_CXX); } + +#define OPERATORS(op) \ + JS_Val operator op(const JS_Val &v) { \ + JS_Val res; \ + if(type == v.type) \ + switch(type) { \ + case TY_Long: return { x.val_long op v.x.val_long }; \ + case TY_Double: return { x.val_double op v.x.val_double }; \ + } \ + else { \ + if(type == TY_Long && v.type == TY_Double) \ + return { (double)x.val_long op v.x.val_double }; \ + if(type == TY_Double && v.type == TY_Long) \ + return { x.val_double op (double)v.x.val_long }; \ + } \ + return res; \ + } + + OPERATORS(+) + OPERATORS(-) + OPERATORS(*) + + // Handle assigning value to a JS_Val obj +#define ASSIGN_OPR(ctype, jstype, jscxxtype) \ + JS_Val& operator=(ctype val) { \ + if (IsCxxProp()) { \ + type = jscxxtype; \ + *(ctype *)x.field = val; \ + } else { \ + type = jstype; \ + x.val_##ctype = val; \ + } \ + return *this; \ + } + + ASSIGN_OPR(double, TY_Double, TY_CXX_Double) + ASSIGN_OPR(long, TY_Long, TY_CXX_Long) + ASSIGN_OPR(bool, TY_Bool, TY_CXX_Bool) + + // assign Object ptr to JS_Val + JS_Val& operator=(Object* val) { + if (IsCxxProp()) { + type = TY_CXX_Object; + *(Object **)x.field = val; + } else { + type = TY_Object; + x.val_obj = val; + } + return *this; + } + + // convert int to numeric type in target JS_Val + JS_Val& operator=(int val) { + if (IsCxxProp()) { + if (type == TY_CXX_Long) + *(long*)x.field = (long)val; + else if (type == TY_CXX_Double) + *(double *)x.field = (double)val; + } else { + if (type == TY_Long) + x.val_long = (long)val; + else if (type == TY_Double) + x.val_double = (double)val; + else if (type == TY_Undef) { + // if target JS_Val is undef, convert to long + type = TY_Long; + x.val_long = (long)val; + } + } + return *this; + } + + JS_Val& operator=(std::string &val) { + if (IsCxxProp()) { + type = TY_CXX_String; + // x.field already pt to a str fd in a c++ obj + *(std::string *)x.field = val; + } else { + type = TY_String; + x.val_string = new std::string(val); + } + return *this; + } + + JS_Val& operator=(char* val) { + if (IsCxxProp()) { + type = TY_CXX_String; + *(std::string *)x.field = std::string(val); + } else { + type = TY_String; + x.val_string = new std::string(val); + } + return *this; + } + + +}; + +typedef std::unordered_map JS_PropList; +typedef std::pair ObjectProp; + +class Object { + public: + JS_PropList propList; + Object* __proto__; // prototype chain + Function* constructor; // constructor of object + + public: + Object(): __proto__(nullptr) {} + Object(Function* ctor, Object* proto): constructor(ctor), __proto__(proto) {} + Object(Function* ctor, Object* proto, std::vector props): constructor(ctor), __proto__(proto) + { + for (int i=0; iAddProp(props[i].first, props[i].second); + } + virtual ~Object() {} + class Ctor; + static Ctor ctor; + virtual std::string Dump(void); + + JS_Val& operator[] (std::string key) + { + if (!HasOwnProp(key)) AddProp(key, JS_Val()); + return GetPropVal(key); + } + + + bool HasOwnProp(std::string key) { + JS_PropList::iterator it; + it = propList.find(key); + return (it != propList.end()); + } + + void AddProp(std::string key, JS_Val val) { + propList[key] = val; + } + + JS_Val GetProp(std::string key) { + return propList[key]; + } + + JS_Val& GetPropVal(std::string key) { + return propList[key]; + } + + void* GetPropField(std::string key) { + return propList[key].x.field; + } + + bool GetPropBool(std::string key) { + if (propList[key].IsCxxProp()) + return *(bool*)GetPropField(key); + return propList[key].x.val_bool; + } + long GetPropLong(std::string key) { + if (propList[key].IsCxxProp()) + return *(long*)GetPropField(key); + return propList[key].x.val_long; + } + double GetPropDouble(std::string key) { + if (propList[key].IsCxxProp()) + return *(double*)GetPropField(key); + return propList[key].x.val_double; + } + void* GetPropBigInt(std::string key) { + if (propList[key].IsCxxProp()) + return *(void**)GetPropField(key); + return propList[key].x.val_bigint; + } + std::string GetPropStr(std::string key) { + if (propList[key].IsCxxProp()) + return *(*(std::string**)GetPropField(key)); + return *propList[key].x.val_string; + } + Object* GetPropObj(std::string key) { + if (propList[key].IsCxxProp()) + return *(Object**)GetPropField(key); + return propList[key].x.val_obj; + } + Function* GetPropFunc(std::string key) { + if (propList[key].IsCxxProp()) + return *(Function**)GetPropField(key); + return propList[key].x.val_func; + } + + virtual bool IsFuncObj() { + return false; + } + + bool IsEmpty() const { + return propList.empty(); + } + + virtual const char* __GetClassName() const { + return ""; + } + + // Put code for JS Object.prototype props as static fields and methods in this class + // and add to propList of Object_ctor.prototype object on system init. + + virtual std::string TypeId() { + return "object"s; + } +}; + + +using ArgsT = Array; + +class Function : public Object { + public: + Object* prototype; // prototype property + Object* _thisArg; // from bind() + ArgsT* _args; // from bind() + + Function(Function* ctor, Object* proto, Object* prototype_proto) : Object(ctor, proto) { + JS_Val val(this); + prototype = new Object(this, prototype_proto); + prototype->AddProp("constructor", val); + } + // Special constructor for creating builtin constructor function "GeneratorFunction" see builtins.h + Function(Function* ctor, Object* proto, Object* prototype_proto, Object* prototype_obj) : Object(ctor, proto) { + JS_Val val(this); + prototype = prototype_obj; + prototype->AddProp("constructor", val); + } + + class Ctor; + static Ctor ctor; + + bool IsFuncObj() { + return true; + } + + // Put code for JS Function.prototype props as static fields and methods in this class + // and add to propList of Function_ctor.prototype object on system init. + virtual Object* bind (Object* obj, ArgsT* argv) { return nullptr; } + virtual JS_Val call (Object* obj, ArgsT* argv) { JS_Val res; return res; } + virtual JS_Val apply(Object* obj, ArgsT* argv) { JS_Val res; return res; } + + std::string TypeId() override { + return "function"s; + } +}; + + + +class Object::Ctor : public Function { + public: + Ctor(Function* ctor, Object* proto) : Function(ctor, proto, nullptr) {} + + Object* operator()(Object* obj) { + return(obj); + } + Object* _new() { + return new Object(this, this->prototype); + } + Object* _new(std::vector props) { + return new Object(this, this->prototype, props); + } +}; + +class Function::Ctor : public Function { + public: + Ctor(Function* ctor, Object* proto, Object* prototype_proto) : Function(ctor, proto, prototype_proto) {} + Ctor(Function* ctor, Object* proto, Object* prototype_proto, Object* prototype_obj) : Function(ctor, proto, prototype_proto, prototype_obj) {} +}; + +template +class ClassFld { + // Helper class for converting between class field offset, void ptr and integer val + // NewProp() creates a JS_Val of type TY_CXX_ with pointer to objet member field. + typedef union { +// void* addr; + T offset; + int fld_offset; + } FldAddr; + + public: + FldAddr field; + public: +// JS_Val NewProp(JS_Type type) {return JS_Val(type, field.addr);} + ClassFld(T offset) {field.offset = offset;} + T Offset() {return field.offset;} + JS_Val NewProp(void* obj, JS_Type type) {return JS_Val(type, (void*)((char*)obj+field.fld_offset));} +}; + +template std::string __js_typeof(T* v) { + return v->TypeId(); +} + +template std::string __js_typeof(T v) { + if (std::is_signed::value) + return "number"s; + if (std::is_integral::value) + return "boolean"s; + return "unknown"s; +} + +template <> inline std::string __js_typeof(std::string v) { + return "string"s; +} + +template <> inline std::string __js_typeof(t2crt::JS_Val v) { + static std::string names[t2crt::TY_LAST] = { + [t2crt::TY_None] = "none"s, + [t2crt::TY_Undef] = "undefined"s, + [t2crt::TY_Null] = "object"s, + [t2crt::TY_Bool] = "boolean"s, + [t2crt::TY_Long] = "number"s, + [t2crt::TY_Double] = "number"s, + [t2crt::TY_BigInt] = "bigint"s, + [t2crt::TY_String] = "string"s, + [t2crt::TY_Symbol] = "symbol"s, + [t2crt::TY_Function] = "function"s, + [t2crt::TY_Object] = "object"s, + }; + return names[v.type]; +} + +// TSC restricts Lhs of instanceof operator to either type any or an object type. +bool InstanceOf(JS_Val val, Function* ctor); + +// Our implementation returns true if the prototype property of the func/class +// constructor appers in the proto chain of the object. +template +bool InstanceOf(T* val, Function* ctor) { + if (ctor == nullptr) + return false; + + Object* p = val->__proto__; + while (p) { + if (p == ctor->prototype) + return true; + else + p = p->__proto__; + } + return false; +} + +// TODO: To be implemented +inline bool StrictEqu(JS_Val lhs, JS_Val rhs) { return false; } +inline bool StrictNotEqu(JS_Val lhs, JS_Val rhs) { return true; } + +void GenerateDOTGraph( std::vector&obj, std::vector&name); + +} // namespace t2crt + +extern std::ostream& operator<< (std::ostream& out, const t2crt::JS_Val& v); +extern std::ostream& operator<< (std::ostream& out, t2crt::Object* obj); +extern const t2crt::JS_Val undefined; +extern const t2crt::JS_Val null; + +#include "builtins.h" + +template +std::ostream& operator<< (std::ostream& out, const std::vector& v) { + if(v.empty()) + out << "[]"; + else { + out << "[ "; + auto i = v.begin(), e = v.end(); + out << *i++; + for (; i != e; ++i) + std::cout << ", " << *i; + out << " ]"; + } + return out; +} + +template +std::ostream& operator<< (std::ostream& out, const t2crt::Array* v) { + if(v->elements.empty()) + out << "[]"; + else { + out << "[ "; + auto i = v->elements.begin(), e = v->elements.end(); + out << *i++; + for (; i != e; ++i) + std::cout << ", " << *i; + out << " ]"; + } + return out; +} + +template +std::ostream& operator<< (std::ostream& out, const t2crt::Array& v) { + if(v.elements.empty()) + out << "[]"; + else { + out << "[ "; + auto i = v.elements.begin(), e = v.elements.end(); + out << *i++; + for (; i != e; ++i) + std::cout << ", " << *i; + out << " ]"; + } + return out; +} + +#define debugger (0) + +using t2crt::Object; +using t2crt::Function; +using t2crt::Array; + +#endif diff --git a/src/MapleFE/ast2cpp/runtime/src/builtins.cpp b/src/MapleFE/ast2cpp/runtime/src/builtins.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43f6dd65fbd1bf433a3576824b3745121c340ef2 --- /dev/null +++ b/src/MapleFE/ast2cpp/runtime/src/builtins.cpp @@ -0,0 +1,23 @@ +#include "../include/ts2cpp.h" + +namespace t2crt { + +Object::Ctor Object::ctor (&Function::ctor, Function::ctor.prototype); +Function::Ctor Function::ctor(&Function::ctor, Function::ctor.prototype, Object::ctor.prototype); +Number::Ctor Number::ctor (&Function::ctor, Function::ctor.prototype, Object::ctor.prototype); +RegExp::Ctor RegExp::ctor (&Function::ctor, Function::ctor.prototype, Object::ctor.prototype); + +IteratorProto IteratorPrototype(&Object::ctor, Object::ctor.prototype); +GeneratorFuncPrototype Generator(&GeneratorFunction, Function::ctor.prototype, &IteratorPrototype); +GeneratorFunc GeneratorFunction(&Function::ctor, &Function::ctor, Function::ctor.prototype, &Generator); +Object* GeneratorPrototype = Generator.prototype; + +ARR_CTOR_DEF(int) +ARR_CTOR_DEF(long) +ARR_CTOR_DEF(double) +ARR_CTOR_DEF(JS_Val) +ARR_CTOR_DEF(Object) +ARR_CTOR_DEF(Object*) + +} // namepsace t2crt + diff --git a/src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp b/src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50fecb38bc70c6b4c71e517d5bf98f7392e4178e --- /dev/null +++ b/src/MapleFE/ast2cpp/runtime/src/ts2cpp.cpp @@ -0,0 +1,151 @@ +#include +#include +#include "../include/ts2cpp.h" +#include "ast_common.h" + +std::ostream& operator<< (std::ostream& out, const t2crt::JS_Val& v) { + switch(v.type) { + case t2crt::TY_None: out << "None"; break; + case t2crt::TY_Undef: out << "undefined"; break; + case t2crt::TY_Null: out << "null"; break; + case t2crt::TY_Bool: out << v.x.val_bool; break; + case t2crt::TY_Long: out << v.x.val_long; break; + case t2crt::TY_Double: out << v.x.val_double; break; + case t2crt::TY_BigInt: out << "bigint"; break; + case t2crt::TY_String: out << *v.x.val_string; break; + case t2crt::TY_Symbol: out << "symbol"; break; + case t2crt::TY_Function: out << "function"; break; + case t2crt::TY_Object: out << v.x.val_obj; break; + case t2crt::TY_Any: out << *(t2crt::JS_Val*)v.x.field; break; + + case t2crt::TY_CXX_Undef: out << "undefined"; break; + case t2crt::TY_CXX_Null: out << "null"; break; + case t2crt::TY_CXX_Bool: out << *(bool*)v.x.field; break; + case t2crt::TY_CXX_Long: out << *(int64_t*)v.x.field; break; + case t2crt::TY_CXX_Double: out << *(double *)v.x.field; break; + case t2crt::TY_CXX_BigInt: out << "bigint"; break; + case t2crt::TY_CXX_String: out << *(std::string*)v.x.field; break; + case t2crt::TY_CXX_Symbol: out << "symbol"; break; + case t2crt::TY_CXX_Function: out << "function"; break; + case t2crt::TY_CXX_Object: out << *(Object**)v.x.field; break; + case t2crt::TY_CXX_Any: out << *(t2crt::JS_Val*)v.x.field; break; + } + return out; +} + +std::ostream& operator<< (std::ostream& out, t2crt::Object *obj) { + if (obj == nullptr) + return out; + out << obj->Dump(); + return out; +} + +const t2crt::JS_Val undefined = { 0, t2crt::TY_Undef, false }; +const t2crt::JS_Val null = { 0, t2crt::TY_Null, false }; + +namespace t2crt { + +std::string Object::Dump(void) { + std::string str; + str += this->constructor->__GetClassName(); + if (this->IsEmpty()) + str += "{}"; + else { + std::vector vec; + unsigned cnt = 0; + std::stringstream buf; + buf << std::boolalpha; + // non-object fields go first + for (bool flag: { false, true }) { + for (auto it = this->propList.begin(); it != this->propList.end(); it++) { + auto k = it->second.type; + auto b = k == t2crt::TY_Object || k == t2crt::TY_CXX_Object; + if (b == flag) { + buf.str(std::string()); + const std::string &prop = it->first; + if (isdigit(prop.front())) + buf << '\'' << prop << "': "; + else { + auto len = prop.length(); + constexpr auto suffixlen = sizeof(RENAMINGSUFFIX) - 1; + if (len > suffixlen && prop.substr(len - suffixlen) == RENAMINGSUFFIX) + buf << prop.substr(0, len - suffixlen) << ": "; + else + buf << prop << ": "; + } + if (k == t2crt::TY_String || k == t2crt::TY_CXX_String) + buf << '\'' << it->second << '\''; + else + buf << it->second; + vec.push_back(buf.str()); + } + } + std::sort(vec.begin() + cnt, vec.end()); + cnt = vec.size(); + } + const char *p = "{ "; + for (auto prop: vec) { + str += p + prop; + p = ", "; + } + str += " }"; + } + return str; +} + +bool InstanceOf(JS_Val val, Function* ctor) { + if (val.type != TY_Object || val.x.val_obj == nullptr || ctor == nullptr) + return false; + + Object* p = val.x.val_obj->__proto__; + while (p) { + if (p == ctor->prototype) + return true; + else + p = p->__proto__; + } + return false; +} + +// Generate DOT graph output to show object inheritance with +// constructor, prototype chain and prototype property linkages +void GenerateDOTGraph( std::vector&obj, std::vector&name) { + for(int g = 0; g < 2; ++g) { + std::vector objs = obj; + std::vector names = name; + std::cout << "digraph JS" << g << " {\nranksep=0.6;\nnodesep=0.6;\n" << (g == 0 ? "newrank=true;\n" : "") << std::endl; + int num = objs.size(); + int k = num; + + for (int i=0; iIsFuncObj(); + if (isFuncObj) { + // only function objects have prototype prop + objs.push_back(((Function *)objs[i])->prototype); + names.push_back(names[i] + "_prototype"); + if (g == 0) { + std::cout << "subgraph cluster_" << names[i] << " {\nrank=same;\ncolor=white;\n" + << names[i] << ";\n" << names[k] << "[label=\"" << names[i] << ".prototype\", shape=box];\n }" << std::endl; + } + else { + std::cout << names[k] << "[label=\"" << names[i] << ".prototype\", shape=box];" << std::endl; + } + std::cout << names[i] << " -> " << names[k] << " [label=\"prototype\", color=blue, fontcolor=blue];" << std::endl; + k++; + } + } + num = objs.size(); + for (int i=0; i 0 && objs[i]->constructor == objs[j]) + std::cout << names[i] << " -> " << names[j] << " [label=\"ctor\", color=darkgreen, fontcolor=darkgreen];" << std::endl; + + if(objs[i]->__proto__ == objs[j]) + std::cout << names[i] << " -> " << names[j] << " [label=\"__proto__\", color=red, fontcolor=red];" << std::endl; + } + } + std::cout << "} // digraph JS" << g << std::endl; + } +} + +} // namespace t2crt diff --git a/src/MapleFE/ast2cpp/src/Makefile b/src/MapleFE/ast2cpp/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..084bcad114a3f5728966433d2aaf28c3569731ba --- /dev/null +++ b/src/MapleFE/ast2cpp/src/Makefile @@ -0,0 +1,93 @@ +# Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +include ../../Makefile.in +BUILDBIN=$(BUILDDIR)/bin +BUILD=$(BUILDDIR)/ast2cpp +BUILDGEN=$(BUILDDIR)/gen +BUILDASTGEN=$(BUILDDIR)/ast_gen/shared +$(shell $(MKDIR_P) $(BUILD)) + +SRC=$(wildcard *.cpp) +OBJ :=$(patsubst %.cpp,%.o,$(SRC)) +DEP :=$(patsubst %.cpp,%.d,$(SRC)) + +SRCG := $(wildcard $(BUILDGEN)/gen*.cpp) +OBJG := $(patsubst %.cpp, %.o, $(SRCG)) +DEPG := $(patsubst %.cpp, %.d, $(SRCG)) + +LOCALOBJS :=$(foreach obj,$(OBJ), $(BUILD)/$(obj)) +LOCALDEPS :=$(foreach dep,$(DEP), $(BUILD)/$(dep)) +OBJS :=$(LOCALOBJS) $(OBJG) +DEPS :=$(LOCALDEPS) $(DEPG) + +LIBOBJS :=$(patsubst $(BUILD)/main.o,,$(LOCALOBJS)) + +GENDIR:=${BUILDDIR}/ast_gen/shared + +INCLUDES := -I $(MAPLEFE_ROOT)/shared/include \ + -I $(MAPLEFE_ROOT)/astopt/include \ + -I $(MAPLEFE_ROOT)/ast2cpp/include \ + -I $(MAPLEFE_ROOT)/autogen/include \ + -I $(MAPLEFE_ROOT)/shared/include \ + -I $(MAPLEFE_ROOT)/typescript/include \ + $(MAPLEALL_INC) -I ${GENDIR} + +INCLUDEGEN := -I $(MAPLEFE_ROOT)/shared/include -I $(BUILDDIR)/gen -I $(BUILDASTGEN) + +TARGET=ast2cpp +TARGET_A=ast2cpp.a + +SHAREDLIB = $(BUILDDIR)/astopt/astopt.a $(BUILDDIR)/shared/shared.a $(BUILDASTGEN)/genast.a +LANGSPEC=$(BUILDDIR)/typescript/lang_spec.o + +.PHONY: all +all: $(BUILDBIN)/$(TARGET) + +-include $(DEPS) +.PHONY: clean + +vpath %.o $(BUILD) +vpath %.d $(BUILD) + +#Pattern Rules +$(BUILD)/%.o : %.cpp + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ + +$(BUILD)/%.d : %.cpp + @$(CXX) $(CXXFLAGS) -MM $(INCLUDES) $< > $@ + @mv -f $(BUILD)/$*.d $(BUILD)/$*.d.tmp + @sed -e 's|.*:|$(BUILD)/$*.o:|' < $(BUILD)/$*.d.tmp > $(BUILD)/$*.d + @rm -f $(BUILD)/$*.d.tmp + +$(BUILDGEN)/%.o : $(BUILDGEN)/%.cpp $(BUILDGEN)/%.d + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDEGEN) -w -c $< -o $@ + +$(BUILDGEN)/%.d : $(BUILDGEN)/%.cpp + @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDEGEN) $< > $@ + @mv -f $(BUILDGEN)/$*.d $(BUILDGEN)/$*.d.tmp + @sed -e 's|.*:|$(BUILDGEN)/$*.o:|' < $(BUILDGEN)/$*.d.tmp > $(BUILDGEN)/$*.d + @rm -f $(BUILDGEN)/$*.d.tmp + +# TARGET depends on OBJS and shared OBJS from shared directory +# as well as mapleall libraries +$(BUILD)/$(TARGET_A): $(LIBOBJS) + /usr/bin/ar rcs $(BUILD)/$(TARGET_A) $(LIBOBJS) + +$(BUILDBIN)/$(TARGET): $(BUILD)/$(TARGET_A) $(OBJS) $(SHAREDLIB) + @mkdir -p $(BUILDBIN) + $(LD) -o $(BUILDBIN)/$(TARGET) $(BUILD)/main.o $(BUILD)/$(TARGET_A) $(OBJG) $(LANGSPEC) $(SHAREDLIB) + +clean: + rm -rf $(BUILD) diff --git a/src/MapleFE/ast2cpp/src/a2c_util.cpp b/src/MapleFE/ast2cpp/src/a2c_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f9bb62cadc557da43df4949d5b5d2e3702303830 --- /dev/null +++ b/src/MapleFE/ast2cpp/src/a2c_util.cpp @@ -0,0 +1,73 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include "a2c_util.h" +#include "gen_astdump.h" + +namespace maplefe { + +std::string ImportedFiles::GetTargetFilename(TreeNode *node) { + std::string filename; + if (node && node->IsLiteral()) { + LiteralNode *lit = static_cast(node); + LitData data = lit->GetData(); + filename = AstDump::GetEnumLitData(data); + filename += ".ts.ast"s; + if(filename.front() != '/') { + std::filesystem::path p = mModule->GetFilename(); + try { + p = std::filesystem::canonical(p.parent_path() / filename); + filename = p.string(); + } + catch(std::filesystem::filesystem_error const& ex) { + // Ignore std::filesystem::filesystem_error exception + // keep filename without converting it to a cannonical path + } + } + } + return filename; +} + +ImportNode *ImportedFiles::VisitImportNode(ImportNode *node) { + std::string name = GetTargetFilename(node->GetTarget()); + if (!name.empty()) { + mFilenames.push_back(name); + } + for (unsigned i = 0; i < node->GetPairsNum(); ++i) { + if (auto x = node->GetPair(i); x->IsSingle()) { + std::string s = GetTargetFilename(x->GetBefore()); + if (!s.empty()) + mFilenames.push_back(s); + } + } + for (unsigned i = 0; i < node->GetPairsNum(); i++) { + XXportAsPairNode *pair = node->GetPair(i); + (void) AstVisitor::VisitTreeNode(pair); + } + return node; +} + +ExportNode *ImportedFiles::VisitExportNode(ExportNode *node) { + std::string name = GetTargetFilename(node->GetTarget()); + if (!name.empty()) + mFilenames.push_back(name); + for (unsigned i = 0; i < node->GetPairsNum(); i++) { + XXportAsPairNode *pair = node->GetPair(i); + (void) AstVisitor::VisitTreeNode(pair); + } + return node; +} +} diff --git a/src/MapleFE/ast2cpp/src/ast2cpp.cpp b/src/MapleFE/ast2cpp/src/ast2cpp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..449e4b9c17caeb49da0feb1e037cf51a99b2ade2 --- /dev/null +++ b/src/MapleFE/ast2cpp/src/ast2cpp.cpp @@ -0,0 +1,243 @@ +/* +* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include +#include + +#include "ast2cpp.h" +#include "ast_handler.h" +#include "gen_astdump.h" +#include "gen_astgraph.h" +#include "gen_aststore.h" +#include "gen_astload.h" +#include "cpp_definition.h" +#include "cpp_declaration.h" +#include "a2c_util.h" + +namespace maplefe { + +void A2C::EmitTS() { + for (HandlerIndex i = 0; i < GetModuleNum(); i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + + // build CFG + handler->BuildCFG(); + + ModuleNode *module = handler->GetASTModule(); + std::cout << "============= AstDump ===========" << std::endl; + AstDump astdump(module); + astdump.Dump("After BuildCFG()", &std::cout); + std::cout << "============= AstGraph ===========" << std::endl; + AstGraph graph(module); + graph.DumpGraph("After BuildCFG()", &std::cout); + std::cout << "============= Emitter ===========" << std::endl; + maplefe::Emitter emitter(handler); + std::string code = emitter.Emit("Convert AST to TypeScript code"); + std::cout << code; + } +} + +bool A2C::LoadImportedModules() { + std::queue queue; + for (HandlerIndex i = 0; i < GetModuleNum(); i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + ModuleNode *module = handler->GetASTModule(); + ImportedFiles imported(module); + imported.VisitTreeNode(module); + for(const auto &e: imported.mFilenames) + queue.push(e); + } + + bool err = false; + while(!queue.empty()) { + std::string filename = queue.front(); + queue.pop(); + if(mASTHandler->GetHandlerIndex(filename.c_str()) == HandlerNotFound) { + std::ifstream input(filename, std::ifstream::binary); + if(input.fail()) { + std::cerr << "Error: File " << filename << " not found for imported module" << std::endl; + err = true; + continue; + } + input >> std::noskipws; + std::istream_iterator s(input), e; + maplefe::AstBuffer vec(s, e); + maplefe::AstLoad loadAst; + maplefe::ModuleNode *mod = loadAst.LoadFromAstBuf(vec); + // add mod to the vector + while(mod) { + mASTHandler->AddModule(mod); + ImportedFiles imported(mod); + imported.VisitTreeNode(mod); + for(const auto &e: imported.mFilenames) + queue.push(e); + mod = loadAst.Next(); + } + } + } + return err; +} + +// starting point of AST +int A2C::ProcessAST() { + mIndexImported = GetModuleNum(); + + // used for FE verification + if (mFlags & FLG_emit_ts_only) { + EmitTS(); + return 0; + } + + // load all imported modules + if (!(mFlags & FLG_no_imported)) + if (LoadImportedModules()) + return 1; + + // loop through module handlers + for (HandlerIndex i = 0; i < GetModuleNum(); i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + ModuleNode *module = handler->GetASTModule(); + + if (mFlags & FLG_trace_1) { + std::cout << "============= in ProcessAST ===========" << std::endl; + std::cout << "srcLang : " << module->GetSrcLangString() << std::endl; + + for(unsigned k = 0; k < module->GetTreesNum(); k++) { + TreeNode *tnode = module->GetTree(k); + if (mFlags & FLG_trace_1) { + tnode->Dump(0); + std::cout << std::endl; + } + } + } + + if (mFlags & FLG_trace_2) { + std::cout << "============= AstGraph ===========" << std::endl; + AstGraph graph(module); + graph.DumpGraph("After LoadFromAstBuf()", &std::cout); + } + } + + // build dependency of modules + PreprocessModules(); + + // loop through module handlers in import/export dependency order + for (auto handler: mHandlersInOrder) { + ModuleNode *module = handler->GetASTModule(); + + // basic analysis + handler->BasicAnalysis(); + + if (mFlags & FLG_trace_2) { + std::cout << "============= After AdjustAST ===========" << std::endl; + for(unsigned k = 0; k < module->GetTreesNum(); k++) { + TreeNode *tnode = module->GetTree(k); + if (mFlags & FLG_trace_1) { + tnode->Dump(0); + std::cout << std::endl; + } + } + AstGraph graph(module); + graph.DumpGraph("After AdjustAST()", &std::cout); + } + + // build CFG + handler->BuildCFG(); + + if (mFlags & FLG_trace_2) { + handler->Dump("After BuildCFG()"); + } + + // control flow analysis + handler->ControlFlowAnalysis(); + + // type inference + handler->TypeInference(); + + if (mFlags & FLG_trace_2) { + std::cout << "============= AstGraph ===========" << std::endl; + AstGraph graph(module); + graph.DumpGraph("After TypeInference()", &std::cout); + } + + if (mFlags & FLG_trace_2) { + std::cout << "============= AstDump ===========" << std::endl; + AstDump astdump(module); + astdump.Dump("After TypeInference()", &std::cout); + } + + // data flow analysis + handler->DataFlowAnalysis(); + + if (mFlags & FLG_trace_2) { + handler->Dump("After DataFlowAnalysis()"); + } + } + + for (auto handler: mHandlersInOrder) { + ModuleNode *module = handler->GetASTModule(); + + if (mFlags & FLG_emit_ts) { + std::cout << "============= Emitter ===========" << std::endl; + maplefe::Emitter emitter(handler); + std::string code = emitter.Emit("Convert AST to TypeScript code"); + std::cout << code; + } + } + + if (mFlags & FLG_trace_2) { + std::cout << "============= CppHandler ===========" << std::endl; + } + maplefe::CppHandler cppHandler(mASTHandler, mFlags); + cppHandler.EmitCxxFiles(); + return 0; +} + +bool CppHandler::EmitCxxFiles() { + unsigned size = mASTHandler->GetSize(); + for (int i = 0; i < size; i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + CppDecl decl(handler); + { // Emit C++ header file + std::string decl_code = decl.Emit(); + std::string fn = decl.GetBaseFilename() + ".h"s; + std::ofstream out(fn.c_str(), std::ofstream::out); + out << decl_code; + out.close(); + if (mFlags & FLG_format_cpp) { + std::string cmd = "clang-format-10 -i --sort-includes=0 "s + fn; + std::system(cmd.c_str()); + } + } + { // Emit C++ implementation file + CppDef def(handler, decl); + std::string def_code = def.Emit(); + std::string fn = def.GetBaseFilename() + ".cpp"s; + std::ofstream out(fn.c_str(), std::ofstream::out); + out << def_code; + out.close(); + if (mFlags & FLG_format_cpp) { + std::string cmd = "clang-format-10 -i --sort-includes=0 "s + fn; + std::system(cmd.c_str()); + } + } + } + return true; +} + +} // namespace maplefe diff --git a/src/MapleFE/ast2cpp/src/cpp_declaration.cpp b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp new file mode 100644 index 0000000000000000000000000000000000000000..315c8624b6a528f0959b5770b4a3d2642a03470b --- /dev/null +++ b/src/MapleFE/ast2cpp/src/cpp_declaration.cpp @@ -0,0 +1,1128 @@ +/* + * Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. + * + * OpenArkFE is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "cpp_declaration.h" +#include "gen_astvisitor.h" +#include +#include +#include "helper.h" +#include "ast_common.h" + +namespace maplefe { + +class ImportExportModules : public AstVisitor { + private: + CppDecl *mCppDecl; + Emitter *mEmitter; + std::string mIncludes; + std::string mImports; + std::string mExports; + bool mExFlag; + + public: + ImportExportModules(CppDecl *c) : mCppDecl(c), + mIncludes("// include directives\n"), + mImports("// imports\n"), + mExports("// exports\n"), + mExFlag(false) { + mEmitter = new Emitter(c->GetModuleHandler()); + } + ~ImportExportModules() { delete mEmitter; } + + std::string GetIncludes() { return mIncludes; } + std::string GetImports() { return mImports; } + std::string GetExports() { return mExports; } + + std::string AddIncludes(TreeNode *node) { + std::string filename; + if (node) { + filename = mEmitter->EmitTreeNode(node); + auto len = filename.size(); + filename = len >= 2 && filename.back() == '"' ? filename.substr(1, len - 2) : std::string(); + // may have some duplicated include directives which do not hurt + if (!filename.empty()) { + std::string incl = "#include \""s + filename + ".h\"\n"s; + std::size_t found = mIncludes.find(incl); + if (found == std::string::npos) { + mIncludes += "#include \""s + filename + ".h\"\n"s; + mCppDecl->AddInit(tab(1) + mCppDecl->GetModuleName(filename.c_str()) + "::__init_func__();\n"s); + } + } + } + return filename; + } + + std::string Comment(TreeNode *node) { + std::string s = mEmitter->EmitTreeNode(node); + return s.empty() ? s : "//--- "s + s.substr(0, s.find('\n')) + '\n'; + } + + ImportNode *VisitImportNode(ImportNode *node) { + std::string filename = AddIncludes(node->GetTarget()); + std::string module = mCppDecl->GetModuleName(filename.c_str()); + for (unsigned i = 0; i < node->GetPairsNum(); ++i) { + if (auto x = node->GetPair(i)) { + mImports += Comment(node); + std::string str; + if (x->IsDefault()) { + if (auto b = x->GetBefore()) { + std::string v = module + "::__export::__default"s; + std::string s = mEmitter->EmitTreeNode(b); + if (b->GetTypeId() == TY_Class) + mImports += "using "s + s + " = "s + v + ";\n"s; + else + mImports += "inline const decltype("s + v + ") &"s + s + " = "s + v + ";\n"s; + } + } else if (x->IsSingle()) { + if (auto b = x->GetBefore(); b->IsLiteral()) { + if (auto a = x->GetAfter()) { + // import X = require("./module"); + std::string after = mEmitter->EmitTreeNode(a); + filename = AddIncludes(b); + module = mCppDecl->GetModuleName(filename.c_str()); + std::string v = module + "::__export::__default"s; + if(a->GetTypeId() == TY_Module || a->GetTypeId() == TY_Namespace) + mImports += "namespace "s + after + " = "s + module + v + ";\n"s; + else if (a->GetTypeId() == TY_Class) + mImports += "using "s + after + " = "s + v + ";\n"s; + else + mImports += "inline const decltype("s + v + ") &"s + after + " = "s + v + ";\n"s; + } + } + } else if (x->IsEverything()) { + if (auto n = x->GetBefore()) { + std::string s = mEmitter->EmitTreeNode(n); + mImports += "namespace "s + s + " = " + module + "::__export;\n"s; + mCppDecl->AddImportedModule(s); + } + } else { + if (auto n = x->GetBefore()) { + std::string v = mEmitter->EmitTreeNode(n); + if (auto a = x->GetAfter()) { + std::string after = mEmitter->EmitTreeNode(a); + if (node->GetTarget()) { + v = "::__export::"s + (v == "default" ? "__"s + v : v); + if (node->IsImportType()) + mImports += "using "s + after + " = "s + module + v + ";\n"s; + else if (a->GetTypeId() == TY_Module || a->GetTypeId() == TY_Namespace) + mImports += "namespace "s + after + " = "s + module + v + ";\n"s; + else + mImports += "inline const decltype("s + module + v + ") &"s + after + + " = "s + module + v + ";\n"s; + } else { + mEmitter->Replace(v, ".", "::"); + mImports += "inline const decltype("s + v + ") &"s + after + " = "s + v + ";\n"s; + } + if (mExFlag) + mExports += "namespace __export { using "s + mCppDecl->GetModuleName() + "::"s + after + "; }\n"s; + } else { + auto u = module + "::__export::"s + v; + if (node->IsImportType()) + mImports += "using "s + v + " = "s + u + ";\n"s; + else + mImports += "inline const decltype("s + u + ") &"s + v + " = "s + u + ";\n"s; + } + } + } + } + } + return node; + } + + ExportNode *VisitExportNode(ExportNode *node) { + if (mCppDecl->IsInNamespace(node)) + return node; + // 'export *' does not re-export a default, it re-exports only named exports + // Multiple 'export *'s fails with tsc if they export multiple exports with same name + std::string filename = AddIncludes(node->GetTarget()); + std::string module = mCppDecl->GetModuleName(filename.c_str()); + for (unsigned i = 0; i < node->GetPairsNum(); ++i) { + if (auto x = node->GetPair(i)) { + mExports += Comment(node); + if (x->IsDefault()) { + if (x->IsRef()) { + auto b = x->GetBefore(); + std::string target = mCppDecl->GetIdentifierName(b); + bool emit = true; + if (target == "default" RENAMINGSUFFIX) { + target = module + "::__export::__default"; + mExports += "namespace __export { inline const decltype("s + target + ") &"s + + "__"s + "default" + " = "s + target + "; }\n"s; + emit = false; + } + if (emit) { + mExports += "namespace __export { inline const decltype("s + target + ") &__default = "s + target + "; }\n"s; + emit = false; + } + if (emit) + mExports += "namespace __export { using "s + module + "::"s + "default" RENAMINGSUFFIX "; }\n"s; + } else { + if (auto n = x->GetBefore()) { + std::string v = mEmitter->EmitTreeNode(n); + mExports += "namespace __export { inline decltype("s + v + ") __default; }\n"s; + } + } + } else if (x->IsSingle()) { + std::string str; + if (auto a = x->GetAfter()) + mExports += "TODO: " + mEmitter->EmitTreeNode(a) + '\n'; + else if (auto b = x->GetBefore()) { + std::string s = mEmitter->EmitTreeNode(b); + if (b->GetTypeId() == TY_Class) + mExports += "namespace __export { using __default = "s + module + "::"s + s + "; }\n"s; + else if (b->GetTypeId() == TY_Namespace) + mExports += "namespace __export { namespace __default = "s + module + "::"s + s + "; }\n"s; + else + mExports += "namespace __export { inline const decltype("s + module + "::"s + s + ") &__default = "s + + module + "::"s + s + "; }\n"s; + } + } else if (x->IsEverything()) { + if (auto b = x->GetBefore()) + mExports += "namespace __export { namespace "s + mCppDecl->GetIdentifierName(b) + + " = " + module + "::__export; }\n"s; + else + mExports += "namespace __export { using namespace "s + module + "::__export; }\n"s; + } else if (x->GetAsNamespace()) { + if (auto b = x->GetBefore()) + mExports += "namespace __export { namespace "s + mCppDecl->GetIdentifierName(b) + + " = " + module + "; }\n"s; + } else { + if (auto b = x->GetBefore()) { + if (b->IsDeclare()) { + DeclareNode *decl = static_cast(b); + if (decl->GetDeclsNum() == 1) + b = decl->GetDeclAtIndex(0); + } + if (b->IsImport()) { + mExFlag = true; + VisitImportNode(static_cast(b)); + mExFlag = false; + continue; + } + std::string target = mCppDecl->GetIdentifierName(b); + bool emit = true; + if (auto a = x->GetAfter()) { + std::string after = mCppDecl->GetIdentifierName(a); + if (target == "default" RENAMINGSUFFIX) { + target = module + "::__export::__default"; + mExports += "namespace __export { inline const decltype("s + target + ") &"s + + (after == "default" RENAMINGSUFFIX ? "__"s + after : after) + " = "s + target + "; }\n"s; + emit = false; + } + else if (target != after) { + auto t = a->GetTypeId(); + if (t == TY_Namespace) + mExports += "namespace __export { namespace "s + after + " = "s + module + "::"s + target + "; }\n"s; + else if (t == TY_Function) + mExports += "namespace __export { inline const decltype("s + target + ") &"s + after + " = "s + + module + "::"s + target + "; }\n"s; + else + mExports += "namespace __export { using "s + after + " = "s + module + "::"s + target + "; }\n"s; + emit = false; + } + } + if (emit) + if (b->IsNamespace()) + mExports += "namespace __export { namespace "s + target + " = "s + module + "::"s + target + "; }\n"s; + else + mExports += "namespace __export { using "s + module + "::"s + target + "; }\n"s; + } + } + } + } + return node; + } +}; + +class ClassDecls : public AstVisitor { + private: + CppDecl *mCppDecl; + std::string mDecls; + + public: + ClassDecls(CppDecl *c) : mCppDecl(c), mDecls("// class decls\n") {} + + ClassNode *VisitClassNode(ClassNode *node) { + std::string ns = mCppDecl->GetNamespace(node); + if (ns.empty()) + mDecls += mCppDecl->EmitTreeNode(node) + ";\n"s; + else + mDecls += "namespace "s + ns + " {\n"s + mCppDecl->EmitTreeNode(node) + ";\n}\n"s; + return node; + } + + StructNode *VisitStructNode(StructNode *node) { + std::string ns = mCppDecl->GetNamespace(node); + if (ns.empty()) + mDecls += mCppDecl->EmitStructNode(node); + else + mDecls += "namespace "s + ns + " {\n"s + mCppDecl->EmitTreeNode(node) + "}\n"s; + return node; + } + + TypeAliasNode *VisitTypeAliasNode(TypeAliasNode* node) { + std::string ns = mCppDecl->GetNamespace(node); + if (ns.empty()) + mDecls += mCppDecl->EmitTypeAliasNode(node); + else + mDecls += "namespace "s + ns + " {\n"s + mCppDecl->EmitTypeAliasNode(node) + "}\n"s; + return node; + } + + std::string GetDecls() { return mDecls; } +}; + +class CollectDecls : public AstVisitor { + private: + CppDecl *mCppDecl; + std::string mDecls; + + public: + CollectDecls(CppDecl *c) : mCppDecl(c), mDecls("// var decls\n") {} + + FunctionNode *VisitFunctionNode(FunctionNode *node) { + return node; + } + + LambdaNode *VisitLambdaNode(LambdaNode *node) { + return node; + } + + DeclNode *VisitDeclNode(DeclNode *node) { + std::string def = mCppDecl->EmitTreeNode(node); + std::string var = mCppDecl->EmitTreeNode(node->GetVar()); + std::string ns = mCppDecl->GetNamespace(node); + std::string ext = "extern "s + def.substr(0, def.find('=')) + ";\n"s; + if (ns.empty()) + mDecls += ext; + else { + mDecls += "namespace "s + ns + " {\n"s + ext + "}\n"s; + def = "namespace "s + ns + " {\n"s + def + ";\n}\n"s; + } + mCppDecl->AddDefinition(def + ";\n"s); + return node; + } + + std::string GetDecls() { return mDecls; } +}; + +void CppDecl::AddImportedModule(const std::string& module) { + mImportedModules.insert(module); +} + +bool CppDecl::IsImportedModule(const std::string& module) { + auto res = mImportedModules.find(module); + return res != mImportedModules.end(); +} + +void CppDecl::CollectFuncArgInfo(TreeNode* node) { + if (!node->IsFunction()) + return; + + FunctionNode* func = static_cast(node); + for (unsigned i = 0; i < func->GetParamsNum(); ++i) { + if (auto n = func->GetParam(i)) { + // build vector of string pairs of argument types and names + std::string name = GetIdentifierName(n); + std::string type = GetTypeString(n, n->IsIdentifier()? static_cast(n)->GetType(): nullptr); + type.erase(type.find_last_not_of(' ')+1); // strip trailing spaces + hFuncTable.AddArgInfo(func->GetNodeId(), type, name); + } + } +} + +std::string CppDecl::EmitModuleNode(ModuleNode *node) { + if (node == nullptr) + return std::string(); + std::string module = GetModuleName(); + std::string header("__"); + for(auto &c : module) + header += std::toupper(c); + header += "__HEADER__\n"; + std::string str("// TypeScript filename: "s + node->GetFilename() + "\n"s); + str += "#ifndef "s + header + "#define "s + header; + str += R"""( +#include "ts2cpp.h" +)"""; + + ImportExportModules xxportModules(this); + xxportModules.Visit(node); + // All include directived from import/export statements + str += xxportModules.GetIncludes(); + + // Generate the namespace of current module + str += R"""( +namespace )""" + module + R"""( { +)"""; + + // Generate code for all imports + str += xxportModules.GetImports(); + + ClassDecls clsDecls(this); + clsDecls.VisitTreeNode(node); + // declarations of user defined classes + str += clsDecls.GetDecls(); + + // declarations of all top level functions + CfgFunc *mod = mHandler->GetCfgFunc(); + auto num = mod->GetNestedFuncsNum(); + for(unsigned i = 0; i < num; ++i) { + CfgFunc *func = mod->GetNestedFuncAtIndex(i); + TreeNode *node = func->GetFuncNode(); + std::string funcName = GetIdentifierName(node); + + CollectFuncArgInfo(node); + if (!IsClassMethod(node)) { + std::string ns = GetNamespace(node); + if (!ns.empty()) + str += "namespace "s + ns + " {\n"s; + bool isGenerator = static_cast(node)->IsGenerator(); + std::string generatorClassDef; + if (isGenerator) { + str += GeneratorClassDecl(funcName, node->GetNodeId()); + generatorClassDef = GeneratorClassDef(ns, funcName, node->GetNodeId()); + AddDefinition(generatorClassDef); + } + else { + // gen function class for each top level function + str += FunctionClassDecl(GetTypeString(static_cast(node)->GetRetType(), nullptr), GetIdentifierName(node), node->GetNodeId()); + } + if (!mHandler->IsFromLambda(node)) { + // top level funcs instantiated here as function objects from their func class + // top level lamda funcs instantiated later in assignment stmts + std::string typeName = isGenerator? GeneratorFuncName(funcName): ClsName(funcName); + std::string funcinit = typeName + "* "s + funcName + " = new "s + typeName + "();\n"s; + if (ns.empty()) + AddDefinition(funcinit); + else + AddDefinition("namespace "s + ns + " {\n"s + funcinit + "\n}\n"s); + str += "extern "s + typeName + "* "s + funcName + ";\n"s; + } + if (!ns.empty()) + str += "\n} // namespace " + ns + '\n'; + } + } + + CollectDecls decls(this); + decls.VisitTreeNode(node); + // declarations of all variables + str += decls.GetDecls(); + + // Generate code for all exports + str += xxportModules.GetExports() + "\nnamespace __export {}\n"s; + + // init function and an object for dynamic properties + str += R"""( + // init function for current module + void __init_func__(); + + // all dynamic properties of current module + extern t2crt::Object __module; + +} // namespace of current module + +#endif +)"""; + return str; +} + +std::string CppDecl::EmitFunctionNode(FunctionNode *node) { + if (node == nullptr) + return std::string(); + std::string str(GetTypeString(node->GetRetType(), node->GetRetType())); + if(node->GetStrIdx()) + str += " "s + node->GetName(); + str += "("s; + for (unsigned i = 0; i < node->GetParamsNum(); ++i) { + if (i) + str += ", "s; + if (auto n = node->GetParam(i)) { + str += EmitTreeNode(n); + } + } + str += ");\n"s; + + if (HasAttrStatic(node)) + str = "static "s + str; + return str; +} + +std::string CppDecl::EmitBinOperatorNode(BinOperatorNode *node) { + const char *op = Emitter::GetEnumOprId(node->GetOprId()); + const Precedence precd = *op & 0x3f; + const bool rl_assoc = *op >> 6; // false: left-to-right, true: right-to-left + std::string lhs, rhs; + if (auto n = node->GetOpndA()) { + lhs = EmitTreeNode(n); + if(precd > mPrecedence || (precd == mPrecedence && rl_assoc)) + lhs = "("s + lhs + ")"s; + } + else + lhs = "(NIL) "s; + if (auto n = node->GetOpndB()) { + rhs = EmitTreeNode(n); + if(precd > mPrecedence || (precd == mPrecedence && !rl_assoc)) + rhs = "("s + rhs + ")"s; + } + else + rhs = " (NIL)"s; + OprId k = node->GetOprId(); + std::string str; + if(k == OPR_Exp) { + str = "std::pow("s + lhs + ", "s + rhs + ")"; + } else { + switch(k) { + case OPR_Band: + case OPR_Bor: + case OPR_Bxor: + case OPR_Shl: + case OPR_Shr: + lhs = "static_cast("s + lhs + ")"s; + break; + case OPR_Zext: + lhs = "static_cast("s + lhs + ")"s; + op = "\015>>"; + break; + } + str = lhs + " "s + std::string(op + 1) + " "s + rhs; + } + mPrecedence = precd; + if (node->IsStmt()) + str += ";\n"s; + return str; + +} + +std::string CppDecl::EmitIdentifierNode(IdentifierNode *node) { + if (node == nullptr) + return std::string(); + std::string str(GetTypeString(node, node->GetType())); + str += " "s + node->GetName(); + + if (HasAttrStatic(node)) + str = "static "s + str; + else if (auto n = node->GetInit()) { + // emit init for non static class field + if (node->GetParent() && node->GetParent()->IsClass()) + str += " = "s + EmitTreeNode(n); + } + return str; +} + +std::string CppDecl::EmitPrimTypeNode(PrimTypeNode *node) { + if (node == nullptr) + return std::string(); + return GetTypeString(node); +} + +std::string CppDecl::EmitDeclNode(DeclNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetVar()) { + str += " "s + EmitTreeNode(n); + } + return str; +} + +std::string CppDecl::EmitCallNode(CallNode *node) { + return std::string(); +} + +std::string CppDecl::EmitCondBranchNode(CondBranchNode *node) { + return std::string(); +} + +std::string CppDecl::EmitForLoopNode(ForLoopNode *node) { + + return std::string(); +} + +std::string CppDecl::EmitWhileLoopNode(WhileLoopNode *node) { + return std::string(); +} + +std::string CppDecl::EmitDoLoopNode(DoLoopNode *node) { + return std::string(); +} + +std::string CppDecl::EmitAssertNode(AssertNode *node) { + return std::string(); +} + +// Generate code to construct an array of type any from an ArrayLiteral. TODO: merge with similar in cppdef +std::string CppDecl::ConstructArrayAny(ArrayLiteralNode *node) { + if (node == nullptr || !node->IsArrayLiteral()) + return std::string(); + + // Generate array ctor call to instantiate array + std::string literals; + for (unsigned i = 0; i < node->GetLiteralsNum(); ++i) { + if (i) + literals += ", "s; + if (auto n = node->GetLiteral(i)) { + if (n->IsArrayLiteral()) + // Recurse to handle array elements that are arrays + literals += ConstructArrayAny(static_cast(n)); + else { + // Wrap element in JS_Val. C++ class constructor of JS_Val + // will set tupe tag in JS_Val according to element type. + literals += "t2crt::JS_Val("s + EmitTreeNode(n) + ")"s; + } + } + } + std::string str = ArrayCtorName(1, "t2crt::JS_Val") + "._new({"s + literals + "})"s; + return str; +} + +// Generate code to construct an array object with brace-enclosed initializer list TODO: merge with similar in cppdef +std::string CppDecl::ConstructArray(ArrayLiteralNode *node, int dim, std::string type) { + if (type.empty()) { + return ConstructArrayAny(node); // proceed as array of type any if no type info + } + // Generate array ctor call to instantiate array + std::string str = ArrayCtorName(dim, type) + "._new({"s; + for (unsigned i = 0; i < node->GetLiteralsNum(); ++i) { + if (i) + str += ", "s; + if (auto n = node->GetLiteral(i)) { + if (n->IsArrayLiteral()) + str += ConstructArray(static_cast(n), dim-1, type); + else + str += EmitTreeNode(n); + } + } + str += "})"s; + return str; +} + +std::string CppDecl::EmitArrayLiteralNode(ArrayLiteralNode *node) { // TODO: merge with similar in cppdef + if (node == nullptr) + return std::string(); + if (node->GetParent() && + node->GetParent()->IsDecl() || // for var decl init + node->GetParent()->IsIdentifier() || // for default val init in class field decl + node->GetParent()->IsFieldLiteral()) { // for obj decl with struct literal init + // emit code to construct array object with brace-enclosed initializer list + int dim; + std::string str, type; + GetArrayTypeInfo(node, dim, type); + str = ConstructArray(node, dim, type); + return str; + } + + // emit code to build a brace-enclosed intializer list (for rhs of array var assignment op) + std::string str("{"s); + for (unsigned i = 0; i < node->GetLiteralsNum(); ++i) { + if (i) + str += ", "s; + if (auto n = node->GetLiteral(i)) { + str += EmitTreeNode(n); + } + } + str += "}"s; + return str; +} + +std::string BuildArrayType(int dim, std::string typeStr) { + std::string str; + str = "t2crt::Array<"s + typeStr + ">*"s;; + for (unsigned i = 1; i < dim; ++i) { + str = "t2crt::Array<"s + str + ">*"s;; + } + return str; +} + +std::string CppDecl::EmitArrayTypeNode(ArrayTypeNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + + if (node->GetElemType() && node->GetDims()) { + str = BuildArrayType( + node->GetDims()->GetDimensionsNum(), + EmitTreeNode(node->GetElemType())); + } + return str; +} + +std::string CppDecl::EmitFieldNode(FieldNode *node) { + return std::string(); +} + +std::string CppDecl::GetTypeString(TreeNode *node, TreeNode *child) { + std::string str; + if (node) { + if (IsGenerator(node)) { // check generator type + if (auto func = GetGeneratorFunc(node)) + return GeneratorName(GetIdentifierName(func)) + "*"s; + } + TypeId k = node->GetTypeId(); + if (k == TY_None || k == TY_Class) { + switch(node->GetKind()) { + case NK_PrimType: + k = static_cast(node)->GetPrimType(); + break; + case NK_Identifier: + case NK_Function: + if (child && child->IsUserType()) + return EmitTreeNode(child); + break; + case NK_UserType: + return EmitTreeNode(node); + } + } + switch(k) { + case TY_Object: + return "t2crt::Object* "s; + case TY_Function: // Need to handle class constructor type: Ctor_* + { + std::string funcName = GetClassOfAssignedFunc(node); + if (!funcName.empty()) + return funcName + "* "; + else + return "t2crt::Function* "s; + } + case TY_Boolean: + return "bool "s; + case TY_Int: + return "long "s; + case TY_String: + return "std::string "s; + case TY_Number: + case TY_Double: + return "double "s; + case TY_Class: + return "t2crt::Object* "s; + case TY_Any: + return "t2crt::JS_Val "s; + } + { + if (child && child->IsStruct() && static_cast(child)->GetProp() == SProp_NA) { + // This will change pending solution for issue #69. + return "t2crt::Object * "s; // object literal type - dynamic-import.ts + } + str = child ? EmitTreeNode(child) : (k == TY_Array ? "t2crt::Array* "s : Emitter::GetEnumTypeId(k)); + if (str != "none"s) + return str + " "s; + } + } + return "t2crt::JS_Val "s; +} + +std::string CppDecl::EmitUserTypeNode(UserTypeNode *node) { + if (node == nullptr) + return std::string(); + { + auto k = node->GetType(); + if(k == UT_Union || k == UT_Inter) + // Generate both vars and arrays of union/intersect type as t2crt::JS_Val of type TY_Object. + return "t2crt::JS_Val"s; + } + std::string str, usrType; + + if (auto n = node->GetId()) { + if (n->IsTypeIdClass()) { + if (mHandler->IsGeneratorUsed(n->GetNodeId())) { + // Check if a generator type : TODO: this needs TI + auto func = mHandler->GetGeneratorUsed(n->GetNodeId()); + usrType = GetIdentifierName(func) + "*"s; + } else + usrType = n->GetName() + "*"s; + } + else if (IsBuiltinObj(n->GetName())) + usrType = "t2crt::"s + n->GetName() + "*"s; + else // TypeAlias Id gets returned here + usrType = n->GetName(); + + str = usrType; // note: array dimension now come from ArrayTypeNode + auto num = node->GetTypeGenericsNum(); + if(num) { + std::string lastChar = ""; + if (str.back() == '*') { + str.pop_back(); + lastChar = "*"; + } + str += "<"s; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetTypeGeneric(i)) { + str += EmitTreeNode(n); + } + } + str += ">"s; + str += lastChar; + } + } +#if 0 + auto k = node->GetType(); + if(k != UT_Regular) { + if(!str.empty()) + str = "using "s + str + " = "s; + std::string op = k == UT_Union ? " | "s : " & "s; + for (unsigned i = 0; i < node->GetUnionInterTypesNum(); ++i) { + if(i) + str += op; + str += EmitTreeNode(node->GetUnionInterType(i)); + } + } +#endif + return str; +} + +std::string CppDecl::EmitClassNode(ClassNode *node) { + std::string str; + std::string base; + std::string staticProps; + + if (node == nullptr) + return std::string(); + + std::string clsName = node->GetName(); + // 1. c++ class for JS object + base = (node->GetSuperClassesNum() != 0)? node->GetSuperClass(0)->GetName() : "t2crt::Object"; + str += "class "s + clsName + " : public "s + base + " {\n"s; + + str += "public:\n"; + + // constructor decl + str += " "s + clsName + "(t2crt::Function* ctor, t2crt::Object* proto);\n"s; + str += " ~"s + clsName + "(){}\n"; + + // class field decl and init. TODO: handle private, protected attrs. + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + auto n = node->GetField(i); + str += " "s + EmitTreeNode(n); + + if (n->IsIdentifier()) { + if (HasAttrStatic(static_cast(n))) { + // static field - add field to ctor prop and init later at field def in cpp + staticProps += tab(3) + "this->AddProp(\""s + clsName + "\", t2crt::JS_Val("s + + TypeIdToJSTypeCXX[n->GetTypeId()] + ", &"s + clsName + "::"s + GetIdentifierName(n) + "));\n"s; + } + } + str += ";\n"; + } + for (unsigned i = 0; i < node->GetMethodsNum(); ++i) { + str += tab(1) + EmitFunctionNode(node->GetMethod(i)); + } + + // 2. c++ class for the JS object's JS constructor + std::string indent = tab(1); + if (!staticProps.empty()) staticProps = "\n"s + staticProps; + base = (node->GetSuperClassesNum() != 0)? (node->GetSuperClass(0)->GetName()+"::Ctor"s) : "t2crt::Function"; + str += indent + "class Ctor : public "s + base + " {\n"s; + str += indent + "public:\n"; + str += indent + " Ctor(t2crt::Function* ctor, t2crt::Object* proto, t2crt::Object* prototype_proto) : "s + + base + "(ctor, proto, prototype_proto) {"s + staticProps + tab(2) + "}\n"s; + + // constructor function + for (unsigned i = 0; i < node->GetConstructorsNum(); ++i) { + std::string ctor; + if (auto c = node->GetConstructor(i)) { + ctor = indent + " "s + clsName + "* operator()("s + clsName + "* obj"s; + for (unsigned k = 0; k < c->GetParamsNum(); ++k) { + ctor += ", "s; + if (auto n = c->GetParam(k)) { + ctor += EmitTreeNode(n); + } + } + ctor += ");\n"; + str += ctor; + } + } + + // Generate decl for default constructor function if none declared for class + if (node->GetConstructorsNum() == 0) + str += indent + " "s + clsName + "* operator()("s + clsName + "* obj);\n"s; + + // Generate new() function + str += indent + " "s+clsName+"* _new() {return new "s+clsName+"(this, this->prototype);}\n"s; + str += indent + " virtual const char* __GetClassName() const {return \""s + clsName + " \";}\n"s; + str += indent + "};\n"; + str += indent + "static Ctor ctor;\n"s; + str += "};\n"; + return str; +} + +std::string CppDecl::EmitNewNode(NewNode *node) { + if (node == nullptr || node->GetAttrsNum() > 0) + return std::string(); + + std::string str; + MASSERT(node->GetId() && "No mId on NewNode"); + if (node->GetId() && node->GetId()->IsTypeIdClass()) { + // Generate code to create new obj and call constructor + str = node->GetId()->GetName() + "::ctor("s + node->GetId()->GetName() + "::ctor._new("s; + } else if (IsBuiltinObj(node->GetId()->GetName())) { + // Check for builtin obejcts: t2crt::Object, t2crt::Function, etc. + str = node->GetId()->GetName() + "::ctor._new("s; + } else { + str = "new "s + EmitTreeNode(node->GetId()); + str += "("s; + } + + auto num = node->GetArgsNum(); + for (unsigned i = 0; i < num; ++i) { + if (i || node->GetId()->IsTypeIdClass()) + str += ", "s; + if (auto n = node->GetArg(i)) { + str += EmitTreeNode(n); + } + } + str += ")"s; + mPrecedence = '\024'; + return str; +} + +std::string CppDecl::EmitInterface(StructNode *node) { + std::string str, ifName; + std::string def; + + if (node == nullptr) + return std::string(); + + std::string superClass = "t2crt::Object"; + if (node->GetSupersNum() > 0) { + auto n = node->GetSuper(0); + superClass = EmitTreeNode(n); + if (superClass.back() == '*') + superClass.pop_back(); + } + ifName = GetIdentifierName(node); + str = "class "s + ifName + " : public "s + superClass + " {\n"s; + str += " public:\n"s; + + // Generate code to add prop in class constructor + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (auto n = node->GetField(i)) { + str += " "s + EmitTreeNode(n) + ";\n"s; + if (n->IsIdentifier()) { + def += tab(1) + GenClassFldAddProp("this", ifName, n->GetName(), + GetTypeString(n, static_cast(n)->GetType()), + TypeIdToJSTypeCXX[hlpGetTypeId(n)]) + ";\n"s; + } + } + } + if (!def.empty()) + def = "\n"+def; + + str += " "s + ifName + "() {};\n"s; + str += " ~"s + ifName + "() {};\n"s; + str += " "s + ifName + "(t2crt::Function* ctor, t2crt::Object* proto);\n"s; + str += " "s + ifName + "(t2crt::Function* ctor, t2crt::Object* proto, std::vector props): "s + superClass + "(ctor, proto, props) {}\n"s; + str += "};\n"s; + + def = ifName + "::"s + ifName + "(t2crt::Function* ctor, t2crt::Object* proto): "s + superClass + "(ctor, proto) {" + def + "}\n"; + AddDefinition(def); + return str; +} + +// Generate C++ class def for the TS num type here and instance in CppDef EmitStructNode. +// TS enum member field can be either Identifier or Literal string (of any character). +// TS enum member value can be either long, double, or string. +// Numeric enum member with no assigned value default to val of preceding member plus 1. +std::string CppDecl::EmitTSEnum(StructNode *node) { + std::string str, init; + TypeId memberValType = TY_None; + + if (node == nullptr) + return std::string(); + + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + // Enum member field default to TY_Int if not specified - should this be set by FE? + if (node->GetField(i)->IsTypeIdNone()) + node->GetField(i)->SetTypeId(TY_Int); + } + + if (node->GetFieldsNum() > 0) { + memberValType = node->GetField(0)->GetTypeId(); + MASSERT(memberValType == TY_String || + memberValType == TY_Double || + memberValType == TY_Int && "Unsupported Enum type"); + } + + str = "class "s; + std::string enumClsName, enumName; + if (auto n = node->GetStructId()) { + enumName = GetIdentifierName(n); + enumClsName = "Enum_"s + enumName; + str += enumClsName + " : public t2crt::Object {\n"s; + } + str += " public:\n"s; + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (auto n = node->GetField(i)) { + if (n->IsLiteral()) { + MWARNING("Literal enum field not supported yet"); + continue; + } + IdentifierNode* id = static_cast(n); + if (id->GetInit()) { + init = EmitTreeNode(id->GetInit()); + } else { + if (memberValType == TY_Int || memberValType == TY_Double) { + // if numeric member and no initialzer, set to 0 or last field + 1 + if (i == 0) + init = "0"; + else + init = GetIdentifierName(node->GetField(i-1)) + "+1"s; + } + } + str += " const "s + EmitTreeNode(n) + " = "s + init + ";\n"s; + } + } + str += " "s + enumClsName + "() {};\n"s; + str += " ~"s + enumClsName + "() {};\n"s; + + std::string def = enumClsName + "* "s + enumName + ";\n"s; + AddDefinition(def); + str += "};\nextern "s + def; + return str; +} + +std::string CppDecl::EmitStructNode(StructNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + const char *suffix = ";\n"; + switch(node->GetProp()) { +#if 0 + case SProp_CStruct: + str = "struct "s; + break; + case SProp_NA: + str = ""s; + break; +#endif + case SProp_TSEnum: + str = EmitTSEnum(node); + return str; + case SProp_TSInterface: + case SProp_NA: // for classes generated by TI + str = EmitInterface(node); + return str; + default: + return std::string(); + MASSERT(0 && "Unexpected enumerator"); + } +#if 0 + if (auto n = node->GetStructId()) { + str += EmitIdentifierNode(n); + } + + auto num = node->GetTypeParamsNum(); + if(num) { + str += "<"s; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetTypeParamAtIndex(i)) + str += EmitTreeNode(n); + } + str += ">"s; + } + + for (unsigned i = 0; i < node->GetSupersNum(); ++i) { + str += i ? ", "s : " extends "s; + if (auto n = node->GetSuper(i)) + str += EmitTreeNode(n); + } + str += " {\n"s; + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (auto n = node->GetField(i)) { + str += EmitTreeNode(n) + suffix; + } + } + + if (auto n = node->GetNumIndexSig()) + str += EmitNumIndexSigNode(n) + "\n"s;; + } + if (auto n = node->GetStrIndexSig()) { + str += EmitStrIndexSigNode(n) + "\n"; + } + + for (unsigned i = 0; i < node->GetMethodsNum(); ++i) { + if (auto n = node->GetMethod(i)) { + std::string func = EmitFunctionNode(n); + if (func.substr(0, 9) == "function ") + func = func.substr(9); + size_t index = func.rfind(')'); + if (index != std::string::npos) { + std::string t = func.substr(index); + Replace(t, "=>", ":"); + func = func.substr(0, index) + t; + } + str += func.length() > 2 && func.substr(func.length() - 2) == ";\n" ? func : func + ";\n"s; + } + } + str += "}\n"s; +#endif + return HandleTreeNode(str, node); +} + +std::string CppDecl::EmitNumIndexSigNode(NumIndexSigNode *node) { + return std::string(); +} + +std::string CppDecl::EmitStrIndexSigNode(StrIndexSigNode *node) { + return std::string(); +} + +std::string CppDecl::EmitTypeAliasNode(TypeAliasNode* node) { + if (node == nullptr) + return std::string(); + std::string str, alias; + + if (auto n = node->GetId()) { + if (n->IsUserType()) { + str = EmitTreeNode(n); + if (str.back() == '*') + str.pop_back(); + } + } + if (auto m = node->GetAlias()) { + if (m->IsUserType()) { + alias = EmitTreeNode(m); + if (alias.back() == '*') + alias.pop_back(); + str = "using "s + str + " = "s + alias + ";\n"; + } else { // if (m->IsStruct()) { + // todo + str = "// type alias for "s + str + '\n';; + } + } + return str; +} + +std::string CppDecl::EmitLiteralNode(LiteralNode *node) { + if (node == nullptr) + return std::string(); + LitData lit = node->GetData(); + std::string str(AstDump::GetEnumLitData(lit)); + if(lit.mType == LT_StringLiteral || lit.mType == LT_CharacterLiteral) + str = '"' + str + '"'; + mPrecedence = '\030'; + str = HandleTreeNode(str, node); + if (auto n = node->GetType()) { + str += ": "s + EmitTreeNode(n); + } + if (auto n = node->GetInit()) { + str += " = "s + EmitTreeNode(n); + } + return str; +} + +} // namespace maplefe diff --git a/src/MapleFE/ast2cpp/src/cpp_definition.cpp b/src/MapleFE/ast2cpp/src/cpp_definition.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6b1935446c577ae09fecea01366394615c1d2df --- /dev/null +++ b/src/MapleFE/ast2cpp/src/cpp_definition.cpp @@ -0,0 +1,1584 @@ +/* + * Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. + * + * OpenArkFE is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "cpp_definition.h" +#include "helper.h" + +namespace maplefe { + +std::string CppDef::EmitCtorInstance(ClassNode *c) { + std::string str, thisClass, ctor, proto, prototypeProto; + ctor = "&t2crt::Function::ctor"; + thisClass = c->GetName(); + if (c->GetSuperClassesNum() == 0) { + proto = "t2crt::Function::ctor.prototype"; + prototypeProto = "t2crt::Object::ctor.prototype"; + } else { + proto = c->GetSuperClass(0)->GetName() + "::ctor"s; + prototypeProto = proto + ".prototype"s; + proto.insert(0, "&"s, 0, std::string::npos); + } + str = "\n// Init class ctor as a static class field for "+ thisClass+ "\n"s; + str += thisClass + "::Ctor "s + thisClass+"::ctor("s +ctor+","s+proto+","+prototypeProto+");\n\n"s; + + // piggy back generation of static field definition + for (unsigned i = 0; i < c->GetFieldsNum(); ++i) { + auto n = c->GetField(i); + if (n->IsIdentifier() && + HasAttrStatic(static_cast(n))) { + str += mCppDecl.GetTypeString(n, n) + " "s + thisClass + "::"s + EmitTreeNode(n); + str += ";\n"; + } + } + + return str; +} + +// Emit default constructor func def and instance +std::string CppDef::EmitDefaultCtor(ClassNode *c) { + if (c == nullptr) + return std::string(); + + std::string str, className; + className = c->GetName(); + str = "\n"s; + str += className + "* "s + className + "::Ctor::operator()("s + className + "* obj)"s; + str += "{ return obj; }\n"s; + str += EmitCtorInstance(c); + + return str; +} + +std::string CppDef::EmitCppCtor(ClassNode* node) { + std::string str, base, props; + props = EmitClassProps(node); + if (!props.empty()) + props = "\n"s + props; + base = (node->GetSuperClassesNum() != 0)? node->GetSuperClass(0)->GetName() : "t2crt::Object"; + str += node->GetName() + "::"s + node->GetName() + "(t2crt::Function* ctor, t2crt::Object* proto): "s + + base + "(ctor, proto)" + " {"s + props +"}\n"s; + return str; +} + +std::string CppDef::EmitModuleNode(ModuleNode *node) { + if (node == nullptr) + return std::string(); + std::string module = GetModuleName(); + + // include directives + std::string str("// TypeScript filename: "s + node->GetFilename() + "\n"s); + str += "#include \n#include \""s + GetBaseFilename() + ".h\"\n\n"s; + + // start a namespace for this module + str += "namespace "s + module + " {\n"s; + + // definitions of default class constructors + for (unsigned i = 0; i < node->GetTreesNum(); ++i) { + if (auto n = node->GetTree(i)) + if (n->IsClass()) { + str += EmitCppCtor(static_cast(n)); + if (static_cast(n)->GetConstructorsNum() == 0) + str += EmitDefaultCtor(static_cast(n)); + } + } + + // definitions + str += mCppDecl.GetDefinitions(); + + // definitions of all top level functions in current module + CfgFunc *mod = mHandler->GetCfgFunc(); + auto num = mod->GetNestedFuncsNum(); + for(unsigned i = 0; i < num; ++i) { + CfgFunc *func = mod->GetNestedFuncAtIndex(i); + TreeNode *node = func->GetFuncNode(); + if (!IsClassMethod(node)) { + hFuncTable.AddTopLevelFunc(node); + hFuncTable.AddNameIsTopLevelFunc(GetIdentifierName(node)); + } + std::string s = EmitTreeNode(node) + GetEnding(node); + str += s; + } + + // definition of init function of current module + str += R"""(void __init_func__() { + // bind "this" to current module + static bool __init_once = false; + if (__init_once) return; + __init_once = true; +)""" + mCppDecl.GetInits(); + mIsInit = true; + for (unsigned i = 0; i < node->GetTreesNum(); ++i) { + if (auto n = node->GetTree(i)) { + if (!n->IsClass()) { + std::string s = EmitTreeNode(n); + if (!s.empty()) + str += tab(1) + s + (s.back()=='\n'? "": ";\n"); + } + } + } + str += R"""(} + + t2crt::Object __module; +} // namespace of current module +)"""; + + AST_Handler *handler = mHandler->GetASTHandler(); + HandlerIndex idx = handler->GetHandlerIndex(node->GetFilename()); + // If the program starts from this module, generate the main function + if (idx == 0) { + str += R"""( +int main(int argc, char **argv) { + std::cout << std::boolalpha; +)""" + " "s + module + R"""(::__init_func__(); // call its __init_func__() + return 0; +} +)"""; + } + return str; +} + +std::string CppDef::EmitExportNode(ExportNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + auto num = node->GetPairsNum(); + for (unsigned i = 0; i < node->GetPairsNum(); ++i) { + if (auto x = node->GetPair(i)) { + if (x->IsDefault() && !x->IsRef()) { + if (auto n = x->GetBefore()) { + std::string v = EmitTreeNode(n); + str += "__export::__default = "s + v + ";\n"s; + } + } + if(node->GetTarget() == nullptr && + !x->IsDefault() && + !x->IsEverything() && + !x->GetAsNamespace() && + !x->IsSingle()) { + //str += EmitXXportAsPairNode(x); + if (auto n = x->GetBefore()) + if ((!n->IsIdentifier() || static_cast(n)->GetInit() != nullptr) && + !n->IsStruct() && + !n->IsClass() && + !n->IsUserType()) + str += EmitTreeNode(n); + } + } + } + return HandleTreeNode(str, node); +} + +std::string CppDef::EmitImportNode(ImportNode *node) { + return std::string(); +} + +std::string CppDef::EmitXXportAsPairNode(XXportAsPairNode *node) { + return std::string(); +} + +inline bool IsClassMethod(FunctionNode* f) { + return (f && f->GetParent() && f->GetParent()->IsClass()); +} + +std::string CppDef::EmitClassProps(TreeNode* node) { + std::string clsFd, addProp; + MASSERT(node->IsClass() && "Not NK_Class node"); + ClassNode* c = static_cast(node); + for (unsigned i = 0; i < c->GetFieldsNum(); ++i) { + auto node = c->GetField(i); + if (!node->IsIdentifier()) + // StrIndexSig, NumIndexSig, ComputedName have to be handled at run time + continue; + IdentifierNode* id = static_cast(node); + if (HasAttrStatic(id)) // static props are added to class ctor + continue; + std::string fdName = node->GetName(); + std::string fdType = mCppDecl.GetTypeString(node, id->GetType()); + TypeId typeId = node->GetTypeId(); + if (typeId == TY_None) { + if (auto n = id->GetType()) { + if (n->IsPrimType()) + typeId = static_cast(n)->GetPrimType(); + else if (n->IsUserType()) + typeId = static_cast(n)->GetTypeId(); + } + } + addProp += " "s + GenClassFldAddProp("this", c->GetName(), fdName, fdType, TypeIdToJSTypeCXX[typeId]) + ";\n"s; + } + return " // Add class fields to obj prop list\n"s + clsFd + addProp; +} + +// "var" declarations in TS/JS functions are function scope. +// Duplicate decls may appear in different blocks within +// function but should all refer to the same function scope var. +// +// So we scan for JS_Var decls with dup names in a function and emit +// a decl list with unique names for insert into function definition. +// +// The var may be initialized to different values in different +// blocks which will be done in the individual DeclNodes (re: var-dup.ts) +std::string CppDef::EmitFuncScopeVarDecls(FunctionNode *node) { + std::unordered_mapvarDeclsInScope; + ASTScope* s = node->GetScope(); + for (int i = 0; i < s->GetDeclNum(); i++) { + // build list of var decls (no dups) in function scope + TreeNode* n = s->GetDecl(i); + if (!n->IsDecl()) + continue; + DeclNode* d = static_cast(n); + if (d->GetProp() == JS_Var) { + // skip var decl name duplicates - same name but diff + // type is illegal in typescript so not checked here + std::unordered_map::iterator it; + it = varDeclsInScope.find(d->GetVar()->GetName()); + if (it == varDeclsInScope.end()) { + varDeclsInScope[d->GetVar()->GetName()] = d; + } + } + } + std::string str; + for (auto const&[key, val] : varDeclsInScope) { + // Emit decl for the var (just type and name). The init part + // to be emitted when corresponding DeclNode is processed + str += tab(1) + mCppDecl.EmitTreeNode(val->GetVar()) + ";\n"s; + } + return str; +} + +std::string CppDef::EmitYieldNode(YieldNode *node) { + if (node == nullptr) + return std::string(); + //std::string str(node->IsTransfer() ? "yield* " : "yield "); + std::string str, res; + if (auto n = node->GetResult()) + res = EmitTreeNode(n); + else + res = "undefined"; + + std::string yieldLabel = GenFnLabels.NextYieldLabel(); + str += " yield = &&" + yieldLabel + ";\n"; // save yp + str += " res.value = t2crt::JS_Val(" +res+ ");\n"; // init value and return + str += " res.done = false;\n"; + str += " return;\n"; + str += yieldLabel + ":\n"; // label for this yp + + mPrecedence = '\024'; + return str; +} + +std::string CppDef::EmitWhileLoopNode(WhileLoopNode *node) { +// return(Emitter::EmitWhileLoopNode(node)); + + if (node == nullptr) + return std::string(); + std::string str; + std::string loopLabel; + + if(auto n = node->GetLabel()) { + str = EmitTreeNode(n) + ":\n"s; + } + + if (mIsGenerator) { // insert label and loop cond check + loopLabel = GenFnLabels.NextLoopLabel(); + str += loopLabel + ":\n"; + if (auto n = node->GetCond()) { + std::string cond = EmitTreeNode(n); + str += " if (!(" +cond+ "))\n"; + str += " goto " +loopLabel+ "_exit;\n"; + } + } else { // normal while loop + str += "while("s; + if (auto n = node->GetCond()) { + str += EmitTreeNode(n); + } + str += ')'; + } + + if (auto n = node->GetBody()) { + str += EmitTreeNode(n) + GetEnding(n); + if (mIsGenerator) { + str.insert(str.find_first_of("{"), " "); + str.insert(str.find_last_of("}"), " "); + } + } + + if (mIsGenerator) { // insert loop back and label at loop exit + str += " goto " +loopLabel+ ";\n"; + str += loopLabel + "_exit:"; + } + + return HandleTreeNode(str, node); +} + + +std::string CppDef::EmitFunctionNode(FunctionNode *node) { + if (mIsInit || node == nullptr) + return std::string(); + + bool isTopLevel = hFuncTable.IsTopLevelFunc(node); + std::string str; + str += "\n"; + str += FunctionHeader(node, mCppDecl.GetTypeString(node->GetRetType(), node->GetRetType())); + mIsGenerator = node->IsGenerator(); + + int bodyPos = str.size(); + if (auto n = node->GetBody()) { + auto varDecls = EmitFuncScopeVarDecls(node); + auto s = EmitBlockNode(n); + if (isTopLevel) + Emitter::Replace(s, "this", "_this"); + if(s.empty() || s.front() != '{') + str += "{\n"s + s + "}\n"s; + else + str += s; + str.insert(bodyPos+2, varDecls); // skip over leading "{\n" of generated block + } else + str += "{}\n"s; + + if (mIsGenerator) { + str.insert(str.find_first_of("{")+1, GeneratorFn_start); + str.insert(str.find_last_of("}"), GeneratorFn_return); + } + + if (node->IsConstructor()) { + Emitter::Replace(str, "this->", "obj->", 0); + std::string ctorBody; + ctorBody += " return obj;\n"s; + str.insert(str.size()-2, ctorBody, 0, std::string::npos); + str += EmitCtorInstance(static_cast(node->GetParent())); + } + + if (mIsGenerator) { + mIsGenerator = false; + GenFnLabels.ResetLabels(); + } + return str; +} + +std::string CppDef::EmitIdentifierNode(IdentifierNode *node) { + if (node == nullptr) + return std::string(); + std::string str = GetQualifiedName(node); + if (auto n = node->GetInit()) { + str += " = "s + EmitTreeNode(n); + } + mPrecedence = '\030'; + return str; +} + +// Generate code to create object instance that was declared using +// an object literal. First process the object literals in the +// StructLiteralNode argument to build the proplist list (vector of +// type ObjectProp) to be used as initializer, then generate call to +// the builtin Object constructor with initializer as parameter. +std::string CppDef::EmitStructLiteralNode(StructLiteralNode* node) { + std::string str; + int stops = 2; + // Build proplist to be used as initializer + str += "\n"s + tab(stops) + "std::vector({\n"s; + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (i) + str += ",\n"s; + if (auto field = node->GetField(i)) { + auto lit = field->GetLiteral(); + std::string fieldName = EmitTreeNode(field->GetFieldName()); + TypeId typId = lit->GetTypeId(); + std::string fieldVal = EmitTreeNode(lit); + str += tab(stops+1); + switch(typId) { + case TY_Object: + break; + case TY_Function: + break; + case TY_Array: + fieldVal = EmitTreeNode(lit); // ArrayLiteralNode + str += "std::make_pair(\""s + fieldName + "\", t2crt::JS_Val("s + fieldVal + "))"s; + break; + case TY_Boolean: + str += "std::make_pair(\""s + fieldName + "\", t2crt::JS_Val(bool("s + fieldVal + ")))"s; + break; + case TY_None: + if (fieldVal.compare("true") == 0 || fieldVal.compare("false") == 0) + str += "std::make_pair(\""s + fieldName + "\", t2crt::JS_Val(bool("s + fieldVal + ")))"s; + else + // if no type info, use type any (JS_Val) + str += "std::make_pair(\""s + fieldName + "\", t2crt::JS_Val("s + fieldVal + "))"s; + break; + case TY_Int: + str += "std::make_pair(\""s + fieldName + "\", t2crt::JS_Val(int64_t("s + fieldVal + ")))"s; + break; + case TY_String: + str += "std::make_pair(\""s + fieldName + "\", t2crt::JS_Val("s + fieldVal + "))"s; + break; + case TY_Number: + case TY_Double: + str += "std::make_pair(\""s + fieldName + "\", t2crt::JS_Val(double("s + fieldVal + ")))"s; + break; + case TY_Class: + // Handle embedded t2crt::ObjectLiterals recursively + if (lit->IsStructLiteral()) { + std::string props = EmitStructLiteralNode(static_cast(lit)); + str += "std::make_pair(\""s + fieldName + "\", t2crt::JS_Val("s + props + "))"s; + } + break; + } + } + } + str += " })"s; + // Generate code to call builtin Object constructor with the initializer proplist. + str = "t2crt::Object::ctor._new("s + str + ")"s; + return str; +} + +std::string CppDef::GenDirectFieldInit(std::string varName, StructLiteralNode* node) { + std::string str; + //str += ";\n"s; + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (auto field = node->GetField(i)) { + auto lit = field->GetLiteral(); + std::string fieldName = EmitTreeNode(field->GetFieldName()); + std::string fieldVal = EmitTreeNode(lit); + if (mHandler->IsCppField(field)) // Check if it accesses a Cxx class field + str += tab(1) + varName + "->"s + fieldName + " = "s + fieldVal + ";\n"s; + else + str += tab(1) + "(*"s + varName + ")[\""s + fieldName + "\"] = "s + fieldVal + ";\n"s; + } + } + return str; +} + +std::string CppDef::GenObjectLiteral(TreeNode* var, std::string varName, TreeNode* varIdType, StructLiteralNode* node) { + if (varName.empty()) + return std::string(); + + std::string str; + // UserType can be TS interface, class, type alias, builtin (t2crt::Object, t2crt::Record..) + UserTypeNode* userType = (varIdType && varIdType->IsUserType())? (UserTypeNode*)varIdType: nullptr; + + if (userType == nullptr) { + // no type info - create instance of builtin t2crt::Object with proplist + str = varName+ " = "s + EmitTreeNode(node); + } else if (IsVarTypeClass(var)) { + // init var of type TS class + // - create obj instance of user defined class and do direct field access init + // - todo: handle class with generics + str = varName+ " = "s +userType->GetId()->GetName()+ "::ctor._new();\n"s; + str += GenDirectFieldInit(varName, node); + } else { + // type is builtin (e.g. t2crt::Record) and StructNode types (e.g. TSInterface) + // create instance of type but set constructor to the builtin t2crt::Object. + str = varName+ " = new "s +EmitUserTypeNode(userType)+ "(&t2crt::Object::ctor, t2crt::Object::ctor.prototype);\n"s; + auto n = mHandler->FindDecl(static_cast(userType->GetId())); + if (n && n->IsStruct() && static_cast(n)->GetProp() == SProp_TSInterface) { + str += GenDirectFieldInit(varName, node); // do direct field init + } + } + return str; +} + +// Generate code to construct an array of type any from an ArrayLiteral. +std::string CppDef::ConstructArrayAny(ArrayLiteralNode *node) { + if (node == nullptr || !node->IsArrayLiteral()) + return std::string(); + + // Generate array ctor call to instantiate array + std::string literals; + for (unsigned i = 0; i < node->GetLiteralsNum(); ++i) { + if (i) + literals += ", "s; + if (auto n = node->GetLiteral(i)) { + if (n->IsArrayLiteral()) + // Recurse to handle array elements that are arrays + literals += ConstructArrayAny(static_cast(n)); + else { + // Wrap element in JS_Val. C++ class constructor of JS_Val + // will set tupe tag in JS_Val according to element type. + literals += "t2crt::JS_Val("s + EmitTreeNode(n) + ")"s; + } + } + } + std::string str = ArrayCtorName(1, "t2crt::JS_Val") + "._new({"s + literals + "})"s; + return str; +} + +// Generate code to construct an array object with brace-enclosed initializer list +std::string CppDef::ConstructArray(ArrayLiteralNode *node, int dim, std::string type) { + if (type.empty()) { + return ConstructArrayAny(node); // proceed as array of type any if no type info + } + // Generate array ctor call to instantiate array + std::string str = ArrayCtorName(dim, type) + "._new({"s; + for (unsigned i = 0; i < node->GetLiteralsNum(); ++i) { + if (i) + str += ", "s; + if (auto n = node->GetLiteral(i)) { + if (n->IsArrayLiteral()) + str += ConstructArray(static_cast(n), dim-1, type); + else + str += EmitTreeNode(n); + } + } + str += "})"s; + return str; +} + +// decl of global var is handled by EmitDeclNode in cpp_declaration +// decl of function vars of type JS_Var is handled in EmitFuncSCopeVarDecls +// This function handles init of global/func var, and decl/init of func let/const. +// +// Declaration of Javascript "var", "let" an "const" variables: +// - "var" decls are function/global scoped +// - "let" and "const" are block scoped +// TS/JS allows duplicate "var" declarations in global scope as well as +// function scope. Duplicate global scope var decls are resolved +// by the front end which make only 1 decl for the dup and changes any inits +// in the dup decls to assigments. Duplicate function scope var decls are +// handled in CppDef::EmitFuncScopeVarDecls. +// +std::string CppDef::EmitDeclNode(DeclNode *node) { + if (node == nullptr) + return std::string(); + + std::string str, varStr; + TreeNode* idType = nullptr; + TypeId varType = TY_None; + + //std::string str(Emitter::GetEnumDeclProp(node->GetProp())); + + // For func var of JS_Var and global vars, emit var name + // For func var of JS_Let/JS_Const, emit both var type & name + if (auto n = node->GetVar()) { + varType = n->GetTypeId(); + if (mIsInit || node->GetProp() == JS_Var) { + // handle declnode inside for-of/for-in (uses GetSet() and has null GetInit()) + if (!node->GetInit() && node->GetParent() && !node->GetParent()->IsForLoop()) + return std::string(); + varStr = EmitTreeNode(n); // emit var name only + } else { + varStr = mCppDecl.EmitTreeNode(n); // emit both var type and name + } + if (n->IsIdentifier()) { + idType = static_cast(n)->GetType(); + } + } + if (auto n = node->GetInit()) { + if (n->IsStructLiteral()) + str += GenObjectLiteral(node->GetVar(), varStr, idType, static_cast(n)); + else if (node->GetVar()->IsIdentifier() && n->IsIdentifier() && n->IsTypeIdClass()) + str += varStr + "= &"s + n->GetName() + "::ctor"s; // init with ctor address + else if (n->IsFunction()) { + if (hFuncTable.IsTopLevelFunc(n)) { + str += varStr + " = new "s + "Cls_" + n->GetName() + "()"s; + hFuncTable.AddNameIsTopLevelFunc(varStr); + } + } else { + str += varStr + " = "; + if (varType == TY_None) // no type info. assume TY_Any and wrap val in JS_Val + str += "t2crt::JS_Val("s + EmitTreeNode(n) + ")"s; + else + str += EmitTreeNode(n); + } + } else { + str = varStr; + } + return str; +} + +static bool QuoteStringLiteral(std::string &s) { + if(s.front() != '"' || s.back() != '"') + return false; + s = s.substr(1, s.length() - 2); + Emitter::Replace(s, "\"", "\\\"", 0); + s = "\"" + s + "\""; + return true; +} + +std::string EmitSuperCtorCall(TreeNode* node) { + while (node->GetKind() && !node->IsClass()) + node = node->GetParent(); + if (node && node->IsClass()) { + std::string base, str; + base = (static_cast(node)->GetSuperClassesNum() != 0)? static_cast(node)->GetSuperClass(0)->GetName() : "t2crt::Object"; + str = " "s + base + "::ctor"s; + return str; + } + return ""s; +} + +std::string CppDef::EmitCallNode(CallNode *node) { + if (node == nullptr) + return std::string(); + bool log = false; + bool isSuper = false; + std::string str; + if (auto n = node->GetMethod()) { + if(n->IsFunction()) { + str += static_cast(n)->GetName(); + } else { + auto s = EmitTreeNode(n); + if(s.compare(0, 12, "console->log") == 0) { + str += "std::cout"s; + log = true; + } else if (s.compare("super") == 0) { + isSuper = true; + str += EmitSuperCtorCall(node); + } else if (hFuncTable.IsTopLevelFuncName(s)) { + // s can be either ts function or ts var of function type + str += "(*"s + s + ")"s; + } else if (hFuncTable.IsImportedField(s)) { + str += "(*"s + s + ")"s; + } else if (hFuncTable.IsStaticMember(s)) { + str += "("s + s +")"s; + } else if (s.find("->") != std::string::npos) + str += s; + else + str += "(*("s + s + "))"s; + } + } + if(!log) + str += isSuper? "(obj"s : "("s; + unsigned num = node->GetArgsNum(); + for (unsigned i = 0; i < num; ++i) { + if(log) { + std::string s = EmitTreeNode(node->GetArg(i)); + if(QuoteStringLiteral(s)) { + //if(num > 1) + // s = "\"'\""s + s + "\"'\""s; + } else if(mPrecedence <= 13) // '\015' + s = "("s + s + ")"s; + if (i) + str += " << ' ' "s; + str += " << "s + s; + } else { + if (i || isSuper) + str += ", "s; + if (auto n = node->GetArg(i)) + str += EmitTreeNode(n); + } + } + if(!log) + str += ")"s; + else + str += " << std::endl;"; + mPrecedence = '\024'; + return str; +} + +std::string CppDef::EmitPrimTypeNode(PrimTypeNode *node) { + return mCppDecl.EmitPrimTypeNode(node); +} + +std::string CppDef::EmitPrimArrayTypeNode(PrimArrayTypeNode *node) { + return std::string(); +} + +inline bool IsBracketNotationProp(TreeNode *node) { + return node->IsArrayElement() && + static_cast(node)->GetArray()->IsTypeIdClass(); +} + +std::string CppDef::EmitArrayElementNode(ArrayElementNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (IsBracketNotationProp(node)) { + bool unused; + str = EmitBracketNotationProp(node, OPR_Arrow, false, unused); + return str; + } + if (auto n = node->GetArray()) { + std::string s = EmitTreeNode(n); + if (mIsInit && s == "this") + str = "__module"s; + else + str = "(*"s + s + ")"s; + if(mPrecedence < '\024') + str = "("s + str + ")"s; + } + + + for (unsigned i = 0; i < node->GetExprsNum(); ++i) { + if (auto n = node->GetExprAtIndex(i)) { + std::string expr; + expr = "["s + EmitTreeNode(n) + "]"s; + if (i < node->GetExprsNum()-1) + str = "(*"s + str + expr + ")"s; + else + str += expr; + } + } + + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + + +std::string CppDef::EmitArrayLiteralNode(ArrayLiteralNode *node) { + if (node == nullptr) + return std::string(); + if (node->GetParent() && + node->GetParent()->IsDecl() || // for var decl init + node->GetParent()->IsIdentifier() || // for default val init in class field decl + node->GetParent()->IsFieldLiteral()) { // for obj decl with struct literal init + // emit code to construct array object with brace-enclosed initializer list + int dim; + std::string str, type; + GetArrayTypeInfo(node, dim, type); + str = ConstructArray(node, dim, type); + return str; + } + + // emit code to build a brace-enclosed intializer list (for rhs of array var assignment op) + std::string str("{"s); + for (unsigned i = 0; i < node->GetLiteralsNum(); ++i) { + if (i) + str += ", "s; + if (auto n = node->GetLiteral(i)) { + str += EmitTreeNode(n); + } + } + str += "}"s; + return str; +} + +std::string CppDef::EmitFieldNode(FieldNode *node) { + if (node == nullptr) + return std::string(); + std::string upper, field, propType; + bool isRhs = false; // indicate if field is rhs (val) or lhs (ref) + auto upnode = node->GetUpper(); + bool upperIsGenerator = false; + if (upnode) { + upper = EmitTreeNode(upnode); + isRhs = !mHandler->IsDef(upnode); + upperIsGenerator = IsGenerator(upnode); // TODO: await TI fix for generator3.ts + } + if (auto n = node->GetField()) { + if (isRhs) { + propType = hlpGetJSValTypeStr(hlpGetTypeId(n)); + } + field = EmitTreeNode(n); + if (n->IsIdentifier()) { // check for static class field or method + if (auto decl = mHandler->FindDecl(static_cast(n))) { + if ((decl->IsFunction() && HasAttrStatic(static_cast(decl))) || + (decl->IsIdentifier() && HasAttrStatic(static_cast(decl)))) { + std::string fdStr = GetClassName(decl) + "::"s + field; + hFuncTable.AddMemberIsStatic(fdStr); + return fdStr; + } + } + } + } + if (upper.empty() || field.empty()) // Error if either is empty + return "%%%Empty%%%"; + if (field == "length") // for length property + return upper + "->size()"s; + if (mCppDecl.IsImportedModule(upper) || upnode->GetTypeId() == TY_Module || upnode->GetTypeId() == TY_Namespace) // for imported module + return hFuncTable.AddFieldIsImported(upper + "::"s + field); + if (mHandler->IsCppField(node->GetField()) || // check if it accesses a Cxx class field + node->IsTypeIdFunction()) + return upper + "->"s + field; + if (isRhs) + return "(*"s + upper + ").GetProp"s + propType + "(\""s + field + "\")"s; + return "(*"s + upper + ")[\""s + field + "\"]"s; +} + +std::string CppDef::EmitCondBranchNode(CondBranchNode *node) { + if (node == nullptr) + return std::string(); + std::string str("if("s); + if (auto n = node->GetCond()) { + auto cond = EmitTreeNode(n); + str += Clean(cond); + } + str += ")"s; + if (auto n = node->GetTrueBranch()) { + str += EmitTreeNode(n) + GetEnding(n); + } + if (auto n = node->GetFalseBranch()) { + str += "else"s + EmitTreeNode(n) + GetEnding(n); + } + if(auto n = node->GetLabel()) { + str += "__label_break_"s + EmitTreeNode(n) + ":;\n"s; + } + return str; +} + +std::string CppDef::EmitBlockNode(BlockNode *node) { + if (node == nullptr) + return std::string(); + std::string str("{\n"); + for (unsigned i = 0; i < node->GetChildrenNum(); ++i) { + if (auto n = node->GetChildAtIndex(i)) { + std::string s = EmitTreeNode(n); + if (n->IsYield()) { + str += s; + continue; + } + if (!s.empty()) + str += " "s + s + GetEnding(n); + } + } + str += "}\n"s; + if(auto n = node->GetLabel()) { + str += "__label_break_"s + EmitTreeNode(n) + ":;\n"s; + } + mPrecedence = '\030'; + return str; +} + +std::string CppDef::EmitForLoopNode(ForLoopNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + str += "for("s; + switch(node->GetProp()) { + case FLP_Regular: + { + for (unsigned i = 0; i < node->GetInitsNum(); ++i) + if (auto n = node->GetInitAtIndex(i)) { + if (i) + str += ", "s; + str += EmitTreeNode(n); + } + str += "; "s; + if (auto n = node->GetCond()) { + str += EmitTreeNode(n); + } + str += "; "s; + for (unsigned i = 0; i < node->GetUpdatesNum(); ++i) + if (auto n = node->GetUpdateAtIndex(i)) { + if (i) + str += ", "s; + str += EmitTreeNode(n); + } + break; + } + case FLP_JSIn: + { + if (auto n = node->GetVariable()) { + str += EmitTreeNode(n); + } + str += " in "s; + if (auto n = node->GetSet()) { + str += EmitTreeNode(n); + } + break; + } + case FLP_JSOf: + { + if (auto n = node->GetVariable()) { + std::string s = EmitTreeNode(n); + str += "auto "s + Clean(s); + } + str += " : "s; + if (auto n = node->GetSet()) { + str += EmitTreeNode(n); + if (n->IsIdentifier() && static_cast(n)->IsTypeIdArray()) { + str += "->elements"s; + } + } + break; + } + case FLP_NA: + return "FLP_NA"s; + default: + MASSERT(0 && "Unexpected enumerator"); + } + str += ")"s; + + auto label = node->GetLabel(); + std::string lstr; + if(label) { + lstr = EmitTreeNode(label); + str += "{\n"s; + } + if (auto n = node->GetBody()) { + str += EmitTreeNode(n) + GetEnding(n); + } + if(label) + str += "__label_cont_"s + lstr + ":;\n}\n"s + "__label_break_"s + lstr + ":;\n"s; + return str; +} + +std::string CppDef::EmitBreakNode(BreakNode *node) { + if (node == nullptr) + return std::string(); + auto target = node->GetTarget(); + std::string str = target ? "goto __label_break_"s + EmitTreeNode(target) : "break"s; + return str; +} + +std::string CppDef::EmitContinueNode(ContinueNode *node) { + if (node == nullptr) + return std::string(); + auto target = node->GetTarget(); + std::string str = target ? "goto __label_cont_"s + EmitTreeNode(target) : "continue"s; + return str; +} + +TypeId CppDef::GetTypeIdFromDecl(TreeNode* node) { + TypeId typeId = TY_None; + + if (auto typ = FindDeclType(node)) { + if (typ->IsPrimType()) + typeId = static_cast(typ)->GetPrimType(); + } + return typeId; +} + +// Check if a bracket notation property is a class member field +bool CppDef::IsClassField(ArrayElementNode* node, std::string propKey) { + if (!node->GetArray()->IsIdentifier()) { + return false; + } + // find declared type of bracket notation obj; if class type + // if class type, lookup class decl and check if prop is a class member fd + if (auto typ = FindDeclType(node->GetArray())) + if (typ->IsUserType() && static_cast(typ)->IsTypeIdClass()) + if (auto classId = static_cast(typ)->GetId()) + if (auto n = mHandler->FindDecl(static_cast(classId))) + if (n->IsClass()) + for (unsigned i = 0; i < static_cast(n)->GetFieldsNum(); ++i) { + auto fd = static_cast(n)->GetField(i); + if (fd->IsIdentifier()) + // skip leading and trailing quote in propKey when comparing + if (propKey.compare(1, propKey.length()-2, static_cast(fd)->GetName()) == 0) + return true; + } + return false; +} + +// +// For property access using bracket notation (e.g. bar["prop"]): +// 1) If the property is a member field in the object's class, emit: bar->prop +// 2) Otherwise it is a property created dynamically at runtime: +// - If it is a lvalue, emit: (*bar)["prop"] - [] operator overloaded in ts2cpp.h +// - If it is a rvalue, emit: bar->GetPropXX("prop") - XX is one of union types in t2crt::JS_Val +// 3) For OP_Assign, if lvalue on lhs is dynamic prop, wrap rhs with t2crt::JS_Val() macro. +// e.g. (*bar)["p1"] = t2crt::JS_Val(0xa); +// (*bar)["p2"] = t2crt::JS_Val(bar->f2); +// (*bar)["p2"] = t2crt::JS_Val(bar->GetPropLong("p1")); +// (*bar)["p2"] = t2crt::JS_Val((uint32_t)(bar->GetPropLong("p2") >> bar->GetPropLong("p1"))); +// +// *note: to do 1), the property key must be a string literal. if the property key +// is an identfier, then we have to do 2) because the identfier can be +// a var or a TS symobol resolvable only at runtime. +// Also, the object may be an expression, in which case, it can only be evaluated at runtime +// +std::string CppDef::EmitBracketNotationProp(ArrayElementNode* ae, OprId binOpId, bool isLhs, bool& isDynProp) { + if (ae == nullptr) + return std::string(); + + isDynProp = true; + std::string str, propKey; + std::string objName; + + if (ae->GetArray()->IsIdentifier()) { + objName = ae->GetArray()->GetName(); + } else { + // case where the object is an expression - re: call-func.ts + objName = EmitTreeNode(ae->GetArray()); + } + + TypeId propKeyType = ae->GetExprAtIndex(0)->GetTypeId(); + if (propKeyType == TY_String && ae->GetExprAtIndex(0)->IsLiteral()) { + propKey = EmitTreeNode(ae->GetExprAtIndex(0)); + if (IsClassField(ae, propKey)) { + // property is class member field + str = objName + "->"s + propKey.substr(1, propKey.length()-2); + isDynProp = false; + return str; + } + } + if (propKeyType == TY_None) { + propKeyType = GetTypeIdFromDecl(ae->GetExprAtIndex(0)); + } + // resolve propKey at runtime + switch (propKeyType) { + case TY_Int: + propKey = "t2crt::to_string("s + EmitTreeNode(ae->GetExprAtIndex(0)) + ")"s; + break; + case TY_String: + propKey = EmitTreeNode(ae->GetExprAtIndex(0)); + break; + case TY_Symbol: + propKey = "t2crt::to_string("s + EmitTreeNode(ae->GetExprAtIndex(0)) + ")"s; + break; + default: + MASSERT(0 && "Encounter unsupported prop key type in bracket notation"); + break; + } + + if (binOpId == OPR_Assign && isLhs) { + // prop is lvalue + str = "(*"s + objName + ")["s + propKey + "]"s; + } else { + switch(ae->GetTypeId()) { + case TY_Long: + case TY_Int: + str = objName + "->GetPropLong("s + propKey + ")"s; + break; + case TY_Double: + str = objName + "->GetPropDouble("s + propKey + ")"s; + break; + case TY_String: + str = objName + "->GetPropString("s + propKey + ")"s; + break; + case TY_Boolean: + str = objName + "->GetPropBool("s + propKey + ")"s; + break; + case TY_Function: + case TY_Object: + str = objName + "->GetPropObj("s + propKey + ")"s; + break; + case TY_Any: + str = objName + "->GetProp("s + propKey + ")"s; + break; + default: + str = "(*"s + objName + ")["s + propKey + ']'; + } + + // prop is rvalue + // emit: bar->GetPropXX("prop") + // Need type info for each property + } + return str; +} + +std::string CppDef::EmitBinOperatorNode(BinOperatorNode *node) { + if (node == nullptr) + return std::string(); + const char *op = Emitter::GetEnumOprId(node->GetOprId()); + const Precedence precd = *op & 0x3f; + const bool rl_assoc = *op >> 6; // false: left-to-right, true: right-to-left + std::string lhs, rhs; + bool lhsIsDynProp = false; + bool rhsIsDynProp = false; + + if (auto n = node->GetOpndA()) { + if (IsBracketNotationProp(n)) { + lhs = EmitBracketNotationProp(static_cast(n), node->GetOprId(), true, lhsIsDynProp); + } else { + lhs = EmitTreeNode(n); + if (n->IsIdentifier() && n->IsTypeIdArray()) + lhs = "*"s + lhs; + } + if(precd > mPrecedence || (precd == mPrecedence && rl_assoc)) + lhs = "("s + lhs + ")"s; + } + else + lhs = "(NIL) "s; + + if (auto n = node->GetOpndB()) { + if (IsBracketNotationProp(n)) { + rhs = EmitBracketNotationProp(static_cast(n), node->GetOprId(), false, rhsIsDynProp); + } else if (IsClassId(n)) { + rhs = "&"s + n->GetName() + "::ctor"s; + } else + rhs = EmitTreeNode(n); + if(precd > mPrecedence || (precd == mPrecedence && !rl_assoc)) + rhs = "("s + rhs + ")"s; + } + else + rhs = " (NIL)"s; + + OprId k = node->GetOprId(); + std::string str; + switch(k) { + case OPR_Exp: + str = "std::pow("s + lhs + ", "s + rhs + ")"; + break; + case OPR_StEq: + str = "t2crt::StrictEqu("s + lhs + ',' + rhs + ')'; + break; + case OPR_StNe: + str = "t2crt::StrictNotEqu("s + lhs + ',' + rhs + ')'; + break; + default: + switch(k) { + case OPR_Band: + case OPR_Bor: + case OPR_Bxor: + case OPR_Shl: + case OPR_Shr: + lhs = "static_cast(static_cast("s + lhs + "))"s; + break; + case OPR_Zext: + lhs = "static_cast(static_cast("s + lhs + "))"s; + op = "\015>>"; + break; + } + if (k == OPR_Assign && lhsIsDynProp) + rhs = "t2crt::JS_Val("s + rhs + ")"s; + str = lhs + " "s + std::string(op + 1) + " "s + rhs; + } + mPrecedence = precd; + return str; +} + +std::string CppDef::EmitUnaOperatorNode(UnaOperatorNode *node) { + if (node == nullptr) + return std::string(); + bool isPost = node->IsPost(); + const char *op = Emitter::GetEnumOprId(node->GetOprId()); + const Precedence precd = *op & 0x3f; + const bool rl_assoc = *op >> 6; // false: left-to-right, true: right-to-left + std::string opr; + if (auto n = node->GetOpnd()) { + opr = EmitTreeNode(n); + if(precd > mPrecedence || (precd == mPrecedence && (rl_assoc && isPost || !rl_assoc && !isPost))) + opr = "("s + opr + ")"s; + } + else + opr = "(NIL)"s; + if(node->GetOprId() == OPR_Bcomp) + opr = "static_cast("s + opr + ")"s; + std::string str; + if(node->IsPost()) + str = opr + std::string(op + 1) + " "s; + else + str = " "s + std::string(op + 1) + opr; + mPrecedence = precd; + return str; +} + +std::string CppDef::EmitTemplateLiteralNode(TemplateLiteralNode *node) { + if (node == nullptr) + return std::string(); + auto num = node->GetTreesNum(); + std::string str; + for (unsigned i = 0; i < num; ++i) { + if (auto n = node->GetTreeAtIndex(i)) { + if (!std::empty(str)) + str += " + "s; + std::string s(EmitTreeNode(n)); + if(i & 0x1) + str += "t2crt::to_string("s + s+ ")"s; + else { + QuoteStringLiteral(s); + str += s; + } + } + } + mPrecedence = '\016'; + return str; +} + +std::string CppDef::EmitLiteralNode(LiteralNode *node) { + if (node == nullptr) + return std::string(); + LitData lit = node->GetData(); + if(lit.mType == LT_VoidLiteral) + return "undefined"; + std::string str = Emitter::EmitLiteralNode(node); + return str; +} + +std::string CppDef::EmitSwitchNode(SwitchNode *node) { + if (node == nullptr) + return std::string(); + bool doable = true; + for (unsigned i = 0; i < node->GetCasesNum(); ++i) + if (SwitchCaseNode* c = node->GetCaseAtIndex(i)) + for (unsigned j = 0; j < c->GetLabelsNum(); ++j) { + auto l = c->GetLabelAtIndex(j); + if (l && l->IsSwitchLabel()) { + auto ln = static_cast(l); + if (auto v = ln->GetValue()) + if(!v->IsLiteral() || !v->IsTypeIdInt()) { + doable = false; + goto out_of_loops; + } + } + } +out_of_loops: + std::string label; + TreeNode* lab = node->GetLabel(); + if(lab) + label = "__label_break_"s + EmitTreeNode(lab); + else + label = "__label_switch_" + std::to_string(node->GetNodeId()); + std::string str; + if(doable) { + str = "switch("s; + if (TreeNode* n = node->GetExpr()) { + std::string expr = EmitTreeNode(n); + str += Clean(expr); + } + str += "){\n"s; + for (unsigned i = 0; i < node->GetCasesNum(); ++i) { + if(SwitchCaseNode* n = node->GetCaseAtIndex(i)) + str += EmitTreeNode(n); + } + str += "}\n"s; + } else { + std::string tmp = "__tmp_"s + std::to_string(node->GetNodeId()); + str = "do { // switch\nauto "s + tmp + " = "s; + if (TreeNode* n = node->GetExpr()) { + std::string expr = EmitTreeNode(n); + str += Clean(expr); + } + str += ";\n"s; + std::string body; + std::string other = "goto "s + label + ";\n"s;; + for (unsigned i = 0; i < node->GetCasesNum(); ++i) + if (SwitchCaseNode* cn = node->GetCaseAtIndex(i)) { + for (unsigned j = 0; j < cn->GetLabelsNum(); ++j) + if (SwitchLabelNode* ln = cn->GetLabelAtIndex(j)) { + if(ln->IsDefault()) + other = "goto __case_"s + std::to_string(cn->GetNodeId()) + ";\n"s; + else { + std::string le = EmitTreeNode(ln->GetValue()); + str += "if("s + tmp + " == ("s + Clean(le) + + "))\ngoto __case_"s + std::to_string(cn->GetNodeId()) + ";\n"s; + } + } + body += "__case_"s + std::to_string(cn->GetNodeId()) + ":\n"s; + for (unsigned s = 0; s < cn->GetStmtsNum(); ++s) + if (TreeNode* t = cn->GetStmtAtIndex(s)) + body += EmitTreeNode(t) + ";\n"s; + } + str += other + body; + str += "} while(0);\n"s; + } + if(!doable || lab) + str += label + ":;\n"s; + return str; +} + +std::string CppDef::EmitTypeOfNode(TypeOfNode *node) { + if (node == nullptr) + return std::string(); + std::string str("t2crt::__js_typeof("s), rhs; + if (auto n = node->GetExpr()) + rhs = EmitTreeNode(n); + str += rhs + ")"s; + return HandleTreeNode(str, node); +} + +// Return C++ object type of "this" parameter in function param declaration +std::string CppDef::GetThisParamObjType(TreeNode *node) { + if (node && !node->IsFunction()) + return std::string(); + + std::string str = "t2crt::Object"; + if (static_cast(node)->GetParamsNum()) { + auto n = static_cast(node)->GetParam(0); + if (n->IsThis()) { + TreeNode* tn = static_cast(n)->GetType(); + str = mCppDecl.GetTypeString(tn, nullptr); + if (str.back() == '*') + str.pop_back(); + if (!str.compare("t2crt::JS_Val ") || !str.compare("t2crt::JS_Val")) { + str = "t2crt::Object"; + } + } + } + return str; +} + +std::string CppDef::EmitNewNode(NewNode *node) { + if (node == nullptr) + return std::string(); + + std::string str; + MASSERT(node->GetId() && "No mId on NewNode"); + + if (auto id = node->GetId()) { + if (id->IsTypeIdClass()) { + // Generate code to create new class obj and call class constructor + std::string clsName = EmitTreeNode(node->GetId()); + if (IsBuiltinObj(clsName)) + clsName = "t2crt::"s + clsName; + str = clsName + "::ctor("s + clsName + "::ctor._new()"s; + + } else if (id->IsTypeIdFunction()) { // TS: new () + // When calling TS new() on constructor function: + // A new object is created and bound to "this" of ctor func which is then invoked. + // The object's proto chain is linked to ctor func prototype, and constructor set + // to the consturctor object. The object is then returned. + // note: When calling new() on functions, TSC only allows void functions that + // reference 'this' or non void function that do not reference 'this'. + // TSC strict mode requires all funcs that refs "this" to declare it as 1st parm. + if (auto decl = mHandler->FindDecl(static_cast(id))) { + std::string objClass = GetThisParamObjType(decl); // "t2crt::Object" , "Foo" etc + std::string fnName = GetIdentifierName(id); + // create new obj with proto chain and ctor init'd : new (, ->prototype) + std::string newObj = "new "s + objClass + "("s + fnName + ", "s + fnName + "->prototype)"s; + str = fnName + "->ctor("s + newObj + ", "s; // call ctor function with new obj as this arg + } + } else { + // for builtins + str = "new "s + EmitTreeNode(node->GetId()); + str += "("s; + } + } + + auto num = node->GetArgsNum(); + for (unsigned i = 0; i < num; ++i) { + if (i || node->GetId()->IsTypeIdClass()) + str += ", "s; + if (auto n = node->GetArg(i)) { + str += EmitTreeNode(n); + } + } + str += ")"s; + if (auto n = node->GetBody()) { + str += " "s + EmitBlockNode(n); + } + mPrecedence = '\024'; + return HandleTreeNode(str, node); +} + +static std::string MethodString(std::string &func) { + size_t s = func.substr(0, 9) == "function " ? 9 : 0; + return func.back() == '}' ? func.substr(s) + "\n"s : func.substr(s) + ";\n"s; +} + +std::string CppDef::EmitStructNode(StructNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + const char *suffix = ";\n"; + switch(node->GetProp()) { + case SProp_CStruct: + str = "struct "s; + break; + case SProp_TSInterface: + return std::string(); // decl already generation by CppDecl + case SProp_TSEnum: { + // Create the enum type object + std::string enumClsName; + if (auto n = node->GetStructId()) { + enumClsName = "Enum_"s + n->GetName(); + str += n->GetName() + " = new "s + enumClsName + "();\n"s; + return str; + } + break; + } + case SProp_NA: + str = ""s; + return str; // todo: handle anonymous struct created for untyped object literals. + break; + default: + MASSERT(0 && "Unexpected enumerator"); + } + + if (auto n = node->GetStructId()) { + str += EmitIdentifierNode(n); + } + + auto num = node->GetTypeParamsNum(); + if(num) { + str += "<"s; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetTypeParamAtIndex(i)) + str += EmitTreeNode(n); + } + str += ">"s; + } + + for (unsigned i = 0; i < node->GetSupersNum(); ++i) { + str += i ? ", "s : " extends "s; + if (auto n = node->GetSuper(i)) + str += EmitTreeNode(n); + } + str += " {\n"s; + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (auto n = node->GetField(i)) { + str += EmitTreeNode(n) + suffix; + } + } + + if (auto n = node->GetNumIndexSig()) { + str += EmitNumIndexSigNode(n) + "\n"s;; + } + if (auto n = node->GetStrIndexSig()) { + str += EmitStrIndexSigNode(n) + "\n"; + } + + for (unsigned i = 0; i < node->GetMethodsNum(); ++i) { + if (auto n = node->GetMethod(i)) { + std::string func = EmitFunctionNode(n); + func = Clean(func); + str += MethodString(func); + } + } + + str += "}\n"s; + return HandleTreeNode(str, node); +} + +std::string CppDef::EmitTypeAliasNode(TypeAliasNode *node) { + return std::string(); +} + +// Return the declared type for an identifier +TreeNode* CppDef::FindDeclType(TreeNode* node) { + if (node == nullptr || !node->IsIdentifier()) + return nullptr; + + if (auto n = mHandler->FindDecl(static_cast(node))) + if (n->IsDecl()) + if (auto var = static_cast(n)->GetVar()) + if (var->IsIdentifier()) + if (auto type = static_cast(var)->GetType()) + return type; + + return nullptr; +} + +// Get template argument for calling InstanceOf template func. +std::string CppDef::GetTypeForTemplateArg(TreeNode* node) { + if (node == nullptr) + return std::string(); + + std::string str; + if (auto n = FindDeclType(node)) { + // lhs type of instanceof operator is either object or ANY + switch(n->GetKind()) { + case NK_UserType: + str = EmitTreeNode(n); + break; + case NK_PrimType: + str = EmitTreeNode(n); + if (str.find("t2crt::JS_Val") != std::string::npos) + str = "t2crt::JS_Val"; + break; + default: + MASSERT(0 && "Unexpected node type"); + } + } else if (node->IsField()) { + // Lookup declared type of the obj in mUpper, then find + // mField from the obj field list to get the field type. + // + // The result is used as template argument for the InstanceOf + // template func. However, without this information + // the compiler does template argument deduction + // to call the template func, and has work ok for testcases. + // So implementation of this part is deferred until needed. + } else { + // No info - return ANY for now... + str = "t2crt::JS_Val"s; + //MASSERT(0 && "Unexpected node type"); + } + return str; +} + +std::string CppDef::EmitInstanceOfNode(InstanceOfNode *node) { + if (node == nullptr) + return std::string(); + const Precedence precd = '\014'; + const bool rl_assoc = false; // false: left-to-right + std::string lhs, rhs, typ; + if (auto n = node->GetLeft()) { + lhs = EmitTreeNode(n); + typ = GetTypeForTemplateArg(n); + if (typ.compare("t2crt::JS_Val") == 0) { + lhs = "t2crt::JS_Val("s + lhs + ")"s; + typ = ""; + } + else if (!typ.empty()) + typ = "<"s + typ + ">"s; // InstanceOf + + if(precd > mPrecedence) + lhs = '(' + lhs + ')'; + } + else + lhs = "(NIL) "s; + + if (auto n = node->GetRight()) { + if (IsClassId(n) || IsBuiltinObj(n->GetName())) + rhs = "&t2crt::"s + n->GetName() + "::ctor"s; + else + rhs = EmitTreeNode(n); + if(precd > mPrecedence || (precd == mPrecedence && !rl_assoc)) + rhs = '(' + rhs + ')'; + } + else + rhs = " (NIL)"s; + + std::string str("t2crt::InstanceOf"s + typ + "("s + lhs + ", "s + rhs + ")"s); + mPrecedence = precd; + return HandleTreeNode(str, node); +} + +std::string CppDef::EmitDeclareNode(DeclareNode *node) { + return std::string(); +} + +std::string CppDef::EmitAsTypeNode(AsTypeNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetType()) + str = EmitTreeNode(n); + if (!str.empty()) + str = '(' + str + ')'; + return str; +} + +std::string CppDef::EmitNamespaceNode(NamespaceNode *node) { + if (node == nullptr) + return std::string(); + // emit namespace in each statement inside of current namespace + std::string str; + for (unsigned i = 0; i < node->GetElementsNum(); ++i) { + if (auto n = node->GetElementAtIndex(i)) { + str += EmitTreeNode(n) + GetEnding(n); + } + } + return str; +} + +std::string &CppDef::HandleTreeNode(std::string &str, TreeNode *node) { + auto num = node->GetAsTypesNum(); + if(num > 0) { + std::string as; + for (unsigned i = 0; i < num; ++i) + if (auto t = node->GetAsTypeAtIndex(i)) + as = EmitAsTypeNode(t) + as; + str = as + '(' + str + ')'; + } + /* + if(node->IsOptional()) + str = AddParentheses(str, node) + '?'; + if(node->IsNonNull()) + str = AddParentheses(str, node) + '!'; + */ + if(node->IsRest()) + str = "..."s; // + AddParentheses(str, node); + /* + if(node->IsConst()) + if(node->IsField()) + str += " as const"s; + else + str = AddParentheses(str, node) + " as const"s; + */ + return str; +} + +std::string CppDef::EmitRegExprNode(RegExprNode *node) { + if (node == nullptr) + return std::string(); + std::string source = Emitter::EmitRegExprNode(node); + InsertEscapes(source); + return "RegExp::ctor._new(\""s + source + "\")"s; +} + +} // namespace maplefe diff --git a/src/MapleFE/ast2cpp/src/cpp_emitter.cpp b/src/MapleFE/ast2cpp/src/cpp_emitter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c5c92c0b0409646a598f2cc081f2b3d50197f638 --- /dev/null +++ b/src/MapleFE/ast2cpp/src/cpp_emitter.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. + * + * OpenArkFE is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "cpp_emitter.h" +#include "helper.h" + +namespace maplefe { + +std::string CppEmitter::GetIdentifierName(TreeNode *node) { + if (node == nullptr) + return std::string(); + switch (node->GetKind()) { + case NK_Identifier: + return std::string(static_cast(node)->GetName()); + case NK_Decl: + return GetIdentifierName(static_cast(node)->GetVar()); + case NK_Struct: + // Named StructNode has name in StructId. Unamed StructNode is assigned + // anonymous name by frontend and can be accessed using node mStrIdx + // through node GetName() interface. + if (auto n = static_cast(node)->GetStructId()) + return GetIdentifierName(n); + else + return node->GetName(); // for anonomyous name + case NK_Function: + if (static_cast(node)->GetFuncName()) + return GetIdentifierName(static_cast(node)->GetFuncName()); + else + return GenAnonFuncName(node); + case NK_Class: + return std::string(static_cast(node)->GetName()); + case NK_Interface: + return std::string(static_cast(node)->GetName()); + case NK_UserType: + return GetIdentifierName(static_cast(node)->GetId()); + case NK_TypeAlias: + return GetIdentifierName(static_cast(node)->GetId()); + case NK_Namespace: + return GetIdentifierName(static_cast(node)->GetId()); + case NK_Module: + return GetModuleName(static_cast(node)->GetFilename()); + case NK_Literal: + return AstDump::GetEnumLitData(static_cast(node)->GetData()); + case NK_Declare: + { auto n = static_cast(node); + auto num = n->GetDeclsNum(); + if (num == 1) + return GetIdentifierName(n->GetDeclAtIndex(0)); + return "Failed: one decl is expected"s; + } + default: + return "Failed to get the name of "s + AstDump::GetEnumNodeKind(node->GetKind()); + } +} + +bool CppEmitter::IsInNamespace(TreeNode *node) { + while (node) { + if (node->IsNamespace()) + return true; + node = node->GetParent(); + } + return false; +} + +std::string CppEmitter::GetNamespace(TreeNode *node) { + std::string ns; + while (node) { + if (node->IsNamespace()) { + TreeNode *id = static_cast(node)->GetId(); + if (id->IsIdentifier()) { + std::string s = Emitter::EmitIdentifierNode(static_cast(id)); + ns = ns.empty() ? s : s + "::"s + ns; + } + } + node = node->GetParent(); + } + return ns; +} + +std::string CppEmitter::GetQualifiedName(IdentifierNode *node) { + std::string name; + if (node == nullptr) + return name; + name = node->GetName(); + TreeNode *parent = node->GetParent(); + if (parent->IsField()) + return name; + Module_Handler *handler = GetModuleHandler(); + TreeNode *decl = handler->FindDecl(node); + if (decl == nullptr) + return name; + std::string ns = GetNamespace(decl); + return ns.empty() ? name : ns + "::"s + name; +} + +// Returns true if identifier is a class +bool CppEmitter::IsClassId(TreeNode* node) { + if (node == nullptr || !node->IsIdentifier()) + return false; + if (auto decl = mHandler->FindDecl(static_cast(node), true)) { // deep, cross module lookup + if (decl->IsClass()) + return true; + // TODO: handle type alias + } + return false; +} + +// Returns true if the declared type of a var is a TS class +bool CppEmitter::IsVarTypeClass(TreeNode* var) { + if (var == nullptr) + return false; + if (auto n = gTypeTable.GetTypeFromTypeIdx(var->GetTypeIdx())) { + if (n->IsClass()) + return true; + } + return false; +} + +void CppEmitter::InsertEscapes(std::string& str) { + Emitter::Replace(str, "\\", "\\\\", 0); + Emitter::Replace(str, "\"", "\\\"", 0); +} + +bool CppEmitter::IsGenerator(TreeNode* node) { + return mHandler->IsGeneratorUsed(node->GetNodeId()); +} + +FunctionNode* CppEmitter::GetGeneratorFunc(TreeNode* node) { + return mHandler->GetGeneratorUsed(node->GetNodeId()); +} + +// +// Interface to get array type and dimension interface for an ArrayLiteral +// (should be just a wrapper to call TI interfaces GetArrayElemTypeId() +// and GetArrayDim(), but until the usage of those 2 interface can cover all +// use caes, this interface encaps any additional work to get array type info. +// +void CppEmitter::GetArrayTypeInfo(ArrayLiteralNode* node, int& numDim, std::string& type) { + TypeId typeId = mHandler->GetArrayElemTypeId(node->GetNodeId()); + DimensionNode* dim = mHandler->GetArrayDim(node->GetNodeId()); + if (dim) + numDim = dim->GetDimensionsNum(); + switch(typeId) { + case TY_Class: { + unsigned tIdx = mHandler->GetArrayElemTypeIdx(node->GetNodeId()); + TreeNode* tp = gTypeTable.GetTypeFromTypeIdx(tIdx); + type = ObjectTypeStr(tp->GetName()); + break; + } + case TY_Int: + type = "long"; + break; + case TY_String: + type = "std::string"; + break; + case TY_Double: + type = "double"; + break; + case TY_None: + type = "t2crt::JS_Val"; + break; +#if 0 + case TY_Array: + type = "t2crt::Array*"; + break; +#endif + case TY_Function: + default: + // TODO + dim = 0; + type = "TBD"; + break; + } + return; + +#if 0 + if (!node->GetParent()) + return; + + switch(node->GetParent()->GetKind()) { + case NK_Decl: + // e.g. var arr: number[]=[1,2,3]; + //GetArrInfoByVarId(node, dim, type); + break; + case NK_Identifier: + // e.g. class Foo { arr: number[]=[1,2,3]; } + //GetArrInfoByClassFieldId(node, dim, type); + break; + case NK_FieldLiteral: + // e.g. var: {arr:number[]} = { n:[1,2,3] }; + //GetArrInfoByObjLiteralClassField(node, dim, type); + break; + } +#endif +} + +// C++ function header for different TS function types: +// Generator: t2crt::IteratorResult [::]GeneratorFunc_::_body(t2crt::Object* _this, void*& yield[, &]...) +// Class ctor: [::]* ::Ctor::operator()(* obj[, ]...) +// Class method: [::]::([params]...) +// Function: [::]Cls_::_body(t2crt::Object|* _this[, params]...) +std::string CppEmitter::FunctionHeader(FunctionNode* node, std::string retType) { + std::string str; + std::string ns = GetNamespace(node).empty() ? ""s : GetNamespace(node)+"::"; + std::string funcName = GetIdentifierName(node); + std::string className= ns + GetClassName(node); + bool isTopLevel = hFuncTable.IsTopLevelFunc(node); + retType = retType + " "s + ns; + + if (node->IsGenerator()) // generator + str += GeneratorFuncHeader(ns+GeneratorFuncName(funcName)+"::", node->GetNodeId()); + else if (node->IsConstructor()) { // class constructor + std::string param = FunctionParams(node->GetNodeId(), false); + param = param.empty() ? ""s : (", "s+param); + str += className + "* "s + className + "::Ctor::operator()" + "(" +className+ "* obj" +param+ ") "; + } + else if (IsClassMethod(node)) // class method + str += retType + GetClassName(node) + "::" + funcName + "(" + FunctionParams(node->GetNodeId(), false) + ") "; + else if (isTopLevel) // top level function + str += retType + "Cls_" + funcName + "::_body" + "(" + FunctionParams(node->GetNodeId(), true) + ") "; + else + str += retType + funcName + "(" + FunctionParams(node->GetNodeId(), false) + ") "; + return str; +} + +// Return class name from class method or class field +std::string CppEmitter::GetClassName(TreeNode* node) { + TreeNode* n = node->GetParent(); + if (n && n->IsClass()) + return n->GetName(); + return ""s; +} + +} // namespace maplefe diff --git a/src/MapleFE/ast2cpp/src/emitter.cpp b/src/MapleFE/ast2cpp/src/emitter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fbf695857eaf577226ec8854914a7f84f48dba2c --- /dev/null +++ b/src/MapleFE/ast2cpp/src/emitter.cpp @@ -0,0 +1,2453 @@ +/* + * Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. + * + * OpenArkFE is licensed under the Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "emitter.h" +#include +#include +#include + +namespace maplefe { + +std::string Emitter::Emit(const char *title) { + std::string code; + code = "// [Beginning of Emitter: "s + title + "\n"s; + code += EmitTreeNode(GetASTModule()); + code += "// End of Emitter]\n"s; + return code; +} + +std::string Emitter::GetEnding(TreeNode *n) { + if (n->IsExport()) { + ExportNode *ex = static_cast(n); + if (ex->GetPairsNum() == 1) { + if (auto p = ex->GetPair(0)->GetBefore()) + n = p; + } + } + if (n->IsDeclare()) { + DeclareNode *d = static_cast(n); + if (d->GetDeclsNum() == 1 && !d->IsGlobal()) + if (auto p = d->GetDeclAtIndex(0)) + n = p; + } + std::string str; + switch(n->GetKind()) { + case NK_Function: + case NK_TripleSlash: + str += '\n'; + break; + default: + str += ';'; + case NK_Block: + case NK_Switch: + case NK_ForLoop: + case NK_WhileLoop: + case NK_DoLoop: + case NK_CondBranch: + case NK_Class: + case NK_Struct: + case NK_Namespace: + case NK_Declare: + case NK_Module: + str += '\n'; + } + return str; +} + +std::string Emitter::Clean(std::string &s) { + auto len = s.length(); + if(len >= 1 && s.back() == '\n') + s = s.erase(len - 1); + if(len >= 2 && s.back() == ';') + return s.erase(len - 2); + return s; +} + +std::string Emitter::GetBaseFilename() { + std::string str(GetASTModule()->GetFilename()); + auto len = str.length(); + if(len >= 3 && str.substr(len - 3) == ".ts") + return str.erase(len - 3); + return str; +} + +std::string Emitter::GetModuleName(const char *p) { + std::string str = p && *p ? p : GetBaseFilename(); + size_t pos = str.rfind("/", std::string::npos); + str = pos == std::string::npos ? str : str.substr(pos); + for (auto &c : str) + if(std::ispunct(c)) + c = '_'; + return "M_"s + str; +} + +std::string Emitter::GetModuleName(TreeNode *node) { + if (node == nullptr) + return std::string(); + std::string str = EmitTreeNode(node); + auto len = str.length(); + if (len <= 2 || str.back() != '"' || str.front() != '"') + return std::string(); + str = str.substr(1, len - 2); + return GetModuleName(str.c_str()); +} + +std::string Emitter::GetEnumAttrId(AttrId k) { + std::string str(AstDump::GetEnumAttrId(k) + 5); + Emitter::Replace(str, "etter", "et"); + str += ' '; + return str; +} + +void Emitter::Replace(std::string &str, const char *o, const char *n, int cnt) { + size_t len = std::strlen(o); + size_t nlen = std::strlen(n); + if(cnt > 0) { + size_t index = 0; + int num = cnt; + do { + index = str.find(o, index); + if (index == std::string::npos) break; + str.replace(index, len, n); + index += nlen; + } while(--num && index < str.size()); + } else { + size_t index = std::string::npos; + int num = cnt ? -cnt : std::numeric_limits::max(); + do { + index = str.rfind(o, index); + if (index == std::string::npos) break; + str.replace(index, len, n); + index -= len; + } while(--num); + } +} + +std::string Emitter::EmitAnnotationNode(AnnotationNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetId()) { + str += EmitTreeNode(n); + } + if (auto num = node->GetArgsNum()) { + str += '('; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetArgAtIndex(i)) + str += EmitTreeNode(n); + } + str += ')'; + } + if (auto n = node->GetType()) { + str += ": "s + EmitAnnotationTypeNode(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitAsTypeNode(AsTypeNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetType()) { + str += " as "s + EmitTreeNode(n); + } + mPrecedence = '\023'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitIdentifierNode(IdentifierNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + + for (unsigned i = 0; i < node->GetAnnotationsNum(); ++i) + if (auto n = node->GetAnnotationAtIndex(i)) + str += '@' + EmitTreeNode(n) + "\n"s; + + std::string accessor1, accessor2; + for (unsigned i = 0; i < node->GetAttrsNum(); ++i) { + std::string s = GetEnumAttrId(node->GetAttrAtIndex(i)); + if (s == "get "s || s == "set "s) + accessor2 += s; + else + accessor1 += s; + } + std::string name(node->GetName()); + if (accessor1 == "private "s && name == "private"s) + str += "#private"s; + else + str += accessor1 + accessor2 + name; + mPrecedence = '\030'; + str = HandleTreeNode(str, node); + //if (auto n = node->GetDims()) { + // str += ' ' + EmitDimensionNode(n); + //} + + if (auto n = node->GetType()) { + std::string s = EmitTreeNode(n); + if(s.length() > 9 && s.substr(0, 9) == "function ") { + std::size_t loc = s.find("("); + if(loc != std::string::npos) + s = s.substr(loc); + } + str += ": "s + s; + } + if (auto n = node->GetInit()) { + str += " = "s + EmitTreeNode(n); + } + return str; +} + +std::string Emitter::EmitFunctionNode(FunctionNode *node) { + if (node == nullptr) + return std::string(); + std::string pre; + for (unsigned i = 0; i < node->GetAnnotationsNum(); ++i) + if (auto n = node->GetAnnotationAtIndex(i)) + pre += '@' + EmitTreeNode(n) + "\n"s; + + auto p = node->GetParent(); + NodeKind k = p ? p->GetKind() : NK_Null; + bool inside = k == NK_Class || k == NK_Struct || k == NK_Interface; + bool func = !inside; + std::string accessor; + for (unsigned i = 0; i < node->GetAttrsNum(); ++i) { + std::string s = GetEnumAttrId(node->GetAttrAtIndex(i)); + if (s == "get "s || s == "set "s) { + func = false; + accessor += s; + } else + pre += s; + } + pre += accessor; + + std::string str; + if (node->IsConstructor()) + str = "constructor "s; + bool has_name; + if(TreeNode* name = node->GetFuncName()) { + std::string s = EmitTreeNode(name); + has_name = s.substr(0, 9) != "__lambda_"; + if (has_name) + str += node->IsIterator() ? "* ["s + s + ']' : s; + } else + has_name = k == NK_XXportAsPair; + + if (node->IsConstructSignature()) + str += "new"s; + + auto num = node->GetTypeParamsNum(); + if(num) { + str += '<'; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetTypeParamAtIndex(i)) { + str += EmitTreeNode(n); + } + } + str += '>'; + } + + /* + for (unsigned i = 0; i < node->GetThrowsNum(); ++i) { + if (auto n = node->GetThrowAtIndex(i)) { + str += ' ' + EmitExceptionNode(n); + } + } + */ + + str += '('; + for (unsigned i = 0; i < node->GetParamsNum(); ++i) { + if (i) + str += ", "s; + if (auto n = node->GetParam(i)) { + str += EmitTreeNode(n); + } + } + str += ')'; + + if (auto n = node->GetAssert()) + str += " : asserts "s + EmitTreeNode(n); + + auto body = node->GetBody(); + if (auto n = node->GetRetType()) { + std::string s = EmitTreeNode(n); + if(!s.empty()) { + str += (body || has_name || inside ? " : "s : " => "s) + s; + if (!body && !has_name) + func = false; + } + } + + str = pre + (func && !node->IsIterator() ? (node->IsGenerator() ? "function* "s : "function "s) : ""s) + str; + + if (body) { + auto s = EmitBlockNode(body); + if(s.empty() || s.front() != '{') + str += '{' + s + "}\n"s; + else + str += s; + } + else + if (k == NK_Block || k == NK_Struct || k == NK_Class) + str += ";\n"s; + /* + if (auto n = node->GetDims()) { + str += ' ' + EmitDimensionNode(n); + } + str += ' ' + std::to_string(node->IsConstructor()); + */ + mPrecedence = '\004'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitUserTypeNode(UserTypeNode *node) { + if (node == nullptr) + return std::string(); + auto k = node->GetType(); + Precedence precd; + switch (k) { + case UT_Union: + precd = '\010'; + break; + case UT_Inter: + precd = '\012'; + break; + default: + precd = '\030'; + } + std::string attrs, accessor, str; + for (unsigned i = 0; i < node->GetAttrsNum(); ++i) { + std::string s = GetEnumAttrId(node->GetAttrAtIndex(i)); + if (s == "get "s || s == "set "s) + accessor += s; + else + attrs += s; + } + attrs += accessor; + if (auto n = node->GetId()) { + str += EmitTreeNode(n); + auto num = node->GetTypeGenericsNum(); + if(num) { + str += '<'; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetTypeGeneric(i)) { + str += EmitTreeNode(n); + } + } + str += '>'; + } + precd = mPrecedence; + } + + if(k != UT_Regular) { + if(!str.empty()) + str = "type "s + str + " = "s; + std::string op = k == UT_Union ? " | "s : " & "s; + for (unsigned i = 0; i < node->GetUnionInterTypesNum(); ++i) { + if(i) + str += op; + std::string s = EmitTreeNode(node->GetUnionInterType(i)); + if (precd >= mPrecedence) + s = '(' + s + ')'; + str += s; + } + mPrecedence = precd; + } + + if (auto n = node->GetDims()) { + std::string s = EmitDimensionNode(n); + if (precd <= mPrecedence) + str = '(' + str + ')'; + str += s; + } + str = attrs + str; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitComputedNameNode(ComputedNameNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + for (unsigned i = 0; i < node->GetAttrsNum(); ++i) { + std::string s = GetEnumAttrId(node->GetAttrAtIndex(i)); + str += s; + } + str += " ["s; + if (auto n = node->GetExpr()) { + str += EmitTreeNode(n); + } + str += "] "s; + + if (auto prop = node->GetProp()) { + if (prop & CNP_Rem_ReadOnly) + str = "-readonly "s + str; + if (prop & CNP_Add_ReadOnly) + str = "readonly "s + str; + if (prop & CNP_Rem_Optional) + str += "-?"s; + if (prop & CNP_Add_Optional) + str += '?'; + } + + str = HandleTreeNode(str, node); + if (auto n = node->GetExtendType()) { + str += ": "s + EmitTreeNode(n); + } + if (auto n = node->GetInit()) { + str += " = "s + EmitTreeNode(n); + } + return str; +} + +std::string Emitter::EmitPackageNode(PackageNode *node) { + if (node == nullptr) + return std::string(); + std::string str = "package"; + if (auto n = node->GetPackage()) { + str += ' ' + EmitTreeNode(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitXXportAsPairNode(XXportAsPairNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (node->IsDefault()) { + if (auto n = node->GetBefore()) + str += "default "s + EmitTreeNode(n); + } else if (node->IsEverything()) { + str += " * "s; + if (auto n = node->GetBefore()) + str += "as "s + EmitTreeNode(n); + } else if (node->IsSingle()) { + if (auto a = node->GetAfter()) + str += EmitTreeNode(a); + if (auto n = node->GetBefore()) { + str += " = "s; + std::string s = EmitTreeNode(n); + str += n->IsLiteral() ? "require("s + s + ')' : s; + } + } else if (node->GetAsNamespace()) { + if (auto n = node->GetBefore()) + str += " as namespace "s + EmitTreeNode(n); + } else { + if (auto n = node->GetBefore()) { + std::string s = EmitTreeNode(n); + if (auto a = node->GetAfter()) + s += " as "s + EmitTreeNode(a); + if (n->IsIdentifier()) + s = "{ "s + s + " }"s; + str += s; + } + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitDeclareNode(DeclareNode *node) { + if (node == nullptr) + return std::string(); + std::string str, accessor; + for (unsigned i = 0; i < node->GetAttrsNum(); ++i) { + std::string s = GetEnumAttrId(node->GetAttrAtIndex(i)); + if (s == "get "s || s == "set "s) + accessor += s; + else + str += s; + } + str += accessor; + + unsigned num = node->GetDeclsNum(); + if (node->IsGlobal() || num != 1) { + str += "declare "s; + if (node->IsGlobal()) { + TreeNode *n = node; + while(n = n->GetParent()) + if (n->IsDeclare()) { + str = std::string(); + break; + } + str += "global "s; + } + str += "{\n"s; + for (unsigned i = 0; i < num; ++i) { + if (auto n = node->GetDeclAtIndex(i)) + str += EmitTreeNode(n) + GetEnding(n); + } + str += "}\n"s; + } else { + if (auto n = node->GetDeclAtIndex(0)) { + std::string s = EmitTreeNode(n); + str += "declare "s + s; + } + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitExportNode(ExportNode *node) { + if (node == nullptr) + return std::string(); + std::string deco; + for (unsigned i = 0; i < node->GetAnnotationsNum(); ++i) + if (auto n = node->GetAnnotationAtIndex(i)) + deco += '@' + EmitTreeNode(n) + "\n"s; + + std::string str; + auto num = node->GetPairsNum(); + if (num == 1 && node->GetTarget() == nullptr) + if (XXportAsPairNode *pair = node->GetPair(0)) + if (auto b = pair->GetBefore()) + if (b->IsModule() && pair->GetAfter() == nullptr) + return "export "s + EmitTreeNode(b); + for (unsigned i = 0; i < num; ++i) { + if (auto n = node->GetPair(i)) { + std::string s = EmitXXportAsPairNode(n); + if (!s.empty() && s.front() == '{' && !str.empty() && str.back() == '}') { + str.pop_back(); + s.erase(0, 1); + } + str += i ? ", "s + s : s; + } + } + if (auto n = node->GetTarget()) { + str += " from "s + EmitTreeNode(n); + } + str = Clean(str); + if (str.empty()) + str = "{}"s; + str = deco + (node->IsExportType() ? "export type "s : "export "s) + str; + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitImportNode(ImportNode *node) { + if (node == nullptr) + return std::string(); + std::string str("import "); + if (node->IsImportType()) + str += "type "s; + /* + switch (node->GetProperty()) { + case ImpNone: + break; + case ImpType: + break; + case ImpStatic: + break; + case ImpSingle: + break; + case ImpAll: + break; + case ImpLocal: + break; + case ImpSystem: + break; + default: + MASSERT(0 && "Unexpected enumerator"); + } + */ + auto num = node->GetPairsNum(); + if (num == 1 && node->GetTarget() == nullptr) + if (XXportAsPairNode *pair = node->GetPair(0)) + if (auto a = pair->GetAfter()) + if (auto b = pair->GetBefore()) + if (a->IsIdentifier() && !b->IsLiteral()) { + str += EmitTreeNode(a) + " = "s + EmitTreeNode(b); + return HandleTreeNode(str, node); + } + + for (unsigned i = 0; i < node->GetPairsNum(); ++i) { + if (auto n = node->GetPair(i)) { + std::string s = EmitXXportAsPairNode(n); + auto len = s.length(); + if(len > 13 && s.substr(len - 13) == " as default }"s) + s = s.substr(1, len - 13); // default export from a module + if(len > 8 && s.substr(0, 8) == "default "s) + s = s.substr(8, len - 1); + if (!s.empty() && s.front() == '{' && !str.empty() && str.back() == '}') { + str.pop_back(); + s.erase(0, 1); + } + str += i ? ", "s + s : s; + } + } + if (auto n = node->GetTarget()) { + std::string s = EmitTreeNode(n); + if (num) + str += " from "s + s; + else { + auto p = node->GetParent(); + if (p && (p->IsField() || p->IsTypeOf() || p->IsAwait())) + str += '(' + s + ')'; + else + str += s; + } + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitUnaOperatorNode(UnaOperatorNode *node) { + if (node == nullptr) + return std::string(); + bool isPost = node->IsPost(); + const char *op = Emitter::GetEnumOprId(node->GetOprId()); + const Precedence precd = *op & 0x3f; + const bool rl_assoc = *op >> 6; // false: left-to-right, true: right-to-left + std::string opr; + if (auto n = node->GetOpnd()) { + opr = EmitTreeNode(n); + if(precd > mPrecedence || (precd == mPrecedence && (rl_assoc && isPost || !rl_assoc && !isPost))) + opr = '(' + opr + ')'; + } + else + opr = "(NIL)"s; + std::string str; + if(node->IsPost()) + str = opr + std::string(op + 1) + ' '; + else + str = ' ' + std::string(op + 1) + opr; + mPrecedence = precd; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitBinOperatorNode(BinOperatorNode *node) { + if (node == nullptr) + return std::string(); + const char *op = Emitter::GetEnumOprId(node->GetOprId()); + const Precedence precd = *op & 0x3f; + const bool rl_assoc = *op >> 6; // false: left-to-right, true: right-to-left + std::string lhs, rhs; + if (auto n = node->GetOpndA()) { + lhs = EmitTreeNode(n); + if(precd > mPrecedence || (precd == mPrecedence && rl_assoc)) + lhs = '(' + lhs + ')'; + } + else + lhs = "(NIL) "s; + if (auto n = node->GetOpndB()) { + rhs = EmitTreeNode(n); + if(precd > mPrecedence || (precd == mPrecedence && !rl_assoc)) + rhs = '(' + rhs + ')'; + } + else + rhs = " (NIL)"s; + std::string str(lhs + ' ' + std::string(op + 1) + ' ' + rhs); + mPrecedence = precd; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitTerOperatorNode(TerOperatorNode *node) { + if (node == nullptr) + return std::string(); + const Precedence precd = '\004'; + const bool rl_assoc = true; // true: right-to-left + std::string str; + if (auto n = node->GetOpndA()) { + str = EmitTreeNode(n); + if(precd > mPrecedence || (precd == mPrecedence && rl_assoc)) + str = '(' + str + ')'; + } + str += " ? "s; + if (auto n = node->GetOpndB()) { + str += EmitTreeNode(n); + } + str += " : "s; + if (auto n = node->GetOpndC()) { + auto s = EmitTreeNode(n); + if(precd > mPrecedence) + s = '(' + s + ')'; + str += s; + } + mPrecedence = '\004'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitTypeAliasNode(TypeAliasNode *node) { + if (node == nullptr) + return std::string(); + std::string str("type "); + if (auto n = node->GetId()) { + str += EmitUserTypeNode(n); + } + if (auto n = node->GetAlias()) { + str += " = "s + EmitTreeNode(n); + } + mPrecedence = '\030'; + return str; +} + +std::string Emitter::EmitConditionalTypeNode(ConditionalTypeNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + Precedence precd = '\030'; + if (auto n = node->GetTypeA()) { + str = EmitTreeNode(n); + precd = mPrecedence; + } + if (auto n = node->GetTypeB()) { + str = Clean(str); + if (precd < '\024') + str = '(' + str + ')'; + str += " extends "s + EmitTreeNode(n); + } + if (auto n = node->GetTypeC()) { + str += " ? "s + EmitTreeNode(n); + } + if (auto n = node->GetTypeD()) { + str += " : "s + EmitTreeNode(n); + } + mPrecedence = '\004'; + return str; +} + +std::string Emitter::EmitTypeParameterNode(TypeParameterNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetId()) { + str = EmitTreeNode(n); + } + if (auto n = node->GetExtends()) { + str += " extends "s + EmitTreeNode(n); + } + if (auto n = node->GetDefault()) { + str += " = "s + EmitTreeNode(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitBlockNode(BlockNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if(auto n = node->GetLabel()) { + str = EmitTreeNode(n) + ":\n"s; + } + str += "{\n"s; + for (unsigned i = 0; i < node->GetChildrenNum(); ++i) { + if (auto n = node->GetChildAtIndex(i)) { + str += EmitTreeNode(n) + GetEnding(n); + } + } + str += "}\n"s; + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitNewNode(NewNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + for (unsigned i = 0; i < node->GetAttrsNum(); ++i) + str += GetEnumAttrId(node->GetAttrAtIndex(i)); + str += "new"s; + if (auto id = node->GetId()) { + std::string idstr = EmitTreeNode(id); + if (mPrecedence <= '\024' + && !id->IsUserType() + && !id->IsLambda() + && !id->IsFunction()) + idstr = '(' + idstr + ')'; + str += ' ' + idstr; + if(!id->IsFunction() && !id->IsLambda() && !id->IsClass()) { + auto num = node->GetArgsNum(); + str += '('; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetArg(i)) { + str += EmitTreeNode(n); + } + } + str += ')'; + } + } + if (auto n = node->GetBody()) { + str += ' ' + EmitBlockNode(n); + } + // Set mPrecedence, e.g. type AType = (new () => Error)|Error; + mPrecedence = '\004'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitDeleteNode(DeleteNode *node) { + if (node == nullptr) + return std::string(); + std::string str("delete "s); + if (auto n = node->GetExpr()) { + str += EmitTreeNode(n); + } + mPrecedence = '\021'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitAnnotationTypeNode(AnnotationTypeNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetId()) { + str += ' ' + EmitIdentifierNode(n); + } + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitDimensionNode(DimensionNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + for (unsigned i = 0; i < node->GetDimensionsNum(); ++i) { + auto n = node->GetDimension(i); + std::string d(n ? std::to_string(n) : ""s); + str += '[' + d + ']'; + } + mPrecedence = '\024'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitDeclNode(DeclNode *node) { + if (node == nullptr) + return std::string(); + std::string str(Emitter::GetEnumDeclProp(node->GetProp())); + if (auto n = node->GetVar()) { + str += ' ' + EmitTreeNode(n); + } + if (auto n = node->GetInit()) { + str += " = "s + EmitTreeNode(n); + } + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitCastNode(CastNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetDestType()) { + str += '<' + EmitTreeNode(n) + ">"; + } + if (auto n = node->GetExpr()) { + str += EmitTreeNode(n); + } + mPrecedence = '\021'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitParenthesisNode(ParenthesisNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetExpr()) { + str += '(' + EmitTreeNode(n) + ')'; + } + mPrecedence = '\025'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitFieldNode(FieldNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + const Precedence precd = '\024'; + if (auto n = node->GetUpper()) { + str = EmitTreeNode(n); + if (precd > mPrecedence) + str = '(' + str + ')'; + } + if (auto n = node->GetField()) { + str += '.' + EmitTreeNode(n); + } + mPrecedence = precd; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitArrayElementNode(ArrayElementNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetArray()) { + str = EmitTreeNode(n); + if(mPrecedence < '\024') + str = '(' + str + ')'; + } + str = Clean(str); + for (unsigned i = 0; i < node->GetExprsNum(); ++i) { + if (auto n = node->GetExprAtIndex(i)) { + if (str.back() == '?') + str += '.'; + str += '[' + EmitTreeNode(n) + ']'; + } + } + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitArrayLiteralNode(ArrayLiteralNode *node) { + if (node == nullptr) + return std::string(); + std::string str("["); + for (unsigned i = 0; i < node->GetLiteralsNum(); ++i) { + if (i) + str += ", "s; + if (auto n = node->GetLiteral(i)) { + str += EmitTreeNode(n); + } + } + str += ']'; + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitBindingElementNode(BindingElementNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetVariable()) { + str += EmitTreeNode(n); + } + if (auto n = node->GetElement()) { + if (!str.empty()) + str += ": "s; + str += EmitTreeNode(n); + } + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitBindingPatternNode(BindingPatternNode *node) { + if (node == nullptr) + return std::string(); + // Needs a flag to distinguish between array destructuring and object destructuring + // Object destructuring: optional-prop.ts + // Array destructuring: trailing-commas.ts + std::string str; + + for (unsigned i = 0; i < node->GetElementsNum(); ++i) { + if (i) + str += ", "s; + if (auto n = node->GetElement(i)) { + str += EmitTreeNode(n); + } + } + + if (node->GetProp() == BPP_ArrayBinding) + str = '[' + str + ']'; + else + str = '{' + str + '}'; + str = HandleTreeNode(str, node); + + if (auto n = node->GetType()) { + str += ": "s + EmitTreeNode(n); + } + if (auto n = node->GetInit()) { + str += " = "s + EmitTreeNode(n); + } + mPrecedence = '\030'; + return str; +} + +std::string Emitter::EmitNumIndexSigNode(NumIndexSigNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetKey()) + str += "[ "s + EmitTreeNode(n) + " : number ]"; + if (auto n = node->GetDataType()) { + str += " : "s + EmitTreeNode(n); + } + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitStrIndexSigNode(StrIndexSigNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetKey()) + str += "[ "s + EmitTreeNode(n) + " : string ]"; + if (auto n = node->GetDataType()) { + str += " : "s + EmitTreeNode(n); + } + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +static std::string MethodString(std::string &func) { + size_t s = func.substr(0, 9) == "function " ? 9 : 0; + return func.back() == '}' ? func.substr(s) + "\n"s : func.substr(s) + ";\n"s; +} + +std::string Emitter::EmitStructNode(StructNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + const char *suffix = ";\n"; + switch(node->GetProp()) { + case SProp_CStruct: + str = "struct "s; + break; + case SProp_TSInterface: + str = "interface "s; + break; + case SProp_TSEnum: + str = "enum "s; + suffix = ",\n"; + break; + case SProp_NA: + str = ""s; + break; + default: + MASSERT(0 && "Unexpected enumerator"); + } + + if (auto n = node->GetStructId()) { + str += EmitIdentifierNode(n); + if (str.substr(0,16) == "AnonymousStruct_") + str = "class "s + str; + } + + auto num = node->GetTypeParamsNum(); + if(num) { + str += '<'; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetTypeParamAtIndex(i)) + str += EmitTreeNode(n); + } + str += '>'; + } + + for (unsigned i = 0; i < node->GetSupersNum(); ++i) { + str += i ? ", "s : " extends "s; + if (auto n = node->GetSuper(i)) + str += EmitTreeNode(n); + } + str += " {\n"s; + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (auto n = node->GetField(i)) { + str += EmitTreeNode(n) + suffix; + } + } + + if (auto n = node->GetNumIndexSig()) { + str += EmitNumIndexSigNode(n) + "\n"s;; + } + if (auto n = node->GetStrIndexSig()) { + str += EmitStrIndexSigNode(n) + "\n"; + } + + for (unsigned i = 0; i < node->GetMethodsNum(); ++i) { + if (auto n = node->GetMethod(i)) { + std::string func = EmitFunctionNode(n); + func = Clean(func); + str += MethodString(func); + } + } + + str += "}\n"s; + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitFieldLiteralNode(FieldLiteralNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + auto lit = node->GetLiteral(); + if (auto n = node->GetFieldName()) { + if(lit && lit->IsFunction() && + static_cast(lit)->GetFuncName() == n) { + str = EmitTreeNode(lit); + if (str.substr(0, 9) == "function ") + str = str.substr(9); + lit = nullptr; + } else { + str = EmitTreeNode(n); + if(lit) + str += ": "s; + } + } + if(lit) { + auto s = EmitTreeNode(lit); + if(s.size() > 4 && (s[0] == 's' || s[0] == 'g') && !s.compare(1, 3, "et ")) + str = s; + else + str += s; + } + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitStructLiteralNode(StructLiteralNode *node) { + if (node == nullptr) + return std::string(); + std::string str("{"); + auto num = node->GetFieldsNum(); + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetField(i)) { + str += EmitFieldLiteralNode(n); + } + } + + // Workaround for an identifier issue + if (num > 1 && str.length() > 6 && + (str.substr(str.length() - 6) == ": true" || + str.substr(str.length() - 7) == ": false")) + str += ','; + + str += '}'; + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitNamespaceNode(NamespaceNode *node) { + if (node == nullptr) + return std::string(); + std::string str("namespace "); + if (auto n = node->GetId()) { + std::string s = EmitTreeNode(n); + str += Clean(s); + } + str += " {\n"s; + for (unsigned i = 0; i < node->GetElementsNum(); ++i) { + if (auto n = node->GetElementAtIndex(i)) { + str += EmitTreeNode(n) + GetEnding(n); + } + } + str += "}\n"s; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitVarListNode(VarListNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + + for (unsigned i = 0; i < node->GetVarsNum(); ++i) { + if (auto n = node->GetVarAtIndex(i)) { + str += ' ' + EmitIdentifierNode(n); + } + } + + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitExprListNode(ExprListNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + + for (unsigned i = 0; i < node->GetExprsNum(); ++i) { + if (auto n = node->GetExprAtIndex(i)) { + str += ' ' + EmitTreeNode(n); + } + } + + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitTemplateLiteralNode(TemplateLiteralNode *node) { + if (node == nullptr) + return std::string(); + std::string str("`"); + auto num = node->GetTreesNum(); + for (unsigned i = 0; i < num; ++i) { + if (auto n = node->GetTreeAtIndex(i)) { + std::string s(EmitTreeNode(n)); + if (i & 0x1) + str += "${"s + s+ '}'; + else + str += s.front() == '"' && s.back() == '"' && s.size() >= 2 ? s.substr(1, s.size() - 2) : s; + } + } + str += '`'; + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitLiteralNode(LiteralNode *node) { + if (node == nullptr) + return std::string(); + LitData lit = node->GetData(); + std::string str(AstDump::GetEnumLitData(lit)); + if(lit.mType == LT_StringLiteral || lit.mType == LT_CharacterLiteral) + str = '"' + str + '"'; + mPrecedence = '\030'; + str = HandleTreeNode(str, node); + if (auto n = node->GetType()) { + str += ": "s + EmitTreeNode(n); + } + if (auto n = node->GetInit()) { + str += " = "s + EmitTreeNode(n); + } + return str; +} + +std::string Emitter::EmitRegExprNode(RegExprNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (const char* e = node->GetData().mExpr) + str = "/"s + e + '/'; + if (const char* f = node->GetData().mFlags) + str += f; + return str; +} + +std::string Emitter::EmitThrowNode(ThrowNode *node) { + if (node == nullptr) + return std::string(); + std::string str("throw "); + for (unsigned i = 0; i < node->GetExceptionsNum(); ++i) { + if (auto n = node->GetExceptionAtIndex(i)) { + str += EmitTreeNode(n); + } + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitCatchNode(CatchNode *node) { + if (node == nullptr) + return std::string(); + std::string str("catch"); + unsigned num = node->GetParamsNum(); + if (num > 0) { + str += '('; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetParamAtIndex(i)) { + str += EmitTreeNode(n); + } + } + str += ')'; + } + if (auto n = node->GetBlock()) { + str += EmitBlockNode(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitFinallyNode(FinallyNode *node) { + if (node == nullptr) + return std::string(); + std::string str("finally "); + if (auto n = node->GetBlock()) { + str += EmitBlockNode(n); + } + else + str += "{}\n"s; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitTryNode(TryNode *node) { + if (node == nullptr) + return std::string(); + std::string str("try "); + if (auto n = node->GetBlock()) { + str += EmitBlockNode(n); + } + for (unsigned i = 0; i < node->GetCatchesNum(); ++i) { + if (auto n = node->GetCatchAtIndex(i)) { + str += EmitCatchNode(n); + } + } + if (auto n = node->GetFinally()) { + str += EmitFinallyNode(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitExceptionNode(ExceptionNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetException()) { + str += ' ' + EmitIdentifierNode(n); + } + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitReturnNode(ReturnNode *node) { + if (node == nullptr) + return std::string(); + std::string str("return"); + if (auto n = node->GetResult()) { + str += ' ' + EmitTreeNode(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitYieldNode(YieldNode *node) { + if (node == nullptr) + return std::string(); + std::string str(node->IsTransfer() ? "yield* " : "yield "); + if (auto n = node->GetResult()) { + str += EmitTreeNode(n); + } + mPrecedence = '\024'; + return str; +} + +std::string Emitter::EmitCondBranchNode(CondBranchNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if(auto n = node->GetLabel()) { + str = EmitTreeNode(n) + ":\n"s; + } + str += "if("s; + if (auto n = node->GetCond()) { + auto cond = EmitTreeNode(n); + str += Clean(cond); + } + str += ")\n"s; + if (auto n = node->GetTrueBranch()) { + str += EmitTreeNode(n) + GetEnding(n); + } + if (auto n = node->GetFalseBranch()) { + str += "else\n"s + EmitTreeNode(n) + GetEnding(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitBreakNode(BreakNode *node) { + if (node == nullptr) + return std::string(); + std::string str("break"); + if (auto n = node->GetTarget()) { + str += ' ' + EmitTreeNode(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitContinueNode(ContinueNode *node) { + if (node == nullptr) + return std::string(); + std::string str("continue"); + if (auto n = node->GetTarget()) { + str += ' ' + EmitTreeNode(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitForLoopNode(ForLoopNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if(auto n = node->GetLabel()) { + str = EmitTreeNode(n) + ":\n"s; + } + str += "for("s; + switch(node->GetProp()) { + case FLP_Regular: + { + for (unsigned i = 0; i < node->GetInitsNum(); ++i) + if (auto n = node->GetInitAtIndex(i)) { + std::string init = EmitTreeNode(n); + if (i) { + str += ", "s; + if(init.substr(0, 4) == "let " || init.substr(0, 4) == "var ") + init = init.substr(4); + else if(init.substr(0, 6) == "const ") + init = init.substr(6); + } + str += init; + } + str += "; "s; + if (auto n = node->GetCond()) { + str += EmitTreeNode(n); + } + str += "; "s; + for (unsigned i = 0; i < node->GetUpdatesNum(); ++i) + if (auto n = node->GetUpdateAtIndex(i)) { + if (i) + str += ", "s; + str += EmitTreeNode(n); + } + break; + } + case FLP_JSIn: + { + if (auto n = node->GetVariable()) { + str += EmitTreeNode(n); + } + str += " in "s; + if (auto n = node->GetSet()) { + str += EmitTreeNode(n); + } + break; + } + case FLP_JSOf: + { + if (auto n = node->GetVariable()) { + str += EmitTreeNode(n); + } + str += " of "s; + if (auto n = node->GetSet()) { + str += EmitTreeNode(n); + } + break; + } + case FLP_NA: + return "FLP_NA"s; + default: + MASSERT(0 && "Unexpected enumerator"); + } + str += ')'; + + if (auto n = node->GetBody()) { + str += EmitTreeNode(n) + GetEnding(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitWhileLoopNode(WhileLoopNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if(auto n = node->GetLabel()) { + str = EmitTreeNode(n) + ":\n"s; + } + str += "while("s; + if (auto n = node->GetCond()) { + str += EmitTreeNode(n); + } + str += ')'; + if (auto n = node->GetBody()) { + str += EmitTreeNode(n) + GetEnding(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitDoLoopNode(DoLoopNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if(auto n = node->GetLabel()) { + str = EmitTreeNode(n) + ":\n"s; + } + str += "do "s; + if (auto n = node->GetBody()) { + str += EmitTreeNode(n); + } + str += "while("s; + if (auto n = node->GetCond()) { + str += EmitTreeNode(n); + } + str += ");\n"s; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitSwitchLabelNode(SwitchLabelNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if(node->IsDefault()) + str += "default:\n"s; + if(auto n = node->GetValue()) { + auto ce = EmitTreeNode(n); + str += "case "s + Clean(ce) + ":\n"s; + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitSwitchCaseNode(SwitchCaseNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + for (unsigned i = 0; i < node->GetLabelsNum(); ++i) { + if (auto n = node->GetLabelAtIndex(i)) { + str += EmitTreeNode(n); + } + } + for (unsigned i = 0; i < node->GetStmtsNum(); ++i) { + if (auto n = node->GetStmtAtIndex(i)) + str += EmitTreeNode(n) + GetEnding(n); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitSwitchNode(SwitchNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if(auto n = node->GetLabel()) { + str = EmitTreeNode(n) + ":\n"s; + } + str += "switch("s; + if (auto n = node->GetExpr()) { + auto expr = EmitTreeNode(n); + str += Clean(expr); + } + str += "){\n"s; + for (unsigned i = 0; i < node->GetCasesNum(); ++i) { + if(auto n = node->GetCaseAtIndex(i)) + str += EmitTreeNode(n); + } + str += "}\n"s; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitAssertNode(AssertNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetExpr()) { + str += ' ' + EmitTreeNode(n); + } + if (auto n = node->GetMsg()) { + str += ' ' + EmitTreeNode(n); + } + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitCallNode(CallNode *node) { + if (node == nullptr) + return std::string(); + // Function call: left-to-right, precedence = 20 + std::string str; + if (auto n = node->GetMethod()) { + std::string s = EmitTreeNode(n); + bool optional = n->IsOptional(); + if (optional && !s.empty() && s.back() == '?') + s.pop_back(); + if(n->IsFunction() || n->IsLambda() || n->IsTerOperator()) + str += '(' + s + ')'; + else + str += s; + if (optional) + str += "?."s; // for optional chaining + } + if(auto num = node->GetTypeArgumentsNum()) { + str += '<'; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetTypeArgumentAtIndex(i)) { + str += EmitTreeNode(n); + } + } + str += '>'; + } + if (auto tagged = node->GetTaggedTemplate()) { + str += EmitTreeNode(tagged); + } else { + str += '('; + for (unsigned i = 0; i < node->GetArgsNum(); ++i) { + if (i) + str += ", "s; + if (auto n = node->GetArg(i)) + str += EmitTreeNode(n); + } + str += ')'; + } + mPrecedence = '\024'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitInterfaceNode(InterfaceNode *node) { + if (node == nullptr) + return std::string(); + std::string str = "interface "s + node->GetName(); + + /* + auto num = node->GetTypeParamsNum(); + if(num) { + str += '<'; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetTypeParamAtIndex(i)) + str += EmitTreeNode(n); + } + str += '>'; + } + */ + + for (unsigned i = 0; i < node->GetSuperInterfacesNum(); ++i) { + str += i ? ", "s : " implements "s; + if (auto n = node->GetSuperInterfaceAtIndex(i)) + str += EmitTreeNode(n); + } + str += " {\n"s; + + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (auto n = node->GetField(i)) { + str += EmitIdentifierNode(n) + ";\n"s; + } + } + + for (unsigned i = 0; i < node->GetMethodsNum(); ++i) { + if (auto n = node->GetMethod(i)) { + std::string func = EmitFunctionNode(n); + func = Clean(func); + str += MethodString(func); + } + } + + str += "}\n"s; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitClassNode(ClassNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + for (unsigned i = 0; i < node->GetAnnotationsNum(); ++i) + if (auto n = node->GetAnnotationAtIndex(i)) + str += '@' + EmitTreeNode(n) + "\n"s; + + for (unsigned i = 0; i < node->GetAttributesNum(); ++i) + str += GetEnumAttrId(node->GetAttribute(i)); + + str += "class "s + node->GetName(); + + auto num = node->GetTypeParamsNum(); + if(num) { + str += '<'; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetTypeParamAtIndex(i)) + str += EmitTreeNode(n); + } + str += '>'; + } + + auto classNum = node->GetSuperClassesNum(); + for (unsigned i = 0; i < classNum; ++i) { + str += i ? ", "s : " extends "s; + if (auto n = node->GetSuperClass(i)) { + std::string s = EmitTreeNode(n); + str += mPrecedence > '\023' ? s : '(' + s + ')'; + } + } + for (unsigned i = 0; i < node->GetSuperInterfacesNum(); ++i) { + str += i ? ", "s : " implements "s; + if (auto n = node->GetSuperInterface(i)) + str += EmitTreeNode(n); + } + str += " {\n"s; + + for (unsigned i = 0; i < node->GetDeclaresNum(); ++i) { + if (auto n = node->GetDeclare(i)) { + std::string s = EmitTreeNode(n); + Replace(s, " var ", " "); // TODO: JS_Var for field + str += s + ";\n"s; + } + } + + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (auto n = node->GetField(i)) { + str += EmitTreeNode(n) + ";\n"s; + } + } + + for (unsigned i = 0; i < node->GetConstructorsNum(); ++i) { + if (auto n = node->GetConstructor(i)) { + std::string func = EmitFunctionNode(n); + if (func.substr(0, 9) == "function ") + func = func.substr(9); + func = Clean(func); + str += func.back() == '}' ? func + "\n"s : func + ";\n"s; + } + } + + for (unsigned i = 0; i < node->GetMethodsNum(); ++i) { + if (FunctionNode *n = node->GetMethod(i)) { + std::string func = EmitFunctionNode(n); + func = Clean(func); + str += MethodString(func); + } + } + + for (unsigned i = 0; i < node->GetInstInitsNum(); ++i) { + if (auto n = node->GetInstInit(i)) { + str += EmitBlockNode(n) + "\n"s; + } + } + + for (unsigned i = 0; i < node->GetLocalClassesNum(); ++i) { + if (auto n = node->GetLocalClass(i)) { + str += EmitClassNode(n) + "\n"s; + } + } + + for (unsigned i = 0; i < node->GetLocalInterfacesNum(); ++i) { + if (auto n = node->GetLocalInterface(i)) { + str += EmitInterfaceNode(n) + "\n"s; + } + } + + str += "}\n"; + mPrecedence = '\020'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitPassNode(PassNode *node) { + if (node == nullptr) + return std::string(); + std::string str("PassNode {"); + + for (unsigned i = 0; i < node->GetChildrenNum(); ++i) { + if (auto n = node->GetChild(i)) { + str += ' ' + EmitTreeNode(n); + } + } + + str += '}'; + mPrecedence = '\030'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitLambdaNode(LambdaNode *node) { + if (node == nullptr) + return std::string(); + switch (node->GetProperty()) { + case LP_JSArrowFunction: + break; + case LP_JavaLambda: + case LP_NA: + default: + MASSERT(0 && "Unexpected enumerator"); + } + + std::string str; + for (unsigned i = 0; i < node->GetAttrsNum(); ++i) + str += GetEnumAttrId(node->GetAttrAtIndex(i)); + auto num = node->GetTypeParamsNum(); + if(num) { + str += '<'; + for (unsigned i = 0; i < num; ++i) { + if (i) + str += ", "s; + if (auto n = node->GetTypeParamAtIndex(i)) { + str += EmitTreeNode(n); + } + } + str += '>'; + } + + str += '('; + for (unsigned i = 0; i < node->GetParamsNum(); ++i) { + if (i) + str += ", "s; + if (auto n = node->GetParam(i)) { + str += EmitTreeNode(n); + } + } + str += ')'; + + if (auto n = node->GetBody()) { + if (auto t = node->GetRetType()) { + str += ": "s + EmitTreeNode(t); + } + std::string s = EmitTreeNode(n); + s = Clean(s); + if (n->IsStructLiteral()) + s = '(' + s + ')'; + str += " => "s + s; + } + else { + if (auto t = node->GetRetType()) { + str += " => "s + EmitTreeNode(t); + } + } + + mPrecedence = '\004'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitInstanceOfNode(InstanceOfNode *node) { + if (node == nullptr) + return std::string(); + const Precedence precd = '\014'; + const bool rl_assoc = false; // false: left-to-right + std::string lhs, rhs; + if (auto n = node->GetLeft()) { + lhs = EmitTreeNode(n); + if(precd > mPrecedence) + lhs = '(' + lhs + ')'; + } + else + lhs = "(NIL) "s; + if (auto n = node->GetRight()) { + rhs = EmitTreeNode(n); + if(precd > mPrecedence || (precd == mPrecedence && !rl_assoc)) + rhs = '(' + rhs + ')'; + } + else + rhs = " (NIL)"s; + std::string str(lhs + " instanceof "s + rhs); + mPrecedence = precd; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitTypeOfNode(TypeOfNode *node) { + if (node == nullptr) + return std::string(); + const Precedence precd = '\121' & 0x3f; + std::string str("typeof "s), rhs; + if (auto n = node->GetExpr()) { + rhs = EmitTreeNode(n); + if(precd > mPrecedence && !n->IsConditionalType()) // right-to-left + rhs = '(' + rhs + ')'; + } + else + rhs = " (NIL)"s; + str += rhs; + mPrecedence = precd; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitKeyOfNode(KeyOfNode *node) { + if (node == nullptr) + return std::string(); + const Precedence precd = '\121' & 0x3f; + std::string str("keyof "s), rhs; + if (auto n = node->GetExpr()) { + rhs = EmitTreeNode(n); + if(precd > mPrecedence) + rhs = '(' + rhs + ')'; + } + else + rhs = " (NIL)"s; + str += rhs; + mPrecedence = precd; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitInferNode(InferNode *node) { + if (node == nullptr) + return std::string(); + std::string str("infer "); + if (auto n = node->GetExpr()) { + str += EmitTreeNode(n); + } + mPrecedence = '\024'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitInNode(InNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetLeft()) { + str += EmitTreeNode(n); + } + str += " in "s; + if (auto n = node->GetRight()) { + str += EmitTreeNode(n); + } + mPrecedence = '\014'; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitIsNode(IsNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetLeft()) { + str = EmitTreeNode(n); + } + str += " is "s; + if (auto n = node->GetRight()) { + str += EmitTreeNode(n); + } + return str; +} + +std::string Emitter::EmitAwaitNode(AwaitNode *node) { + if (node == nullptr) + return std::string(); + std::string str("await "s); + if (auto n = node->GetExpr()) { + str += EmitTreeNode(n); + } + mPrecedence = '\023'; + if (node->IsStmt()) + str += ";\n"s; + return str; +} + +std::string Emitter::EmitNameTypePairNode(NameTypePairNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + if (auto n = node->GetVar()) { + str += EmitTreeNode(n) + ": "s; + } + if (auto n = node->GetType()) { + str += EmitTreeNode(n); + } + return str; +} + +std::string Emitter::EmitTupleTypeNode(TupleTypeNode *node) { + if (node == nullptr) + return std::string(); + std::string str("[ "); + + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (i) + str += ", "s; + if (auto n = node->GetField(i)) { + str += EmitNameTypePairNode(n); + } + } + str += " ]"s; + + mPrecedence = '\030'; + return str; +} + +std::string Emitter::EmitTripleSlashNode(TripleSlashNode *node) { + if (node == nullptr) + return std::string(); + std::string str; + str += "/// GetProp()); + if (auto n = node->GetValue()) { + str += '=' + EmitTreeNode(n); + } + str += " />"s; + return str; +} + +std::string Emitter::EmitModuleNode(ModuleNode *node) { + if (node == nullptr) + return std::string(); + + std::string str; + for (unsigned i = 0; i < node->GetTreesNum(); ++i) { + if (auto n = node->GetTree(i)) { + str += EmitTreeNode(n) + GetEnding(n); + } + } + + std::string name = node->GetFilename(); + if (auto p = node->GetParent()) { + if (node->IsAmbient()) + name = '"' + name + '"'; + str = "module "s + name + " {\n"s + str + "}\n"s; + } else + str = "// Filename: "s + name + "\n"s + str; + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitAttrNode(AttrNode *node) { + if (node == nullptr) + return std::string(); + std::string str(GetEnumAttrId(node->GetId())); + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitArrayTypeNode(ArrayTypeNode *node) { + // TODO + std::string str = ""; + return str; +} + +std::string Emitter::EmitFunctionTypeNode(FunctionTypeNode *node) { + // TODO + std::string str = ""; + return str; +} + +std::string Emitter::EmitPrimTypeNode(PrimTypeNode *node) { + if (node == nullptr) + return std::string(); + auto k = node->GetPrimType(); + std::string str = k == TY_None ? std::string() : Emitter::GetEnumTypeId(k); + if (node->IsUnique()) + str = "unique "s + str; + mPrecedence = '\030'; + return str; +} + +std::string Emitter::EmitPrimArrayTypeNode(PrimArrayTypeNode *node) { + if (node == nullptr) + return std::string(); + std::string str, accessor; + for (unsigned i = 0; i < node->GetAttrsNum(); ++i) { + std::string s = GetEnumAttrId(node->GetAttrAtIndex(i)); + if (s == "get "s || s == "set "s) + accessor += s; + else + str += s; + } + str += accessor; + if (auto n = node->GetPrim()) { + str += EmitPrimTypeNode(n); + } + if (auto n = node->GetDims()) { + str += EmitDimensionNode(n); + Replace(str, "never[", "["); + } + return HandleTreeNode(str, node); +} + +std::string Emitter::EmitTreeNode(TreeNode *node) { + if (node == nullptr) + return std::string(); + switch (node->GetKind()) { + case NK_Module: + return EmitModuleNode(static_cast(node)); + break; + case NK_Package: + return EmitPackageNode(static_cast(node)); + break; + case NK_XXportAsPair: + return EmitXXportAsPairNode(static_cast(node)); + break; + case NK_Import: + return EmitImportNode(static_cast(node)); + break; + case NK_Export: + return EmitExportNode(static_cast(node)); + break; + case NK_Declare: + return EmitDeclareNode(static_cast(node)); + break; + case NK_Decl: + return EmitDeclNode(static_cast(node)); + break; + case NK_Identifier: + return EmitIdentifierNode(static_cast(node)); + break; + case NK_Field: + return EmitFieldNode(static_cast(node)); + break; + case NK_Dimension: + return EmitDimensionNode(static_cast(node)); + break; + case NK_Attr: + return EmitAttrNode(static_cast(node)); + break; + case NK_NameTypePair: + return EmitNameTypePairNode(static_cast(node)); + break; + case NK_PrimType: + return EmitPrimTypeNode(static_cast(node)); + break; + case NK_PrimArrayType: + return EmitPrimArrayTypeNode(static_cast(node)); + break; + case NK_ArrayType: + return EmitArrayTypeNode(static_cast(node)); + break; + case NK_FunctionType: + return EmitFunctionTypeNode(static_cast(node)); + break; + case NK_UserType: + return EmitUserTypeNode(static_cast(node)); + break; + case NK_TypeParameter: + return EmitTypeParameterNode(static_cast(node)); + break; + case NK_AsType: + return EmitAsTypeNode(static_cast(node)); + break; + case NK_TypeAlias: + return EmitTypeAliasNode(static_cast(node)); + break; + case NK_ConditionalType: + return EmitConditionalTypeNode(static_cast(node)); + break; + case NK_TupleType: + return EmitTupleTypeNode(static_cast(node)); + break; + case NK_Cast: + return EmitCastNode(static_cast(node)); + break; + case NK_Parenthesis: + return EmitParenthesisNode(static_cast(node)); + break; + case NK_BindingElement: + return EmitBindingElementNode(static_cast(node)); + break; + case NK_BindingPattern: + return EmitBindingPatternNode(static_cast(node)); + break; + case NK_Struct: + return EmitStructNode(static_cast(node)); + break; + case NK_StructLiteral: + return EmitStructLiteralNode(static_cast(node)); + break; + case NK_FieldLiteral: + return EmitFieldLiteralNode(static_cast(node)); + break; + case NK_NumIndexSig: + return EmitNumIndexSigNode(static_cast(node)); + break; + case NK_StrIndexSig: + return EmitStrIndexSigNode(static_cast(node)); + break; + case NK_ComputedName: + return EmitComputedNameNode(static_cast(node)); + break; + case NK_ArrayElement: + return EmitArrayElementNode(static_cast(node)); + break; + case NK_ArrayLiteral: + return EmitArrayLiteralNode(static_cast(node)); + break; + case NK_VarList: + return EmitVarListNode(static_cast(node)); + break; + case NK_ExprList: + return EmitExprListNode(static_cast(node)); + break; + case NK_TemplateLiteral: + return EmitTemplateLiteralNode(static_cast(node)); + break; + case NK_RegExpr: + return EmitRegExprNode(static_cast(node)); + break; + case NK_Literal: + return EmitLiteralNode(static_cast(node)); + break; + case NK_UnaOperator: + return EmitUnaOperatorNode(static_cast(node)); + break; + case NK_BinOperator: + return EmitBinOperatorNode(static_cast(node)); + break; + case NK_TerOperator: + return EmitTerOperatorNode(static_cast(node)); + break; + case NK_Lambda: + return EmitLambdaNode(static_cast(node)); + break; + case NK_InstanceOf: + return EmitInstanceOfNode(static_cast(node)); + break; + case NK_TypeOf: + return EmitTypeOfNode(static_cast(node)); + break; + case NK_KeyOf: + return EmitKeyOfNode(static_cast(node)); + break; + case NK_In: + return EmitInNode(static_cast(node)); + break; + case NK_Is: + return EmitIsNode(static_cast(node)); + break; + case NK_Infer: + return EmitInferNode(static_cast(node)); + break; + case NK_TripleSlash: + return EmitTripleSlashNode(static_cast(node)); + break; + case NK_Block: + return EmitBlockNode(static_cast(node)); + break; + case NK_Function: + return EmitFunctionNode(static_cast(node)); + break; + case NK_Class: + return EmitClassNode(static_cast(node)); + break; + case NK_Interface: + return EmitInterfaceNode(static_cast(node)); + break; + case NK_Namespace: + return EmitNamespaceNode(static_cast(node)); + break; + case NK_AnnotationType: + return EmitAnnotationTypeNode(static_cast(node)); + break; + case NK_Annotation: + return EmitAnnotationNode(static_cast(node)); + break; + case NK_Try: + return EmitTryNode(static_cast(node)); + break; + case NK_Catch: + return EmitCatchNode(static_cast(node)); + break; + case NK_Finally: + return EmitFinallyNode(static_cast(node)); + break; + case NK_Exception: + return EmitExceptionNode(static_cast(node)); + break; + case NK_Throw: + return EmitThrowNode(static_cast(node)); + break; + case NK_Await: + return EmitAwaitNode(static_cast(node)); + break; + case NK_Return: + return EmitReturnNode(static_cast(node)); + break; + case NK_Yield: + return EmitYieldNode(static_cast(node)); + break; + case NK_CondBranch: + return EmitCondBranchNode(static_cast(node)); + break; + case NK_Break: + return EmitBreakNode(static_cast(node)); + break; + case NK_Continue: + return EmitContinueNode(static_cast(node)); + break; + case NK_ForLoop: + return EmitForLoopNode(static_cast(node)); + break; + case NK_WhileLoop: + return EmitWhileLoopNode(static_cast(node)); + break; + case NK_DoLoop: + return EmitDoLoopNode(static_cast(node)); + break; + case NK_New: + return EmitNewNode(static_cast(node)); + break; + case NK_Delete: + return EmitDeleteNode(static_cast(node)); + break; + case NK_Call: + return EmitCallNode(static_cast(node)); + break; + case NK_Assert: + return EmitAssertNode(static_cast(node)); + break; + case NK_SwitchLabel: + return EmitSwitchLabelNode(static_cast(node)); + break; + case NK_SwitchCase: + return EmitSwitchCaseNode(static_cast(node)); + break; + case NK_Switch: + return EmitSwitchNode(static_cast(node)); + break; + case NK_Pass: + return EmitPassNode(static_cast(node)); + break; + case NK_Null: + // Ignore NullNode + break; + default: + MASSERT(0 && "Unexpected node kind"); + } + return std::string(); +} + +std::string &Emitter::AddParentheses(std::string &str, TreeNode *node) { + if (mPrecedence < '\024' || + (!node->IsIdentifier() && + !node->IsField() && + !node->IsInfer() && + !node->IsLiteral() && + !node->IsArrayLiteral() && + !node->IsBindingPattern())) { + str = '(' + str + ')'; + mPrecedence = '\030'; + } + return str; +} + +std::string &Emitter::HandleTreeNode(std::string &str, TreeNode *node) { + auto num = node->GetAsTypesNum(); + if(num > 0) { + if (node->IsBinOperator() || + node->IsUnaOperator() || + node->IsTerOperator() || + node->IsNew()) { + str = '(' + str + ')'; + mPrecedence = '\030'; + } + for (unsigned i = 0; i < num; ++i) + if (auto t = node->GetAsTypeAtIndex(i)) { + str += EmitAsTypeNode(t); + mPrecedence = '\003'; + } + } + if(node->IsOptional()) + str = AddParentheses(str, node) + '?'; + if(node->IsNonNull()) + str = AddParentheses(str, node) + '!'; + if(node->IsRest()) + str = "..."s + AddParentheses(str, node); + if(node->IsConst()) { + str = AddParentheses(str, node) + " as const"s; + mPrecedence = '\003'; + } + return str; +} + +std::string Emitter::GetEnumTypeId(TypeId k) { + std::string str(AstDump::GetEnumTypeId(k) + 3); + if (k != TY_Function && k != TY_Object) + str[0] = std::tolower(str[0]); + return str; +} + +std::string Emitter::GetEnumDeclProp(DeclProp k) { + std::string str(AstDump::GetEnumDeclProp(k) + 3); + if(str != "NA") + str[0] = std::tolower(str[0]); + return str; +} + +const char *Emitter::GetEnumOprId(OprId k) { + // The first char in the returned string includes operator precedence and associativity info + // + // bits 7 6 5 4 3 2 1 0 + // 0 ^ ^---^---^-+-^---^---^ + // | |__ operator precedence + // | + // |__ associativity, 0: left-to-right, 1: right-to-left + // + switch (k) { + case OPR_Plus: + return "\121+"; + case OPR_Add: + return "\016+"; + case OPR_Minus: + return "\121-"; + case OPR_Sub: + return "\016-"; + case OPR_Mul: + return "\017*"; + case OPR_Div: + return "\017/"; + case OPR_Mod: + return "\017%"; + case OPR_PreInc: + return "\121++"; + case OPR_Inc: + return "\022++"; + case OPR_PreDec: + return "\121--"; + case OPR_Dec: + return "\022--"; + case OPR_Exp: + return "\120**"; + case OPR_EQ: + return "\013=="; + case OPR_NE: + return "\013!="; + case OPR_GT: + return "\014>"; + case OPR_LT: + return "\014<"; + case OPR_GE: + return "\014>="; + case OPR_LE: + return "\014<="; + case OPR_Band: + return "\012&"; + case OPR_Bor: + return "\010|"; + case OPR_Bxor: + return "\011^"; + case OPR_Bcomp: + return "\121~"; + case OPR_Shl: + return "\015<<"; + case OPR_Shr: + return "\015>>"; + case OPR_Zext: + return "\015>>>"; + case OPR_Land: + return "\007&&"; + case OPR_Lor: + return "\006||"; + case OPR_Not: + return "\121!"; + case OPR_Assign: + return "\103="; + case OPR_AddAssign: + return "\103+="; + case OPR_SubAssign: + return "\103-="; + case OPR_MulAssign: + return "\103*="; + case OPR_DivAssign: + return "\103/="; + case OPR_ModAssign: + return "\103%="; + case OPR_ShlAssign: + return "\103<<="; + case OPR_ShrAssign: + return "\103>>="; + case OPR_BandAssign: + return "\103&="; + case OPR_BorAssign: + return "\103|="; + case OPR_BxorAssign: + return "\103^="; + case OPR_ZextAssign: + return "\103>>>="; + case OPR_NullAssign: + return "\103??="; + case OPR_Arrow: + return "\030 OPR_Arrow"; + case OPR_Diamond: + return "\030 OPR_Diamond"; + case OPR_StEq: + return "\013==="; + case OPR_StNe: + return "\013!=="; + case OPR_ArrowFunction: + return "\030 OPR_ArrowFunction"; + case OPR_NullCoalesce: + return "\005??"; + case OPR_NA: + return "\030 OPR_NA"; + default: + MASSERT(0 && "Unexpected enumerator"); + } + return "UNEXPECTED OprId"; +} + +const char *Emitter::GetEnumTripleSlashProp(TripleSlashProp k) { + switch (k) { + case TSP_Path: + return "path"; + case TSP_Types: + return "types"; + case TSP_Lib: + return "lib"; + case TSP_NoDefaultLib: + return "no-default-lib"; + case TSP_NA: + return "TSP_NA"; + default: + MASSERT(0 && "Unexpected enumerator"); + } + return "UNEXPECTED TripleSlashProp"; +} + +} // namespace maplefe diff --git a/src/MapleFE/ast2cpp/src/helper.cpp b/src/MapleFE/ast2cpp/src/helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1222f2341802e47bf06284101f033cd65dd21376 --- /dev/null +++ b/src/MapleFE/ast2cpp/src/helper.cpp @@ -0,0 +1,355 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ +#include "helper.h" + +namespace maplefe { + +FuncTable hFuncTable; +GeneratorLabels GenFnLabels; + +std::unordered_mapTypeIdToJSTypeCXX = { + // AST TypeId to t2crt JS_Type mapping for JS_Val type of obj props that pts to CXX class fields + {TY_Object, "t2crt::TY_CXX_Object"}, + {TY_Function,"t2crt::TY_CXX_Function"}, + {TY_Boolean, "t2crt::TY_CXX_Bool"}, + {TY_Int, "t2crt::TY_CXX_Long"}, + {TY_String, "t2crt::TY_CXX_String"}, + {TY_Number, "t2crt::TY_CXX_Double"}, + {TY_Double, "t2crt::TY_CXX_Double"}, + {TY_Array, "t2crt::TY_CXX_Object"}, + {TY_Class, "t2crt::TY_CXX_Object"}, + {TY_Any, "t2crt::TY_CXX_Any"}, +}; + +std::string GeneratorFn_start = R"""( + if (yield != nullptr) + goto *yield; +)"""; + +std::string GeneratorFn_return = R"""( + res.value = undefined; + res.done = true; + return; +)"""; + +// Used to build GetProp for calls to get Object (class Object in ts2cpp.h) property +std::string hlpGetJSValTypeStr(TypeId typeId) { + switch(typeId) { + case TY_Object: + case TY_Class: + return "Obj"; + case TY_Any: + return ""; + case TY_Function: + return "Func"; + case TY_Boolean: + return "bool"; + case TY_Number: + return "Double"; + case TY_String: + return "Str"; + } + return std::string(); +} + +// Get TypeId info for a treenode. +TypeId hlpGetTypeId(TreeNode* node) { + // lookup typetable + if (node->GetTypeIdx()) { + TypeEntry* te = gTypeTable.GetTypeEntryFromTypeIdx(node->GetTypeIdx()); + if (te) + return te->GetTypeId(); + } + + // lookup ast node mTypeId (will be deprecated) + if (node->GetTypeId() != TY_None) { + return node->GetTypeId(); + } + return TY_Any; +} + +// Temp. workaround to get func info for var of type function. TODO: replace with TI API when avail. +std::string GetClassOfAssignedFunc(TreeNode* node) { + if (node->IsIdentifier() && + node->GetParent() && + node->GetParent()->IsDecl() && + static_cast(node->GetParent())->GetInit() && + static_cast(node->GetParent())->GetInit()->IsFunction()) { + auto n = static_cast(node->GetParent())->GetInit(); + return("Cls_"s + static_cast(n)->GetName()); + } + return std::string(); +} + +// Generate call to create obj prop with ptr to c++ class fld member +// e.g. obj->AddProp("fdLong", t2crt::ClassFld(&Foo::fdLong).NewProp(this, t2crt::TY_CXX_Long)) +// obj->AddProp("fdAny", t2crt::ClassFld(&Foo::fdAny).NewProp(this, t2crt::TY_CXX_Any)) +std::string GenClassFldAddProp(std::string objName, + std::string clsName, + std::string fldName, + std::string fldCType, + std::string fldJSType) { + std::string str; + str = objName + "->AddProp(\"" + fldName + "\", t2crt::ClassFld<" + + fldCType + " " + clsName + "::*>(&" + + clsName + "::" + fldName + ").NewProp(this, " + fldJSType + "))"; + return str; +} + +// From TS func param info, generate param and arg list for corresponding mapped C++ func. +// +// Different formats of arg list as needed by C++ mapping of function/class/generators +// - args for function class functor and generation class constructor +// () - generator class constructor field init list +// & - args passed by reference to generation function _body method +// ; - generator class fields for capturing closure +// +std::string FunctionParams(unsigned nodeId, bool handleThis, bool argsOnly, bool byRef, bool fdInit, bool capture) { + std::vector> funcParams = hFuncTable.GetArgInfo(nodeId); + std::string ObjT = "t2crt::Object*"; + std::string str; + + // "this" in TS function paramter mapping to C++: + // + // TS2cpp's C++ mapping for TS func has a "this" obj in the c++ func param list + // which will be generated from AST if "this" is declared as a TS func parameter + // as required by TS strict mode. However TS funcs that do not reference 'this' + // are not required to declare it, in which case emitter has to insert one. + // + // Cases: + // if TS func has no param + // - insert param "ts2crt::Object* _this" + // if 1st TS func param is not "this" + // - insert param "ts2crt::Object* _this" + // if 1st TS func param is "this" + // - rename to "_this" + // - if type is Any (JS_Val), change to "ts2crt::Object*" + // + if (handleThis) { + if (funcParams.size() == 0) // func has no param + return argsOnly ? "_this"s : (ObjT + " _this"); + } + + for (bool first=true; auto elem : funcParams) { + std::string type = elem.first, name = elem.second; + if (!first) + str += ", "s; + else { // 1st param of TS func + if (handleThis) { + if (name.compare("this") != 0) // if not "this", insert _this + str += argsOnly? ("_this, "s): (ObjT + " _this, "s); + else { // if "this" + name = "_this"; // rename to "_this" + if (type.compare("t2crt::JS_Val") == 0) + type = ObjT; // change type Any to Object* + } + } + first = false; + } + if (fdInit) + str += name + "(" + name + ")"; + else if (capture) + str += type + " " + name + ";\n"; + else + str += argsOnly? name: (type + (byRef?"\&":"") + " "s + name); + } + return str; +} + +// Each first level function is instantiated from a corresponding class generated with interfaces below: +// Body - user defined function code +// () - functor for OrdinaryCallEvaluteBody [9.2.1.3] +// Ctor - Call user defined code as constructor (with object from new() op) +// Call - Call user defined code with designated 'this' +// Apply - Call user defined code with designated 'this' and array of argument +// Bind - Create and return function object binded to designated this and optional args +// note: the parameter args is expected to be a string that start with "_this" +// TODO: apply and bind may be moved to ts2cpp.h Fuction class as virtual +// note: TSC prohibits calling non-void constructor func with new(), so in the code generated below +// for ctor(), it calls _body() but ignores return val from _body(), and instead returns _this +// per TS/JS spec. + +std::string FunctionClassDecl(std::string retType, std::string funcName, unsigned nodeId) { + std::string str, args, params, thisType; + + std::string clsName = ClsName(funcName); + params = FunctionParams(nodeId, true, false); + args = FunctionParams(nodeId, true, true); + thisType = params.substr(0, params.find(" ")); // extract return type of "this" parameter + + std::string functorParams = params; + std::string functorArgs = args; + functorArgs.replace(0, 5, "_thisArg"); // replace _this with _thisArg + size_t pos; + if ((pos = functorParams.find("_this, ")) != std::string::npos) + functorParams.erase(0, pos+7); + else if ((pos = functorParams.find("_this")) != std::string::npos) + functorParams.erase(0, pos+5); + + str = R"""( +class )""" + clsName + R"""( : public t2crt::Function { + public: + )""" + clsName + R"""(() : t2crt::Function(&t2crt::Function::ctor,t2crt::Function::ctor.prototype,t2crt::Object::ctor.prototype) {} + ~)""" + clsName + R"""(() {} + + )""" + retType + R"""( _body()""" + params + R"""(); + )""" + retType + R"""( operator()()""" + functorParams + R"""() { return _body(()""" + thisType + R"""())""" + functorArgs + R"""(); } + t2crt::Object* ctor ()""" + params + R"""() { _body()""" + args + R"""(); return(_this); } + )""" + retType + R"""( call ()""" + params + R"""() { return _body()""" + args + R"""( ); } + )""" + retType + R"""( apply(t2crt::Object* _this, t2crt::ArgsT& args) { /* TODO: call _body wtih flatten args */ } + )""" + clsName + R"""(* bind (t2crt::Object* _this, t2crt::ArgsT* args) { + )""" + clsName + R"""(* func = new )""" + clsName + R"""((); + func->_thisArg = _this; + func->_args = args; + return(func); + } + virtual const char* __GetClassName() const {return ")""" + funcName + R"""( ";} +}; + +)"""; + return str; +} + +// build generator function header for _body +std::string GeneratorFuncHeader(std::string cls, unsigned nodeId) { + std::string params = FunctionParams(nodeId, false, false, true); // pass params by ref into _body() + if (!params.empty()) + params = ", " + params; + return "void " + cls + "_body(t2crt::Object* _this, void*& yield, t2crt::IteratorResult& res" + params + ")"; +} + +// Generating Generators and Generator Functions: +// For each TS generator function, 2 C++ classes: generator and generator function are emitted. +// The generator function has only a single instance. It is called to create generator instances. +std::string GeneratorClassDecl(std::string funcName, unsigned nodeId) { + std::string str; + std::string generatorName = GeneratorName(funcName); + std::string generatorFuncName = GeneratorFuncName(funcName); + + std::string functorArgs = FunctionParams(nodeId, false, false); + std::string initList = FunctionParams(nodeId, false, false, false, true) ; + std::string captureFields = FunctionParams(nodeId, false, false, false, false, true); + std::string ctorArgs = functorArgs.empty()? std::string(): (", "s + functorArgs); + initList = initList.empty()? "": (", "s + initList); + + std::string genClsDecl[] = { +"// " +funcName+ " generators", +"class " +generatorName+ " : public t2crt::GeneratorProto {", +"public:", +" " +generatorName+ "(t2crt::Function* ctor, t2crt::Object* proto" +ctorArgs+ ") : t2crt::GeneratorProto(ctor, proto)" +initList+ " {}", +" ~" +generatorName+ "() {}", +" // closure capture fields", +" " +captureFields, +" // iterator interface (override _return and _throw when needed)", +" t2crt::IteratorResult* next(t2crt::JS_Val* arg = nullptr) override;", +"};", +"// " +funcName+ " generator function", +"class " +generatorFuncName+ " : public t2crt::GeneratorFuncPrototype {", +"public:", +" " +generatorFuncName+ "() : t2crt::GeneratorFuncPrototype(&t2crt::GeneratorFunction, &t2crt::Generator, t2crt::GeneratorPrototype) {}", +" ~" +generatorFuncName+ "() {}", +" // call operator returns generator instances", +" " +generatorName+ "* operator()(" +functorArgs+ ");", +" // generator function body", +" " +GeneratorFuncHeader("", nodeId)+ ";", +"};", +"" + }; + + str += "\n"; + for (auto elem : genClsDecl) + str += elem + "\n"; + return str; +} + +std::string GeneratorClassDef(std::string ns, std::string funcName, unsigned nodeId) { + std::string str; + std::string generatorName = ns + GeneratorName(funcName); + std::string generatorFuncName = ns + GeneratorFuncName(funcName); + + if (!ns.empty()) + funcName = ns + "::" + funcName; + + std::string params = FunctionParams(nodeId, false, false); + std::string args = FunctionParams(nodeId, false, true); + if (!args.empty()) + args = ", " + args; + + str = R"""( +t2crt::IteratorResult* )""" + generatorName + R"""(::next(t2crt::JS_Val* arg) { + if (_finished) { + _res.done = true; + return &_res; + } + // iterate by calling generation function with captures in generator + )""" + funcName + R"""(->_body(this, _yield, _res)""" + args + R"""(); + if (_res.done == true) + _finished = true; + return &_res; +} + +)""" + generatorName + "* "s + generatorFuncName + R"""(::operator()()""" + params + R"""() { + return new )""" + generatorName + R"""((&t2crt::Generator, foo->prototype)""" + args + R"""(); +} + +)"""; + return str; +} + +bool IsClassMethod(TreeNode* node) { + return(node->IsFunction() && node->GetParent() && node->GetParent()->IsClass()); +} + +std::string tab(int n) { + return std::string(n*2,' '); +} + +std::string GenAnonFuncName(TreeNode* node) { + return "_anon_func_"s + std::to_string(node->GetNodeId()); +} + +// return array constructor name of given type +// format: +// 1D array: t2crt::Array::ctor +// 2D array: t2crt::Array*>::ctor +// 3D array: t2crt::Array*>*>::ctor +// ... +// note: must be in sycn with format generated by ARR_CTOR_DEF in builtins.h +std::string ArrayCtorName(int dim, std::string type) { + if (!dim) + return std::string(); + std::string str = "t2crt::Array<"s + type + ">"s; + for (int i=1; i"s; + } + str = str + "::ctor"s; + return str; +} + +// note: entries below are to match values from ast nodes. Do not prepend with "t2crt::" +std::vectorbuiltins = {"Object", "Function", "Number", "Array", "Record"}; + +bool IsBuiltinObj(std::string name) { + return std::find(builtins.begin(), builtins.end(), name) != builtins.end(); +} + +std::string ObjectTypeStr(std::string name) { + if (IsBuiltinObj(name)) + return "t2crt::" + name + "*"; + else + return name + "*"; +} + +} // namespace maplefe diff --git a/src/MapleFE/ast2cpp/src/main.cpp b/src/MapleFE/ast2cpp/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6062f4228f538d04148f62a5fa909b7bacb08819 --- /dev/null +++ b/src/MapleFE/ast2cpp/src/main.cpp @@ -0,0 +1,108 @@ +/* +* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include "gen_astload.h" +#include "ast_handler.h" +#include "ast2cpp.h" + +static void help() { + std::cout << "ast2cpp a.ast[,b.ast] [options]:" << std::endl; + std::cout << " --out=x.cpp : cpp output file" << std::endl; + std::cout << " --help : print this help" << std::endl; + std::cout << " --trace=n : Emit trace with 4-bit combo levels 1...15" << std::endl; + std::cout << " 1 : Emit ast tree visits" << std::endl; + std::cout << " 2 : Emit graph" << std::endl; + std::cout << " --emit-ts-only : Emit ts code only" << std::endl; + std::cout << " --emit-ts : Emit ts code" << std::endl; + std::cout << " --format-cpp : Format cpp" << std::endl; + std::cout << " --no-imported : Do not process the imported modules" << std::endl; + std::cout << "default out name uses the first input name: a.cpp" << std::endl; +} + +int main (int argc, char *argv[]) { + if (argc == 1 || (!strncmp(argv[1], "--help", 6) && (strlen(argv[1]) == 6))) { + help(); + exit(-1); + } + + unsigned flags; + // one or more input .ast files separated by ',' + const char *inputname = argv[1]; + // output .cpp file + const char *outputname = nullptr; + + // Parse the argument + for (unsigned i = 2; i < argc; i++) { + if (!strncmp(argv[i], "--trace=", 8)) { + int val = atoi(argv[i] + 8); + if (val < 1 || val > 15) { + help(); + exit(-1); + } + flags |= val; + } else if (!strncmp(argv[i], "--emit-ts-only", 14)) { + flags |= maplefe::FLG_emit_ts_only; + } else if (!strncmp(argv[i], "--emit-ts", 9)) { + flags |= maplefe::FLG_emit_ts; + } else if (!strncmp(argv[i], "--format-cpp", 12)) { + flags |= maplefe::FLG_format_cpp; + } else if (!strncmp(argv[i], "--no-imported", 13)) { + flags |= maplefe::FLG_no_imported; + } else if (!strncmp(argv[i], "--in=", 5)) { + inputname = argv[i]+5; + } else if (!strncmp(argv[i], "--out=", 6)) { + outputname = argv[i]+6; + } else { + std::cerr << "unknown option " << argv[i] << std::endl; + exit(-1); + } + } + + // input ast files + std::vector inputfiles; + if (inputname) { + std::stringstream ss; + ss.str(inputname); + std::string item; + while (std::getline(ss, item, ',')) { + // std::cout << "item " << item << " xxx"<< std::endl; + inputfiles.push_back(item); + } + } + + unsigned trace = (flags & maplefe::FLG_trace); + maplefe::AST_Handler handler(trace); + for (auto astfile: inputfiles) { + std::ifstream input(astfile, std::ifstream::binary); + input >> std::noskipws; + std::istream_iterator s(input), e; + maplefe::AstBuffer vec(s, e); + maplefe::AstLoad loadAst; + maplefe::ModuleNode *mod = loadAst.LoadFromAstBuf(vec); + // add mod to the vector + while(mod) { + handler.AddModule(mod); + mod = loadAst.Next(); + } + } + + maplefe::A2C *a2c = new maplefe::A2C(&handler, flags); + int res = a2c->ProcessAST(); + + return res; +} diff --git a/src/MapleFE/test/testall b/src/MapleFE/ast2mpl/Makefile old mode 100755 new mode 100644 similarity index 71% rename from src/MapleFE/test/testall rename to src/MapleFE/ast2mpl/Makefile index 5de40cd76a41b0fbc4a25cd8d8a55707cfeecb14..da0321c1b14cbbfc75d469ee5abcdb42e6d29b15 --- a/src/MapleFE/test/testall +++ b/src/MapleFE/ast2mpl/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. # # OpenArkFE is licensed under the Mulan PSL v2. # You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -12,5 +12,16 @@ # See the Mulan PSL v2 for more details. # -./java2mpl_runtests.pl java2mpl -./sharedfe_runtests.pl sharedfe +include ../Makefile.in + +all: + $(MAKE) -C src + +clean: + rm -rf $(BUILDDIR)/shared + +test: + $(MAKE) -C ../test p + +.PHONY: $(TARGS) + diff --git a/src/MapleFE/java/include/ast2mpl_java.h b/src/MapleFE/ast2mpl/include/ast2mpl.h similarity index 53% rename from src/MapleFE/java/include/ast2mpl_java.h rename to src/MapleFE/ast2mpl/include/ast2mpl.h index cec63ef9035608a2e8ab8eddf821b02b6d0fc2ae..a9283482498005a40f1666a3bbaace49a85e4557 100644 --- a/src/MapleFE/java/include/ast2mpl_java.h +++ b/src/MapleFE/ast2mpl/include/ast2mpl.h @@ -13,25 +13,38 @@ * See the Mulan PSL v2 for more details. */ -///////////////////////////////////////////////////////////////////////////////// -// Java Specific AST2MPL // -///////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////// +// This is the interface to translate AST to MapleIR. +////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef __AST2MPL_JAVA_H__ -#define __AST2MPL_JAVA_H__ +#ifndef __AST2MPL_HEADER__ +#define __AST2MPL_HEADER__ -#include "ast2mpl.h" +#include "astopt.h" +#include "ast_handler.h" + +#include "mir_module.h" +#include "maplefe_mir_builder.h" namespace maplefe { -class A2MJava : public A2M { +class A2M : public AstOpt { private: -public: - A2MJava(const char *filename) : A2M(filename) { } + AST_Handler *mASTHandler; + unsigned mFlags; + unsigned mIndexImported; - const char *Type2Label(const maple::MIRType *type); - - maple::MIRType *MapPrimType(PrimTypeNode *ptnode); +public: + explicit A2M(AST_Handler *h, unsigned flags) : + AstOpt(h, flags), + mASTHandler(h), + mFlags(flags), + mIndexImported(0) {} + ~A2M() = default; + + // return 0 if successful + // return non-zero if failed + int ProcessAST(); }; } diff --git a/src/MapleFE/shared/include/ast2mpl.h b/src/MapleFE/ast2mpl/include/ast2mpl_builder.h similarity index 75% rename from src/MapleFE/shared/include/ast2mpl.h rename to src/MapleFE/ast2mpl/include/ast2mpl_builder.h index 837c7ee30229625f1a58893e3f424b26a858f48a..1270063fde7b185f7c04293502898921f6174215 100644 --- a/src/MapleFE/shared/include/ast2mpl.h +++ b/src/MapleFE/ast2mpl/include/ast2mpl_builder.h @@ -17,14 +17,14 @@ // This is the interface to translate AST to MapleIR. ////////////////////////////////////////////////////////////////////////////////////////////// -#ifndef __AST2MPL_HEADER__ -#define __AST2MPL_HEADER__ +#ifndef __AST2MPL_BUILDER_HEADER__ +#define __AST2MPL_BUILDER_HEADER__ -#include "ast_module.h" #include "ast.h" -#include "ast_type.h" +#include "ast_handler.h" #include "mir_module.h" +#include "generic_attrs.h" #include "maplefe_mir_builder.h" namespace maplefe { @@ -40,54 +40,72 @@ enum StmtExprKind { SK_Expr }; -class A2M { +enum bool3 { + false3, + true3, + maybe3 +}; + +class Ast2MplBuilder { private: - const char *mFileName; - bool mTraceA2m; - FEMIRBuilder *mMirBuilder; + AST_Handler *mASTHandler; + const char *mFilename; + bool mTraceA2m; + FEMIRBuilder *mMirBuilder; maple::MIRType *mDefaultType; - FieldData *mFieldData; + FieldData *mFieldData; + unsigned mUniqNum; + unsigned mFlags; + public: maple::MIRModule *mMirModule; // use type's uniq name as key - std::map mNodeTypeMap; - std::map> mNameFuncMap; + std::map mNodeTypeMap; + std::map> mNameFuncMap; std::map mBlockNodeMap; std::map mBlockFuncMap; std::map mFuncMap; - std::map, maple::MIRSymbol*> mNameBlockVarMap; + std::map, maple::MIRSymbol*> mNameBlockVarMap; + + Ast2MplBuilder(AST_Handler *h, unsigned f); + ~Ast2MplBuilder(); - A2M(const char *filename); - ~A2M(); + void Build(); void Init(); bool IsStmt(TreeNode *tnode); + bool3 IsCompatibleTo(maple::PrimType expected, maple::PrimType prim); void UpdateFuncName(maple::MIRFunction *func); virtual const char *Type2Label(const maple::MIRType *type); void Type2Name(std::string &str, const maple::MIRType *type); + ClassNode *GetSuperClass(ClassNode *klass); BlockNode *GetSuperBlock(BlockNode *block); maple::MIRSymbol *GetSymbol(TreeNode *tnode, BlockNode *block); maple::MIRSymbol *CreateSymbol(TreeNode *tnode, BlockNode *block); maple::MIRSymbol *CreateTempVar(const char *prefix, maple::MIRType *type); - maple::MIRFunction *GetFunc(BlockNode *block); - maple::MIRFunction *SearchFunc(const char *name, const maple::MapleVector &args); + maple::MIRFunction *GetCurrFunc(BlockNode *block); + maple::MIRFunction *SearchFunc(unsigned idx, maple::MapleVector &args); + maple::MIRFunction *SearchFunc(TreeNode *method, maple::MapleVector &args, BlockNode *block); maple::MIRClassType *GetClass(BlockNode *block); void UpdateUniqName(std::string &str); - virtual maple::MIRType *MapPrimType(PrimTypeNode *tnode)=0; + maple::PrimType MapPrim(TypeId id); + maple::MIRType *MapPrimType(TypeId id); + maple::MIRType *MapPrimType(PrimTypeNode *tnode); maple::MIRType *MapType(TreeNode *tnode); - void MapAttr(maple::GenericAttrs &attr, const IdentifierNode *inode); + void MapAttr(maple::GenericAttrs &attr, AttrId id); + void MapAttr(maple::GenericAttrs &attr, IdentifierNode *inode); + void MapAttr(maple::GenericAttrs &attr, FunctionNode *fnode); maple::Opcode MapUnaOpcode(OprId); maple::Opcode MapBinOpcode(OprId); maple::Opcode MapBinCmpOpcode(OprId); maple::Opcode MapBinComboOpcode(OprId); - void ProcessAST(bool trace_a2m); maple::BaseNode *ProcessNodeDecl(StmtExprKind, TreeNode *tnode, BlockNode *); maple::BaseNode *ProcessNode(StmtExprKind, TreeNode *tnode, BlockNode *); @@ -123,6 +141,7 @@ public: BlockNode *block); maple::BaseNode *ProcessLoopCondBody(StmtExprKind skind, TreeNode *cond, TreeNode *body, BlockNode *block); + maple::BaseNode *GetNewNodeLhs(NewNode *node, BlockNode *block); }; } diff --git a/src/MapleFE/autogen/src/expr_gen.cpp b/src/MapleFE/ast2mpl/include/cvt_block.h similarity index 39% rename from src/MapleFE/autogen/src/expr_gen.cpp rename to src/MapleFE/ast2mpl/include/cvt_block.h index 1a5af43a85bb0328fc87483e9a1d188989ac93c4..99ac1da878fed8b78a11a0465c6d7aec4a56bd33 100644 --- a/src/MapleFE/autogen/src/expr_gen.cpp +++ b/src/MapleFE/ast2mpl/include/cvt_block.h @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -12,36 +12,30 @@ * FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. */ -#include "expr_gen.h" -namespace maplefe { - -void ExprGen::Generate() { - GenRuleTables(); - GenHeaderFile(); - GenCppFile(); -} +#ifndef __AST_CVT_BLOCK_H__ +#define __AST_CVT_BLOCK_H__ -void ExprGen::GenHeaderFile() { - mHeaderFile.WriteOneLine("#ifndef __EXPR_GEN_H__", 22); - mHeaderFile.WriteOneLine("#define __EXPR_GEN_H__", 22); - mHeaderFile.WriteOneLine("namespace maplefe {", 19); +#include "ast_module.h" +#include "ast.h" +#include "gen_astvisitor.h" - // generate the rule tables - mHeaderFile.WriteFormattedBuffer(&mRuleTableHeader); +namespace maplefe { - mHeaderFile.WriteOneLine("}", 1); - mHeaderFile.WriteOneLine("#endif", 6); -} +// CvtBlockVisitor is to fix up some tree nodes after the AST is created +class CvtToBlockVisitor : public AstVisitor { + private: + ModuleNode *mASTModule; + bool mUpdated; -void ExprGen::GenCppFile() { - mCppFile.WriteOneLine("#include \"common_header_autogen.h\"", 34); - mCppFile.WriteOneLine("namespace maplefe {", 19); + public: + CvtToBlockVisitor(ModuleNode *m) : mASTModule(m), mUpdated(false) {} - // generate the rule tables - mCppFile.WriteFormattedBuffer(&mRuleTableCpp); - mCppFile.WriteOneLine("}", 1); -} -} + bool CvtToBlock(); + CondBranchNode *VisitCondBranchNode(CondBranchNode *node); + ForLoopNode *VisitForLoopNode(ForLoopNode *node); +}; +} +#endif diff --git a/src/MapleFE/ast2mpl/include/generic_attrs.h b/src/MapleFE/ast2mpl/include/generic_attrs.h new file mode 100644 index 0000000000000000000000000000000000000000..ecab7c62d180bec7218941b55af3167d9d8eefcf --- /dev/null +++ b/src/MapleFE/ast2mpl/include/generic_attrs.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef GENERIC_ATTRS_H +#define GENERIC_ATTRS_H +#include +#include "mir_type.h" + +namespace maple { +// only for internal use, not emitted +enum GenericAttrKind { +#define FUNC_ATTR +#define TYPE_ATTR +#define FIELD_ATTR +#define ATTR(STR) GENATTR_##STR, +#include "all_attributes.def" +#undef ATTR +#undef FUNC_ATTR +#undef TYPE_ATTR +#undef FIELD_ATTR +}; + +class GenericAttrs { + public: + GenericAttrs() = default; + GenericAttrs(const GenericAttrs &ta) = default; + GenericAttrs &operator=(const GenericAttrs &p) = default; + ~GenericAttrs() = default; + + void SetAttr(GenericAttrKind x) { + attrFlag.set(x); + } + + bool GetAttr(GenericAttrKind x) const { + return attrFlag[x]; + } + + bool operator==(const GenericAttrs &tA) const { + return attrFlag == tA.attrFlag; + } + + bool operator!=(const GenericAttrs &tA) const { + return !(*this == tA); + } + + FieldAttrs ConvertToFieldAttrs(); + TypeAttrs ConvertToTypeAttrs(); + FuncAttrs ConvertToFuncAttrs(); + + private: + std::bitset<128> attrFlag = 0; +}; +} +#endif // GENERIC_ATTRS_H \ No newline at end of file diff --git a/src/MapleFE/shared/include/maplefe_mir_builder.h b/src/MapleFE/ast2mpl/include/maplefe_mir_builder.h similarity index 89% rename from src/MapleFE/shared/include/maplefe_mir_builder.h rename to src/MapleFE/ast2mpl/include/maplefe_mir_builder.h index d4fa730156948804ba3add28fa1162b3ec61b3cf..52261130d603806cea5c925440facd161cf15718 100644 --- a/src/MapleFE/shared/include/maplefe_mir_builder.h +++ b/src/MapleFE/ast2mpl/include/maplefe_mir_builder.h @@ -77,6 +77,11 @@ class FEMIRBuilder : public maple::MIRBuilder { bool TraverseToNamedField(maple::MIRStructType *structType, unsigned &fieldID, FieldData *fieldData); maple::BaseNode *CreateExprDread(const maple::MIRSymbol *symbol, maple::FieldID fieldID = maple::FieldID(0)); + + // use maple::PTY_ref for pointer types + maple::MIRType *GetOrCreatePointerType(const maple::MIRType *pointTo) { + return maple::GlobalTables::GetTypeTable().GetOrCreatePointerType(*pointTo, maple::PTY_ref); + } }; } diff --git a/src/MapleFE/ast2mpl/src/Makefile b/src/MapleFE/ast2mpl/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..51ab1dcd3e1b7c95dcda06ba6a8a02e8df10d433 --- /dev/null +++ b/src/MapleFE/ast2mpl/src/Makefile @@ -0,0 +1,88 @@ +# Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +include ../../Makefile.in +BUILDBIN=$(BUILDDIR)/bin +BUILD=$(BUILDDIR)/ast2mpl +BUILDGEN=$(BUILDDIR)/gen +BUILDASTGEN=$(BUILDDIR)/ast_gen/shared +$(shell $(MKDIR_P) $(BUILD)) + +SRC=$(wildcard *.cpp) +OBJ :=$(patsubst %.cpp,%.o,$(SRC)) +DEP :=$(patsubst %.cpp,%.d,$(SRC)) + +SRCG := $(wildcard $(BUILDGEN)/gen*.cpp) +OBJG := $(patsubst %.cpp, %.o, $(SRCG)) +DEPG := $(patsubst %.cpp, %.d, $(SRCG)) + +OBJS :=$(foreach obj,$(OBJ), $(BUILD)/$(obj)) $(OBJG) +DEPS :=$(foreach dep,$(DEP), $(BUILD)/$(dep)) $(DEPG) + +LIBOBJS :=$(patsubst $(BUILD)/main.o,,$(OBJS)) + +GENDIR:=${BUILDDIR}/ast_gen/shared + +INCLUDES := -I $(MAPLEFE_ROOT)/shared/include \ + -I $(MAPLEFE_ROOT)/astopt/include \ + -I $(MAPLEFE_ROOT)/ast2mpl/include \ + -I $(MAPLEFE_ROOT)/autogen/include \ + -I $(MAPLEFE_ROOT)/shared/include \ + -I $(MAPLEFE_ROOT)/java/include \ + $(MAPLEALL_INC) -I ${GENDIR} + +AST2MPLLIB = ast2mpl.a + +INCLUDEGEN := -I $(MAPLEFE_ROOT)/shared/include -I $(BUILDDIR)/gen -I $(BUILDASTGEN) + +TARGET=ast2mpl +SHAREDLIB = $(BUILDDIR)/astopt/astopt.a $(BUILDDIR)/shared/shared.a $(BUILDASTGEN)/genast.a +LANGSPEC=$(BUILDDIR)/java/lang_spec.o + +.PHONY: all +all: $(BUILDBIN)/$(TARGET) + +-include $(DEPS) +.PHONY: clean + +vpath %.o $(BUILD) +vpath %.d $(BUILD) + +#Pattern Rules +$(BUILD)/%.o : %.cpp + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ + +$(BUILD)/%.d : %.cpp + @$(CXX) $(CXXFLAGS) -MM $(INCLUDES) $< > $@ + @mv -f $(BUILD)/$*.d $(BUILD)/$*.d.tmp + @sed -e 's|.*:|$(BUILD)/$*.o:|' < $(BUILD)/$*.d.tmp > $(BUILD)/$*.d + @rm -f $(BUILD)/$*.d.tmp + +$(BUILDGEN)/%.o : $(BUILDGEN)/%.cpp $(BUILDGEN)/%.d + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDEGEN) -w -c $< -o $@ + +$(BUILDGEN)/%.d : $(BUILDGEN)/%.cpp + @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDEGEN) $< > $@ + @mv -f $(BUILDGEN)/$*.d $(BUILDGEN)/$*.d.tmp + @sed -e 's|.*:|$(BUILDGEN)/$*.o:|' < $(BUILDGEN)/$*.d.tmp > $(BUILDGEN)/$*.d + @rm -f $(BUILDGEN)/$*.d.tmp + +# TARGET depends on OBJS and shared OBJS from shared directory +# as well as mapleall libraries +$(BUILDBIN)/$(TARGET): $(OBJS) $(SHAREDLIB) + @mkdir -p $(BUILDBIN) + $(LD) -o $(BUILDBIN)/$(TARGET) $(OBJS) $(LANGSPEC) $(SHAREDLIB) $(MAPLELIBS) + +clean: + rm -rf $(BUILD) diff --git a/src/MapleFE/ast2mpl/src/ast2mpl.cpp b/src/MapleFE/ast2mpl/src/ast2mpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e6ac6c2b44641dfdd3b96313037b5dadfe55ecbb --- /dev/null +++ b/src/MapleFE/ast2mpl/src/ast2mpl.cpp @@ -0,0 +1,129 @@ +/* +* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include + +#include "ast2mpl.h" +#include "ast_handler.h" +#include "gen_astdump.h" +#include "gen_astgraph.h" +#include "gen_aststore.h" +#include "gen_astload.h" + +#include "mir_function.h" +#include "ast2mpl_builder.h" + +namespace maplefe { + +// starting point of AST +int A2M::ProcessAST() { + mIndexImported = GetModuleNum(); + + // loop through module handlers + for (HandlerIndex i = 0; i < GetModuleNum(); i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + ModuleNode *module = handler->GetASTModule(); + + if (mFlags & FLG_trace_1) { + std::cout << "============= in ProcessAST ===========" << std::endl; + std::cout << "srcLang : " << module->GetSrcLangString() << std::endl; + + for(unsigned k = 0; k < module->GetTreesNum(); k++) { + TreeNode *tnode = module->GetTree(k); + if (mFlags & FLG_trace_1) { + tnode->Dump(0); + std::cout << std::endl; + } + } + } + + if (mFlags & FLG_trace_2) { + std::cout << "============= AstGraph ===========" << std::endl; + AstGraph graph(module); + graph.DumpGraph("After LoadFromAstBuf()", &std::cout); + } + } + + // build dependency of modules + PreprocessModules(); + + // loop through module handlers in import/export dependency order + for (auto handler: mHandlersInOrder) { + ModuleNode *module = handler->GetASTModule(); + + // basic analysis + handler->BasicAnalysis(); + + if (mFlags & FLG_trace_2) { + std::cout << "============= After AdjustAST ===========" << std::endl; + for(unsigned k = 0; k < module->GetTreesNum(); k++) { + TreeNode *tnode = module->GetTree(k); + if (mFlags & FLG_trace_1) { + tnode->Dump(0); + std::cout << std::endl; + } + } + AstGraph graph(module); + graph.DumpGraph("After AdjustAST()", &std::cout); + } + + // build CFG + handler->BuildCFG(); + + if (mFlags & FLG_trace_2) { + handler->Dump("After BuildCFG()"); + } + + // control flow analysis + handler->ControlFlowAnalysis(); + + // type inference + handler->TypeInference(); + + if (mFlags & FLG_trace_2) { + std::cout << "============= AstGraph ===========" << std::endl; + AstGraph graph(module); + graph.DumpGraph("After BuildCFG()", &std::cout); + } + + if (mFlags & FLG_trace_2) { + std::cout << "============= AstDump ===========" << std::endl; + AstDump astdump(module); + astdump.Dump("After BuildCFG()", &std::cout); + } + + // data flow analysis + handler->DataFlowAnalysis(); + + if (mFlags & FLG_trace_2) { + handler->Dump("After DataFlowAnalysis()"); + } + } + + // build mpl + if (mFlags & FLG_trace_2) { + std::cout << "============= Ast2Mpl Build ===========" << std::endl; + } + maplefe::Ast2MplBuilder ast2mpl_builder(mASTHandler, mFlags); + ast2mpl_builder.Build(); + + ast2mpl_builder.mMirModule->OutputAsciiMpl("", ".mpl"); + return 0; +} + +} diff --git a/src/MapleFE/shared/src/ast2mpl.cpp b/src/MapleFE/ast2mpl/src/ast2mpl_builder.cpp similarity index 50% rename from src/MapleFE/shared/src/ast2mpl.cpp rename to src/MapleFE/ast2mpl/src/ast2mpl_builder.cpp index f980347848ae9f737588bf3a6dc768ea8ca57a01..2c8c3546f32498b5d14b0b4639585a97e747164d 100644 --- a/src/MapleFE/shared/src/ast2mpl.cpp +++ b/src/MapleFE/ast2mpl/src/ast2mpl_builder.cpp @@ -13,80 +13,127 @@ * See the Mulan PSL v2 for more details. */ -#include "ast2mpl.h" +#include "ast2mpl_builder.h" +#include "gen_astdump.h" +#include "mir_module.h" #include "mir_function.h" #include "maplefe_mir_builder.h" +#include "cvt_block.h" namespace maplefe { -static unsigned mVarUniqNum; - -A2M::A2M(const char *filename) : mFileName(filename) { - mMirModule = new maple::MIRModule(mFileName); +Ast2MplBuilder::Ast2MplBuilder(AST_Handler *h, unsigned f) : mASTHandler(h), mFlags(f) { + mFilename = h->GetModuleHandler((unsigned)0)->GetASTModule()->GetFilename(); + mMirModule = new maple::MIRModule(mFilename); maple::theMIRModule = mMirModule; mMirBuilder = new FEMIRBuilder(mMirModule); mFieldData = new FieldData(); - mVarUniqNum = 1; Init(); } -A2M::~A2M() { +Ast2MplBuilder::~Ast2MplBuilder() { delete mMirModule; delete mMirBuilder; delete mFieldData; mNodeTypeMap.clear(); } -void A2M::Init() { +void Ast2MplBuilder::Init() { // create mDefaultType maple::MIRType *type = maple::GlobalTables::GetTypeTable().GetOrCreateClassType("DEFAULT_TYPE", *mMirModule); type->SetMIRTypeKind(maple::kTypeClass); - mDefaultType = maple::GlobalTables::GetTypeTable().GetOrCreatePointerType(*type); + mDefaultType = mMirBuilder->GetOrCreatePointerType(type); // setup flavor and srclang mMirModule->SetFlavor(maple::kFeProduced); mMirModule->SetSrcLang(maple::kSrcLangJava); // setup INFO_filename - maple::GStrIdx idx = maple::GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(mFileName); + maple::GStrIdx idx = maple::GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(mFilename); SET_INFO_PAIR(mMirModule, "INFO_filename", idx.GetIdx(), true); - // add to java src file list - std::string str(mFileName); + // add to src file list + std::string str(mFilename); size_t pos = str.rfind('/'); if (pos != std::string::npos) { idx = maple::GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(str.substr(pos+1)); } mMirModule->PushbackFileInfo(maple::MIRInfoPair(idx, 2)); + + // initialize unique serial number for temporary variables and inner classes + mUniqNum = 1; } // starting point of AST to MPL process -void A2M::ProcessAST(bool trace_a2m) { - mTraceA2m = trace_a2m; - if (mTraceA2m) std::cout << "============= in ProcessAST ===========" << std::endl; - // pass 1: collect class/interface/function decl - for(auto it: gModule.mTrees) { - TreeNode *tnode = it->mRootNode; - ProcessNodeDecl(SK_Stmt, tnode, nullptr); +void Ast2MplBuilder::Build() { + mTraceA2m = mFlags & FLG_trace_2; + for (HandlerIndex i = 0; i < mASTHandler->GetSize(); i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + ModuleNode *module = handler->GetASTModule(); + + AstDump astdump(module); + + if (mTraceA2m) { + std::cout << "============= in ProcessAST ===========" << std::endl; + std::cout << "srcLang : " << module->GetSrcLangString() << std::endl; + } + // pass 0: convert to use BlockNode for if-then-else and loop bodies + CvtToBlockVisitor visitor(module); + visitor.CvtToBlock(); + + // pass 1: collect class/interface/function decl + for (unsigned i = 0; i < module->GetTreesNum(); i++) { + TreeNode *tnode = module->GetTree(i); + ProcessNodeDecl(SK_Stmt, tnode, nullptr); + } + + // pass 2: handle function def + for (unsigned i = 0; i < module->GetTreesNum(); i++) { + TreeNode *tnode = module->GetTree(i); + ProcessNode(SK_Stmt, tnode, nullptr); + } + if (mTraceA2m) { astdump.Dump("Build", &std::cout); } } - // pass 2: handle function def - for(auto it: gModule.mTrees) { - TreeNode *tnode = it->mRootNode; - if (mTraceA2m) { tnode->Dump(0); fflush(0); } - ProcessNode(SK_Stmt, tnode, nullptr); +} + +maple::PrimType Ast2MplBuilder::MapPrim(TypeId id) { + maple::PrimType prim; + switch (id) { + case TY_Boolean: prim = maple::PTY_u1; break; + case TY_Byte: prim = maple::PTY_u8; break; + case TY_Short: prim = maple::PTY_i16; break; + case TY_Int: prim = maple::PTY_i32; break; + case TY_Long: prim = maple::PTY_i64; break; + case TY_Char: prim = maple::PTY_u16; break; + case TY_Float: prim = maple::PTY_f32; break; + case TY_Double: prim = maple::PTY_f64; break; + case TY_Void: prim = maple::PTY_void; break; + case TY_Null: prim = maple::PTY_void; break; + default: MASSERT("Unsupported PrimType"); break; } + return prim; +} + +maple::MIRType *Ast2MplBuilder::MapPrimType(TypeId id) { + maple::PrimType prim = MapPrim(id); + maple::TyIdx tid(prim); + return maple::GlobalTables::GetTypeTable().GetTypeFromTyIdx(tid); +} + +maple::MIRType *Ast2MplBuilder::MapPrimType(PrimTypeNode *ptnode) { + return MapPrimType(ptnode->GetPrimType()); } -maple::MIRType *A2M::MapType(TreeNode *type) { +maple::MIRType *Ast2MplBuilder::MapType(TreeNode *type) { if (!type) { return maple::GlobalTables::GetTypeTable().GetVoid(); } maple::MIRType *mir_type = mDefaultType; - const char *name = type->GetName(); - if (mNodeTypeMap.find(name) != mNodeTypeMap.end()) { - return mNodeTypeMap[name]; + unsigned idx = type->GetStrIdx(); + if (mNodeTypeMap.find(idx) != mNodeTypeMap.end()) { + return mNodeTypeMap[idx]; } if (type->IsPrimType()) { @@ -94,7 +141,7 @@ maple::MIRType *A2M::MapType(TreeNode *type) { mir_type = MapPrimType(ptnode); // update mNodeTypeMap - mNodeTypeMap[name] = mir_type; + mNodeTypeMap[idx] = mir_type; } else if (type->IsUserType()) { if (type->IsIdentifier()) { IdentifierNode *inode = static_cast(type); @@ -106,14 +153,20 @@ maple::MIRType *A2M::MapType(TreeNode *type) { } // DimensionNode *mDims // unsigned dnum = inode->GetDimsNum(); - mNodeTypeMap[name] = mir_type; + mNodeTypeMap[idx] = mir_type; + } else if (idx) { + AST2MPLMSG("MapType add a class type by idx", idx); + mir_type = maple::GlobalTables::GetTypeTable().GetOrCreateClassType(type->GetName(), *mMirModule); + mir_type->SetMIRTypeKind(maple::kTypeClass); + mir_type = mMirBuilder->GetOrCreatePointerType(mir_type); + mNodeTypeMap[idx] = mir_type; } else { - NOTYETIMPL("MapType Unknown"); + NOTYETIMPL("MapType unknown type"); } return mir_type; } -maple::Opcode A2M::MapUnaOpcode(OprId ast_op) { +maple::Opcode Ast2MplBuilder::MapUnaOpcode(OprId ast_op) { maple::Opcode op = maple::OP_undef; switch (ast_op) { case OPR_Add: op = maple::OP_add; break; @@ -127,7 +180,7 @@ maple::Opcode A2M::MapUnaOpcode(OprId ast_op) { return op; } -maple::Opcode A2M::MapBinOpcode(OprId ast_op) { +maple::Opcode Ast2MplBuilder::MapBinOpcode(OprId ast_op) { maple::Opcode op = maple::OP_undef; switch (ast_op) { case OPR_Add: op = maple::OP_add; break; @@ -148,7 +201,7 @@ maple::Opcode A2M::MapBinOpcode(OprId ast_op) { return op; } -maple::Opcode A2M::MapBinCmpOpcode(OprId ast_op) { +maple::Opcode Ast2MplBuilder::MapBinCmpOpcode(OprId ast_op) { maple::Opcode op = maple::OP_undef; switch (ast_op) { case OPR_EQ: op = maple::OP_eq; break; @@ -162,7 +215,7 @@ maple::Opcode A2M::MapBinCmpOpcode(OprId ast_op) { return op; } -maple::Opcode A2M::MapBinComboOpcode(OprId ast_op) { +maple::Opcode Ast2MplBuilder::MapBinComboOpcode(OprId ast_op) { maple::Opcode op = maple::OP_undef; switch (ast_op) { case OPR_AddAssign: op = maple::OP_add; break; @@ -182,7 +235,25 @@ maple::Opcode A2M::MapBinComboOpcode(OprId ast_op) { return op; } -const char *A2M::Type2Label(const maple::MIRType *type) { +#if 1 +const char *Ast2MplBuilder::Type2Label(const maple::MIRType *type) { + maple::PrimType pty = type->GetPrimType(); + switch (pty) { + case maple::PTY_u1: return "Z"; + case maple::PTY_u8: return "B"; + case maple::PTY_i16: return "S"; + case maple::PTY_u16: return "C"; + case maple::PTY_i32: return "I"; + case maple::PTY_i64: return "J"; + case maple::PTY_f32: return "F"; + case maple::PTY_f64: return "D"; + case maple::PTY_void: return "V"; + default: return "L"; + } +} +#else + +const char *Ast2MplBuilder::Type2Label(const maple::MIRType *type) { maple::PrimType pty = type->GetPrimType(); switch (pty) { case maple::PTY_u1: return "Z"; @@ -200,16 +271,13 @@ const char *A2M::Type2Label(const maple::MIRType *type) { default: return "L"; } } +#endif -bool A2M::IsStmt(TreeNode *tnode) { +bool Ast2MplBuilder::IsStmt(TreeNode *tnode) { bool status = true; if (!tnode) return false; switch (tnode->GetKind()) { - case NK_Literal: - case NK_Identifier: - status = false; - break; case NK_Parenthesis: { ParenthesisNode *node = static_cast(tnode); status = IsStmt(node->GetExpr()); @@ -221,16 +289,57 @@ bool A2M::IsStmt(TreeNode *tnode) { if (ast_op != OPR_Inc && ast_op != OPR_Dec) { status = false; } + break; } case NK_BinOperator: { BinOperatorNode *bon = static_cast(tnode); - maple::Opcode op = MapBinComboOpcode(bon->mOprId); - if (bon->mOprId != OPR_Assign && op == maple::OP_undef) { + maple::Opcode op = MapBinComboOpcode(bon->GetOprId()); + if (bon->GetOprId() != OPR_Assign && op == maple::OP_undef) { status = false; } break; } + case NK_Block: + case NK_Break: + case NK_Call: + case NK_CondBranch: + case NK_Delete: + case NK_DoLoop: + case NK_ExprList: + case NK_ForLoop: + case NK_Function: + case NK_Interface: + case NK_Lambda: + case NK_New: + case NK_Return: + case NK_Switch: + case NK_SwitchCase: + case NK_VarList: + case NK_WhileLoop: + status = true; + break; + case NK_Annotation: + case NK_AnnotationType: + case NK_Assert: + case NK_Attr: + case NK_Cast: + case NK_Class: + case NK_Dimension: + case NK_Exception: + case NK_Field: + case NK_Identifier: + case NK_Import: + case NK_InstanceOf: + case NK_Literal: + case NK_Package: + case NK_Pass: + case NK_PrimArrayType: + case NK_PrimType: + case NK_SwitchLabel: + case NK_TerOperator: + case NK_UserType: default: + status = false; break; } return status; @@ -251,7 +360,7 @@ bool A2M::IsStmt(TreeNode *tnode) { #define RARG "_29" // ")" #endif -void A2M::Type2Name(std::string &str, const maple::MIRType *type) { +void Ast2MplBuilder::Type2Name(std::string &str, const maple::MIRType *type) { maple::PrimType pty = type->GetPrimType(); const char *n = Type2Label(type); str.append(n); @@ -265,16 +374,15 @@ void A2M::Type2Name(std::string &str, const maple::MIRType *type) { } } -// update to use uniq name: str --> str|mVarUniqNum -void A2M::UpdateUniqName(std::string &str) { +// update to use uniq name: str --> str|mUniqNum +void Ast2MplBuilder::UpdateUniqName(std::string &str) { str.append(SEP); - str.append(std::to_string(mVarUniqNum)); - mVarUniqNum++; + str.append(std::to_string(mUniqNum++)); return; } // update to use mangled name: className|funcName|(argTypes)retType -void A2M::UpdateFuncName(maple::MIRFunction *func) { +void Ast2MplBuilder::UpdateFuncName(maple::MIRFunction *func) { std::string str; maple::TyIdx tyIdx = func->GetClassTyIdx(); maple::MIRType *type; @@ -308,21 +416,29 @@ void A2M::UpdateFuncName(maple::MIRFunction *func) { maple::GlobalTables::GetGsymTable().AddToStringSymbolMap(*funcst); } -BlockNode *A2M::GetSuperBlock(BlockNode *block) { - TreeNode *blk = block->GetParent(); - while (blk && !blk->IsBlock()) { - blk = blk->GetParent(); +ClassNode *Ast2MplBuilder::GetSuperClass(ClassNode *klass) { + TreeNode *tnode = klass->GetParent(); + while (tnode && !tnode->IsClass()) { + tnode = tnode->GetParent(); } - return (BlockNode*)blk; + return static_cast(tnode); } -maple::MIRSymbol *A2M::GetSymbol(TreeNode *tnode, BlockNode *block) { - const char *name = tnode->GetName(); +BlockNode *Ast2MplBuilder::GetSuperBlock(BlockNode *block) { + TreeNode *tnode = block->GetParent(); + while (tnode && !tnode->IsBlock()) { + tnode = tnode->GetParent(); + } + return static_cast(tnode); +} + +maple::MIRSymbol *Ast2MplBuilder::GetSymbol(TreeNode *tnode, BlockNode *block) { + unsigned idx = tnode->GetStrIdx(); maple::MIRSymbol *symbol = nullptr; // global symbol if (!block) { - std::pair P(tnode->GetName(), block); + std::pair P(idx, block); symbol = mNameBlockVarMap[P]; return symbol; } @@ -330,7 +446,7 @@ maple::MIRSymbol *A2M::GetSymbol(TreeNode *tnode, BlockNode *block) { // trace block hirachy for defined symbol BlockNode *blk = block; do { - std::pair P(tnode->GetName(), blk); + std::pair P(idx, blk); symbol = mNameBlockVarMap[P]; if (symbol) { return symbol; @@ -339,12 +455,12 @@ maple::MIRSymbol *A2M::GetSymbol(TreeNode *tnode, BlockNode *block) { } while (blk); // check parameters - maple::MIRFunction *func = GetFunc(blk); + maple::MIRFunction *func = GetCurrFunc(blk); if (!func) { NOTYETIMPL("Block parent hirachy"); return symbol; } - maple::GStrIdx stridx = maple::GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + maple::GStrIdx stridx = maple::GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(tnode->GetName()); if (func->IsAFormalName(stridx)) { maple::FormalDef def = func->GetFormalFromName(stridx); return def.formalSym; @@ -352,21 +468,20 @@ maple::MIRSymbol *A2M::GetSymbol(TreeNode *tnode, BlockNode *block) { return symbol; } -maple::MIRSymbol *A2M::CreateTempVar(const char *prefix, maple::MIRType *type) { +maple::MIRSymbol *Ast2MplBuilder::CreateTempVar(const char *prefix, maple::MIRType *type) { if (!type) { return nullptr; } std::string str(prefix); str.append(SEP); - str.append(std::to_string(mVarUniqNum)); - mVarUniqNum++; + str.append(std::to_string(mUniqNum++)); maple::MIRFunction *func = mMirModule->CurFunction(); maple::MIRSymbol *var = mMirBuilder->CreateLocalDecl(str, *type); return var; } -maple::MIRSymbol *A2M::CreateSymbol(TreeNode *tnode, BlockNode *block) { - const char *name = tnode->GetName(); +maple::MIRSymbol *Ast2MplBuilder::CreateSymbol(TreeNode *tnode, BlockNode *block) { + std::string name = tnode->GetName(); maple::MIRType *mir_type; if (tnode->IsIdentifier()) { @@ -381,12 +496,12 @@ maple::MIRSymbol *A2M::CreateSymbol(TreeNode *tnode, BlockNode *block) { maple::MIRTypeKind kind = mir_type->GetKind(); if (kind == maple::kTypeClass || kind == maple::kTypeClassIncomplete || kind == maple::kTypeInterface || kind == maple::kTypeInterfaceIncomplete) { - mir_type = maple::GlobalTables::GetTypeTable().GetOrCreatePointerType(*mir_type, maple::PTY_ref); + mir_type = mMirBuilder->GetOrCreatePointerType(mir_type); } maple::MIRSymbol *symbol = nullptr; if (block) { - maple::MIRFunction *func = GetFunc(block); + maple::MIRFunction *func = GetCurrFunc(block); symbol = mMirBuilder->GetLocalDecl(name); std::string str(name); // symbol with same name already exist, use a uniq new name @@ -404,54 +519,197 @@ maple::MIRSymbol *A2M::CreateSymbol(TreeNode *tnode, BlockNode *block) { symbol = mMirBuilder->CreateGlobalDecl(str, *mir_type, maple::kScGlobal); } - std::pair P(name, block); + std::pair P(tnode->GetStrIdx(), block); mNameBlockVarMap[P] = symbol; return symbol; } -maple::MIRFunction *A2M::GetFunc(BlockNode *block) { +maple::MIRFunction *Ast2MplBuilder::GetCurrFunc(BlockNode *block) { maple::MIRFunction *func = nullptr; // func = mBlockFuncMap[block]; func = mMirModule->CurFunction(); return func; } -maple::MIRClassType *A2M::GetClass(BlockNode *block) { - maple::TyIdx tyidx = GetFunc(block)->GetClassTyIdx(); +maple::MIRClassType *Ast2MplBuilder::GetClass(BlockNode *block) { + maple::TyIdx tyidx = GetCurrFunc(block)->GetClassTyIdx(); return (maple::MIRClassType*)maple::GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyidx); } -maple::MIRFunction *A2M::SearchFunc(const char *name, const maple::MapleVector &args) { - if (mNameFuncMap.find(name) == mNameFuncMap.end()) { +bool3 Ast2MplBuilder::IsCompatibleTo(maple::PrimType expected, maple::PrimType prim) { + if (expected == prim) + return true3; + + maple::PrimitiveType type(prim); + bool3 comp = false3; + switch (expected) { + case maple::PTY_i8: + case maple::PTY_i16: + case maple::PTY_i32: + case maple::PTY_i64: + case maple::PTY_u8: + case maple::PTY_u16: + case maple::PTY_u32: + case maple::PTY_u64: + case maple::PTY_u1: + if (type.IsInteger()) { + comp = true3; + } + break; + case maple::PTY_ptr: + case maple::PTY_ref: + if (type.IsPointer()) { + comp = true3; + } + if (type.IsInteger()) { + comp = maybe3; + } + break; + case maple::PTY_a32: + case maple::PTY_a64: + if (type.IsAddress()) { + comp = true3; + } + break; + case maple::PTY_f32: + case maple::PTY_f64: + case maple::PTY_f128: + if (type.IsFloat()) { + comp = true3; + } + break; + case maple::PTY_c64: + case maple::PTY_c128: + if (type.IsInteger()) { + comp = true3; + } + break; + case maple::PTY_constStr: + case maple::PTY_gen: + case maple::PTY_agg: + case maple::PTY_unknown: + case maple::PTY_v2i64: + case maple::PTY_v4i32: + case maple::PTY_v8i16: + case maple::PTY_v16i8: + case maple::PTY_v2f64: + case maple::PTY_v4f32: + case maple::PTY_void: + default: + break; + } + return comp; +} + +maple::MIRFunction *Ast2MplBuilder::SearchFunc(unsigned idx, maple::MapleVector &args) { + if (mNameFuncMap.find(idx) == mNameFuncMap.end()) { return nullptr; } - for (auto it: mNameFuncMap[name]) { + std::vector candidates; + for (auto it: mNameFuncMap[idx]) { if (it->GetFormalCount() != args.size()) { continue; } bool matched = true; + bool3 mightmatched = true3; for (int i = 0; i < it->GetFormalCount(); i++) { - // TODO: allow compatible types maple::MIRType *type = maple::GlobalTables::GetTypeTable().GetTypeFromTyIdx(it->GetFormalDefAt(i).formalTyIdx); - if (type->GetPrimType() != args[i]->GetPrimType()) { + bool3 comp = IsCompatibleTo(type->GetPrimType(), args[i]->GetPrimType()); + if (comp == false3) { matched = false; + mightmatched = false3; break; + } else if (comp == maybe3) { + matched = false; } } - if (!matched) { - continue; + if (matched) { + return it; } - return it; + if (mightmatched != false3) { + candidates.push_back(it); + } + } + if (candidates.size()) { + return candidates[0]; } return nullptr; } -void A2M::MapAttr(maple::GenericAttrs &attr, const IdentifierNode *inode) { +maple::MIRFunction *Ast2MplBuilder::SearchFunc(TreeNode *method, maple::MapleVector &args, BlockNode *block) { + maple::MIRFunction *func = nullptr; + switch (method->GetKind()) { + case NK_Function: { + func = SearchFunc(method->GetStrIdx(), args); + break; + } + case NK_Identifier: { + IdentifierNode *imethod = static_cast(method); + func = SearchFunc(imethod->GetStrIdx(), args); + break; + } + case NK_Field: { + FieldNode *node = static_cast(method); + TreeNode *upper = node->GetUpper(); + TreeNode *field = node->GetField(); + if (field->IsIdentifier()) { + // pass upper as this + maple::BaseNode *bn = ProcessNode(SK_Expr, upper, block); + if (bn) { + args[0] = bn; + } + } + func = SearchFunc(field, args, block); + break; + } + default: + NOTYETIMPL("GetFuncName() method to be handled"); + } + + return func; +} + +void Ast2MplBuilder::MapAttr(maple::GenericAttrs &attr, AttrId id) { + switch (id) { +#undef ATTRIBUTE +#define ATTRIBUTE(X) case ATTR_##X: attr.SetAttr(maple::GENATTR_##X); break; +// #include "supported_attributes.def" +ATTRIBUTE(abstract) +ATTRIBUTE(const) +ATTRIBUTE(volatile) +ATTRIBUTE(final) +ATTRIBUTE(native) +ATTRIBUTE(private) +ATTRIBUTE(protected) +ATTRIBUTE(public) +ATTRIBUTE(static) +ATTRIBUTE(default) +ATTRIBUTE(synchronized) + +// ATTRIBUTE(strictfp) + case ATTR_strictfp: attr.SetAttr(maple::GENATTR_strict); break; + + default: + break; + } +} + +void Ast2MplBuilder::MapAttr(maple::GenericAttrs &attr, IdentifierNode *inode) { // SmallVector mAttrs unsigned anum = inode->GetAttrsNum(); for (int i = 0; i < anum; i++) { + const AttrId ast_attr = inode->GetAttrAtIndex(i); + MapAttr(attr, ast_attr); } } + +void Ast2MplBuilder::MapAttr(maple::GenericAttrs &attr, FunctionNode *fnode) { + unsigned anum = fnode->GetAttrsNum(); + for (int i = 0; i < anum; i++) { + const AttrId ast_attr = fnode->GetAttrAtIndex(i); + MapAttr(attr, ast_attr); + } } +} diff --git a/src/MapleFE/ast2mpl/src/cvt_block.cpp b/src/MapleFE/ast2mpl/src/cvt_block.cpp new file mode 100644 index 0000000000000000000000000000000000000000..419d1c54bd72c4aa5d0db2ac80bb82b0b40f713a --- /dev/null +++ b/src/MapleFE/ast2mpl/src/cvt_block.cpp @@ -0,0 +1,62 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include "cvt_block.h" + +namespace maplefe { + +bool CvtToBlockVisitor::CvtToBlock() { + for (unsigned i = 0; i < mASTModule->GetTreesNum(); i++ ) { + TreeNode *it = mASTModule->GetTree(i); + Visit(it); + } + return mUpdated; +} + +// if-then-else +CondBranchNode *CvtToBlockVisitor::VisitCondBranchNode(CondBranchNode *node) { + TreeNode *tn = VisitTreeNode(node->GetTrueBranch()); + if (tn && !tn->IsBlock()) { + BlockNode *blk = (BlockNode*)gTreePool.NewTreeNode(sizeof(BlockNode)); + new (blk) BlockNode(); + blk->AddChild(tn); + node->SetTrueBranch(blk); + mUpdated = true; + } + tn = VisitTreeNode(node->GetFalseBranch()); + if (tn && !tn->IsBlock()) { + BlockNode *blk = (BlockNode*)gTreePool.NewTreeNode(sizeof(BlockNode)); + new (blk) BlockNode(); + blk->AddChild(tn); + node->SetFalseBranch(blk); + mUpdated = true; + } + return node; +} + +// for +ForLoopNode *CvtToBlockVisitor::VisitForLoopNode(ForLoopNode *node) { + TreeNode *tn = VisitTreeNode(node->GetBody()); + if (tn && !tn->IsBlock()) { + BlockNode *blk = (BlockNode*)gTreePool.NewTreeNode(sizeof(BlockNode)); + new (blk) BlockNode(); + blk->AddChild(tn); + node->SetBody(blk); + mUpdated = true; + } + return node; +} + +} diff --git a/src/MapleFE/ast2mpl/src/generic_attrs.cpp b/src/MapleFE/ast2mpl/src/generic_attrs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..185d327387249f9ceea60c5fd288970ac463c739 --- /dev/null +++ b/src/MapleFE/ast2mpl/src/generic_attrs.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "generic_attrs.h" + +namespace maple { +TypeAttrs GenericAttrs::ConvertToTypeAttrs() { + TypeAttrs attr; + constexpr uint32 maxAttrNum = 128; + for (uint32 i = 0; i < maxAttrNum; ++i) { + if (attrFlag[i] == 0) { + continue; + } + auto tA = static_cast(i); + switch (tA) { +#define TYPE_ATTR +#define ATTR(STR) \ + case GENATTR_##STR: \ + attr.SetAttr(ATTR_##STR); \ + break; +#include "all_attributes.def" +#undef ATTR +#undef TYPE_ATTR + default: + ASSERT(false, "unknown TypeAttrs"); + break; + } + } + return attr; +} + +FuncAttrs GenericAttrs::ConvertToFuncAttrs() { + FuncAttrs attr; + constexpr uint32 maxAttrNum = 128; + for (uint32 i = 0; i < maxAttrNum; ++i) { + if (attrFlag[i] == 0) { + continue; + } + auto tA = static_cast(i); + switch (tA) { +#define FUNC_ATTR +#define ATTR(STR) \ + case GENATTR_##STR: \ + attr.SetAttr(FUNCATTR_##STR); \ + break; +#include "all_attributes.def" +#undef ATTR +#undef FUNC_ATTR + default: + ASSERT(false, "unknown FuncAttrs"); + break; + } + } + return attr; +} + +FieldAttrs GenericAttrs::ConvertToFieldAttrs() { + FieldAttrs attr; + constexpr uint32 maxAttrNum = 128; + for (uint32 i = 0; i < maxAttrNum; ++i) { + if (attrFlag[i] == 0) { + continue; + } + auto tA = static_cast(i); + switch (tA) { +#define FIELD_ATTR +#define ATTR(STR) \ + case GENATTR_##STR: \ + attr.SetAttr(FLDATTR_##STR); \ + break; +#include "all_attributes.def" +#undef ATTR +#undef FIELD_ATTR + default: + ASSERT(false, "unknown FieldAttrs"); + break; + } + } + return attr; +} +} \ No newline at end of file diff --git a/src/MapleFE/ast2mpl/src/main.cpp b/src/MapleFE/ast2mpl/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a0f89a9114ac926688e5a8b2f6e0d4ff6c9176d8 --- /dev/null +++ b/src/MapleFE/ast2mpl/src/main.cpp @@ -0,0 +1,96 @@ +/* +* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include "gen_astload.h" +#include "ast_handler.h" +#include "ast2mpl.h" + +static void help() { + std::cout << "ast2cpp a.ast[,b.ast] [options]:" << std::endl; + std::cout << " --out=x.cpp : cpp output file" << std::endl; + std::cout << " --help : print this help" << std::endl; + std::cout << " --trace=n : Emit trace with 4-bit combo levels 1...15" << std::endl; + std::cout << " 1 : Emit ast tree visits" << std::endl; + std::cout << " 2 : Emit graph" << std::endl; + std::cout << " --emit-ts-only : Emit ts code only" << std::endl; + std::cout << " --emit-ts : Emit ts code" << std::endl; + std::cout << " --format-cpp : Format cpp" << std::endl; + std::cout << " --no-imported : Do not process the imported modules" << std::endl; + std::cout << "default out name uses the first input name: a.cpp" << std::endl; +} + +int main (int argc, char *argv[]) { + if (argc == 1 || (!strncmp(argv[1], "--help", 6) && (strlen(argv[1]) == 6))) { + help(); + exit(-1); + } + + unsigned flags; + // one or more input .ast files separated by ',' + const char *inputname = argv[1]; + + // Parse the argument + for (unsigned i = 2; i < argc; i++) { + if (!strncmp(argv[i], "--trace=", 8)) { + int val = atoi(argv[i] + 8); + if (val < 1 || val > 15) { + help(); + exit(-1); + } + flags |= val; + } else { + std::cerr << "unknown option " << argv[i] << std::endl; + exit(-1); + } + } + + // input ast files + std::vector inputfiles; + if (inputname) { + std::stringstream ss; + ss.str(inputname); + std::string item; + while (std::getline(ss, item, ',')) { + // std::cout << "item " << item << " xxx"<< std::endl; + inputfiles.push_back(item); + } + } + + unsigned trace = (flags & maplefe::FLG_trace); + maplefe::AST_Handler handler(trace); + for (auto astfile: inputfiles) { + std::ifstream input(astfile, std::ifstream::binary); + input >> std::noskipws; + std::istream_iterator s(input), e; + maplefe::AstBuffer vec(s, e); + maplefe::AstLoad loadAst; + maplefe::ModuleNode *mod = loadAst.LoadFromAstBuf(vec); + // add mod to the vector + while(mod) { + handler.AddModule(mod); + mod = loadAst.Next(); + } + } + + maplefe::A2M *a2m = new maplefe::A2M(&handler, flags); + int res = a2m->ProcessAST(); + + delete a2m; + + return 0; +} diff --git a/src/MapleFE/shared/src/maplefe_mir_builder.cpp b/src/MapleFE/ast2mpl/src/maplefe_mir_builder.cpp similarity index 94% rename from src/MapleFE/shared/src/maplefe_mir_builder.cpp rename to src/MapleFE/ast2mpl/src/maplefe_mir_builder.cpp index adae368a639ea461a274e7ba7d5df2e55b5fcbc3..680635f744443258f5713f5ebaab85fe54fc1278 100644 --- a/src/MapleFE/shared/src/maplefe_mir_builder.cpp +++ b/src/MapleFE/ast2mpl/src/maplefe_mir_builder.cpp @@ -59,7 +59,8 @@ bool FEMIRBuilder::TraverseToNamedField(maple::MIRStructType *structType, unsign } maple::BaseNode *FEMIRBuilder::CreateExprDread(const maple::MIRSymbol *symbol, maple::FieldID fieldID) { - maple::BaseNode *nd = new maple::AddrofNode(maple::OP_dread, maple::kPtyInvalid, symbol->GetStIdx(), fieldID); + maple::PrimType prim = symbol->GetType()->GetPrimType(); + maple::BaseNode *nd = new maple::AddrofNode(maple::OP_dread, prim, symbol->GetStIdx(), fieldID); return nd; } diff --git a/src/MapleFE/shared/src/mpl_processor.cpp b/src/MapleFE/ast2mpl/src/mpl_processor.cpp similarity index 50% rename from src/MapleFE/shared/src/mpl_processor.cpp rename to src/MapleFE/ast2mpl/src/mpl_processor.cpp index 62e2e29d0f242febba626ffefd240c4fceb98544..378c18860ff09647cbe0d32e5dd21e526a94b0f3 100644 --- a/src/MapleFE/shared/src/mpl_processor.cpp +++ b/src/MapleFE/ast2mpl/src/mpl_processor.cpp @@ -13,11 +13,12 @@ * See the Mulan PSL v2 for more details. */ -#include "ast2mpl.h" +#include "ast2mpl_builder.h" +#include "stringpool.h" namespace maplefe { -maple::BaseNode *A2M::ProcessNodeDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessNodeDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { if (!tnode) { return nullptr; } @@ -25,19 +26,19 @@ maple::BaseNode *A2M::ProcessNodeDecl(StmtExprKind skind, TreeNode *tnode, Block maple::BaseNode *mpl_node = nullptr; switch (tnode->GetKind()) { case NK_Class: { - mpl_node =ProcessClassDecl(SK_Stmt, tnode, nullptr); + mpl_node =ProcessClassDecl(SK_Stmt, tnode, block); break; } case NK_Interface: { - mpl_node = ProcessInterfaceDecl(SK_Stmt, tnode, nullptr); + mpl_node = ProcessInterfaceDecl(SK_Stmt, tnode, block); break; } case NK_Function: { - mpl_node = ProcessFuncDecl(SK_Stmt, tnode, nullptr); + mpl_node = ProcessFuncDecl(SK_Stmt, tnode, block); break; } case NK_Block: { - mpl_node = ProcessBlockDecl(SK_Stmt, tnode, nullptr); + mpl_node = ProcessBlockDecl(SK_Stmt, tnode, block); break; } default: { @@ -47,7 +48,7 @@ maple::BaseNode *A2M::ProcessNodeDecl(StmtExprKind skind, TreeNode *tnode, Block return mpl_node; } -maple::BaseNode *A2M::ProcessNode(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessNode(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { if (!tnode) { return nullptr; } @@ -64,21 +65,43 @@ maple::BaseNode *A2M::ProcessNode(StmtExprKind skind, TreeNode *tnode, BlockNode return mpl_node; } -maple::BaseNode *A2M::ProcessPackage(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessModule(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessModule()"); + ModuleNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessPackage(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessPackage()"); PackageNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessImport(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessDeclare(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessImport(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessImport()"); ImportNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessIdentifier(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessExport(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessExport()"); + ExportNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessXXportAsPair(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessXXportAsPair()"); + XXportAsPairNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessIdentifier(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { IdentifierNode *node = static_cast(tnode); - const char *name = node->GetName(); + std::string name = node->GetName(); if (skind == SK_Stmt) { AST2MPLMSG("ProcessIdentifier() is a decl", name); @@ -94,7 +117,7 @@ maple::BaseNode *A2M::ProcessIdentifier(StmtExprKind skind, TreeNode *tnode, Blo } maple::GStrIdx stridx = maple::GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); - maple::MIRFunction *func = GetFunc(block); + maple::MIRFunction *func = GetCurrFunc(block); // check parameters if (func->IsAFormalName(stridx)) { @@ -118,7 +141,7 @@ maple::BaseNode *A2M::ProcessIdentifier(StmtExprKind skind, TreeNode *tnode, Blo maple::BaseNode *bn = mMirBuilder->CreateExprDread(sym); maple::MIRType *ftype = maple::GlobalTables::GetTypeTable().GetTypeFromTyIdx(mFieldData->GetTyIdx()); AST2MPLMSG("ProcessIdentifier() found match field", name); - return new maple::IreadNode(maple::OP_iread, ftype->GetPrimType(), mFieldData->GetTyIdx(), maple::FieldID(fid), bn); + return new maple::IreadNode(maple::OP_iread, ftype->GetPrimType(), sym->GetTyIdx(), maple::FieldID(fid), bn); } // check global var @@ -129,11 +152,12 @@ maple::BaseNode *A2M::ProcessIdentifier(StmtExprKind skind, TreeNode *tnode, Blo } AST2MPLMSG("ProcessIdentifier() unknown identifier", name); + // create a dummy var with name and mDefaultType symbol = mMirBuilder->GetOrCreateLocalDecl(name, *mDefaultType); return mMirBuilder->CreateExprDread(symbol); } -maple::BaseNode *A2M::ProcessField(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessField(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { FieldNode *node = static_cast(tnode); maple::BaseNode *bn = nullptr; @@ -148,40 +172,81 @@ maple::BaseNode *A2M::ProcessField(StmtExprKind skind, TreeNode *tnode, BlockNod maple::MIRType *ctype = nullptr; maple::TyIdx cptyidx(0); - maple::BaseNode *dr = nullptr; + maple::BaseNode *nd = nullptr; + nd = ProcessNode(SK_Expr, upper, block); if (upper->IsLiteral()) { LiteralNode *lt = static_cast(upper); if (lt->GetData().mType == LT_ThisLiteral) { - maple::MIRFunction *func = GetFunc(block); + maple::MIRFunction *func = GetCurrFunc(block); maple::MIRSymbol *sym = func->GetFormal(0); // this cptyidx = sym->GetTyIdx(); ctype = GetClass(block); - dr = new maple::DreadNode(maple::OP_dread, maple::PTY_ptr, sym->GetStIdx(), 0); + nd = new maple::DreadNode(maple::OP_dread, maple::PTY_ptr, sym->GetStIdx(), 0); } else { NOTYETIMPL("ProcessField() not this literal"); } + } else if (nd) { + maple::TyIdx tyidx(0); + switch (nd->GetOpCode()) { + case maple::OP_dread: { + maple::AddrofNode *dr = static_cast(nd); + maple::StIdx stidx = dr->GetStIdx(); + maple::MIRSymbol *sym = nullptr; + if (stidx.Islocal()) { + sym = mMirModule->CurFunction()->GetSymTab()->GetSymbolFromStIdx(stidx.Idx()); + } else { + sym = maple::GlobalTables::GetGsymTable().GetSymbolFromStidx(stidx.Idx()); + } + tyidx = sym->GetTyIdx(); + break; + } + case maple::OP_iread: { + maple::IreadNode *ir = static_cast(nd); + tyidx = ir->GetTyIdx(); + break; + } + default: + NOTYETIMPL("ProcessField() supper"); + break; + } + maple::MIRType *type = maple::GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyidx); + cptyidx = type->GetTypeIndex(); + while (type->GetKind() == maple::kTypePointer) { + maple::MIRPtrType *ptype = static_cast(type); + type = ptype->GetPointedType(); + } + ctype = type; } else { - NOTYETIMPL("ProcessField() upper not literal"); + NOTYETIMPL("ProcessField() nullptr nd"); } - if (!ctype) { - NOTYETIMPL("ProcessField() null class type"); + if (!(ctype && ctype->IsInstanceOfMIRStructType())) { + NOTYETIMPL("ProcessField() null or non structure/class/interface type"); return bn; } - const char *fname = field->GetName(); + std::string fname = field->GetName(); maple::GStrIdx stridx = maple::GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fname); mFieldData->ResetStrIdx(stridx); maple::uint32 fid = 0; bool status = mMirBuilder->TraverseToNamedField((maple::MIRStructType*)ctype, fid, mFieldData); + maple::MIRType *ftype = maple::GlobalTables::GetTypeTable().GetTypeFromTyIdx(mFieldData->GetTyIdx()); if (status) { - maple::MIRType *ftype = maple::GlobalTables::GetTypeTable().GetTypeFromTyIdx(mFieldData->GetTyIdx()); - bn = new maple::IreadNode(maple::OP_iread, ftype->GetPrimType(), cptyidx, fid, dr); + bn = new maple::IreadNode(maple::OP_iread, ftype->GetPrimType(), cptyidx, fid, nd); + } else { + NOTYETIMPL("ProcessField() can not find field"); + // insert a dummy field with fname and mDefaultType + const maple::FieldAttrs attr; + maple::TyIdxFieldAttrPair P0(mDefaultType->GetTypeIndex(), attr); + maple::FieldPair P1(stridx, P0); + maple::MIRStructType *stype = static_cast(ctype); + stype->GetFields().push_back(P1); + bn = new maple::IreadNode(maple::OP_iread, maple::PTY_begin, cptyidx, fid+1, nd); } return bn; } -maple::BaseNode *A2M::ProcessFieldDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessFieldDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { FieldNode *node = static_cast(tnode); maple::BaseNode *bn = nullptr; @@ -192,88 +257,133 @@ maple::BaseNode *A2M::ProcessFieldDecl(StmtExprKind skind, TreeNode *tnode, Bloc TreeNode *parent = tnode->GetParent(); MASSERT((parent->IsClass() || parent->IsInterface()) && "Not class or interface"); - maple::MIRType *ptype = mNodeTypeMap[parent->GetName()]; + maple::MIRType *ptype = mNodeTypeMap[parent->GetStrIdx()]; + if (ptype->IsMIRPtrType()) { + maple::MIRPtrType * ptrtype = static_cast(ptype); + ptype = ptrtype->GetPointedType(); + } maple::MIRStructType *stype = static_cast(ptype); MASSERT(stype && "struct type not valid"); IdentifierNode *inode = static_cast(tnode); - const char *name = inode->GetName(); + std::string name = inode->GetName(); TreeNode *type = inode->GetType(); // PrimTypeNode or UserTypeNode TreeNode *init = inode->GetInit(); // Init value maple::GenericAttrs genAttrs; MapAttr(genAttrs, inode); + maple::FieldAttrs fAttrs = genAttrs.ConvertToFieldAttrs(); + bool isStatic = fAttrs.GetAttr(maple::FLDATTR_static); - maple::GStrIdx stridx = maple::GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); maple::MIRType *mir_type = MapType(type); - // always use pointer type for classes, with PTY_ref - if (mir_type->GetKind() == maple::kTypeClass || mir_type->GetKind() == maple::kTypeClassIncomplete || - mir_type->GetKind() == maple::kTypeInterface || mir_type->GetKind() == maple::kTypeInterfaceIncomplete) { - mir_type = maple::GlobalTables::GetTypeTable().GetOrCreatePointerType(*mir_type, maple::PTY_ref); + if (!mir_type) { + NOTYETIMPL("ProcessFieldSetup() unknown field type"); } - if (mir_type) { - maple::TyIdxFieldAttrPair P0(mir_type->GetTypeIndex(), genAttrs.ConvertToFieldAttrs()); - maple::FieldPair P1(stridx, P0); + + // use mangled name for static fields as they will be global + std::string str(name); + if (isStatic) { + str.insert(0, "|"); + str.insert(0, parent->GetName()); + } + + maple::GStrIdx stridx = maple::GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(str); + maple::TyIdxFieldAttrPair P0(mir_type->GetTypeIndex(), fAttrs); + maple::FieldPair P1(stridx, P0); + maple::MIRSymbol *symbol = nullptr; + if (isStatic) { + stype->GetStaticFields().push_back(P1); + symbol = mMirBuilder->CreateGlobalDecl(str, *mir_type, maple::kScGlobal); + symbol->SetAttrs(genAttrs.ConvertToTypeAttrs()); + } else { stype->GetFields().push_back(P1); } + if (init) { + if (isStatic) { + if (init->IsLiteral()) { + maple::BaseNode *val = ProcessLiteral(SK_Expr, init, nullptr); + if (val->op == maple::OP_constval) { + maple::ConstvalNode *cval = static_cast(val); + symbol->SetKonst(cval->GetConstVal()); + } else { + NOTYETIMPL("ProcessFieldSetup() not constval Init"); + } + } + } else { + NOTYETIMPL("ProcessFieldSetup() non-static Init"); + } + } + return bn; } -maple::BaseNode *A2M::ProcessAssert(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + DeclNode *node = static_cast(tnode); + TreeNode *vars = node->GetVar(); + return ProcessNode(skind, vars, block); +} + +maple::BaseNode *Ast2MplBuilder::ProcessAssert(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessAssert()"); AssertNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessDimension(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessDimension(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessDimension()"); DimensionNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessAttr(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessAttr(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessAttr()"); // AttrNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessPrimType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessPrimType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessPrimType()"); PrimTypeNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessPrimArrayType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessPrimArrayType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessPrimArrayType()"); PrimArrayTypeNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessUserType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessUserType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessUserType()"); UserTypeNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessCast(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessCast(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessCast()"); CastNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessParenthesis(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessParenthesis(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { ParenthesisNode *node = static_cast(tnode); return ProcessNode(skind, node->GetExpr(), block); } -maple::BaseNode *A2M::ProcessVarList(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessVarList(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { VarListNode *node = static_cast(tnode); - for (int i = 0; i < node->GetNum(); i++) { - TreeNode *n = node->VarAtIndex(i); + for (int i = 0; i < node->GetVarsNum(); i++) { + TreeNode *n = node->GetVarAtIndex(i); IdentifierNode *inode = static_cast(n); AST2MPLMSG("ProcessVarList() decl", inode->GetName()); maple::MIRSymbol *symbol = CreateSymbol(inode, block); + + maple::GenericAttrs genAttrs; + MapAttr(genAttrs, inode); + maple::TypeAttrs tAttrs = genAttrs.ConvertToTypeAttrs(); + symbol->SetAttrs(tAttrs); + TreeNode *init = inode->GetInit(); // Init value if (init) { maple::BaseNode *bn = ProcessNode(SK_Expr, init, block); @@ -288,35 +398,78 @@ maple::BaseNode *A2M::ProcessVarList(StmtExprKind skind, TreeNode *tnode, BlockN return nullptr; } -maple::BaseNode *A2M::ProcessExprList(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessExprList(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessExprList()"); ExprListNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessLiteral(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessNamespace(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessLiteral(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { LiteralNode *node = static_cast(tnode); LitData data = node->GetData(); + maple::MIRType *type = nullptr; + maple::PrimType prim = maple::PTY_unknown; maple::BaseNode *bn = nullptr; switch (data.mType) { case LT_IntegerLiteral: { - maple::MIRType *typeI32 = maple::GlobalTables::GetTypeTable().GetInt32(); - maple::MIRIntConst *cst = new maple::MIRIntConst(data.mData.mInt, *typeI32); - bn = new maple::ConstvalNode(maple::PTY_i32, cst); + type = MapPrimType(TY_Int); + prim = MapPrim(TY_Int); + maple::MIRIntConst *cst = new maple::MIRIntConst(data.mData.mInt, *type); + bn = new maple::ConstvalNode(prim, cst); break; } case LT_BooleanLiteral: { - int val = (data.mData.mBool == true) ? 1 : 0; - maple::MIRType *typeU1 = maple::GlobalTables::GetTypeTable().GetUInt1(); - bn = new maple::ConstvalNode(maple::PTY_u1, new maple::MIRIntConst(val, *typeU1)); + type = MapPrimType(TY_Boolean); + prim = MapPrim(TY_Boolean); + maple::MIRIntConst *cst = new maple::MIRIntConst((data.mData.mBool == true) ? 1 : 0, *type); + bn = new maple::ConstvalNode(prim, cst); + break; + } + case LT_CharacterLiteral: { + type = MapPrimType(TY_Char); + prim = MapPrim(TY_Char); + maple::MIRIntConst *cst = new maple::MIRIntConst((int)data.mData.mChar.mData.mChar, *type); + bn = new maple::ConstvalNode(prim, cst); + break; + } + case LT_FPLiteral: { + type = MapPrimType(TY_Float); + prim = MapPrim(TY_Float); + maple::MIRFloatConst *cst = new maple::MIRFloatConst(data.mData.mFloat, *type); + bn = new maple::ConstvalNode(prim, cst); + break; + } + case LT_DoubleLiteral: { + type = MapPrimType(TY_Double); + prim = MapPrim(TY_Double); + maple::MIRDoubleConst *cst = new maple::MIRDoubleConst(data.mData.mDouble, *type); + bn = new maple::ConstvalNode(prim, cst); + break; + } + case LT_StringLiteral: { + const std::string str(gStringPool.GetStringFromStrIdx(data.mData.mStrIdx)); + maple::UStrIdx strIdx = maple::GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(str); + bn = new maple::ConststrNode(strIdx); + bn->SetPrimType(maple::PTY_ptr); + break; + } + case LT_NullLiteral: { + type = MapPrimType(TY_Null); + prim = MapPrim(TY_Null); + maple::MIRIntConst *cst = new maple::MIRIntConst(0, *type); + bn = new maple::ConstvalNode(prim, cst); + break; + } + case LT_ThisLiteral: { + maple::MIRFunction *func = GetCurrFunc(block); + maple::MIRSymbol *sym = func->GetFormal(0); + bn = mMirBuilder->CreateExprDread(sym); break; } - case LT_FPLiteral: - case LT_DoubleLiteral: - case LT_CharacterLiteral: - case LT_StringLiteral: - case LT_NullLiteral: - case LT_ThisLiteral: default: { NOTYETIMPL("ProcessLiteral() need support"); break; @@ -325,7 +478,7 @@ maple::BaseNode *A2M::ProcessLiteral(StmtExprKind skind, TreeNode *tnode, BlockN return bn; } -maple::BaseNode *A2M::ProcessUnaOperator(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessUnaOperator(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { UnaOperatorNode *node = static_cast(tnode); OprId ast_op = node->GetOprId(); TreeNode *ast_rhs = node->GetOpnd(); @@ -347,11 +500,11 @@ maple::BaseNode *A2M::ProcessUnaOperator(StmtExprKind skind, TreeNode *tnode, Bl return mpl_node; } -maple::BaseNode *A2M::ProcessBinOperator(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessBinOperator(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { BinOperatorNode *bon = static_cast(tnode); - OprId ast_op = bon->mOprId; - TreeNode *ast_lhs = bon->mOpndA; - TreeNode *ast_rhs = bon->mOpndB; + OprId ast_op = bon->GetOprId(); + TreeNode *ast_lhs = bon->GetOpndA(); + TreeNode *ast_rhs = bon->GetOpndB(); maple::BaseNode *lhs = ProcessNode(SK_Expr, ast_lhs, block); maple::BaseNode *rhs = ProcessNode(SK_Expr, ast_rhs, block); maple::BaseNode *mpl_node = nullptr; @@ -394,35 +547,98 @@ maple::BaseNode *A2M::ProcessBinOperator(StmtExprKind skind, TreeNode *tnode, Bl return mpl_node; } -maple::BaseNode *A2M::ProcessTerOperator(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessTerOperator(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessTerOperator()"); TerOperatorNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessLambda(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessLambda(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessLambda()"); LambdaNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessBlockDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessInstanceOf(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessInstanceOf()"); + InstanceOfNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessTemplateLiteral(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessTemplateLiteral()"); + TemplateLiteralNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessRegExpr(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessIn(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessIn()"); + InNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessComputedName(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessIs(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessIs()"); + IsNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessTypeOf(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessTypeOf()"); + TypeOfNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessAwait(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessKeyOf(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessInfer(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessTripleSlash(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessFunctionType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessBlockDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { BlockNode *ast_block = static_cast(tnode); - maple::BlockNode *blk = mBlockNodeMap[block]; for (int i = 0; i < ast_block->GetChildrenNum(); i++) { TreeNode *child = ast_block->GetChildAtIndex(i); - maple::BaseNode *stmt = ProcessNodeDecl(skind, child, block); + maple::BaseNode *stmt = ProcessNodeDecl(skind, child, ast_block); } return nullptr; } -maple::BaseNode *A2M::ProcessBlock(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessBlock(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { BlockNode *ast_block = static_cast(tnode); - maple::BlockNode *blk = mBlockNodeMap[block]; + if (block) { + // promote statements to parent + mBlockNodeMap[ast_block] = mBlockNodeMap[block]; + } else { + mBlockNodeMap[ast_block] = new maple::BlockNode(); + } + maple::BlockNode *blk = mBlockNodeMap[ast_block]; for (int i = 0; i < ast_block->GetChildrenNum(); i++) { TreeNode *child = ast_block->GetChildAtIndex(i); - maple::BaseNode *stmt = ProcessNode(skind, child, block); - if (stmt) { + maple::BaseNode *stmt = ProcessNode(skind, child, ast_block); + if (stmt && IsStmt(child)) { blk->AddStatement((maple::StmtNode*)stmt); if (mTraceA2m) stmt->Dump(0); } @@ -430,19 +646,19 @@ maple::BaseNode *A2M::ProcessBlock(StmtExprKind skind, TreeNode *tnode, BlockNod return nullptr; } -maple::BaseNode *A2M::ProcessFunction(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessFunction(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { MASSERT(tnode->IsFunction() && "it is not an FunctionNode"); NOTYETIMPL("ProcessFunction()"); return nullptr; } -maple::BaseNode *A2M::ProcessFuncDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessFuncDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { FunctionNode *ast_func = static_cast(tnode); - const char *name = ast_func->GetName(); + std::string name = ast_func->GetName(); // SmallVector mAttrs; // SmallVector mAnnotations; //annotation or pragma // SmallVector mThrows; // exceptions it can throw - TreeNode *ast_rettype = ast_func->GetType(); // return type + TreeNode *ast_rettype = ast_func->GetRetType(); // return type // SmallVector mParams; // BlockNode *ast_body = ast_func->GetBody(); // DimensionNode *mDims; @@ -452,7 +668,11 @@ maple::BaseNode *A2M::ProcessFuncDecl(StmtExprKind skind, TreeNode *tnode, Block TreeNode *parent = tnode->GetParent(); maple::MIRStructType *stype = nullptr; if (parent->IsClass() || parent->IsInterface()) { - maple::MIRType *ptype = mNodeTypeMap[parent->GetName()]; + maple::MIRType *ptype = mNodeTypeMap[parent->GetStrIdx()]; + if (ptype->IsMIRPtrType()) { + maple::MIRPtrType * ptrtype = static_cast(ptype); + ptype = ptrtype->GetPointedType(); + } stype = static_cast(ptype); MASSERT(stype && "struct type not valid"); } @@ -461,8 +681,12 @@ maple::BaseNode *A2M::ProcessFuncDecl(StmtExprKind skind, TreeNode *tnode, Block maple::MIRFunction *func = mMirBuilder->GetOrCreateFunction(name, rettype->GetTypeIndex()); // init function fields - func->SetBody(func->GetCodeMemPool()->New()); + maple::BlockNode *funcbody = func->GetCodeMemPool()->New(); + func->SetBody(funcbody); func->AllocSymTab(); + if (ast_func->IsConstructor()) { + func->SetAttr(maple::FUNCATTR_constructor); + } mMirModule->AddFunction(func); mMirModule->SetCurFunction(func); @@ -480,7 +704,7 @@ maple::BaseNode *A2M::ProcessFuncDecl(StmtExprKind skind, TreeNode *tnode, Block if (stype) { maple::GStrIdx stridx = maple::GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("this"); maple::TypeAttrs attr = maple::TypeAttrs(); - maple::MIRType *sptype = maple::GlobalTables::GetTypeTable().GetOrCreatePointerType(*stype, maple::PTY_ref); + maple::MIRType *sptype = mMirBuilder->GetOrCreatePointerType(stype); maple::MIRSymbol *sym = mMirBuilder->GetOrCreateLocalDecl("this", *sptype); sym->SetStorageClass(maple::kScFormal); func->AddArgument(sym); @@ -512,10 +736,11 @@ maple::BaseNode *A2M::ProcessFuncDecl(StmtExprKind skind, TreeNode *tnode, Block // use className|funcName|_argTypes_retType as function name UpdateFuncName(func); mFuncMap[ast_func] = func; - mNameFuncMap[name].push_back(func); + mNameFuncMap[ast_func->GetStrIdx()].push_back(func); // create function type - maple::MIRFuncType *functype = (maple::MIRFuncType*)maple::GlobalTables::GetTypeTable().GetOrCreateFunctionType(*mMirModule, rettype->GetTypeIndex(), funcvectype, funcvecattr, /*isvarg*/ false, false); + maple::MIRFuncType *functype = (maple::MIRFuncType*)maple::GlobalTables::GetTypeTable().GetOrCreateFunctionType( + rettype->GetTypeIndex(), funcvectype, funcvecattr, /*isvarg*/ false); func->SetMIRFuncType(functype); // update function symbol's type @@ -531,11 +756,10 @@ maple::BaseNode *A2M::ProcessFuncDecl(StmtExprKind skind, TreeNode *tnode, Block stype->GetMethods().push_back(P1); } - if (ast_func->GetBody()) { - BlockNode *ast_block = static_cast(ast_func->GetBody()); - for (int i = 0; i < ast_block->GetChildrenNum(); i++) { - TreeNode *child = ast_block->GetChildAtIndex(i); - maple::BaseNode *stmt = ProcessNodeDecl(skind, child, block); + if (ast_body) { + for (int i = 0; i < ast_body->GetChildrenNum(); i++) { + TreeNode *child = ast_body->GetChildAtIndex(i); + maple::BaseNode *stmt = ProcessNodeDecl(skind, child, ast_body); } } @@ -543,7 +767,7 @@ maple::BaseNode *A2M::ProcessFuncDecl(StmtExprKind skind, TreeNode *tnode, Block return nullptr; } -maple::BaseNode *A2M::ProcessFuncSetup(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessFuncSetup(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { FunctionNode *ast_func = static_cast(tnode); maple::MIRFunction *func = mFuncMap[ast_func]; @@ -572,11 +796,27 @@ maple::BaseNode *A2M::ProcessFuncSetup(StmtExprKind skind, TreeNode *tnode, Bloc return nullptr; } -maple::BaseNode *A2M::ProcessClassDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessClassDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { ClassNode *classnode = static_cast(tnode); - const char *name = classnode->GetName(); + std::string name = classnode->GetName(); + TreeNode *parent = GetSuperClass(classnode); + // mangle the name for inner classes + if (parent) { + if (parent->IsClass()) { + std::string str = parent->GetName(); + str.append("$"); // indicate inner class name + str.append(std::to_string(mUniqNum++)); + str.append(name); + name = strdup(str.c_str()); + classnode->SetStrIdx(name); + } + } maple::MIRType *type = maple::GlobalTables::GetTypeTable().GetOrCreateClassType(name, *mMirModule); - mNodeTypeMap[name] = type; + type->SetMIRTypeKind(maple::kTypeClass); + // always use pointer type for classes, with PTY_ref + type = mMirBuilder->GetOrCreatePointerType(type); + unsigned idx = gStringPool.GetStrIdx(name); + mNodeTypeMap[idx] = type; AST2MPLMSG("\n================== class =====================", name); for (int i=0; i < classnode->GetLocalClassesNum(); i++) { @@ -591,7 +831,7 @@ maple::BaseNode *A2M::ProcessClassDecl(StmtExprKind skind, TreeNode *tnode, Bloc ProcessFieldDecl(skind, classnode->GetField(i), block); } - for (int i=0; i < classnode->GetConstructorNum(); i++) { + for (int i=0; i < classnode->GetConstructorsNum(); i++) { ProcessFuncDecl(skind, classnode->GetConstructor(i), block); } @@ -599,16 +839,13 @@ maple::BaseNode *A2M::ProcessClassDecl(StmtExprKind skind, TreeNode *tnode, Bloc ProcessFuncDecl(skind, classnode->GetMethod(i), block); } - // set kind to kTypeClass from kTypeClassIncomplete - type->SetMIRTypeKind(maple::kTypeClass); return nullptr; } -maple::BaseNode *A2M::ProcessClass(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessClass(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { ClassNode *classnode = static_cast(tnode); - const char *name = classnode->GetName(); - maple::MIRType *type = maple::GlobalTables::GetTypeTable().GetOrCreateClassType(name, *mMirModule); - mNodeTypeMap[name] = type; + std::string name = classnode->GetName(); + maple::MIRType *type = mNodeTypeMap[classnode->GetStrIdx()]; AST2MPLMSG("\n================== class =====================", name); for (int i=0; i < classnode->GetLocalClassesNum(); i++) { @@ -619,7 +856,7 @@ maple::BaseNode *A2M::ProcessClass(StmtExprKind skind, TreeNode *tnode, BlockNod ProcessInterface(skind, classnode->GetLocalInterface(i), block); } - for (int i=0; i < classnode->GetConstructorNum(); i++) { + for (int i=0; i < classnode->GetConstructorsNum(); i++) { ProcessFuncSetup(skind, classnode->GetConstructor(i), block); } @@ -627,49 +864,149 @@ maple::BaseNode *A2M::ProcessClass(StmtExprKind skind, TreeNode *tnode, BlockNod ProcessFuncSetup(skind, classnode->GetMethod(i), block); } - // set kind to kTypeClass from kTypeClassIncomplete - type->SetMIRTypeKind(maple::kTypeClass); return nullptr; } -maple::BaseNode *A2M::ProcessInterfaceDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessInterfaceDecl(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessInterfaceDecl()"); InterfaceNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessInterface(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessInterface(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessInterface()"); InterfaceNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessAnnotationType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessArrayElement(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessArrayElement()"); + ArrayElementNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessArrayLiteral(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessArrayLiteral()"); + ArrayLiteralNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessNumIndexSig(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessStrIndexSig(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessBindingElement(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessBindingPattern(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessTypeAlias(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessAsType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessConditionalType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessTypeParameter(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessNameTypePair(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessTupleType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessStruct(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessStruct()"); + StructNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessStructLiteral(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessStructLiteral()"); + StructLiteralNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessFieldLiteral(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessFieldLiteral()"); + FieldLiteralNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessAnnotationType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessAnnotationType()"); AnnotationTypeNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessAnnotation(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessAnnotation(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessAnnotation()"); AnnotationNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessException(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessTry(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessTry()"); + TryNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessCatch(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessCatch()"); + CatchNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessFinally(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessFinally()"); + FinallyNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessThrow(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessThrow()"); + ThrowNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessException(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessException()"); ExceptionNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessReturn(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessReturn(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { ReturnNode *node = static_cast(tnode); maple::BaseNode *val = ProcessNode(SK_Expr, node->GetResult(), block); maple::NaryStmtNode *stmt = mMirBuilder->CreateStmtReturn(val); return stmt; } -maple::BaseNode *A2M::ProcessCondBranch(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessYield(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessArrayType(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessCondBranch(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { CondBranchNode *node = static_cast(tnode); maple::BaseNode *cond = ProcessNode(SK_Expr, node->GetCond(), block); if (!cond) { @@ -700,13 +1037,19 @@ maple::BaseNode *A2M::ProcessCondBranch(StmtExprKind skind, TreeNode *tnode, Blo return ifnode; } -maple::BaseNode *A2M::ProcessBreak(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessBreak(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessBreak()"); BreakNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessLoopCondBody(StmtExprKind skind, TreeNode *cond, TreeNode *body, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessContinue(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { + NOTYETIMPL("ProcessContinue()"); + ContinueNode *node = static_cast(tnode); + return nullptr; +} + +maple::BaseNode *Ast2MplBuilder::ProcessLoopCondBody(StmtExprKind skind, TreeNode *cond, TreeNode *body, BlockNode *block) { maple::BaseNode *mircond = ProcessNode(SK_Expr, cond, block); if (!mircond) { NOTYETIMPL("ProcessLoopCondBody() condition"); @@ -727,14 +1070,14 @@ maple::BaseNode *A2M::ProcessLoopCondBody(StmtExprKind skind, TreeNode *cond, Tr return nullptr; } -maple::BaseNode *A2M::ProcessForLoop(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessForLoop(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { ForLoopNode *node = static_cast(tnode); maple::BlockNode *mblock = mBlockNodeMap[block]; maple::BaseNode *bn = nullptr; // init - for (int i = 0; i < node->GetInitNum(); i++) { - bn = ProcessNode(SK_Stmt, node->InitAtIndex(i), block); + for (int i = 0; i < node->GetInitsNum(); i++) { + bn = ProcessNode(SK_Stmt, node->GetInitAtIndex(i), block); if (bn) { mblock->AddStatement((maple::StmtNode*)bn); if (mTraceA2m) bn->Dump(0); @@ -748,8 +1091,8 @@ maple::BaseNode *A2M::ProcessForLoop(StmtExprKind skind, TreeNode *tnode, BlockN maple::BlockNode *mbody = mBlockNodeMap[static_cast(astbody)]; // update stmts are added into loop mbody - for (int i = 0; i < node->GetUpdateNum(); i++) { - bn = ProcessNode(SK_Stmt, node->UpdateAtIndex(i), (maplefe::BlockNode*)astbody); + for (int i = 0; i < node->GetUpdatesNum(); i++) { + bn = ProcessNode(SK_Stmt, node->GetUpdateAtIndex(i), (maplefe::BlockNode*)astbody); if (bn) { mbody->AddStatement((maple::StmtNode*)bn); if (mTraceA2m) bn->Dump(0); @@ -759,33 +1102,81 @@ maple::BaseNode *A2M::ProcessForLoop(StmtExprKind skind, TreeNode *tnode, BlockN return nullptr; } -maple::BaseNode *A2M::ProcessWhileLoop(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessWhileLoop(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { WhileLoopNode *node = static_cast(tnode); return ProcessLoopCondBody(skind, node->GetCond(), node->GetBody(), block); } -maple::BaseNode *A2M::ProcessDoLoop(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessDoLoop(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { DoLoopNode *node = static_cast(tnode); return ProcessLoopCondBody(skind, node->GetCond(), node->GetBody(), block); } -maple::BaseNode *A2M::ProcessNew(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { - NOTYETIMPL("ProcessNew()"); +maple::BaseNode *Ast2MplBuilder::ProcessNew(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NewNode *node = static_cast(tnode); - return nullptr; + maple::BaseNode *bn = nullptr; + + // search for constructor to call + TreeNode *id = node->GetId(); + if (!id->IsClass()) { + NOTYETIMPL("ProcessNew() mId not class"); + return bn; + } + ClassNode *classnode = static_cast(id); + + FunctionNode *func = nullptr; + for (int i=0; i < classnode->GetConstructorsNum(); i++) { + func = classnode->GetConstructor(i); + if (func->GetParamsNum() == node->GetArgsNum()) { + break; + } + } + if (!func) { + NOTYETIMPL("ProcessNew() null ast constructor"); + return bn; + } + + maple::BaseNode *obj = GetNewNodeLhs(node, block); + if (!obj) { + NOTYETIMPL("ProcessNew() null lhs"); + return bn; + } + + maple::MapleVector args(mMirModule->CurFuncCodeMemPoolAllocator()->Adapter()); + args.push_back(obj); + // pass arg + for (int i = 0; i < node->GetArgsNum(); i++) { + maple::BaseNode *arg = ProcessNode(SK_Expr, node->GetArg(i), block); + if (arg) { + args.push_back(arg); + } else { + NOTYETIMPL("ProcessCall() null arg"); + } + } + + maple::MIRFunction *callfunc = SearchFunc(func, args, block); + if (!callfunc) { + NOTYETIMPL("ProcessNew() null maple constructor"); + return bn; + } + maple::PUIdx puIdx = callfunc->GetPuidx(); + maple::Opcode callop = maple::OP_virtualcall; + maple::StmtNode *stmt = mMirBuilder->CreateStmtCallAssigned(puIdx, args, nullptr, callop); + maple::BlockNode *blk = mBlockNodeMap[block]; + blk->AddStatement(stmt); + return bn; } -maple::BaseNode *A2M::ProcessDelete(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessDelete(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessDelete()"); DeleteNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessCall(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { - NOTYETIMPL("ProcessCall()"); +maple::BaseNode *Ast2MplBuilder::ProcessCall(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { CallNode *node = static_cast(tnode); maple::MapleVector args(mMirModule->CurFuncCodeMemPoolAllocator()->Adapter()); - maple::MIRFunction *func = GetFunc(block); + maple::MIRFunction *func = GetCurrFunc(block); // pass this maple::MIRSymbol *sym = func->GetFormal(0); @@ -801,24 +1192,20 @@ maple::BaseNode *A2M::ProcessCall(StmtExprKind skind, TreeNode *tnode, BlockNode } TreeNode *method = node->GetMethod(); - if (!method->IsIdentifier()) { - NOTYETIMPL("ProcessCall() method not an identifier"); - } - IdentifierNode *imethod = static_cast(method); - func = SearchFunc(imethod->GetName(), args); - if (!func) { + maple::MIRFunction *callfunc = SearchFunc(method, args, block); + if (!callfunc) { NOTYETIMPL("ProcessCall() method not found"); return nullptr; } - maple::PUIdx puIdx = func->GetPuidx(); + maple::PUIdx puIdx = callfunc->GetPuidx(); - maple::MIRType *returnType = func->GetReturnType(); + maple::MIRType *returnType = callfunc->GetReturnType(); maple::MIRSymbol *rv = nullptr; - maple::Opcode callop = maple::OP_call; + maple::Opcode callop = func->IsJava() ? maple::OP_virtualcall : maple::OP_call; if (returnType->GetPrimType() != maple::PTY_void) { - NOTYETIMPL("ProcessCall() OP_callassigned"); - // rv = CreateTempVar("retvar", returnType); - // callop = maple::OP_callassigned; + AST2MPLMSG0("ProcessCall() OP_[virtual]callassigned"); + rv = CreateTempVar("retvar", returnType); + callop = func->IsJava() ? maple::OP_virtualcallassigned : maple::OP_callassigned; } maple::StmtNode *stmt = mMirBuilder->CreateStmtCallAssigned(puIdx, args, rv, callop); @@ -832,25 +1219,25 @@ maple::BaseNode *A2M::ProcessCall(StmtExprKind skind, TreeNode *tnode, BlockNode } } -maple::BaseNode *A2M::ProcessSwitchLabel(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessSwitchLabel(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessSwitchLabel()"); SwitchLabelNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessSwitchCase(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessSwitchCase(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessSwitchCase()"); SwitchCaseNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessSwitch(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessSwitch(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { NOTYETIMPL("ProcessSwitch()"); SwitchNode *node = static_cast(tnode); return nullptr; } -maple::BaseNode *A2M::ProcessPass(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { +maple::BaseNode *Ast2MplBuilder::ProcessPass(StmtExprKind skind, TreeNode *tnode, BlockNode *block) { PassNode *node = static_cast(tnode); maple::BlockNode *blk = mBlockNodeMap[block]; maple::BaseNode *stmt = nullptr; @@ -860,12 +1247,15 @@ maple::BaseNode *A2M::ProcessPass(StmtExprKind skind, TreeNode *tnode, BlockNode if (stmt && IsStmt(child)) { blk->AddStatement((maple::StmtNode*)stmt); if (mTraceA2m) stmt->Dump(0); + } else { + NOTYETIMPL("ProcessPass() having unhandled stmt"); + break; } } return nullptr; } -maple::BaseNode *A2M::ProcessUnaOperatorMpl(StmtExprKind skind, +maple::BaseNode *Ast2MplBuilder::ProcessUnaOperatorMpl(StmtExprKind skind, maple::Opcode op, maple::BaseNode *bn, BlockNode *block) { @@ -910,7 +1300,7 @@ maple::BaseNode *A2M::ProcessUnaOperatorMpl(StmtExprKind skind, return node; } -maple::BaseNode *A2M::ProcessBinOperatorMplAssign(StmtExprKind skind, +maple::BaseNode *Ast2MplBuilder::ProcessBinOperatorMplAssign(StmtExprKind skind, maple::BaseNode *lhs, maple::BaseNode *rhs, BlockNode *block) { @@ -939,7 +1329,7 @@ maple::BaseNode *A2M::ProcessBinOperatorMplAssign(StmtExprKind skind, return node; } -maple::BaseNode *A2M::ProcessBinOperatorMplComboAssign(StmtExprKind skind, +maple::BaseNode *Ast2MplBuilder::ProcessBinOperatorMplComboAssign(StmtExprKind skind, maple::Opcode op, maple::BaseNode *lhs, maple::BaseNode *rhs, @@ -949,7 +1339,7 @@ maple::BaseNode *A2M::ProcessBinOperatorMplComboAssign(StmtExprKind skind, return assign; } -maple::BaseNode *A2M::ProcessBinOperatorMplArror(StmtExprKind skind, +maple::BaseNode *Ast2MplBuilder::ProcessBinOperatorMplArror(StmtExprKind skind, maple::BaseNode *lhs, maple::BaseNode *rhs, BlockNode *block) { @@ -957,5 +1347,51 @@ maple::BaseNode *A2M::ProcessBinOperatorMplArror(StmtExprKind skind, return nullptr; } +// Lhs = new ... +maple::BaseNode *Ast2MplBuilder::GetNewNodeLhs(NewNode *node, BlockNode *block) { + maple::BaseNode *obj = nullptr; + TreeNode *id = node->GetId(); + + TreeNode *parent = node->GetParent(); + if (!parent) { + NOTYETIMPL("GetNewNodeLhs() null parent"); + return obj; + } + maple::BaseNode *bn = nullptr; + switch (parent->GetKind()) { + // Lhs = new ... + case NK_BinOperator: { + BinOperatorNode *biop = static_cast(parent); + switch (biop->GetOprId()) { + case OPR_Assign: { + obj = ProcessNode(SK_Expr, biop->GetOpndA(), block); + break; + } + default: { + NOTYETIMPL("GetNewNodeLhs() not BinOperator"); + break; + } + } + break; + } + // decl init: Type Lhs = new ... + case NK_Identifier: { + obj = ProcessNode(SK_Expr, parent, block); + break; + } + default: + NOTYETIMPL("GetNewNodeLhs() other kind"); + break; + } + + if (!obj) { + AST2MPLMSG0("ProcessNew() null lhs"); + maple::MIRType *type = MapType(id); + maple::MIRSymbol *var = CreateTempVar("dummy_new", type); + obj = mMirBuilder->CreateExprDread(var); + } + return obj; +} + } diff --git a/src/MapleFE/astopt/Makefile b/src/MapleFE/astopt/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0a16203b38c8275b85df68e1d5e3fb7ad56fac63 --- /dev/null +++ b/src/MapleFE/astopt/Makefile @@ -0,0 +1,27 @@ +# Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +include ../Makefile.in + +all: + $(MAKE) -C src + +clean: + rm -rf $(BUILDDIR)/astopt + +test: + $(MAKE) -C ../test p + +.PHONY: $(TARGS) + diff --git a/src/MapleFE/astopt/include/ast_adj.h b/src/MapleFE/astopt/include/ast_adj.h new file mode 100644 index 0000000000000000000000000000000000000000..36675d91eb0d6004051f5d04c2518db280fe7337 --- /dev/null +++ b/src/MapleFE/astopt/include/ast_adj.h @@ -0,0 +1,85 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __AST_ADJ_HEADER__ +#define __AST_ADJ_HEADER__ + +#include +#include +#include +#include +#include "ast_module.h" +#include "ast.h" +#include "ast_type.h" +#include "gen_astvisitor.h" +#include "ast_info.h" + +namespace maplefe { + +class AST_ADJ { + private: + Module_Handler *mHandler; + unsigned mFlags; + + public: + explicit AST_ADJ(Module_Handler *h, unsigned f) : mHandler(h), mFlags(f) {} + ~AST_ADJ() {} + + void AdjustAST(); +}; + +class AdjustASTVisitor : public AstVisitor { + private: + Module_Handler *mHandler; + AST_INFO *mInfo; + AST_Util *mUtil; + unsigned mFlags; + bool mUpdated; + + public: + explicit AdjustASTVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h), mFlags(f), mUpdated(false) { + mInfo = h->GetINFO(); + mInfo->SetNameAnonyStruct(true); + mUtil = h->GetUtil(); + } + ~AdjustASTVisitor() = default; + + std::unordered_map mRenameMap; + void CheckAndRenameCppKeywords(TreeNode *node); + void AssignPseudoName(TreeNode *node); + + DeclNode *VisitDeclNode(DeclNode *node); + ImportNode *VisitImportNode(ImportNode *node); + ExportNode *VisitExportNode(ExportNode *node); + CondBranchNode *VisitCondBranchNode(CondBranchNode *node); + ForLoopNode *VisitForLoopNode(ForLoopNode *node); + LambdaNode *VisitLambdaNode(LambdaNode *node); + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); + NamespaceNode *VisitNamespaceNode(NamespaceNode *node); + StructNode *VisitStructNode(StructNode *node); + StructLiteralNode *VisitStructLiteralNode(StructLiteralNode *node); + ClassNode *VisitClassNode(ClassNode *node); + InterfaceNode *VisitInterfaceNode(InterfaceNode *node); + FunctionNode *VisitFunctionNode(FunctionNode *node); + UserTypeNode *VisitUserTypeNode(UserTypeNode *node); + TypeAliasNode *VisitTypeAliasNode(TypeAliasNode *node); + LiteralNode *VisitLiteralNode(LiteralNode *node); + UnaOperatorNode *VisitUnaOperatorNode(UnaOperatorNode *node); + PrimArrayTypeNode *VisitPrimArrayTypeNode(PrimArrayTypeNode *node); +}; + +} +#endif diff --git a/src/MapleFE/astopt/include/ast_cfa.h b/src/MapleFE/astopt/include/ast_cfa.h new file mode 100644 index 0000000000000000000000000000000000000000..b4b65773184350b795ac3f891a43421fa315f854 --- /dev/null +++ b/src/MapleFE/astopt/include/ast_cfa.h @@ -0,0 +1,45 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __AST_CFA_HEADER__ +#define __AST_CFA_HEADER__ + +#include +#include +#include "ast_module.h" +#include "ast.h" +#include "ast_type.h" +#include "gen_astvisitor.h" + +namespace maplefe { + +class AST_CFA { + private: + Module_Handler *mHandler; + unsigned mFlags; + std::unordered_set mReachableBbIdx;; + + public: + explicit AST_CFA(Module_Handler *h, unsigned f) : mHandler(h), mFlags(f) {} + ~AST_CFA() {} + + void ControlFlowAnalysis(); + void CollectReachableBB(); + void RemoveUnreachableBB(); + void Dump(); +}; + +} +#endif diff --git a/src/MapleFE/astopt/include/ast_cfg.h b/src/MapleFE/astopt/include/ast_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..40fd2e9c4af8fafe3e10683b1d725625aff95cc4 --- /dev/null +++ b/src/MapleFE/astopt/include/ast_cfg.h @@ -0,0 +1,272 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __AST_CFG_HEADER__ +#define __AST_CFG_HEADER__ + +#include +#include "ast_module.h" +#include "ast.h" +#include "ast_type.h" +#include "gen_astvisitor.h" + +namespace maplefe { + +enum BBKind { + BK_Unknown, // Uninitialized + BK_Uncond, // BB for unconditional branch + BK_Block, // BB for a block/compound statement + BK_Branch, // BB ends up with a predicate for true/false branches + BK_LoopHeader, // BB for a loop header of a for, for/in, for/of, while, or do/while statement + BK_Switch, // BB for a switch statement + BK_Case, // BB for a case in switch statement + BK_Try, // BB for a try block + BK_Catch, // BB for a catch block + BK_Finally, // BB for a finally block + BK_Yield, // Yield BB eneded with a yield statement + BK_Terminated, // Return BB endded with a return/break/continue statement + BK_Join, // BB at join point for loops and switch + BK_Join2, // BB at join point for if-stmt and block +}; + +enum BBAttribute : unsigned { + AK_None = 0, + AK_Entry = 1 << 0, + AK_Exit = 1 << 1, + AK_Break = 1 << 2, + AK_Return = 1 << 3, + AK_Throw = 1 << 4, + AK_Cont = 1 << 5, + AK_InLoop = 1 << 6, + AK_HasCall = 1 << 7, + AK_ALL = 0xffffffff +}; + +inline BBAttribute operator|(BBAttribute x, BBAttribute y) { + return static_cast(static_cast(x) | static_cast(y)); +} +inline BBAttribute operator&(BBAttribute x, BBAttribute y) { + return static_cast(static_cast(x) & static_cast(y)); +} + +using BBIndex = unsigned; +class Module_Handler; +class AST_AST; + +class CfgBB { + private: + BBKind mKind; + BBAttribute mAttr; + BBIndex mId; // unique BB id + TreeNode *mPredicate; // a predicate for true/false branches + TreeNode *mAuxNode; // the auxiliary node of current BB + SmallList mStatements; // all statement nodes + SmallList mSuccessors; // for BK_Branch: [0] true branch, [1] false branch + SmallList mPredecessors; + + friend class AST_AST; + friend class AST_CFA; + + public: + explicit CfgBB(BBKind k) + : mKind(k), mAttr(AK_None), mId(GetNextId()), mPredicate(nullptr), mAuxNode(nullptr) {} + ~CfgBB() {mStatements.Release(); mSuccessors.Release(); mPredecessors.Release();} + + void SetKind(BBKind k) {mKind = k;} + BBKind GetKind() {return mKind;} + + void SetAttr(BBAttribute a) {mAttr = mAttr | a;} + BBIndex GetAttr() {return mAttr;} + bool TestAttr(BBAttribute a) {return mAttr & a;} + + void SetId(BBIndex id) {mId = id;} + BBIndex GetId() {return mId;} + + void SetPredicate(TreeNode *node) {mPredicate = node;} + TreeNode *GetPredicate() {return mPredicate;} + + void SetAuxNode(TreeNode *node) {mAuxNode = node;} + TreeNode *GetAuxNode() {return mAuxNode;} + + unsigned GetStatementsNum() {return mStatements.GetNum();} + TreeNode* GetStatementAtIndex(unsigned i) {return mStatements.ValueAtIndex(i);} + + void AddStatement(TreeNode *stmt) { + if(mKind != BK_Terminated) { + mStatements.PushBack(stmt); + stmt->SetIsStmt(); + } + } + + void InsertStmtAfter(TreeNode *new_stmt, TreeNode *exist_stmt) { + mStatements.LocateValue(exist_stmt); + mStatements.InsertAfter(new_stmt); + } + + void InsertStmtBefore(TreeNode *new_stmt, TreeNode *exist_stmt) { + mStatements.LocateValue(exist_stmt); + mStatements.InsertBefore(new_stmt); + } + + void AddSuccessor(CfgBB *succ) { + if(mKind == BK_Terminated) { + return; + } + mSuccessors.PushBack(succ); + succ->mPredecessors.PushBack(this); + } + unsigned GetSuccessorsNum() {return mSuccessors.GetNum();} + CfgBB *GetSuccessorAtIndex(unsigned i) {return mSuccessors.ValueAtIndex(i);} + unsigned GetPredecessorsNum() {return mPredecessors.GetNum();} + CfgBB *GetPredecessorAtIndex(unsigned i) {return mPredecessors.ValueAtIndex(i);} + + static BBIndex GetLastId() {return GetNextId(false);} + + void Dump(); + + private: + static BBIndex GetNextId(bool inc = true) {static BBIndex id = 0; return inc ? ++id : id; } +}; + +class CfgFunc { + private: + TreeNode *mFuncNode; // ModuleNode, FunctionNode or LambdaNode + SmallList mNestedFuncs; // nested functions + CfgFunc *mParent; + CfgBB *mEntryBB; + CfgBB *mExitBB; + BBIndex mLastBBId; + + public: + explicit CfgFunc() : mFuncNode(nullptr), mParent(nullptr), mEntryBB(nullptr), mExitBB(nullptr) {} + ~CfgFunc() {mNestedFuncs.Release();} + + void SetFuncNode(TreeNode *func) {mFuncNode = func;} + TreeNode *GetFuncNode() {return mFuncNode;} + + const char *GetName() { + return mFuncNode->IsModule() ? "_init_" : + (mFuncNode->GetStrIdx() ? mFuncNode->GetName() : "_anonymous_"); + } + + void AddNestedFunc(CfgFunc *func) {mNestedFuncs.PushBack(func); func->SetParent(this);} + unsigned GetNestedFuncsNum() {return mNestedFuncs.GetNum();} + CfgFunc *GetNestedFuncAtIndex(unsigned i) {return mNestedFuncs.ValueAtIndex(i);} + + void SetParent(CfgFunc *func) {mParent = func;} + CfgFunc *GetParent() {return mParent;} + + void SetEntryBB(CfgBB *bb) {mEntryBB = bb; bb->SetAttr(AK_Entry);} + CfgBB *GetEntryBB() {return mEntryBB;} + + void SetExitBB(CfgBB *bb) {mExitBB = bb; bb->SetAttr(AK_Exit);} + CfgBB *GetExitBB() {return mExitBB;} + + void SetLastBBId(BBIndex id) {mLastBBId = id;} + BBIndex GetLastBBId() {return mLastBBId;} + + void Dump(); +}; + +class CfgBuilder : public AstVisitor { + + using TargetLabel = unsigned; + using TargetBB = std::pair; + using TargetBBStack = std::vector; + + private: + Module_Handler *mHandler; + unsigned mFlags; + + CfgFunc *mCurrentFunction; + CfgBB *mCurrentBB; + + TargetBBStack mBreakBBs; + TargetBBStack mContinueBBs; + TargetBBStack mThrowBBs; + + public: + explicit CfgBuilder(Module_Handler *h, unsigned f) + : AstVisitor(false), mHandler(h), mFlags(f) {} + ~CfgBuilder() = default; + + void Build(); + + // Create CfgFunc nodes for a module + CfgFunc *InitCfgFunc(ModuleNode *module); + + CfgFunc *NewFunction(TreeNode *); + CfgBB *NewBB(BBKind k); + + static void Push(TargetBBStack &stack, CfgBB* bb, TreeNode *label); + static CfgBB *LookUp(TargetBBStack &stack, TreeNode *label); + static void Pop(TargetBBStack &stack); + + void InitializeFunction(CfgFunc *func); + void FinalizeFunction(); + + // For function and lambda + FunctionNode *VisitFunctionNode(FunctionNode *node); + LambdaNode *VisitLambdaNode(LambdaNode *node); + + // For class and interface + ClassNode *VisitClassNode(ClassNode *node); + InterfaceNode *VisitInterfaceNode(InterfaceNode *node); + StructNode *VisitStructNode(StructNode *node); + + // For statements of control flow + ReturnNode *VisitReturnNode(ReturnNode *node); + CondBranchNode *VisitCondBranchNode(CondBranchNode *node); + ForLoopNode *VisitForLoopNode(ForLoopNode *node); + WhileLoopNode *VisitWhileLoopNode(WhileLoopNode *node); + DoLoopNode *VisitDoLoopNode(DoLoopNode *node); + ContinueNode *VisitContinueNode(ContinueNode *node); + BreakNode *VisitBreakNode(BreakNode *node); + SwitchNode *VisitSwitchNode(SwitchNode *node); + TryNode *VisitTryNode(TryNode *node); + ThrowNode *VisitThrowNode(ThrowNode *node); + BlockNode *VisitBlockNode(BlockNode *node); + NamespaceNode *VisitNamespaceNode(NamespaceNode *node); + + // For statements of a BB + PassNode *VisitPassNode(PassNode *node); + TemplateLiteralNode *VisitTemplateLiteralNode(TemplateLiteralNode *node); + ImportNode *VisitImportNode(ImportNode *node); + ExportNode *VisitExportNode(ExportNode *node); + DeclNode *VisitDeclNode(DeclNode *node); + ParenthesisNode *VisitParenthesisNode(ParenthesisNode *node); + CastNode *VisitCastNode(CastNode *node); + ArrayElementNode *VisitArrayElementNode(ArrayElementNode *node); + VarListNode *VisitVarListNode(VarListNode *node); + ExprListNode *VisitExprListNode(ExprListNode *node); + UnaOperatorNode *VisitUnaOperatorNode(UnaOperatorNode *node); + BinOperatorNode *VisitBinOperatorNode(BinOperatorNode *node); + TerOperatorNode *VisitTerOperatorNode(TerOperatorNode *node); + InstanceOfNode *VisitInstanceOfNode(InstanceOfNode *node); + TypeOfNode *VisitTypeOfNode(TypeOfNode *node); + NewNode *VisitNewNode(NewNode *node); + DeleteNode *VisitDeleteNode(DeleteNode *node); + CallNode *VisitCallNode(CallNode *node); + AssertNode *VisitAssertNode(AssertNode *node); + UserTypeNode *VisitUserTypeNode(UserTypeNode *node); + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); + LiteralNode *VisitLiteralNode(LiteralNode *node); + TypeAliasNode *VisitTypeAliasNode(TypeAliasNode *node); + FieldNode *VisitFieldNode(FieldNode *node); + + TreeNode *BaseTreeNode(TreeNode *node); +}; +} +#endif diff --git a/src/MapleFE/astopt/include/ast_common.h b/src/MapleFE/astopt/include/ast_common.h new file mode 100644 index 0000000000000000000000000000000000000000..7c25f1ca9f1e7553c799aefcba22a8f93d64c638 --- /dev/null +++ b/src/MapleFE/astopt/include/ast_common.h @@ -0,0 +1,42 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __AST_COMMON_HEADER__ +#define __AST_COMMON_HEADER__ + +namespace maplefe { + +#define DEFAULTVALUE 0xdeadbeef +#define RENAMINGSUFFIX "__RENAMED" + +#define NOTYETIMPL(M) { if (mFlags & FLG_trace) { MNYI(M); }} +#define MSGNOLOC0(M) { if (mFlags & FLG_trace_3) { MMSGNOLOC0(M); }} +#define MSGNOLOC(M,v) { if (mFlags & FLG_trace_3) { MMSGNOLOC(M,v); }} + +enum AST_Flags { + FLG_trace_1 = 0x00000001, + FLG_trace_2 = 0x00000002, + FLG_trace_3 = 0x00000004, + FLG_trace_4 = 0x00000008, + FLG_trace = 0x0000000f, + + FLG_emit_ts = 0x00000010, + FLG_emit_ts_only = 0x00000020, + FLG_format_cpp = 0x00000040, + FLG_no_imported = 0x00000080, +}; + +} +#endif diff --git a/src/MapleFE/astopt/include/ast_dfa.h b/src/MapleFE/astopt/include/ast_dfa.h new file mode 100644 index 0000000000000000000000000000000000000000..5e232449f729595439d87b1c02c3d65e96cece52 --- /dev/null +++ b/src/MapleFE/astopt/include/ast_dfa.h @@ -0,0 +1,155 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __AST_DFA_HEADER__ +#define __AST_DFA_HEADER__ + +#include +#include + +#include "stringpool.h" +#include "ast_module.h" +#include "ast.h" +#include "ast_type.h" +#include "ast_handler.h" +#include "gen_astvisitor.h" + +namespace maplefe { + +// def positions: +typedef std::pair DefPosition; +// map +typedef std::unordered_map BVMap; + +class AST_DFA { + private: + Module_Handler *mHandler; + unsigned mFlags; + std::unordered_map mVar2DeclMap; // var to decl, both NodeId + + // stmt id + SmallVector mStmtIdVec; + std::unordered_map mStmtId2StmtMap; + std::unordered_map mEntryBbId2FuncMap; + + // def node id set + std::unordered_set mDefNodeIdSet; + // def and use id set: i in i++; i+=j; + std::unordered_set mDefUseNodeIdSet; + // def positions, def index + SmallVector mDefPositionVec; + // use stridx to set of node id + std::unordered_map> mUsePositionMap; + + // followint maps with key BB id + BVMap mPrsvMap; + BVMap mGenMap; + BVMap mRchInMap; // reaching definition bit vector entering bb + BVMap mRchOutMap; + + // def/use nid --> stmtid + std::unordered_map mNodeId2StmtIdMap; + // stmtid --> bbid + std::unordered_map mStmtId2BbIdMap; + + // def stridx set + std::unordered_set mDefStrIdxSet; + // def-use : key is def node id to a set of use node id + std::unordered_map> mDefUseMap; + + friend class DefUseChainVisitor; + + public: + explicit AST_DFA(Module_Handler *h, unsigned f) : mHandler(h), mFlags(f) {} + ~AST_DFA(); + + void DataFlowAnalysis(); + + void CollectInfo(); + void CollectDefNodes(); + void BuildBitVectors(); + void BuildDefUseChain(); + + bool IsDef(unsigned nid) { return mDefNodeIdSet.find(nid) != mDefNodeIdSet.end();} + bool IsDefUse(unsigned nid) { return mDefUseNodeIdSet.find(nid) != mDefUseNodeIdSet.end();} + // return def stridx, return 0 if no def + unsigned GetDefStrIdx(TreeNode *node); + // return def nodeId, return 0 if no def + unsigned AddDef(TreeNode *node, unsigned &bitnum, unsigned bbid); + + void SetNodeId2StmtId(unsigned nid, unsigned sid) { mNodeId2StmtIdMap[nid] = sid; } + unsigned GetStmtIdFromNodeId(unsigned id) { return mNodeId2StmtIdMap[id]; } + unsigned GetBbIdFromStmtId(unsigned id) { return mStmtId2BbIdMap[id]; } + TreeNode *GetStmtFromStmtId(unsigned id) { return mStmtId2StmtMap[id]; } + CfgBB *GetBbFromBbId(unsigned id) { return mHandler->GetBbFromBbId(id); } + + void DumpDefPosition(unsigned idx, DefPosition pos); + void DumpDefPositionVec(); + void DumpReachDefIn(); + + void DumpBV(BitVector *bv); + void DumpBVMap(BVMap &bvmap); + void DumpAllBVMaps(); + void DumpDefUse(); + void TestBV(); + void Clear(); +}; + +class CollectInfoVisitor : public AstVisitor { + private: + AST_DFA *mDFA; + unsigned mStmtIdx; + unsigned mBbId; + + public: + explicit CollectInfoVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mDFA(h->GetDFA()) {} + ~CollectInfoVisitor() = default; + + void SetStmtIdx(unsigned id) { mStmtIdx = id; } + void SetBbId(unsigned id) { mBbId = id; } + + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); +}; + +class DefUseChainVisitor : public AstVisitor { + private: + Module_Handler *mHandler; + AST_DFA *mDFA; + unsigned mFlags; + unsigned mStmtIdx; + unsigned mBbId; + + public: + unsigned mDefNodeId; + unsigned mDefStrIdx; + unsigned mReachDef; + unsigned mReachNewDef; + + public: + explicit DefUseChainVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h), mDFA(h->GetDFA()), mFlags(f) {} + ~DefUseChainVisitor() = default; + + void SetStmtIdx(unsigned id) { mStmtIdx = id; } + void SetBbId(unsigned id) { mBbId = id; } + void VisitBB(unsigned bbid); + + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); + BinOperatorNode *VisitBinOperatorNode(BinOperatorNode *node); +}; + +} +#endif diff --git a/src/MapleFE/astopt/include/ast_handler.h b/src/MapleFE/astopt/include/ast_handler.h new file mode 100644 index 0000000000000000000000000000000000000000..42153f013fb46b771480e7cba2c63a86480d7f76 --- /dev/null +++ b/src/MapleFE/astopt/include/ast_handler.h @@ -0,0 +1,267 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __AST_HANDLER_HEADER__ +#define __AST_HANDLER_HEADER__ + +#include +#include +#include +#include +#include +#include +#include +#include "ast_module.h" +#include "ast.h" +#include "astopt.h" +#include "ast_cfg.h" +#include "ast_type.h" +#include "ast_common.h" +#include "gen_astvisitor.h" + +namespace maplefe { + +class CfgBB; +class CfgFunc; +class AST_INFO; +class AST_ADJ; +class AST_CFA; +class AST_DFA; +class AST_SCP; +class AST_Util; +class AST_XXport;; +class Module_Handler; +class TypeInfer; +class TypeTable; +class AstOpt; + +using HandlerIndex = unsigned; +const HandlerIndex HandlerNotFound = UINT_MAX; + +struct StrLess { + bool operator()(const char *p, const char *q) const { + return std::strcmp(p, q) < 0; + } +}; + +class AST_Handler { + private: + MemPool mMemPool; // Memory pool for all CfgFunc, CfgBB, etc. + AstOpt *mAstOpt; + unsigned mSize; + unsigned mFlags; + + // vector of all AST modules + SmallVector mModuleHandlers; + Module_Handler *GetModuleHandler(ModuleNode *module); + + public: + // mapping of mModuleHandlers index with its corresponding filename as its key + std::map mModuleHandlerMap; + + explicit AST_Handler(unsigned f) : mSize(0), mFlags(f) {} + ~AST_Handler() {mMemPool.Release();} + + MemPool *GetMemPool() {return &mMemPool;} + + AstOpt *GetAstOpt() {return mAstOpt;} + void SetAstOpt(AstOpt *opt) {mAstOpt = opt;} + + Module_Handler *GetModuleHandler(unsigned i) {return mModuleHandlers.ValueAtIndex(i);} + Module_Handler *GetModuleHandler(TreeNode *node); + + unsigned GetSize() {return mSize;} + + // If m does not exist in mModuleHandlerMap, + // create an object of Module_Handler for module m + // add this object to mModuleHandlers + // map its corresponding filename and the index of this object in mModuleHandlers in mModuleHandlerMap + // return true + // Otherwise, + // return false + bool AddModule(ModuleNode *m); + + // Return an index of mModuleHandlers if filename exists in mModuleHandlerMap, otherwise return HandlerNotFound + HandlerIndex GetHandlerIndex(const char *filename); +}; + +// Each source file is a module +class Module_Handler { + private: + AST_Handler *mASTHandler; + ModuleNode *mASTModule; // for an AST module + CfgFunc *mCfgFunc; // initial CfgFunc in module scope + AST_INFO *mINFO; + AST_ADJ *mADJ; + AST_SCP *mSCP; + TypeInfer *mTI; + AST_CFA *mCFA; + AST_DFA *mDFA; + AST_Util *mUtil; + const char *mOutputFilename; + unsigned mHidx; // handler index in AST_Handler + + unsigned mFlags; + bool mIsTS; + + std::unordered_map mNodeId2BbMap; + + public: + // module's ast function vector + std::vector mModuleFuncs; + // all BBs + std::unordered_map mBbId2BbMap; + // bbid vec - only reachable BBs + std::vector mBbIdVec; + // identifier node id to decl + std::unordered_map mNodeId2Decl; + // array's element type: decl node id to typeid + std::unordered_map mArrayDeclId2EleTypeIdMap; + // array's element typeidx: decl node id to typeidx + std::unordered_map mArrayDeclId2EleTypeIdxMap; + // array literal's dim: decl node id to dim + std::unordered_map mArrayDeclId2DimMap; + // nodeid to used generator + std::unordered_map mGeneratorUsedMap; + // fields' nodeid set + std::unordered_set mDirectFieldSet; + // alias type, identifier node id + std::unordered_set mAliasTypeSet; + + public: + explicit Module_Handler(unsigned f) : + mCfgFunc(nullptr), + mINFO(nullptr), + mADJ(nullptr), + mSCP(nullptr), + mTI(nullptr), + mCFA(nullptr), + mDFA(nullptr), + mUtil(nullptr), + mFlags(f) {} + ~Module_Handler(); + + void BasicAnalysis(); + void CollectInfo(); + void AdjustAST(); + void ScopeAnalysis(); + void TypeInference(); + void BuildCFG(); + void ControlFlowAnalysis(); + void DataFlowAnalysis(); + + const char *GetOutputFilename() {return mOutputFilename;} + void SetOutputFilename(const char *name) {mOutputFilename = name;} + + void SetASTHandler(AST_Handler *h) {mASTHandler = h;} + AST_Handler *GetASTHandler() {return mASTHandler;} + + void SetASTModule(ModuleNode *mod) {mASTModule = mod;} + ModuleNode *GetASTModule() {return mASTModule;} + + MemPool *GetMemPool(); + + void SetCfgFunc(CfgFunc *func) {mCfgFunc = func;} + CfgFunc *GetCfgFunc() {return mCfgFunc;} + + void SetBbFromNodeId(unsigned id, CfgBB *bb) { mNodeId2BbMap[id] = bb; } + CfgBB *GetBbFromNodeId(unsigned id) { return mNodeId2BbMap[id]; } + + void SetBbFromBbId(unsigned id, CfgBB *bb) { mBbId2BbMap[id] = bb; } + CfgBB *GetBbFromBbId(unsigned id) { return mBbId2BbMap[id]; } + + unsigned GetFlags() {return mFlags;} + unsigned GetHidx() {return mHidx;} + AST_INFO *GetINFO() {return mINFO;} + AST_ADJ *GetADJ() {return mADJ;} + AST_CFA *GetCFA() {return mCFA;} + AST_DFA *GetDFA() {return mDFA;} + AST_SCP *GetSCP() {return mSCP;} + TypeInfer *GetTI() {return mTI;} + AST_Util *GetUtil() {return mUtil;} + AstOpt *GetAstOpt(); + AST_XXport *GetASTXXport(); + + void SetHidx(unsigned idx) {mHidx = idx;} + void SetINFO(AST_INFO *p) {mINFO = p;} + void SetADJ(AST_ADJ *p) {mADJ = p;} + void SetCFA(AST_CFA *p) {mCFA = p;} + void SetDFA(AST_DFA *p) {mDFA = p;} + void SetSCP(AST_SCP *p) {mSCP = p;} + void SetTI(TypeInfer *p) {mTI = p;} + void SetUtil(AST_Util *p) {mUtil = p;} + void SetIsTS(bool b) {mIsTS = b;} + + // deep true : find Decl in imported module as well + // false : find Decl in current module only + TreeNode *FindDecl(IdentifierNode *node, bool deep = false); + + TreeNode *FindType(IdentifierNode *node); + TreeNode *FindFunc(TreeNode *node); + + void AddDirectField(TreeNode *node); + bool IsDirectField(TreeNode *node); + + bool IsFromLambda(TreeNode *node); + bool IsDef(TreeNode *node); + bool IsTS() {return mIsTS;} + + void AddNodeId2DeclMap(unsigned nid, TreeNode *node) { + mNodeId2Decl[nid] = node; + } + + void AddAliasType(unsigned nid) { mAliasTypeSet.insert(nid); } + bool isAliasType(unsigned nid) { + return mAliasTypeSet.find(nid) != mAliasTypeSet.end(); + } + bool isAliasType(TreeNode *node) { return isAliasType(node->GetNodeId()); } + + template + T *NewTreeNode() { + T *node = (T*)gTreePool.NewTreeNode(sizeof(T)); + new (node) T(); + AstOpt *opt = mASTHandler->GetAstOpt(); + opt->AddNodeId2NodeMap(node); + return node; + } + + Module_Handler *GetModuleHandler(unsigned i) {return mASTHandler->GetModuleHandler(i);} + Module_Handler *GetModuleHandler(TreeNode *node) {return mASTHandler->GetModuleHandler(node);} + + // array's element typeid + TypeId GetArrayElemTypeId(unsigned nid); + void SetArrayElemTypeId(unsigned nid, TypeId tid); + unsigned GetArrayElemTypeIdx(unsigned nid); + void SetArrayElemTypeIdx(unsigned nid, unsigned tidx); + DimensionNode *GetArrayDim(unsigned nid); + void SetArrayDim(unsigned nid, DimensionNode *dim); + + // used generator + void AddGeneratorUsed(unsigned nid, FunctionNode *func); + bool IsGeneratorUsed(unsigned nid); + FunctionNode *GetGeneratorUsed(unsigned nid); + bool UpdateGeneratorUsed(unsigned target, unsigned src); + + // API to check a node is c++ field which satisfy both: + // 1. direct field + // 2. its name is valid in c++ + bool IsCppField(TreeNode *node); + + void Dump(char *msg); + void DumpArrayElemTypeIdMap(); +}; + +} +#endif diff --git a/src/MapleFE/astopt/include/ast_info.h b/src/MapleFE/astopt/include/ast_info.h new file mode 100644 index 0000000000000000000000000000000000000000..83a0fc37122e10231fdde2f6d7050bd0eaf908ff --- /dev/null +++ b/src/MapleFE/astopt/include/ast_info.h @@ -0,0 +1,197 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __AST_INFO_HEADER__ +#define __AST_INFO_HEADER__ + +#include +#include +#include +#include +#include "ast_module.h" +#include "ast.h" +#include "ast_type.h" +#include "gen_astvisitor.h" + +namespace maplefe { + +class FindStrIdxVisitor; + +class AST_INFO { + private: + Module_Handler *mHandler; + unsigned mFlags; + unsigned mNum; + bool mNameAnonyStruct; + unsigned mPass; + FindStrIdxVisitor *mStrIdxVisitor; + + std::unordered_set mReachableBbIdx;; + std::unordered_map> mFieldNum2StructNodeMap; + std::unordered_map> mStructId2FieldsMap; + std::unordered_map mStrIdx2StructMap; + std::unordered_set mTypeParamStrIdxSet; + std::unordered_set mWithTypeParamNodeSet; + std::unordered_set mWithThisFuncSet;; + std::unordered_set mFromLambda; + std::unordered_map mStrIdx2TypeIdxMap; + + void AddField(unsigned nid, TreeNode *node); + + public: + explicit AST_INFO(Module_Handler *h, unsigned f) : mHandler(h), mFlags(f), mNum(1), + mNameAnonyStruct(false) {} + ~AST_INFO() {} + + void CollectInfo(); + + unsigned GetPass() { return mPass; } + TypeId GetTypeId(TreeNode *node); + unsigned GetFieldsSize(TreeNode *node, bool native = false); + TreeNode *GetField(TreeNode *node, unsigned i, bool native = false); + void AddField(TreeNode *container, TreeNode *node); + TreeNode *GetField(unsigned nid, unsigned stridx); + unsigned GetSuperSize(TreeNode *node, unsigned idx); + TreeNode *GetSuper(TreeNode *node, unsigned i, unsigned idx); + + void SetStrIdx2Struct(unsigned stridx, TreeNode *node) { mStrIdx2StructMap[stridx] = node; } + TreeNode *GetStructFromStrIdx(unsigned stridx) { return mStrIdx2StructMap[stridx]; } + + TreeNode *GetCanonicStructNode(TreeNode *node); + + IdentifierNode *CreateIdentifierNode(unsigned stridx); + UserTypeNode *CreateUserTypeNode(unsigned stridx, ASTScope *scope = NULL); + UserTypeNode *CreateUserTypeNode(IdentifierNode *node); + TypeAliasNode *CreateTypeAliasNode(TreeNode *to, TreeNode *from); + StructNode *CreateStructFromStructLiteral(StructLiteralNode *node); + + unsigned GetAnonymousName(); + TreeNode *GetAnonymousStruct(TreeNode *node); + + bool IsInterface(TreeNode *node); + bool IsTypeIdCompatibleTo(TypeId field, TypeId target); + bool IsTypeCompatible(TreeNode *node1, TreeNode *node2); + bool IsFieldCompatibleTo(TreeNode *from, TreeNode *to); + + void SetNameAnonyStruct(bool b) { mNameAnonyStruct = b; } + bool GetNameAnonyStruct() { return mNameAnonyStruct; } + + template void SortFields(T1 *node); + template void ExtendFields(T1 *node, TreeNode *sup); + + bool WithStrIdx(TreeNode *node, unsigned stridx); + bool WithTypeParam(TreeNode *node); + bool WithTypeParamFast(TreeNode *node); + void InsertTypeParamStrIdx(unsigned stridx) { mTypeParamStrIdxSet.insert(stridx); } + void InsertWithTypeParamNode(TreeNode *node) { mWithTypeParamNodeSet.insert(node->GetNodeId()); } + + bool WithThis(TreeNode *node); + void InsertWithThisFunc(TreeNode *node) { mWithThisFuncSet.insert(node->GetNodeId()); } + bool IsFuncBodyUseThis(TreeNode *node) { return mWithThisFuncSet.find(node->GetNodeId())!= mWithThisFuncSet.end(); } + + bool WithSuper(TreeNode *node); + + void SetTypeId(TreeNode *node, TypeId tid); + void SetTypeIdx(TreeNode *node, unsigned tidx); + + void AddFromLambda(unsigned nid) { mFromLambda.insert(nid); } + bool IsFromLambda(unsigned nid) { return mFromLambda.find(nid) != mFromLambda.end(); } + + void AddBuiltInTypes(); + bool IsBuiltInType(TreeNode *node); + unsigned GetBuiltInTypeIdx(unsigned stridx); + unsigned GetBuiltInTypeIdx(TreeNode *node); +}; + +class FillNodeInfoVisitor : public AstVisitor { + private: + Module_Handler *mHandler; + AST_INFO *mInfo; + + public: + explicit FillNodeInfoVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h) { + mInfo= mHandler->GetINFO(); + } + ~FillNodeInfoVisitor() = default; + + LiteralNode *VisitLiteralNode(LiteralNode *node); + PrimTypeNode *VisitPrimTypeNode(PrimTypeNode *node); + UserTypeNode *VisitUserTypeNode(UserTypeNode *node); + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); + FunctionNode *VisitFunctionNode(FunctionNode *node); +}; + +class ClassStructVisitor : public AstVisitor { + private: + Module_Handler *mHandler; + AST_INFO *mInfo; + + public: + explicit ClassStructVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h) { + mInfo= mHandler->GetINFO(); + } + ~ClassStructVisitor() = default; + + StructLiteralNode *VisitStructLiteralNode(StructLiteralNode *node); + StructNode *VisitStructNode(StructNode *node); + ClassNode *VisitClassNode(ClassNode *node); + InterfaceNode *VisitInterfaceNode(InterfaceNode *node); + TypeParameterNode *VisitTypeParameterNode(TypeParameterNode *node); + FunctionNode *VisitFunctionNode(FunctionNode *node); +}; + +class FunctionVisitor : public AstVisitor { + private: + Module_Handler *mHandler; + AST_INFO *mInfo; + + public: + explicit FunctionVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h) { + mInfo= mHandler->GetINFO(); + } + ~FunctionVisitor() = default; + + FunctionNode *VisitFunctionNode(FunctionNode *node); +}; + +class FindStrIdxVisitor : public AstVisitor { + private: + Module_Handler *mHandler; + AST_INFO *mInfo; + unsigned mStrIdx; + bool mCheckThis; + bool mFound; + + public: + explicit FindStrIdxVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h), mStrIdx(0), + mCheckThis(false), mFound(false) { + mInfo = mHandler->GetINFO(); + } + ~FindStrIdxVisitor() = default; + + void ResetFound() { mFound = false; } + void SetStrIdx(unsigned stridx) { mStrIdx = stridx; } + void SetCheckThis(bool b = true) { mCheckThis = b; } + bool GetFound() { return mFound; } + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); + LiteralNode *VisitLiteralNode(LiteralNode *node); +}; + +} +#endif diff --git a/src/MapleFE/astopt/include/ast_scp.h b/src/MapleFE/astopt/include/ast_scp.h new file mode 100644 index 0000000000000000000000000000000000000000..1a9a7124a2adbd4d89b4da617fa21fbb57763f6a --- /dev/null +++ b/src/MapleFE/astopt/include/ast_scp.h @@ -0,0 +1,173 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __AST_SCP_HEADER__ +#define __AST_SCP_HEADER__ + +#include +#include +#include + +#include "stringpool.h" +#include "ast_module.h" +#include "ast.h" +#include "ast_type.h" +#include "ast_handler.h" +#include "gen_astvisitor.h" + +namespace maplefe { + +class AST_SCP { + private: + Module_Handler *mHandler; + unsigned mFlags; + + public: + explicit AST_SCP(Module_Handler *h, unsigned f) : mHandler(h), mFlags(f) {} + ~AST_SCP() {}; + + void ScopeAnalysis(); + + void BuildScope(); + void RenameVar(); + void AdjustASTWithScope(); +}; + +class BuildScopeBaseVisitor : public AstVisitor { + public: + std::stack mScopeStack; + std::stack mUserScopeStack; + + public: + explicit BuildScopeBaseVisitor(unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base) {} + ~BuildScopeBaseVisitor() = default; + +#undef NODEKIND +#define NODEKIND(K) virtual K##Node *Visit##K##Node(K##Node *node) {\ + ASTScope *scope = mScopeStack.top(); \ + node->SetScope(scope); \ + (void) AstVisitor::Visit##K##Node(node); \ + return node; \ +} +#include "ast_nk.def" +}; + +class BuildScopeVisitor : public BuildScopeBaseVisitor { + private: + Module_Handler *mHandler; + ModuleNode *mASTModule; + unsigned mFlags; + bool mRunIt; + AST_XXport *mXXport; + + // stridx to scope map for struct/class + std::unordered_map mStrIdx2ScopeMap;; + + std::unordered_map> mScope2DeclsMap; + std::unordered_map> mScope2ImportedDeclsMap; + std::unordered_map> mScope2ExportedDeclsMap; + std::unordered_map> mScope2TypesMap; + + public: + explicit BuildScopeVisitor(Module_Handler *h, unsigned f, bool base = false) + : BuildScopeBaseVisitor(f, base), mHandler(h), mFlags(f) { + mASTModule = mHandler->GetASTModule(); + mXXport = h->GetASTXXport(); + } + ~BuildScopeVisitor() = default; + + bool GetRunIt() { return mRunIt; } + void SetRunIt(bool b) { mRunIt = b; } + + void InitInternalTypes(); + ClassNode *AddClass(unsigned stridx, unsigned tyidx = 0); + FunctionNode *AddFunction(std::string name); + + void AddType(ASTScope *scope, TreeNode *node); + void AddImportedDecl(ASTScope *scope, TreeNode *node); + void AddExportedDecl(ASTScope *scope, TreeNode *node); + void AddDecl(ASTScope *scope, TreeNode *node); + void AddTypeAndDecl(ASTScope *scope, TreeNode *node); + ASTScope *NewScope(ASTScope *parent, TreeNode *node); + + void AddScopeMap(unsigned stridx, ASTScope *scope) { mStrIdx2ScopeMap[stridx] = scope; } + + // scope nodes + BlockNode *VisitBlockNode(BlockNode *node); + FunctionNode *VisitFunctionNode(FunctionNode *node); + LambdaNode *VisitLambdaNode(LambdaNode *node); + ClassNode *VisitClassNode(ClassNode *node); + StructNode *VisitStructNode(StructNode *node); + StructLiteralNode *VisitStructLiteralNode(StructLiteralNode *node); + InterfaceNode *VisitInterfaceNode(InterfaceNode *node); + NamespaceNode *VisitNamespaceNode(NamespaceNode *node); + ForLoopNode *VisitForLoopNode(ForLoopNode *node); + TryNode *VisitTryNode(TryNode *node); + CatchNode *VisitCatchNode(CatchNode *node); + FinallyNode *VisitFinallyNode(FinallyNode *node); + + FieldNode *VisitFieldNode(FieldNode *node); + TypeParameterNode *VisitTypeParameterNode(TypeParameterNode *node); + + // related node with scope : decl, type + DeclNode *VisitDeclNode(DeclNode *node); + UserTypeNode *VisitUserTypeNode(UserTypeNode *node); + TypeAliasNode *VisitTypeAliasNode(TypeAliasNode *node); + ImportNode *VisitImportNode(ImportNode *node); + ExportNode *VisitExportNode(ExportNode *node); +}; + +class RenameVarVisitor : public AstVisitor { + private: + Module_Handler *mHandler; + ModuleNode *mASTModule; + AstOpt *mAstOpt; + unsigned mFlags; + + public: + unsigned mPass; + unsigned mOldStrIdx; + unsigned mNewStrIdx; + std::unordered_map> mStridx2DeclIdMap; + + public: + explicit RenameVarVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h), mFlags(f) { + mASTModule = mHandler->GetASTModule(); + mAstOpt = mHandler->GetASTHandler()->GetAstOpt(); + } + ~RenameVarVisitor() = default; + + bool SkipRename(IdentifierNode *node); + bool IsFuncArg(FunctionNode *func, IdentifierNode *node); + void InsertToStridx2DeclIdMap(unsigned stridx, IdentifierNode *node); + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); +}; + +class AdjustASTWithScopeVisitor : public AstVisitor { + private: + Module_Handler *mHandler; + + public: + explicit AdjustASTWithScopeVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h) {} + ~AdjustASTWithScopeVisitor() = default; + + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); +}; + +} +#endif diff --git a/src/MapleFE/astopt/include/ast_ti.h b/src/MapleFE/astopt/include/ast_ti.h new file mode 100644 index 0000000000000000000000000000000000000000..ece38d68dcbe7e6257562c68bfc23f37383b231b --- /dev/null +++ b/src/MapleFE/astopt/include/ast_ti.h @@ -0,0 +1,232 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __AST_TYPE_INFERENCE_HEADER__ +#define __AST_TYPE_INFERENCE_HEADER__ + +#include +#include +#include "ast_module.h" +#include "ast.h" +#include "ast_type.h" +#include "gen_astvisitor.h" +#include "ast_common.h" + +namespace maplefe { + +class Module_Handler; + +class TypeInfer { + private: + Module_Handler *mHandler; + unsigned mFlags; + + public: + explicit TypeInfer(Module_Handler *h, unsigned f) : mHandler(h), mFlags(f) {} + ~TypeInfer() {} + + void TypeInference(); + void CheckType(); +}; + +class BuildIdNodeToDeclVisitor : public AstVisitor { + Module_Handler *mHandler; + + public: + explicit BuildIdNodeToDeclVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h) {} + ~BuildIdNodeToDeclVisitor() = default; + + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); +}; + +class BuildIdDirectFieldVisitor : public AstVisitor { + Module_Handler *mHandler; + unsigned mFlags; + + public: + explicit BuildIdDirectFieldVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h), mFlags(f) {} + ~BuildIdDirectFieldVisitor() = default; + + TreeNode *GetParentVarClass(TreeNode *node); + Module_Handler *GetHandler(TreeNode *node); + + FieldNode *VisitFieldNode(FieldNode *node); + FieldLiteralNode *VisitFieldLiteralNode(FieldLiteralNode *node); + ArrayElementNode *VisitArrayElementNode(ArrayElementNode *node); + void Dump(); +}; + +class TypeInferBaseVisitor : public AstVisitor { + public: + explicit TypeInferBaseVisitor(unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base) {} + ~TypeInferBaseVisitor() = default; + +#undef NODEKIND +#define NODEKIND(K) virtual K##Node *Visit##K##Node(K##Node *node) { \ + (void) AstVisitor::Visit##K##Node(node); \ + return node; \ +} +#include "ast_nk.def" +}; + +class ChangeTypeIdxVisitor : public AstVisitor { + private: + Module_Handler *mHandler; + unsigned mStrIdx; + unsigned mTypeIdx; + + public: + explicit ChangeTypeIdxVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h) {} + ~ChangeTypeIdxVisitor() = default; + + void Setup(unsigned stridx, unsigned tidx) { mStrIdx = stridx; mTypeIdx = tidx;} + + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); +}; + +class TypeInferVisitor : public TypeInferBaseVisitor { + private: + Module_Handler *mHandler; + unsigned mFlags; + bool mUpdated; + AST_INFO *mInfo; + AST_XXport *mXXport; + AstOpt *mAstOpt; + + ChangeTypeIdxVisitor *mChangeTypeIdxVisitor; + + std::unordered_map> mParam2ArgArrayDeclMap;; + + // func nodeid to typeidx + std::unordered_map mFuncIsNodeMap;; + std::unordered_map> mCbFuncIsDone; + + public: + explicit TypeInferVisitor(Module_Handler *h, unsigned f, bool base = false) + : TypeInferBaseVisitor(f, base), mHandler(h), mFlags(f) { + mChangeTypeIdxVisitor = new ChangeTypeIdxVisitor(h, f, true); + mInfo = h->GetINFO(); + mXXport = h->GetASTXXport(); + mAstOpt = h->GetAstOpt(); + } + + ~TypeInferVisitor() = default; + + bool IsPrimTypeId(TypeId tid); + + bool GetUpdated() {return mUpdated;} + void SetUpdated(bool b = true) {mUpdated = b;} + + void SetTypeId(TreeNode *node, TypeId tid); + void SetTypeId(TreeNode *node1, TreeNode *node2); + void UpdateTypeId(TreeNode *node, TypeId tid); + void UpdateTypeId(TreeNode *node1, TreeNode *node2); + + void SetTypeIdx(TreeNode *node, unsigned tidx); + void SetTypeIdx(TreeNode *node1, TreeNode *node2); + void UpdateTypeIdx(TreeNode *node, unsigned tidx); + void UpdateTypeIdx(TreeNode *node1, TreeNode *node2); + + void UpdateFuncRetTypeId(FunctionNode *node, TypeId tid, unsigned tidx); + void UpdateTypeUseNode(TreeNode *target, TreeNode *input); + void UpdateArgArrayDecls(unsigned nid, TypeId tid); + void UpdateArrayElemTypeMap(TreeNode *node, TypeId tid, unsigned tidx); + void UpdateArrayDimMap(TreeNode *node, DimensionNode *dim); + bool UpdateVarTypeWithInit(TreeNode *var, TreeNode *init); + TypeId GetArrayElemTypeId(TreeNode *node); + unsigned GetArrayElemTypeIdx(TreeNode *node); + + TypeId MergeTypeId(TypeId tia, TypeId tib); + unsigned MergeTypeIdx(unsigned tia, unsigned tib); + + bool IsArray(TreeNode *node); + // refer to shared/include/supported_types.def + bool IsPrimTypeIdx(unsigned tidx) { return tidx > 0 && tidx < TY_Void; } + + PrimTypeNode *GetOrClonePrimTypeNode(PrimTypeNode *node, TypeId tid); + + TreeNode *VisitClassField(TreeNode *node); + + ArrayElementNode *VisitArrayElementNode(ArrayElementNode *node); + ArrayLiteralNode *VisitArrayLiteralNode(ArrayLiteralNode *node); + AsTypeNode *VisitAsTypeNode(AsTypeNode *node); + BinOperatorNode *VisitBinOperatorNode(BinOperatorNode *node); + CallNode *VisitCallNode(CallNode *node); + CastNode *VisitCastNode(CastNode *node); + ClassNode *VisitClassNode(ClassNode *node); + CondBranchNode *VisitCondBranchNode(CondBranchNode *node); + DeclNode *VisitDeclNode(DeclNode *node); + ExportNode *VisitExportNode(ExportNode *node); + FieldLiteralNode *VisitFieldLiteralNode(FieldLiteralNode *node); + FieldNode *VisitFieldNode(FieldNode *node); + ForLoopNode *VisitForLoopNode(ForLoopNode *node); + FunctionNode *VisitFunctionNode(FunctionNode *node); + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); + ImportNode *VisitImportNode(ImportNode *node); + InterfaceNode *VisitInterfaceNode(InterfaceNode *node); + IsNode *VisitIsNode(IsNode *node); + LambdaNode *VisitLambdaNode(LambdaNode *node); + LiteralNode *VisitLiteralNode(LiteralNode *node); + NewNode *VisitNewNode(NewNode *node); + ReturnNode *VisitReturnNode(ReturnNode *node); + StructLiteralNode *VisitStructLiteralNode(StructLiteralNode *node); + StructNode *VisitStructNode(StructNode *node); + TemplateLiteralNode *VisitTemplateLiteralNode(TemplateLiteralNode *node); + TerOperatorNode *VisitTerOperatorNode(TerOperatorNode *node); + TypeAliasNode *VisitTypeAliasNode(TypeAliasNode *node); + TypeOfNode *VisitTypeOfNode(TypeOfNode *node); + UnaOperatorNode *VisitUnaOperatorNode(UnaOperatorNode *node); + UserTypeNode *VisitUserTypeNode(UserTypeNode *node); +}; + +class ShareUTVisitor : public AstVisitor { + private: + std::stack mScopeStack; + + public: + explicit ShareUTVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base) {} + ~ShareUTVisitor() = default; + + void Push(ASTScope *scope) { mScopeStack.push(scope); } + void Pop() { mScopeStack.pop(); } + + UserTypeNode *VisitUserTypeNode(UserTypeNode *node); +}; + +class CheckTypeVisitor : public AstVisitor { + private: + Module_Handler *mHandler; + unsigned mFlags; + + std::stack mScopeStack; + + public: + explicit CheckTypeVisitor(Module_Handler *h, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mHandler(h), mFlags(f) {} + ~CheckTypeVisitor() = default; + + // check if typeid "tid" is compatible with "target" + bool IsCompatible(TypeId tid, TypeId target); + + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); +}; + +} +#endif diff --git a/src/MapleFE/astopt/include/ast_util.h b/src/MapleFE/astopt/include/ast_util.h new file mode 100644 index 0000000000000000000000000000000000000000..c2a39d40d31ce275deb9bcf829424acbaca230bd --- /dev/null +++ b/src/MapleFE/astopt/include/ast_util.h @@ -0,0 +1,55 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +////////////////////////////////////////////////////////////////////////////////////////////// +// This is the interface to translate AST to C++ +////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef __AST_UTIL_HEADER__ +#define __AST_UTIL_HEADER__ + +#include + +namespace maplefe { + +class Module_Handler; + +class AST_Util { + private: + Module_Handler *mHandler; + unsigned mFlags; + + std::unordered_set mCppKeywords; + + void BuildCppKeyWordSet(); + + public: + explicit AST_Util(Module_Handler *h, unsigned f) : mHandler(h), mFlags(f) { + BuildCppKeyWordSet(); + } + ~AST_Util() {} + + bool IsDirectField(TreeNode *node); + bool IsCppKeyWord(unsigned stridx); + bool IsCppKeyWord(std::string name); + bool IsCppName(std::string name); + bool IsCppField(TreeNode *node); + + void SetTypeId(TreeNode *node, TypeId tid); + void SetTypeIdx(TreeNode *node, unsigned tidx); +}; + +} +#endif diff --git a/src/MapleFE/astopt/include/ast_xxport.h b/src/MapleFE/astopt/include/ast_xxport.h new file mode 100644 index 0000000000000000000000000000000000000000..f5f99e7352f721b88d1f4db931fd762acdd18be5 --- /dev/null +++ b/src/MapleFE/astopt/include/ast_xxport.h @@ -0,0 +1,166 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __AST_XXPORT_HEADER__ +#define __AST_XXPORT_HEADER__ + +#include +#include +#include +#include +#include +#include +#include "ast_module.h" +#include "ast.h" +#include "gen_astvisitor.h" + +namespace maplefe { + +class AstOpt; +class AST_Handler; +class Module_Handler; + +class XXportInfo { + public: + unsigned mModuleStrIdx; + unsigned mXXportNodeId; + unsigned mDefaultNodeId; + bool mEverything; + std::set> mNodeIdPairs; + + public: + explicit XXportInfo(unsigned stridx, unsigned nid) : + mModuleStrIdx(stridx), mXXportNodeId(nid), mDefaultNodeId(0), mEverything(false) {} + ~XXportInfo() = default; + + void SetEverything() {mEverything = true;} + void Dump(); +}; + +class AST_XXport { + private: + AstOpt *mAstOpt; + AST_Handler *mASTHandler; + unsigned mFlags; + + std::list mHandlersIdxInOrder; + std::unordered_map> mHandlerIdx2DependentHandlerIdxMap; + std::unordered_map mStrIdx2HandlerIdxMap; + + std::unordered_map mIdStrIdx2ModuleStrIdxMap; + + public: + // module handler idx to set of XXportInfo + std::unordered_map> mImports; + std::unordered_map> mExports; + + // module handler idx to import/export nodes in the module + std::unordered_map> mImportNodeSets; + std::unordered_map> mExportNodeSets; + + std::unordered_map> mImportedDeclIds; + std::unordered_map> mExportedDeclIds; + + public: + explicit AST_XXport(AstOpt *o, unsigned f); + ~AST_XXport() {} + + unsigned GetModuleNum(); + + void BuildModuleOrder(); + + void SetModuleStrIdx(); + void CollectXXportNodes(); + + TreeNode *GetTarget(TreeNode *node); + std::string GetTargetFilename(unsigned hidx, TreeNode *node); + void UpdateDependency(unsigned hidx, TreeNode *node); + void AddHandler(); + + void SortHandler(); + + void CollectXXportInfo(unsigned hidx); + void CollectImportInfo(unsigned hidx); + void CollectExportInfo(unsigned hidx); + + void AddHandlerIdx2DependentHandlerIdxMap(unsigned hdlIdx, unsigned depHdlIdx) { + mHandlerIdx2DependentHandlerIdxMap[hdlIdx].insert(depHdlIdx); + } + + unsigned GetHandleIdxFromStrIdx(unsigned stridx); + + // check if node with id is imported decl + bool IsImportedDeclId(unsigned hidx, unsigned id) { + return (std::find(mImportedDeclIds[hidx].begin(), + mImportedDeclIds[hidx].end(), id) != mImportedDeclIds[hidx].end()); + } + + // check if node with id is exported decl + bool IsExportedDeclId(unsigned hidx, unsigned id) { + return (std::find(mExportedDeclIds[hidx].begin(), + mExportedDeclIds[hidx].end(), id) != mExportedDeclIds[hidx].end()); + } + + bool IsImportedExportedDeclId(unsigned hidx, unsigned id) { + return IsImportedDeclId(hidx, id) || IsExportedDeclId(hidx, id); + } + + void AddImportedDeclIds(unsigned hidx, unsigned nid) {mImportedDeclIds[hidx].push_back(nid);} + void AddExportedDeclIds(unsigned hidx, unsigned nid) {mExportedDeclIds[hidx].push_back(nid);} + + TreeNode *FindExportedDecl(unsigned hidx, unsigned stridx); + + // get stridx of M from M.get() + unsigned ExtractTargetStrIdx(TreeNode *node); + + // get/set full module file name stridx of M.ts from an identifier of that module M + unsigned GetModuleStrIdxFromIdStrIdx(unsigned stridx) {return mIdStrIdx2ModuleStrIdxMap[stridx];} + void SetIdStrIdx2ModuleStrIdx(unsigned id, unsigned mod) {mIdStrIdx2ModuleStrIdxMap[id] = mod;} + + // find default exported node in handler + TreeNode *GetExportedDefault(unsigned hstridx); + + // find exported node of given name in handler hidx + TreeNode *GetExportedNamedNode(unsigned hidx, unsigned stridx); + + // find the exported node in exporting module given imported node + // hidx is the handler index of node with index nid + TreeNode *GetExportedNodeFromImportedNode(unsigned hidx, unsigned nid); + + // get identifier from node + TreeNode *GetIdentifier(TreeNode *node); + + void Dump(); +}; + +class XXportBasicVisitor : public AstVisitor { + private: + AST_XXport *mASTXXport; + unsigned mHandlerIdx; + + public: + std::unordered_set mImported; + + public: + explicit XXportBasicVisitor(AST_XXport *xx, Module_Handler *h, unsigned i, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mASTXXport(xx), mHandlerIdx(i) {} + ~XXportBasicVisitor() = default; + + ImportNode *VisitImportNode(ImportNode *node); + ExportNode *VisitExportNode(ExportNode *node); +}; + +} +#endif diff --git a/src/MapleFE/astopt/include/astopt.h b/src/MapleFE/astopt/include/astopt.h new file mode 100644 index 0000000000000000000000000000000000000000..6a5fd6e144fbc8c99b0547c7910bfb0b6e87698b --- /dev/null +++ b/src/MapleFE/astopt/include/astopt.h @@ -0,0 +1,110 @@ +/* +* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +////////////////////////////////////////////////////////////////////////////////////////////// +// This is the interface to translate AST to C++ +////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef __ASTOPT_HEADER__ +#define __ASTOPT_HEADER__ + +#include +#include +#include +#include "ast_module.h" +#include "ast.h" +#include "gen_astvisitor.h" +#include "ast_common.h" + +namespace maplefe { + +class AST_Handler; +class Module_Handler; +class AST_XXport; + +class AstOpt { +private: + AST_Handler *mASTHandler; + AST_XXport *mASTXXport; + unsigned mFlags; + + // nodeid to node map for all nodes in all modules + std::unordered_map mNodeId2NodeMap; + + // language keywords + std::unordered_set mLangKeywords; + + // nodeid to handler map for all nodes in all modules + std::unordered_map mNodeId2HandlerMap; + +public: + // module handlers in mASTHandler sorted by import/export dependency + std::vector mHandlersInOrder; + +public: + explicit AstOpt(AST_Handler *h, unsigned f); + ~AstOpt() {} + + AST_Handler *GetASTHandler() {return mASTHandler;} + AST_XXport *GetASTXXport() {return mASTXXport;} + unsigned GetModuleNum(); + Module_Handler *GetModuleHandler(unsigned i) { return mHandlersInOrder[i]; } + void AddModuleHandler(Module_Handler *h) { mHandlersInOrder.push_back(h); } + + void PreprocessModules(); + virtual void ProcessAST(unsigned trace); + + TreeNode *GetNodeFromNodeId(unsigned nid) { return mNodeId2NodeMap[nid]; } + void AddNodeId2NodeMap(TreeNode *node) { mNodeId2NodeMap[node->GetNodeId()] = node; } + + Module_Handler *GetHandlerFromNodeId(unsigned nid) { return mNodeId2HandlerMap[nid]; } + void AddNodeId2HandlerMap(unsigned nid, Module_Handler *h) { mNodeId2HandlerMap[nid] = h; } + + bool IsLangKeyword(TreeNode *node) { + return mLangKeywords.find(node->GetStrIdx()) != mLangKeywords.end(); + } +}; + +class BuildNodeIdToNodeVisitor : public AstVisitor { + AstOpt *mAstOpt; + unsigned mFlags; + Module_Handler *mHandler; + + public: + explicit BuildNodeIdToNodeVisitor(AstOpt *opt, unsigned f, bool base = false) + : AstVisitor((f & FLG_trace_1) && base), mAstOpt(opt), mFlags(f) {} + ~BuildNodeIdToNodeVisitor() = default; + + void SetHandler(Module_Handler *handler) { mHandler = handler; } + + TreeNode *VisitTreeNode(TreeNode *node) { + if (mFlags & FLG_trace_3) std::cout << "nodeid2node: " << node->GetNodeId() << std::endl; + (void) AstVisitor::VisitTreeNode(node); + mAstOpt->AddNodeId2NodeMap(node); + mAstOpt->AddNodeId2HandlerMap(node->GetNodeId(), mHandler); + return node; + } + + TreeNode *BaseTreeNode(TreeNode *node) { + if (mFlags & FLG_trace_3) std::cout << "nodeid2node: b " << node->GetNodeId() << std::endl; + (void) AstVisitor::BaseTreeNode(node); + mAstOpt->AddNodeId2NodeMap(node); + mAstOpt->AddNodeId2HandlerMap(node->GetNodeId(), mHandler); + return node; + } +}; + +} +#endif diff --git a/src/MapleFE/astopt/include/cpp_keywords.def b/src/MapleFE/astopt/include/cpp_keywords.def new file mode 100644 index 0000000000000000000000000000000000000000..f2fc30566654fbdca92a9621b6324dd4b46be091 --- /dev/null +++ b/src/MapleFE/astopt/include/cpp_keywords.def @@ -0,0 +1,112 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +CPPKEYWORD(alignas) +CPPKEYWORD(alignof) +CPPKEYWORD(and) +CPPKEYWORD(and_eq) +CPPKEYWORD(asm) +CPPKEYWORD(atomic_cancel) +CPPKEYWORD(atomic_commit) +CPPKEYWORD(atomic_noexcept) +CPPKEYWORD(auto) +CPPKEYWORD(bitand) +CPPKEYWORD(bitor) +CPPKEYWORD(bool) +CPPKEYWORD(break) +CPPKEYWORD(case) +CPPKEYWORD(catch) +CPPKEYWORD(char) +CPPKEYWORD(char8_t) +CPPKEYWORD(char16_t) +CPPKEYWORD(char32_t) +CPPKEYWORD(class) +CPPKEYWORD(compl) +CPPKEYWORD(concept) +CPPKEYWORD(const) +CPPKEYWORD(consteval) +CPPKEYWORD(constexpr) +CPPKEYWORD(constinit) +CPPKEYWORD(const_cast) +CPPKEYWORD(continue) +CPPKEYWORD(co_await) +CPPKEYWORD(co_return) +CPPKEYWORD(co_yield) +CPPKEYWORD(decltype) +CPPKEYWORD(default) +CPPKEYWORD(delete) +CPPKEYWORD(do) +CPPKEYWORD(double) +CPPKEYWORD(dynamic_cast) +CPPKEYWORD(else) +CPPKEYWORD(enum) +CPPKEYWORD(explicit) +CPPKEYWORD(export) +CPPKEYWORD(extern) +CPPKEYWORD(false) +CPPKEYWORD(float) +CPPKEYWORD(for) +CPPKEYWORD(friend) +CPPKEYWORD(goto) +CPPKEYWORD(if) +CPPKEYWORD(inline) +CPPKEYWORD(int) +CPPKEYWORD(long) +CPPKEYWORD(mutable) +CPPKEYWORD(namespace) +CPPKEYWORD(new) +CPPKEYWORD(noexcept) +CPPKEYWORD(not) +CPPKEYWORD(not_eq) +CPPKEYWORD(nullptr) +CPPKEYWORD(operator) +CPPKEYWORD(or) +CPPKEYWORD(or_eq) +CPPKEYWORD(private) +CPPKEYWORD(protected) +CPPKEYWORD(public) +CPPKEYWORD(reflexpr) +CPPKEYWORD(register) +CPPKEYWORD(reinterpret_cast) +CPPKEYWORD(requires) +CPPKEYWORD(return) +CPPKEYWORD(short) +CPPKEYWORD(signed) +CPPKEYWORD(sizeof) +CPPKEYWORD(static) +CPPKEYWORD(static_assert) +CPPKEYWORD(static_cast) +CPPKEYWORD(struct) +CPPKEYWORD(switch) +CPPKEYWORD(synchronized) +CPPKEYWORD(template) +CPPKEYWORD(this) +CPPKEYWORD(thread_local) +CPPKEYWORD(throw) +CPPKEYWORD(true) +CPPKEYWORD(try) +CPPKEYWORD(typedef) +CPPKEYWORD(typeid) +CPPKEYWORD(typename) +CPPKEYWORD(union) +CPPKEYWORD(unsigned) +CPPKEYWORD(using) +CPPKEYWORD(virtual) +CPPKEYWORD(void) +CPPKEYWORD(volatile) +CPPKEYWORD(wchar_t) +CPPKEYWORD(while) +CPPKEYWORD(xor) +CPPKEYWORD(xor_eq) diff --git a/src/MapleFE/astopt/src/Makefile b/src/MapleFE/astopt/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..3d61edb58810ed11d2f63a25a32eba9c5b225f77 --- /dev/null +++ b/src/MapleFE/astopt/src/Makefile @@ -0,0 +1,61 @@ +# Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +include ../../Makefile.in +BUILD=$(BUILDDIR)/astopt +$(shell $(MKDIR_P) $(BUILD)) + +SRC=$(wildcard *.cpp) +OBJ :=$(patsubst %.cpp,%.o,$(SRC)) +DEP :=$(patsubst %.cpp,%.d,$(SRC)) + +OBJS :=$(foreach obj,$(OBJ), $(BUILD)/$(obj)) +DEPS :=$(foreach dep,$(DEP), $(BUILD)/$(dep)) + +LIBOBJS :=$(patsubst $(BUILD)/main.o,,$(OBJS)) + + +INCLUDES := -I $(MAPLEFE_ROOT)/shared/include \ + -I $(MAPLEFE_ROOT)/astopt/include \ + -I $(MAPLEFE_ROOT)/$(SRCLANG)/include \ + -I ${BUILDDIR}/ast_gen/shared + +TARGET=astopt.a + +.PHONY: all +all: $(BUILD)/$(TARGET) + +-include $(DEPS) +.PHONY: clean + +vpath %.o $(BUILD) +vpath %.d $(BUILD) + +#Pattern Rules +$(BUILD)/%.o : %.cpp + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ + +$(BUILD)/%.d : %.cpp + @$(CXX) $(CXXFLAGS) -MM $(INCLUDES) $< > $@ + @mv -f $(BUILD)/$*.d $(BUILD)/$*.d.tmp + @sed -e 's|.*:|$(BUILD)/$*.o:|' < $(BUILD)/$*.d.tmp > $(BUILD)/$*.d + @rm -f $(BUILD)/$*.d.tmp + +# TARGET depends on OBJS and shared OBJS from shared directory +# as well as mapleall libraries +$(BUILD)/$(TARGET): $(OBJS) + /usr/bin/ar rcs $(BUILD)/$(TARGET) $(OBJS) + +clean: + rm -rf $(BUILD) diff --git a/src/MapleFE/astopt/src/ast_adj.cpp b/src/MapleFE/astopt/src/ast_adj.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64b8e82bf1f0de9ea9ecc9c1e7f3ef79609bd954 --- /dev/null +++ b/src/MapleFE/astopt/src/ast_adj.cpp @@ -0,0 +1,607 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include "ast_handler.h" +#include "typetable.h" +#include "ast_info.h" +#include "ast_adj.h" +#include "ast_util.h" + +namespace maplefe { + +void AST_ADJ::AdjustAST() { + MSGNOLOC0("============== AdjustAST =============="); + ModuleNode *module = mHandler->GetASTModule(); + for(unsigned i = 0; i < module->GetTreesNum(); i++) { + TreeNode *it = module->GetTree(i); + it->SetParent(module); + } + + // adjust ast + AdjustASTVisitor adjust_visitor(mHandler, mFlags, true); + adjust_visitor.Visit(module); +} + +// set parent for some identifier's type +IdentifierNode *AdjustASTVisitor::VisitIdentifierNode(IdentifierNode *node) { + (void) AstVisitor::VisitIdentifierNode(node); + CheckAndRenameCppKeywords(node); + + TreeNode *type = node->GetType(); + if (type && type->IsUserType()) { + type->SetParent(node); + } + return node; +} + +ClassNode *AdjustASTVisitor::VisitClassNode(ClassNode *node) { + (void) AstVisitor::VisitClassNode(node); + CheckAndRenameCppKeywords(node); + AssignPseudoName(node); + + // record names + gStringPool.AddAltStrIdx(node->GetStrIdx()); + for (unsigned i = 0; i < node->GetFieldsNum(); i++) { + TreeNode *n = node->GetField(i); + gStringPool.AddAltStrIdx(n->GetStrIdx()); + } + for (unsigned i = 0; i < node->GetMethodsNum(); i++) { + TreeNode *n = node->GetMethod(i); + gStringPool.AddAltStrIdx(n->GetStrIdx()); + } + + // skip getting canonical type if not only fields + if (node->GetMethodsNum() || node->GetSuperClassesNum() || node->GetSuperInterfacesNum() || + node->GetSuperClassesNum() || node->GetTypeParamsNum()) { + return node; + } + + TreeNode *parent = node->GetParent(); + TreeNode *newnode = mInfo->GetCanonicStructNode(node); + if (newnode == node) { + return node; + } + + // create a TypeAlias for duplicated type if top level + if (parent && parent->IsModule()) { + newnode = (ClassNode*)(mInfo->CreateTypeAliasNode(newnode, node)); + } + + return (ClassNode*)newnode; +} + +InterfaceNode *AdjustASTVisitor::VisitInterfaceNode(InterfaceNode *node) { + (void) AstVisitor::VisitInterfaceNode(node); + CheckAndRenameCppKeywords(node); + + // record names + gStringPool.AddAltStrIdx(node->GetStrIdx()); + for (unsigned i = 0; i < node->GetFieldsNum(); i++) { + TreeNode *n = node->GetField(i); + gStringPool.AddAltStrIdx(n->GetStrIdx()); + } + for (unsigned i = 0; i < node->GetMethodsNum(); i++) { + TreeNode *n = node->GetMethod(i); + gStringPool.AddAltStrIdx(n->GetStrIdx()); + } + + // skip getting canonical type if not only fields + if (node->GetMethodsNum() || node->GetSuperInterfacesNum()) { + return node; + } + + TreeNode *parent = node->GetParent(); + TreeNode *newnode = mInfo->GetCanonicStructNode(node); + if (newnode == node) { + return node; + } + + // create a TypeAlias for duplicated type if top level + if (parent && parent->IsModule()) { + newnode = (InterfaceNode*)(mInfo->CreateTypeAliasNode(newnode, node)); + } + return (InterfaceNode*)newnode; +} + +StructLiteralNode *AdjustASTVisitor::VisitStructLiteralNode(StructLiteralNode *node) { + (void) AstVisitor::VisitStructLiteralNode(node); + + unsigned size = node->GetFieldsNum(); + for (unsigned fid = 0; fid < size; fid++) { + FieldLiteralNode *field = node->GetField(fid); + TreeNode *name = field->GetFieldName(); + TreeNode *lit = field->GetLiteral(); + if (!name || !lit || !lit->IsLiteral()) { + return node; + } + } + + TreeNode *newnode = mInfo->GetCanonicStructNode(node); + gStringPool.AddAltStrIdx(newnode->GetStrIdx()); + if (newnode != node) { + node->SetTypeIdx(newnode->GetTypeIdx()); + } + + return node; +} + +StructNode *AdjustASTVisitor::VisitStructNode(StructNode *node) { + (void) AstVisitor::VisitStructNode(node); + CheckAndRenameCppKeywords(node); + + // record names + gStringPool.AddAltStrIdx(node->GetStrIdx()); + for (unsigned i = 0; i < node->GetFieldsNum(); i++) { + TreeNode *n = node->GetField(i); + gStringPool.AddAltStrIdx(n->GetStrIdx()); + } + for (unsigned i = 0; i < node->GetMethodsNum(); i++) { + TreeNode *n = node->GetMethod(i); + gStringPool.AddAltStrIdx(n->GetStrIdx()); + } + + // skip getting canonical type for TypeAlias + TreeNode *parent_orig = node->GetParent(); + TreeNode *p = parent_orig; + while (p) { + if (p->IsTypeAlias()) { + return node; + } + p = p->GetParent(); + } + + // skip getting canonical type if not only fields + if (node->GetMethodsNum() || node->GetSupersNum() || node->GetTypeParamsNum()) { + return node; + } + + TreeNode *newnode = mInfo->GetCanonicStructNode(node); + + // if returned itself that means it should be added to the moudule if not yet + if (newnode == node) { + ModuleNode *module = mHandler->GetASTModule(); + bool found = false; + for (unsigned i = 0; i < module->GetTreesNum(); ++i) { + if (newnode == module->GetTree(i)) { + found = true; + break; + } + } + if (!found) { + module->AddTreeFront(newnode); + } + } + + // create a TypeAlias for duplicated type if top level + // except newly added anonymous type which has updated parent + TreeNode *parent = node->GetParent(); + if (newnode != node && parent_orig && parent && parent == parent_orig && parent->IsModule()) { + newnode = mInfo->CreateTypeAliasNode(newnode, node); + } + + // for non top level tree node, replace it with a UserType node + if (!parent_orig || !parent_orig->IsModule()) { + if (newnode->GetStrIdx()) { + // for anonymous class, check it is given a name + // not skipped due to type parameters + newnode = mInfo->CreateUserTypeNode(newnode->GetStrIdx()); + } + } + + return (StructNode*)newnode; +} + +// convert prim array node to array type node +PrimArrayTypeNode *AdjustASTVisitor::VisitPrimArrayTypeNode(PrimArrayTypeNode *node) { + (void) AstVisitor::VisitPrimArrayTypeNode(node); + ArrayTypeNode *arr = mHandler->NewTreeNode(); + DimensionNode *dim = node->GetDims(); + arr->SetDims(dim); + arr->SetElemType(node->GetPrim()); + + return (PrimArrayTypeNode *)arr; +} + +// set UserTypeNode's mStrIdx to be its mId's +UserTypeNode *AdjustASTVisitor::VisitUserTypeNode(UserTypeNode *node) { + (void) AstVisitor::VisitUserTypeNode(node); + TreeNode *id = node->GetId(); + if (id) { + node->SetStrIdx(id->GetStrIdx()); + } + + // use array type node + DimensionNode *dim = node->GetDims(); + bool isarr = (dim != NULL); + // element type + TreeNode *etype = NULL; + + if (isarr) { + etype = node; + } else if (id && id->IsIdentifier()) { + IdentifierNode *idnode = static_cast(id); + isarr = (idnode->GetStrIdx() == gStringPool.GetStrIdx("Array")); + if (isarr) { + if (unsigned s = node->GetTypeGenericsNum()) { + if (s == 1) { + etype = node->GetTypeGeneric(0); + } else { + NOTYETIMPL("array usertype with multiple generic type"); + } + } + } + } + + if (isarr) { + ArrayTypeNode *arr = mHandler->NewTreeNode(); + arr->SetDims(dim); + arr->SetElemType(etype); + node->SetDims(NULL); + node = (UserTypeNode *)arr; + } + + return node; +} + +// set TypeAliasNode's mStrIdx to be its mId's +TypeAliasNode *AdjustASTVisitor::VisitTypeAliasNode(TypeAliasNode *node) { + (void) AstVisitor::VisitTypeAliasNode(node); + UserTypeNode *id = node->GetId(); + if (id && id->GetId()) { + node->SetStrIdx(id->GetId()->GetStrIdx()); + } + return node; +} + +LiteralNode *AdjustASTVisitor::VisitLiteralNode(LiteralNode *node) { + (void) AstVisitor::VisitLiteralNode(node); + if (node->IsThis()) { + unsigned stridx = gStringPool.GetStrIdx("this"); + IdentifierNode *id = mInfo->CreateIdentifierNode(stridx); + TreeNode *type = node->GetType(); + if (type) { + id->SetType(type); + id->SetTypeId(type->GetTypeId()); + id->SetTypeIdx(type->GetTypeIdx()); + } + node = (LiteralNode *)id; + } + return node; +} + +UnaOperatorNode *AdjustASTVisitor::VisitUnaOperatorNode(UnaOperatorNode *node) { + (void) AstVisitor::VisitUnaOperatorNode(node); + TreeNode *opnd = node->GetOpnd(); + OprId op = node->GetOprId(); + if (op == OPR_Plus || op == OPR_Minus) { + if (opnd->IsLiteral()) { + LiteralNode *lit = static_cast(opnd); + if (lit->GetData().mType == LT_StringLiteral) { + unsigned stridx = lit->GetData().mData.mStrIdx; + std::string str = gStringPool.GetStringFromStrIdx(stridx); + double d = std::stod(str); + if (op == OPR_Minus) { + d = -d; + } + long l = (long)d; + LitData data; + if (d == l) { + data.mType = LT_IntegerLiteral; + data.mData.mInt = l; + } else { + data.mType = LT_DoubleLiteral; + data.mData.mDouble = d; + } + LiteralNode *n = mHandler->NewTreeNode(); + n->SetData(data); + n->SetParent(node->GetParent()); + return (UnaOperatorNode*)n; + } + } + } + return node; +} + +FunctionNode *AdjustASTVisitor::VisitFunctionNode(FunctionNode *node) { + (void) AstVisitor::VisitFunctionNode(node); + CheckAndRenameCppKeywords(node); + + gStringPool.AddAltStrIdx(node->GetStrIdx()); + + for(unsigned i = 0; i < node->GetParamsNum(); i++) { + TreeNode *it = node->GetParam(i); + gStringPool.AddAltStrIdx(it->GetStrIdx()); + } + + TreeNode *type = node->GetRetType(); + if (type && type->IsUserType()) { + type->SetParent(node); + } + + // Refine function TypeParames + for(unsigned i = 0; i < node->GetTypeParamsNum(); i++) { + type = node->GetTypeParamAtIndex(i); + if (type->IsIdentifier()) { + IdentifierNode *inode = static_cast(type); + TreeNode *newtype = mInfo->CreateUserTypeNode(inode); + node->SetTypeParamAtIndex(i, newtype); + newtype->SetParent(node); + } + } + return node; +} + +// move init from identifier to decl +// copy stridx to decl +DeclNode *AdjustASTVisitor::VisitDeclNode(DeclNode *node) { + TreeNode *var = node->GetVar(); + if (var->IsIdentifier()) { + IdentifierNode *inode = static_cast(var); + (void) AstVisitor::VisitIdentifierNode(inode); + + // copy stridx from Identifier to Decl + unsigned stridx = inode->GetStrIdx(); + if (stridx) { + node->SetStrIdx(stridx); + gStringPool.AddAltStrIdx(stridx); + mUpdated = true; + } + + // move init from Identifier to Decl + TreeNode *init = inode->GetInit(); + if (init) { + node->SetInit(init); + inode->ClearInit(); + mUpdated = true; + } + } else if (var->IsBindingPattern()) { + BindingPatternNode *bind = static_cast(var); + VisitBindingPatternNode(bind); + } else { + NOTYETIMPL("decl not idenfier or bind pattern"); + } + + // reorg before processing init + (void) AstVisitor::VisitDeclNode(node); + return node; +} + +ImportNode *AdjustASTVisitor::VisitImportNode(ImportNode *node) { + (void) AstVisitor::VisitImportNode(node); + + return node; +} + +// if-then-else : use BlockNode for then and else bodies +// split export decl and body +// export {func add(y)} ==> export {add}; func add(y) +ExportNode *AdjustASTVisitor::VisitExportNode(ExportNode *node) { + (void) AstVisitor::VisitExportNode(node); + TreeNode *parent = node->GetParent(); + if (!parent || parent->IsNamespace()) { + // Export declarations are not permitted in a namespace + return node; + } + if (node->GetPairsNum() == 1) { + XXportAsPairNode *p = node->GetPair(0); + TreeNode *bfnode = p->GetBefore(); + if (bfnode) { + if (!bfnode->IsIdentifier()) { + switch (bfnode->GetKind()) { + case NK_Function: { + FunctionNode *func = static_cast(bfnode); + IdentifierNode *n = mInfo->CreateIdentifierNode(func->GetStrIdx()); + // update p + p->SetBefore(n); + n->SetParent(p); + mUpdated = true; + // insert func into AST after node + if (parent->IsBlock()) { + static_cast(parent)->InsertStmtAfter(func, node); + } else if (parent->IsModule()) { + static_cast(parent)->InsertAfter(func, node); + } + // cp annotation from node to func + for (unsigned i = 0; i < node->GetAnnotationsNum(); i++) { + func->AddAnnotation(node->GetAnnotationAtIndex(i)); + } + node->ClearAnnotation(); + break; + } + case NK_Class: { + ClassNode *classnode = static_cast(bfnode); + IdentifierNode *n = mInfo->CreateIdentifierNode(classnode->GetStrIdx()); + // update p + p->SetBefore(n); + n->SetParent(p); + mUpdated = true; + // insert classnode into AST after node + if (parent->IsBlock()) { + static_cast(parent)->InsertStmtAfter(classnode, node); + } else if (parent->IsModule()) { + static_cast(parent)->InsertAfter(classnode, node); + } + // cp annotation from node to classnode + for (unsigned i = 0; i < node->GetAnnotationsNum(); i++) { + classnode->AddAnnotation(node->GetAnnotationAtIndex(i)); + } + node->ClearAnnotation(); + break; + } + default: + NOTYETIMPL("VisitExportNode neither function nor class"); + break; + } + } + } + } + return node; +} + +NamespaceNode *AdjustASTVisitor::VisitNamespaceNode(NamespaceNode *node) { + (void) AstVisitor::VisitNamespaceNode(node); + TreeNode *id = node->GetId(); + if (id) { + // for namespace with nested id, split into namespaces + if (id->IsField()) { + FieldNode *fld = static_cast(id); + TreeNode *upper = fld->GetUpper(); + TreeNode *field = fld->GetField(); + // rename node with upper + node->SetId(upper); + + NamespaceNode *ns = mHandler->NewTreeNode(); + // name ns with field + ns->SetId(field); + // move elements of node to ns + for (unsigned i = 0; i < node->GetElementsNum(); i++) { + ns->AddElement(node->GetElementAtIndex(i)); + } + node->Release(); + // add ns as element of node + node->AddElement(ns); + + // recursive if needed + if (!upper->IsIdentifier()) { + node = VisitNamespaceNode(static_cast(node)); + } + } + } + return node; +} + +CondBranchNode *AdjustASTVisitor::VisitCondBranchNode(CondBranchNode *node) { + TreeNode *tn = VisitTreeNode(node->GetCond()); + tn = VisitTreeNode(node->GetTrueBranch()); + if (tn && !tn->IsBlock()) { + BlockNode *blk = mHandler->NewTreeNode(); + blk->AddChild(tn); + node->SetTrueBranch(blk); + mUpdated = true; + } + tn = VisitTreeNode(node->GetFalseBranch()); + if (tn && !tn->IsBlock()) { + BlockNode *blk = mHandler->NewTreeNode(); + blk->AddChild(tn); + node->SetFalseBranch(blk); + mUpdated = true; + } + return node; +} + +// for : use BlockNode for body +ForLoopNode *AdjustASTVisitor::VisitForLoopNode(ForLoopNode *node) { + (void) AstVisitor::VisitForLoopNode(node); + TreeNode *tn = node->GetBody(); + if (tn && !tn->IsBlock()) { + BlockNode *blk = mHandler->NewTreeNode(); + blk->AddChild(tn); + node->SetBody(blk); + mUpdated = true; + } + return node; +} + +static unsigned uniq_number = 1; + +// lamda : create a FunctionNode for it +// use BlockNode for body, add a ReturnNode +LambdaNode *AdjustASTVisitor::VisitLambdaNode(LambdaNode *node) { + FunctionNode *func = mHandler->NewTreeNode(); + + // func name + std::string str("__lambda_"); + str += std::to_string(uniq_number++); + str += "__"; + unsigned stridx = gStringPool.GetStrIdx(str); + IdentifierNode *name = mInfo->CreateIdentifierNode(stridx); + func->SetStrIdx(stridx); + func->SetFuncName(name); + mInfo->AddFromLambda(func->GetNodeId()); + + // func parameters + for (int i = 0; i < node->GetParamsNum(); i++) { + func->AddParam(node->GetParam(i)); + } + + // func Attributes + for (int i = 0; i < node->GetAttrsNum(); i++) { + func->AddAttr(node->GetAttrAtIndex(i)); + } + + // func type parameters + for (int i = 0; i < node->GetTypeParamsNum(); i++) { + func->AddTypeParam(node->GetTypeParamAtIndex(i)); + } + + // func body + TreeNode *tn = VisitTreeNode(node->GetBody()); + if (tn) { + if (tn->IsBlock()) { + func->SetBody(static_cast(tn)); + func->SetRetType(node->GetRetType()); + } else { + BlockNode *blk = mHandler->NewTreeNode(); + ReturnNode *ret = mHandler->NewTreeNode(); + ret->SetResult(tn); + blk->AddChild(ret); + + func->SetBody(blk); + } + } + + // func return type + if (node->GetRetType()) { + func->SetRetType(node->GetRetType()); + } + + mUpdated = true; + // note: the following conversion is only for the visitor to notice the node is updated + return (LambdaNode*)func; +} + +void AdjustASTVisitor::CheckAndRenameCppKeywords(TreeNode *node) { + if (!mHandler->IsTS() || node->GetStrIdx() == 0) { + return; + } + + unsigned stridx = node->GetStrIdx(); + if (mRenameMap.find(stridx) != mRenameMap.end()) { + node->SetStrIdx(mRenameMap[stridx]); + return; + } + + if (mUtil->IsCppKeyWord(stridx)) { + std::string name = gStringPool.GetStringFromStrIdx(stridx); + unsigned newidx = gStringPool.GetStrIdx(name + RENAMINGSUFFIX); + node->SetStrIdx(newidx); + mRenameMap[stridx] = newidx; + } +} + +void AdjustASTVisitor::AssignPseudoName(TreeNode *node) { + if (!mHandler->IsTS() || node->GetStrIdx() != 0) { + return; + } + static int pseudo = 0; + // Set a pseudo name + unsigned newidx = gStringPool.GetStrIdx("__Pseudo_" + std::to_string(++pseudo)); + node->SetStrIdx(newidx); +} + +} diff --git a/src/MapleFE/astopt/src/ast_cfa.cpp b/src/MapleFE/astopt/src/ast_cfa.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57dda93f78017323662bb905e3dbf68c1410094d --- /dev/null +++ b/src/MapleFE/astopt/src/ast_cfa.cpp @@ -0,0 +1,107 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include "ast_handler.h" +#include "ast_cfa.h" + +namespace maplefe { + +void AST_CFA::ControlFlowAnalysis() { + MSGNOLOC0("============== ControlFlowAnalysis =============="); + CollectReachableBB(); + RemoveUnreachableBB(); + + if (mFlags & FLG_trace_3) { + Dump(); + } +} + +void AST_CFA::Dump() { + ModuleNode *module = mHandler->GetASTModule(); + for(unsigned i = 0; i < module->GetTreesNum(); i++) { + TreeNode *it = module->GetTree(i); + it->Dump(0); + std::cout << std::endl; + } +} + +// this calcuates mNodeId2BbMap +void AST_CFA::CollectReachableBB() { + MSGNOLOC0("============== CollectReachableBB =============="); + mReachableBbIdx.clear(); + std::deque working_list; + + // process each functions + for (auto func: mHandler->mModuleFuncs) { + // initialisze work list with all entry BB + working_list.push_back(func->GetEntryBB()); + + while(working_list.size()) { + CfgBB *bb = working_list.front(); + MASSERT(bb && "null BB"); + unsigned bbid = bb->GetId(); + + // skip bb already visited + if (mReachableBbIdx.find(bbid) != mReachableBbIdx.end()) { + working_list.pop_front(); + continue; + } + + for (int i = 0; i < bb->GetSuccessorsNum(); i++) { + working_list.push_back(bb->GetSuccessorAtIndex(i)); + } + + for (int i = 0; i < bb->GetStatementsNum(); i++) { + TreeNode *node = bb->GetStatementAtIndex(i); + mHandler->SetBbFromNodeId(node->GetNodeId(), bb); + } + + mHandler->SetBbFromBbId(bbid, bb); + mHandler->mBbIdVec.push_back(bbid); + + mReachableBbIdx.insert(bbid); + working_list.pop_front(); + } + } +} + +void AST_CFA::RemoveUnreachableBB() { + std::set deadBb; + CfgBB *bb = nullptr; + for (auto id: mReachableBbIdx) { + bb = mHandler->mBbId2BbMap[id]; + for (int i = 0; i < bb->GetPredecessorsNum(); i++) { + CfgBB *pred = bb->GetPredecessorAtIndex(i); + unsigned pid = pred->GetId(); + if (mHandler->mBbId2BbMap.find(pid) == mHandler->mBbId2BbMap.end()) { + deadBb.insert(pred); + } + } + } + for (auto it: deadBb) { + if (mFlags & FLG_trace_3) std::cout << "deleted BB :"; + for (int i = 0; i < it->GetSuccessorsNum(); i++) { + bb = it->GetSuccessorAtIndex(i); + bb->mPredecessors.Remove(it); + } + if (mFlags & FLG_trace_3) std::cout << " BB" << it->GetId(); + it->~CfgBB(); + } + if (mFlags & FLG_trace_3) std::cout << std::endl; +} + +} diff --git a/src/MapleFE/astopt/src/ast_cfg.cpp b/src/MapleFE/astopt/src/ast_cfg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..63bda48be94433bf8c45d6ca52e3f6235734da2f --- /dev/null +++ b/src/MapleFE/astopt/src/ast_cfg.cpp @@ -0,0 +1,882 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include +#include "ast_cfg.h" +#include "ast_dfa.h" +#include "ast_handler.h" +#include "gen_astdump.h" + +namespace maplefe { + +class CollectNestedFuncs : public AstVisitor { + private: + CfgBuilder *mBuilder; + CfgFunc *mFunc; + + public: + CollectNestedFuncs(CfgBuilder *b, CfgFunc *f) : mBuilder(b), mFunc(f) {} + + FunctionNode *VisitFunctionNode(FunctionNode *node) { + if(TreeNode *body = node->GetBody()) + HandleNestedFunc(node, body); + return node; + } + + LambdaNode *VisitLambdaNode(LambdaNode *node) { + if(TreeNode *body = node->GetBody()) + HandleNestedFunc(node, body); + return node; + } + + void HandleNestedFunc(TreeNode *func, TreeNode *body) { + CfgFunc *current = mFunc; + mFunc = mBuilder->NewFunction(func); + current->AddNestedFunc(mFunc); + AstVisitor::VisitTreeNode(body); + mFunc = current; + } +}; + +// Create CfgFunc nodes for a module +CfgFunc *CfgBuilder::InitCfgFunc(ModuleNode *module) { + CfgFunc *module_func = NewFunction(module); + CollectNestedFuncs collector(this, module_func); + collector.Visit(module); + return module_func; +} + +// Initialize a CfgFunc node +void CfgBuilder::InitializeFunction(CfgFunc *func) { + // Create the entry BB and exit BB of current function + CfgBB *entry = NewBB(BK_Uncond); + func->SetEntryBB(entry); + CfgBB *exit = NewBB(BK_Join); + func->SetExitBB(exit); + CfgBuilder::Push(mThrowBBs, exit, nullptr); + // Initialize the working function and BB + mCurrentFunction = func; + mCurrentBB = NewBB(BK_Uncond); + entry->AddSuccessor(mCurrentBB); +} + +// Finalize a CfgFunc node +void CfgBuilder::FinalizeFunction() { + CfgBuilder::Pop(mThrowBBs); + CfgBB *exit = mCurrentFunction->GetExitBB(); + mCurrentBB->AddSuccessor(exit); + mCurrentFunction->SetLastBBId(CfgBB::GetLastId()); + mCurrentFunction = nullptr; + mCurrentBB = nullptr; +} + +// Push a BB to target BB stack +void CfgBuilder::Push(TargetBBStack &stack, CfgBB* bb, TreeNode *label) { + unsigned idx = 0; + if(label && label->IsIdentifier()) + idx = static_cast(label)->GetStrIdx(); + stack.push_back(TargetBB{bb, idx}); +} + +// Look up a target BB +CfgBB *CfgBuilder::LookUp(TargetBBStack &stack, TreeNode *label) { + unsigned idx = 0; + if(label && label->IsIdentifier()) + idx = static_cast(label)->GetStrIdx(); + if(idx == 0) { + for(auto it = stack.rbegin(); it != stack.rend(); ++it) + if(it->first->GetKind() != BK_Join2) + return it->first; + } else { + for(auto it = stack.rbegin(); it != stack.rend(); ++it) + if(it->second == idx) + return it->first; + } + MASSERT(0 && "Unexpected: Target not found."); + return nullptr; +} + +// Pop from a target BB stack +void CfgBuilder::Pop(TargetBBStack &stack) { + stack.pop_back(); +} + +// Handle a function +FunctionNode *CfgBuilder::VisitFunctionNode(FunctionNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// Handle a lambda +LambdaNode *CfgBuilder::VisitLambdaNode(LambdaNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +ClassNode *CfgBuilder::VisitClassNode(ClassNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +InterfaceNode *CfgBuilder::VisitInterfaceNode(InterfaceNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +StructNode *CfgBuilder::VisitStructNode(StructNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For control flow +ReturnNode *CfgBuilder::VisitReturnNode(ReturnNode *node) { + mCurrentBB->AddStatement(node); + CfgBB *exit = mCurrentFunction->GetExitBB(); + mCurrentBB->AddSuccessor(exit); + mCurrentBB->SetKind(BK_Terminated); + mCurrentBB->SetAttr(AK_Return); + return node; +} + +// For control flow +CondBranchNode *CfgBuilder::VisitCondBranchNode(CondBranchNode *node) { + mCurrentBB->SetKind(BK_Branch); + //mCurrentBB->AddStatement(node); + mCurrentBB->SetAuxNode(node); + + if(TreeNode *cond = node->GetCond()) { + // Set predicate of current BB + mCurrentBB->SetPredicate(cond); + mCurrentBB->AddStatement(cond); + } + + // Save current BB + CfgBB *current_bb = mCurrentBB; + + // Create a new BB for true branch + mCurrentBB = NewBB(BK_Uncond); + current_bb->AddSuccessor(mCurrentBB); + + // Create a BB for the join point + CfgBB *join = NewBB(BK_Join2); + + // Handle the label of current if-statement + TreeNode *label = node->GetLabel(); + if(label) + CfgBuilder::Push(mBreakBBs, join, label); + + // Visit true branch first + VisitTreeNode(node->GetTrueBranch()); + mCurrentBB->AddSuccessor(join); + + TreeNode *false_branch = node->GetFalseBranch(); + if(false_branch == nullptr) { + current_bb->AddSuccessor(join); + } else { + mCurrentBB = NewBB(BK_Uncond); + current_bb->AddSuccessor(mCurrentBB); + // Visit false branch if it exists + VisitTreeNode(false_branch); + mCurrentBB->AddSuccessor(join); + } + + if(label) + CfgBuilder::Pop(mBreakBBs); + + // Keep going with the BB at the join point + mCurrentBB = join; + return node; +} + +// For control flow +// ForLoopProp: FLP_Regular, FLP_JSIn, FLP_JSOf +ForLoopNode *CfgBuilder::VisitForLoopNode(ForLoopNode *node) { + // Visit all inits + for (unsigned i = 0; i < node->GetInitsNum(); ++i) { + VisitTreeNode(node->GetInitAtIndex(i)); + } + + CfgBB *current_bb = mCurrentBB; + // Create a new BB for loop header + mCurrentBB = NewBB(BK_LoopHeader); + + // Add current node to the loop header BB + //mCurrentBB->AddStatement(node); + mCurrentBB->SetAuxNode(node); + current_bb->AddSuccessor(mCurrentBB); + // Set current_bb to be loop header + current_bb = mCurrentBB; + + if(node->GetProp() == FLP_Regular) { + if(TreeNode *cond = node->GetCond()) { + // Set predicate of current BB + mCurrentBB->SetPredicate(cond); + mCurrentBB->AddStatement(cond); + } + } else + // Set predicate to be current ForLoopNode when it is FLP_JSIn or FLP_JSOf + mCurrentBB->SetPredicate(node); + + // Create a BB for loop body + mCurrentBB = NewBB(BK_Uncond); + current_bb->AddSuccessor(mCurrentBB); + // Create a new BB for getting out of the loop + CfgBB *loop_exit = NewBB(BK_Join); + + // Push loop_exit and current_bb to stacks for 'break' and 'continue' + CfgBuilder::Push(mBreakBBs, loop_exit, node->GetLabel()); + CfgBuilder::Push(mContinueBBs, current_bb, node->GetLabel()); + // Visit loop body + VisitTreeNode(node->GetBody()); + CfgBuilder::Pop(mContinueBBs); + CfgBuilder::Pop(mBreakBBs); + + // Visit all updates + for (unsigned i = 0; i < node->GetUpdatesNum(); ++i) { + VisitTreeNode(node->GetUpdateAtIndex(i)); + } + // Add a back edge to loop header + mCurrentBB->AddSuccessor(current_bb); + current_bb->AddSuccessor(loop_exit); + mCurrentBB = loop_exit; + return node; +} + +// For control flow +WhileLoopNode *CfgBuilder::VisitWhileLoopNode(WhileLoopNode *node) { + CfgBB *current_bb = mCurrentBB; + // Create a new BB for loop header + mCurrentBB = NewBB(BK_LoopHeader); + // Add current node to the loop header BB + //mCurrentBB->AddStatement(node); + mCurrentBB->SetAuxNode(node); + current_bb->AddSuccessor(mCurrentBB); + // Set current_bb to be loop header + current_bb = mCurrentBB; + + if(TreeNode *cond = node->GetCond()) { + // Set predicate of current BB + mCurrentBB->SetPredicate(cond); + mCurrentBB->AddStatement(cond); + } + + // Create a BB for loop body + mCurrentBB = NewBB(BK_Uncond); + current_bb->AddSuccessor(mCurrentBB); + // Create a new BB for getting out of the loop + CfgBB *loop_exit = NewBB(BK_Join); + + // Push loop_exit and current_bb to stacks for 'break' and 'continue' + CfgBuilder::Push(mBreakBBs, loop_exit, node->GetLabel()); + CfgBuilder::Push(mContinueBBs, current_bb, node->GetLabel()); + // Visit loop body + VisitTreeNode(node->GetBody()); + CfgBuilder::Pop(mContinueBBs); + CfgBuilder::Pop(mBreakBBs); + + // Add a back edge to loop header + mCurrentBB->AddSuccessor(current_bb); + current_bb->AddSuccessor(loop_exit); + mCurrentBB = loop_exit; + return node; +} + +// For control flow +DoLoopNode *CfgBuilder::VisitDoLoopNode(DoLoopNode *node) { + CfgBB *current_bb = mCurrentBB; + // Create a new BB for loop header + mCurrentBB = NewBB(BK_LoopHeader); + // Add current node to the loop header BB + //mCurrentBB->AddStatement(node); + mCurrentBB->SetAuxNode(node); + current_bb->AddSuccessor(mCurrentBB); + // Set current_bb to be loop header + current_bb = mCurrentBB; + + // Create a BB for loop body + mCurrentBB = NewBB(BK_Uncond); + current_bb->AddSuccessor(mCurrentBB); + // Create a new BB for getting out of the loop + CfgBB *loop_exit = NewBB(BK_Join); + + // Push loop_exit and current_bb to stacks for 'break' and 'continue' + CfgBuilder::Push(mBreakBBs, loop_exit, node->GetLabel()); + CfgBuilder::Push(mContinueBBs, current_bb, node->GetLabel()); + // Visit loop body + VisitTreeNode(node->GetBody()); + CfgBuilder::Pop(mContinueBBs); + CfgBuilder::Pop(mBreakBBs); + + if(TreeNode *cond = node->GetCond()) { + // Set predicate of current BB + mCurrentBB->SetPredicate(cond); + mCurrentBB->AddStatement(cond); + } + + // Add a back edge to loop header + mCurrentBB->AddSuccessor(current_bb); + mCurrentBB->AddSuccessor(loop_exit); + mCurrentBB = loop_exit; + return node; +} + +// For control flow +ContinueNode *CfgBuilder::VisitContinueNode(ContinueNode *node) { + mCurrentBB->AddStatement(node); + // Get the loop header + CfgBB *loop_header = CfgBuilder::LookUp(mContinueBBs, node->GetTarget()); + // Add the loop header as a successor of current BB + mCurrentBB->AddSuccessor(loop_header); + mCurrentBB->SetKind(BK_Terminated); + mCurrentBB->SetAttr(AK_Cont); + return node; +} + +// For control flow +BreakNode *CfgBuilder::VisitBreakNode(BreakNode *node) { + mCurrentBB->AddStatement(node); + // Get the target BB for a loop or switch statement + CfgBB *exit = CfgBuilder::LookUp(mBreakBBs, node->GetTarget()); + // Add the target as a successor of current BB + mCurrentBB->AddSuccessor(exit); + mCurrentBB->SetKind(BK_Terminated); + mCurrentBB->SetAttr(AK_Break); + return node; +} + +// For control flow +SwitchNode *CfgBuilder::VisitSwitchNode(SwitchNode *node) { + mCurrentBB->SetKind(BK_Switch); + mCurrentBB->AddStatement(node); + // Set the root node of current BB + mCurrentBB->SetAuxNode(node); + + // Save current BB + CfgBB *current_bb = mCurrentBB; + + // Create a new BB for getting out of the switch block + CfgBB *exit = NewBB(BK_Join); + CfgBuilder::Push(mBreakBBs, exit, node->GetLabel()); + CfgBB *prev_block = nullptr; + TreeNode *switch_expr = node->GetExpr(); + for (unsigned i = 0; i < node->GetCasesNum(); ++i) { + CfgBB *case_bb = NewBB(BK_Case); + current_bb->AddSuccessor(case_bb); + + TreeNode *case_node = node->GetCaseAtIndex(i); + // Set the auxiliary node and predicate for current case BB + case_bb->SetAuxNode(case_node); + case_bb->SetPredicate(switch_expr); + case_bb->AddStatement(switch_expr); + + bool is_default = false; + TreeNode *case_expr = nullptr; + if(case_node->IsSwitchCase()) { + // Use the first label node of current SwitchCaseNode + TreeNode *label_node = static_cast(case_node)->GetLabelAtIndex(0); + if(label_node->IsSwitchLabel()) { + is_default = static_cast(label_node)->IsDefault(); + case_expr = static_cast(label_node)->GetValue(); + } + } + + // Optimize for default case + if(is_default) { + mCurrentBB = case_bb; + case_bb->SetKind(BK_Uncond); + } else { + mCurrentBB = NewBB(BK_Uncond); + case_bb->AddSuccessor(mCurrentBB); + } + + // Add a fall-through edge if needed + if(prev_block) { + prev_block->AddSuccessor(mCurrentBB); + } + + // Visit all statements of current case + if(case_node->IsSwitchCase()) { + SwitchCaseNode *cnode = static_cast(case_node); + for (unsigned i = 0; i < cnode->GetStmtsNum(); ++i) { + if (auto t = cnode->GetStmtAtIndex(i)) + VisitTreeNode(t); + } + } + + // Prepare for next case + prev_block = mCurrentBB; + current_bb = case_bb; + } + CfgBuilder::Pop(mBreakBBs); + + // Connect to the exit BB of this switch statement + prev_block->AddSuccessor(exit); + if(prev_block != current_bb) { + current_bb->AddSuccessor(exit); + } + mCurrentBB = exit; + return node; +} + +// For control flow +TryNode *CfgBuilder::VisitTryNode(TryNode *node) { + mCurrentBB->SetKind(BK_Try); + //mCurrentBB->AddStatement(node); + mCurrentBB->SetAuxNode(node); + + auto try_block_node = node->GetBlock(); + //mCurrentBB->AddStatement(try_block_node); + + unsigned num = node->GetCatchesNum(); + CfgBB *catch_bb = num ? NewBB(BK_Catch) : nullptr; + + auto finally_node = node->GetFinally(); + // Create a BB for the join point + CfgBB *join = finally_node ? NewBB(BK_Finally) : NewBB(BK_Join); + + // Save current BB + CfgBB *current_bb = mCurrentBB; + // Create a new BB for current block node + mCurrentBB = NewBB(BK_Uncond); + current_bb->AddSuccessor(mCurrentBB); + + // Add an edge for exception + current_bb->AddSuccessor(num ? catch_bb : join); + + // Visit try block + if(num) { + CfgBuilder::Push(mThrowBBs, catch_bb, nullptr); + AstVisitor::VisitBlockNode(try_block_node); + CfgBuilder::Pop(mThrowBBs); + } else + AstVisitor::VisitBlockNode(try_block_node); + + // Add an edge to join point + mCurrentBB->AddSuccessor(join); + + // JavaScript can have one catch block, or one finally block without catch block + // Other languages, such as C++ and Java, may have multiple catch blocks + CfgBB *curr_bb = mCurrentBB; + for (unsigned i = 0; i < num; ++i) { + if(i > 0) + catch_bb = NewBB(BK_Catch); + // Add an edge to catch bb + curr_bb->AddSuccessor(catch_bb); + mCurrentBB = catch_bb; + auto catch_node = node->GetCatchAtIndex(i); + catch_bb->AddStatement(catch_node); + + auto catch_block = catch_node->GetBlock(); + catch_bb->AddStatement(catch_block); + AstVisitor::VisitBlockNode(catch_block); + + mCurrentBB->AddSuccessor(join); + curr_bb = catch_bb; + } + + mCurrentBB = join; + if(finally_node) { + // For finally block + //mCurrentBB->AddStatement(finally_node); + mCurrentBB->SetAuxNode(finally_node); + AstVisitor::VisitTreeNode(finally_node); + curr_bb = NewBB(BK_Join); + mCurrentBB->AddSuccessor(curr_bb); + // Add an edge to recent catch BB or exit BB + mCurrentBB->AddSuccessor(CfgBuilder::LookUp(mThrowBBs, nullptr)); + mCurrentBB = curr_bb; + } + return node; +} + +// For control flow +ThrowNode *CfgBuilder::VisitThrowNode(ThrowNode *node) { + mCurrentBB->AddStatement(node); + // Get the catch/exit bb for this throw statement + CfgBB *catch_bb = CfgBuilder::LookUp(mThrowBBs, nullptr); + // Add the loop header as a successor of current BB + mCurrentBB->AddSuccessor(catch_bb); + mCurrentBB->SetKind(BK_Terminated); + mCurrentBB->SetAttr(AK_Throw); + return node; +} + +// For control flow +BlockNode *CfgBuilder::VisitBlockNode(BlockNode *node) { + //mCurrentBB->AddStatement(node); + mCurrentBB->SetAuxNode(node); + // Check if current block constains any JS_Let or JS_Const DeclNode + unsigned i, num = node->GetChildrenNum(); + for (i = 0; i < num; ++i) { + TreeNode *child = node->GetChildAtIndex(i); + if(child == nullptr || !child->IsDecl()) { + continue; + } + DeclNode *decl = static_cast(child); + if(decl->GetProp() == JS_Let || decl->GetProp() == JS_Const) { + break; + } + } + + // Handle the label of current block statement + TreeNode *label = node->GetLabel(); + + if(i >= num && label == nullptr) { + // Do not create BB for current block when no JS_Let or JS_Const DeclNode inside + // Visit all child nodes + AstVisitor::VisitBlockNode(node); + } else { + mCurrentBB->SetKind(BK_Block); + // Set the auxiliary node of this BB + mCurrentBB->SetAuxNode(node); + + // Create a BB for the join point + CfgBB *join = NewBB(BK_Join2); + + if(label) + CfgBuilder::Push(mBreakBBs, join, label); + + // Needs BBs for current block + // Save current BB + CfgBB *current_bb = mCurrentBB; + // Create a new BB for current block node + mCurrentBB = NewBB(BK_Uncond); + current_bb->AddSuccessor(mCurrentBB); + + // Visit all child nodes + AstVisitor::VisitBlockNode(node); + + mCurrentBB->AddSuccessor(join); + // This edge is to determine the block range for JS_Let or JS_Const DeclNode + //current_bb->AddSuccessor(join); + + if(label) + CfgBuilder::Pop(mBreakBBs); + + mCurrentBB = join; + } + return node; +} + +// For control flow +NamespaceNode *CfgBuilder::VisitNamespaceNode(NamespaceNode *node) { + //mCurrentBB->AddStatement(node); + mCurrentBB->SetKind(BK_Block); + // Set the auxiliary node of this BB + mCurrentBB->SetAuxNode(node); + + // Create a BB for the join point + CfgBB *join = NewBB(BK_Join2); + + // Save current BB + CfgBB *current_bb = mCurrentBB; + // Create a new BB for current block node + mCurrentBB = NewBB(BK_Uncond); + current_bb->AddSuccessor(mCurrentBB); + + // Visit all child nodes + AstVisitor::VisitNamespaceNode(node); + + mCurrentBB->AddSuccessor(join); + // This edge is to determine the namespace range + //current_bb->AddSuccessor(join); + + mCurrentBB = join; + return node; +} + +// For PassNode +PassNode *CfgBuilder::VisitPassNode(PassNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +TemplateLiteralNode *CfgBuilder::VisitTemplateLiteralNode(TemplateLiteralNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +ImportNode *CfgBuilder::VisitImportNode(ImportNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +ExportNode *CfgBuilder::VisitExportNode(ExportNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +DeclNode *CfgBuilder::VisitDeclNode(DeclNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +ParenthesisNode *CfgBuilder::VisitParenthesisNode(ParenthesisNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +CastNode *CfgBuilder::VisitCastNode(CastNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +ArrayElementNode *CfgBuilder::VisitArrayElementNode(ArrayElementNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +VarListNode *CfgBuilder::VisitVarListNode(VarListNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +ExprListNode *CfgBuilder::VisitExprListNode(ExprListNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +UnaOperatorNode *CfgBuilder::VisitUnaOperatorNode(UnaOperatorNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +BinOperatorNode *CfgBuilder::VisitBinOperatorNode(BinOperatorNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +TerOperatorNode *CfgBuilder::VisitTerOperatorNode(TerOperatorNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +InstanceOfNode *CfgBuilder::VisitInstanceOfNode(InstanceOfNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +TypeOfNode *CfgBuilder::VisitTypeOfNode(TypeOfNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +NewNode *CfgBuilder::VisitNewNode(NewNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +DeleteNode *CfgBuilder::VisitDeleteNode(DeleteNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +CallNode *CfgBuilder::VisitCallNode(CallNode *node) { + mCurrentBB->AddStatement(node); + mCurrentBB->SetAttr(AK_HasCall); + return node; +} + +// For statement of current BB +AssertNode *CfgBuilder::VisitAssertNode(AssertNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +UserTypeNode *CfgBuilder::VisitUserTypeNode(UserTypeNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +IdentifierNode *CfgBuilder::VisitIdentifierNode(IdentifierNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +LiteralNode *CfgBuilder::VisitLiteralNode(LiteralNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +TypeAliasNode *CfgBuilder::VisitTypeAliasNode(TypeAliasNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +// For statement of current BB +FieldNode *CfgBuilder::VisitFieldNode(FieldNode *node) { + mCurrentBB->AddStatement(node); + return node; +} + +TreeNode *CfgBuilder::BaseTreeNode(TreeNode *node) { + return node; +} + +// Allocate a new CfgFunc node +CfgFunc *CfgBuilder::NewFunction(TreeNode *node) { + CfgFunc *func = new(mHandler->GetMemPool()->Alloc(sizeof(CfgFunc))) CfgFunc; + func->SetFuncNode(node); + return func; +} + +// Allocate a new CfgBB node +CfgBB *CfgBuilder::NewBB(BBKind k) { + return new(mHandler->GetMemPool()->Alloc(sizeof(CfgBB))) CfgBB(k); +} + +// Helper for a node in dot graph +static std::string BBLabelStr(CfgBB *bb, const char *shape = nullptr, const char *fn = nullptr) { + static const char* const kBBNames[] = + { "unknown", "uncond", "block", "branch", "loop", "switch", "case", "try", "catch", "finally", + "yield", "term", "join", "join2" }; + if(shape == nullptr) + return kBBNames[bb->GetKind()]; + std::string str("BB" + std::to_string(bb->GetId())); + str += " [label=\"" + str + (shape[0] == 'e' ? std::string("\\n") + kBBNames[bb->GetKind()] : "") + + (fn ? std::string("\\n\\\"") + fn + "\\\"" : "") + "\", shape=" + shape + "];\n"; + return str; +} + +// Dump current CfgFunc node +void CfgFunc::Dump() { + const char *func_name = GetName(); + std::cout << "Function " << func_name << " {" << std::endl; + unsigned num = GetNestedFuncsNum(); + if(num > 0) { + std::cout << "Nested Functions: " << num << " [" << std::endl; + for(unsigned i = 0; i < num; ++i) { + CfgFunc *afunc = GetNestedFuncAtIndex(i); + const char *fname = afunc->GetName(); + std::cout << "Function: " << i + 1 << " " << fname << std::endl; + afunc->Dump(); + } + std::cout << "] // Nested Functions" << std::endl; + } + std::cout << "BBs: [" << std::endl; + + std::stack bb_stack; + CfgBB *entry = GetEntryBB(), *exit = GetExitBB(); + bb_stack.push(exit); + bb_stack.push(entry); + std::set visited; + visited.insert(exit); + visited.insert(entry); + // Dump CFG in dot format + std::string dot("---\ndigraph CFG_"); + dot = dot + func_name + " {\n" + BBLabelStr(entry, "box", func_name) + BBLabelStr(exit, "doubleoctagon"); + const char* scoped = " [style=dashed color=grey];"; + while(!bb_stack.empty()) { + CfgBB *bb = bb_stack.top(); + bb_stack.pop(); + unsigned succ_num = bb->GetSuccessorsNum(); + std::cout << "BB" << bb->GetId() << ", " << BBLabelStr(bb) << (succ_num ? " ( succ: " : " ( Exit "); + for(unsigned i = 0; i < succ_num; ++i) { + CfgBB *curr = bb->GetSuccessorAtIndex(i); + std::cout << "BB" << curr->GetId() << " "; + dot += "BB" + std::to_string(bb->GetId()) + " -> BB" + std::to_string(curr->GetId()) + + (bb == entry ? (curr == exit ? scoped : ";") : + succ_num == 1 ? ";" : i ? bb->GetKind() == BK_Block ? scoped : + " [color=darkred];" : " [color=darkgreen];") + "\n"; + if(visited.find(curr) == visited.end()) { + bb_stack.push(curr); + visited.insert(curr); + dot += BBLabelStr(curr, "ellipse"); + } + } + std::cout << ")" << std::endl; + unsigned stmt_num = bb->GetStatementsNum(); + if(stmt_num) { + for(unsigned i = 0; i < stmt_num; ++i) { + TreeNode *stmt = bb->GetStatementAtIndex(i); + std::cout << " " << i + 1 << ". NodeId: " << stmt->GetNodeId() << ", " + << AstDump::GetEnumNodeKind(stmt->GetKind()) << " : "; + stmt->Dump(0); + std::cout << std::endl; + } + } + } + std::cout << dot << "} // CFG in dot format" << std::endl; + std::cout << "] // BBs\nLastBBId" << (num ? " (Including nested functions)" : "") << ": " + << GetLastBBId() << "\n} // Function" << std::endl; +} + +void CfgBuilder::Build() { + MSGNOLOC0("============== BuildCFG =============="); + + ModuleNode *module = mHandler->GetASTModule(); + + // Set the init function for current module + CfgFunc *func = InitCfgFunc(module); + mHandler->mModuleFuncs.push_back(func); + + mHandler->SetCfgFunc(func); + + std::queue funcQueue; + funcQueue.push(func); + while(!funcQueue.empty()) { + func = funcQueue.front(); + funcQueue.pop(); + // Start to build CFG for current function + InitializeFunction(func); + TreeNode *node = func->GetFuncNode(); + switch(node->GetKind()) { + case NK_Function: + Visit(static_cast(node)->GetBody());; + break; + case NK_Lambda: + { + auto n = static_cast(node)->GetBody(); + if(n->IsBlock()) + Visit(n); + } + break; + default: + Visit(node); + } + FinalizeFunction(); + for(unsigned i = 0; i < func->GetNestedFuncsNum(); ++i) { + CfgFunc *f = func->GetNestedFuncAtIndex(i); + funcQueue.push(f); + mHandler->mModuleFuncs.push_back(f); + } + } +} + +} diff --git a/src/MapleFE/astopt/src/ast_dfa.cpp b/src/MapleFE/astopt/src/ast_dfa.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3e6918b17001c4d523858a3a637f438307762009 --- /dev/null +++ b/src/MapleFE/astopt/src/ast_dfa.cpp @@ -0,0 +1,711 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include "stringpool.h" +#include "ast_cfg.h" +#include "ast_dfa.h" + +namespace maplefe { + +AST_DFA::~AST_DFA() { + mVar2DeclMap.clear(); + for (auto it: mStmtId2StmtMap) { + delete it.second; + } + mStmtId2StmtMap.clear(); + for (auto it: mPrsvMap) { + delete it.second; + } + mPrsvMap.clear(); + for (auto it: mGenMap) { + delete it.second; + } + mGenMap.clear(); + for (auto it: mRchInMap) { + delete it.second; + } + mRchInMap.clear(); + for (auto it: mRchOutMap) { + delete it.second; + } +} + +void AST_DFA::TestBV() { + unsigned size = 300; + BitVector *bv1 = new BitVector(size); + bv1->WipeOff(0xab); + + BitVector *bv2 = new BitVector(size); + bv2->WipeOff(0x12); + + DumpBV(bv1); + DumpBV(bv2); + + bv1->Or(bv2); + DumpBV(bv1); + + bv1->And(bv2); + DumpBV(bv1); + + free(bv1); + free(bv2); +} + +void AST_DFA::DataFlowAnalysis() { + Clear(); + // TestBV(); + CollectInfo(); + CollectDefNodes(); + BuildBitVectors(); + BuildDefUseChain(); + if (mFlags & FLG_trace_3) DumpDefUse(); +} + +void AST_DFA::Clear() { + mVar2DeclMap.clear(); + mStmtIdVec.Clear(); + mStmtId2StmtMap.clear(); + mDefNodeIdSet.clear(); + mDefPositionVec.Clear(); + mUsePositionMap.clear(); + for (auto it: mStmtId2StmtMap) { + delete it.second; + } + mStmtId2StmtMap.clear(); + for (auto it: mPrsvMap) { + delete it.second; + } + mPrsvMap.clear(); + for (auto it: mGenMap) { + delete it.second; + } + mGenMap.clear(); + for (auto it: mRchInMap) { + delete it.second; + } + mRchInMap.clear(); + for (auto it: mRchOutMap) { + delete it.second; + } + for (auto it: mPrsvMap) { + delete it.second; + } + mNodeId2StmtIdMap.clear(); + mStmtId2BbIdMap.clear(); + mDefStrIdxSet.clear(); + mDefUseMap.clear(); +} + +void AST_DFA::DumpDefPosition(unsigned idx, DefPosition pos) { + std::cout << " DefPos: " << idx; + unsigned stridx = pos.first; + std::cout << " stridx: " << stridx << " " << gStringPool.GetStringFromStrIdx(stridx) << "\t"; + unsigned nid = pos.second; + std::cout << "nodeid: " << nid << "\t"; + unsigned sid = GetStmtIdFromNodeId(nid); + std::cout << "stmtid: " << sid << "\t"; + unsigned bbid = GetBbIdFromStmtId(sid); + std::cout << " bbid: " << bbid << "\t"; + std::cout << std::endl; +} + +void AST_DFA::DumpDefPositionVec() { + MSGNOLOC0("============== DefPositionVec =============="); + for (unsigned i = 0; i < mDefPositionVec.GetNum(); i++) { + DefPosition pos = mDefPositionVec.ValueAtIndex(i); + DumpDefPosition(i, pos); + } +} + +#define DUMMY_BBID 0xffffffff + +unsigned AST_DFA::GetDefStrIdx(TreeNode *node) { + unsigned stridx = 0; + // pass DUMMY_BBID to indicate to get stridx only + AddDef(node, stridx, DUMMY_BBID); + return stridx; +} + +// return def-node id defined in node +// return 0 if node has no def +unsigned AST_DFA::AddDef(TreeNode *node, unsigned &bitnum, unsigned bbid) { + unsigned stridx = 0; + unsigned nodeid = 0; + bool isDefUse = false; + switch (node->GetKind()) { + case NK_Decl: { + DeclNode *decl = static_cast(node); + if (decl->GetInit()) { + stridx = decl->GetStrIdx(); + nodeid = decl->GetVar()->GetNodeId(); + } + break; + } + case NK_BinOperator: { + BinOperatorNode *bon = static_cast(node); + OprId op = bon->GetOprId(); + switch (op) { + case OPR_Assign: { + TreeNode *lhs = bon->GetOpndA(); + if (lhs->IsField()) { + lhs = static_cast(lhs)->GetUpper(); + } + stridx = lhs->GetStrIdx(); + nodeid = lhs->GetNodeId(); + break; + } + case OPR_AddAssign: + case OPR_SubAssign: + case OPR_MulAssign: + case OPR_DivAssign: + case OPR_ModAssign: + case OPR_ShlAssign: + case OPR_ShrAssign: + case OPR_BandAssign: + case OPR_BorAssign: + case OPR_BxorAssign: + case OPR_ZextAssign: { + TreeNode *lhs = bon->GetOpndA(); + if (lhs->IsField()) { + lhs = static_cast(lhs)->GetUpper(); + } + stridx = lhs->GetStrIdx(); + nodeid = lhs->GetNodeId(); + isDefUse = true; + break; + } + default: + break; + } + break; + } + case NK_UnaOperator: { + UnaOperatorNode *uon = static_cast(node); + OprId op = uon->GetOprId(); + if (op == OPR_Inc || op == OPR_Dec || op == OPR_PreInc || op == OPR_PreDec) { + TreeNode *lhs = uon->GetOpnd(); + stridx = lhs->GetStrIdx(); + nodeid = lhs->GetNodeId(); + isDefUse = true; + } + break; + } + default: + break; + } + + // update mDefPositionVec + if (stridx) { + if (bbid == DUMMY_BBID) { + // special usage for GetDefStrIdx(): use bitnum to return stridx + bitnum = stridx; + } else { + DefPosition pos(stridx, nodeid); + bitnum++; + mDefStrIdxSet.insert(stridx); + mDefNodeIdSet.insert(nodeid); + if (isDefUse) { + mDefUseNodeIdSet.insert(nodeid); + } + mDefPositionVec.PushBack(pos); + return nodeid; + } + } + + return nodeid; +} + +// this calcuates mDefPositionVec +void AST_DFA::CollectDefNodes() { + MSGNOLOC0("============== CollectDefNodes =============="); + std::unordered_set done_list; + std::deque working_list; + + unsigned bitnum = 0; + + // process each functions + for (auto func: mHandler->mModuleFuncs) { + // add arguments as def + TreeNode *f = static_cast(func)->GetFuncNode(); + if (f->IsFunction()) { + FunctionNode *fn = static_cast(f); + for (unsigned i = 0; i < fn->GetParamsNum(); i++) { + TreeNode *arg = fn->GetParam(i); + if (arg->IsIdentifier()) { + unsigned stridx = arg->GetStrIdx(); + unsigned nodeid = arg->GetNodeId(); + DefPosition pos(stridx, nodeid); + bitnum++; + mDefStrIdxSet.insert(stridx); + mDefNodeIdSet.insert(nodeid); + mDefPositionVec.PushBack(pos); + SetNodeId2StmtId(nodeid, fn->GetNodeId()); + } + } + } + + CfgBB *bb = func->GetEntryBB(); + MASSERT(bb && "null BB"); + unsigned bbid = bb->GetId(); + + working_list.push_back(bb); + + while(working_list.size()) { + bb = working_list.front(); + MASSERT(bb && "null BB"); + bbid = bb->GetId(); + + // process bb not visited + if (done_list.find(bbid) == done_list.end()) { + if (mFlags & FLG_trace_3) std::cout << "working_list work " << bbid << std::endl; + for (int i = 0; i < bb->GetStatementsNum(); i++) { + TreeNode *stmt = bb->GetStatementAtIndex(i); + (void) AddDef(stmt, bitnum, bbid); + } + + for (int i = 0; i < bb->GetSuccessorsNum(); i++) { + working_list.push_back(bb->GetSuccessorAtIndex(i)); + } + + done_list.insert(bbid); + } + + working_list.pop_front(); + } + } + + if (mFlags & FLG_trace_3) DumpDefPositionVec(); +} + +void AST_DFA::BuildBitVectors() { + MSGNOLOC0("============== BuildBitVectors =============="); + std::unordered_set done_list; + std::deque working_list; + + // init bit vectors + unsigned bvsize = mDefPositionVec.GetNum(); + for (auto bbid: mHandler->mBbIdVec) { + BitVector *bv1 = new BitVector(bvsize); + bv1->WipeOff(0xff); // init with all 1 + mPrsvMap[bbid] = bv1; + + BitVector *bv2 = new BitVector(bvsize); + bv2->WipeOff(0); + mGenMap[bbid] = bv2; + + working_list.push_back(mHandler->mBbId2BbMap[bbid]); + } + + while(working_list.size()) { + CfgBB *bb = working_list.front(); + MASSERT(bb && "null BB"); + unsigned bbid = bb->GetId(); + + // skip bb already visited + if (done_list.find(bbid) != done_list.end()) { + working_list.pop_front(); + continue; + } + + for (int it = 0; it < bb->GetSuccessorsNum(); it++) { + working_list.push_back(bb->GetSuccessorAtIndex(it)); + } + + // function parameters are considered defined at function entry bb + if (bb->GetAttr() == AK_Entry) { + CfgFunc *func = mEntryBbId2FuncMap[bbid]; + if(func) { + FunctionNode *fn = static_cast(func->GetFuncNode()); + for (unsigned i = 0; i < fn->GetParamsNum(); i++) { + TreeNode *arg = fn->GetParam(i); + if (arg->IsIdentifier()) { + for (int i = 0; i < mDefPositionVec.GetNum(); i++) { + // set bits for matching bbid + unsigned nid = mDefPositionVec.ValueAtIndex(i).second; + unsigned sid = GetStmtIdFromNodeId(nid); + unsigned bid = GetBbIdFromStmtId(sid); + if (bid == bbid) { + mGenMap[bbid]->SetBit(i); + } + } + } + } + } + } + + for (int it = 0; it < bb->GetStatementsNum(); it++) { + TreeNode *node = bb->GetStatementAtIndex(it); + unsigned stridx = GetDefStrIdx(node); + if (stridx != 0) { + // now loop through all the definition positions + // mPrsvMap + for (int i = 0; i < mDefPositionVec.GetNum(); i++) { + // clear bits for matching stridx + if (mDefPositionVec.ValueAtIndex(i).first == stridx) { + mPrsvMap[bbid]->ClearBit(i); + } + } + + // mGenMap + for (int i = 0; i < mDefPositionVec.GetNum(); i++) { + // set bits for matching bbid + unsigned nid = mDefPositionVec.ValueAtIndex(i).second; + unsigned sid = GetStmtIdFromNodeId(nid); + unsigned bid = GetBbIdFromStmtId(sid); + if (bid == bbid) { + mGenMap[bbid]->SetBit(i); + } + } + } + } + + done_list.insert(bbid); + working_list.pop_front(); + } + + // mRchInMap + for (auto bbid: mHandler->mBbIdVec) { + BitVector *bv = new BitVector(bvsize); + bv->Alloc(bvsize); + bv->WipeOff(0); + mRchInMap[bbid] = bv; + } + + working_list.clear(); + // initialize work list with all reachable BB + for (auto it: done_list) { + CfgBB *bb = mHandler->mBbId2BbMap[it]; + working_list.push_back(bb); + } + + BitVector *old_bv = new BitVector(bvsize); + BitVector *tmp_bv = new BitVector(bvsize); + while (working_list.size()) { + CfgBB *bb = working_list.front(); + unsigned bbid = bb->GetId(); + + tmp_bv->WipeOff(0); + old_bv->WipeOff(0); + old_bv->Or(mRchInMap[bbid]); + mRchInMap[bbid]->WipeOff(0); + for (int i = 0; i < bb->GetPredecessorsNum(); i++){ + CfgBB *pred = bb->GetPredecessorAtIndex(i); + unsigned pid = pred->GetId(); + tmp_bv->WipeOff(0); + tmp_bv->Or(mRchInMap[pid]); + tmp_bv->And(mPrsvMap[pid]); + tmp_bv->Or(mGenMap[pid]); + mRchInMap[bbid]->Or(tmp_bv); + } + + working_list.pop_front(); + if (!mRchInMap[bbid]->Equal(old_bv)) { + for (int i = 0; i < bb->GetSuccessorsNum(); i++) { + working_list.push_back(bb->GetSuccessorAtIndex(i)); + } + } + } + + bool buildOutMap = false; + if (buildOutMap) { + for (auto bbid: mHandler->mBbIdVec) { + BitVector *bv = new BitVector(bvsize); + bv->Alloc(bvsize); + bv->WipeOff(0); + mRchOutMap[bbid] = bv; + } + } + + delete old_bv; + delete tmp_bv; + if (mFlags & FLG_trace_3) DumpAllBVMaps(); +} + +void AST_DFA::DumpAllBVMaps() { + MSGNOLOC0("=== mPrsvMap ==="); + DumpBVMap(mPrsvMap); + MSGNOLOC0("=== mGenMap ==="); + DumpBVMap(mGenMap); + MSGNOLOC0("=== mRchInMap ==="); + DumpBVMap(mRchInMap); +} + +void AST_DFA::DumpBVMap(BVMap &map) { + if (!map.size()) { return; } + std::set ordered(mHandler->mBbIdVec.begin(), mHandler->mBbIdVec.end()); + for (auto bbid: ordered) { + std::cout << "BB" << bbid << " : "; + DumpBV(map[bbid]); + } + std::cout << std::endl; +} + +void AST_DFA::DumpBV(BitVector *bv) { + std::cout << "BitVector: "; + for (int i = 0; i < mDefPositionVec.GetNum(); i++) { + std::cout << bv->GetBit(i); + if (i%8 == 7) std::cout << " "; + if (i%64 == 63) { + std::cout << std::endl; + std::cout << " "; + } + } + std::cout << std::endl; +} + +void AST_DFA::DumpDefUse() { + MSGNOLOC0("============== Dump DefUse =============="); + for (unsigned i = 0; i < mDefPositionVec.GetNum(); i++) { + DefPosition pos = mDefPositionVec.ValueAtIndex(i); + DumpDefPosition(i, pos); + + std::cout << "Use: "; + for (auto nid: mDefUseMap[pos.second]) { + std::cout << nid << " "; + } + std::cout << std::endl; + } +} + +void AST_DFA::CollectInfo() { + MSGNOLOC0("============== CollectInfo =============="); + // process each functions for arguments + for (auto func: mHandler->mModuleFuncs) { + // add arguments as def + TreeNode *f = static_cast(func)->GetFuncNode(); + if (f && f->IsFunction()) { + unsigned sid = f->GetNodeId(); + mStmtIdVec.PushBack(sid); + + // use entry bbid for function and its arguments + unsigned bbid = func->GetEntryBB()->GetId(); + mStmtId2BbIdMap[sid] = bbid; + mEntryBbId2FuncMap[bbid] = func; + + FunctionNode *fn = static_cast(f); + for (unsigned i = 0; i < fn->GetParamsNum(); i++) { + TreeNode *arg = fn->GetParam(i); + if (arg->IsIdentifier()) { + SetNodeId2StmtId(arg->GetNodeId(), sid); + } + } + } + } + + // loop through each BB and each statement + CollectInfoVisitor visitor(mHandler, mFlags, true); + for (auto bbid: mHandler->mBbIdVec) { + visitor.SetBbId(bbid); + if (mFlags & FLG_trace_3) std::cout << " == bbid " << bbid << std::endl; + CfgBB *bb = mHandler->mBbId2BbMap[bbid]; + for (int i = 0; i < bb->GetStatementsNum(); i++) { + TreeNode *stmt = bb->GetStatementAtIndex(i); + // function nodes are handled above + // so do not override with real bbid + if (stmt->IsFunction()) { + continue; + } + unsigned sid = stmt->GetNodeId(); + mStmtIdVec.PushBack(sid); + mStmtId2StmtMap[sid] = stmt; + mStmtId2BbIdMap[sid] = bbid; + visitor.SetStmtIdx(stmt->GetNodeId()); + visitor.SetBbId(bbid); + visitor.Visit(stmt); + } + } +} + +IdentifierNode *CollectInfoVisitor::VisitIdentifierNode(IdentifierNode *node) { + AstVisitor::VisitIdentifierNode(node); + mDFA->SetNodeId2StmtId(node->GetNodeId(), mStmtIdx); + return node; +} + +void AST_DFA::BuildDefUseChain() { + MSGNOLOC0("============== BuildDefUseChain =============="); + DefUseChainVisitor visitor(mHandler, mFlags, true); + std::unordered_set defStrIdxs; + std::unordered_set done_list; + CfgBB *bb; + + // loop through each variable def + for (int i = 0; i < mDefPositionVec.GetNum(); i++) { + DefPosition pos = mDefPositionVec.ValueAtIndex(i); + if (mFlags & FLG_trace_3) DumpDefPosition(i, pos); + std::deque working_list; + + // def stridx + visitor.mDefStrIdx = pos.first; + // def nodeid + visitor.mDefNodeId = pos.second; + visitor.mReachNewDef = false; + unsigned sid = GetStmtIdFromNodeId(visitor.mDefNodeId); + unsigned bid = GetBbIdFromStmtId(sid); + // check if func entry bb + if (mEntryBbId2FuncMap.find(bid) != mEntryBbId2FuncMap.end()) { + // func arguments are defined in entry bb, mark defined + visitor.mReachDef = true; + } else { + visitor.mReachDef = false; + } + + bb = mHandler->mBbId2BbMap[bid]; + + // loop through each BB and each statement + working_list.push_back(bb); + done_list.clear(); + + while(working_list.size()) { + bb = working_list.front(); + MASSERT(bb && "null BB"); + unsigned bbid = bb->GetId(); + MSGNOLOC("BB", bbid); + + // check if def is either alive at bb entry or created in bb + bool alive = mRchInMap[bbid]->GetBit(i); + bool gen = mGenMap[bbid]->GetBit(i); + if (!(alive || gen)) { + done_list.insert(bbid); + working_list.pop_front(); + continue; + } + + // process bb + visitor.VisitBB(bbid); + + // add successors to working_list if not in done_list + if (done_list.find(bbid) == done_list.end()) { + // if new def in bb, then no need to visit successors for the current def + if (!visitor.mReachNewDef) { + for (int i = 0; i < bb->GetSuccessorsNum(); i++) { + working_list.push_back(bb->GetSuccessorAtIndex(i)); + } + } + } + + done_list.insert(bbid); + working_list.pop_front(); + } + } +} + +void DefUseChainVisitor::VisitBB(unsigned bbid) { + SetBbId(bbid); + CfgBB *bb = mHandler->mBbId2BbMap[bbid]; + for (int i = 0; i < bb->GetStatementsNum(); i++) { + TreeNode *node = bb->GetStatementAtIndex(i); + SetStmtIdx(node->GetNodeId()); + if (node->IsFunction()) { + FunctionNode *func = static_cast(node); + for (unsigned i = 0; i < func->GetParamsNum(); i++) { + TreeNode *arg = func->GetParam(i); + Visit(arg); + } + } else { + Visit(node); + } + if (mReachNewDef) { + return; + } + } + return; +} + +IdentifierNode *DefUseChainVisitor::VisitIdentifierNode(IdentifierNode *node) { + if (mFlags & FLG_trace_1) std::cout << "Visiting IdentifierNode, id=" << node->GetNodeId() << "..." << std::endl; + + // only deal with use with same stridx of current def + unsigned stridx = node->GetStrIdx(); + if (stridx != mDefStrIdx) { + return node; + } + + // new def, quit + unsigned nid = node->GetNodeId(); + bool isDef = mHandler->GetDFA()->IsDef(nid); + bool isUse = mHandler->GetDFA()->IsDefUse(nid); + if (isDef) { + if (mReachDef) { + mReachNewDef = true; + if (!isUse) { + return node; + } + } else { + mReachDef = true; + isUse = false; + } + } else if (mReachDef) { + isUse = true; + } + + // exclude its own decl + TreeNode *p = node->GetParent(); + if (p && p->IsDecl()) { + DeclNode *dn = static_cast(p); + if (dn->GetVar() == node) { + return node; + } + } + + // add to mDefUseMap + if (isUse) { + mDFA->mDefUseMap[mDefNodeId].insert(nid); + } + return node; +} + +BinOperatorNode *DefUseChainVisitor::VisitBinOperatorNode(BinOperatorNode *node) { + if (mFlags & FLG_trace_1) std::cout << "Visiting BinOperatorNode, id=" << node->GetNodeId() << "..." << std::endl; + + BinOperatorNode *bon = static_cast(node); + OprId op = bon->GetOprId(); + switch (op) { + case OPR_Assign: + case OPR_AddAssign: + case OPR_SubAssign: + case OPR_MulAssign: + case OPR_DivAssign: + case OPR_ModAssign: + case OPR_ShlAssign: + case OPR_ShrAssign: + case OPR_BandAssign: + case OPR_BorAssign: + case OPR_BxorAssign: + case OPR_ZextAssign: { + // visit rhs first due to computation use/def order + TreeNode *rhs = bon->GetOpndB(); + (void) AstVisitor::VisitTreeNode(rhs); + + TreeNode *lhs = bon->GetOpndA(); + (void) AstVisitor::VisitTreeNode(lhs); + break; + } + default: + TreeNode *lhs = bon->GetOpndA(); + (void) AstVisitor::VisitTreeNode(lhs); + + TreeNode *rhs = bon->GetOpndB(); + (void) AstVisitor::VisitTreeNode(rhs); + break; + } + return node; +} + + +} diff --git a/src/MapleFE/astopt/src/ast_handler.cpp b/src/MapleFE/astopt/src/ast_handler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d08f7415070c5c5908d0d876d002fec026d97733 --- /dev/null +++ b/src/MapleFE/astopt/src/ast_handler.cpp @@ -0,0 +1,343 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include "ast_handler.h" +#include "ast_cfg.h" +#include "ast_info.h" +#include "ast_adj.h" +#include "ast_scp.h" +#include "ast_ti.h" +#include "ast_cfa.h" +#include "ast_dfa.h" +#include "ast_util.h" +#include "ast_xxport.h" +#include "astopt.h" +#include "typetable.h" +#include "gen_astdump.h" + +namespace maplefe { + +Module_Handler::~Module_Handler() { + mNodeId2BbMap.clear(); + mModuleFuncs.clear(); + mBbId2BbMap.clear(); + mBbIdVec.clear(); + mNodeId2Decl.clear(); + mArrayDeclId2EleTypeIdMap.clear(); + delete mCfgFunc; + delete mINFO; + delete mADJ; + delete mSCP; + delete mTI; + delete mCFA; + delete mDFA; + delete mUtil; +} + +MemPool *Module_Handler::GetMemPool() { + return mASTHandler->GetMemPool(); +} + +Module_Handler *AST_Handler::GetModuleHandler(ModuleNode *module) { + for (unsigned i = 0; i < mModuleHandlers.GetNum(); i++) { + Module_Handler *h = mModuleHandlers.ValueAtIndex(i); + if (h->GetASTModule() == module) { + return h; + } + } + return NULL; +} + +Module_Handler *AST_Handler::GetModuleHandler(TreeNode *node) { + ASTScope *scp = node->GetScope(); + while (!scp->GetTree()->IsModule()) { + scp = scp->GetParent(); + } + TreeNode *mod = scp->GetTree(); + Module_Handler *h = NULL; + if (mod && mod->IsModule()) { + h = GetModuleHandler(static_cast(mod)); + } + + return h; +} + +HandlerIndex AST_Handler::GetHandlerIndex(const char *filename) { + if (mModuleHandlerMap.find(filename) == mModuleHandlerMap.end()) + return HandlerNotFound; + return mModuleHandlerMap.at(filename); +} + +bool AST_Handler::AddModule(ModuleNode *m) { + const char *filename = m->GetFilename(); + if (mModuleHandlerMap.find(filename) != mModuleHandlerMap.end()) + return false; + mModuleHandlerMap[filename] = mSize; + + Module_Handler *handler = new(mMemPool.Alloc(sizeof(Module_Handler))) Module_Handler(mFlags); + handler->SetASTModule(m); + handler->SetIsTS(m->GetSrcLang() == SrcLangTypeScript); + handler->SetASTHandler(this); + mModuleHandlers.PushBack(handler); + mSize++; + return true; +} + +void Module_Handler::BasicAnalysis() { + // collect AST info + CollectInfo(); + + // rewirte some AST nodes + AdjustAST(); + + // scope analysis + ScopeAnalysis(); +} + +void Module_Handler::CollectInfo() { + if (!mUtil) { + mUtil = new(GetMemPool()->Alloc(sizeof(AST_Util))) AST_Util(this, mFlags); + } + if (!mINFO) { + mINFO = new(GetMemPool()->Alloc(sizeof(AST_INFO))) AST_INFO(this, mFlags); + } + mINFO->CollectInfo(); +} + +void Module_Handler::AdjustAST() { + if (!mADJ) { + mADJ = new(GetMemPool()->Alloc(sizeof(AST_ADJ))) AST_ADJ(this, mFlags); + } + mADJ->AdjustAST(); +} + +void Module_Handler::ScopeAnalysis() { + if (!mSCP) { + mSCP = new(GetMemPool()->Alloc(sizeof(AST_SCP))) AST_SCP(this, mFlags); + } + mSCP->ScopeAnalysis(); + + if (mFlags & FLG_trace_2) { + std::cout << "============== Dump Scope ==============" << std::endl; + mASTModule->GetRootScope()->Dump(0); + } +} + +void Module_Handler::TypeInference() { + if (!mTI) { + mTI = new(GetMemPool()->Alloc(sizeof(TypeInfer))) TypeInfer(this, mFlags); + } + mTI->TypeInference(); +} + +void Module_Handler::BuildCFG() { + CfgBuilder builder(this, mFlags); + builder.Build(); +} + +void Module_Handler::ControlFlowAnalysis() { + if (!mCFA) { + mCFA = new(GetMemPool()->Alloc(sizeof(AST_CFA))) AST_CFA(this, mFlags); + } + mCFA->ControlFlowAnalysis(); +} + +void Module_Handler::DataFlowAnalysis() { + if (!mDFA) { + mDFA = new(GetMemPool()->Alloc(sizeof(AST_DFA))) AST_DFA(this, mFlags); + } + mDFA->DataFlowAnalysis(); +} + +AstOpt *Module_Handler::GetAstOpt() { + return mASTHandler->GetAstOpt(); +} + +AST_XXport *Module_Handler::GetASTXXport() { + return mASTHandler->GetAstOpt()->GetASTXXport(); +} + +// input an identifire ===> returen the decl node with same name +TreeNode *Module_Handler::FindDecl(IdentifierNode *node, bool deep) { + TreeNode *decl = NULL; + if (!node) { + return decl; + } + unsigned nid = node->GetNodeId(); + + // search the existing map mNodeId2Decl first + if (mNodeId2Decl.find(nid) != mNodeId2Decl.end()) { + decl = mNodeId2Decl[nid]; + // deep search for imported decl, chase down + if (deep && decl && GetASTXXport()->IsImportedDeclId(mHidx, decl->GetNodeId())) { + decl = GetASTXXport()->GetExportedNodeFromImportedNode(mHidx, decl->GetNodeId()); + } + return decl; + } + + ASTScope *scope = node->GetScope(); + MASSERT(scope && "null scope"); + + TreeNode *tree = scope->GetTree(); + unsigned stridx = node->GetStrIdx(); + + decl = mINFO->GetField(tree->GetNodeId(), stridx); + + if (!decl) { + decl = scope->FindDeclOf(stridx); + } + + if (!decl && deep) { + decl = scope->FindExportedDeclOf(stridx); + } + + if (decl) { + AddNodeId2DeclMap(node->GetNodeId(), decl); + } + + if (deep && decl && GetASTXXport()->IsImportedDeclId(mHidx, decl->GetNodeId())) { + decl = GetASTXXport()->GetExportedNodeFromImportedNode(mHidx, decl->GetNodeId()); + } + + return decl; +} + +TreeNode *Module_Handler::FindType(IdentifierNode *node) { + if (!node) { + return NULL; + } + ASTScope *scope = node->GetScope(); + MASSERT(scope && "null scope"); + TreeNode *type = scope->FindTypeOf(node->GetStrIdx()); + + return type; +} + +// input a node ==> return the function node contains it +TreeNode *Module_Handler::FindFunc(TreeNode *node) { + ASTScope *scope = node->GetScope(); + MASSERT(scope && "null scope"); + while (scope) { + TreeNode *sn = scope->GetTree(); + if (sn->IsFunction()) { + return sn; + } + scope = scope->GetParent(); + } + return NULL; +} + +void Module_Handler::AddDirectField(TreeNode *node) { + mDirectFieldSet.insert(node->GetNodeId()); +} + +bool Module_Handler::IsDirectField(TreeNode *node) { + return mDirectFieldSet.find(node->GetNodeId()) != mDirectFieldSet.end(); +} + +// array's element typeid +TypeId Module_Handler::GetArrayElemTypeId(unsigned nid) { + TypeId tid = TY_None; + if (mArrayDeclId2EleTypeIdMap.find(nid) != mArrayDeclId2EleTypeIdMap.end()) { + tid = mArrayDeclId2EleTypeIdMap[nid]; + } + return tid; +} + +void Module_Handler::SetArrayElemTypeId(unsigned nid, TypeId tid) { + mArrayDeclId2EleTypeIdMap[nid] = tid; +} + +// array's element typeidx +unsigned Module_Handler::GetArrayElemTypeIdx(unsigned nid) { + unsigned tidx = 0; + if (mArrayDeclId2EleTypeIdxMap.find(nid) != mArrayDeclId2EleTypeIdxMap.end()) { + tidx = mArrayDeclId2EleTypeIdxMap[nid]; + } + return tidx; +} + +void Module_Handler::SetArrayElemTypeIdx(unsigned nid, unsigned tidx) { + mArrayDeclId2EleTypeIdxMap[nid] = tidx; +} + +DimensionNode *Module_Handler::GetArrayDim(unsigned nid) { + DimensionNode *dim = NULL; + if (mArrayDeclId2DimMap.find(nid) != mArrayDeclId2DimMap.end()) { + dim = mArrayDeclId2DimMap[nid]; + } + return dim; +} + +void Module_Handler::SetArrayDim(unsigned nid, DimensionNode *dim) { + mArrayDeclId2DimMap[nid] = dim; +} + +void Module_Handler::AddGeneratorUsed(unsigned nid, FunctionNode *func) { + mGeneratorUsedMap[nid] = func; +} + +bool Module_Handler::IsGeneratorUsed(unsigned nid) { + return (mGeneratorUsedMap.find(nid) != mGeneratorUsedMap.end()); +} + +FunctionNode *Module_Handler::GetGeneratorUsed(unsigned nid) { + if (mGeneratorUsedMap.find(nid) != mGeneratorUsedMap.end()) { + return mGeneratorUsedMap[nid]; + } + return NULL; +} + +bool Module_Handler::UpdateGeneratorUsed(unsigned target, unsigned src) { + if (mGeneratorUsedMap.find(src) != mGeneratorUsedMap.end()) { + mGeneratorUsedMap[target] = mGeneratorUsedMap[src]; + return true; + } + return false; +} + +bool Module_Handler::IsFromLambda(TreeNode *node) { + if (!node) { + return false; + } + unsigned nid = node->GetNodeId(); + return mINFO->IsFromLambda(nid); +} + +bool Module_Handler::IsDef(TreeNode *node) { + return mDFA->IsDef(node->GetNodeId()); +} + +bool Module_Handler::IsCppField(TreeNode *node) { + return mUtil->IsCppField(node); +} + +void Module_Handler::Dump(char *msg) { + std::cout << msg << " : " << std::endl; + CfgFunc *func = GetCfgFunc(); + func->Dump(); +} + +void Module_Handler::DumpArrayElemTypeIdMap() { + std::cout << "================= ArrayDeclId2EleTypeIdMap ==========" << std::endl; + for (auto it : mArrayDeclId2EleTypeIdMap) { + std::cout << "nodeid : " << it.first << " " + << AstDump::GetEnumTypeId(it.second) << std::endl; + } +} + +} diff --git a/src/MapleFE/astopt/src/ast_info.cpp b/src/MapleFE/astopt/src/ast_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c8ef881ec5d39d5ac2f54f6a6cae737fbb8cb82 --- /dev/null +++ b/src/MapleFE/astopt/src/ast_info.cpp @@ -0,0 +1,977 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include "ast_handler.h" +#include "typetable.h" +#include "ast_util.h" +#include "ast_info.h" +#include "ast_xxport.h" + +namespace maplefe { + +void AST_INFO::CollectInfo() { + MSGNOLOC0("============== ASTInfo =============="); + ModuleNode *module = mHandler->GetASTModule(); + for(unsigned i = 0; i < module->GetTreesNum(); i++) { + TreeNode *it = module->GetTree(i); + it->SetParent(module); + } + + AddBuiltInTypes(); + + // collect import/export info + MSGNOLOC0("============== XXport info =============="); + mHandler->GetASTXXport()->CollectXXportInfo(mHandler->GetHidx()); + + MSGNOLOC0("============== Fill node info =============="); + FillNodeInfoVisitor visitor_node(mHandler, mFlags, true); + visitor_node.Visit(module); + + mStrIdxVisitor = new FindStrIdxVisitor(mHandler, mFlags, true); + + // collect class/interface/struct decl + mPass = 0; + MSGNOLOC0("============== Collect class/interface/struct =============="); + ClassStructVisitor visitor(mHandler, mFlags, true); + visitor.Visit(module); + + if (module->GetSrcLang() != SrcLangTypeScript) { + return; + } + + // collect type parameters + // sort fields according to the field name stridx + // it also include first visit to named types to reduce + // creation of unnecessary anonymous struct + mPass = 1; + MSGNOLOC0("============== type parameter, super fields and Sort fields =============="); + visitor.Visit(module); + + // merge class/interface/struct decl first to reduce + // introducing of unnecessary anonymous structs + mPass = 2; + MSGNOLOC0("============== merge class/interface/struct =============="); + visitor.Visit(module); + + // collect function types + FunctionVisitor func_visitor(mHandler, mFlags, true); + func_visitor.Visit(module); +} + +void AST_INFO::AddBuiltInTypes() { + unsigned size = gTypeTable.size(); + for (unsigned idx = 1; idx < size; idx++) { + TreeNode *node = gTypeTable.GetTypeFromTypeIdx(idx); + if (node->IsUserType()) { + mStrIdx2TypeIdxMap[node->GetStrIdx()] = node->GetTypeIdx(); + } + } + + // add language builtin types + TreeNode *node = NULL; + unsigned stridx = 0; +#define BUILTIN(T) \ + stridx = gStringPool.GetStrIdx(#T);\ + if (mStrIdx2TypeIdxMap.find(stridx) == mStrIdx2TypeIdxMap.end()) {\ + node = gTypeTable.CreateBuiltinType(#T, TY_Class);\ + gTypeTable.AddType(node);\ + mStrIdx2TypeIdxMap[stridx] = node->GetTypeIdx();\ + } +#include "lang_builtin.def" +} + +bool AST_INFO::IsBuiltInType(TreeNode *node) { + return mStrIdx2TypeIdxMap.find(node->GetStrIdx()) != mStrIdx2TypeIdxMap.end(); +} + +unsigned AST_INFO::GetBuiltInTypeIdx(unsigned stridx) { + if (mStrIdx2TypeIdxMap.find(stridx) != mStrIdx2TypeIdxMap.end()) { + return mStrIdx2TypeIdxMap[stridx]; + } + return 0; +} + +unsigned AST_INFO::GetBuiltInTypeIdx(TreeNode *node) { + unsigned stridx = node->GetStrIdx(); + return GetBuiltInTypeIdx(stridx); +} + +TypeId AST_INFO::GetTypeId(TreeNode *node) { + return node->GetTypeId(); +} + +unsigned AST_INFO::GetFieldsSize(TreeNode *node, bool native) { + unsigned size = 0; + unsigned nid = node->GetNodeId(); + if (!native && mStructId2FieldsMap.find(nid) != mStructId2FieldsMap.end()) { + size = mStructId2FieldsMap[nid].GetNum(); + return size; + } + switch (node->GetKind()) { + case NK_StructLiteral: + size = static_cast(node)->GetFieldsNum(); + break; + case NK_Struct: + size = static_cast(node)->GetFieldsNum(); + break; + case NK_Class: + size = static_cast(node)->GetFieldsNum(); + break; + case NK_Interface: + size = static_cast(node)->GetFieldsNum(); + break; + default: + break; + } + return size; +} + +TreeNode *AST_INFO::GetField(TreeNode *node, unsigned i, bool native) { + TreeNode *fld = NULL; + unsigned nid = node->GetNodeId(); + if (!native && mStructId2FieldsMap.find(nid) != mStructId2FieldsMap.end()) { + fld = mStructId2FieldsMap[nid].ValueAtIndex(i); + return fld; + } + switch (node->GetKind()) { + case NK_StructLiteral: + fld = static_cast(node)->GetField(i); + break; + case NK_Struct: + fld = static_cast(node)->GetField(i); + break; + case NK_Class: + fld = static_cast(node)->GetField(i); + break; + case NK_Interface: + fld = static_cast(node)->GetField(i); + break; + default: + break; + } + return fld; +} + +void AST_INFO::AddField(TreeNode *container, TreeNode *node) { + unsigned nid = container->GetNodeId(); + if (mStructId2FieldsMap.find(nid) == mStructId2FieldsMap.end()) { + for (unsigned i = 0; i < GetFieldsSize(container, true); i++) { + TreeNode *fld = GetField(container, i, true); + mStructId2FieldsMap[nid].PushBack(fld); + } + } + AddField(nid, node); +} + +void AST_INFO::AddField(unsigned nid, TreeNode *node) { + mStructId2FieldsMap[nid].PushBack(node); +} + +// get the filed in nid, including its super, with name stridx +// return NULL if not found +TreeNode *AST_INFO::GetField(unsigned nid, unsigned stridx) { + if (mStructId2FieldsMap.find(nid) != mStructId2FieldsMap.end()) { + unsigned size = mStructId2FieldsMap[nid].GetNum(); + for (unsigned i = 0; i < size; i++) { + TreeNode *fld = mStructId2FieldsMap[nid].ValueAtIndex(i); + if (fld->GetStrIdx() == stridx) { + return fld; + } + } + } + return NULL; +} + +unsigned AST_INFO::GetSuperSize(TreeNode *node, unsigned idx) { + unsigned size1 = 0; + unsigned size2 = 0; + switch (node->GetKind()) { + case NK_Struct: { + size1 = static_cast(node)->GetSupersNum(); + size2 = 0; + break; + } + case NK_Class: { + size1 = static_cast(node)->GetSuperClassesNum(); + size2 = static_cast(node)->GetSuperInterfacesNum(); + break; + } + case NK_Interface: { + size1 = static_cast(node)->GetSuperInterfacesNum(); + size2 = 0; + break; + } + default: + break; + } + return (idx == 1) ? size1 : size2; +} + +TreeNode *AST_INFO::GetSuper(TreeNode *node, unsigned i, unsigned idx) { + TreeNode *fld1 = NULL; + TreeNode *fld2 = NULL; + switch (node->GetKind()) { + case NK_Struct: + fld1 = static_cast(node)->GetSuper(i); + fld2 = NULL; + break; + case NK_Class: { + fld1 = (idx == 1) ? static_cast(node)->GetSuperClass(i) : NULL; + fld2 = (idx == 2) ? static_cast(node)->GetSuperInterface(i) : NULL; + break; + } + case NK_Interface: + fld1 = static_cast(node)->GetSuperInterfaceAtIndex(i); + fld2 = NULL; + break; + default: + break; + } + return (idx == 1) ? fld1 : fld2; +} + +bool AST_INFO::IsInterface(TreeNode *node) { + bool isI = node->IsInterface(); + if (node->IsStruct()) { + isI = isI || (static_cast(node)->GetProp() == SProp_TSInterface); + } + return isI; +} + +bool AST_INFO::IsTypeCompatible(TreeNode *node1, TreeNode *node2) { + if (node1 == node2) { + return true; + } + // only one is NULL + if ((!node1 && node2) || (node1 && !node2)) { + return false; + } + // not same kind + if (node1->GetKind() != node2->GetKind()) { + return false; + } + // at least one is prim + if (node1->IsPrimType() || node2->IsPrimType()) { + TypeId tid_field = GetTypeId(node2); + TypeId tid_target = GetTypeId(node1); + return (tid_field == tid_target); + } + bool result = false; + // same kind + NodeKind nk = node1->GetKind(); + switch (nk) { + case NK_UserType: { + UserTypeNode *ut1 = static_cast(node1); + UserTypeNode *ut2 = static_cast(node2); + result = IsTypeCompatible(ut1->GetId(), ut2->GetId()); + } + case NK_PrimType: { + PrimTypeNode *pt1 = static_cast(node1); + PrimTypeNode *pt2 = static_cast(node2); + result = (pt1->GetPrimType() == pt2->GetPrimType()); + } + case NK_PrimArrayType: { + PrimArrayTypeNode *pat1 = static_cast(node1); + PrimArrayTypeNode *pat2 = static_cast(node2); + result = IsTypeCompatible(pat1->GetPrim(), pat2->GetPrim()); + if (!result) { + break; + } + result = IsTypeCompatible(pat1->GetDims(), pat2->GetDims()); + } + case NK_Dimension: { + DimensionNode *dim1 = static_cast(node1); + DimensionNode *dim2 = static_cast(node2); + result = (dim1->GetDimensionsNum() == dim2->GetDimensionsNum()); + if (!result) { + break; + } + for (unsigned i = 0; i < dim1->GetDimensionsNum(); i++) { + result = result && (dim1->GetDimension(i) == dim2->GetDimension(i)); + } + break; + } + default: { + break; + } + } + return result; +} + +bool AST_INFO::IsTypeIdCompatibleTo(TypeId field, TypeId target) { + if (target == TY_None) { + return true; + } else if (target == TY_Number) { + return field == TY_Int || field == TY_Long || field == TY_Float || field == TY_Double; + } else { + return field == target; + } + return false; +} + +// check if "field" is compatible to "target" +bool AST_INFO::IsFieldCompatibleTo(TreeNode *field, TreeNode *target) { + if (!target->IsIdentifier()) { + return false; + } + unsigned stridx_target = target->GetStrIdx(); + IdentifierNode *id_target = static_cast(target); + + unsigned stridx_field = 0; + bool result = false; + + // is identifier + if (field->IsIdentifier()) { + stridx_field = field->GetStrIdx(); + if (stridx_field != stridx_target) { + return false; + } + IdentifierNode *id_field = static_cast(field); + TreeNode *type_target = id_target->GetType(); + TreeNode *type_field = id_field->GetType(); + result = IsTypeCompatible(type_field, type_target); + } + // field literal + else if (field->IsFieldLiteral()) { + FieldLiteralNode *fln = static_cast(field); + TreeNode *name = fln->GetFieldName(); + if (name && name->IsIdentifier()) { + stridx_field = name->GetStrIdx(); + } + if (stridx_field != stridx_target) { + return false; + } + TreeNode *lit = fln->GetLiteral(); + if (!lit->IsLiteral()) { + return false; + } + LiteralNode *ln = static_cast(lit); + TypeId tid_field = GetTypeId(ln); + TypeId tid_target = GetTypeId(id_target->GetType()); + result = IsTypeIdCompatibleTo(tid_field, tid_target); + } + + return result; +} + +TreeNode *AST_INFO::GetCanonicStructNode(TreeNode *node) { + // node with super does not map to others + if (WithSuper(node)) { + return node; + } + + unsigned size = GetFieldsSize(node); + bool isI0 = IsInterface(node); + + for (auto s: mFieldNum2StructNodeMap[size]) { + // found itself + if (node == s) { + return s; + } + + bool isI = IsInterface(s); + if (!node->IsStructLiteral()) { + // skip if one is interface but other is not + if ((isI0 && !isI) || (!isI0 && isI)) { + continue; + } + } + bool match = true;; + // check fields + for (unsigned fid = 0; fid < size; fid++) { + TreeNode *f0 = GetField(node, fid); + TreeNode *f1 = GetField(s, fid); + if (!IsFieldCompatibleTo(f0, f1)) { + match = false; + break; + } + } + + if (match) { + node->SetTypeIdx(s->GetTypeIdx()); + return s; + } + } + + // do not proceed if node contains type parameter + if (WithTypeParamFast(node)) { + return node; + } + + // not match + unsigned stridx = node->GetStrIdx(); + + // node as anonymous struct will be added to module scope + if (GetNameAnonyStruct() && stridx == 0) { + TreeNode *anony = GetAnonymousStruct(node); + if (!anony) { + return node; + } else { + node->SetTypeIdx(anony->GetTypeIdx()); + node = anony; + } + } + mFieldNum2StructNodeMap[size].insert(node); + + return node; +} + +IdentifierNode *AST_INFO::CreateIdentifierNode(unsigned stridx) { + IdentifierNode *node = mHandler->NewTreeNode(); + node->SetStrIdx(stridx); + return node; +} + +UserTypeNode *AST_INFO::CreateUserTypeNode(unsigned stridx, ASTScope *scope) { + unsigned tidx = GetBuiltInTypeIdx(stridx); + IdentifierNode *node = CreateIdentifierNode(stridx); + SetTypeId(node, TY_Class); + SetTypeIdx(node, tidx); + if (scope) { + node->SetScope(scope); + } + + UserTypeNode *utype = mHandler->NewTreeNode(); + utype->SetId(node); + utype->SetStrIdx(stridx); + SetTypeId(utype, TY_Class); + SetTypeIdx(utype, tidx); + node->SetParent(utype); + return utype; +} + +UserTypeNode *AST_INFO::CreateUserTypeNode(IdentifierNode *node) { + SetTypeId(node, TY_Class); + UserTypeNode *utype = mHandler->NewTreeNode(); + utype->SetId(node); + utype->SetStrIdx(node->GetStrIdx()); + SetTypeId(utype, TY_Class); + node->SetParent(utype); + return utype; +} + +TypeAliasNode *AST_INFO::CreateTypeAliasNode(TreeNode *to, TreeNode *from) { + UserTypeNode *utype1 = CreateUserTypeNode(from->GetStrIdx()); + UserTypeNode *utype2 = CreateUserTypeNode(to->GetStrIdx()); + + TypeAliasNode *alias = mHandler->NewTreeNode(); + alias->SetId(utype1); + alias->SetStrIdx(from->GetStrIdx()); + alias->SetAlias(utype2); + + return alias; +} + +StructNode *AST_INFO::CreateStructFromStructLiteral(StructLiteralNode *node) { + StructNode *newnode = mHandler->NewTreeNode(); + SetTypeId(newnode, TY_Class); + + for (unsigned i = 0; i < node->GetFieldsNum(); i++) { + FieldLiteralNode *fl = node->GetField(i); + TreeNode *name = fl->GetFieldName(); + if (!name || !name->IsIdentifier()) { + newnode->Release(); + return NULL; + } + + IdentifierNode *fid = CreateIdentifierNode(name->GetStrIdx()); + newnode->AddField(fid); + mHandler->AddDirectField(fid); + + TreeNode *lit = fl->GetLiteral(); + if (lit && lit->IsLiteral()) { + TypeId tid = GetTypeId(lit); + PrimTypeNode *type = mHandler->NewTreeNode(); + type->SetPrimType(tid); + fid->SetType(type); + } else { + NOTYETIMPL("StructLiteralNode literal field kind"); + } + } + return newnode; +} + +unsigned AST_INFO::GetAnonymousName() { + std::string str("AnonymousStruct__"); + str += std::to_string(mNum++); + unsigned stridx = gStringPool.GetStrIdx(str); + return stridx; +} + +TreeNode *AST_INFO::GetAnonymousStruct(TreeNode *node) { + unsigned stridx = GetAnonymousName(); + TreeNode *newnode = node; + if (newnode->IsStructLiteral()) { + StructLiteralNode *sl = static_cast(node); + newnode = CreateStructFromStructLiteral(sl); + if (!newnode) { + return NULL; + } + } + newnode->SetStrIdx(stridx); + + // for struct node, set structid + if (newnode->IsStruct()) { + StructNode *snode = static_cast(newnode); + IdentifierNode *id = snode->GetStructId(); + if (!id) { + id = CreateIdentifierNode(0); + id->SetScope(snode->GetScope()); + snode->SetStructId(id); + } + + // set stridx for structid + id->SetStrIdx(stridx); + } + + ModuleNode *module = mHandler->GetASTModule(); + gTypeTable.AddType(newnode); + module->GetScope()->AddType(newnode); + module->AddTreeFront(newnode); + return newnode; +} + +bool AST_INFO::WithStrIdx(TreeNode *node, unsigned stridx) { + mStrIdxVisitor->ResetFound(); + mStrIdxVisitor->SetStrIdx(stridx); + mStrIdxVisitor->Visit(node); + return mStrIdxVisitor->GetFound(); +} + +bool AST_INFO::WithTypeParam(TreeNode *node) { + for (auto idx: mTypeParamStrIdxSet) { + if (WithStrIdx(node, idx)) { + return true; + } + } + return false; +} + +bool AST_INFO::WithThis(TreeNode *node) { + unsigned idx = gStringPool.GetStrIdx("this"); + mStrIdxVisitor->SetCheckThis(true); + if (WithStrIdx(node, idx)) { + return true; + } + return false; +} + +bool AST_INFO::WithTypeParamFast(TreeNode *node) { + return (mWithTypeParamNodeSet.find(node->GetNodeId()) != mWithTypeParamNodeSet.end()); +} + +bool AST_INFO::WithSuper(TreeNode *node) { + unsigned supernum = 0; + switch (node->GetKind()) { + case NK_Class: + supernum = static_cast(node)->GetSuperClassesNum(); + break; + case NK_Interface: + supernum = static_cast(node)->GetSuperInterfacesNum(); + break; + default: + break; + } + return (supernum != 0); +} + +template +void AST_INFO::ExtendFields(T1 *node, TreeNode *sup) { + if (sup == NULL) { + // let sup be node itself + sup = node; + } + unsigned nid = node->GetNodeId(); + if (sup && sup->IsUserType()) { + sup = static_cast(sup)->GetId(); + } + if (sup && sup->IsIdentifier()) { + sup = GetStructFromStrIdx(sup->GetStrIdx()); + } + if (!sup) { + return; + } + for (unsigned i = 0; i < GetFieldsSize(sup, true); i++) { + TreeNode *fld = GetField(sup, i, true); + AddField(nid, fld); + } + for (unsigned i = 0; i < GetSuperSize(sup, 1); i++) { + TreeNode *s = GetSuper(sup, i, 1); + ExtendFields(node, s); + } + for (unsigned i = 0; i < GetSuperSize(sup, 2); i++) { + TreeNode *s = GetSuper(sup, i, 2); + ExtendFields(node, s); + } +} + +template +static void DumpVec(std::vector> vec) { + unsigned size = vec.size(); + std::cout << "================ Dump Vec ================" << std::endl; + for (unsigned i = 0; i < size; i++) { + std::cout << "item #" << i + << " nodeid " << vec[i].second->GetNodeId() + << " stridx " << vec[i].second->GetStrIdx() + << std::endl; + } +} + +template +void AST_INFO::SortFields(T1 *node) { + std::vector> vec; + unsigned size = GetFieldsSize(node, true); + if (size) { + for (unsigned i = 0; i < size; i++) { + T2 *fld = node->GetField(i); + unsigned stridx = fld->GetStrIdx(); + std::pair p(stridx, fld); + vec.push_back(p); + } + std::sort(vec.begin(), vec.end()); + for (unsigned i = 0; i < size; i++) { + node->SetField(i, vec[i].second); + } + } + + unsigned nid = node->GetNodeId(); + if (mStructId2FieldsMap.find(nid) != mStructId2FieldsMap.end()) { + std::vector> vec; + unsigned size = mStructId2FieldsMap[nid].GetNum(); + for (unsigned i = 0; i < size; i++) { + TreeNode *fld = mStructId2FieldsMap[nid].ValueAtIndex(i); + unsigned stridx = fld->GetStrIdx(); + std::pair p(stridx, fld); + vec.push_back(p); + } + std::sort(vec.begin(), vec.end()); + for (unsigned i = 0; i < size; i++) { + *(mStructId2FieldsMap[nid].RefAtIndex(i)) = vec[i].second; + } + } +} + +void AST_INFO::SetTypeId(TreeNode *node, TypeId tid) { + mHandler->GetUtil()->SetTypeId(node, tid); +} + +void AST_INFO::SetTypeIdx(TreeNode *node, unsigned tidx) { + mHandler->GetUtil()->SetTypeIdx(node, tidx); +} + +IdentifierNode *FillNodeInfoVisitor::VisitIdentifierNode(IdentifierNode *node) { + (void) AstVisitor::VisitIdentifierNode(node); + TreeNode *type = node->GetType(); + if (type) { + mInfo->SetTypeId(node, type->GetTypeId()); + mInfo->SetTypeIdx(node, type->GetTypeIdx()); + } + return node; +} + +FunctionNode *FillNodeInfoVisitor::VisitFunctionNode(FunctionNode *node) { + (void) AstVisitor::VisitFunctionNode(node); + TreeNode *type = node->GetRetType(); + if (type) { + mInfo->SetTypeId(node, type->GetTypeId()); + mInfo->SetTypeIdx(node, type->GetTypeIdx()); + } else if (node->IsGenerator()) { + unsigned stridx = gStringPool.GetStrIdx("Generator"); + unsigned tidx = mInfo->GetBuiltInTypeIdx(stridx); + UserTypeNode *ut = mInfo->CreateUserTypeNode(stridx); + node->SetRetType(ut); + } + return node; +} + +LiteralNode *FillNodeInfoVisitor::VisitLiteralNode(LiteralNode *node) { + (void) AstVisitor::VisitLiteralNode(node); + LitData data = node->GetData(); + LitId id = data.mType; + switch (id) { + case LT_IntegerLiteral: + mInfo->SetTypeId(node, TY_Int); + mInfo->SetTypeIdx(node, TY_Int); + break; + case LT_FPLiteral: + mInfo->SetTypeId(node, TY_Float); + mInfo->SetTypeIdx(node, TY_Float); + break; + case LT_DoubleLiteral: + mInfo->SetTypeId(node, TY_Double); + mInfo->SetTypeIdx(node, TY_Double); + break; + case LT_BooleanLiteral: + mInfo->SetTypeId(node, TY_Boolean); + mInfo->SetTypeIdx(node, TY_Boolean); + break; + case LT_CharacterLiteral: + mInfo->SetTypeId(node, TY_Char); + mInfo->SetTypeIdx(node, TY_Char); + break; + case LT_StringLiteral: + mInfo->SetTypeId(node, TY_String); + mInfo->SetTypeIdx(node, TY_String); + if (node->GetStrIdx() == 0) { + node->SetStrIdx(data.mData.mStrIdx); + } + break; + case LT_NullLiteral: + mInfo->SetTypeId(node, TY_Null); + break; + case LT_SuperLiteral: + mInfo->SetTypeId(node, TY_Object); + break; + case LT_VoidLiteral: + mInfo->SetTypeId(node, TY_Void); + break; + case LT_ThisLiteral: + break; + default: + break; + } + return node; +} + +PrimTypeNode *FillNodeInfoVisitor::VisitPrimTypeNode(PrimTypeNode *node) { + (void) AstVisitor::VisitPrimTypeNode(node); + TypeId prim = node->GetPrimType(); + bool isprim = gTypeTable.IsPrimTypeId(prim); + + if (isprim) { + mInfo->SetTypeIdx(node, prim); + } else { + TreeNode *type = gTypeTable.GetTypeFromTypeId(prim); + mInfo->SetTypeIdx(node, type->GetTypeIdx()); + } + return node; +} + +UserTypeNode *FillNodeInfoVisitor::VisitUserTypeNode(UserTypeNode *node) { + (void) AstVisitor::VisitUserTypeNode(node); + TreeNode *id = node->GetId(); + if (id) { + unsigned tidx = mInfo->GetBuiltInTypeIdx(id); + if (tidx) { + mInfo->SetTypeIdx(id, tidx); + } + if (!id->IsTypeIdNone()) { + mInfo->SetTypeId(node, id->GetTypeId()); + mInfo->SetTypeIdx(node, id->GetTypeIdx()); + } + } + return node; +} + +StructLiteralNode *ClassStructVisitor::VisitStructLiteralNode(StructLiteralNode *node) { + mInfo->SetTypeId(node, TY_Class); + (void) AstVisitor::VisitStructLiteralNode(node); + if (mInfo->GetPass() == 0) { + // field literal stridx to its ids' + for (unsigned i = 0; i < node->GetFieldsNum(); i++) { + FieldLiteralNode *fln = node->GetField(i); + TreeNode *name = fln->GetFieldName(); + if (name) { + fln->SetStrIdx(name->GetStrIdx()); + } + } + } else if (mInfo->GetPass() == 1) { + if (mInfo->WithTypeParam(node)) { + mInfo->InsertWithTypeParamNode(node); + } + // sort fields + mInfo->SortFields(node); + } else if (mInfo->GetPass() == 2) { + // create a anonymous struct for it + mInfo->SetNameAnonyStruct(true); + TreeNode *csn = mInfo->GetCanonicStructNode(node); + if (csn && csn != node) { + VisitTreeNode(csn); + } + } + return node; +} + +StructNode *ClassStructVisitor::VisitStructNode(StructNode *node) { + if (node->GetProp() != SProp_TSEnum) { + mInfo->SetTypeId(node, TY_Class); + if (node->GetStructId()) { + mInfo->SetTypeId(node->GetStructId(), TY_Class); + } + } + (void) AstVisitor::VisitStructNode(node); + if (mInfo->GetPass() == 0) { + gTypeTable.AddType(node); + IdentifierNode *id = node->GetStructId(); + if (id && node->GetStrIdx() == 0) { + node->SetStrIdx(id->GetStrIdx()); + } + if (node->GetStrIdx() == 0) { + node->SetStrIdx(mInfo->GetAnonymousName()); + } + mInfo->SetStrIdx2Struct(node->GetStrIdx(), node); + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (TreeNode *t = node->GetField(i)) { + if (!t->IsStrIndexSig()) { + mHandler->AddDirectField(t); + } + } + } + } else if (mInfo->GetPass() == 1) { + if (mInfo->WithTypeParam(node)) { + mInfo->InsertWithTypeParamNode(node); + } + // extends + mInfo->ExtendFields(node, NULL); + // sort fields + mInfo->SortFields(node); + } else if (mInfo->GetPass() == 2) { + // skip getting canonical type if not only fields + if (node->GetMethodsNum() || node->GetStrIdx() == 0) { + return node; + } + mInfo->GetCanonicStructNode(node); + } + return node; +} + +ClassNode *ClassStructVisitor::VisitClassNode(ClassNode *node) { + mInfo->SetTypeId(node, TY_Class); + (void) AstVisitor::VisitClassNode(node); + if (mInfo->GetPass() == 0) { + if (node->GetStrIdx() == 0) { + node->SetStrIdx(mInfo->GetAnonymousName()); + } + gTypeTable.AddType(node); + mInfo->SetStrIdx2Struct(node->GetStrIdx(), node); + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (TreeNode *t = node->GetField(i)) { + if (!t->IsStrIndexSig()) { + mHandler->AddDirectField(t); + } + } + } + } else if (mInfo->GetPass() == 1) { + if (mInfo->WithTypeParam(node)) { + mInfo->InsertWithTypeParamNode(node); + } + // include super class fields + mInfo->ExtendFields(node, NULL); + // sort fields + mInfo->SortFields(node); + } else if (mInfo->GetPass() == 2) { + // skip getting canonical type if not only fields + if (node->GetMethodsNum() || node->GetTypeParamsNum()) { + return node; + } + mInfo->GetCanonicStructNode(node); + } + return node; +} + +InterfaceNode *ClassStructVisitor::VisitInterfaceNode(InterfaceNode *node) { + mInfo->SetTypeId(node, TY_Class); + (void) AstVisitor::VisitInterfaceNode(node); + if (mInfo->GetPass() == 0) { + if (node->GetStrIdx() == 0) { + node->SetStrIdx(mInfo->GetAnonymousName()); + } + gTypeTable.AddType(node); + mInfo->SetStrIdx2Struct(node->GetStrIdx(), node); + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + if (TreeNode *t = node->GetField(i)) { + if (!t->IsStrIndexSig()) { + mHandler->AddDirectField(t); + } + } + } + } else if (mInfo->GetPass() == 1) { + if (mInfo->WithTypeParam(node)) { + mInfo->InsertWithTypeParamNode(node); + } + // sort fields + mInfo->SortFields(node); + } else if (mInfo->GetPass() == 2) { + // skip getting canonical type if not only fields + if (node->GetMethodsNum() || node->GetSuperInterfacesNum()) { + return node; + } + mInfo->GetCanonicStructNode(node); + } + return node; +} + +TypeParameterNode *ClassStructVisitor::VisitTypeParameterNode(TypeParameterNode *node) { + (void) AstVisitor::VisitTypeParameterNode(node); + if (mInfo->GetPass() == 0) { + TreeNode *id = node->GetId(); + if (id) { + unsigned stridx = id->GetStrIdx(); + mInfo->InsertTypeParamStrIdx(stridx); + node->SetStrIdx(stridx); + } + } + return node; +} + +FunctionNode *ClassStructVisitor::VisitFunctionNode(FunctionNode *node) { + (void) AstVisitor::VisitFunctionNode(node); + if (mInfo->GetPass() == 1) { + TreeNode *body = node->GetBody(); + if (body && mInfo->WithThis(body)) { + mInfo->InsertWithThisFunc(node); + } + } + return node; +} + +FunctionNode *FunctionVisitor::VisitFunctionNode(FunctionNode *node) { + FunctionTypeNode *functype = mHandler->NewTreeNode(); + TreeNode *n = NULL; + for (unsigned i = 0; i < node->GetParamsNum(); i++) { + n = node->GetParam(i); + functype->AddParam(n ? n->GetTypeIdx() : 0); + } + + // add return + n = node->GetRetType(); + functype->AddParam(n ? n->GetTypeIdx() : 0); + + unsigned tidx = gTypeTable.GetOrCreateFunctionTypeIdx(functype); + node->SetTypeIdx(tidx); + + return node; +} + +IdentifierNode *FindStrIdxVisitor::VisitIdentifierNode(IdentifierNode *node) { + (void) AstVisitor::VisitIdentifierNode(node); + if (node->GetStrIdx() == mStrIdx) { + mFound = true; + } + return node; +} + +LiteralNode *FindStrIdxVisitor::VisitLiteralNode(LiteralNode *node) { + (void) AstVisitor::VisitLiteralNode(node); + if (mCheckThis && node->IsThis()) { + mFound = true; + } + return node; +} + +} diff --git a/src/MapleFE/astopt/src/ast_scp.cpp b/src/MapleFE/astopt/src/ast_scp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fe472ccd5efd3289ee290da38b51789e456a4f01 --- /dev/null +++ b/src/MapleFE/astopt/src/ast_scp.cpp @@ -0,0 +1,911 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include "stringpool.h" +#include "astopt.h" +#include "ast_cfg.h" +#include "ast_scp.h" +#include "ast_xxport.h" +#include "typetable.h" + +namespace maplefe { + +void AST_SCP::ScopeAnalysis() { + MSGNOLOC0("============== ScopeAnalysis =============="); + BuildScope(); + RenameVar(); + AdjustASTWithScope(); +} + +void AST_SCP::BuildScope() { + MSGNOLOC0("============== BuildScope =============="); + BuildScopeVisitor visitor(mHandler, mFlags, true); + + // add all module themselves to the stridx to scope map + AST_Handler *asthandler = mHandler->GetASTHandler(); + for (int i = 0; i < asthandler->GetSize(); i++) { + Module_Handler *handler = asthandler->GetModuleHandler(i); + ModuleNode *module = handler->GetASTModule(); + ASTScope *scope = module->GetRootScope(); + module->SetScope(scope); + visitor.AddScopeMap(module->GetStrIdx(), scope); + } + + ModuleNode *module = mHandler->GetASTModule(); + ASTScope *scope = module->GetRootScope(); + + visitor.InitInternalTypes(); + + visitor.SetRunIt(true); + unsigned count = 0; + // run twice if necessary in case struct's scope is used before set + while (visitor.GetRunIt() && count < 2) { + visitor.SetRunIt(false); + while(!visitor.mScopeStack.empty()) { + visitor.mScopeStack.pop(); + } + visitor.mScopeStack.push(scope); + + while(!visitor.mUserScopeStack.empty()) { + visitor.mUserScopeStack.pop(); + } + visitor.mUserScopeStack.push(scope); + + visitor.Visit(module); + count++; + } + + if (mFlags & FLG_trace_3) { + gTypeTable.Dump(); + } +} + +void BuildScopeVisitor::AddDecl(ASTScope *scope, TreeNode *node) { + unsigned sid = scope->GetTree()->GetNodeId(); + if (mScope2DeclsMap[sid].find(node->GetNodeId()) == + mScope2DeclsMap[sid].end()) { + scope->AddDecl(node); + mScope2DeclsMap[sid].insert(node->GetNodeId()); + } +} + +void BuildScopeVisitor::AddImportedDecl(ASTScope *scope, TreeNode *node) { + unsigned sid = scope->GetTree()->GetNodeId(); + unsigned nid = node->GetNodeId(); + if (mScope2ImportedDeclsMap[sid].find(nid) == + mScope2ImportedDeclsMap[sid].end()) { + scope->AddImportDecl(node); + mScope2ImportedDeclsMap[sid].insert(nid); + mHandler->AddNodeId2DeclMap(nid, node); + } +} + +void BuildScopeVisitor::AddExportedDecl(ASTScope *scope, TreeNode *node) { + unsigned sid = scope->GetTree()->GetNodeId(); + unsigned nid = node->GetNodeId(); + if (mScope2ExportedDeclsMap[sid].find(nid) == + mScope2ExportedDeclsMap[sid].end()) { + scope->AddExportDecl(node); + mScope2ExportedDeclsMap[sid].insert(nid); + } +} + +void BuildScopeVisitor::AddType(ASTScope *scope, TreeNode *node) { + unsigned sid = scope->GetTree()->GetNodeId(); + if (mScope2TypesMap[sid].find(node->GetNodeId()) == + mScope2TypesMap[sid].end()) { + scope->AddType(node); + gTypeTable.AddType(node); + mScope2TypesMap[sid].insert(node->GetNodeId()); + } +} + +void BuildScopeVisitor::AddTypeAndDecl(ASTScope *scope, TreeNode *node) { + AddType(scope, node); + AddDecl(scope, node); +} + +void BuildScopeVisitor::InitInternalTypes() { + // add primitive and builtin types to root scope + ModuleNode *module = mHandler->GetASTModule(); + ASTScope *scope = module->GetRootScope(); + for (unsigned i = 1; i < gTypeTable.GetPreBuildSize(); i++) { + TreeNode *node = gTypeTable.GetTypeFromTypeIdx(i); + node->SetScope(scope); + if (node->IsUserType()) { + UserTypeNode *ut = static_cast(node); + TreeNode *id = ut->GetId(); + id->SetScope(scope); + AddType(scope, ut); + // id as a decl + AddDecl(scope, id); + } else { + AddType(scope, node); + } + } + + // add dummpy console.log() + unsigned size = gStringPool.GetSize(); + unsigned stridx = gStringPool.GetStrIdx("console"); + TreeNode *type = gTypeTable.GetTypeFromStrIdx(stridx); + if (!type) { + ClassNode *console = AddClass(stridx); + ASTScope *scp = NewScope(scope, console); + mStrIdx2ScopeMap[console->GetStrIdx()] = scp; + FunctionNode *log = AddFunction("log"); + log->SetTypeIdx(TY_Void); + console->AddMethod(log); + log->SetScope(scp); + AddDecl(scp, log); + } +} + +ClassNode *BuildScopeVisitor::AddClass(unsigned stridx, unsigned tyidx) { + ClassNode *node = mHandler->NewTreeNode(); + node->SetStrIdx(stridx); + node->SetTypeIdx(tyidx); + + ModuleNode *module = mHandler->GetASTModule(); + ASTScope *scope = module->GetRootScope(); + AddTypeAndDecl(scope, node); + return node; +} + +FunctionNode *BuildScopeVisitor::AddFunction(std::string name) { + FunctionNode *func = mHandler->NewTreeNode(); + unsigned idx = gStringPool.GetStrIdx(name); + func->SetStrIdx(idx); + + IdentifierNode *id = mHandler->NewTreeNode(); + id->SetStrIdx(idx); + func->SetFuncName(id); + + // add func to module scope + ModuleNode *module = mHandler->GetASTModule(); + ASTScope *scope = module->GetRootScope(); + AddDecl(scope, func); + id->SetScope(scope); + return func; +} + +ASTScope *BuildScopeVisitor::NewScope(ASTScope *parent, TreeNode *node) { + MASSERT(parent && "parent scope NULL"); + ASTScope *scope = node->GetScope(); + if (!scope || (scope && scope->GetTree() != node)) { + scope = mASTModule->NewScope(parent, node); + } + return scope; +} + +BlockNode *BuildScopeVisitor::VisitBlockNode(BlockNode *node) { + ASTScope *parent = mScopeStack.top(); + ASTScope *scope = NewScope(parent, node); + mScopeStack.push(scope); + BuildScopeBaseVisitor::VisitBlockNode(node); + mScopeStack.pop(); + return node; +} + +FunctionNode *BuildScopeVisitor::VisitFunctionNode(FunctionNode *node) { + ASTScope *parent = mScopeStack.top(); + // function is a decl + AddDecl(parent, node); + ASTScope *scope = NewScope(parent, node); + mScopeStack.push(scope); + mUserScopeStack.push(scope); + + // add parameters as decl + for(unsigned i = 0; i < node->GetParamsNum(); i++) { + TreeNode *it = node->GetParam(i); + AddDecl(scope, it); + + // added extra this is the parent with typeid TY_Class + if (it->GetStrIdx() == gStringPool.GetStrIdx("this") && it->GetTypeIdx() == 0) { + ASTScope *scp = scope; + while (scp && scp->GetTree()->GetTypeId() != TY_Class) { + scp = scp->GetParent(); + } + if (scp) { + it->SetTypeId(TY_Object); + it->SetTypeIdx(scp->GetTree()->GetTypeIdx()); + } + } + } + + for(unsigned i = 0; i < node->GetTypeParamsNum(); i++) { + TreeNode *it = node->GetTypeParamAtIndex(i); + + // add type parameter as decl + if (it->IsTypeParameter()) { + VisitTreeNode(it); + continue; + } + + // add it to scope's mTypes only if it is a new type + TreeNode *tn = it; + if (it->IsUserType()) { + UserTypeNode *ut = static_cast(it); + tn = ut->GetId(); + } + TreeNode *decl = NULL; + if (tn->IsIdentifier()) { + IdentifierNode *id = static_cast(tn); + // check if it is a known type + decl = scope->FindTypeOf(id->GetStrIdx()); + } + // add it if not found + if (!decl) { + AddType(scope, it); + } + } + BuildScopeBaseVisitor::VisitFunctionNode(node); + mUserScopeStack.pop(); + mScopeStack.pop(); + return node; +} + +LambdaNode *BuildScopeVisitor::VisitLambdaNode(LambdaNode *node) { + ASTScope *parent = mScopeStack.top(); + ASTScope *scope = NewScope(parent, node); + + // add parameters as decl + for(unsigned i = 0; i < node->GetParamsNum(); i++) { + TreeNode *it = node->GetParam(i); + AddDecl(scope, it); + } + mScopeStack.push(scope); + mUserScopeStack.push(scope); + BuildScopeBaseVisitor::VisitLambdaNode(node); + mUserScopeStack.pop(); + mScopeStack.pop(); + return node; +} + +ClassNode *BuildScopeVisitor::VisitClassNode(ClassNode *node) { + ASTScope *parent = mScopeStack.top(); + // inner class is a decl + if (parent) { + AddDecl(parent, node); + AddType(parent, node); + } + + ASTScope *scope = NewScope(parent, node); + if (node->GetStrIdx()) { + mStrIdx2ScopeMap[node->GetStrIdx()] = scope; + } + + // add fields as decl + for(unsigned i = 0; i < node->GetFieldsNum(); i++) { + TreeNode *fld = node->GetField(i); + if (fld->IsStrIndexSig()) { + StrIndexSigNode *sis = static_cast(fld); + TreeNode *key = sis->GetKey(); + if (key) { + AddDecl(scope, key); + } + } else if (fld->IsIdentifier()) { + AddDecl(scope, fld); + } else { + NOTYETIMPL("new type of class field"); + } + } + mScopeStack.push(scope); + BuildScopeBaseVisitor::VisitClassNode(node); + mScopeStack.pop(); + return node; +} + +InterfaceNode *BuildScopeVisitor::VisitInterfaceNode(InterfaceNode *node) { + ASTScope *parent = mScopeStack.top(); + // inner interface is a decl + if (parent) { + AddDecl(parent, node); + AddType(parent, node); + } + + ASTScope *scope = NewScope(parent, node); + if (node->GetStrIdx()) { + mStrIdx2ScopeMap[node->GetStrIdx()] = scope; + } + + // add fields as decl + for(unsigned i = 0; i < node->GetFieldsNum(); i++) { + TreeNode *fld = node->GetField(i); + if (fld->IsStrIndexSig()) { + continue; + } + if (fld->IsIdentifier()) { + AddDecl(scope, fld); + } + } + mScopeStack.push(scope); + BuildScopeBaseVisitor::VisitInterfaceNode(node); + mScopeStack.pop(); + return node; +} + +StructNode *BuildScopeVisitor::VisitStructNode(StructNode *node) { + ASTScope *parent = mScopeStack.top(); + // struct is a decl + if (parent) { + AddDecl(parent, node); + AddType(parent, node); + } + + ASTScope *scope = NewScope(parent, node); + mScopeStack.push(scope); + if (node->GetStructId() && node->GetStructId()->GetStrIdx()) { + mStrIdx2ScopeMap[node->GetStructId()->GetStrIdx()] = scope; + } + + // add fields as decl + for(unsigned i = 0; i < node->GetFieldsNum(); i++) { + TreeNode *fld = node->GetField(i); + if (fld->IsStrIndexSig()) { + continue; + } + if (fld && fld->IsIdentifier()) { + AddDecl(scope, fld); + } + } + + // add type parameter as decl + for(unsigned i = 0; i < node->GetTypeParamsNum(); i++) { + VisitTreeNode(node->GetTypeParamAtIndex(i)); + continue; + } + + // add string indexed field as decl + StrIndexSigNode *sig = node->GetStrIndexSig(); + if (sig) { + TreeNode *fld = sig->GetKey(); + sig->SetStrIdx(fld->GetStrIdx()); + if (fld && fld->IsIdentifier()) { + AddDecl(scope, fld); + } + } + + BuildScopeBaseVisitor::VisitStructNode(node); + mScopeStack.pop(); + return node; +} + +StructLiteralNode *BuildScopeVisitor::VisitStructLiteralNode(StructLiteralNode *node) { + ASTScope *parent = mScopeStack.top(); + + ASTScope *scope = NewScope(parent, node); + + // add fields as decl + for(unsigned i = 0; i < node->GetFieldsNum(); i++) { + FieldLiteralNode *fld = node->GetField(i); + TreeNode *name = fld->GetFieldName(); + if (name && name->IsIdentifier()) { + AddDecl(scope, name); + } + } + mScopeStack.push(scope); + BuildScopeBaseVisitor::VisitStructLiteralNode(node); + mScopeStack.pop(); + return node; +} + +NamespaceNode *BuildScopeVisitor::VisitNamespaceNode(NamespaceNode *node) { + node->SetTypeId(TY_Namespace); + TreeNode *id = node->GetId(); + unsigned stridx = 0; + if (id && id->GetStrIdx()) { + stridx = id->GetStrIdx(); + node->SetStrIdx(stridx); + } + + ASTScope *parent = mScopeStack.top(); + // inner namespace is a decl + if (parent) { + AddTypeAndDecl(parent, node); + } + + ASTScope *scope = NewScope(parent, node); + if (stridx != 0) { + mStrIdx2ScopeMap[stridx] = scope; + } + + mScopeStack.push(scope); + mUserScopeStack.push(scope); + BuildScopeBaseVisitor::VisitNamespaceNode(node); + mUserScopeStack.pop(); + mScopeStack.pop(); + return node; +} + +DeclNode *BuildScopeVisitor::VisitDeclNode(DeclNode *node) { + BuildScopeBaseVisitor::VisitDeclNode(node); + ASTScope *scope = NULL; + bool deep = true; + if (node->GetProp() == JS_Var) { + // promote to use function or module scope + scope = mUserScopeStack.top(); + + // update scope + node->SetScope(scope); + if (node->GetVar()) { + node->GetVar()->SetScope(scope); + } + } else { + scope = mScopeStack.top(); + // for body of function use function scope instead of body scope + TreeNode *b = node->GetParent(); + if (b && b->IsBlock()) { + TreeNode *f = b->GetParent(); + if (f && f->IsFunction()) { + scope = mUserScopeStack.top(); + } + } + // restrict to current scope + deep = false; + } + // check if it is already a decl in the scope + unsigned stridx = node->GetStrIdx(); + TreeNode *decl = scope->FindDeclOf(stridx, deep); + if (decl) { + if (decl != node) { + // replace with an assignment if apply + if (node->GetInit()) { + BinOperatorNode *bop = mHandler->NewTreeNode(); + bop->SetOprId(OPR_Assign); + IdentifierNode *id = mHandler->NewTreeNode(); + id->SetStrIdx(stridx); + id->SetScope(scope); + + bop->SetOpndA(id); + bop->SetOpndB(node->GetInit()); + node = (DeclNode *)bop; + } else { + node = NULL; + } + } + } else { + AddDecl(scope, node); + } + return node; +} + +UserTypeNode *BuildScopeVisitor::VisitUserTypeNode(UserTypeNode *node) { + BuildScopeBaseVisitor::VisitUserTypeNode(node); + ASTScope *scope = mScopeStack.top(); + TreeNode *p = node->GetParent(); + if (p) { + if (p->IsFunction()) { + // exclude function return type + FunctionNode *f = static_cast(p); + if (f->GetRetType() == node) { + return node; + } + } else if (p->IsTypeAlias()) { + // handled by typealias node + return node; + } + + if (p->IsScope()) { + // normal type decl + // check if it is already in typetable + TreeNode *id = node->GetId(); + if (id) { + TreeNode *decl = scope->FindTypeOf(id->GetStrIdx()); + if (!decl) { + AddType(scope, node); + } + } + } + } + return node; +} + +TypeAliasNode *BuildScopeVisitor::VisitTypeAliasNode(TypeAliasNode *node) { + ASTScope *scope = mScopeStack.top(); + BuildScopeBaseVisitor::VisitTypeAliasNode(node); + TreeNode *ut = node->GetId(); + if (ut->IsUserType()) { + TreeNode *id = static_cast(ut)->GetId(); + AddDecl(scope, id); + + // add to Alias type + mHandler->AddAliasType(id->GetNodeId()); + } + return node; +} + +ForLoopNode *BuildScopeVisitor::VisitForLoopNode(ForLoopNode *node) { + ASTScope *parent = mScopeStack.top(); + ASTScope *scope = parent; + if (node->GetProp() == FLP_JSIn) { + scope = NewScope(parent, node); + TreeNode *var = node->GetVariable(); + if (var) { + if (var->IsDecl()) { + AddDecl(scope, var); + } else { + NOTYETIMPL("VisitForLoopNode() FLP_JSIn var not decl"); + } + } + mScopeStack.push(scope); + } + + BuildScopeBaseVisitor::VisitForLoopNode(node); + + if (scope != parent) { + mScopeStack.pop(); + } + return node; +} + +FieldNode *BuildScopeVisitor::VisitFieldNode(FieldNode *node) { + BuildScopeBaseVisitor::VisitFieldNode(node); + + TreeNode *upper = node->GetUpper(); + TreeNode *field = node->GetField(); + + if (upper && upper->GetStrIdx()) { + ASTScope *scope = mStrIdx2ScopeMap[upper->GetStrIdx()]; + if (!scope && upper->IsIdentifier()) { + TreeNode *decl = mHandler->FindDecl(static_cast(upper)); + if (decl && decl->IsDecl()) { + decl = static_cast(decl)->GetVar(); + } + if (decl && decl->IsIdentifier()) { + IdentifierNode *id = static_cast(decl); + TreeNode *type = id->GetType(); + if (type && type->IsUserType()) { + TreeNode *id = static_cast(type)->GetId(); + if (id) { + scope = mStrIdx2ScopeMap[id->GetStrIdx()]; + } + } else if (id->GetParent() && id->GetParent()->IsXXportAsPair()) { + scope = id->GetScope(); + } + } + } + if (scope) { + mScopeStack.push(scope); + BuildScopeBaseVisitor::Visit(field); + mScopeStack.pop(); + } else { + mRunIt = true; + } + } + + return node; +} + +TypeParameterNode *BuildScopeVisitor::VisitTypeParameterNode(TypeParameterNode *node) { + BuildScopeBaseVisitor::VisitTypeParameterNode(node); + TreeNode *id = node->GetId(); + if (id && id->IsIdentifier()) { + ASTScope *scope = mScopeStack.top(); + id->SetScope(scope); + AddDecl(scope, id); + } + return node; +} + +ImportNode *BuildScopeVisitor::VisitImportNode(ImportNode *node) { + (void) AstVisitor::VisitImportNode(node); + ASTScope *scope = mScopeStack.top(); + + Module_Handler *targetHandler = NULL; + TreeNode *target = node->GetTarget(); + if (target) { + unsigned hstridx = target->GetStrIdx(); + unsigned hidx = mXXport->GetHandleIdxFromStrIdx(hstridx); + targetHandler = mHandler->GetASTHandler()->GetModuleHandler(hidx); + } + + for (unsigned i = 0; i < node->GetPairsNum(); i++) { + XXportAsPairNode *p = node->GetPair(i); + TreeNode *bfnode = p->GetBefore(); + TreeNode *afnode = p->GetAfter(); + if (p->IsDefault()) { + if (bfnode) { + bfnode->SetScope(scope); + AddImportedDecl(scope, bfnode); + } + } else if (p->IsEverything()) { + if (bfnode) { + AddImportedDecl(scope, bfnode); + // imported scope + scope = targetHandler->GetASTModule()->GetScope(); + bfnode->SetScope(scope); + } + } else if (afnode) { + afnode->SetScope(scope); + AddImportedDecl(scope, afnode); + + if (bfnode && targetHandler) { + ModuleNode *mod = targetHandler->GetASTModule(); + ASTScope *modscp = mod->GetScope(); + bfnode->SetScope(modscp); + } + } else if (bfnode) { + bfnode->SetScope(scope); + AddImportedDecl(scope, bfnode); + } + } + + return node; +} + +ExportNode *BuildScopeVisitor::VisitExportNode(ExportNode *node) { + (void) AstVisitor::VisitExportNode(node); + ASTScope *scope = mScopeStack.top(); + + Module_Handler *targetHandler = NULL; + TreeNode *target = node->GetTarget(); + // re-export + if (target) { + unsigned hstridx = target->GetStrIdx(); + unsigned hidx = mXXport->GetHandleIdxFromStrIdx(hstridx); + targetHandler = mHandler->GetASTHandler()->GetModuleHandler(hidx); + } + + for (unsigned i = 0; i < node->GetPairsNum(); i++) { + XXportAsPairNode *p = node->GetPair(i); + TreeNode *bfnode = p->GetBefore(); + TreeNode *afnode = p->GetAfter(); + if (targetHandler) { + ModuleNode *mod = targetHandler->GetASTModule(); + ASTScope *modscp = mod->GetScope(); + + if (bfnode) { + bfnode->SetScope(modscp); + // reexported bfnode is treated as a decl, add directly into map + if (bfnode->IsIdentifier()) { + mHandler->AddNodeId2DeclMap(bfnode->GetNodeId(), bfnode); + } + } else if (!afnode) { + // reexport everything + for (unsigned j = 0; j < modscp->GetExportedDeclNum(); j++) { + AddExportedDecl(scope, modscp->GetExportedDecl(j)); + } + } + } else { + if (!p->IsDefault() && bfnode && !afnode) { + AddExportedDecl(scope, bfnode); + } + } + + if (afnode && afnode->IsIdentifier()) { + // exported afnode is treated as a decl, add directly into map + mHandler->AddNodeId2DeclMap(afnode->GetNodeId(), afnode); + AddExportedDecl(scope, afnode); + } + } + + return node; +} + +TryNode *BuildScopeVisitor::VisitTryNode(TryNode *node) { + ASTScope *parent = mScopeStack.top(); + ASTScope *scope = NewScope(parent, node); + mScopeStack.push(scope); + BuildScopeBaseVisitor::VisitTryNode(node); + mScopeStack.pop(); + return node; +} + +CatchNode *BuildScopeVisitor::VisitCatchNode(CatchNode *node) { + ASTScope *parent = mScopeStack.top(); + ASTScope *scope = NewScope(parent, node); + + // add params as decl + for (unsigned i = 0; i < node->GetParamsNum(); i++) { + TreeNode *n = node->GetParamAtIndex(i); + AddDecl(scope, n); + } + + mScopeStack.push(scope); + BuildScopeBaseVisitor::VisitCatchNode(node); + mScopeStack.pop(); + return node; +} + +FinallyNode *BuildScopeVisitor::VisitFinallyNode(FinallyNode *node) { + ASTScope *parent = mScopeStack.top(); + ASTScope *scope = NewScope(parent, node); + mScopeStack.push(scope); + BuildScopeBaseVisitor::VisitFinallyNode(node); + mScopeStack.pop(); + return node; +} + +// rename var with same name, i --> i__vN where N is 1, 2, 3 ... +void AST_SCP::RenameVar() { + MSGNOLOC0("============== RenameVar =============="); + RenameVarVisitor visitor(mHandler, mFlags, true); + ModuleNode *module = mHandler->GetASTModule(); + visitor.mPass = 0; + visitor.Visit(module); + + visitor.mPass = 1; + for (auto it: visitor.mStridx2DeclIdMap) { + unsigned stridx = it.first; + unsigned size = it.second.size(); + if (size > 1) { + const char *name = gStringPool.GetStringFromStrIdx(stridx); + + if (mFlags & FLG_trace_3) { + std::cout << "\nstridx: " << stridx << " " << name << std::endl; + std::cout << "decl nid : "; + for (auto i : visitor.mStridx2DeclIdMap[stridx]) { + std::cout << " " << i; + } + std::cout << std::endl; + } + + // variable renaming is in reverse order starting from smaller scope variables + std::deque::reverse_iterator rit = visitor.mStridx2DeclIdMap[stridx].rbegin(); + size--; + for (; size && rit!= visitor.mStridx2DeclIdMap[stridx].rend(); --size, ++rit) { + unsigned nid = *rit; + std::string str(name); + str += "__v"; + str += std::to_string(size); + visitor.mOldStrIdx = stridx; + visitor.mNewStrIdx = gStringPool.GetStrIdx(str); + gStringPool.AddAltStrIdx(visitor.mNewStrIdx); + TreeNode *tn = mHandler->GetAstOpt()->GetNodeFromNodeId(nid); + ASTScope *scope = tn->GetScope(); + tn = scope->GetTree(); + if (mFlags & FLG_trace_3) { + std::cout << "\nupdate name : " + << gStringPool.GetStringFromStrIdx(visitor.mOldStrIdx) + << " --> " + << gStringPool.GetStringFromStrIdx(visitor.mNewStrIdx) + << std::endl; + } + visitor.Visit(tn); + } + } + } +} + +// fields are not renamed +bool RenameVarVisitor::SkipRename(IdentifierNode *node) { + TreeNode *parent = node->GetParent(); + if (parent) { + switch (parent->GetKind()) { + case NK_Struct: + case NK_Class: + case NK_Interface: + return true; + case NK_Field: { + FieldNode *f = static_cast(parent); + // skip for mField + return node == f->GetField();; + } + default: + return false; + } + } + return true; +} + +// check if node is of same name as a parameter of func +bool RenameVarVisitor::IsFuncArg(FunctionNode *func, IdentifierNode *node) { + for (unsigned i = 0; i < func->GetParamsNum(); i++) { + if (func->GetParam(i)->GetStrIdx() == node->GetStrIdx()) { + return true; + } + } + return false; +} + +// insert decl in lattice order of scopes hierachy to ensure proper name versions. +// +// the entries of node id in mStridx2DeclIdMap are inserted to a list from larger scopes to smaller scopes +// later variable renaming is performed in reverse from bottom up of AST within the scope of the variable +// +void RenameVarVisitor::InsertToStridx2DeclIdMap(unsigned stridx, IdentifierNode *node) { + ASTScope *s0 = node->GetScope(); + std::deque::iterator it; + unsigned i = 0; + for (it = mStridx2DeclIdMap[stridx].begin(); it != mStridx2DeclIdMap[stridx].end(); ++it) { + i = *it; + TreeNode *node1 = mHandler->GetAstOpt()->GetNodeFromNodeId(i); + ASTScope *s1 = node1->GetScope(); + // decl at same scope already exist + if (s1 == s0) { + return; + } + // do not insert node after node1 if node's scope s0 is an ancestor of node1's scope s1 + if (s1->IsAncestor(s0)) { + mStridx2DeclIdMap[stridx].insert(it, node->GetNodeId()); + return; + } + } + mStridx2DeclIdMap[stridx].push_back(node->GetNodeId()); +} + +IdentifierNode *RenameVarVisitor::VisitIdentifierNode(IdentifierNode *node) { + AstVisitor::VisitIdentifierNode(node); + // fields are not renamed + if (SkipRename(node)) { + return node; + } + if (mPass == 0) { + unsigned stridx = node->GetStrIdx(); + if (stridx) { + TreeNode *parent = node->GetParent(); + if (parent) { + // insert in order according to scopes hierachy to ensure proper name version + if ((parent->IsDecl() && parent->GetStrIdx() == stridx)) { + // decl + InsertToStridx2DeclIdMap(stridx, node); + } else if (parent->IsFunction() && IsFuncArg(static_cast(parent), node)) { + // func parameters + InsertToStridx2DeclIdMap(stridx, node); + } + } + } else { + NOTYETIMPL("Unexpected - decl without name stridx"); + } + } else if (mPass == 1) { + if (node->GetStrIdx() == mOldStrIdx) { + node->SetStrIdx(mNewStrIdx); + MSGNOLOC0(" name updated"); + TreeNode *parent = node->GetParent(); + if (parent && parent->IsDecl()) { + parent->SetStrIdx(mNewStrIdx); + } + } + } + return node; +} + +void AST_SCP::AdjustASTWithScope() { + MSGNOLOC0("============== AdjustASTWithScope =============="); + AdjustASTWithScopeVisitor visitor(mHandler, mFlags, true); + ModuleNode *module = mHandler->GetASTModule(); + visitor.Visit(module); +} + +IdentifierNode *AdjustASTWithScopeVisitor::VisitIdentifierNode(IdentifierNode *node) { + TreeNode *decl = mHandler->FindDecl(node); + if (!decl) { + LitData data; + bool change = false; + // handle literals true false + unsigned stridx = node->GetStrIdx(); + if (stridx == gStringPool.GetStrIdx("true")) { + data.mType = LT_BooleanLiteral; + data.mData.mBool = true; + change = true; + } else if (stridx == gStringPool.GetStrIdx("false")) { + data.mType = LT_BooleanLiteral; + data.mData.mBool = false; + change = true; + } + + if (change) { + LiteralNode *lit = mHandler->NewTreeNode(); + lit->SetData(data); + return (IdentifierNode*)(lit); + } + } + return node; +} + +} diff --git a/src/MapleFE/astopt/src/ast_ti.cpp b/src/MapleFE/astopt/src/ast_ti.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99439b59de694b757e30393cd8db4d3a3456d115 --- /dev/null +++ b/src/MapleFE/astopt/src/ast_ti.cpp @@ -0,0 +1,2042 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include "ast_handler.h" +#include "ast_info.h" +#include "ast_util.h" +#include "ast_xxport.h" +#include "ast_ti.h" +#include "typetable.h" +#include "gen_astdump.h" + +#define ITERATEMAX 10 + +namespace maplefe { + +void TypeInfer::TypeInference() { + ModuleNode *module = mHandler->GetASTModule(); + + if (mFlags & FLG_trace_3) { + gStringPool.Dump(); + gTypeTable.Dump(); + } + + // build mNodeId2Decl + MSGNOLOC0("============== Build NodeId2Decl =============="); + BuildIdNodeToDeclVisitor visitor_build(mHandler, mFlags, true); + visitor_build.Visit(module); + + // type inference + MSGNOLOC0("============== TypeInfer =============="); + TypeInferVisitor visitor_ti(mHandler, mFlags, true); + visitor_ti.SetUpdated(true); + int count = 0; + while (visitor_ti.GetUpdated() && count++ <= ITERATEMAX) { + MSGNOLOC("\n TypeInference iterate ", count); + visitor_ti.SetUpdated(false); + visitor_ti.Visit(module); + } + + // build mDirectFieldSet + MSGNOLOC0("============== Build DirectFieldSet =============="); + BuildIdDirectFieldVisitor visitor_field(mHandler, mFlags, true); + visitor_field.Visit(module); + if (mFlags & FLG_trace_3) { + visitor_field.Dump(); + } + + if (mFlags & FLG_trace_3) std::cout << "\n>>>>>> TypeInference() iterated " << count << " times\n" << std::endl; + + // share UserType + MSGNOLOC0("============== Share UserType =============="); + ShareUTVisitor visitor_ut(mHandler, mFlags, true); + visitor_ut.Push(module->GetRootScope()); + visitor_ut.Visit(module); + + // Check Type + MSGNOLOC0("============== Check Type =============="); + CheckTypeVisitor visitor_check(mHandler, mFlags, true); + visitor_check.Visit(module); + + if (mFlags & FLG_trace_3) { + mHandler->DumpArrayElemTypeIdMap(); + } +} + +// build up mNodeId2Decl by visiting each Identifier +IdentifierNode *BuildIdNodeToDeclVisitor::VisitIdentifierNode(IdentifierNode *node) { + if (mHandler->GetAstOpt()->IsLangKeyword(node)) { + return node; + } + (void) AstVisitor::VisitIdentifierNode(node); + // mHandler->FindDecl() will use/add entries to mNodeId2Decl + TreeNode *decl = mHandler->FindDecl(node); + if (decl && decl != node) { + mHandler->GetUtil()->SetTypeId(node, decl->GetTypeId()); + mHandler->GetUtil()->SetTypeIdx(node, decl->GetTypeIdx()); + } + TreeNode *type = node->GetType(); + if (type && type->IsPrimType()) { + PrimTypeNode *ptn = static_cast(type); + TypeId tid = ptn->GetPrimType(); + if (gTypeTable.IsPrimTypeId(tid)) { + // mHandler->GetUtil()->SetTypeId(node, tid); + mHandler->GetUtil()->SetTypeIdx(node, tid); + } + } + return node; +} + +FieldNode *BuildIdDirectFieldVisitor::VisitFieldNode(FieldNode *node) { + (void) AstVisitor::VisitFieldNode(node); + IdentifierNode *field = static_cast(node->GetField()); + TreeNode *decl = NULL; + decl = mHandler->FindDecl(field); + if (decl) { + mHandler->AddDirectField(field); + mHandler->AddDirectField(node); + } + return node; +} + +TreeNode *BuildIdDirectFieldVisitor::GetParentVarClass(TreeNode *node) { + TreeNode *n = node; + while (n && !n->IsModule()) { + unsigned tyidx = 0; + if (n->IsDecl()) { + tyidx = n->GetTypeIdx(); + } else if (n->IsBinOperator()) { + tyidx = n->GetTypeIdx(); + } + if (tyidx) { + return gTypeTable.GetTypeFromTypeIdx(tyidx); + } + n = n->GetParent(); + } + return NULL; +} + +FieldLiteralNode *BuildIdDirectFieldVisitor::VisitFieldLiteralNode(FieldLiteralNode *node) { + (void) AstVisitor::VisitFieldLiteralNode(node); + TreeNode *name = node->GetFieldName(); + IdentifierNode *field = static_cast(name); + TreeNode *decl = mHandler->FindDecl(field); + TreeNode *vtype = GetParentVarClass(decl); + if (vtype && !mHandler->GetINFO()->IsBuiltInType(vtype)) { + // check if decl is a field of vtype + // note: vtype could be in different module + Module_Handler *h = mHandler->GetModuleHandler(vtype); + TreeNode *fld = h->GetINFO()->GetField(vtype->GetNodeId(), decl->GetStrIdx()); + if (fld) { + mHandler->AddDirectField(field); + mHandler->AddDirectField(node); + } + } + return node; +} + +ArrayElementNode *BuildIdDirectFieldVisitor::VisitArrayElementNode(ArrayElementNode *node) { + (void) AstVisitor::VisitArrayElementNode(node); + TreeNode *array = node->GetArray(); + if (!array || !array->IsIdentifier()) { + return node; + } + + TreeNode *decl = mHandler->FindDecl(static_cast(array)); + if (decl && decl->IsTypeIdClass()) { + // indexed access of types + TreeNode *exp = node->GetExprAtIndex(0); + unsigned stridx = exp->GetStrIdx(); + if (exp->IsLiteral() && exp->IsTypeIdString()) { + stridx = (static_cast(exp))->GetData().mData.mStrIdx; + } + if (decl->IsDecl()) { + TreeNode *var = static_cast(decl)->GetVar(); + TreeNode * type = static_cast(var)->GetType(); + if (type && type->IsUserType()) { + UserTypeNode *ut = static_cast(type); + decl = mHandler->FindDecl(static_cast(ut->GetId())); + } + } + if (decl->IsStruct() || decl->IsClass()) { + for (int i = 0; i < mHandler->GetINFO()->GetFieldsSize(decl); i++) { + TreeNode *f = mHandler->GetINFO()->GetField(decl, i); + if (f->GetStrIdx() == stridx) { + mHandler->AddDirectField(exp); + mHandler->AddDirectField(node); + return node; + } + } + } + } + return node; +} + +void BuildIdDirectFieldVisitor::Dump() { + MSGNOLOC0("============== Direct Field NodeIds =============="); + for (auto i: mHandler->mDirectFieldSet) { + std::cout << " " << i; + } + std::cout << std::endl; +} + +#undef TYPE +#undef PRIMTYPE +#define TYPE(T) +#define PRIMTYPE(T) case TY_##T: +bool TypeInferVisitor::IsPrimTypeId(TypeId tid) { + bool result = false; + switch (tid) { +#include "supported_types.def" + result = true; + break; + default: + break; + } + return result; +} + +TypeId TypeInferVisitor::MergeTypeId(TypeId tia, TypeId tib) { + if (tia == tib || tib == TY_None) { + return tia; + } + + if (tib == TY_Object || tib == TY_User) { + return tib; + } + + if ((tia == TY_Function && tib == TY_Class) || (tib == TY_Function && tia == TY_Class)) { + return TY_None; + } + + // tia != tib && tib != TY_None + TypeId result = TY_None; + switch (tia) { + case TY_None: result = tib; break; + + case TY_Class: + case TY_Object: + case TY_User: result = tia; break; + + case TY_Merge: + case TY_Undefined: + case TY_String: + case TY_Function: + case TY_Array: result = TY_Merge; break; + + case TY_Number: { + switch (tib) { + case TY_Int: + case TY_Long: + case TY_Float: + case TY_Double: result = tib; break; + default: result = TY_Merge; break; + } + break; + } + + case TY_Boolean: { + switch (tib) { + case TY_Int: + case TY_Long: + case TY_Float: + case TY_Double: result = tib; break; + case TY_Number: result = tia; break; + default: result = TY_Merge; break; + } + break; + } + case TY_Int: { + switch (tib) { + case TY_Number: + case TY_Boolean: result = tia; break; + case TY_Long: + case TY_Float: + case TY_Double: result = tib; break; + default: result = TY_Merge; break; + } + break; + } + case TY_Long: { + switch (tib) { + case TY_Number: + case TY_Boolean: + case TY_Int: result = tia; break; + case TY_Float: + case TY_Double: result = TY_Double; break; + default: result = TY_Merge; break; + } + break; + } + case TY_Float: { + switch (tib) { + case TY_Number: + case TY_Boolean: + case TY_Int: result = tia; break; + case TY_Long: + case TY_Double: result = TY_Double; break; + default: result = TY_Merge; break; + } + break; + } + case TY_Double: { + switch (tib) { + case TY_Number: + case TY_Boolean: + case TY_Int: + case TY_Long: + case TY_Double: result = tia; break; + default: result = TY_Merge; break; + } + break; + } + default: + break; + } + if (result == TY_None) { + NOTYETIMPL("MergeTypeId()"); + } + if (mFlags & FLG_trace_3) { + std::cout << " Type Merge: " + << AstDump::GetEnumTypeId(tia) << " " + << AstDump::GetEnumTypeId(tib) << " --> " + << AstDump::GetEnumTypeId(result) << std::endl; + } + return result; +} + +unsigned TypeInferVisitor::MergeTypeIdx(unsigned tia, unsigned tib) { + if (tia == tib || tib <= 1) { + return tia; + } + + if (tia <= 1) { + return tib; + } + + unsigned result = 0; + + TreeNode *ta = gTypeTable.GetTypeFromTypeIdx(tia); + TreeNode *tb = gTypeTable.GetTypeFromTypeIdx(tib); + if (ta->IsPrimType() && tb->IsPrimType()) { + TypeId tid = MergeTypeId(ta->GetTypeId(), tb->GetTypeId()); + result = (unsigned)tid; + } else { + TreeNode *type = gTypeTable.GetTypeFromTypeId(TY_Merge); + result = type->GetTypeIdx(); + } + + if (mFlags & FLG_trace_3) { + std::cout << " Type idx Merge: " + << tia << " " + << tib << " --> " + << result << std::endl; + } + return result; +} + +void TypeInferVisitor::SetTypeId(TreeNode *node, TypeId tid) { + TypeId id = node->GetTypeId(); + mHandler->GetUtil()->SetTypeId(node, tid); + if (tid != id) { + id = node->GetTypeId(); + if (IsPrimTypeIdx(id) && node->GetTypeIdx() == 0) { + SetTypeIdx(node, id); + } + SetUpdated(); + } +} + +void TypeInferVisitor::SetTypeIdx(TreeNode *node, unsigned tidx) { + mHandler->GetUtil()->SetTypeIdx(node, tidx); + if (node && node->GetTypeIdx() != tidx) { + SetUpdated(); + } +} + +void TypeInferVisitor::SetTypeId(TreeNode *node1, TreeNode *node2) { + SetTypeId(node1, node2->GetTypeId()); + SetTypeIdx(node1, node2->GetTypeIdx()); +} + +void TypeInferVisitor::SetTypeIdx(TreeNode *node1, TreeNode *node2) { + SetTypeIdx(node1, node2->GetTypeIdx()); +} + +void TypeInferVisitor::UpdateTypeId(TreeNode *node, TypeId tid) { + if (tid == TY_None || !node || node->IsLiteral()) { + return; + } + tid = MergeTypeId(node->GetTypeId(), tid); + SetTypeId(node, tid); +} + +void TypeInferVisitor::UpdateTypeId(TreeNode *node1, TreeNode *node2) { + if (!node1 || !node2 || node1 == node2) { + return; + } + TypeId tid = MergeTypeId(node1->GetTypeId(), node2->GetTypeId()); + if (!node1->IsLiteral()) { + SetTypeId(node1, tid); + } + if (!node2->IsLiteral()) { + SetTypeId(node2, tid); + } + + // update type idx as well + UpdateTypeIdx(node1, node2); +} + +void TypeInferVisitor::UpdateTypeIdx(TreeNode *node, unsigned tidx) { + if (tidx == 0 || !node || node->IsLiteral()) { + return; + } + tidx = MergeTypeIdx(node->GetTypeIdx(), tidx); + SetTypeIdx(node, tidx); +} + +void TypeInferVisitor::UpdateTypeIdx(TreeNode *node1, TreeNode *node2) { + if (!node1 || !node2 || node1 == node2) { + return; + } + unsigned tidx = MergeTypeIdx(node1->GetTypeIdx(), node2->GetTypeIdx()); + if (tidx != 0) { + SetTypeIdx(node1, tidx); + SetTypeIdx(node2, tidx); + } +} + +PrimTypeNode *TypeInferVisitor::GetOrClonePrimTypeNode(PrimTypeNode *pt, TypeId tid) { + PrimTypeNode *new_pt = pt; + TypeId oldtid = pt->GetTypeId(); + // merge tids + tid = MergeTypeId(oldtid, tid); + // check if we need update + if (tid != oldtid) { + // check if we need clone PrimTypeNode to avoid using the shared one + if (oldtid == TY_None) { + new_pt = mHandler->NewTreeNode(); + new_pt->SetPrimType(pt->GetPrimType()); + } + SetTypeId(new_pt, tid); + if (IsPrimTypeId(tid)) { + SetTypeIdx(new_pt, tid); + } else { + SetTypeIdx(new_pt, gTypeTable.GetTypeFromTypeId(tid)->GetTypeIdx()); + } + SetUpdated(); + } + return new_pt; +} + +bool static IsScalar(TypeId tid) { + switch (tid) { + case TY_None: + case TY_Int: + case TY_Long: + case TY_Float: + case TY_Double: + return true; + default: + return false; + } + return false; +} + +// when function arry type parameter is updated, need update all +// caller arguments to be consistent with the array type parameter +void TypeInferVisitor::UpdateArgArrayDecls(unsigned nid, TypeId tid) { + for (auto id: mParam2ArgArrayDeclMap[nid]) { + mHandler->SetArrayElemTypeId(nid, tid); + if (id && id->IsDecl()) { + id = static_cast(id)->GetVar(); + } + if (id && id->IsIdentifier()) { + IdentifierNode *inode = static_cast(id); + TreeNode *type = inode->GetType(); + if (type && type->IsPrimArrayType()) { + PrimArrayTypeNode *pat = static_cast(type); + SetTypeId(pat->GetPrim(), tid); + SetUpdated(); + } + } + } +} + +// use input node's type info to update target node's type info +void TypeInferVisitor::UpdateTypeUseNode(TreeNode *target, TreeNode *input) { + // this functionality is reserved for typescript + if (!mHandler->IsTS()) { + return; + } + TypeId tid = target->GetTypeId(); + TypeId iid = input->GetTypeId(); + if ((tid == iid && IsScalar(tid)) || (iid == TY_Array && tid != iid)) { + return; + } + switch (iid) { + case TY_None: + break; + case TY_Array: { + // function's formals with corresponding calls' parameters passed in + if (input->IsIdentifier()) { + TreeNode *decl = mHandler->FindDecl(static_cast(input)); + TypeId old_elemTypeId = GetArrayElemTypeId(target); + unsigned old_elemTypeIdx = GetArrayElemTypeIdx(target); + TypeId inid = GetArrayElemTypeId(decl); + unsigned inidx = GetArrayElemTypeIdx(decl); + if (old_elemTypeId != inid || old_elemTypeIdx != inidx) { + UpdateArrayElemTypeMap(target, inid, inidx); + } + TypeId new_elemTypeId = GetArrayElemTypeId(target); + TreeNode *type = static_cast(target)->GetType(); + MASSERT(target->IsIdentifier() && "target node not identifier"); + if (type && type->IsPrimArrayType()) { + unsigned nid = target->GetNodeId(); + mParam2ArgArrayDeclMap[nid].insert(decl); + if (old_elemTypeId != new_elemTypeId) { + PrimArrayTypeNode *pat = static_cast(type); + PrimTypeNode *pt = pat->GetPrim(); + PrimTypeNode *new_pt = GetOrClonePrimTypeNode(pt, new_elemTypeId); + pat->SetPrim(new_pt); + SetUpdated(); + + UpdateArgArrayDecls(nid, new_elemTypeId); + } + } + } + // function's return type with return statement + else if (input->IsArrayLiteral()) { + TypeId old_elemTypeId = GetArrayElemTypeId(target); + unsigned old_elemTypeIdx = GetArrayElemTypeIdx(target); + TypeId inid = GetArrayElemTypeId(input); + unsigned inidx = GetArrayElemTypeIdx(input); + if (old_elemTypeId != inid || old_elemTypeIdx != inidx) { + UpdateArrayElemTypeMap(target, inid, inidx); + } + TypeId new_elemTypeId = GetArrayElemTypeId(target); + if (target->IsPrimArrayType()) { + unsigned nid = target->GetNodeId(); + if (old_elemTypeId != new_elemTypeId) { + PrimArrayTypeNode *pat = static_cast(target); + PrimTypeNode *pt = pat->GetPrim(); + PrimTypeNode *new_pt = GetOrClonePrimTypeNode(pt, new_elemTypeId); + pat->SetPrim(new_pt); + SetUpdated(); + + UpdateArgArrayDecls(nid, new_elemTypeId); + } + } + } else { + NOTYETIMPL("parameter not identifier"); + } + break; + } + case TY_Int: + case TY_Long: + case TY_Float: + case TY_Double: + case TY_String: + case TY_Class: + case TY_Object: + case TY_Function: { + TypeId merged = MergeTypeId(tid, iid); + if (merged != tid && merged != TY_None) { + SetTypeId(target, merged); + SetUpdated(); + } + break; + } + case TY_User: + break; + default: + NOTYETIMPL("TypeId not handled"); + break; + } + return; +} + +void TypeInferVisitor::UpdateFuncRetTypeId(FunctionNode *node, TypeId tid, unsigned tidx) { + if (!node || (node->GetTypeId() == tid && node->GetTypeIdx() == tidx)) { + return; + } + TreeNode *type = node->GetRetType(); + // create new return type node if it was shared + + if (type) { + if (type->IsPrimType() && type->IsTypeIdNone()) { + type = GetOrClonePrimTypeNode((PrimTypeNode *)type, tid); + node->SetRetType(type); + } + tid = MergeTypeId(type->GetTypeId(), tid); + SetTypeId(type, tid); + tidx = MergeTypeIdx(type->GetTypeIdx(), tidx); + SetTypeIdx(type, tidx); + } +} + +TypeId TypeInferVisitor::GetArrayElemTypeId(TreeNode *node) { + unsigned nid = node->GetNodeId(); + return mHandler->GetArrayElemTypeId(nid); +} + +unsigned TypeInferVisitor::GetArrayElemTypeIdx(TreeNode *node) { + unsigned nid = node->GetNodeId(); + return mHandler->GetArrayElemTypeIdx(nid); +} + +void TypeInferVisitor::UpdateArrayElemTypeMap(TreeNode *node, TypeId tid, unsigned tidx) { + if (!node || tid == TY_None || !IsArray(node)) { + return; + } + unsigned nodeid = node->GetNodeId(); + TypeId currtid = mHandler->GetArrayElemTypeId(nodeid); + tid = MergeTypeId(tid, currtid); + + unsigned currtidx = mHandler->GetArrayElemTypeIdx(nodeid); + tidx = MergeTypeIdx(tidx, currtidx); + + if (currtid != tid || currtidx != tidx) { + mHandler->SetArrayElemTypeId(node->GetNodeId(), tid); + mHandler->SetArrayElemTypeIdx(node->GetNodeId(), tidx); + SetUpdated(); + + // update array's PrimType node with a new node + if (node->IsDecl()) { + DeclNode *decl = static_cast(node); + node = decl->GetVar(); + } + if (node->IsIdentifier()) { + IdentifierNode *in = static_cast(node); + node = in->GetType(); + } + + if (node->IsPrimArrayType()) { + PrimArrayTypeNode *pat = static_cast(node); + PrimTypeNode *pt = pat->GetPrim(); + PrimTypeNode *new_pt = GetOrClonePrimTypeNode(pt, tid); + pat->SetPrim(new_pt); + } + } +} + +void TypeInferVisitor::UpdateArrayDimMap(TreeNode *node, DimensionNode *dim) { + mHandler->SetArrayDim(node->GetNodeId(), dim); +} + +// return true if identifier is constructor +bool TypeInferVisitor::UpdateVarTypeWithInit(TreeNode *var, TreeNode *init) { + bool result = var->IsFunction(); + if (!var->IsIdentifier()) { + return result; + } + IdentifierNode *idnode = static_cast(var); + TreeNode *type = idnode->GetType(); + // use init NewNode to set decl type + if (init) { + if (init->IsNew()) { + NewNode *n = static_cast(init); + if (n->GetId()) { + TreeNode *id = n->GetId(); + if (id->IsIdentifier() && id->IsTypeIdClass()) { + UserTypeNode *utype = mInfo->CreateUserTypeNode(id->GetStrIdx(), var->GetScope()); + utype->SetParent(idnode); + idnode->SetType(utype); + SetUpdated(); + } + } + } else if (init->IsIdentifier()) { + TreeNode *decl = mHandler->FindDecl(static_cast(init)); + if (decl) { + unsigned tidx = decl->GetTypeIdx(); + if ((decl->IsClass() || (0 < tidx && tidx < (unsigned)TY_Max))) { + SetTypeId(idnode, TY_Function); + SetUpdated(); + result = true; + } + } + } else if (init->IsStructLiteral()) { + if (!type && init->GetTypeIdx() != 0) { + type = gTypeTable.GetTypeFromTypeIdx(init->GetTypeIdx()); + UserTypeNode *utype = mInfo->CreateUserTypeNode(type->GetStrIdx(), var->GetScope()); + utype->SetParent(idnode); + idnode->SetType(utype); + SetUpdated(); + } + } else if (init->IsArrayLiteral()) { + TypeId tid = GetArrayElemTypeId(init); + unsigned tidx = GetArrayElemTypeIdx(init); + if (type) { + if (type->IsArrayType()) { + ArrayTypeNode *pat = static_cast(type); + // update array element type + SetTypeId(pat->GetElemType(), tid); + SetTypeIdx(pat->GetElemType(), tidx); + SetUpdated(); + } else { + NOTYETIMPL("array type not ArrayTypeNode"); + } + return result; + } + + TreeNode *elemtype = NULL; + if (IsPrimTypeId(tid)) { + elemtype = gTypeTable.GetTypeFromTypeId(tid); + } else if (tidx != 0) { + elemtype = gTypeTable.GetTypeFromTypeIdx(tidx); + } + if (elemtype) { + ArrayTypeNode *pat = mHandler->NewTreeNode(); + pat->SetElemType(elemtype); + + DimensionNode *dims = mHandler->GetArrayDim(init->GetNodeId()); + pat->SetDims(dims); + + pat->SetParent(idnode); + idnode->SetType(pat); + SetUpdated(); + } + } + } + return result; +} + +bool TypeInferVisitor::IsArray(TreeNode *node) { + if (!node) { + return false; + } + if (node->IsArrayLiteral() || node->IsPrimArrayType()) { + return true; + } + TreeNode *tn = node; + if (node->IsDecl()) { + DeclNode *decl = static_cast(node); + tn = decl->GetVar(); + } + if (tn->IsIdentifier()) { + IdentifierNode *idnode = static_cast(tn); + if (idnode && idnode->GetType() && idnode->GetType()->IsPrimArrayType()) { + return true; + } + } else if (tn->IsBindingPattern()) { + // could be either object or array destructuring + return false; + } else { + NOTYETIMPL("array not identifier or bind pattern"); + } + return false; +} + +TreeNode *TypeInferVisitor::VisitClassField(TreeNode *node) { + (void) AstVisitor::VisitTreeNode(node); + if (node->IsIdentifier()) { + IdentifierNode *idnode = static_cast(node); + TreeNode *type = idnode->GetType(); + if (type) { + TypeId tid = type->GetTypeId(); + if (type->IsPrimType()) { + PrimTypeNode *ptn = static_cast(type); + tid = ptn->GetPrimType(); + } + // use non TY_Number + if (tid != TY_Number) { + SetTypeId(node, tid); + } + } + TreeNode *init = idnode->GetInit(); + if (init) { + VisitTreeNode(init); + UpdateTypeId(node, init->GetTypeId()); + } + } else if (node->IsLiteral()) { + MSGNOLOC0("field is Literal"); + } else if (node->IsComputedName()) { + MSGNOLOC0("field is ComputedName"); + } else if (node->IsStrIndexSig()) { + MSGNOLOC0("field is StrIndexSig"); + } else { + NOTYETIMPL("field new kind"); + } + return node; +} + +// ArrayElementNode are for +// 1. array access +// 2. indexed access of class/structure for fields, field types +ArrayElementNode *TypeInferVisitor::VisitArrayElementNode(ArrayElementNode *node) { + (void) AstVisitor::VisitArrayElementNode(node); + TreeNode *array = node->GetArray(); + if (array) { + if (array->IsIdentifier()) { + TreeNode *decl = mHandler->FindDecl(static_cast(array)); + if (decl) { + // indexed access of class fields or types + if (decl->IsTypeIdClass()) { + SetTypeId(array, TY_Class); + TreeNode *exp = node->GetExprAtIndex(0); + if (exp->IsLiteral()) { + if (exp->IsTypeIdString()) { + // indexed access of types + unsigned stridx = (static_cast(exp))->GetData().mData.mStrIdx; + if (decl->IsDecl()) { + TreeNode *var = static_cast(decl)->GetVar(); + TreeNode * type = static_cast(var)->GetType(); + if (type && type->IsUserType()) { + UserTypeNode *ut = static_cast(type); + decl = mHandler->FindDecl(static_cast(ut->GetId())); + } + } + if (decl->IsStruct() || decl->IsClass()) { + bool found = false; + for (int i = 0; i < mInfo->GetFieldsSize(decl); i++) { + TreeNode *f = mInfo->GetField(decl, i); + if (f->GetStrIdx() == stridx) { + UpdateTypeId(node, f); + found = true; + break; + } + } + // new field + if (!found) { + IdentifierNode *id = mInfo->CreateIdentifierNode(stridx); + mInfo->AddField(decl, id); + } + } + } else if (exp->IsTypeIdInt()) { + // indexed access of fields + // unsigned i = (static_cast(exp))->GetData().mData.mInt64; + NOTYETIMPL("indexed access with literal field id"); + } else { + AstVisitor::VisitTreeNode(exp); + NOTYETIMPL("indexed access not literal"); + } + } else { + AstVisitor::VisitTreeNode(exp); + } + } else { + // default + UpdateTypeId(array, TY_Array); + UpdateTypeId(decl, array); + UpdateArrayElemTypeMap(decl, node->GetTypeId(), node->GetTypeIdx()); + UpdateTypeId(node, mHandler->GetArrayElemTypeId(decl->GetNodeId())); + } + } else { + NOTYETIMPL("array not declared"); + } + } else if (array->IsArrayElement()) { + NOTYETIMPL("array in ArrayElementNode IsArrayElement"); + } else if (array->IsField()) { + NOTYETIMPL("array in ArrayElementNode IsField"); + } else if (array->IsUserType()) { + NOTYETIMPL("array in ArrayElementNode IsUserType"); + } else if (array->IsBinOperator()) { + NOTYETIMPL("array in ArrayElementNode IsBinOperator"); + } else if (array->IsLiteral() && ((LiteralNode*)array)->IsThis()) { + NOTYETIMPL("array in ArrayElementNode IsLiteral"); + } else if (array->IsPrimType()) { + NOTYETIMPL("array in ArrayElementNode IsPrimType"); + } else { + NOTYETIMPL("array in ArrayElementNode unknown"); + } + } + return node; +} + +FieldLiteralNode *TypeInferVisitor::VisitFieldLiteralNode(FieldLiteralNode *node) { + (void) AstVisitor::VisitFieldLiteralNode(node); + TreeNode *name = node->GetFieldName(); + TreeNode *lit = node->GetLiteral(); + UpdateTypeId(name, lit->GetTypeId()); + UpdateTypeId(node, name); + return node; +} + +ArrayLiteralNode *TypeInferVisitor::VisitArrayLiteralNode(ArrayLiteralNode *node) { + UpdateTypeId(node, TY_Array); + (void) AstVisitor::VisitArrayLiteralNode(node); + if (node->IsArrayLiteral()) { + unsigned size = node->GetLiteralsNum(); + TypeId tid = TY_None; + unsigned tidx = 0; + bool allElemArray = true; + for (unsigned i = 0; i < size; i++) { + TreeNode *n = node->GetLiteral(i); + TypeId id = n->GetTypeId(); + unsigned idx = n->GetTypeIdx(); + tid = MergeTypeId(tid, id); + tidx = MergeTypeIdx(tidx, idx); + if (tid != TY_Array) { + allElemArray = false; + } + } + + DimensionNode *dim = mHandler->NewTreeNode(); + dim->AddDimension(size); + + // n-D array: elements are all arrays + if (allElemArray) { + unsigned elemdim = DEFAULTVALUE; + // recalculate element typeid + tid = TY_None; + tidx = 0; + for (unsigned i = 0; i < size; i++) { + TreeNode *n = node->GetLiteral(i); + if (n->IsArrayLiteral()) { + DimensionNode * dn = mHandler->GetArrayDim(n->GetNodeId()); + unsigned currdim = dn ? dn->GetDimensionsNum() : 0; + // find min dim of all elements + if (elemdim == DEFAULTVALUE) { + elemdim = currdim; + tid = mHandler->GetArrayElemTypeId(n->GetNodeId()); + tidx = mHandler->GetArrayElemTypeIdx(n->GetNodeId()); + } else if (currdim < elemdim) { + elemdim = currdim; + tid = TY_Merge; + tidx = 0; + } else if (currdim > elemdim) { + tid = TY_Merge; + tidx = 0; + } else { + tid = MergeTypeId(tid, mHandler->GetArrayElemTypeId(n->GetNodeId())); + tidx = MergeTypeIdx(tidx, mHandler->GetArrayElemTypeIdx(n->GetNodeId())); + } + } + } + if (elemdim != DEFAULTVALUE) { + for (unsigned i = 0; i < elemdim; i++) { + // with unspecified length, can add details later + dim->AddDimension(0); + } + } + } + + UpdateArrayElemTypeMap(node, tid, tidx); + UpdateArrayDimMap(node, dim); + } + + return node; +} + +BinOperatorNode *TypeInferVisitor::VisitBinOperatorNode(BinOperatorNode *node) { + if (mFlags & FLG_trace_1) std::cout << "Visiting BinOperatorNode, id=" << node->GetNodeId() << "..." << std::endl; + // (void) AstVisitor::VisitBinOperatorNode(node); + OprId op = node->GetOprId(); + TreeNode *ta = node->GetOpndA(); + TreeNode *tb = node->GetOpndB(); + (void) VisitTreeNode(tb); + (void) VisitTreeNode(ta); + // modified operand + TreeNode *mod = NULL; + TypeId tia = ta->GetTypeId(); + TypeId tib = tb->GetTypeId(); + switch (op) { + case OPR_StEq: + case OPR_EQ: + case OPR_NE: + case OPR_GT: + case OPR_LT: + case OPR_GE: + case OPR_LE: { + if (tia != TY_None && tib == TY_None) { + UpdateTypeId(tb, tia); + mod = tb; + } else if (tia == TY_None && tib != TY_None) { + UpdateTypeId(ta, tib); + mod = ta; + } + SetTypeId(node, TY_Boolean); + SetTypeIdx(node, TY_Boolean); + break; + } + case OPR_Assign: + case OPR_AddAssign: + case OPR_SubAssign: + case OPR_MulAssign: + case OPR_DivAssign: + case OPR_ModAssign: + case OPR_ShlAssign: + case OPR_ShrAssign: + case OPR_BandAssign: + case OPR_BorAssign: + case OPR_BxorAssign: + case OPR_ZextAssign: { + TypeId ti = MergeTypeId(tia, tib); + if (tia == TY_None || (ta->IsIdentifier() && tia != ti)) { + UpdateTypeId(ta, ti); + mod = ta; + } else if (tib == TY_None) { + UpdateTypeId(tb, ti); + mod = tb; + } + UpdateTypeId(node, ti); + unsigned tix = MergeTypeIdx(ta->GetTypeIdx(), tb->GetTypeIdx()); + UpdateTypeIdx(ta, tix); + UpdateTypeIdx(tb, tix); + UpdateTypeIdx(node, tix); + break; + } + case OPR_Add: + case OPR_Sub: + case OPR_Mul: + case OPR_Div: { + if (tia != TY_None && tib == TY_None) { + UpdateTypeId(tb, tia); + mod = tb; + } else if (tia == TY_None && tib != TY_None) { + UpdateTypeId(ta, tib); + mod = ta; + } + TypeId ti = MergeTypeId(tia, tib); + UpdateTypeId(node, ti); + unsigned tix = MergeTypeIdx(ta->GetTypeIdx(), tb->GetTypeIdx()); + UpdateTypeIdx(ta, tix); + UpdateTypeIdx(tb, tix); + UpdateTypeIdx(node, tix); + break; + } + case OPR_Mod: + case OPR_Band: + case OPR_Bor: + case OPR_Bxor: + case OPR_Shl: + case OPR_Shr: + case OPR_Zext: { + SetTypeId(ta, TY_Int); + SetTypeId(tb, TY_Int); + SetTypeId(node, TY_Int); + SetTypeIdx(ta, TY_Int); + SetTypeIdx(tb, TY_Int); + SetTypeIdx(node, TY_Int); + break; + } + case OPR_Land: + case OPR_Lor: { + SetTypeId(ta, TY_Boolean); + SetTypeId(tb, TY_Boolean); + SetTypeId(node, TY_Boolean); + SetTypeIdx(ta, TY_Boolean); + SetTypeIdx(tb, TY_Boolean); + SetTypeIdx(node, TY_Boolean); + break; + } + case OPR_Exp: { + if (tia == TY_Int && tib == TY_Int) { + SetTypeId(node, TY_Int); + SetTypeIdx(node, TY_Int); + } + break; + } + case OPR_NullCoalesce: + break; + default: { + NOTYETIMPL("VisitBinOperatorNode()"); + break; + } + } + // visit mod to update its content + (void) VisitTreeNode(mod); + return node; +} + +CallNode *TypeInferVisitor::VisitCallNode(CallNode *node) { + if (mFlags & FLG_trace_1) std::cout << "Visiting CallNode, id=" << node->GetNodeId() << "..." << std::endl; + TreeNode *method = node->GetMethod(); + Module_Handler *handler = mHandler; + UpdateTypeId(method, TY_Function); + if (method) { + if (method->IsField()) { + FieldNode *field = static_cast(method); + method = field->GetField(); + TreeNode *upper = field->GetUpper(); + handler = mAstOpt->GetHandlerFromNodeId(upper->GetNodeId()); + } + if (method->IsIdentifier()) { + IdentifierNode *mid = static_cast(method); + TreeNode *decl = mHandler->FindDecl(mid); + if (decl) { + SetTypeIdx(node, decl->GetTypeIdx()); + SetTypeIdx(mid, decl->GetTypeIdx()); + + if (decl->IsDecl()) { + DeclNode *d = static_cast(decl); + if (d->GetInit()) { + decl = d->GetInit(); + } + } + if (decl && decl->IsIdentifier()) { + IdentifierNode *id = static_cast(decl); + if (id->GetType()) { + decl = id->GetType(); + } else if (id->IsTypeIdFunction()) { + NOTYETIMPL("VisitCallNode TY_Function"); + } + } + if (decl) { + if (decl->IsFunction()) { + FunctionNode *func = static_cast(decl); + // check if called a generator + if (func->IsGenerator()) { + mHandler->AddGeneratorUsed(node->GetNodeId(), func); + } + // update call's return type + if (func->GetRetType()) { + UpdateTypeId(node, func->GetRetType()->GetTypeId()); + } + // skip imported and exported functions as they are generic + // so should not restrict their types + if (!mXXport->IsImportedExportedDeclId(mHandler->GetHidx(), decl->GetNodeId())) { + unsigned min = func->GetParamsNum(); + if (func->GetParamsNum() != node->GetArgsNum()) { + // count minimun number of args need to be passed + min = 0; + // check arg about whether it is optional or has default value + for (unsigned i = 0; i < func->GetParamsNum(); i++) { + TreeNode *arg = func->GetParam(i); + if (arg->IsOptional()) { + continue; + } else if(arg->IsIdentifier()) { + IdentifierNode *id = static_cast(arg); + TreeNode *d = mHandler->FindDecl(id); + if (d) { + SetTypeId(id, d->GetTypeId()); + SetTypeIdx(id, d->GetTypeIdx()); + } + if (!id->GetInit()) { + min++; + } + } else { + min++; + } + } + if (min > node->GetArgsNum()) { + NOTYETIMPL("call and func number of arguments not compatible"); + return node; + } + } + // update function's argument types + for (unsigned i = 0; i < min; i++) { + UpdateTypeUseNode(func->GetParam(i), node->GetArg(i)); + } + + // dummy functions like console.log + if (func->IsTypeIdNone()) { + for (unsigned i = 0; i < node->GetArgsNum(); i++) { + TreeNode *arg = node->GetArg(i); + if(arg->IsIdentifier()) { + IdentifierNode *id = static_cast(arg); + TreeNode *d = mHandler->FindDecl(id); + if (d) { + SetTypeId(id, d->GetTypeId()); + SetTypeIdx(id, d->GetTypeIdx()); + } + } + } + } + } + } else if (decl->IsCall()) { + (void) VisitCallNode(static_cast(decl)); + } else if (decl->IsDecl()) { + DeclNode *d = static_cast(decl); + if (d->GetInit()) { + NOTYETIMPL("VisitCallNode decl init"); + } + } else if (decl->IsLiteral()) { + NOTYETIMPL("VisitCallNode literal node"); + } else if (decl->IsTypeIdClass()) { + // object + if (node->GetArgsNum()) { + TreeNode *arg = node->GetArg(0); + SetTypeId(arg, TY_Object); + SetTypeIdx(arg, decl->GetTypeIdx()); + } + } else { + NOTYETIMPL("VisitCallNode not function node"); + } + } else { + NOTYETIMPL("VisitCallNode null decl"); + } + } else if (mAstOpt->IsLangKeyword(mid)) { + // known calls + } else { + // calling constructor like Array(...) could also end up here + TreeNode *type = mHandler->FindType(mid); + if (type) { + NOTYETIMPL("VisitCallNode type"); + } else { + NOTYETIMPL("VisitCallNode null decl and null type"); + } + } + } + } + (void) AstVisitor::VisitCallNode(node); + return node; +} + +CastNode *TypeInferVisitor::VisitCastNode(CastNode *node) { + (void) AstVisitor::VisitCastNode(node); + TreeNode *dest = node->GetDestType(); + SetTypeId(node, dest); + return node; +} + +AsTypeNode *TypeInferVisitor::VisitAsTypeNode(AsTypeNode *node) { + (void) AstVisitor::VisitAsTypeNode(node); + TreeNode *dest = node->GetType(); + if (node->GetTypeIdx() == 0) { + SetTypeId(node, dest); + } + + TreeNode *parent = node->GetParent(); + if (parent) { + // pass to parent, need refine if multiple AsTypeNode + if (parent->GetAsTypesNum() == 1 && parent->GetAsTypeAtIndex(0) == node) { + if (parent->GetTypeIdx() == 0) { + SetTypeId(parent, dest); + } + } + } + return node; +} + +ClassNode *TypeInferVisitor::VisitClassNode(ClassNode *node) { + if (mFlags & FLG_trace_1) std::cout << "Visiting ClassNode, id=" << node->GetNodeId() << "..." << std::endl; + UpdateTypeId(node, TY_Class); + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + TreeNode *t = node->GetField(i); + (void) VisitClassField(t); + } + (void) AstVisitor::VisitClassNode(node); + return node; +} + +CondBranchNode *TypeInferVisitor::VisitCondBranchNode(CondBranchNode *node) { + (void) AstVisitor::VisitCondBranchNode(node); + TreeNode *cond = node->GetCond(); + TreeNode *blockT = NULL; + TreeNode *blockF = NULL; + if (cond->IsUnaOperator()) { + cond = static_cast(cond)->GetOpnd(); + blockT = node->GetFalseBranch(); + blockF = node->GetTrueBranch(); + } else { + blockT = node->GetTrueBranch(); + blockF = node->GetFalseBranch(); + } + + if (cond->IsCall()) { + CallNode *call = static_cast(cond); + TreeNode *method = call->GetMethod(); + if (method && method->IsIdentifier()) { + IdentifierNode *id = static_cast(method); + unsigned mid = id->GetStrIdx(); + unsigned nid = node->GetNodeId(); + // check if already visited for mid and nodeid + if (mCbFuncIsDone.find(mid) != mCbFuncIsDone.end() && + mCbFuncIsDone[mid].find(nid) != mCbFuncIsDone[mid].end()) { + return node; + } + TreeNode *decl = mHandler->FindDecl(id); + if (decl && decl->IsFunction()) { + unsigned fid = decl->GetNodeId(); + if (mFuncIsNodeMap.find(fid) != mFuncIsNodeMap.end()) { + unsigned tidx = mFuncIsNodeMap[fid]; + TreeNode *arg = call->GetArg(0); + if (arg->IsIdentifier()) { + unsigned stridx = arg->GetStrIdx(); + mChangeTypeIdxVisitor->Setup(stridx, tidx); + mChangeTypeIdxVisitor->Visit(blockT); + mCbFuncIsDone[mid].insert(nid); + SetUpdated(); + + // if union of 2 types, update other branch with other type + TreeNode *argdecl = mHandler->FindDecl(static_cast(arg)); + if (argdecl && argdecl->IsIdentifier()) { + TreeNode *type = static_cast(argdecl)->GetType(); + if (type->IsUserType()) { + UserTypeNode *ut = static_cast(type); + if (ut->GetType() == UT_Union && ut->GetUnionInterTypesNum() == 2) { + TreeNode *u0 = ut->GetUnionInterType(0); + TreeNode *u1 = ut->GetUnionInterType(1); + tidx = (u0->GetTypeIdx() == tidx) ? u1->GetTypeIdx() : u0->GetTypeIdx(); + mChangeTypeIdxVisitor->Setup(stridx, tidx); + mChangeTypeIdxVisitor->Visit(blockF); + } + } + } + } + } + } + + } else { + NOTYETIMPL("mentod null or not identifier"); + } + } + + return node; +} + +DeclNode *TypeInferVisitor::VisitDeclNode(DeclNode *node) { + if (mFlags & FLG_trace_1) std::cout << "Visiting DeclNode, id=" << node->GetNodeId() << "..." << std::endl; + (void) AstVisitor::VisitDeclNode(node); + TreeNode *init = node->GetInit(); + TreeNode *var = node->GetVar(); + TypeId merged = node->GetTypeId(); + unsigned mergedtidx = node->GetTypeIdx(); + TypeId elemTypeId = TY_None; + unsigned elemTypeIdx = 0; + bool isArray = false; + bool isFromGenerator = false; + if (init) { + merged = MergeTypeId(merged, init->GetTypeId()); + mergedtidx = MergeTypeIdx(mergedtidx, init->GetTypeIdx()); + // collect array element typeid if any + elemTypeId = GetArrayElemTypeId(init); + elemTypeIdx = GetArrayElemTypeIdx(init); + isArray = (elemTypeId != TY_None); + // pass IsGeneratorUsed + isFromGenerator = mHandler->UpdateGeneratorUsed(node->GetNodeId(), init->GetNodeId()); + if (var && isFromGenerator) { + mHandler->UpdateGeneratorUsed(var->GetNodeId(), init->GetNodeId()); + } + } + if (var) { + // normal cases + if(var->IsIdentifier()) { + IdentifierNode *idvar = static_cast(var); + if (isFromGenerator && !idvar->GetType()) { + unsigned stridx = gStringPool.GetStrIdx("Generator"); + UserTypeNode *ut = mInfo->CreateUserTypeNode(stridx, var->GetScope()); + idvar->SetType(ut); + } + merged = MergeTypeId(merged, var->GetTypeId()); + mergedtidx = MergeTypeIdx(mergedtidx, var->GetTypeIdx()); + bool isFunc = UpdateVarTypeWithInit(var, init); + if (isFunc) { + UpdateTypeId(node, var->GetTypeId()); + UpdateTypeIdx(node, mergedtidx); + UpdateTypeIdx(var, mergedtidx); + return node; + } + } else { + // BindingPatternNode + } + } else { + MASSERT("var null"); + } + // override TypeId for array + if (isArray) { + merged = TY_Array; + SetTypeId(node, merged); + SetTypeId(init, merged); + SetTypeId(var, merged); + } else { + UpdateTypeId(node, merged); + UpdateTypeId(init, merged); + UpdateTypeId(var, merged); + if (mergedtidx > 0) { + UpdateTypeIdx(node, mergedtidx); + UpdateTypeIdx(init, mergedtidx); + UpdateTypeIdx(var, mergedtidx); + } + } + SetTypeIdx(node, var->GetTypeIdx()); + if (isArray || IsArray(node)) { + UpdateArrayElemTypeMap(node, elemTypeId, elemTypeIdx); + } + return node; +} + +ImportNode *TypeInferVisitor::VisitImportNode(ImportNode *node) { + //(void) AstVisitor::VisitImportNode(node); + TreeNode *target = node->GetTarget(); + unsigned hidx = DEFAULTVALUE; + unsigned hstridx = 0; + if (target) { + std::string name = mXXport->GetTargetFilename(mHandler->GetHidx(), target); + // store name's string index in node + hstridx = gStringPool.GetStrIdx(name); + hidx = mXXport->GetHandleIdxFromStrIdx(hstridx); + } + for (unsigned i = 0; i < node->GetPairsNum(); i++) { + XXportAsPairNode *p = node->GetPair(i); + TreeNode *bfnode = p->GetBefore(); + TreeNode *afnode = p->GetAfter(); + if (bfnode) { + if (hidx == DEFAULTVALUE) { + hstridx = mXXport->ExtractTargetStrIdx(bfnode); + if (hstridx) { + hidx = mXXport->GetHandleIdxFromStrIdx(hstridx); + } else { + NOTYETIMPL("can not find import target"); + return node; + } + } + if (p->IsDefault()) { + TreeNode *dflt = mXXport->GetExportedDefault(hstridx); + if (dflt) { + UpdateTypeId(bfnode, dflt->GetTypeId()); + UpdateTypeIdx(bfnode, dflt->GetTypeIdx()); + } else { + NOTYETIMPL("can not find exported default"); + } + } else if (!bfnode->IsTypeIdModule()) { + TreeNode *exported = NULL; + if (bfnode->IsField()) { + FieldNode *field = static_cast(bfnode); + TreeNode *upper = field->GetUpper(); + TreeNode *fld = field->GetField(); + if (upper->IsTypeIdModule()) { + TreeNode *type = gTypeTable.GetTypeFromTypeIdx(upper->GetTypeIdx()); + Module_Handler *h = mHandler->GetModuleHandler(type); + exported = mXXport->GetExportedNamedNode(h->GetHidx(), fld->GetStrIdx()); + if (exported) { + UpdateTypeId(bfnode, exported->GetTypeId()); + UpdateTypeIdx(bfnode, exported->GetTypeIdx()); + } + } + } else { + exported = mXXport->GetExportedNamedNode(hidx, bfnode->GetStrIdx()); + if (exported) { + SetTypeId(bfnode, exported); + } + } + if (!exported) { + NOTYETIMPL("can not find exported node"); + } + } + + SetTypeId(p, bfnode); + if (afnode) { + SetTypeId(afnode, bfnode); + } + } + } + return node; +} + +// check if node is identifier with name "default"+RENAMINGSUFFIX +static bool IsDefault(TreeNode *node) { + return node->GetStrIdx() == gStringPool.GetStrIdx(std::string("default") + RENAMINGSUFFIX); +} + +ExportNode *TypeInferVisitor::VisitExportNode(ExportNode *node) { + (void) AstVisitor::VisitExportNode(node); + unsigned hidx = mHandler->GetHidx(); + for (unsigned i = 0; i < node->GetPairsNum(); i++) { + XXportAsPairNode *p = node->GetPair(i); + TreeNode *bfnode = p->GetBefore(); + TreeNode *afnode = p->GetAfter(); + if (bfnode) { + switch (bfnode->GetKind()) { + case NK_Struct: + case NK_Function: + case NK_Decl: { + mXXport->AddExportedDeclIds(hidx, bfnode->GetNodeId()); + break; + } + case NK_Declare: { + DeclareNode *declare = static_cast(bfnode); + for (unsigned i = 0; i < declare-> GetDeclsNum(); i++) { + TreeNode *decl = declare->GetDeclAtIndex(i); + if (decl) { + mXXport->AddExportedDeclIds(hidx, decl->GetNodeId()); + } + } + break; + } + case NK_Identifier: { + IdentifierNode *idnode = static_cast(bfnode); + TreeNode *decl = mHandler->FindDecl(idnode); + if (decl) { + mXXport->AddExportedDeclIds(hidx, decl->GetNodeId()); + } + if (IsDefault(bfnode)) { + unsigned stridx = node->GetStrIdx(); + TreeNode *dflt = mXXport->GetExportedDefault(stridx); + if (dflt) { + UpdateTypeId(bfnode, dflt->GetTypeId()); + UpdateTypeIdx(bfnode, dflt->GetTypeIdx()); + } else { + NOTYETIMPL("can not find exported default"); + } + } + break; + } + case NK_TypeAlias: + case NK_UserType: + case NK_Import: + break; + default: { + NOTYETIMPL("new export node kind"); + break; + } + } + + UpdateTypeId(p, bfnode->GetTypeId()); + UpdateTypeIdx(p, bfnode->GetTypeIdx()); + if (afnode) { + UpdateTypeId(afnode, bfnode->GetTypeId()); + UpdateTypeIdx(afnode, bfnode->GetTypeIdx()); + } + } + } + return node; +} + +FieldNode *TypeInferVisitor::VisitFieldNode(FieldNode *node) { + (void) AstVisitor::VisitFieldNode(node); + TreeNode *upper = node->GetUpper(); + IdentifierNode *field = static_cast(node->GetField()); + TreeNode *decl = NULL; + if (!upper) { + decl = mHandler->FindDecl(field); + } else { + if (upper->IsLiteral()) { + LiteralNode *ln = static_cast(upper); + // this.f + if (ln->GetData().mType == LT_ThisLiteral) { + decl = mHandler->FindDecl(field); + } + } + if (!decl) { + unsigned tidx = upper->GetTypeIdx(); + if (tidx) { + TreeNode *n = gTypeTable.GetTypeFromTypeIdx(tidx); + ASTScope *scope = n->GetScope(); + decl = scope->FindDeclOf(field->GetStrIdx()); + } + } + } + if (decl) { + UpdateTypeId(node, decl); + } + UpdateTypeId(field, node); + return node; +} + +ForLoopNode *TypeInferVisitor::VisitForLoopNode(ForLoopNode *node) { + if (mFlags & FLG_trace_1) std::cout << "Visiting ForLoopNode, id=" << node->GetNodeId() << "..." << std::endl; + if (node->GetProp() == FLP_JSIn) { + TreeNode *var = node->GetVariable(); + if (var) { + SetTypeId(var, TY_Int); + } + } + (void) AstVisitor::VisitForLoopNode(node); + return node; +} + +FunctionNode *TypeInferVisitor::VisitFunctionNode(FunctionNode *node) { + if (mFlags & FLG_trace_1) std::cout << "Visiting FunctionNode, id=" << node->GetNodeId() << "..." << std::endl; + UpdateTypeId(node, node->IsArray() ? TY_Object : TY_Function); + (void) AstVisitor::VisitFunctionNode(node); + if (node->GetFuncName()) { + SetTypeId(node->GetFuncName(), node->GetTypeId()); + } + return node; +} + +IdentifierNode *TypeInferVisitor::VisitIdentifierNode(IdentifierNode *node) { + if (mFlags & FLG_trace_1) std::cout << "Visiting IdentifierNode, id=" << node->GetNodeId() << "..." << std::endl; + if (mAstOpt->IsLangKeyword(node)) { + return node; + } + TreeNode *type = node->GetType(); + if (type) { + if (type->IsPrimArrayType()) { + SetTypeId(node, TY_Array); + SetUpdated(); + } + } + (void) AstVisitor::VisitIdentifierNode(node); + if (type) { + unsigned tidx = type->GetTypeIdx(); + if (tidx && node->GetTypeIdx() != tidx) { + UpdateTypeId(node, type->GetTypeId()); + UpdateTypeIdx(node, tidx); + SetUpdated(); + } + } + TreeNode *init = node->GetInit(); + if (init) { + if (node->GetTypeId() == TY_None) { + SetTypeId(node, init->GetTypeId()); + } + if (node->GetTypeIdx() == 0) { + SetTypeIdx(node, init->GetTypeIdx()); + } + SetUpdated(); + if (init->IsArrayLiteral()) { + // pass array element info + TypeId tid = mHandler->GetArrayElemTypeId(init->GetNodeId()); + unsigned tidx = mHandler->GetArrayElemTypeIdx(init->GetNodeId()); + UpdateArrayElemTypeMap(node, tid, tidx); + if (type && type->IsArrayType()) { + TreeNode *et = static_cast(type)->GetElemType(); + et->SetTypeId(tid); + et->SetTypeIdx(tidx); + } + } + return node; + } + TreeNode *parent = node->GetParent(); + TreeNode *decl = NULL; + if (parent && parent->IsField()) { + FieldNode *field = static_cast(parent); + TreeNode *upper = field->GetUpper(); + TreeNode *fld = field->GetField(); + ASTScope *scope = NULL; + if (node == upper) { + if (upper->IsThis()) { + // this.f + scope = upper->GetScope(); + // this is the parent with typeid TY_Class + while (scope && scope->GetTree()->GetTypeId() != TY_Class) { + scope = scope->GetParent(); + } + if (scope) { + upper->SetTypeId(scope->GetTree()->GetTypeId()); + upper->SetTypeIdx(scope->GetTree()->GetTypeIdx()); + } + decl = upper; + } else { + decl = mHandler->FindDecl(node, true); + } + } else if (node == fld) { + TreeNode *uptype = gTypeTable.GetTypeFromTypeIdx(upper->GetTypeIdx()); + if (uptype) { + scope = uptype->GetScope(); + if (scope) { + node->SetScope(scope); + decl = mHandler->FindDecl(node, true); + } + } + } else { + NOTYETIMPL("node not in field"); + } + } else { + decl = mHandler->FindDecl(node); + } + + if (decl) { + // check node itself is part of decl + if (decl != parent) { + UpdateTypeId(node, decl); + UpdateTypeIdx(node, decl); + } + // pass IsGeneratorUsed + mHandler->UpdateGeneratorUsed(node->GetNodeId(), decl->GetNodeId()); + } else { + NOTYETIMPL("node not declared"); + MSGNOLOC0(node->GetName()); + } + + return node; +} + +InterfaceNode *TypeInferVisitor::VisitInterfaceNode(InterfaceNode *node) { + UpdateTypeId(node, TY_Class); + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + TreeNode *t = node->GetField(i); + (void) VisitClassField(t); + } + (void) AstVisitor::VisitInterfaceNode(node); + return node; +} + +IsNode *TypeInferVisitor::VisitIsNode(IsNode *node) { + (void) AstVisitor::VisitIsNode(node); + SetTypeIdx(node, TY_Boolean); + TreeNode *parent = node->GetParent(); + if (parent->IsFunction()) { + FunctionNode *func = static_cast(parent); + if (func->GetRetType() == node) { + TreeNode *right = node->GetRight(); + if (right->IsUserType()) { + TreeNode *id = static_cast(right)->GetId(); + SetTypeIdx(right, id->GetTypeIdx()); + mFuncIsNodeMap[func->GetNodeId()] = id->GetTypeIdx(); + } else { + NOTYETIMPL("isnode right not user type"); + } + } + } + + return node; +} + +NewNode *TypeInferVisitor::VisitNewNode(NewNode *node) { + (void) AstVisitor::VisitNewNode(node); + TreeNode *id = node->GetId(); + if (id) { + UpdateTypeId(node, TY_Class); + if (id->GetTypeIdx() == 0) { + if (id->IsIdentifier()) { + IdentifierNode *idn = static_cast(id); + TreeNode *decl = mHandler->FindDecl(idn); + if (decl && decl->GetTypeIdx() != 0) { + SetTypeIdx(node, decl->GetTypeIdx()); + } + } + } else { + SetTypeIdx(node, id->GetTypeIdx()); + } + } + return node; +} + +StructNode *TypeInferVisitor::VisitStructNode(StructNode *node) { + if (node->GetProp() != SProp_TSEnum) { + SetTypeId(node, TY_Class); + } + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + TreeNode *t = node->GetField(i); + (void) VisitClassField(t); + } + if (node->GetProp() == SProp_TSEnum) { + TypeId tid = TY_None; + unsigned tidx = 0; + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + TreeNode *t = node->GetField(i); + tid = MergeTypeId(tid, t->GetTypeId()); + tidx = MergeTypeIdx(tidx, t->GetTypeIdx()); + } + if (tid == TY_None) { + tid = TY_Int; + tidx = (unsigned)TY_Int; + } + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + TreeNode *t = node->GetField(i); + SetTypeId(t, tid); + SetTypeIdx(t, tidx); + } + TreeNode *id = node->GetStructId(); + if (id) { + SetTypeId(id, node->GetTypeId()); + SetTypeIdx(id, node->GetTypeIdx()); + } + } + (void) AstVisitor::VisitStructNode(node); + return node; +} + +LambdaNode *TypeInferVisitor::VisitLambdaNode(LambdaNode *node) { + if (mFlags & FLG_trace_1) std::cout << "Visiting LambdaNode, id=" << node->GetNodeId() << "..." << std::endl; + UpdateTypeId(node, TY_Function); + (void) AstVisitor::VisitLambdaNode(node); + return node; +} + +LiteralNode *TypeInferVisitor::VisitLiteralNode(LiteralNode *node) { + (void) AstVisitor::VisitLiteralNode(node); + LitId id = node->GetData().mType; + switch (id) { + case LT_IntegerLiteral: + SetTypeId(node, TY_Int); + SetTypeIdx(node, TY_Int); + break; + case LT_FPLiteral: + SetTypeId(node, TY_Float); + SetTypeIdx(node, TY_Float); + break; + case LT_DoubleLiteral: + SetTypeId(node, TY_Double); + SetTypeIdx(node, TY_Double); + break; + case LT_StringLiteral: + SetTypeId(node, TY_String); + SetTypeIdx(node, TY_String); + break; + case LT_VoidLiteral: + SetTypeId(node, TY_Undefined); + break; + default: + break; + } + return node; +} + +ReturnNode *TypeInferVisitor::VisitReturnNode(ReturnNode *node) { + (void) AstVisitor::VisitReturnNode(node); + TreeNode *res = node->GetResult(); + if (res) { + UpdateTypeId(node, res->GetTypeId()); + UpdateTypeIdx(node, res->GetTypeIdx()); + } + TreeNode *tn = mHandler->FindFunc(node); + if (tn) { + FunctionNode *func = static_cast(tn); + // use dummy PrimTypeNode as return type of function if not set to carry return TypeId + if (!func->GetRetType()) { + PrimTypeNode *type = mHandler->NewTreeNode(); + type->SetPrimType(TY_None); + func->SetRetType(type); + } + if (!func->IsGenerator() && !func->IsIterator()) { + UpdateFuncRetTypeId(func, node->GetTypeId(), node->GetTypeIdx()); + if (res) { + // use res to update function's return type + UpdateTypeUseNode(func->GetRetType(), res); + } + } + } + return node; +} + +StructLiteralNode *TypeInferVisitor::VisitStructLiteralNode(StructLiteralNode *node) { + SetTypeId(node, TY_Class); + for (unsigned i = 0; i < node->GetFieldsNum(); ++i) { + FieldLiteralNode *t = node->GetField(i); + (void) VisitFieldLiteralNode(t); + } + (void) AstVisitor::VisitStructLiteralNode(node); + return node; +} + +TemplateLiteralNode *TypeInferVisitor::VisitTemplateLiteralNode(TemplateLiteralNode *node) { + UpdateTypeId(node, TY_String); + (void) AstVisitor::VisitTemplateLiteralNode(node); + return node; +} + +TerOperatorNode *TypeInferVisitor::VisitTerOperatorNode(TerOperatorNode *node) { + TreeNode *ta = node->GetOpndA(); + TreeNode *tb = node->GetOpndB(); + TreeNode *tc = node->GetOpndC(); + (void) VisitTreeNode(ta); + (void) VisitTreeNode(tb); + (void) VisitTreeNode(tc); + UpdateTypeId(node, tb); + return node; +} + +TypeOfNode *TypeInferVisitor::VisitTypeOfNode(TypeOfNode *node) { + UpdateTypeId(node, TY_String); + (void) AstVisitor::VisitTypeOfNode(node); + return node; +} + +TypeAliasNode *TypeInferVisitor::VisitTypeAliasNode(TypeAliasNode *node) { + (void) AstVisitor::VisitTypeAliasNode(node); + UserTypeNode *id = node->GetId(); + TreeNode *alias = node->GetAlias(); + UpdateTypeId(id, alias); + return node; +} + +UnaOperatorNode *TypeInferVisitor::VisitUnaOperatorNode(UnaOperatorNode *node) { + (void) AstVisitor::VisitUnaOperatorNode(node); + OprId op = node->GetOprId(); + TreeNode *ta = node->GetOpnd(); + switch (op) { + case OPR_Plus: + case OPR_Minus: + UpdateTypeId(node, ta->GetTypeId()); + break; + case OPR_PreInc: + case OPR_Inc: + case OPR_PreDec: + case OPR_Dec: + UpdateTypeId(ta, TY_Int); + UpdateTypeId(node, TY_Int); + break; + case OPR_Bcomp: + UpdateTypeId(ta, TY_Int); + UpdateTypeId(node, TY_Int); + break; + case OPR_Not: + UpdateTypeId(ta, TY_Boolean); + UpdateTypeId(node, TY_Boolean); + break; + default: { + NOTYETIMPL("VisitUnaOperatorNode()"); + break; + } + } + return node; +} + +UserTypeNode *TypeInferVisitor::VisitUserTypeNode(UserTypeNode *node) { + (void) AstVisitor::VisitUserTypeNode(node); + if (node->GetDims()) { + SetTypeId(node, TY_Array); + SetTypeIdx(node, TY_Array); + } else if (node->GetId()) { + // non-enum user type which keep TY_None + if (node->GetId()->GetTypeId() != TY_None) { + SetTypeId(node, TY_Class); + } + UpdateTypeIdx(node, node->GetId()); + } + TreeNode *parent = node->GetParent(); + if (parent && parent->IsIdentifier()) { + // typeid: merge -> user + if (parent->IsTypeIdMerge()) { + SetTypeId(parent, TY_User); + SetUpdated(); + } else if (parent->IsTypeIdArray()) { + TreeNode *idnode = node->GetId(); + if (idnode && idnode->IsIdentifier()) { + // number, string could have been used + // as usertype identifier instand of primtype by parser + IdentifierNode *id = static_cast(idnode); + TypeId tid = TY_None; + unsigned stridx = id->GetStrIdx(); + if (stridx == gStringPool.GetStrIdx("number")) { + tid = TY_Number; + } else if (stridx == gStringPool.GetStrIdx("string")) { + tid = TY_String; + } + if (tid != TY_None) { + PrimArrayTypeNode *type = mHandler->NewTreeNode(); + PrimTypeNode *pt = mHandler->NewTreeNode(); + pt->SetPrimType(tid); + type->SetPrim(pt); + type->SetDims(node->GetDims()); + IdentifierNode *parentid = static_cast(parent); + parentid->SetType(type); + + // clean up parent info + id->SetParent(NULL); + node->SetParent(NULL); + + // set updated + SetUpdated(); + } + } + } + } + return node; +} + +UserTypeNode *ShareUTVisitor::VisitUserTypeNode(UserTypeNode *node) { + // skip it + return node; + + (void) AstVisitor::VisitUserTypeNode(node); + + // skip for array + if (node->GetDims()) { + return node; + } + + TreeNode *idnode = node->GetId(); + if (idnode && idnode->IsIdentifier()) { + IdentifierNode *id = static_cast(idnode); + ASTScope *scope = id->GetScope(); + TreeNode *type = scope->FindTypeOf(id->GetStrIdx()); + if (type && type != node && type->IsUserType()) { + UserTypeNode *ut = static_cast(type); + if (node->GetType() == ut->GetType()) { + // do not share if there are generics + if (ut->GetTypeGenericsNum() == 0) { + return ut; + } + } + } + } + return node; +} + +bool CheckTypeVisitor::IsCompatible(TypeId tid, TypeId target) { + if (tid == target) { + return true; + } + + bool result = false; + switch (target) { + case TY_Number: { + switch (tid) { + case TY_None: + case TY_Int: + case TY_Long: + case TY_Float: + case TY_Double: + result = true; + break; + default: + result = false; + break; + } + break; + } + case TY_Any: + // TY_Any or unspecified matches everything + result = true; + break; + default: + // ok if same typeid + result = (target == tid); + break; + } + + // tid being TY_None means untouched + result = result || (tid == TY_None); + + return result; +} + +IdentifierNode *CheckTypeVisitor::VisitIdentifierNode(IdentifierNode *node) { + (void) AstVisitor::VisitIdentifierNode(node); + + TreeNode *d = mHandler->FindDecl(node); + if (d && d->IsDecl()) { + DeclNode *decl = static_cast(d); + TreeNode *var = decl->GetVar(); + if (var && var != node && var->IsIdentifier()) { + IdentifierNode *id = static_cast(var); + bool result = false; + TreeNode *type = id->GetType(); + if (type) { + TypeId id = node->GetTypeId(); + TypeId target = TY_None; + switch (type->GetKind()) { + case NK_PrimType: { + PrimTypeNode *ptn = static_cast(type); + target = ptn->GetPrimType(); + break; + } + case NK_UserType: { + target = var->GetTypeId(); + break; + } + default: { + target = var->GetTypeId(); + break; + } + } + result = IsCompatible(id, target); + if (!result || (mFlags & FLG_trace_3)) { + std::cout << " Type Compatiblity : " << result << " : " + << AstDump::GetEnumTypeId(target) << " " + << AstDump::GetEnumTypeId(id) << std::endl; + } + } + } + } + return node; +} + +IdentifierNode *ChangeTypeIdxVisitor::VisitIdentifierNode(IdentifierNode *node) { + (void) AstVisitor::VisitIdentifierNode(node); + if (node->GetStrIdx() == mStrIdx) { + mHandler->GetUtil()->SetTypeIdx(node, mTypeIdx); + } + return node; +} + +} diff --git a/src/MapleFE/astopt/src/ast_util.cpp b/src/MapleFE/astopt/src/ast_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..84faa11a789b3d1396105073d4d9c3d55b59e194 --- /dev/null +++ b/src/MapleFE/astopt/src/ast_util.cpp @@ -0,0 +1,102 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include "ast.h" +#include "ast_util.h" +#include "ast_handler.h" +#include "gen_astdump.h" + +namespace maplefe { + +#define CPPKEYWORD(K) stridx = gStringPool.GetStrIdx(#K); mCppKeywords.insert(stridx); +void AST_Util::BuildCppKeyWordSet() { + unsigned stridx; +#include "cpp_keywords.def" +} + +bool AST_Util::IsDirectField(TreeNode *node) { + return mHandler->IsDirectField(node); +} + +bool AST_Util::IsCppKeyWord(unsigned stridx) { + return mCppKeywords.find(stridx) != mCppKeywords.end(); +} + +bool AST_Util::IsCppKeyWord(std::string name) { + unsigned stridx = gStringPool.GetStrIdx(name); + return mCppKeywords.find(stridx) != mCppKeywords.end(); +} + +// +bool AST_Util::IsCppName(std::string name) { + // check first char [a-z][A-Z]_ + char c = name[0]; + if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_')) { + return false; + } + + // check char [a-z][A-Z][0-9]_ + for (int i = 1; i < name.length(); i++) { + char c = name[i]; + if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) { + return false; + } + } + + return true; +} + +bool AST_Util::IsCppField(TreeNode *node) { + // check if it is a direct field + if (!IsDirectField(node)) { + return false; + } + + // check if it's name is a C++ keyworld + unsigned stridx = node->GetStrIdx(); + if (IsCppKeyWord(stridx)) { + return false; + } + + // check if it's name is a valid C++ name + std::string name = gStringPool.GetStringFromStrIdx(stridx); + if (!IsCppName(name)) { + return false; + } + return true; +} + +void AST_Util::SetTypeId(TreeNode *node, TypeId tid) { + if (tid != TY_None && node && node->GetTypeId() != tid) { + if (mFlags & FLG_trace_3) { + std::cout << " NodeId : " << node->GetNodeId() << " Set TypeId : " + << AstDump::GetEnumTypeId(node->GetTypeId()) << " --> " + << AstDump::GetEnumTypeId(tid) << std::endl; + } + node->SetTypeId(tid); + } +} + +void AST_Util::SetTypeIdx(TreeNode *node, unsigned tidx) { + if (node && node->GetTypeIdx() != tidx) { + if (mFlags & FLG_trace_3) { + std::cout << " NodeId : " << node->GetNodeId() << " Set TypeIdx : " + << node->GetTypeIdx() << " --> " << tidx << std::endl; + } + node->SetTypeIdx(tidx); + } +} + +} diff --git a/src/MapleFE/astopt/src/ast_xxport.cpp b/src/MapleFE/astopt/src/ast_xxport.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3b828851ba70dbec2137c069b8d0b647e1f34ca0 --- /dev/null +++ b/src/MapleFE/astopt/src/ast_xxport.cpp @@ -0,0 +1,546 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include +#include "ast_handler.h" +#include "ast_util.h" +#include "astopt.h" +#include "ast_xxport.h" +#include "gen_astdump.h" + +namespace maplefe { + +AST_XXport::AST_XXport(AstOpt *o, unsigned f) { + mAstOpt = o; + mASTHandler = o->GetASTHandler(); + mFlags = f; +} + +unsigned AST_XXport::GetModuleNum() { + return mASTHandler->GetSize(); +} + +void AST_XXport::BuildModuleOrder() { + // setup module stridx + SetModuleStrIdx(); + + // collect dependent info + CollectXXportNodes(); + + // collect dependent info + AddHandler(); + + // sort handlers with dependency + SortHandler(); +} + +void AST_XXport::SetModuleStrIdx() { + for (int i = 0; i < GetModuleNum(); i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + ModuleNode *module = handler->GetASTModule(); + + // setup module node stridx with module file name + unsigned stridx = gStringPool.GetStrIdx(module->GetFilename()); + module->SetStrIdx(stridx); + mStrIdx2HandlerIdxMap[stridx] = i; + } +} + +TreeNode *AST_XXport::FindExportedDecl(unsigned hidx, unsigned stridx) { + for (auto nid : mExportedDeclIds[hidx]) { + TreeNode *node = mAstOpt->GetNodeFromNodeId(nid); + if (node->GetStrIdx() == stridx) { + return node; + } + } + return NULL; +} + +void AST_XXport::CollectXXportNodes() { + for (int i = 0; i < GetModuleNum(); i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + ModuleNode *module = handler->GetASTModule(); + + XXportBasicVisitor visitor(this, handler, i, mFlags); + visitor.Visit(module); + } +} + +void AST_XXport::AddHandler() { + for (unsigned hidx = 0; hidx < GetModuleNum(); hidx++) { + for (auto it : mImportNodeSets[hidx]) { + ImportNode *node = it; + UpdateDependency(hidx, node); + } + for (auto it : mExportNodeSets[hidx]) { + ExportNode *node = it; + UpdateDependency(hidx, node); + } + } +} + +void AST_XXport::SortHandler() { + for (int i = 0; i < GetModuleNum(); i++) { + if (mHandlersIdxInOrder.size() == 0) { + mHandlersIdxInOrder.push_back(i); + continue; + } + + bool added = false; + std::list::iterator it = mHandlersIdxInOrder.begin(); + for (; it != mHandlersIdxInOrder.end(); it++) { + unsigned idx = *it; + // check if handler idx has dependency on i + if (mHandlerIdx2DependentHandlerIdxMap[idx].find(i) != mHandlerIdx2DependentHandlerIdxMap[i].end()) { + mHandlersIdxInOrder.insert(it, i); + added = true; + break; + } + } + + if (!added) { + mHandlersIdxInOrder.push_back(i); + } + } + + // copy result to AstOpt + std::list::iterator it = mHandlersIdxInOrder.begin(); + for (; it != mHandlersIdxInOrder.end(); it++) { + unsigned idx = *it; + Module_Handler *h = mASTHandler->GetModuleHandler(idx); + mAstOpt->AddModuleHandler(h); + } + + if (mFlags & FLG_trace_2) { + std::cout << "============== Module Order ==============" << std::endl; + for (auto hidx: mHandlersIdxInOrder) { + Module_Handler *handler = mASTHandler->GetModuleHandler(hidx); + ModuleNode *module = handler->GetASTModule(); + std::cout << "module : " << gStringPool.GetStringFromStrIdx(module->GetStrIdx()) << std::endl; + for (auto nid: mExportedDeclIds[hidx]) { + TreeNode * node = mAstOpt->GetNodeFromNodeId(nid); + std::cout << " export : " << gStringPool.GetStringFromStrIdx(node->GetStrIdx()) << " " << nid << std::endl; + } + } + } +} + +unsigned AST_XXport::GetHandleIdxFromStrIdx(unsigned stridx) { + if (mStrIdx2HandlerIdxMap.find(stridx) != mStrIdx2HandlerIdxMap.end()) { + return mStrIdx2HandlerIdxMap[stridx]; + } + return FLG_no_imported ? 0 : DEFAULTVALUE; +} + +void AST_XXport::CollectXXportInfo(unsigned hidx) { + CollectImportInfo(hidx); + CollectExportInfo(hidx); +} + +// check if node is identifier with name "default" +static bool IsDefault(TreeNode *node) { + return node->GetStrIdx() == gStringPool.GetStrIdx("default"); +} + +void AST_XXport::CollectImportInfo(unsigned hidx) { + Module_Handler *handler = mASTHandler->GetModuleHandler(hidx); + ModuleNode *module = handler->GetASTModule(); + + for (auto it : mImportNodeSets[hidx]) { + ImportNode *node = it; + TreeNode *target = GetTarget(node); + unsigned stridx = (target && target->GetStrIdx()) ? target->GetStrIdx() : module->GetStrIdx(); + XXportInfo *info = new XXportInfo(stridx, node->GetNodeId());; + + unsigned targethidx = DEFAULTVALUE;; + Module_Handler *targethandler = NULL; + ModuleNode *targetmodule = NULL; + + if (target) { + targethidx = GetHandleIdxFromStrIdx(target->GetStrIdx()); + targethandler = mASTHandler->GetModuleHandler(targethidx); + targetmodule = targethandler->GetASTModule(); + } + + for (unsigned i = 0; i < node->GetPairsNum(); i++) { + XXportAsPairNode *p = node->GetPair(i); + TreeNode *bfnode = p->GetBefore(); + TreeNode *afnode = p->GetAfter(); + MASSERT(bfnode && "before node NULL for default"); + + // import * as MM from "./M"; + // bfnode represents a module + if (p->IsEverything()) { + info->SetEverything(); + + MASSERT(target && "everything export no target"); + SetIdStrIdx2ModuleStrIdx(bfnode->GetStrIdx(), target->GetStrIdx()); + + bfnode->SetTypeId(TY_Module); + bfnode->SetTypeIdx(targetmodule->GetTypeIdx()); + + std::pair pnid(bfnode->GetNodeId(), 0); + info->mNodeIdPairs.insert(pnid); + } else { + // reformat default import + if (!p->IsDefault()) { + if (IsDefault(bfnode) ) { + p->SetIsDefault(true); + p->SetBefore(afnode); + p->SetAfter(NULL); + } + } + + bfnode = p->GetBefore(); + afnode = p->GetAfter(); + if (p->IsDefault()) { + TreeNode *exported = GetExportedDefault(targetmodule->GetStrIdx()); + if (exported) { + std::pair pnid(exported->GetNodeId(), bfnode->GetNodeId()); + info->mNodeIdPairs.insert(pnid); + TypeId tid = exported->GetTypeId(); + bfnode->SetTypeId(tid); + unsigned tidx = exported->GetTypeIdx(); + bfnode->SetTypeIdx(tidx); + } else { + NOTYETIMPL("failed to find the exported - default"); + } + } else if (afnode) { + // import bfnode as afnode + TreeNode *exported = FindExportedDecl(targethidx, bfnode->GetStrIdx()); + if (!exported) { + NOTYETIMPL("need to extract exported - bfnode M.x"); + exported = bfnode; + } + std::pair pnid(exported->GetNodeId(), afnode->GetNodeId()); + info->mNodeIdPairs.insert(pnid); + TypeId tid = exported->GetTypeId(); + unsigned tidx = exported->GetTypeIdx(); + bfnode->SetTypeId(tid); + bfnode->SetTypeIdx(tidx); + afnode->SetTypeId(tid); + afnode->SetTypeIdx(tidx); + } else if (bfnode) { + // import bfnode + TreeNode *exported = FindExportedDecl(targethidx, bfnode->GetStrIdx()); + if (!exported) { + NOTYETIMPL("need to extract exported - bfnode M.x"); + exported = bfnode; + } + std::pair pnid(exported->GetNodeId(), bfnode->GetNodeId()); + info->mNodeIdPairs.insert(pnid); + TypeId tid = exported->GetTypeId(); + unsigned tidx = exported->GetTypeIdx(); + bfnode->SetTypeId(tid); + bfnode->SetTypeIdx(tidx); + } else { + NOTYETIMPL("failed to find the exported"); + } + } + // add afnode, bfnode as a decl + if (afnode) { + AddImportedDeclIds(handler->GetHidx(), afnode->GetNodeId()); + handler->AddNodeId2DeclMap(afnode->GetNodeId(), afnode); + } + AddImportedDeclIds(handler->GetHidx(), bfnode->GetNodeId()); + handler->AddNodeId2DeclMap(bfnode->GetNodeId(), bfnode); + } + + mImports[hidx].insert(info); + } +} + +TreeNode *AST_XXport::GetIdentifier(TreeNode *node) { + switch (node->GetKind()) { + case NK_Decl: { + DeclNode *decl = static_cast(node); + node = GetIdentifier(decl->GetVar()); + break; + } + case NK_Identifier: + break; + case NK_TypeAlias: { + TypeAliasNode *ta = static_cast(node); + node = GetIdentifier(ta->GetId()); + break; + } + case NK_UserType: { + UserTypeNode *ut = static_cast(node); + node = GetIdentifier(ut->GetId()); + break; + } + default: + NOTYETIMPL("need to extract identifier"); + break; + } + return node; +} + +void AST_XXport::CollectExportInfo(unsigned hidx) { + Module_Handler *handler = mASTHandler->GetModuleHandler(hidx); + ModuleNode *module = handler->GetASTModule(); + + for (auto it : mExportNodeSets[hidx]) { + ExportNode *node = it; + TreeNode *target = GetTarget(node); + unsigned stridx = (target && target->GetStrIdx()) ? target->GetStrIdx() : module->GetStrIdx(); + XXportInfo *info = new XXportInfo(stridx, node->GetNodeId());; + + unsigned targethidx = DEFAULTVALUE; + Module_Handler *targethandler = NULL; + ModuleNode *targetmodule = NULL; + + if (target) { + targethidx = GetHandleIdxFromStrIdx(target->GetStrIdx()); + targethandler = mASTHandler->GetModuleHandler(targethidx); + targetmodule = targethandler->GetASTModule(); + } + + for (unsigned i = 0; i < node->GetPairsNum(); i++) { + XXportAsPairNode *p = node->GetPair(i); + TreeNode *bfnode = p->GetBefore(); + TreeNode *afnode = p->GetAfter(); + + // export import a = M.a + if (bfnode && bfnode->IsImport()) { + ImportNode *imp = static_cast(bfnode); + for (unsigned j = 0; j < imp->GetPairsNum(); j++) { + XXportAsPairNode *q = imp->GetPair(i); + TreeNode *bf = q->GetBefore(); + TreeNode *af = q->GetAfter(); + std::pair pnid(af->GetNodeId(), bf->GetNodeId()); + info->mNodeIdPairs.insert(pnid); + } + continue; + } + + if (p->IsEverything()) { + info->SetEverything(); + if (bfnode) { + // export * as MM from "./M"; + // bfnode represents a module + MASSERT(target && "everything export no target"); + SetIdStrIdx2ModuleStrIdx(bfnode->GetStrIdx(), target->GetStrIdx()); + + bfnode->SetTypeId(TY_Module); + bfnode->SetTypeIdx(targetmodule->GetTypeIdx()); + AddExportedDeclIds(hidx, bfnode->GetNodeId()); + } else { + // export * from "./M" + for (auto k : mExportedDeclIds[targethidx]) { + AddExportedDeclIds(hidx, k); + } + continue; + } + } + + // reformat default export + if (p->IsDefault()) { + p->SetIsRef(false); + } else if (afnode && IsDefault(afnode)) { + p->SetIsDefault(true); + p->SetBefore(bfnode); + p->SetAfter(NULL); + } + + afnode = p->GetAfter(); + bfnode = p->GetBefore(); + if (!bfnode->IsIdentifier()) { + bfnode = GetIdentifier(bfnode); + } + + unsigned exportednid = (afnode ? afnode->GetNodeId(): bfnode->GetNodeId()); + if (p->IsDefault()) { + info->mDefaultNodeId = exportednid; + } else if (mExportNodeSets[hidx].size() == 1 && node->GetPairsNum() == 1) { + info->mDefaultNodeId = bfnode->GetNodeId(); + std::pair pnid(bfnode->GetNodeId(), exportednid); + info->mNodeIdPairs.insert(pnid); + } else { + std::pair pnid(bfnode->GetNodeId(), exportednid); + info->mNodeIdPairs.insert(pnid); + } + AddExportedDeclIds(hidx, exportednid); + } + + if (info->mDefaultNodeId || info->mNodeIdPairs.size()) { + mExports[hidx].insert(info); + } else { + delete info; + } + } +} + +TreeNode *AST_XXport::GetTarget(TreeNode *node) { + TreeNode *tree = NULL; + if (node->IsImport()) { + tree = static_cast(node)->GetTarget(); + } else if (node->IsExport()) { + tree = static_cast(node)->GetTarget(); + } + return tree; +} + +// borrowed from ast2cpp +std::string AST_XXport::GetTargetFilename(unsigned hidx, TreeNode *node) { + std::string filename; + if (node && node->IsLiteral()) { + LiteralNode *lit = static_cast(node); + LitData data = lit->GetData(); + filename = AstDump::GetEnumLitData(data); + filename += ".ts"s; + if(filename.front() != '/') { + Module_Handler *handler = mASTHandler->GetModuleHandler(hidx); + ModuleNode *module = handler->GetASTModule(); + std::filesystem::path p = module->GetFilename(); + try { + p = std::filesystem::canonical(p.parent_path() / filename); + filename = p.string(); + } + catch(std::filesystem::filesystem_error const& ex) { + // Ignore std::filesystem::filesystem_error exception + // keep filename without converting it to a cannonical path + } + } + } + return filename; +} + +// set up import/export node stridx with target module file name stridx +void AST_XXport::UpdateDependency(unsigned hidx, TreeNode *node) { + TreeNode *target = GetTarget(node); + if (target) { + std::string name = GetTargetFilename(hidx, target); + + // store name's string index in node + unsigned stridx = gStringPool.GetStrIdx(name); + node->SetStrIdx(stridx); + target->SetStrIdx(stridx); + + // update handler dependency map + unsigned dep = GetHandleIdxFromStrIdx(stridx); + mHandlerIdx2DependentHandlerIdxMap[hidx].insert(dep); + + if (node->IsImport()) { + Module_Handler *handler = mASTHandler->GetModuleHandler(dep); + ModuleNode *module = handler->GetASTModule(); + + node->SetTypeId(module->GetTypeId()); + node->SetTypeIdx(module->GetTypeIdx()); + } + } +} + +unsigned AST_XXport::ExtractTargetStrIdx(TreeNode *node) { + unsigned stridx = 0; + if (node->IsField()) { + FieldNode *fld = static_cast(node); + TreeNode *upper = fld->GetUpper(); + stridx = GetModuleStrIdxFromIdStrIdx(upper->GetStrIdx()); + if (stridx) { + unsigned hidx = GetHandleIdxFromStrIdx(stridx); + Module_Handler *handler = mASTHandler->GetModuleHandler(hidx); + ModuleNode *module = handler->GetASTModule(); + upper->SetTypeId(TY_Module); + upper->SetTypeIdx(module->GetTypeIdx()); + } + } + return stridx; +} + +// hstridx is the string index of handler/module name with full path +TreeNode *AST_XXport::GetExportedDefault(unsigned hstridx) { + if (mStrIdx2HandlerIdxMap.find(hstridx) != mStrIdx2HandlerIdxMap.end()) { + unsigned hidx = GetHandleIdxFromStrIdx(hstridx); + for (auto it : mExports[hidx]) { + if (it->mDefaultNodeId) { + return mAstOpt->GetNodeFromNodeId(it->mDefaultNodeId); + } + } + } + return NULL; +} + +// hidx is the index of handler, string is the string index of identifier +TreeNode *AST_XXport::GetExportedNamedNode(unsigned hidx, unsigned stridx) { + for (auto it : mExports[hidx]) { + for (auto it1 : it->mNodeIdPairs) { + unsigned nid = it1.first; + TreeNode *node = mAstOpt->GetNodeFromNodeId(nid); + if (node->GetStrIdx() == stridx ) { + return node; + } + } + } + return NULL; +} + +// hidx is the index of handler, string is the string index of identifier +TreeNode *AST_XXport::GetExportedNodeFromImportedNode(unsigned hidx, unsigned nid) { + TreeNode *node = mAstOpt->GetNodeFromNodeId(nid); + + for (auto it : mImports[hidx]) { + if (it->mDefaultNodeId == nid) { + node = GetExportedDefault(it->mModuleStrIdx); + return node; + } + for (auto it1 : it->mNodeIdPairs) { + unsigned nid2 = it1.second; + if (nid2 == nid) { + unsigned nid1 = it1.first; + node = mAstOpt->GetNodeFromNodeId(nid1); + return node; + } + } + } + return node; +} + +ImportNode *XXportBasicVisitor::VisitImportNode(ImportNode *node) { + (void) AstVisitor::VisitImportNode(node); + mASTXXport->mImportNodeSets[mHandlerIdx].push_back(node); + + TreeNode *target = mASTXXport->GetTarget(node); + if (!target) { + // extract target info for + // import Bar = require("./Foo"); + for (unsigned i = 0; i < node->GetPairsNum(); i++) { + XXportAsPairNode *p = node->GetPair(i); + TreeNode *bfnode = p->GetBefore(); + if (bfnode && bfnode->IsLiteral()) { + LiteralNode *lit = static_cast(bfnode); + LitId id = lit->GetData().mType; + if (id == LT_StringLiteral) { + node->SetTarget(bfnode); + p->SetBefore(p->GetAfter()); + p->SetAfter(NULL); + p->SetIsDefault(true); + } + } + } + } + return node; +} + +ExportNode *XXportBasicVisitor::VisitExportNode(ExportNode *node) { + (void) AstVisitor::VisitExportNode(node); + mASTXXport->mExportNodeSets[mHandlerIdx].push_back(node); + return node; +} + +} diff --git a/src/MapleFE/astopt/src/astopt.cpp b/src/MapleFE/astopt/src/astopt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd2ab47d290cfe4fc2577c821046c192246c9ba6 --- /dev/null +++ b/src/MapleFE/astopt/src/astopt.cpp @@ -0,0 +1,119 @@ +/* +* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include "astopt.h" +#include "typetable.h" +#include "ast_handler.h" +#include "ast_xxport.h" +#include "gen_astgraph.h" +#include "gen_aststore.h" +#include "gen_astload.h" + +namespace maplefe { + +class ImportedFiles; + +AstOpt::AstOpt(AST_Handler *h, unsigned f) { + mASTHandler = h; + h->SetAstOpt(this); + mASTXXport = new AST_XXport(this, f); + mFlags = f; +} + +unsigned AstOpt::GetModuleNum() { + return mASTHandler->GetSize(); +} + +// starting point of AST +void AstOpt::ProcessAST(unsigned flags) { + // loop through module handlers + for (int i = 0; i < GetModuleNum(); i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + ModuleNode *module = handler->GetASTModule(); + + mFlags = flags; + if (mFlags & FLG_trace_3) { + std::cout << "============= in ProcessAST ===========" << std::endl; + std::cout << "srcLang : " << module->GetSrcLangString() << std::endl; + + for(unsigned i = 0; i < module->GetTreesNum(); i++) { + TreeNode *tnode = module->GetTree(i); + tnode->Dump(0); + std::cout << std::endl; + } + } + } + + // build dependency of modules + PreprocessModules(); + + for (auto handler: mHandlersInOrder) { + // basic analysis + handler->BasicAnalysis(); + + // build CFG + handler->BuildCFG(); + + // control flow analysis + handler->ControlFlowAnalysis(); + + // type inference + handler->TypeInference(); + + // data flow analysis + handler->DataFlowAnalysis(); + } + + for (auto handler: mHandlersInOrder) { + ModuleNode *module = handler->GetASTModule(); + + AstStore saveAst(module); + saveAst.StoreInAstBuf(); + } + + return; +} + +void AstOpt::PreprocessModules() { + // initialize gTypeTable with builtin types + gTypeTable.AddPrimAndBuiltinTypes(); + + // collect language keywords +#undef LANGKEYWORD +#define LANGKEYWORD(K) mLangKeywords.insert(gStringPool.GetStrIdx(#K)); +#include "lang_keywords.def" + + // scan through modules to setup mNodeId2NodeMap + BuildNodeIdToNodeVisitor visitor(this, mFlags); + + for (int i = 0; i < GetModuleNum(); i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + // fill handler index + handler->SetHidx(i); + + ModuleNode *module = handler->GetASTModule(); + // add module as type for import/export purpose + module->SetTypeId(TY_Module); + gTypeTable.AddType(module); + + visitor.SetHandler(handler); + visitor.Visit(module); + } + + // list modules according to dependency + mASTXXport->BuildModuleOrder(); +} + +} diff --git a/src/MapleFE/java/alt_tokens.spec b/src/MapleFE/autogen/alt_tokens.spec similarity index 95% rename from src/MapleFE/java/alt_tokens.spec rename to src/MapleFE/autogen/alt_tokens.spec index 831eb7a829637f416ba53a862d6cf60a54dd5bc9..26dc069662815249b01beb67ee04558a1d88bc48 100644 --- a/src/MapleFE/java/alt_tokens.spec +++ b/src/MapleFE/autogen/alt_tokens.spec @@ -17,6 +17,8 @@ // This file will be included in token_gen.cpp. // This file defines the alternative tokens of some special tokens. Please refer // shared/include/token.h for the definition of alternative tokens. +// +// Right now this is language independent {">>", 2, ">"}, {">>>", 3, ">"} diff --git a/src/MapleFE/autogen/include/auto_gen.h b/src/MapleFE/autogen/include/auto_gen.h index fc5269ec5ad24f74ddb66f6fcfb1db24ea02dd50..40da81fb2e91567b32fc3cf14c1aa1015eec459c 100644 --- a/src/MapleFE/autogen/include/auto_gen.h +++ b/src/MapleFE/autogen/include/auto_gen.h @@ -25,10 +25,8 @@ #include "iden_gen.h" #include "literal_gen.h" #include "type_gen.h" -#include "block_gen.h" #include "separator_gen.h" #include "operator_gen.h" -#include "expr_gen.h" #include "stmt_gen.h" #include "keyword_gen.h" #include "attr_gen.h" @@ -43,21 +41,23 @@ private: LiteralGen *mLitGen; TypeGen *mTypeGen; AttrGen *mAttrGen; - BlockGen *mBlockGen; SeparatorGen *mSeparatorGen; OperatorGen *mOperatorGen; KeywordGen *mKeywordGen; - ExprGen *mExprGen; StmtGen *mStmtGen; TokenGen *mTokenGen; std::vector mGenArray; SPECParser *mParser; + std::string mLang; // the language(i.e. directory) + public: AutoGen(SPECParser *p) : mParser(p) {} ~AutoGen(); + void SetLang(std::string s) {mLang = s;} + void Init(); void Run(); void BackPatch(); diff --git a/src/MapleFE/autogen/include/base_gen.h b/src/MapleFE/autogen/include/base_gen.h index 07c08121cf0da65352cb3aa6dac3d1a659c1e37f..fa8a76229fb18f00d118a955cc1836c72a657ad4 100644 --- a/src/MapleFE/autogen/include/base_gen.h +++ b/src/MapleFE/autogen/include/base_gen.h @@ -50,7 +50,7 @@ class SPECParser;; // the current type of element being read. This helps to read ')' and '+'. // // Possibly new syntax in the future also need this help. -typedef enum { +typedef enum ST_status { ST_Set, // in ( , , ) ST_Concatenate, // in E + E + E ST_Null @@ -67,7 +67,7 @@ public: FormattedBuffer mRuleTableCpp; FormattedBuffer mRuleTableHeader; - std::string mSpecFile; + std::string mSpecFile; FileWriter mHeaderFile; FileWriter mCppFile; StringPool *mStringPool; diff --git a/src/MapleFE/autogen/include/base_struct.h b/src/MapleFE/autogen/include/base_struct.h index 957810021afa54fdd7b561281947651e4cb38644..63e49b4444d3247ce8bcc7087a63338aae98ed74 100644 --- a/src/MapleFE/autogen/include/base_struct.h +++ b/src/MapleFE/autogen/include/base_struct.h @@ -37,7 +37,7 @@ class StringPool; // 2-tuple or 3 tuple. The data in each StructElem could be number, string, // string literal (those quoted with "). // -// Each type of .spec has its own definition of STRUCT and so its data in +// Each type of .spec has its own definition of STRUCT and so its data in // StructElem. So the parsing of a StructElem is left to each .spec parser. // But we do provide some common functions of parsing certain StructElem. // @@ -114,7 +114,7 @@ public: void SetName(const char *s) { mName = s; } bool Empty() {return mStructElems.size() == 0;} void Dump(); - void Sort(unsigned i); // sort by the length of i-th element which is astring + void Sort(unsigned i); // sort by the length of i-th element which is astring }; } diff --git a/src/MapleFE/autogen/include/buffer2write.h b/src/MapleFE/autogen/include/buffer2write.h index c954eda99ae061ed0b48b555877845cf42d23ff2..dcf0cf2b16686159477cabc6b9abbffb2484c32f 100644 --- a/src/MapleFE/autogen/include/buffer2write.h +++ b/src/MapleFE/autogen/include/buffer2write.h @@ -53,12 +53,12 @@ class BaseGen; // default construction of buffers. // ////////////////////////////////////////////////////////////////////////// -typedef enum { +typedef enum WriteStatus { WR_GOOD, WR_OVERSIZE }WriteStatus; -typedef enum { +typedef enum SimpleBufferType { SB_Line, SB_Rect }SimpleBufferType; @@ -75,7 +75,7 @@ public: public: SimpleBuffer(unsigned ind) : mIndentation(ind) {} - ~SimpleBuffer() {} + virtual ~SimpleBuffer() = default; virtual WriteStatus AddChar(const char) = 0; virtual WriteStatus AddString(const char*) = 0; @@ -86,7 +86,7 @@ public: virtual bool CurrentLineEmpty() = 0; }; - + // A single line buffer, over MAX_LINE_LIMIT. Theoritically the LineBuffer // can extend to unlimited length. class LineBuffer : public SimpleBuffer { @@ -127,7 +127,7 @@ class RectBuffer : public SimpleBuffer { public: unsigned mUsed; // a LINES_PER_BLOCK bitmap telling which lines are used. char mData[MAX_LINE_LIMIT * LINES_PER_BLOCK]; - char *mCurrLine; + char *mCurrLine; unsigned mCurrLineSize; // how many char-s in the line public: @@ -161,7 +161,7 @@ public: union { SimpleBuffer *mSimple; FormattedBuffer *mFormatted; - }mData; + }mData; bool mIsSimple; public: @@ -194,10 +194,10 @@ public: ///////////////////////////////////////////////////////////////////////////// // [FormattedBuffer] // -// A formatted buffer is composed of a set of SimpleBuffer or nested +// A formatted buffer is composed of a set of SimpleBuffer or nested // formatted buffer. Its goal is to provide interface for buffer users. // The inside details of the OneBuffer is protected. -// +// // The nested FormattedBuffer is never modified by the parent FormattedBuffer. // So the children should be fixed before added into the parent. @@ -216,7 +216,7 @@ public: FormattedBuffer(unsigned ind = 0, bool iscomment = false); ~FormattedBuffer(); -public: +public: void AddNestedBuffer(FormattedBuffer *); char* NewLine(); @@ -312,7 +312,7 @@ public: // FunctionBuffer // // A function has three buffers. // // 1) Declaration in .h file // -// 2) Header in .cpp file // +// 2) Header in .cpp file // // 3) Body in .cpp file // // Here is an example: // // void foo (int a) <-- Header // @@ -332,7 +332,7 @@ public: void AddReturnType(const char*); void AddFunctionName(const char*); - void AddParameter(const char* type, const char *name, bool end = false); + void AddParameter(const char* type, const char *name, bool end = false); ScopedBuffer* GetBody() { return &mBody; } }; diff --git a/src/MapleFE/autogen/include/exprbuffer.h b/src/MapleFE/autogen/include/exprbuffer.h index 6fd37327fac5701ac0c9efe4869d7e84a983b036..da0b7133769f3e62486563c43c6bb10a0a612f32 100644 --- a/src/MapleFE/autogen/include/exprbuffer.h +++ b/src/MapleFE/autogen/include/exprbuffer.h @@ -99,8 +99,8 @@ public: // the following functions are used for un-determined number of children. void AllocChildren(unsigned i, ExprBuffer *buf); ExprNode* GetChild(unsigned index); -}; - +}; + class ExprBuffer { private: char *mData; @@ -126,7 +126,7 @@ public: public: ExprBuffer(); - ~ExprBuffer(); + ~ExprBuffer(); // write the expr to the buffer, mData, in text format void Write2Buffer(); diff --git a/src/MapleFE/autogen/include/operator_gen.h b/src/MapleFE/autogen/include/operator_gen.h index 3d3e902359db79540ad00c1c62e172812deb3811..943106cfa475ab754641a0bb972aea16611fa0ec 100644 --- a/src/MapleFE/autogen/include/operator_gen.h +++ b/src/MapleFE/autogen/include/operator_gen.h @@ -14,7 +14,7 @@ */ //////////////////////////////////////////////////////////////////////// // Operator Generation -// The output of this Operator Generation is a table in gen_operator.cpp +// The output of this Operator Generation is a table in gen_operator.cpp // // OprTableEntry OprTable[OPR_Null] = { // {"xxx", OPR_Xxx}, @@ -37,7 +37,7 @@ namespace maplefe { // For each operator, it has three parts involved in the generation. // 1. OprId: Used inside autogen, connection between LANGUAGE and // shared/supported.h files -// 2. Name: Name of OPR ID, to be generated in gen_operator.cpp +// 2. Name: Name of OPR ID, to be generated in gen_operator.cpp // 4. Text: LANGUAGE syntax text, to be in gen_operator.cpp // The SUPPORTED operator and their name. diff --git a/src/MapleFE/autogen/include/rule.h b/src/MapleFE/autogen/include/rule.h index 607d8c9369aa116bbc5ec45d62cb08b72962ea73..5c23c5ee007c4da4f34ee3fee521d30941e9ecf7 100644 --- a/src/MapleFE/autogen/include/rule.h +++ b/src/MapleFE/autogen/include/rule.h @@ -30,15 +30,16 @@ namespace maplefe { class Rule; class StructData; -typedef enum { +typedef enum RuleOp { RO_Oneof, // one of (...) RO_Zeroormore, // zero or more of (...) RO_Zeroorone, // zero or one ( ... ) RO_Concatenate,// Elem + Elem + Elem + RO_ASI, // Typescript/Javascript semicolon checking RO_Null } RuleOp; -typedef enum { +typedef enum ElemType { ET_Char, // It's a literal elements, char, 'c'. ET_String, // It's a literal elements, string "abc". ET_Rule, // It's rule diff --git a/src/MapleFE/autogen/include/rule_gen.h b/src/MapleFE/autogen/include/rule_gen.h index da0cd43cdb485f470b88582dce370eaa3609709b..c68109a69bfcc881aee807046389d0a426b5310c 100644 --- a/src/MapleFE/autogen/include/rule_gen.h +++ b/src/MapleFE/autogen/include/rule_gen.h @@ -66,7 +66,7 @@ public: void PatchTokenOnElem(RuleElem*); void PatchToken(); - void Generate(); + void Generate(); }; } diff --git a/src/MapleFE/autogen/include/separator_gen.h b/src/MapleFE/autogen/include/separator_gen.h index 31597f55668e43e87462935c64fd624223dde7bc..e5b4e3b77a525fe97550e3ce02cafbbf3e3907d3 100644 --- a/src/MapleFE/autogen/include/separator_gen.h +++ b/src/MapleFE/autogen/include/separator_gen.h @@ -14,7 +14,7 @@ */ //////////////////////////////////////////////////////////////////////// // Separator Generation -// The output of this Separator Generation is a table in gen_separator.cpp +// The output of this Separator Generation is a table in gen_separator.cpp // // SepTableEntry SepTable[SEP_Null] = { // {"xxx", SEP_Xxx}, @@ -45,7 +45,7 @@ namespace maplefe { // For each separator, it has three parts involved in the generation. // 1. SepId: Used inside autogen, connection between LANGUAGE and SUPPORTED // .spec files -// 2. Name: Name of SEP_ID, to be generated in gen_separator.cpp +// 2. Name: Name of SEP_ID, to be generated in gen_separator.cpp // 4. Keyword: LANGUAGE syntax text, to be in gen_separator.cpp // The SUPPORTED separator and their name. diff --git a/src/MapleFE/autogen/include/spec_keywords.h b/src/MapleFE/autogen/include/spec_keywords.h index 9ede40d1238ab3899900a16802a5a9fa522a5d27..8d944cf257d7e764a79f19eb0b6d0fec9d9dc634 100644 --- a/src/MapleFE/autogen/include/spec_keywords.h +++ b/src/MapleFE/autogen/include/spec_keywords.h @@ -16,6 +16,7 @@ KEYWORD(rule, Rule) KEYWORD(ONEOF, Oneof) KEYWORD(ZEROORONE, Zeroorone) KEYWORD(ZEROORMORE, Zeroormore) +KEYWORD(ASI, ASI) KEYWORD(STRUCT, Struct) KEYWORD(func, Func) KEYWORD(attr, Attr) diff --git a/src/MapleFE/autogen/include/spec_lexer.h b/src/MapleFE/autogen/include/spec_lexer.h index cd5d2fbdefedb9f6e5df976546704304c47ffa67..db32e526eb897155b06cb3d7c317a39612aa5daf 100644 --- a/src/MapleFE/autogen/include/spec_lexer.h +++ b/src/MapleFE/autogen/include/spec_lexer.h @@ -107,7 +107,7 @@ class SPECLexer { return _thekind; } - char *GetLine() const { return line; } + char *GetLine() const { return line; } int GetLineNum() const { return _linenum; } int GetCuridx() const { return curidx; } const std::string &GetTheName() const { return thename; } diff --git a/src/MapleFE/autogen/include/spec_parser.h b/src/MapleFE/autogen/include/spec_parser.h index cc2ac3ebc668874d1205f9f135f5bee4aacb6ad7..af1754b1311d87c0dea4b954adb8f1d094b9b1dc 100644 --- a/src/MapleFE/autogen/include/spec_parser.h +++ b/src/MapleFE/autogen/include/spec_parser.h @@ -69,7 +69,7 @@ public: bool ParseStruct(); bool ParseStructElements(); bool ParseElemData(StructElem *elem); - + bool ParseType(); bool ParseAttr(); diff --git a/src/MapleFE/autogen/include/spec_tokens.h b/src/MapleFE/autogen/include/spec_tokens.h index 666e52677eca583ecd50132776a6bfbe24893f23..8d8cb19cfbf3ceab0653be4a6de226e2bcf47e6d 100644 --- a/src/MapleFE/autogen/include/spec_tokens.h +++ b/src/MapleFE/autogen/include/spec_tokens.h @@ -14,7 +14,7 @@ */ #ifndef SPERC_TOKENS_H #define SPERC_TOKENS_H -typedef enum { +typedef enum SPECTokenKind { SPECTK_Invalid, // keywords #define KEYWORD(S,T) SPECTK_##T, diff --git a/src/MapleFE/autogen/reserved.spec b/src/MapleFE/autogen/reserved.spec index b3bb95f7aaa8715527a8f3e76c4d3b8141018e5d..cd258684dc2ad9b79fe06683a1d021930fe3fa98 100644 --- a/src/MapleFE/autogen/reserved.spec +++ b/src/MapleFE/autogen/reserved.spec @@ -22,19 +22,21 @@ rule CHAR : ONEOF('a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',' # DIGIT refers to the 10 digits rule DIGIT : ONEOF('0', '1', '2', '3', '4', '5', '6', '7', '8', '9') -# The ASCII character exclude ", ', and \ -# -# [NOTE] Becareful of ' over here. It's duplicated in ESCAPE as '\' + '''. There is a reason. -# When the lexer read a string "doesn't", which is wrong since Java request ' be escaped but -# many code does NOT escape, the string in memory is "doesn't" too. The system Reading function -# which is in C doesn't escape '. So I duplicate here to catch this case. -# -# Please see test case java2mpl/literal-string-2.java for example. -# -rule ASCII : ONEOF(' ', '!', '#', '$', '%', ''', '&', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', CHAR, DIGIT) +# The ASCII character exclude ", ', \, and \n +rule ASCII : ONEOF(' ', '!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', CHAR, DIGIT) # About the handling of escape character in autogen, xx_gen.cpp/h, and stringutil.cpp # please refer to the comments in StringToValue::StringToString() in stringutil.cpp rule ESCAPE : ONEOF('\' + 'b', '\' + 't', '\' + 'n', '\' + 'f', '\' + 'r', '\' + '"', '\' + ''', '\' + '\') rule HEXDIGIT : ONEOF(DIGIT, 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F') + +# irregular char like \n, \, DEL, etc. will be handled in lexer.cpp if some language allows them in string literal. +rule IRREGULAR_CHAR : "this_is_for_fake_rule" + +# Below are special rules handled in lexer.cpp. Since it'll be in lexer code, it means +# it's a shared rule of all languages. It has to be in reserved.spec. +rule UTF8 : "this_is_for_fake_rule" +rule TemplateLiteral : "this_is_for_fake_rule" +rule RegularExpression : "this_is_for_fake_rule" +rule NoLineTerminator : "this_is_for_fake_rule" diff --git a/src/MapleFE/autogen/src/Makefile b/src/MapleFE/autogen/src/Makefile index 86927f0b36c18b1eb363aeebd544dea2587d4499..7297ffdb8d3decb0a97a0bb9d936a02390535a3d 100644 --- a/src/MapleFE/autogen/src/Makefile +++ b/src/MapleFE/autogen/src/Makefile @@ -1,8 +1,22 @@ +# Copyright (C) [2020-2021] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + include ../../Makefile.in # create build first BUILD=$(BUILDDIR)/autogen -$(shell $(MKDIR_P) $(BUILD)) +$(shell $(MKDIR_P) $(BUILD) $(BUILDDIR)/$(SRCLANG) $(BUILDDIR)/gen) SHAREDSRC := token.cpp mempool.cpp stringmap.cpp stringpool.cpp write2file.cpp SRC := $(wildcard *.cpp) $(SHAREDSRC) @@ -14,33 +28,24 @@ LIBOBJS :=$(patsubst $(BUILD)/main.o,,$(OBJS)) DEPS := $(foreach dep, $(DEP), $(BUILD)/$(dep)) INCLUDES := -I $(MAPLEFE_ROOT)/autogen/include \ - -I $(MAPLEFE_ROOT)/shared/include \ - -I $(MAPLEFE_ROOT)/java/include \ - -I $(MAPLEFE_ROOT)/java + -I $(MAPLEFE_ROOT)/autogen \ + -I $(MAPLEFE_ROOT)/shared/include + +SPECS := $(wildcard $(MAPLEFE_ROOT)/$(SRCLANG)/*.spec) TARGET = autogen AUTOGENLIB = autogen.a .PHONY: all +all: $(BUILD)/$(TARGET) -all: $(TARGET) - -$(TARGET) : $(AUTOGENLIB) +$(BUILD)/$(TARGET) : $(BUILD)/$(AUTOGENLIB) $(LD) -o $(BUILD)/$(TARGET) $(BUILD)/main.o $(BUILD)/$(AUTOGENLIB) - @ln -sf $(MAPLEFE_ROOT)/java/identifier.spec $(BUILD)/identifier.spec - @ln -sf $(MAPLEFE_ROOT)/java/literal.spec $(BUILD)/literal.spec - @ln -sf $(MAPLEFE_ROOT)/java/operator.spec $(BUILD)/operator.spec - @ln -sf $(MAPLEFE_ROOT)/java/separator.spec $(BUILD)/separator.spec - @ln -sf $(MAPLEFE_ROOT)/java/keyword.spec $(BUILD)/keyword.spec - @ln -sf $(MAPLEFE_ROOT)/java/type.spec $(BUILD)/type.spec - @ln -sf $(MAPLEFE_ROOT)/java/attr.spec $(BUILD)/attr.spec - @ln -sf $(MAPLEFE_ROOT)/java/block.spec $(BUILD)/block.spec - @ln -sf $(MAPLEFE_ROOT)/java/expr.spec $(BUILD)/expr.spec - @ln -sf $(MAPLEFE_ROOT)/java/stmt.spec $(BUILD)/stmt.spec - @ln -sf $(MAPLEFE_ROOT)/autogen/reserved.spec $(BUILD)/reserved.spec - -$(AUTOGENLIB) : $(OBJS) + (cd $(BUILD); ./$(TARGET) $(SRCLANG)) + (cd $(MAPLEFE_ROOT); ./scripts/maplefe-autogen.py) + +$(BUILD)/$(AUTOGENLIB) : $(OBJS) /usr/bin/ar rcs $(BUILD)/$(AUTOGENLIB) $(LIBOBJS) -include $(DEPS) @@ -50,24 +55,15 @@ vpath %.cpp $(MAPLEFE_ROOT)/shared/src vpath %.o $(BUILD) vpath %.d $(BUILD) -ifeq ($(LANG), java) -CXXFLAGS := $(CXXFLAGS) -I ../java/ -endif - #Pattern Rules $(BUILD)/%.o : %.cpp $(BUILD)/%.d $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ -$(BUILD)/%.d : %.cpp +$(BUILD)/%.d : %.cpp $(SPECS) @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $< > $@ @mv -f $(BUILD)/$*.d $(BUILD)/$*.d.tmp @sed -e 's|.*:|$(BUILD)/$*.o:|' < $(BUILD)/$*.d.tmp > $(BUILD)/$*.d @rm -f $(BUILD)/$*.d.tmp - -#.cpp.o: -# $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $*.cpp -o $(BUILD)/$*.o -# $(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $*.cpp > $(BUILD)/$*.d - clean: rm -rf $(BUILD) diff --git a/src/MapleFE/autogen/src/all_supported.cpp b/src/MapleFE/autogen/src/all_supported.cpp index 66ebbdbf2f11dd1d7544189c7a7143964eb40cb1..5ef17f9564e15a043cb16ddd60c1b3567d6cfcf3 100644 --- a/src/MapleFE/autogen/src/all_supported.cpp +++ b/src/MapleFE/autogen/src/all_supported.cpp @@ -22,7 +22,9 @@ namespace maplefe { ////////////////////////////////////////////////////////////////////// #undef TYPE +#undef PRIMTYPE #define TYPE(T) {#T, TY_##T}, +#define PRIMTYPE(T) {#T, TY_##T}, TypeMapping TypesSupported[TY_NA] = { #include "supported_types.def" }; @@ -36,7 +38,9 @@ TypeId FindTypeIdLangIndep(const std::string &s) { } #undef TYPE +#undef PRIMTYPE #define TYPE(T) case TY_##T: return #T; +#define PRIMTYPE(T) case TY_##T: return #T; char *GetTypeString(TypeId tid) { switch (tid) { #include "supported_types.def" @@ -83,7 +87,7 @@ LiteralSuppStruct LiteralsSupported[LT_NA] = { #include "supported_literals.def" }; -// s : the name +// s : the name // return the LitId LitId FindLiteralId(const std::string &s) { for (unsigned u = 0; u < LT_NA; u++) { diff --git a/src/MapleFE/autogen/src/attr_gen.cpp b/src/MapleFE/autogen/src/attr_gen.cpp index a2c2cc963f35afa55e0aecac3f5d0c013710fdef..a311fddab876c1337d348ad42880acdfcb2b9b1e 100644 --- a/src/MapleFE/autogen/src/attr_gen.cpp +++ b/src/MapleFE/autogen/src/attr_gen.cpp @@ -66,29 +66,28 @@ const std::string AttrGen::EnumNextElem(){ ///////////////////////////////////////////////////////////////////// void AttrGen::Generate() { - GenHeaderFile(); GenCppFile(); } -void AttrGen::GenHeaderFile() { - mHeaderFile.WriteOneLine("#ifndef __ATTR_GEN_H__", 22); - mHeaderFile.WriteOneLine("#define __ATTR_GEN_H__", 22); - mHeaderFile.WriteOneLine("namespace maplefe {", 19); - mHeaderFile.WriteOneLine("extern AttrKeyword AttrKeywordTable[ATTR_NA];", 45); - mHeaderFile.WriteOneLine("}", 1); - mHeaderFile.WriteOneLine("#endif", 6); -} - void AttrGen::GenCppFile() { mCppFile.WriteOneLine("#include \"common_header_autogen.h\"", 34); mCppFile.WriteOneLine("namespace maplefe {", 19); TableBuffer tb; - tb.Generate(this, "AttrKeyword AttrKeywordTable[ATTR_NA] = {"); + std::string s = "AttrKeyword AttrKeywordTable["; + std::string num = std::to_string(mAttrs.size()); + s += num; + s += "] = {"; + tb.Generate(this, s); mCppFile.WriteFormattedBuffer(&tb); mCppFile.WriteOneLine("};", 2); + + // generate the table size + s = "unsigned AttrKeywordTableSize = "; + s += num; + s += ";"; + mCppFile.WriteOneLine(s.c_str(), s.size()); + mCppFile.WriteOneLine("}", 1); } } - - diff --git a/src/MapleFE/autogen/src/auto_gen.cpp b/src/MapleFE/autogen/src/auto_gen.cpp index e53abeb62264e6f43588277634b417167e3b8661..d2baba06127bf93fbbfc9cd9d1a60b500a4a6542 100644 --- a/src/MapleFE/autogen/src/auto_gen.cpp +++ b/src/MapleFE/autogen/src/auto_gen.cpp @@ -62,52 +62,9 @@ FileWriter *gSummaryCppFile; unsigned gRuleTableNum; std::vector gTopRules; -static void WriteSummaryHFile() { - gSummaryHFile->WriteOneLine("#ifndef __DEBUG_GEN_H__", 23); - gSummaryHFile->WriteOneLine("#define __DEBUG_GEN_H__", 23); - gSummaryHFile->WriteOneLine("#include \"ruletable.h\"", 22); - gSummaryHFile->WriteOneLine("#include \"succ_match.h\"", 23); - gSummaryHFile->WriteOneLine("#include ", 17); - gSummaryHFile->WriteOneLine("namespace maplefe {", 19); - gSummaryHFile->WriteOneLine("typedef struct {", 16); - gSummaryHFile->WriteOneLine(" const RuleTable *mAddr;", 25); - gSummaryHFile->WriteOneLine(" const char *mName;", 25); - gSummaryHFile->WriteOneLine(" unsigned mIndex;", 26); - gSummaryHFile->WriteOneLine("}RuleTableSummary;", 18); - gSummaryHFile->WriteOneLine("extern RuleTableSummary gRuleTableSummarys[];", 45); - gSummaryHFile->WriteOneLine("extern unsigned RuleTableNum;", 29); - gSummaryHFile->WriteOneLine("extern const char* GetRuleTableName(const RuleTable*);", 54); - - std::string s = "extern std::vector gFailed["; - s += std::to_string(gRuleTableNum); - s += "];"; - gSummaryHFile->WriteOneLine(s.c_str(), s.size()); - - // Write SuccMatch array - s = "class SuccMatch;"; - gSummaryHFile->WriteOneLine(s.c_str(), s.size()); - - s = "extern SuccMatch gSucc["; - s += std::to_string(gRuleTableNum); - s += "];"; - gSummaryHFile->WriteOneLine(s.c_str(), s.size()); - - // Write Top rules - s = "extern unsigned gTopRulesNum;"; - gSummaryHFile->WriteOneLine(s.c_str(), s.size()); - - s = "extern RuleTable* gTopRules["; - s += std::to_string(gTopRules.size()); - s += "];"; - gSummaryHFile->WriteOneLine(s.c_str(), s.size()); - - gSummaryHFile->WriteOneLine("}", 1); - gSummaryHFile->WriteOneLine("#endif", 6); -} - // write the beginning part of summary file static void PrepareSummaryCppFile() { - gSummaryCppFile->WriteOneLine("#include \"gen_summary.h\"", 24); + gSummaryCppFile->WriteOneLine("#include \"rule_summary.h\"", 25); gSummaryCppFile->WriteOneLine("#include \"common_header_autogen.h\"", 34); gSummaryCppFile->WriteOneLine("namespace maplefe {", 19); gSummaryCppFile->WriteOneLine("RuleTableSummary gRuleTableSummarys[] = {", 41); @@ -130,7 +87,7 @@ static void FinishSummaryCppFile() { gSummaryCppFile->WriteOneLine(" return NULL;", 14); gSummaryCppFile->WriteOneLine("}", 1); - std::string s = "std::vector gFailed["; + std::string s = "BitVector gFailed["; s += std::to_string(gRuleTableNum); s += "];"; gSummaryCppFile->WriteOneLine(s.c_str(), s.size()); @@ -167,85 +124,96 @@ static void FinishSummaryCppFile() { /////////////////////////////////////////////////////////////////////////////////////// void AutoGen::Init() { - std::string lang_path_header("../../java/include/"); - std::string lang_path_cpp("../../java/src/"); + std::string lang_path("../gen/"); - std::string summary_file_name = lang_path_cpp + "gen_summary.cpp"; + std::string summary_file_name = lang_path + "gen_summary.cpp"; gSummaryCppFile = new FileWriter(summary_file_name); - summary_file_name = lang_path_header + "gen_summary.h"; + summary_file_name = lang_path + "gen_summary.h"; gSummaryHFile = new FileWriter(summary_file_name); gRuleTableNum = 0; PrepareSummaryCppFile(); - std::string hFile = lang_path_header + "gen_reserved.h"; - std::string cppFile = lang_path_cpp + "gen_reserved.cpp"; - mReservedGen = new ReservedGen("reserved.spec", hFile.c_str(), cppFile.c_str()); + std::string hFile = lang_path + "gen_reserved.h"; + std::string cppFile = lang_path + "gen_reserved.cpp"; + mReservedGen = new ReservedGen("../../../autogen/reserved.spec", hFile.c_str(), cppFile.c_str()); mReservedGen->SetReserved(mReservedGen); mGenArray.push_back(mReservedGen); - hFile = lang_path_header + "gen_iden.h"; - cppFile = lang_path_cpp + "gen_iden.cpp"; - mIdenGen = new IdenGen("identifier.spec", hFile.c_str(), cppFile.c_str()); + hFile = lang_path + "gen_iden.h"; + cppFile = lang_path + "gen_iden.cpp"; + std::string specFile = "../../../"; + specFile += mLang; + specFile += "/identifier.spec"; + mIdenGen = new IdenGen(specFile.c_str(), hFile.c_str(), cppFile.c_str()); mIdenGen->SetReserved(mReservedGen); mGenArray.push_back(mIdenGen); - hFile = lang_path_header + "gen_literal.h"; - cppFile = lang_path_cpp + "gen_literal.cpp"; - mLitGen = new LiteralGen("literal.spec", hFile.c_str(), cppFile.c_str()); + hFile = lang_path + "gen_literal.h"; + cppFile = lang_path + "gen_literal.cpp"; + specFile = "../../../"; + specFile += mLang; + specFile += "/literal.spec"; + mLitGen = new LiteralGen(specFile.c_str(), hFile.c_str(), cppFile.c_str()); mLitGen->SetReserved(mReservedGen); mGenArray.push_back(mLitGen); - hFile = lang_path_header + "gen_type.h"; - cppFile = lang_path_cpp + "gen_type.cpp"; - mTypeGen = new TypeGen("type.spec", hFile.c_str(), cppFile.c_str()); + hFile = lang_path + "gen_type.h"; + cppFile = lang_path + "gen_type.cpp"; + specFile = "../../../"; + specFile += mLang; + specFile += "/type.spec"; + mTypeGen = new TypeGen(specFile.c_str(), hFile.c_str(), cppFile.c_str()); mTypeGen->SetReserved(mReservedGen); mGenArray.push_back(mTypeGen); - hFile = lang_path_header + "gen_attr.h"; - cppFile = lang_path_cpp + "gen_attr.cpp"; - mAttrGen = new AttrGen("attr.spec", hFile.c_str(), cppFile.c_str()); + hFile = lang_path + "gen_attr.h"; + cppFile = lang_path + "gen_attr.cpp"; + specFile = "../../../"; + specFile += mLang; + specFile += "/attr.spec"; + mAttrGen = new AttrGen(specFile.c_str(), hFile.c_str(), cppFile.c_str()); mAttrGen->SetReserved(mReservedGen); mGenArray.push_back(mAttrGen); - hFile = lang_path_header + "gen_block.h"; - cppFile = lang_path_cpp + "gen_block.cpp"; - mBlockGen = new BlockGen("block.spec", hFile.c_str(), cppFile.c_str()); - mBlockGen->SetReserved(mReservedGen); - mGenArray.push_back(mBlockGen); - - hFile = lang_path_header + "gen_separator.h"; - cppFile = lang_path_cpp + "gen_separator.cpp"; - mSeparatorGen = new SeparatorGen("separator.spec", hFile.c_str(), cppFile.c_str()); + hFile = lang_path + "gen_separator.h"; + cppFile = lang_path + "gen_separator.cpp"; + specFile = "../../../"; + specFile += mLang; + specFile += "/separator.spec"; + mSeparatorGen = new SeparatorGen(specFile.c_str(), hFile.c_str(), cppFile.c_str()); mSeparatorGen->SetReserved(mReservedGen); mGenArray.push_back(mSeparatorGen); - hFile = lang_path_header + "gen_operator.h"; - cppFile = lang_path_cpp + "gen_operator.cpp"; - mOperatorGen = new OperatorGen("operator.spec", hFile.c_str(), cppFile.c_str()); + hFile = lang_path + "gen_operator.h"; + cppFile = lang_path + "gen_operator.cpp"; + specFile = "../../../"; + specFile += mLang; + specFile += "/operator.spec"; + mOperatorGen = new OperatorGen(specFile.c_str(), hFile.c_str(), cppFile.c_str()); mOperatorGen->SetReserved(mReservedGen); mGenArray.push_back(mOperatorGen); - hFile = lang_path_header + "gen_keyword.h"; - cppFile = lang_path_cpp + "gen_keyword.cpp"; - mKeywordGen = new KeywordGen("keyword.spec", hFile.c_str(), cppFile.c_str()); + hFile = lang_path + "gen_keyword.h"; + cppFile = lang_path + "gen_keyword.cpp"; + specFile = "../../../"; + specFile += mLang; + specFile += "/keyword.spec"; + mKeywordGen = new KeywordGen(specFile.c_str(), hFile.c_str(), cppFile.c_str()); mKeywordGen->SetReserved(mReservedGen); mGenArray.push_back(mKeywordGen); - hFile = lang_path_header + "gen_expr.h"; - cppFile = lang_path_cpp + "gen_expr.cpp"; - mExprGen = new ExprGen("expr.spec", hFile.c_str(), cppFile.c_str()); - mExprGen->SetReserved(mReservedGen); - mGenArray.push_back(mExprGen); - - hFile = lang_path_header + "gen_stmt.h"; - cppFile = lang_path_cpp + "gen_stmt.cpp"; - mStmtGen = new StmtGen("stmt.spec", hFile.c_str(), cppFile.c_str()); + hFile = lang_path + "gen_stmt.h"; + cppFile = lang_path + "gen_stmt.cpp"; + specFile = "../../../"; + specFile += mLang; + specFile += "/stmt.spec"; + mStmtGen = new StmtGen(specFile.c_str(), hFile.c_str(), cppFile.c_str()); mStmtGen->SetReserved(mReservedGen); mGenArray.push_back(mStmtGen); - hFile = lang_path_header + "gen_token.h"; - cppFile = lang_path_cpp + "gen_token.cpp"; + hFile = lang_path + "gen_token.h"; + cppFile = lang_path + "gen_token.cpp"; mTokenGen = new TokenGen(hFile.c_str(), cppFile.c_str()); mTokenGen->SetReserved(mReservedGen); mGenArray.push_back(mTokenGen); @@ -304,7 +272,6 @@ void AutoGen::Gen() { gen->Generate(); } - WriteSummaryHFile(); FinishSummaryCppFile(); } diff --git a/src/MapleFE/autogen/src/base_gen.cpp b/src/MapleFE/autogen/src/base_gen.cpp index 2bad09f17e5d1bc9b9b94e847464b308fd6bcf2a..23f00799aaf9469b78a149295a79ae3073a116a3 100644 --- a/src/MapleFE/autogen/src/base_gen.cpp +++ b/src/MapleFE/autogen/src/base_gen.cpp @@ -81,8 +81,8 @@ BaseGen::~BaseGen() { } Rule *BaseGen::AddLiteralRule(std::string rulename) { - Rule *rule = NULL; - if (rule = FindRule(rulename)) { + Rule *rule = FindRule(rulename); + if (rule) { return rule; } diff --git a/src/MapleFE/autogen/src/block_gen.cpp b/src/MapleFE/autogen/src/block_gen.cpp deleted file mode 100644 index 365f093ad106fb1db90569ae08993eb7be8508bd..0000000000000000000000000000000000000000 --- a/src/MapleFE/autogen/src/block_gen.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. -* -* OpenArkFE is licensed under the Mulan PSL v2. -* You can use this software according to the terms and conditions of the Mulan PSL v2. -* You may obtain a copy of Mulan PSL v2 at: -* -* http://license.coscl.org.cn/MulanPSL2 -* -* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -* FIT FOR A PARTICULAR PURPOSE. -* See the Mulan PSL v2 for more details. -*/ -#include "block_gen.h" - -namespace maplefe { - -void BlockGen::Generate() { - GenRuleTables(); - GenHeaderFile(); - GenCppFile(); -} - -void BlockGen::GenHeaderFile() { - mHeaderFile.WriteOneLine("#ifndef __BLOCK_GEN_H__", 23); - mHeaderFile.WriteOneLine("#define __BLOCK_GEN_H__", 23); - mHeaderFile.WriteOneLine("namespace maplefe {", 19); - - // generate the rule tables - mHeaderFile.WriteFormattedBuffer(&mRuleTableHeader); - - mHeaderFile.WriteOneLine("}", 1); - mHeaderFile.WriteOneLine("#endif", 6); -} - -void BlockGen::GenCppFile() { - mCppFile.WriteOneLine("#include \"common_header_autogen.h\"", 34); - mCppFile.WriteOneLine("namespace maplefe {", 19); - // generate the rule tables - mCppFile.WriteFormattedBuffer(&mRuleTableCpp); - mCppFile.WriteOneLine("}", 1); -} -} - - diff --git a/src/MapleFE/autogen/src/buffer2write.cpp b/src/MapleFE/autogen/src/buffer2write.cpp index 7381a69168343728306b0d16597effe67009cfa3..17d7bb7be28966ac0755a67eda9f9b526b4335e1 100644 --- a/src/MapleFE/autogen/src/buffer2write.cpp +++ b/src/MapleFE/autogen/src/buffer2write.cpp @@ -102,7 +102,7 @@ WriteStatus LineBuffer::AddInteger(int i) { unsigned digits = 0; if (i < 0) { digits = 1; - } + } digits += NumDigits(i); @@ -166,12 +166,12 @@ char* RectBuffer::GetNextAvailLine() { if (CurrentLineEmpty()) return mCurrLine; - + unsigned mask = (1 << LINES_PER_BLOCK) - 1; unsigned line = (mUsed & mask) + 1; unsigned log2line = (unsigned)log2(line); char *addr = mData + MAX_LINE_LIMIT * log2line; - mUsed = mUsed | line; + mUsed = mUsed | line; mCurrLine = addr; mCurrLineSize = 0; @@ -212,7 +212,7 @@ WriteStatus RectBuffer::AddInteger(int i) { // take '-' into account. if (i < 0) { digits = 1; - } + } digits += NumDigits(i); left -= digits; @@ -238,7 +238,7 @@ WriteStatus RectBuffer::AddString(const char *str){ // std::string data(indentation); // data = data + str; // str = data.c_str(); - + char *pos = mCurrLine + mCurrLineSize; unsigned left = MAX_LINE_LIMIT - mCurrLineSize; unsigned len = strlen(str); @@ -404,7 +404,7 @@ char* FormattedBuffer::NewLine() { // default constructor of OneBuffer will allocate a new RectBuffer ob = NewOneBuffer(); } - return ob->GetNextAvailLine(); + return ob->GetNextAvailLine(); } // Open a new line for comment, return the addr of the line. @@ -473,7 +473,7 @@ void FormattedBuffer::AddStringWholeLine(const char *str){ void FormattedBuffer::AddNestedBuffer(FormattedBuffer *nested) { OneBuffer *ob = new OneBuffer(nested); mBuffers.push_back(ob); - return; + return; } // wipe existing data, fill with whitespace. @@ -490,7 +490,7 @@ void FormattedBuffer::ClearLine(char *line) { // the enum structure will have the following pattern. The following is // for Separator. -// typedef enum { +// typedef enum SepId { // SEP_Xxx, // ... // SEP_Null @@ -508,21 +508,23 @@ void EnumBuffer::Generate(BaseGen *bg, const char *last_item){ while(!bg->EnumEnd()) { NewLine(); std::string elem = bg->EnumNextElem(); - if (!bg->EnumEnd() || last_item) - if (!elem.size()) + if (!bg->EnumEnd() || last_item) { + if (!elem.size()) { elem = ","; - else + } else { elem = elem + ","; + } + } AddString(elem); - } + } NewLine(); AddString(last_item); - + DecIndent(); const std::string name = bg->EnumName(); std::string s = "}" + name + ";"; NewOneBuffer(s.size(), true); // a separate LineBuffer - AddString(s); + AddString(s); return; } @@ -596,13 +598,15 @@ void TableBuffer::Generate(BaseGen *bg, const std::string decl){ while(!bg->EnumEnd()) { NewLine(); std::string elem = bg->EnumNextElem(); - if (!bg->EnumEnd()) - if (!elem.size()) + if (!bg->EnumEnd()) { + if (!elem.size()) { elem = ","; - else + } else { elem = elem + ","; + } + } AddString(elem); - } + } DecIndent(); return; diff --git a/src/MapleFE/autogen/src/exprbuffer.cpp b/src/MapleFE/autogen/src/exprbuffer.cpp index 4425cc7d0a178b4193ec69b8f44a97060bc9ff49..507ad149840db83a11387fb5c97d6ff5682384e3 100644 --- a/src/MapleFE/autogen/src/exprbuffer.cpp +++ b/src/MapleFE/autogen/src/exprbuffer.cpp @@ -21,7 +21,7 @@ namespace maplefe { // Note: This must be in the order as in 'enum OprCode', and this is the // reason I duplicate OprCode here in order to make the code easy -// to maintain. +// to maintain. OprInfo gOprInfo[OPC_Null] = { {OPC_Add, OPT_Bin, "+"}, {OPC_Sub, OPT_Bin, "-"}, @@ -71,21 +71,21 @@ void ExprNode::SetCall(const char *s) { unsigned len = strlen(s); MASSERT(len < NAME_SIZE); strncpy(mName, s, len); - mOpc = OPC_Call; + mOpc = OPC_Call; } void ExprNode::SetString(const char *s) { unsigned len = strlen(s); MASSERT(len < NAME_SIZE); strncpy(mName, s, len); - mOpc = OPC_Str; + mOpc = OPC_Str; } void ExprNode::SetLiteral(const char *s) { unsigned len = strlen(s); MASSERT(len < NAME_SIZE); strncpy(mName, s, len); - mOpc = OPC_Lit; + mOpc = OPC_Lit; } ////////////////////////////////////////////////////////////////////////// @@ -94,7 +94,7 @@ void ExprNode::SetLiteral(const char *s) { ExprBuffer::ExprBuffer() { mSize = EXPR_SIZE; - mData = (char*)malloc(mSize); + mData = (char*)malloc(mSize); MASSERT(mData && "Cannot malloc buffer for ExprBuffer"); mPos = 0; mRoot = (ExprNode*)mMemPool.Alloc(sizeof(ExprNode)); @@ -104,8 +104,8 @@ ExprBuffer::ExprBuffer() { // Depth-first search to free string memory which is allocated by // the caller of ExprBuffer. ExprBuffer::~ExprBuffer() { - if (mData); - free(mData); + if (mData) + free(mData); } // Extend the size of mData @@ -134,7 +134,7 @@ ExprNode* ExprBuffer::NewExprNodes(unsigned num) { // In-Order void ExprBuffer::Write2Buffer(){ MASSERT(mRoot && "Root of expression is NULL!"); - W2BRecursive(mRoot); + W2BRecursive(mRoot); } void ExprBuffer::WriteStringNode(const ExprNode *n){ @@ -143,7 +143,7 @@ void ExprBuffer::WriteStringNode(const ExprNode *n){ Extend(mPos + len); strncpy(mData+mPos, n->mName, len); - mPos += len; + mPos += len; } void ExprBuffer::WriteLiteralNode(const ExprNode *n){ @@ -153,7 +153,7 @@ void ExprBuffer::WriteLiteralNode(const ExprNode *n){ WriteChar('\"'); strncpy(mData+mPos, n->mName, len); - mPos += len; + mPos += len; WriteChar('\"'); } @@ -170,7 +170,7 @@ void ExprBuffer::WriteOperatorNode(const ExprNode *n){ if (mPos + len > mSize) Extend(mPos + len); strncpy(mData + mPos, text, len); - mPos += len; + mPos += len; } void ExprBuffer::WriteChar(const char c){ diff --git a/src/MapleFE/autogen/src/file_write.cpp b/src/MapleFE/autogen/src/file_write.cpp index 752ffcf699dcf793435793d3d13ae8cd1604f9eb..ed301faaa6ad1d1344580131c198b512b4bd1eee 100644 --- a/src/MapleFE/autogen/src/file_write.cpp +++ b/src/MapleFE/autogen/src/file_write.cpp @@ -47,7 +47,7 @@ void FileWriter::WriteSimpleBuffers(const FormattedBuffer *fb) { std::vector::const_iterator it = fb->mBuffers.begin(); for (; it != fb->mBuffers.end(); it++) { OneBuffer *one = *it; - if (one->mIsSimple) { + if (one->mIsSimple) { RectBuffer *rect = one->GetRectBuffer(); if (rect) { mIndentation = rect->mIndentation; diff --git a/src/MapleFE/autogen/src/keyword_gen.cpp b/src/MapleFE/autogen/src/keyword_gen.cpp index 36d4afd4b96e715b1b2d84db823bba59ef7f6d90..74bb18dee8aa70f76811f9220c9e6d7337475bc9 100644 --- a/src/MapleFE/autogen/src/keyword_gen.cpp +++ b/src/MapleFE/autogen/src/keyword_gen.cpp @@ -36,7 +36,7 @@ const bool KeywordGen::EnumEnd(){ const std::string KeywordGen::EnumNextElem(){ std::string keyword = "\"" + *mEnumIter + "\""; mEnumIter++; - return keyword; + return keyword; } ///////////////////////////////////////////////////////////////////// diff --git a/src/MapleFE/autogen/src/main.cpp b/src/MapleFE/autogen/src/main.cpp index c8d04677a3682776771ff2bb23ae76f4f00ecbda..02343c71a819dc50bcf12400399643a468330701 100644 --- a/src/MapleFE/autogen/src/main.cpp +++ b/src/MapleFE/autogen/src/main.cpp @@ -31,11 +31,19 @@ int main(int argc, char *argv[]) { int verbose = 0; int fileIndex = 2; + std::string lang; + if (argc >=2) { for (int i = 1; i < argc; i++) { int len = strlen(argv[i]); if (!strncmp(argv[i], "-verbose=", 9)) { verbose = atoi(argv[i]+9); + } else if (!strncmp(argv[i], "java", 4)) { + lang = "java"; + } else if (!strncmp(argv[i], "typescript", 10)) { + lang = "typescript"; + } else if (!strncmp(argv[i], "c", 1)) { + lang = "c"; } else if (strcmp(argv[i], "-p") == 0) { checkParserOnly = true; } else { @@ -57,6 +65,7 @@ int main(int argc, char *argv[]) { } maplefe::AutoGen ag(parser); + ag.SetLang(lang); ag.Gen(); return 0; diff --git a/src/MapleFE/autogen/src/operator_gen.cpp b/src/MapleFE/autogen/src/operator_gen.cpp index eb9ea3f20c87cd9f71f520ff7a564c6166ab06a0..5113524011919ca0954b09f5c02709465130122a 100644 --- a/src/MapleFE/autogen/src/operator_gen.cpp +++ b/src/MapleFE/autogen/src/operator_gen.cpp @@ -27,11 +27,12 @@ OperatorId OprsSupported[OPR_NA] = { #include "supported_operators.def" }; -// s : the literal name +// s : the literal name // return the OprId OprId FindOperatorId(const std::string &s) { for (unsigned u = 0; u < OPR_NA; u++) { - if (!OprsSupported[u].mName.compare(0, s.length(), s)) + if (!OprsSupported[u].mName.compare(0, s.length(), s) && + s.length() == OprsSupported[u].mName.size()) return OprsSupported[u].mOprId; } return OPR_NA; @@ -74,7 +75,7 @@ const std::string OperatorGen::EnumNextElem(){ enum_item = enum_item + "\"" + opr.mText + "\", OPR_" + FindOperatorName(opr.mID); enum_item = enum_item + "}"; mEnumIter++; - return enum_item; + return enum_item; } ///////////////////////////////////////////////////////////////////// @@ -111,7 +112,7 @@ void OperatorGen::GenHeaderFile() { mHeaderFile.WriteOneLine("#ifndef __OPERATOR_GEN_H__", 26); mHeaderFile.WriteOneLine("#define __OPERATOR_GEN_H__", 26); mHeaderFile.WriteOneLine("namespace maplefe {", 19); - mHeaderFile.WriteOneLine("extern OprTableEntry OprTable[OPR_NA];", 38); + mHeaderFile.WriteOneLine("extern OprTableEntry OprTable[];", 32); mHeaderFile.WriteOneLine("}", 1); mHeaderFile.WriteOneLine("#endif", 6); } @@ -120,9 +121,20 @@ void OperatorGen::GenCppFile() { mCppFile.WriteOneLine("#include \"ruletable.h\"", 22); mCppFile.WriteOneLine("namespace maplefe {", 19); TableBuffer tb; - tb.Generate(this, "OprTableEntry OprTable[] = {"); + std::string s = "OprTableEntry OprTable["; + std::string num = std::to_string(mOperators.size()); + s += num; + s += "] = {"; + tb.Generate(this, s); mCppFile.WriteFormattedBuffer(&tb); mCppFile.WriteOneLine("};", 2); + + // generate the table size + s = "unsigned OprTableSize = "; + s += num; + s += ";"; + mCppFile.WriteOneLine(s.c_str(), s.size()); + mCppFile.WriteOneLine("}", 1); } } diff --git a/src/MapleFE/autogen/src/reserved_gen.cpp b/src/MapleFE/autogen/src/reserved_gen.cpp index 06a60db950802d6cb4f75da7071989436100eff4..5920a7094ee5cb5f15bde22caceb56f8f292f7c7 100644 --- a/src/MapleFE/autogen/src/reserved_gen.cpp +++ b/src/MapleFE/autogen/src/reserved_gen.cpp @@ -25,10 +25,12 @@ ReservedGen::ReservedGen(const char *dfile, const char *hf, const char *cppf) ReservedOp oneof = {"ONEOF", RO_Oneof}; ReservedOp zeroplus = {"ZEROORMORE", RO_Zeroormore}; ReservedOp zeroorone = {"ZEROORONE", RO_Zeroorone}; + ReservedOp asi = {"ASI", RO_ASI}; mOps.push_back(oneof); mOps.push_back(zeroplus); mOps.push_back(zeroorone); + mOps.push_back(asi); } // Needs to override BaseGen::Run, since we dont need process diff --git a/src/MapleFE/autogen/src/rule.cpp b/src/MapleFE/autogen/src/rule.cpp index 259485306ffa7c12c2ce1dee180ddcdf763e254f..bde0e42ca0d00c440410947c983f3220653ce479 100644 --- a/src/MapleFE/autogen/src/rule.cpp +++ b/src/MapleFE/autogen/src/rule.cpp @@ -132,6 +132,7 @@ const char *RuleElem::GetRuleOpName() { case RO_Oneof: return "ONEOF"; case RO_Zeroormore: return "ZEROORMORE"; case RO_Zeroorone: return "ZEROORONE"; + case RO_ASI: return "ASI"; case RO_Concatenate: case RO_Null: default: return ""; @@ -170,7 +171,10 @@ void RuleElem::Dump(bool newline) { case ET_Op: { std::cout << GetRuleOpName(); - if (mData.mOp == RO_Oneof || mData.mOp == RO_Zeroormore || mData.mOp == RO_Zeroorone) + if (mData.mOp == RO_Oneof + || mData.mOp == RO_Zeroormore + || mData.mOp == RO_Zeroorone + || mData.mOp == RO_ASI ) std::cout << "("; std::vector::iterator it = mSubElems.begin(); @@ -197,6 +201,7 @@ void RuleElem::Dump(bool newline) { } case RO_Zeroormore: case RO_Zeroorone: + case RO_ASI: { (*it)->Dump(); break; @@ -205,7 +210,10 @@ void RuleElem::Dump(bool newline) { break; } - if (mData.mOp == RO_Oneof || mData.mOp == RO_Zeroormore || mData.mOp == RO_Zeroorone) + if (mData.mOp == RO_Oneof + || mData.mOp == RO_Zeroormore + || mData.mOp == RO_Zeroorone + || mData.mOp == RO_ASI) std::cout << ")"; break; } diff --git a/src/MapleFE/autogen/src/rule_gen.cpp b/src/MapleFE/autogen/src/rule_gen.cpp index fdf811afd28ff6f9531cd4116ded4b930425b982..33269487078102ae13291a040dde0def0ca12a0d 100644 --- a/src/MapleFE/autogen/src/rule_gen.cpp +++ b/src/MapleFE/autogen/src/rule_gen.cpp @@ -77,14 +77,14 @@ namespace maplefe { // Generate the table name for mRule std::string RuleGen::GetTblName(const Rule *rule) { std::string tn = "Tbl" + rule->mName; - return tn; + return tn; } // Generate the table name for sub rules in mRule // The table id will be introduced here std::string RuleGen::GetSubTblName() { std::string tn = "Tbl" + mRule->mName + "_sub" + std::to_string(mSubTblNum); - return tn; + return tn; } std::string RuleGen::GetPropertyName(const RuleAttr *attr) { @@ -122,7 +122,7 @@ std::string RuleGen::GetEntryTypeName(ElemType type, RuleOp op) { name = "ET_Data"; break; case ET_Op: { - switch(op) { + switch(op) { case RO_Oneof: name = "ET_Oneof"; break; @@ -135,6 +135,9 @@ std::string RuleGen::GetEntryTypeName(ElemType type, RuleOp op) { case RO_Concatenate: name = "ET_Concatenate"; break; + case RO_ASI: + name = "ET_ASI"; + break; default: MERROR("unknown RuleOp"); break; @@ -190,7 +193,7 @@ std::string RuleGen::Gen4RuleElem(const RuleElem *elem) { // Note: The table could be defined in other files. Need include them. data += "DT_Subtable, &"; data += GetTblName(elem->mData.mRule); - break; + break; case ET_Op: { // Each Op will be generated as a new sub table mSubTblNum++; @@ -248,7 +251,7 @@ void RuleGen::GenDebug(const std::string &rule_table_name) { addr_name_mapping += rule_table_name; addr_name_mapping += "\", "; addr_name_mapping += std::to_string(gRuleTableNum); - addr_name_mapping += "}\,"; + addr_name_mapping += "},"; gSummaryCppFile->WriteOneLine(addr_name_mapping.c_str(), addr_name_mapping.size()); gRuleTableNum++; } @@ -336,7 +339,7 @@ void RuleGen::Gen4Table(const Rule *rule, const RuleElem *elem){ } } } - + Gen4RuleAttr(rule_table_name, attr); Gen4TableHeader(rule_table_name); unsigned index = gRuleTableNum; @@ -347,7 +350,7 @@ void RuleGen::Gen4Table(const Rule *rule, const RuleElem *elem){ std::string rule_table; // 1. Add the LHS of table decl - rule_table = "RuleTable " + rule_table_name + " ="; + rule_table = "RuleTable " + rule_table_name + " ="; rule_table_data = "TableData " + rule_table_data_name + "["; std::string elemnum = std::to_string(elem->mSubElems.size()); @@ -358,7 +361,7 @@ void RuleGen::Gen4Table(const Rule *rule, const RuleElem *elem){ if (elem && (elem->mSubElems.size() == 0)) elemnum = "1"; - rule_table_data += elemnum + "] ="; + rule_table_data += elemnum + "] ="; // 2. Add the beginning '{' rule_table += '{'; @@ -389,7 +392,7 @@ void RuleGen::Gen4Table(const Rule *rule, const RuleElem *elem){ rule_table += "};"; - + // 4. go through the rule elements, generate rule table data std::string data = Gen4TableData(elem); rule_table_data += '{'; @@ -405,7 +408,7 @@ void RuleGen::Gen4Table(const Rule *rule, const RuleElem *elem){ // The structure of rule and its sub-rule can be viewed as a tree. // We generate tables for rule and its sub-rules in depth first order. -// +// void RuleGen::Generate() { bool need_patch = true; if ((mRule->mName.compare("CHAR") == 0) || diff --git a/src/MapleFE/autogen/src/separator_gen.cpp b/src/MapleFE/autogen/src/separator_gen.cpp index 0afaa8ed75662b63cd5aebcc4b716faddd090141..39cb2318d175e1e5bd151c022fb84d97b0476227 100644 --- a/src/MapleFE/autogen/src/separator_gen.cpp +++ b/src/MapleFE/autogen/src/separator_gen.cpp @@ -28,7 +28,7 @@ SuppSepId SepsSupported[SEP_NA] = { #include "supported_separators.def" }; -// s : the literal name +// s : the literal name // return the SepId SepId FindSeparatorId(const std::string &s) { for (unsigned u = 0; u < SEP_NA; u++) { @@ -75,7 +75,7 @@ const std::string SeparatorGen::EnumNextElem(){ enum_item = enum_item + "\"" + sep.mKeyword + "\", SEP_" + FindSeparatorName(sep.mID); enum_item = enum_item + "}"; mEnumIter++; - return enum_item; + return enum_item; } ///////////////////////////////////////////////////////////////////// @@ -112,7 +112,7 @@ void SeparatorGen::GenHeaderFile() { mHeaderFile.WriteOneLine("#ifndef __SEPARATOR_GEN_H__", 27); mHeaderFile.WriteOneLine("#define __SEPARATOR_GEN_H__", 27); mHeaderFile.WriteOneLine("namespace maplefe {", 19); - mHeaderFile.WriteOneLine("extern SepTableEntry SepTable[SEP_NA];", 38); + mHeaderFile.WriteOneLine("extern SepTableEntry SepTable[];", 32); mHeaderFile.WriteOneLine("}", 1); mHeaderFile.WriteOneLine("#endif", 6); } @@ -121,9 +121,20 @@ void SeparatorGen::GenCppFile() { mCppFile.WriteOneLine("#include \"ruletable.h\"", 22); mCppFile.WriteOneLine("namespace maplefe {", 19); TableBuffer tb; - tb.Generate(this, "SepTableEntry SepTable[SEP_NA] = {"); + std::string s = "SepTableEntry SepTable["; + std::string num = std::to_string(mSeparators.size()); + s += num; + s += "] = {"; + tb.Generate(this, s); mCppFile.WriteFormattedBuffer(&tb); mCppFile.WriteOneLine("};", 2); + + // generate the table size + s = "unsigned SepTableSize = "; + s += num; + s += ";"; + mCppFile.WriteOneLine(s.c_str(), s.size()); + mCppFile.WriteOneLine("}", 1); } } diff --git a/src/MapleFE/autogen/src/spec_lexer.cpp b/src/MapleFE/autogen/src/spec_lexer.cpp index 8aea7c1db0900a123d1cda9f9f38ea4516bc287a..bb581c3469e7d71ed6283c55152f073a3e21ce9b 100644 --- a/src/MapleFE/autogen/src/spec_lexer.cpp +++ b/src/MapleFE/autogen/src/spec_lexer.cpp @@ -600,6 +600,10 @@ std::string SPECLexer::GetTokenString(SPECTokenKind thekind) { temp = "ZEROORMORE"; break; } + case SPECTK_ASI: { + temp = "ASI"; + break; + } case SPECTK_Concat: { temp = "+"; break; diff --git a/src/MapleFE/autogen/src/spec_parser.cpp b/src/MapleFE/autogen/src/spec_parser.cpp index f8af4546aac1688a239c475278118eda729593d3..aa0108fad0b41435fc4835ebeb17010aaeb9e647 100644 --- a/src/MapleFE/autogen/src/spec_parser.cpp +++ b/src/MapleFE/autogen/src/spec_parser.cpp @@ -31,7 +31,7 @@ namespace maplefe { ////////////////////////////////////////////////////////////////////////////// -void SPECParser::ParserError(std::string msg, std::string str) { +void SPECParser::ParserError(std::string msg, std::string str) { std::cout << "\n================================= spec file syntax error ============================" << std::endl; std::cout << "file " << mFilename << std::endl; std::cout << "line " << mLexer->GetLineNum() << std::endl; @@ -194,6 +194,10 @@ bool SPECParser::ParseElement(RuleElem *&elem, bool allowConcat) { elem = mBaseGen->NewRuleElem(RO_Zeroormore); status = ParseElementSet(elem); break; + case SPECTK_ASI: + elem = mBaseGen->NewRuleElem(RO_ASI); + status = ParseElementSet(elem); + break; case SPECTK_Char: { elem = mBaseGen->GetOrCreateRuleElemFromChar(mLexer->thechar); @@ -299,8 +303,11 @@ RuleAction *SPECParser::GetAction() { bool SPECParser::ParseElementSet(RuleElem *elem) { SPECTokenKind optk = mLexer->GetToken(); - if (!(optk == SPECTK_Oneof || optk == SPECTK_Zeroorone || optk == SPECTK_Zeroormore)) - ParserError("expect ONEOF/ZEROORONE/ZEROORMORE but get ", mLexer->GetTokenString()); + if (!(optk == SPECTK_Oneof + || optk == SPECTK_Zeroorone + || optk == SPECTK_Zeroormore + || optk == SPECTK_ASI)) + ParserError("expect ONEOF/ZEROORONE/ZEROORMORE/ASI but get ", mLexer->GetTokenString()); SPECTokenKind tk = mLexer->NextToken(); if (tk != SPECTK_Lparen) @@ -318,8 +325,8 @@ bool SPECParser::ParseElementSet(RuleElem *elem) { tk = mLexer->GetToken(); if (optk == SPECTK_Oneof && tk == SPECTK_Coma) tk = mLexer->NextToken(); - else if (optk == SPECTK_Zeroorone || optk == SPECTK_Zeroormore) - // SPECTK_Zeroorone and SPECTK_Zeroormore only allow one element + else if (optk == SPECTK_Zeroorone || optk == SPECTK_Zeroormore || optk == SPECTK_ASI) + // SPECTK_Zeroorone, SPECTK_Zeroormore and ASI only allow one element break; } diff --git a/src/MapleFE/autogen/src/token_gen.cpp b/src/MapleFE/autogen/src/token_gen.cpp index 725192414d5cbdd64d937aa63a9a9cfb504affbc..45840e7e312e0b3052e20d8e0d3feb49136effe0 100644 --- a/src/MapleFE/autogen/src/token_gen.cpp +++ b/src/MapleFE/autogen/src/token_gen.cpp @@ -65,11 +65,12 @@ void TokenGen::ProcessAltTokens() { for (unsigned i = 0; i < mAltTokensNum; i++) { AlternativeToken at = alt_tokens[i]; unsigned orig_id; - bool found = gTokenTable.FindStringTokenId(at.mName, orig_id); - MASSERT(found); + bool orig_found = gTokenTable.FindStringTokenId(at.mName, orig_id); unsigned alt_id; - found = gTokenTable.FindStringTokenId(at.mAltName, alt_id); - MASSERT(found); + bool alt_found = gTokenTable.FindStringTokenId(at.mAltName, alt_id); + if (!orig_found || !alt_found) { + continue; + } ProcessedAltToken pat; pat.mId = orig_id; @@ -155,7 +156,7 @@ void TokenGen::GenCppFile() { std::list::iterator oit = gTokenTable.mOperators->begin(); for (; oit != gTokenTable.mOperators->end(); oit++, overall_index++) { - std::string output = " {.mTkType = TT_OP, {.mOprId = "; + std::string output = " {.mTkType = TT_OP, .mLineNum = 0, .mColNum = 0, .mLineBegin = false, .mLineEnd = false, {.mOprId = "; Operator opr = *oit; std::string opr_name = "OPR_"; opr_name += FindOperatorName(opr.mID); @@ -186,7 +187,7 @@ void TokenGen::GenCppFile() { std::list::iterator sit = gTokenTable.mSeparators->begin(); for (; sit != gTokenTable.mSeparators->end(); sit++, overall_index++) { - std::string output = " {.mTkType = TT_SP, {.mSepId = "; + std::string output = " {.mTkType = TT_SP, .mLineNum = 0, .mColNum = 0, .mLineBegin = false, .mLineEnd = false, {.mSepId = "; Separator sep = *sit; std::string sep_name = "SEP_"; sep_name += FindSeparatorName(sep.mID); @@ -217,7 +218,7 @@ void TokenGen::GenCppFile() { unsigned kw_size = gTokenTable.mKeywords.size(); for (unsigned index = 0; index < kw_size; index++, overall_index++) { - std::string output = " {.mTkType = TT_KW, {.mName = "; + std::string output = " {.mTkType = TT_KW, .mLineNum = 0, .mColNum = 0, .mLineBegin = false, .mLineEnd = false, {.mName = "; std::string keyword = gTokenTable.mKeywords[index]; output += "\""; output += keyword; @@ -247,7 +248,7 @@ void TokenGen::GenCppFile() { } // Write the comment token - std::string output = " {.mTkType = TT_CM, {.mName = NULL}, .mAltTokens = NULL}"; + std::string output = " {.mTkType = TT_CM, .mLineNum = 0, .mColNum = 0, .mLineBegin = false, .mLineEnd = false, {.mName = NULL}, .mAltTokens = NULL}"; mCppFile.WriteOneLine(output.c_str(), output.size()); mCppFile.WriteOneLine("};", 2); mCppFile.WriteOneLine("}", 1); diff --git a/src/MapleFE/autogen/src/type_gen.cpp b/src/MapleFE/autogen/src/type_gen.cpp index 786a3d57618abcf6b2bebdbc53a65632572b422e..57214ec7fd0f9f5a32c12df874e048e5b06b24d6 100644 --- a/src/MapleFE/autogen/src/type_gen.cpp +++ b/src/MapleFE/autogen/src/type_gen.cpp @@ -76,7 +76,7 @@ void TypeGen::GenHeaderFile() { mHeaderFile.WriteOneLine("namespace maplefe {", 19); // generate the keyword table - mHeaderFile.WriteOneLine("extern TypeKeyword TypeKeywordTable[TY_NA];", 43); + mHeaderFile.WriteOneLine("extern TypeKeyword TypeKeywordTable[];", 38); // generate the rule tables mHeaderFile.WriteFormattedBuffer(&mRuleTableHeader); @@ -90,12 +90,23 @@ void TypeGen::GenCppFile() { // generate the keyword table TableBuffer tb; - tb.Generate(this, "TypeKeyword TypeKeywordTable[TY_NA] = {"); + std::string s = "TypeKeyword TypeKeywordTable["; + std::string num = std::to_string(mTypes.size()); + s += num; + s += "] = {"; + tb.Generate(this, s); mCppFile.WriteFormattedBuffer(&tb); mCppFile.WriteOneLine("};", 2); + // generate the table size + s = "unsigned TypeKeywordTableSize = "; + s += num; + s += ";"; + mCppFile.WriteOneLine(s.c_str(), s.size()); + // generate the rule tables mCppFile.WriteFormattedBuffer(&mRuleTableCpp); + mCppFile.WriteOneLine("}", 1); } diff --git a/src/MapleFE/c/Makefile b/src/MapleFE/c/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6ff0312533c771b903d1686b33384d7da06eff4b --- /dev/null +++ b/src/MapleFE/c/Makefile @@ -0,0 +1,24 @@ +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +include ../Makefile.in + +TARGS = c2ast + +$(TARGS): + $(MAKE) -C src + +clean: + rm -rf $(BUILDDIR)/c + +.PHONY: $(TARGS) diff --git a/src/MapleFE/c/attr.spec b/src/MapleFE/c/attr.spec new file mode 100644 index 0000000000000000000000000000000000000000..7211303cd96c3d2ceb5755398e12958832394a0a --- /dev/null +++ b/src/MapleFE/c/attr.spec @@ -0,0 +1,18 @@ +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. + +STRUCT Attribute : (("const", const), + ("static", static), + ("volatile", volatile), + ("restrict", restrict)) \ No newline at end of file diff --git a/src/MapleFE/c/identifier.spec b/src/MapleFE/c/identifier.spec new file mode 100644 index 0000000000000000000000000000000000000000..ff6f96fdb1c0fa797e70f876d0d2f53f41342f8c --- /dev/null +++ b/src/MapleFE/c/identifier.spec @@ -0,0 +1,17 @@ +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. + +rule CChar : ONEOF(CHAR, '_') +rule CharOrDigit : ONEOF(CChar, DIGIT) +rule Identifier : CChar + ZEROORMORE(CharOrDigit) \ No newline at end of file diff --git a/src/MapleFE/c/include/lang_builtin.def b/src/MapleFE/c/include/lang_builtin.def new file mode 100644 index 0000000000000000000000000000000000000000..8c127c72a426bb6113253cdf59a103a11785e8fb --- /dev/null +++ b/src/MapleFE/c/include/lang_builtin.def @@ -0,0 +1,14 @@ +// Copyright (C) [2022] Futurewei Technologies, Inc. All rights reverved. +// +// OpenArkFE is licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// + diff --git a/src/MapleFE/c/include/lang_keywords.def b/src/MapleFE/c/include/lang_keywords.def new file mode 100644 index 0000000000000000000000000000000000000000..fc60a43491ab2c16f99198453f2543f60947aad0 --- /dev/null +++ b/src/MapleFE/c/include/lang_keywords.def @@ -0,0 +1,52 @@ +/* + * Copyright (c) [2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +LANGKEYWORD(auto) +LANGKEYWORD(break) +LANGKEYWORD(case) +LANGKEYWORD(char) +LANGKEYWORD(const) +LANGKEYWORD(continue) +LANGKEYWORD(default) +LANGKEYWORD(do) +LANGKEYWORD(double) +LANGKEYWORD(else) +LANGKEYWORD(enum) +LANGKEYWORD(extern) +LANGKEYWORD(float) +LANGKEYWORD(for) +LANGKEYWORD(goto) +LANGKEYWORD(if) +LANGKEYWORD(inline) +LANGKEYWORD(int) +LANGKEYWORD(long) +LANGKEYWORD(register) +LANGKEYWORD(restrict) +LANGKEYWORD(return) +LANGKEYWORD(short) +LANGKEYWORD(signed) +LANGKEYWORD(sizeof) +LANGKEYWORD(static) +LANGKEYWORD(struct) +LANGKEYWORD(switch) +LANGKEYWORD(typedef) +LANGKEYWORD(union) +LANGKEYWORD(unsigned) +LANGKEYWORD(void) +LANGKEYWORD(volatile) +LANGKEYWORD(while) +LANGKEYWORD(_Bool) +LANGKEYWORD(_Complex) +LANGKEYWORD(_Imaginary) \ No newline at end of file diff --git a/src/MapleFE/c/include/lang_spec.h b/src/MapleFE/c/include/lang_spec.h new file mode 100644 index 0000000000000000000000000000000000000000..bae3daba4ee9dc8df6b59334d68e9df4b9f84798 --- /dev/null +++ b/src/MapleFE/c/include/lang_spec.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLEFE_LANG_SPEC_H +#define MAPLEFE_LANG_SPEC_H +#include "stringutil.h" +#include "token.h" +#include "lexer.h" + +namespace maplefe { + +class StringToValueImpl : public StringToValue { +public: + float StringToFloat(std::string &s); + double StringToDouble(std::string &s); + bool StringToBool(std::string &s); + Char StringToChar(std::string &s); + bool StringIsNull(std::string &s); +}; + +extern LitData ProcessLiteral(LitId type, const char *str); + +class CLexer : public Lexer { +}; + +} +#endif //MAPLEFE_LANG_SPEC_H diff --git a/src/MapleFE/c/keyword.spec b/src/MapleFE/c/keyword.spec new file mode 100644 index 0000000000000000000000000000000000000000..2e62b807aaaf736015788008e0c36e2b1843bc51 --- /dev/null +++ b/src/MapleFE/c/keyword.spec @@ -0,0 +1,51 @@ +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. + +STRUCT KeyWord : ((auto), + (break), + (case), + (char), + (const), + (continue), + (default), + (do), + (double), + (else), + (enum), + (extern), + (float), + (for), + (goto), + (if), + (inline), + (int), + (long), + (register), + (restrict), + (return), + (short), + (signed), + (sizeof), + (static), + (struct), + (switch), + (typedef), + (union), + (unsigned), + (void), + (volatile), + (while), + (_Bool), + (_Complex), + (_Imaginary)) diff --git a/src/MapleFE/c/literal.spec b/src/MapleFE/c/literal.spec new file mode 100644 index 0000000000000000000000000000000000000000..013f438418239a299bcd63ca4285bc00efd532c6 --- /dev/null +++ b/src/MapleFE/c/literal.spec @@ -0,0 +1,118 @@ +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. + +######################################################################### +## Integer ## +######################################################################### + +### Decimal rules + +rule NonZeroDigit : ONEOF('1', '2', '3', '4', '5', '6', '7', '8', '9') +rule Digit : ONEOF('0', NonZeroDigit) +rule DecimalNumeral : ONEOF('0', NonZeroDigit + ZEROORONE(Digit)) + +### Hexadecimal rules + +rule HexDigit : ONEOF('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', + 'A', 'B', 'C', 'D', 'E', 'F') +rule HexNumeral : ONEOF("0x" + HexDigit, "0X" + HexDigit) + +### Octal rules + +rule OctalDigit : ONEOF('0', '1', '2', '3', '4', '5', '6', '7') +rule OctalNumeral : ONEOF('0' + OctalDigit) + +rule IntegerTypeSuffix : ONEOF('L', 'l') +rule DecimalIntegerLiteral: DecimalNumeral + ZEROORONE(IntegerTypeSuffix) +rule HexIntegerLiteral : HexNumeral + ZEROORONE(IntegerTypeSuffix) +rule OctalIntegerLiteral : OctalNumeral + ZEROORONE(IntegerTypeSuffix) + +rule IntegerLiteral: ONEOF(DecimalIntegerLiteral, + HexIntegerLiteral, + OctalIntegerLiteral) + +######################################################################### +## Floating Point ## +######################################################################### + +##### Decimal floating point literal + +rule Sign : ONEOF('+', '-') +rule FloatTypeSuffix : ONEOF('f', 'F') +rule ExponentIndicator : ONEOF('e', 'E') +rule SignedInteger : ZEROORONE(Sign) + Digit +rule ExponentPart : ExponentIndicator + SignedInteger + +rule DecFPLiteral : ONEOF(Digit + '.' + ZEROORONE(Digit) + ZEROORONE(ExponentPart) + ZEROORONE(FloatTypeSuffix), + '.'+Digit + ZEROORONE(ExponentPart) + ZEROORONE(FloatTypeSuffix), + Digit + ExponentPart + ZEROORONE(FloatTypeSuffix), + Digit + ZEROORONE(ExponentPart)) + +####### Hex floating point literal + +rule BinaryExponentIndicator : ONEOF('p', 'P') +rule BinaryExponent : BinaryExponentIndicator + SignedInteger +rule HexSignificand : ONEOF(HexNumeral + ZEROORONE('.'), + "0x" + ZEROORONE(HexDigit) + '.' + HexDigit, + "0X" + ZEROORONE(HexDigit) + '.' + HexDigit) +rule HexFPLiteral: HexSignificand + BinaryExponent + ZEROORONE(FloatTypeSuffix) + +###### Floating Point Literal + +rule FPLiteral : ONEOF(DecFPLiteral, HexFPLiteral) + +######################################################################### +## Boolean ## +######################################################################### + +rule BooleanLiteral : ONEOF ("true", "false") + +######################################################################### +## Character ## +## ESCAPE is a reserved rule in reserved.spec. ## +######################################################################### + +rule UnicodeEscape: '\' + 'u' + HEXDIGIT + HEXDIGIT + HEXDIGIT + HEXDIGIT +rule RawInputCharacter : ONEOF(ASCII, ''', ESCAPE) +rule SingleCharacter: ONEOF(UnicodeEscape, RawInputCharacter) + +rule OctalEscape : ONEOF('\' + '0', '\' + '1') +rule EscapeSequence : ONEOF(ESCAPE, OctalEscape) +rule CharacterLiteral : ''' + ONEOF(SingleCharacter, EscapeSequence) + ''' + +######################################################################### +## String ## +######################################################################### +# The UnicodeEscape is limited from \u0000 to \u00ff. +rule StringUnicodeEscape: '\' + 'u' + '0' + '0' + HEXDIGIT + HEXDIGIT +rule StringCharater: ONEOF(StringUnicodeEscape, RawInputCharacter) +rule StringLiteral : '"' + ZEROORMORE(StringCharater) + '"' + +######################################################################### +## Null ## +######################################################################### + +rule NullLiteral : "NULL" + +######################################################################### +## Literal ## +######################################################################### + +rule Literal : ONEOF(IntegerLiteral, + FPLiteral, + BooleanLiteral, + CharacterLiteral, + StringLiteral, + NullLiteral) \ No newline at end of file diff --git a/src/MapleFE/c/operator.spec b/src/MapleFE/c/operator.spec new file mode 100644 index 0000000000000000000000000000000000000000..eac023f63e58c861984945d34559c511e2c45daf --- /dev/null +++ b/src/MapleFE/c/operator.spec @@ -0,0 +1,54 @@ +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. + +STRUCT Operator : ONEOF( + # Arithmetic + ("+", Add), + ("-", Sub), + ("*", Mul), + ("/", Div), + ("%", Mod), + ("++", Inc), + ("--", Dec), + # Relation + ("==", EQ), + ("!=", NE), + (">", GT), + ("<", LT), + (">=", GE), + ("<=", LE), + # Bitwise + ("&", Band), + ("|", Bor), + ("^", Bxor), + ("~", Bcomp), + # Shift + ("<<", Shl), + (">>", Shr), + # Logical + ("&&", Land), + ("||", Lor), + ("!", Not), + # Assign + ("=", Assign), + ("+=", AddAssign), + ("-=", SubAssign), + ("*=", MulAssign), + ("/=", DivAssign), + ("%=", ModAssign), + ("<<=", ShlAssign), + (">>=", ShrAssign), + ("&=", BandAssign), + ("|=", BorAssign), + ("^=", BxorAssign)) \ No newline at end of file diff --git a/src/MapleFE/c/separator.spec b/src/MapleFE/c/separator.spec new file mode 100644 index 0000000000000000000000000000000000000000..dd37454e81425f720a84c45ab4e96d2a0f4f311f --- /dev/null +++ b/src/MapleFE/c/separator.spec @@ -0,0 +1,29 @@ +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. + +STRUCT Separator : ((" ", Whitespace), + ("(", Lparen), + (")", Rparen), + ("{", Lbrace), + ("}", Rbrace), + ("[", Lbrack), + ("]", Rbrack), + (";", Semicolon), + (",", Comma), + (".", Dot), + ("...", Dotdotdot), + (":", Colon), + ("?", Select), + ("::", Of), + ("#", Pound)) \ No newline at end of file diff --git a/src/MapleFE/c/src/Makefile b/src/MapleFE/c/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6947fdd0cb0f81fba87b75fa82bcc51d37e8b91c --- /dev/null +++ b/src/MapleFE/c/src/Makefile @@ -0,0 +1,80 @@ +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. + +include ../../Makefile.in +BUILDBIN=$(BUILDDIR)/bin +BUILD=$(BUILDDIR)/c +BUILDGEN=$(BUILDDIR)/gen +BUILDASTGEN=$(BUILDDIR)/ast_gen/shared +$(shell $(MKDIR_P) $(BUILD) $(BUILDGEN)) + +SRC=$(wildcard *.cpp) +OBJ :=$(patsubst %.cpp,%.o,$(SRC)) +DEP :=$(patsubst %.cpp,%.d,$(SRC)) + +SRCG := $(wildcard $(BUILDGEN)/gen*.cpp) +OBJG := $(patsubst %.cpp, %.o, $(SRCG)) +DEPG := $(patsubst %.cpp, %.d, $(SRCG)) + +OBJS :=$(foreach obj,$(OBJ), $(BUILD)/$(obj)) $(OBJG) +DEPS :=$(foreach dep,$(DEP), $(BUILD)/$(dep)) $(DEPG) + +INCLUDES := -I $(MAPLEFE_ROOT)/shared/include \ + -I $(MAPLEFE_ROOT)/c/include \ + -I $(MAPLEFE_ROOT)/autogen/include \ + -I ${BUILDDIR}/ast_gen/shared \ + -I $(BUILDGEN) + +INCLUDEGEN := -I $(BUILDGEN) -I $(MAPLEFE_ROOT)/shared/include + +TARGET=c2ast + +SHAREDLIB = $(BUILDDIR)/shared/shared.a $(BUILDASTGEN)/genast.a + +.PHONY: all +all: $(BUILDBIN)/$(TARGET) + +-include $(DEPS) +.PHONY: clean + +vpath %.o $(BUILD) +vpath %.d $(BUILD) + +# Pattern Rules +$(BUILD)/%.o : %.cpp + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ + +$(BUILD)/%.d : %.cpp + @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $< > $@ + @mv -f $(BUILD)/$*.d $(BUILD)/$*.d.tmp + @sed -e 's|.*:|$(BUILD)/$*.o:|' < $(BUILD)/$*.d.tmp > $(BUILD)/$*.d + @rm -f $(BUILD)/$*.d.tmp + +$(BUILDGEN)/%.o : $(BUILDGEN)/%.cpp $(BUILDGEN)/%.d + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDEGEN) -w -c $< -o $@ + +$(BUILDGEN)/%.d : $(BUILDGEN)/%.cpp + @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDEGEN) $< > $@ + @mv -f $(BUILDGEN)/$*.d $(BUILDGEN)/$*.d.tmp + @sed -e 's|.*:|$(BUILDGEN)/$*.o:|' < $(BUILDGEN)/$*.d.tmp > $(BUILDGEN)/$*.d + @rm -f $(BUILDGEN)/$*.d.tmp + +# TARGET depends on OBJS and shared OBJS from shared directory +# as well as mapleall libraries +$(BUILDBIN)/$(TARGET): $(OBJS) $(SHAREDLIB) + @mkdir -p $(BUILDBIN) + $(LD) -o $(BUILDBIN)/$(TARGET) $(OBJS) $(SHAREDLIB) -lstdc++fs + +clean: + rm -rf $(BUILD) diff --git a/src/MapleFE/c/src/lang_spec.cpp b/src/MapleFE/c/src/lang_spec.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3fd8113c8b85c1770822f1b9b324b860407c410 --- /dev/null +++ b/src/MapleFE/c/src/lang_spec.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "lang_spec.h" +#include "stringpool.h" + +namespace maplefe { +float StringToValueImpl::StringToFloat(std::string &s) { + return stof(s); +} + +double StringToValueImpl::StringToDouble(std::string &s) { + std::string str = s; + char suffix = str[str.length() - 1]; + if (suffix == 'l' || suffix == 'L') + str[str.length() - 1] = 'L'; + return stod(str); +} + +bool StringToValueImpl::StringToBool(std::string &s) { + if ((s.size() == 4) && (s.compare("true") == 0)) + return true; + else if ((s.size() == 5) && (s.compare("false") == 0)) + return false; + else + MERROR("unknown bool literal"); +} + +bool StringToValueImpl::StringIsNull(std::string &s) {return false;} + +static char DeEscape(char c) { + switch(c) { + case 'b': + return '\b'; + case 't': + return '\t'; + case 'n': + return '\n'; + case 'f': + return '\f'; + case 'r': + return '\r'; + case '"': + return '\"'; + case '\'': + return '\''; + case '\\': + return '\\'; + case '0': + return '\0'; + default: + MERROR("Unsupported in DeEscape()."); + } +} + +static int char2int(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else + MERROR("Unsupported char in char2int()."); +} + +Char StringToValueImpl::StringToChar(std::string &s) { + Char ret_char; + ret_char.mIsUnicode = false; + MASSERT (s[0] == '\''); + if (s[1] == '\\') { + if (s[2] == 'u') { + ret_char.mIsUnicode = true; + int first = char2int(s[3]); + int second = char2int(s[4]); + int third = char2int(s[5]); + int forth = char2int(s[6]); + MASSERT(s[7] == '\''); + ret_char.mData.mUniValue = (first << 12) + (second << 8) + + (third << 4) + forth; + } else { + ret_char.mData.mChar = DeEscape(s[2]); + } + } else { + MASSERT(s[2] == '\''); + ret_char.mData.mChar = s[1]; + } + return ret_char; +} + +LitData ProcessLiteral(LitId id, const char *str) { + LitData data; + std::string value_text(str); + StringToValueImpl s2v; + + switch (id) { + case LT_IntegerLiteral: { + int i = s2v.StringToInt(value_text); + data.mType = LT_IntegerLiteral; + data.mData.mInt = i; + break; + } + case LT_FPLiteral: { + char suffix = value_text[value_text.length() - 1]; + if (suffix == 'f' || suffix == 'F') { + float f = s2v.StringToFloat(value_text); + data.mType = LT_FPLiteral; + data.mData.mFloat = f; + } else { + double d = s2v.StringToDouble(value_text); + data.mType = LT_DoubleLiteral; + data.mData.mDouble = d; + } + break; + } + case LT_BooleanLiteral: { + bool b = s2v.StringToBool(value_text); + data.mType = LT_BooleanLiteral; + data.mData.mBool = b; + break; } + case LT_CharacterLiteral: { + Char c = s2v.StringToChar(value_text); + data.mType = LT_CharacterLiteral; + data.mData.mChar = c; + break; } + case LT_StringLiteral: { + const char *s = s2v.StringToString(value_text); + data.mType = LT_StringLiteral; + data.mData.mStrIdx = gStringPool.GetStrIdx(s); + break; } + case LT_NullLiteral: { + // Just need set the id + data.mType = LT_NullLiteral; + break; } + case LT_NA: // N/A, + default: + data.mType = LT_NA; + break; + } + + return data; +} + +Lexer* CreateLexer() { + Lexer *lexer = new CLexer(); + return lexer; +} + +} diff --git a/src/MapleFE/c/src/main.cpp b/src/MapleFE/c/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b055675ccd5e23deec5d5292167d7cea2d3a57a6 --- /dev/null +++ b/src/MapleFE/c/src/main.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include +#include "parser.h" +#include "token.h" +#include "common_header_autogen.h" +#include "ruletable_util.h" +#include "gen_summary.h" +#include "gen_aststore.h" +#include "gen_astdump.h" +#include "gen_astgraph.h" + +static void help() { + std::cout << "c sourcefile [options]:\n" << std::endl; + std::cout << " --help : print this help" << std::endl; + std::cout << " --trace-lexer : Trace lexing" << std::endl; + std::cout << " --trace-table : Trace rule table when entering and exiting" << std::endl; + std::cout << " --trace-left-rec : Trace left recursion parsing" << std::endl; + std::cout << " --trace-appeal : Trace appeal process" << std::endl; + std::cout << " --trace-failed : Trace failed tokens of table" << std::endl; + std::cout << " --trace-timing : Trace parsing time" << std::endl; + std::cout << " --trace-stack : Trace visited-token stack of table" << std::endl; + std::cout << " --trace-sortout : Trace SortOut" << std::endl; + std::cout << " --trace-ast-build : Trace AST Builder" << std::endl; + std::cout << " --trace-patch-was-succ : Trace Patching of WasSucc nodes" << std::endl; + std::cout << " --trace-warning : Print Warning" << std::endl; + std::cout << " --dump-ast : Dump AST in text format" << std::endl; + std::cout << " --dump-dot : Dump AST in dot format" << std::endl; +} + +int main (int argc, char *argv[]) { + if (argc == 1 || (!strncmp(argv[1], "--help", 6) && (strlen(argv[1]) == 6))) { + help(); + exit(-1); + } + + maplefe::Parser *parser = new maplefe::Parser(argv[1]); + + bool dump_ast = false; + bool dump_dot = false; + bool succ; + + // Parse the argument + for (unsigned i = 2; i < argc; i++) { + if (!strncmp(argv[i], "--trace-lexer", 13) && (strlen(argv[i]) == 13)) { + parser->SetLexerTrace(); + } else if (!strncmp(argv[i], "--trace-table", 13) && (strlen(argv[i]) == 13)) { + parser->mTraceTable = true; + } else if (!strncmp(argv[i], "--trace-left-rec", 16) && (strlen(argv[i]) == 16)) { + parser->mTraceLeftRec = true; + } else if (!strncmp(argv[i], "--trace-appeal", 14) && (strlen(argv[i]) == 14)) { + parser->mTraceAppeal = true; + } else if (!strncmp(argv[i], "--trace-stack", 13) && (strlen(argv[i]) == 13)) { + parser->mTraceVisited = true; + } else if (!strncmp(argv[i], "--trace-failed", 14) && (strlen(argv[i]) == 14)) { + parser->mTraceFailed = true; + } else if (!strncmp(argv[i], "--trace-timing", 14) && (strlen(argv[i]) == 14)) { + parser->mTraceTiming = true; + } else if (!strncmp(argv[i], "--trace-sortout", 15) && (strlen(argv[i]) == 15)) { + parser->mTraceSortOut = true; + } else if (!strncmp(argv[i], "--trace-ast-build", 17) && (strlen(argv[i]) == 17)) { + parser->mTraceAstBuild = true; + } else if (!strncmp(argv[i], "--trace-patch-was-succ", 22) && (strlen(argv[i]) == 22)) { + parser->mTracePatchWasSucc = true; + } else if (!strncmp(argv[i], "--trace-warning", 15) && (strlen(argv[i]) == 15)) { + parser->mTraceWarning = true; + } else if (!strncmp(argv[i], "--dump-ast", 10) && (strlen(argv[i]) == 10)) { + dump_ast = true; + } else if (!strncmp(argv[i], "--dump-dot", 10) && (strlen(argv[i]) == 10)) { + dump_dot = true; + } else { + std::cerr << "unknown option " << argv[i] << std::endl; + exit(-1); + } + } + + parser->InitRecursion(); + succ = parser->Parse(); + if (!succ) { + delete parser; + return 1; + } + + // the module from parser + maplefe::ModuleNode *module = parser->GetModule(); + + if(dump_ast) { + maplefe::AstDump astdump(module); + astdump.Dump("c2ast: Initial AST", &std::cout); + } + + if(dump_dot) { + maplefe::AstGraph graph(module); + graph.DumpGraph("c2ast: Initial AST", &std::cout); + } + + maplefe::AstStore saveAst(module); + saveAst.StoreInAstBuf(); + maplefe::AstBuffer &ast_buf = saveAst.GetAstBuf(); + + std::ofstream ofs; + std::string fname(module->GetFilename()); + fname = fname.replace(fname.find(".c"), 2, ".mast"); + ofs.open(fname, std::ofstream::out); + const char *addr = (const char *)(&(ast_buf[0])); + ofs.write(addr, ast_buf.size()); + ofs.close(); + + delete parser; + return 0; +} diff --git a/src/MapleFE/c/stmt.spec b/src/MapleFE/c/stmt.spec new file mode 100644 index 0000000000000000000000000000000000000000..f71d36b960266b2d4a5e42e799f73bf60a0223ff --- /dev/null +++ b/src/MapleFE/c/stmt.spec @@ -0,0 +1,163 @@ +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. + +###################################################################### +# Expression # +###################################################################### + +rule PrimaryExpression : ONEOF( + Literal, + Identifier +) + +rule DimExprs : DimExpr + ZEROORMORE(DimExpr) + +rule DimExpr : '[' + Expression + ']' + +rule Expression : ONEOF( + PrimaryExpression, + UnaryExpression) + +rule UnaryExpression : ONEOF( + PreIncrementExpression, + PreDecrementExpression, + PostIncrementExpression, + PostDecrementExpression) + +rule PreIncrementExpression : "++" + PrimaryExpression + attr.action : BuildUnaryOperation(%1, %2) + +rule PreDecrementExpression : "--" + PrimaryExpression + attr.action : BuildUnaryOperation(%1, %2) + +rule PostIncrementExpression : PrimaryExpression + "++" + attr.action : BuildPostfixOperation(%2, %1) + +rule PostDecrementExpression : PrimaryExpression + "--" + attr.action : BuildPostfixOperation(%2, %1) + +###################################################################### +# Variable # +###################################################################### + +rule GlobalVariableDeclarationStatement : VariableDeclaration + ';' + attr.property : Top + +rule LocalVariableDeclarationStatement : VariableDeclaration + ';' + +rule VariableDeclaration : ZEROORMORE(VariableModifier) + Type + VariableDeclaratorList + attr.action: BuildDecl(%2, %3) + attr.action: AddModifier(%1) + +rule VariableModifier : ONEOF( + "static", + "const", + "volatile", + "restrict") + +rule VariableDeclaratorList : VariableDeclarator + ZEROORMORE(',' + VariableDeclarator) + attr.action: BuildVarList(%1, %2) + +rule VariableDeclarator : VariableDeclaratorId + ZEROORONE('=' + VariableInitializer) + attr.action: AddInitTo(%1, %2) + +rule VariableDeclaratorId : Identifier + ZEROORONE(Dims) + attr.action: AddDimsTo(%1, %2) + +rule VariableInitializer : ONEOF( + Expression, + ArrayInitializer) + +rule ArrayInitializer : '{' + ZEROORONE(VariableInitializerList) + ZEROORONE(',') + '}' + +rule VariableInitializerList: VariableInitializer + ZEROORMORE(',' + VariableInitializer) + +rule Dims : Dim + ZEROORMORE(Dim) + attr.action: BuildDims(%1, %2) + +rule Dim : '[' + ']' + attr.action: BuildDim(%1) + +###################################################################### +# statement # +###################################################################### + +rule Statement : ONEOF(LocalVariableDeclarationStatement, + ExpressionStatement, + ReturnStatement) + attr.property: Single + +rule ExpressionStatement : StatementExpression + ';' + +rule StatementExpression : ONEOF( + PreIncrementExpression, + PreDecrementExpression, + PostIncrementExpression, + PostDecrementExpression, + ) + attr.property: Single + +rule ReturnStatement : "return" + ZEROORONE(Expression) + ';' + attr.action : BuildReturn(%2) + + +###################################################################### +# Function # +###################################################################### + +rule GlobalFuncDeclaration : FuncDeclaration + attr.property : Top + +rule FuncDeclaration : ZEROORMORE(FuncModifier) + FuncHeader + FuncBody + attr.action: AddModifierTo(%2, %1) + attr.action: AddFunctionBodyTo(%2, %3) + +rule FuncBody : ONEOF(Block, ';') + attr.property : Single + +rule FuncHeader : ONEOF(Result + FuncDeclarator) + attr.action.%1: AddType(%2, %1) + attr.property : Single + +rule Result : ONEOF(Type, "void") + attr.property : Single + +rule FuncDeclarator : Identifier + '(' + ZEROORONE(FormalParameters) + ')' + attr.action: BuildFunction(%1) + attr.action: AddParams(%3) + +rule FuncAttr : ONEOF("const", "static") + attr.property : Single + +rule FuncModifier : ONEOF(FuncAttr) + attr.property : Single + +rule FormalParameters : ONEOF(FormalParameter + ZEROORMORE(',' + FormalParameter)) + attr.property : Single + +rule FormalParameter : ZEROORMORE(VariableModifier) + Type + VariableDeclaratorId + attr.action: BuildDecl(%2, %3) + attr.action: AddModifier(%1) + +###################################################################### +# Block # +###################################################################### + +rule BlockStatement : ONEOF(LocalVariableDeclarationStatement, Statement) + attr.property : Single + +rule BlockStatements : BlockStatement + ZEROORMORE(BlockStatement) + +rule Block : '{' + ZEROORONE(BlockStatements) + '}' + attr.action: BuildBlock(%2) diff --git a/src/MapleFE/c/type.spec b/src/MapleFE/c/type.spec new file mode 100644 index 0000000000000000000000000000000000000000..af2d02bbb43ecb326acb4a3722ef4c981d76285a --- /dev/null +++ b/src/MapleFE/c/type.spec @@ -0,0 +1,37 @@ +# +# Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. + +STRUCT Keyword : (("char", Char), + ("short", Short), + ("int", Int), + ("long", Long), + ("float", Float), + ("double", Double), + ("void", Void), + ("_Bool", Boolean)) + +rule BooleanType : "_Bool" +rule IntType : ONEOF("char", "unsigned" + "char", "signed" + "char", + "short", "unsigned" + "short", "signed" + "short", + "int", "unsigned" + "int", "signed" + "int", "unsigned", "signed", + "long", "unsigned" + "long", "signed" + "long") +rule FPType : ONEOF("float", "double") +rule NumericType : ONEOF(IntType, FPType) + +rule PrimitiveType : ONEOF(NumericType, BooleanType) +rule TypeVariable : Identifier + +rule NonePointerType : ONEOF(PrimitiveType, TypeVariable) +rule PointerType : NonePointerType + '*' + ZEROORMORE('*') +rule Type : ONEOF(NonePointerType, PointerType) \ No newline at end of file diff --git a/src/MapleFE/docs/astdump.md b/src/MapleFE/docs/astdump.md new file mode 100644 index 0000000000000000000000000000000000000000..7f68eeff72608372e0ba4d81e8a7296497013c37 --- /dev/null +++ b/src/MapleFE/docs/astdump.md @@ -0,0 +1,45 @@ +## Overview + +The `astdump.sh` tool is a bash script which executes the `ts2cpp` binary executable with option +`--trace-a2c` to dump the AST and CFG graphs of a TypeScript program. + +It also dump the TypeScript code converted from the corresponding AST with AST emitter. + +## Usage to astdump.sh + +```bash +Usage: astdump.sh [-dot] [-f|--fullscreen] [-p |--pre ] [-a|--ast] [-c|--cfg] [-A|--all] [-C|--clean] [ ...] + + -d | --dot Use Graphviz dot to generate the graph and view it with viewnior + -f | --fullscreen View the generated graph in fullscreen mode. It implies option -dot + -p | --pre Filter graphs with the specified , e.g. -p "CFG_" + -a | --ast Show AST graph. It is equivalent to options "-dot -p AST" + -c | --cfg Show CFG graph. It is equivalent to options "-dot -p CFG" + -s | --syntax Syntax highlighting the generated TypeScript code + -A | --all Process all .ts files in current directory excluding *.ts-[0-9]*.out.ts + -C | --clean Clean up generated files (*.ts-[0-9]*.out.ts) + [ ...] Specify one or more TypeScript files to be processed +``` +## Example with binary-search.ts + +You can execute the following commands to get the CFG graph of the test case `binary-search.ts`, and the +TypeScript code converted from the corresponding AST. + +### 1. Command lines +```bash +cd MapleFE/test/typescript/unit_tests +../../astdump.sh --cfg --syntax binary-search.ts +``` + +### 2. CFG graph of function "binarySearch" + +This is the CFG graph of function `binarySearch`. + + + +### 3. TypeScript code converted from the corresponding AST + +This is the TypeScript code generated from AST. + + + diff --git a/src/MapleFE/docs/astvisitor.md b/src/MapleFE/docs/astvisitor.md new file mode 100644 index 0000000000000000000000000000000000000000..6a579350701c0463ca903e31834acd571ad792f6 --- /dev/null +++ b/src/MapleFE/docs/astvisitor.md @@ -0,0 +1,86 @@ +## Overview of AstVisitor + +The `AstVisitor` class is to let you be able to traverse an AST in a depth-first manner and call a visitor +function for each node in the AST. Each visitor function for a tree node can be overridden by a customized +visitor in a derived class of `AstVisitor`. + +A customized visitor enable you to gather any interesting information of a tree node and replace this tree +node with another which the customized visitor returns. + +## Creat your own visitors in a derived class of AstVisitor + +First of all, you need to derive a class from `AstVisitor` and implement your own visitors for any nodes to +be processed. + +Here is an example. The class `MyVisitor` is derived from `AstVisitor` and has two customized visitors +implemented for `CondBranchNode`. + + +```c +class MyVisitor : public AstVisitor { + ... ... + CondBranchNode *VisitCondBranchNode(CondBranchNode *node); +} +``` + +```c +CondBranchNode *MyVisitor::VisitCondBranchNode(CondBranchNode *node) { + // Do something as needed + ... + // Call AstVisitor::VisitCondBranchNode to traverse subtrees of this node if needed + AstVisitor::VisitCondBranchNode(node); + return node; +} +``` + +## Replace a tree node with another one + +You may replace a tree node with another one with your customized visitor. + +```c +CondBranchNode *MyVisitor::VisitCondBranchNode(CondBranchNode *node) { + // Do something as needed + ... + // Create a new CondBranchNode node to replace the current one + CondBranchNode *new_node = ...; + return new_node; +} +``` + +The customized visitor `MyVisitor::VisitCondBranchNode()` visits a node which is the root of a subtree, +and replace this node with `new_node` which is the root of another subtree. This provides a way to +transform a subtree into a new subtree when needed. + +## How does the replacement work? + +The `AstVisitor` class is declared and defined in `MapleFE/output/typescript/ast_gen/shared/gen_astvisitor.{h,cpp}`. + +```c +BlockNode *AstVisitor::VisitBlockNode(BlockNode *node) { + if (node != nullptr) { + if (mTrace) { + std::cout << "Visiting BlockNode, id=" << node->GetNodeId() << "..." << std::endl; + } + + for (unsigned i = 0; i < node->GetChildrenNum(); ++i) { + if (auto t = node->GetChildAtIndex(i)) { + auto n = VisitTreeNode(t); + if (n != t) { // If the returned node 'n' is not the same as 't' + node->SetChildAtIndex(i, n); // the current child node `t` of BlockNode is replaced with 'n' + } + } + } + + if (auto t = node->GetSync()) { + auto n = VisitTreeNode(t); + if (n != t) { // Similar as mentioned above + node->SetSync(n); + } + } + } + return node; +} +``` + +if a `CondBranchNode` node is a child of a `BlockNode` node, and `MyVisitor::VisitCondBranchNode()` returns +a new node, this child node of the `BlockNode` node will be replaced with the one returned. diff --git a/src/MapleFE/docs/builtin-constructors.md b/src/MapleFE/docs/builtin-constructors.md new file mode 100644 index 0000000000000000000000000000000000000000..aa844737710707a03f7a67d1b7751fb919b9b24c --- /dev/null +++ b/src/MapleFE/docs/builtin-constructors.md @@ -0,0 +1,123 @@ + +## JavaScript built-in objects + +JavaScript built-in object info is available at: + +### 1. ECMA-262 standard +https://262.ecma-international.org/12.0/#sec-ecmascript-standard-built-in-objects +``` +Under sections: + 19 The Global Object + 20 Fundamental Objects + 21 Numbers and Dates + 22 Text Processing + 23 Indexed Collections + 24 Keyed Collections + 25 Structured Data +``` + +### 2. Mozilla Developer docs +https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference under Built-in objects + +## JavaScript built-in object constructors + +Not all built-in objects work as object constructors. The following is a list of +JavaScript built-in objects that works as object constructors to create objects +of corresponding built-in type: + +### 1. List of JavaScript built-in object constructors +``` + 1 AggregateError + 2 Array + 3 ArrayBuffer + 4 AsyncFunction + 5 BigInt64Array + 6 BigUint64Array + 7 Boolean + 8 DataView + 9 Date + 10 Error + 11 EvalError + 12 FinalizationRegistry + 13 Float32Array + 14 Float64Array + 15 Function + 16 Generator + 17 GeneratorFunction + 18 Int16Array + 19 Int32Array + 20 Int8Array + 21 InternalError (Mozilla only) + 22 Map + 23 Number + 24 Object + 25 Promise + 26 Proxy + 27 RangeError + 28 ReferenceError + 29 RegExp + 30 Set + 31 SharedArrayBuffer + 32 String + 33 Symbol + 34 SyntaxError + 35 TypeError + 36 Uint16Array + 37 Uint32Array + 38 Uint8Array + 39 Uint8ClampedArray + 40 URIError + 41 WeakMap + 42 WeakRef + 43 WeakSet +``` + +### 2. JavaScript builtin String/Number/Boolean object constructor and string/number/boolean primitive +https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_primitives_and_string_objects + +"Note that JavaScript distinguishes between String objects and primitive string values. (The same is true of Boolean and Numbers.) + +String literals (denoted by double or single quotes) and strings returned from String calls in a non-constructor context (that is, called without using the new keyword) are primitive strings. JavaScript automatically converts primitives to String objects, so that it's possible to use String object methods for primitive strings. In contexts where a method is to be invoked on a primitive string or a property lookup occurs, JavaScript will automatically wrap the string primitive and call the method or perform the property lookup." +``` + 1 var s1 : string = "test"; // string literal + 2 var s2 : String = "test"; // string literal + 3 var s3 : string = String("test"); // string literal + 4 var s4 : String = String("test"); // string literal + 5 var s5 : String = new String("test"); // String object + 6 console.log(typeof(s1)); // string + 7 console.log(s1.slice(1,2)); // string literal s1 wrapped/converted to String object for call + 8 console.log(typeof(s2)); // string + 9 console.log(typeof(s3)); // string + 10 console.log(typeof(s4)); // string + 11 console.log(typeof(s5)); // object +``` + +For TypeScript to C++ mapping, string primitive maps to std::string, and String objects maples to builtin String object t2crt::String (same for Booelan and Numbers). + +The type returned by JavaScript/TypeScript String/Number/Boolean builtin/constructor function depends on the usage: +- when used as a function, it is a type converter (convert between literal typeis), returns primitve/literal type string/number/boolean +- when used with new op(), it is a constructor and returns an object +- A variable declared as primitve type string/number/boolean will be wrapped/converted to a String/Number/Boolean object if any object property/method is referenced + For TypeScript to C++, this conversion can be done by the runtime, but there is opportunity for optimization if it can be determined at compile time whether a primitive will be used as an object, in which case the primitve literal can be generated as object intead. + + +## TypeScript types + +Additionally these TypeScript types will be treated as built-in object types too: +- Record +- Tuple +- Iterable +- Iterator + +### 1. Record and Tuple types +Record and Tuple currently are TypeScript only types. They are +not ECMA-262 standard yet, but has been proposed and undergoing standardization. + +- https://tc39.es/proposal-record-tuple +- https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types +- https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type + +### 2. Iterable and Iterator types +These are TypeScript types +- https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-6.html#stricter-generators +- https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html#iterable-interface diff --git a/src/MapleFE/docs/maplefe-autogen.md b/src/MapleFE/docs/maplefe-autogen.md new file mode 100644 index 0000000000000000000000000000000000000000..843f2b6a7a7f2f506037b0e0624821a8a97568d7 --- /dev/null +++ b/src/MapleFE/docs/maplefe-autogen.md @@ -0,0 +1,138 @@ +## Overview +The Python script `maplefe-autogen.py` is a tool to generate the code for class `AstVisitor`, `AstDump`, `AstGraph`, +etc. for AST tree. + +Whenever a new kind of AST tree node is introduced for a new language feature in the future, or any changes are made +to the existing AST tree node, these classes will be updated automatically. It reduces the maintenance effort and +ensures the consistency and completeness of these classes. + +## How does it work? + +It makes use of `clang-doc-10` to parse source file `ast_builder.cpp` and get its documentation files in YAML format. +These YAML files are fed into `maplefe-autogen.py` to generate C++ header and source files as described below. + +## What should I do to generate a new C++ class? + +Let's use `AstVisitor` as an example to explain it. + +### 1. Set filename, class name, prefix of function name and extra include directives + +```python +gen_args = [ + "gen_astvisitor", # Filename + "AstVisitor", # Class name + "Visit", # Prefix of function name + "", # Extra include directives + ] +``` +The list `gen_args` contains the filename, class name, prefix of function name and extra include directives for +generating C++ header and source files. You have to use the list name `gen_args` for them. + +### 2. Define the specific content in header file + +```python +astvisitor_init = [ +""" +private: +bool mTrace; + +public: +{gen_args1}(bool t = false) : mTrace(t) {{}} + +TreeNode* {gen_args2}(TreeNode* node) {{ + return {gen_args2}TreeNode(node); +}} +""".format(gen_args1=gen_args[1], gen_args2=gen_args[2]) +] # astvisitor_init +``` +The list `astvisitor_init` contains the specific content in C++ header file. The list name can be customized. + +### 3. Set callback functions for each part of a C++ function for a AST node + +The following callback functions are defined for generating the code for `AstVisitor`. + +```python +gen_call_handle_values = lambda: False +``` +This function returns true or false. +There are two kinds of fields in an AST node. One is a pointer to another AST node, and another is +a value with a non-AST-node type, such as enum, int, etc. +If this function returns false, all non-AST-node values will be ignored. + + +```python +gen_func_declaration = lambda dictionary, node_name: ... +``` +Function `gen_func_declaration` returns a string for the declaration of a function for an AST node `node_name`. The result will be in +the C++ header file. + + +```python +gen_func_definition = lambda dictionary, node_name: ... +``` +Function `gen_func_definition` returns a string for the definition of a function for an AST node `node_name`. The result will be in +the C++ source file. Any code which occurs at the beginning of its function body can be placed here. + + +```python +gen_call_child_node = lambda dictionary, node_name, field_name, node_type, accessor: ... +``` +Function `gen_call_child_node` returns a string with the statements to handle a child AST node `field_name`. The child node has +`node_type` and you can use `accessor` to get its pointer value. + + +```python +gen_call_children_node = lambda dictionary, node_name, field_name, node_type, accessor: '' +``` +Function `gen_call_children_node` returns a string with the statements to handle a SmallVector or SmallList node `field_name` with +`node_type`. The `accessor` can be used to get its pointer value. It returns an empty string for `AstVisitor`. + + +```python +gen_call_children_node_end = lambda dictionary, node_name, field_name, node_type, accessor: '' +``` +Function `gen_call_children_node_end` returns a string with the statements following the for-loop for each value stored in the +SmallVector or SmallList node `field_name`. It returns an empty string for `AstVisitor`. + + +```python +gen_func_definition_end = lambda dictionary, node_name: '}\nreturn node;\n}' +``` +Function `gen_func_definition_end` returns a string with the statements at the end of the function body. + +Since it does not need to handle any non-AST-node values, therefore some functions for values are missing for `AstVisitor`. + +### 4. Generate the code in C++ header and source files + +Here is the code block for generating the C++ code. +```python +handle_src_include_files(Initialization) +append(include_file, astvisitor_init) +handle_yaml(initial_yaml, gen_handler) +handle_src_include_files(Finalization) +``` + +It has to call `handle_src_include_files(Initialization)` and `handle_src_include_files(Finalization)` at the beginning and end of the block as shown above. + +```python +append(include_file, astvisitor_init) +``` +This is to append the code in list `astvisitor_init` to the C++ header file. + +```python +handle_yaml(initial_yaml, gen_handler) +``` +This function call `handle_yaml(initial_yaml, gen_handler)` is to handle all related YAML file, call the `gen_func_*` and `gen_call_*` callback functions defined at step 3, and generate the code in C++ header and source files with them. + +## Where are the generated files located? + +They can be found under directory `MapleFE/output/typescript/ast_gen/shared/`. +```bash +MapleFE/output/typescript/ast_gen/shared/gen_astvisitor.h +MapleFE/output/typescript/ast_gen/shared/gen_astvisitor.cpp +``` + +## Format of the generated C++ header and source files + +The generated C++ header and source files will be formatted with clang-format-10. You do not +have to format the generated code manually. diff --git a/src/MapleFE/docs/readme b/src/MapleFE/docs/readme new file mode 100644 index 0000000000000000000000000000000000000000..9ff4bbefc70014338c1bd442785b82389db6b262 --- /dev/null +++ b/src/MapleFE/docs/readme @@ -0,0 +1,192 @@ +1. SOURCE CODE +============== + +git clone https://gitee.com/openarkcompiler/OpenArkCompiler -b dev_MapleFE + +2. ENVIRONMENT +============== +System software versions used: + Ubuntu: 20.04 + Typescript: 4.5.5 + Nodejs: 14.7.0 + +export MFE=~/OpenArkCompiler/src/MapleFE +export tsbin=$MFE/output/typescript/bin +export rtsrc=$MFE/ast2cpp/runtime/src +export unit=$MFE/test/typescript/unit_tests +export rtsrc=$MFE/ast2cpp/runtime/src +alias runbld='cd $MFE;source envsetup.sh typescript;make -j16;cd -' +alias runtest='rm cxx.log; ../ts2cxx-test.sh +alias goutil='cd $MFE/test/typescript/utils' +alias gofe='cd $MFE' +alias gocpp='cd $MFE/ast2cpp/src' +alias gort='cd $MFE/ast2cpp/runtime/include' +alias gounit='cd $unit' + +- To build everything: runbld +- To run unit tests: cd $unit; runtest +- To run single test: cd $unit; ../ts2cxx-test.sh +- To run TSC compile and nodejs execute of JS only for specific testcase: cd $unit; ../tsc.sh +- CPP emitter source code: $MFE/ast2cpp/src +- MapleFe compiler toolsfor TSC: + o xxx.ts -> [ast2cpp] -> xxx.ts.ast -> [ast2cpp] -> xxx.h xxx.cpp + o $tsbin/ts2ast - Compile .ts into .ts.ast + o $tsbin/ast2cpp - Compiles .ts.ast into .cpp or back into .ts (for verification) + o $MFE/test/astdump.sh - Dump AST tree from .ts.ast. Output can be text or graph. + o run each of above cmds to see parameters and options, e.g. $tsbin/ast2cpp will display: + ast2cpp a.ast[,b.ast] [options]: + --out=x.cpp : cpp output file + --help : print this help + --trace=n : Emit trace with 4-bit combo levels 1...15 + 1 : Emit ast tree visits + 2 : Emit graph + --emit-ts-only : Emit ts code only + --emit-ts : Emit ts code + --format-cpp : Format cpp + ... +- For graphic view of JavaScript object inheritance relations: + o cd $MFE/docs/util; node proto.js | ./viewdot.sh + +3. Run a single case from .ts + 1) ~/OpenArkCompiler/src/MapleFE/output/typescript/bin/ts2ast while-stmt.ts + This creates while-stmt.ts.ast at the same directory + 2) ~/OpenArkCompiler/src/MapleFE/output/typescript/bin/ast2cpp while-stmt.ts.ast + This generates the while-stmt.cpp + 3) g++ -g -o run -I/home/ubuntu/OpenArkCompiler/src/MapleFE/ast2cpp/runtime/include -I/home/ubuntu/OpenArkCompiler/src/MapleFE/astopt/include -std=c++17 while-stmt.cpp /home/ubuntu/OpenArkCompiler/src/MapleFE/ast2cpp/runtime/src/*.cpp + This generates the executable run. + 4) ./run to test the result. + +4. TypeScript/JavaScript inheritance modeling in C++ +==================================================== + +4.1 JavaScript Object Properties + +JavaScript objects have both instance properties and inherited +properties. Instance properties are held in the object's own property +list. Inherited properties are held in an object pointed to by the +instance property __proto__. + +The chain of __proto__ between objects forms a hierarchical prototype +chain used in the lookup for an object's inherited properties. Inherited +properites have only a single copy and is shared by all objects that +inherits the property. + +In Javascript, object property lookup order is: +- first lookup instance property (from property list of current object) +- then lookup inherited property (from property list of object pointed to + by chain of __proto__ starting from __proto__ of current object + +4.2 TypeScript/JavaScript inheritance modeling in C++ + +The inheritance relationship of TS/JS objects is mapped to C++ as +classes derived hierarchically along the __proto__ chain. This allows +accessing inherited properties directly as C++ fields and methods of +parent classess, instead of having to traverse the __proto__ chain. + +To maintain continued support of property lookup by __proto__ chain +traversal, each object has a proplist which is a C++ map of the object's +property name and value pairs. + +Proplist entries for runtime created instance properties holds the +actual property value. Proplist entries for properties generated as +C++ class fields and methods at compile time holds pointers to class +fields and methods. + +This guarantees continued functioning of run time property lookup +using prop list and __proto__ chain traversal. This is necessary not +only because of compatibility but also because TS objects can have +instance properties created at runtime which can only be accessed +through prop list because they cannot be generated as C++ class fields +at compile time. + +To ensure inherited properties have only a single copy, all properties +in prototype objects are generated at compile time as C++ static class +fields and methods and accessed either via direct C++ object field +reference, or via pointers from the prototype object's proplist. + +Note that where __proto__ points to a JavaScript function constructor +instead of a prototype object, there is still only a single copy of +inheited properties, because in JavaScript, there is only 1 single +instance of each function constructor. + +4.3 Property inheritance with __proto__ chain + +See environment section in readme for instruction to view graphic +display of JavaScript object inheritance relationship. The following +graphs will be displayed: + + Graph Id. Graph Name + 1. Class Graph with Constructor Edges + 2. Generator Graph with Constructor Edges + 3. Builtin Graph with Constructor Edges + 4. Closure Graph with Constructor Edges + 5. Iterator Graph with Constructor Edges + 6. Async Graph with Constructor Edges + 7. Class Graph + 8. Generator Graph + 9. Builtin Graph + 10. Closure Graph + 11. Iterator Graph + 12. Async Graph + +The CPP emitter optimises property access with static compilation by: +- Generate C++ class fields and methods for JS properties of an object and +- Generate code to access JS properties directly as C++ object fields/method +- Disallow runtime modification of __proto__ property. +- Disallow runtime modification of inheritable properties in prototype objects. + +All JavaScript objects have a __proto__ property. Depending on what the +kind of JS object, its __proto__ may point to different kinds of JS objects: +note: (graph x: node x) cross refs example objects by id of graph above and node within graph. + +JS object What the object's __proto__ is set to +========= ===================================== +1) Object instances (What .__proto__ is set to) + a) Created by user defined or + builtin JS ctor functions, Prototype of the object's ctor function + e.g. myCar, car (graph 1: node 7, 14) (graph 1: node 8, 9) + including builtin objects: + - JSON (graph 3: node 7) (graph 3: node 1) + - Math (graph 3: node 6) + b) Special object instances: + - user defined generators The builtin "Generator" (renamed GeneratorFunction.prototype in 2022 spec) + (graph 2: node 4) (graph 2: node 8) + - generator instances returned by Prototype of user defined generator that returned the instance + user defined generators (graph 2: node 5) + (graph 2: node 10) + +2) Prototype object of ctor function which is: (What .prototype.__proto__ is set to) + a) ctor of a JS class Prototype of ctor of class it extends + (graph 1: node 8) (graph 1: node 9) + b) ctor of top level func or class Prototype of the builtin "Object" (Object.prototype) + (graph 1: node 10) (graph 1: node 1) + includes builtin functions + - Symbol (graph 3: node 5) (graph 3: node 1) + - Promise (graph 3: node 9) (graph 3: node 1) + +3) Special Prototype objects + a) prototype of user defined generators The builtin "GeneratorPrototype" + (graph 2: node 5) (graph 2: node 6) + b) the builtin "Generator" Prototype of the builtin "Function" (Function.prototype) + (graph 2: node 8) (graph 2: node 2) + (GeneratorFunction.prototype in 2022 spec) + c) the builtin "GeneratorPrototype" The builtin "IteratorPrototype" + (graph 2: node 6) (graph 2: node 7) + (renamed GeneratorFunction.prototype.prototype in 2022 spec) + d) the builtin "IteratorPrototype" Prototype of the builtin "Object" (Object.prototype) + (graph 2: node 7) (graph 2: node 1) + note: A prototype object is usaually the prototype object of its constructor + but IteraorPrototype is an exception. Its constructor is "Object" but + it is not the prototype object of "Object", or any other ctor function. + It's an independent prototype object that does not belong to any constructor + +4) Ctor function (What .__proto__ is set to) + a) ctor for a JS class Ctor of class it extends (i.e parent class) + (graph 1: node 13) (graph 1: node 12) + b) top level func or class Prototype of the builtin "Function" (Function.prototype) + (graph 1: node 11) (graph 1: node 2) + includes builtin functions + - Symbol (graph 3: node 4) (graph 3: node 2) + - Promise (graph 3: node 8) + c) the builtin "GeneratorFunction" Ctor of "Function" ("GeneratorFunction extends Function" - so use rule a) + (graph 2: node 9) (graph 2: node 3) diff --git a/src/MapleFE/docs/utils/README b/src/MapleFE/docs/utils/README new file mode 100644 index 0000000000000000000000000000000000000000..1364eab75456cecfec2e7c9c6fa34a87720e5a50 --- /dev/null +++ b/src/MapleFE/docs/utils/README @@ -0,0 +1,13 @@ +Contents in this directory: + +o proto.js + - Sample Javascript program to demonstrate object inheritance with constructors, prototype chain and prototype properties. + - Run with following commands: + node proto.js | ./viewdot.sh +o proto.cpp + - Sample C++ program based on proto.js to demonstrate how JavaSCript object inheritance can be modeled in C++. + - Run with following commands: + g++ ../../ast2cpp/runtime/src/builtins.cpp ../../ast2cpp/runtime/src/ts2cpp.cpp proto.cpp; + ./a.out | ./viewdot.sh + +note: requires dot and viewnior for graph generation and display. diff --git a/src/MapleFE/docs/utils/proto-ctor.png b/src/MapleFE/docs/utils/proto-ctor.png new file mode 100644 index 0000000000000000000000000000000000000000..d6fa7cff21607b69e556bb167f278d20c3d31c9b Binary files /dev/null and b/src/MapleFE/docs/utils/proto-ctor.png differ diff --git a/src/MapleFE/docs/utils/proto.cpp b/src/MapleFE/docs/utils/proto.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e57e11232bc7eae40cc3b99903edfd781acbde1b --- /dev/null +++ b/src/MapleFE/docs/utils/proto.cpp @@ -0,0 +1,112 @@ +#include "../../ast2cpp/runtime/include/ts2cpp.h" + +using namespace t2crt; + +class Ctor_Vehicle; +class Ctor_Car; +class Ctor_MyCar; + +class Vehicle; +class Car; +class MyCar; + +extern Ctor_Vehicle Vehicle_ctor; +extern Ctor_Car Car_ctor; +extern Ctor_MyCar MyCar_ctor; + +class Vehicle : public Object { + public: + Vehicle(Function* ctor, Object* proto): Object(ctor, proto) {} + // Vehicle.prototype props (use static) + + public: + // Vehicle instance props + std::string name; +}; + +class Car : public Vehicle { + public: + Car(Function* ctor, Object* proto): Vehicle(ctor, proto) {} + // Car.prototype props (use static) + + public: + // Car instance props +}; + +// C++ Class def for instance props and prototype props +class MyCar : public Car { + public: + MyCar(Function* ctor, Object* proto): Car(ctor, proto) {} + // MyCar.prototype props (use static) + + public: + // MyCar instance props +}; + +// Class def for function constructors + +class Ctor_Vehicle : public Function { + public: + Ctor_Vehicle(Function* ctor, Object* proto, Object* prototype) : Function(ctor, proto, prototype) {} + + Vehicle* _new() { + return new Vehicle(this, this->prototype); + } + + void operator()(Vehicle* obj , std::string name) { + // add instance props to instance prop list + ClassFld field(&Vehicle::name); + obj->AddProp("name", field.NewProp(TY_String)); + // init instance props + obj->name = name; + } +}; + +class Ctor_Car : public Ctor_Vehicle { + public: + Ctor_Car(Function* ctor, Object* proto, Object* prototype) : Ctor_Vehicle(ctor, proto, prototype) {} + + Car* _new() { + return new Car(this, this->prototype); + } + + void operator()(Car* obj , std::string name) { + Vehicle_ctor(obj, name); + } +}; + +class Ctor_MyCar : public Ctor_Car { + public: + Ctor_MyCar(Function* ctor, Object* proto, Object* prototype) : Ctor_Car(ctor, proto, prototype) {} + + MyCar* _new() { + return new MyCar(this, this->prototype); + } + + void operator()(MyCar* obj , std::string name) { + Car_ctor(obj, name); + } +}; + +// Function constructors +Ctor_MyCar MyCar_ctor (&Function_ctor, &Car_ctor, Car_ctor.prototype); +Ctor_Car Car_ctor (&Function_ctor, &Vehicle_ctor, Vehicle_ctor.prototype); +Ctor_Vehicle Vehicle_ctor (&Function_ctor, Function_ctor.prototype, Object_ctor.prototype); + +// Object instances +Car* car = Car_ctor._new(); +MyCar* mycar= MyCar_ctor._new(); +Array* arr = Array_ctor._new(); +Object* obj = Object_ctor._new(); + +int main(int argc, char* argv[]) { + // InitAllProtoTypeProps(); + + Car_ctor(car, "Tesla"); + MyCar_ctor(mycar, "Tesla Model X"); + std::vector objs = {obj, arr, &Array_ctor, &Vehicle_ctor, &Car_ctor, &MyCar_ctor, car, mycar, &Function_ctor, &Object_ctor}; + std::vector names = {"obj", "arr", "Array", "Vehicle", "Car", "MyCar", "car", "mycar", "Function", "Object"}; + GenerateDOTGraph(objs, names); + return 0; +} + diff --git a/src/MapleFE/docs/utils/proto.js b/src/MapleFE/docs/utils/proto.js new file mode 100644 index 0000000000000000000000000000000000000000..6115e6d550e9b98a8657ae0ac7a7482e2d9ebcec --- /dev/null +++ b/src/MapleFE/docs/utils/proto.js @@ -0,0 +1,98 @@ +// Command line to get graphs: nodejs proto.js | ./viewdot.sh +class Vehicle { + constructor (name) { this.name = name; } +} +class Car extends Vehicle { + constructor (name) { super(name); } +} +class MyCar extends Car { + constructor (name) { super(name); } +} + +let car = new Car("A car"); +let myCar = new MyCar("My car"); +let arr = [1, 2, 3] +let regexpr = /ab+c/i + +function* generator() { yield 1; } +const gpt = generator.prototype.__proto__; + +function makeClosure(a) { + return function (b) { + return a + b; + } +} +const closure = makeClosure(1); + +let myMap = new Map(); +let myMapIterator = myMap[Symbol.iterator](); +let MapIteratorPrototype = Object.getPrototypeOf(new Map()[Symbol.iterator]()); + +async function asyncFunction() {} +async function* asyncGenerator() {} +const agpt = asyncGenerator.prototype.__proto__; + +// All data for generating graphs +let graphData = { + Class : ["Array", "arr", "myCar", "car"], + Generator: ["generator", [generator(), "generator_instance"], [gpt, "GeneratorPrototype"], + [gpt.__proto__, "IteratorPrototype"], [generator.__proto__, "Generator"]], + Builtin : ["Symbol", "Math", "JSON", "Promise", "RegExp", "regexpr"], + Closure : ["makeClosure", "closure"], + Iterator : ["myMap", "myMapIterator", "MapIteratorPrototype", [gpt.__proto__, "IteratorPrototype"]], + Async : ["asyncFunction", "asyncGenerator", [asyncGenerator(), "asyncGenerator_instance"], [agpt, "AsyncGeneratorPrototype"], + [agpt.__proto__, "AsyncIteratorPrototype"], [asyncGenerator.__proto__, "AsyncGenerator"]], +}; + +generateGraph(graphData); + +function generateGraph(data) { + // Gather all reachable objects from their prototype, __proto__ and constructor properties + function insert(g, depth, ...args) { + for (let arg of args) { + let [o, name] = typeof arg === "string" ? [eval(arg), arg] : arg; + if (typeof o !== "undefined" && o !== null) + if (!g.has(o)) { + g.set(o, name !== null || typeof o !== "function" ? name : o.toString().split(" ")[1].replace(/[^a-zA-Z0-9+]/g, "")); + insert(g, depth + 1, [o.prototype, g.get(o) === null ? null : g.get(o) + "Prototype"], [o.__proto__, null], [o.constructor, null]); + } else if (name !== null) + g.set(o, name); + } + if (depth === 0) { + let visited = new Set(); + for (let [index, [key, val]] of Array.from(g).entries()) { + val = val === null || val === "" ? "Object_" + index : val.replace(/[^A-Za-z0-9]+/g, "_"); + if (visited.has(val)) val += "__" + index; + visited.add(val); + g.set(key, val); + } + } + } + + // Dump graphs with edges for prototype, __proto__ and constructor properties of each object + let nodejs = (typeof process !== 'undefined') && (process.release.name === 'node') + for (let prop in data) { + let graph = new Map(); + insert(graph, 0, "Function", "Object", ...data[prop]); + for (let ctor of ["", "_with_Constructor_Edges"]) { + console.log("digraph JS_" + prop + ctor + " {\nlabel=\"\\n" + prop + " Graph" + ctor.replace(/_/g, " ") + "\\n(Node in gray: function)" + + "\";\nrankdir = TB;\nranksep=0.6;\nnodesep=0.6;\n" + (ctor != "" ? "" : "newrank=true;")); + for (let [index, [key, val]] of Array.from(graph).entries()) { + let func = typeof key === "function"; + // Add comments with detailed information of keys + if (nodejs) + console.log("\n/* key =", key, "\nObject.getOwnPropertyNames(" + val + "):\n", Object.getOwnPropertyNames(key), + "\n" + val + ".toString(): " + (func ? key.toString().replace(/\s+/g, " ") : "-") + "\n*/"); + console.log(val + " [label=\"" + val + " " + (index < 4 ? 3 - index : index) + "\", shape=" + + (val.includes("Prototype") ? "box" : "oval") + (func ? ", style=filled" : "") + "];"); + // Add edges for prototype, constructor and __proto__ properties of objects + for (let [f, c] of [["prototype", "blue"], ["constructor", "darkgreen"], ["__proto__", "red"]]) + if (typeof key[f] !== "undefined" && key[f] !== null && graph.has(key[f]) && (ctor != "" || f !== "constructor")) + console.log((ctor != "" || f !== "prototype" ? "" : "subgraph cluster_" + val + " {\nlabel=\"\";rank=same;color=white;\n" + + val + ";\n" + graph.get(key.prototype) + " [shape=box];\n}\n") + val + " -> " + graph.get(key[f]) + + " [label=\"" + (f === "constructor" ? "ctor" : f) + "\", color=" + c + ", fontcolor=" + c + "];"); + } + console.log("} // digraph JS_" + prop + ctor); + } + } +} // generateGraph diff --git a/src/MapleFE/docs/utils/proto.png b/src/MapleFE/docs/utils/proto.png new file mode 100644 index 0000000000000000000000000000000000000000..b938c09f413a08ffcc3f90c994bf171a8320244b Binary files /dev/null and b/src/MapleFE/docs/utils/proto.png differ diff --git a/src/MapleFE/docs/utils/proto2.ts b/src/MapleFE/docs/utils/proto2.ts new file mode 100644 index 0000000000000000000000000000000000000000..d7d0c406520b346a16a93236e401f4debff57ace --- /dev/null +++ b/src/MapleFE/docs/utils/proto2.ts @@ -0,0 +1,54 @@ +interface IPrototype { prototype: any; } +type TPrototype = IPrototype & Function; +interface IProto { __proto__: any; } +type TProto = IProto & Object; + +// Command line to get graphs: tsc -t es6 proto2.ts; nodejs proto2.js | ./viewdot.sh +class Vehicle { +} +class Car implements Vehicle { + name: string; + constructor (name) { this.name = name; } +} +class MyCar extends Car { + constructor (name) { super(name); } +} + +let car = new Car("A car"); +let mycar = new MyCar("My car"); +let arr = [] + +// Dump graphs with edges for prototype, __proto__ and constructor properties of each objects +for(let g = 0; g < 2; ++g) { + let objs = [ arr, Array, Vehicle, Car, MyCar, car, mycar, Function, Object, ]; + let names = [ "arr", "Array", "Vehicle", "Car", "MyCar", "car", "mycar", "Function", "Object", ]; + console.log("digraph JS" + g + " {\nranksep=0.6;\nnodesep=0.6;\n" + (g == 0 ? "newrank=true;\n" : "")); + let num = objs.length; + let k = num; + // Add prototype objects and edges for them + for(let i = 0; i < num; ++i) { + let x = typeof (objs[i] as unknown as TPrototype).prototype; + if(x === "function" || x === "object") { + objs[k] = (objs[i] as unknown as TPrototype).prototype; + names[k] = names[i] + "_prototype"; + console.log(g == 0 ? "subgraph cluster_" + names[i] + " {\nrank=same;\ncolor=white;\n" + + names[i] + ";\n" + names[k] + "[label=\"" + names[i] + ".prototype\", shape=box];\n }" + : names[k] + "[label=\"" + names[i] + ".prototype\", shape=box];"); + console.log(names[i] + " -> " + names[k] + " [label=\"prototype\", color=blue, fontcolor=blue];"); + k++; + } + } + // Add edges for __proto__ and constructor properties of each objects + num = objs.length; + for(let i = 0; i < num; ++i) { + for(let j = 0; j < num; ++j) { + // Edges for constructor properties in the second graph only + if(g > 0 && objs[i].constructor === objs[j]) + console.log(names[i] + " -> " + names[j] + " [label=\"ctor\", color=darkgreen, fontcolor=darkgreen];"); + // Edges for __proto__ properties + if((objs[i] as unknown as TProto).__proto__ === objs[j]) + console.log(names[i] + " -> " + names[j] + " [label=\"__proto__\", color=red, fontcolor=red];"); + } + } + console.log("}"); +} diff --git a/src/MapleFE/docs/utils/viewdot.sh b/src/MapleFE/docs/utils/viewdot.sh new file mode 100755 index 0000000000000000000000000000000000000000..f9252d7c0ae07e7fb98cfdfa058bcfa6bcd6a583 --- /dev/null +++ b/src/MapleFE/docs/utils/viewdot.sh @@ -0,0 +1,23 @@ +#!/bin/bash +if [ $# -lt 1 ]; then + out=$(cat) + tmpdir=$(mktemp -dt viewdot-XXXXXX) + trap "rm -rf $tmpdir" SIGINT SIGQUIT SIGKILL + grep -n -e "digraph [^{]* {" -e "^} // digraph JS" <<< "$out" | grep -A1 "digraph [^{]* {" | + grep -v ^-- | sed 'N;s/\n/ /' | sed -e 's/:.*digraph [^{]* { */,/' -e 's/:.*/p/g' | + { while read cmd; do + name=$(sed -n $cmd <<< "$out" | head -1 | sed 's/.*digraph \([^{]*\) {.*/\1/') + echo $$-$name + sed -n $cmd <<< "$out" > "$tmpdir"/$$-$name.dot + dot -Tpng -o "$tmpdir"/$$-$name.png "$tmpdir"/$$-$name.dot + env LC_ALL=C viewnior "$tmpdir"/$$-$name.png & + done + wait + rm -rf "$tmpdir"; } + exit +fi +for f; do + dot -Tpng -o $f.png $f + viewnior $f.png + rm -f $f.png +done diff --git a/src/MapleFE/envsetup.sh b/src/MapleFE/envsetup.sh index 1895cbccb164fd281ea3a071a2fc425bec9b3281..bc75a54707313c7edd50cad8b64557d54b67b914 100755 --- a/src/MapleFE/envsetup.sh +++ b/src/MapleFE/envsetup.sh @@ -12,26 +12,35 @@ # FIT FOR A PARTICULAR PURPOSE. # See the Mulan PSL v2 for more details. # +if [ "${BASH_SOURCE[0]}" -ef "$0" ]; then + echo "This script should be sourced in a bash shell, not executed directly" + exit 1 +fi function print_usage { echo " " - echo "usage: source envsetup.sh" + echo "usage: source envsetup.sh java/typescript/c" echo " " } -if [ "$#" -ne 0 ]; then +if [ "$#" -gt 1 ]; then echo $# print_usage return fi -pdir=$(cd ..; pwd) -unset MAPLE_ROOT -export MAPLE_ROOT=${pdir} +LANGSRC=java +if [ "$#" -eq 1 ]; then + if [ $1 = "typescript" ]; then + LANGSRC=typescript + elif [ $1 = "c" ]; then + LANGSRC=c + fi +fi +export SRCLANG=$LANGSRC -curdir=$(pwd) -unset MAPLEFE_ROOT -export MAPLEFE_ROOT=${curdir} +export MAPLEFE_ROOT=$(cd $(dirname ${BASH_SOURCE[0]}); pwd) +export MAPLE_ROOT=$(cd ${MAPLEFE_ROOT}/../../..; pwd) unset MAPLEALL_ROOT export MAPLEALL_ROOT=${MAPLE_ROOT}/OpenArkCompiler @@ -40,4 +49,4 @@ unset MAPLEALL_SRC export MAPLEALL_SRC=${MAPLEALL_ROOT}/src/mapleall unset BUILDDIR -export BUILDDIR=${MAPLEFE_ROOT}/output +export BUILDDIR=${MAPLEFE_ROOT}/output/${SRCLANG} diff --git a/src/MapleFE/java/attr.spec b/src/MapleFE/java/attr.spec index daa682e84c9fcd5953172872560e37cdf0922498..3f098f9c9ab505abc952ee48b66ba263220b9529 100644 --- a/src/MapleFE/java/attr.spec +++ b/src/MapleFE/java/attr.spec @@ -31,5 +31,6 @@ STRUCT Attribute : (("abstract", abstract), ("public", public), ("static", static), ("strictfp", strictfp), - ("default", default)) + ("default", default), + ("synchronized", synchronized)) diff --git a/src/MapleFE/java/block.spec b/src/MapleFE/java/block.spec deleted file mode 100644 index 905f252c80befab9080c03548ad4c8b87453940e..0000000000000000000000000000000000000000 --- a/src/MapleFE/java/block.spec +++ /dev/null @@ -1,346 +0,0 @@ -# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. -# -# OpenArkFE is licensed under the Mulan PSL v2. -# You can use this software according to the terms and conditions of the Mulan PSL v2. -# You may obtain a copy of Mulan PSL v2 at: -# -# http://license.coscl.org.cn/MulanPSL2 -# -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -# FIT FOR A PARTICULAR PURPOSE. -# See the Mulan PSL v2 for more details. -# -################################################################################### -# This file defines the Java Block/Class/Interface statement. -################################################################################### - -rule ClassDeclaration : ONEOF(NormalClassDeclaration, EnumDeclaration) - attr.property : Single, Top -rule NormalClassDeclaration : ZEROORMORE(ClassModifier) + "class" + Identifier + - ZEROORONE(TypeParameters) + ZEROORONE(Superclass) + - ZEROORONE(Superinterfaces) + ClassBody - attr.action : BuildClass(%3) - attr.action : AddModifier(%1) - attr.action : AddClassBody(%7) - attr.action : AddSuperClass(%5) - attr.action : AddSuperInterface(%6) - attr.property.%1,%4,%5,%6 : ZomFast - -rule ClassAttr : ONEOF("public", "protected", "private", "abstract", "static", "final", "strictfp") - attr.property : Single -rule ClassModifier : ONEOF(Annotation, ClassAttr) - attr.property : Single - -# 1. Generic class -# 2. TypeParameter will be defined in type.spec -rule TypeParameters : '<' + TypeParameterList + '>' -rule TypeParameterList : TypeParameter + ZEROORMORE(',' + TypeParameter) -rule TypeParameter : ZEROORMORE(TypeParameterModifier) + Identifier + ZEROORONE(TypeBound) -rule TypeParameterModifier : Annotation -rule TypeBound : ONEOF("extends" + TypeVariable, - "extends" + ClassOrInterfaceType + ZEROORMORE(AdditionalBound)) -rule AdditionalBound : '&' + InterfaceType - -# ClassType and InterfaceType are defined in type.spec -rule Superclass : "extends" + ClassType -rule Superinterfaces : "implements" + InterfaceTypeList -rule InterfaceTypeList : InterfaceType + ZEROORMORE(',' + InterfaceType) - -# class body -rule ClassBody : "{" + ZEROORMORE(ClassBodyDeclaration) + "}" - attr.action: BuildBlock(%2) - attr.property.%2 : ZomFast - -rule ClassBodyDeclaration : ONEOF(ClassMemberDeclaration, - InstanceInitializer, - StaticInitializer, - ConstructorDeclaration) - attr.property : Single - -rule InstanceInitializer : Block - attr.action: BuildInstInit(%1) -rule StaticInitializer : "static" + Block - attr.action: BuildInstInit(%2) - attr.action: AddModifierTo(%2, %1) - -rule ClassMemberDeclaration : ONEOF(FieldDeclaration, - MethodDeclaration, - ClassDeclaration, - InterfaceDeclaration, - ';') - attr.property : Single - -rule FieldDeclaration : ZEROORMORE(FieldModifier) + UnannType + VariableDeclaratorList + ';' - attr.action: BuildDecl(%2, %3) - attr.action: AddModifier(%1) - -rule MethodDeclaration : ZEROORMORE(MethodModifier) + MethodHeader + MethodBody - attr.action: AddModifierTo(%2, %1) - attr.action: AddFunctionBodyTo(%2, %3) - -rule MethodBody : ONEOF(Block, ';') - attr.property : Single -rule MethodHeader : ONEOF(Result + MethodDeclarator + ZEROORONE(Throws), - TypeParameters + ZEROORMORE(Annotation) + Result + MethodDeclarator + - ZEROORONE(Throws)) - attr.action.%1: AddTypeTo(%2, %1) - attr.action.%1: AddThrowsTo(%2, %3) - attr.action.%2: AddTypeTo(%4, %3) - attr.action.%2: AddThrowsTo(%4, %5) - attr.property : Single - -rule Result : ONEOF(UnannType, "void") - attr.property : Single -rule MethodDeclarator : Identifier + '(' + ZEROORONE(FormalParameterList) + ')' + ZEROORONE(Dims) - attr.action: BuildFunction(%1) - attr.action: AddParams(%3) - attr.action: AddDims(%5) - -rule Throws : "throws" + ExceptionTypeList - attr.action: BuildThrows(%2) - -rule ExceptionTypeList : ExceptionType + ZEROORMORE(',' + ExceptionType) -rule ExceptionType : ONEOF(ClassType, TypeVariable) - -rule MethodAttr : ONEOF("public", "protected", "private", "abstract", "static", - "final", "synchronized", "native", "strictfp") - attr.property : Single - -rule MethodModifier : ONEOF(Annotation, MethodAttr) - attr.property : Single - -rule FormalParameterListNoReceiver : ONEOF(FormalParameters + ',' + LastFormalParameter, - LastFormalParameter) - attr.action.%1: BuildVarList(%1, %3) - -# ReceiverParameter and FormalParameterListNoReceiver could match at the same -# but with different num of tokens. Here is an example -# foo(T T.this) -# The NoReceiver could match "T T", while Receiver match "T T.this". -# Although later it figures out NoReceiver is wrong, but at this rule, both rule work. -# If we put NoReceiver as the 1st child and set property 'Single', we will miss -# Receiver which is the correct one. -# -# So I move Receiver to be the 1st child, since NoReceiver is not correct matching -# if Receiver works. -rule FormalParameterList : ONEOF(ReceiverParameter, FormalParameterListNoReceiver) - attr.property : Single - -rule FormalParameters : ONEOF(FormalParameter + ZEROORMORE(',' + FormalParameter), - ReceiverParameter + ZEROORMORE(',' + FormalParameter)) - attr.action.%1: BuildVarList(%1, %2) - attr.property : Single - -rule FormalParameter : ZEROORMORE(VariableModifier) + UnannType + VariableDeclaratorId - attr.action: BuildDecl(%2, %3) - attr.action: AddModifier(%1) -rule ReceiverParameter : ZEROORMORE(Annotation) + UnannType + ZEROORONE(Identifier + '.') + "this" - -rule LastFormalParameter : ONEOF(ZEROORMORE(VariableModifier) + UnannType + ZEROORMORE(Annotation) + - "..." + VariableDeclaratorId, - FormalParameter) - attr.property : Single - - -rule FieldAttr : ONEOF("public", "protected", "private", "static", "final", "transient", "volatile") - attr.property : Single -rule FieldModifier : ONEOF(Annotation, FieldAttr) - attr.property : Single - -################################################################ -# Constructor # -################################################################ -rule ConstructorDeclaration : ZEROORMORE(ConstructorModifier) + ConstructorDeclarator + - ZEROORONE(Throws) + ConstructorBody - attr.action : AddFunctionBodyTo(%2, %4) - -rule ConstructorAttr : ONEOF("public", "protected", "private") - attr.property : Single -rule ConstructorModifier : ONEOF(Annotation, ConstructorAttr) - attr.property : Single -rule ConstructorDeclarator : ZEROORONE(TypeParameters) + SimpleTypeName + '(' + - ZEROORONE(FormalParameterList) + ')' - attr.action : BuildConstructor(%2) -rule SimpleTypeName : Identifier -rule ConstructorBody : '{' + ZEROORONE(ExplicitConstructorInvocation) + - ZEROORONE(BlockStatements) + '}' - attr.action : BuildBlock(%3) - -# Although ExpressionName and Primary are not excluding each other, given the rest -# of the concatenate elements this is a 'Single' rule. -rule ExplicitConstructorInvocation : ONEOF( - ZEROORONE(TypeArguments) + "this" + '(' + ZEROORONE(ArgumentList) + ')' + ';', - ZEROORONE(TypeArguments) + "super" + '(' + ZEROORONE(ArgumentList) + ')' + ';', - ExpressionName + '.' + ZEROORONE(TypeArguments) + "super" + '(' + ZEROORONE(ArgumentList) + ')' + ';', - Primary + '.' + ZEROORONE(TypeArguments) + "super" + '(' + ZEROORONE(ArgumentList) + ')' + ';') - attr.property : Single - -###################################################################### -# Enum # -###################################################################### -rule EnumDeclaration: ZEROORMORE(ClassModifier) + "enum" + Identifier + - ZEROORONE(Superinterfaces) + EnumBody - attr.action : BuildClass(%3) - attr.action : SetClassIsJavaEnum() - attr.action : AddModifier(%1) - attr.action : AddSuperInterface(%4) - attr.action : AddClassBody(%5) - -# This returns a PassNode with some ConstantNode and BlockNode. The -# different between ConstantNode and LiteralNode can be found in their definition. -rule EnumBody: '{' + ZEROORONE(EnumConstantList) + ZEROORONE(',') + - ZEROORONE(EnumBodyDeclarations) + '}' - attr.action: BuildBlock(%2) - attr.action: AddToBlock(%4) - -# This returns a PassNode -rule EnumConstantList: EnumConstant + ZEROORMORE(',' + EnumConstant) - -# AddInitTo() will handle this complicated JavaEnum style initial value of identifier -rule EnumConstant: ZEROORMORE(EnumConstantModifier) + Identifier + - ZEROORONE('(' + ZEROORONE(ArgumentList) + ')') + ZEROORONE(ClassBody) - attr.action : AddInitTo(%2, %3) - attr.action : AddInitTo(%2, %4) - -rule EnumConstantModifier: Annotation - -# This returns a PassNode with a set of BlockNode -rule EnumBodyDeclarations: ';' + ZEROORMORE(ClassBodyDeclaration) - -###################################################################### -# Block # -###################################################################### - -# 1st and 3rd children don't exclude each other. However, if both of them -# match, they will match the same sequence of tokens, being a -# LocalVariableDeclarationStatement. So don't need traverse 3rd any more. -rule BlockStatement : ONEOF(LocalVariableDeclarationStatement, - ClassDeclaration, - Statement) - attr.property : Single - -rule BlockStatements : BlockStatement + ZEROORMORE(BlockStatement) - attr.property.%2 : ZomFast -rule Block : '{' + ZEROORONE(BlockStatements) + '}' - attr.action: BuildBlock(%2) - - -###################################################################### -# Interface # -###################################################################### -rule InterfaceDeclaration : ONEOF(NormalInterfaceDeclaration, AnnotationTypeDeclaration) - attr.property : Single, Top - -rule NormalInterfaceDeclaration : ZEROORMORE(InterfaceModifier) + "interface" + Identifier + - ZEROORONE(TypeParameters) + ZEROORONE(ExtendsInterfaces) + InterfaceBody - attr.action : BuildInterface(%3) - attr.action : AddInterfaceBody(%6) - -rule InterfaceAttr : ONEOF("public", "protected", "private", "abstract", "static", "strictfp") - attr.property : Single -rule InterfaceModifier : ONEOF(Annotation, InterfaceAttr) - attr.property : Single -rule ExtendsInterfaces : "extends" + InterfaceTypeList -rule InterfaceBody : '{' + ZEROORMORE(InterfaceMemberDeclaration) + '}' - attr.action : BuildBlock(%2) - attr.property.%2 : ZomFast - -rule InterfaceMemberDeclaration : ONEOF(ConstantDeclaration, - InterfaceMethodDeclaration, - ClassDeclaration, - InterfaceDeclaration, - ';') - attr.property : Single - -# constant decl is also called field decl. In interface, field must have a variable initializer -# However, the rules below don't tell this limitation. -rule ConstantDeclaration : ZEROORMORE(ConstantModifier) + UnannType + VariableDeclaratorList + ';' -rule ConstantAttr : ONEOF("public", "static", "final") - attr.property : Single -rule ConstantModifier : ONEOF(Annotation, ConstantAttr) - attr.property : Single - -rule InterfaceMethodDeclaration : ZEROORMORE(InterfaceMethodModifier) + MethodHeader + MethodBody - attr.action: AddModifierTo(%2, %1) - attr.action: AddFunctionBodyTo(%2, %3) -rule InterfaceMethodAttr : ONEOF("public", "abstract", "default", "static", "strictfp") - attr.property : Single -rule InterfaceMethodModifier : ONEOF(Annotation, InterfaceMethodAttr) - attr.property : Single - -###################################################################### -# Annotation Type # -###################################################################### -rule AnnotationTypeDeclaration : ZEROORMORE(InterfaceModifier) + '@' + "interface" + - Identifier + AnnotationTypeBody - attr.action : BuildAnnotationType(%4) - attr.action : AddModifier(%1) - attr.action : AddAnnotationTypeBody(%5) - -rule AnnotationTypeBody : '{' + ZEROORMORE(AnnotationTypeMemberDeclaration) + '}' - attr.action : BuildBlock(%2) -rule AnnotationTypeMemberDeclaration : ONEOF(AnnotationTypeElementDeclaration, - ConstantDeclaration, - ClassDeclaration, - InterfaceDeclaration, - ';') - attr.property : Single -rule AnnotationTypeElementDeclaration : ZEROORMORE(AnnotationTypeElementModifier) + UnannType + - Identifier + '(' + ')' + ZEROORONE(Dims) + - ZEROORONE(DefaultValue) + ';' -rule AnnotationTypeElementAttr : ONEOF("public", "abstract") - attr.property : Single -rule AnnotationTypeElementModifier : ONEOF(Annotation, AnnotationTypeElementAttr) - attr.property : Single -rule DefaultValue : "default" + ElementValue - -###################################################################### -# Annotation # -###################################################################### -rule Annotation : ONEOF(NormalAnnotation, - MarkerAnnotation, - SingleElementAnnotation) - -rule NormalAnnotation : '@' + TypeName + '(' + ZEROORONE(ElementValuePairList) + ')' - attr.action : BuildAnnotation(%2) - -rule MarkerAnnotation : '@' + TypeName - attr.action : BuildAnnotation(%2) - -rule SingleElementAnnotation : '@' + TypeName + '(' + ElementValue + ')' - attr.action : BuildAnnotation(%2) - -rule ElementValuePairList : ElementValuePair + ZEROORMORE(',' + ElementValuePair) -rule ElementValuePair : Identifier + '=' + ElementValue -rule ElementValue : ONEOF(ConditionalExpression, - ElementValueArrayInitializer, - Annotation) -rule ElementValueArrayInitializer : '{' + ZEROORONE(ElementValueList) + ZEROORONE(',') + '}' -rule ElementValueList : ElementValue + ZEROORMORE(',' + ElementValue) - -###################################################################### -# Package # -###################################################################### -rule PackageModifier: Annotation -rule PackageDeclaration: ZEROORMORE(PackageModifier) + "package" + Identifier + ZEROORMORE('.' + Identifier) + ';' - attr.action : BuildField(%3, %4) - attr.action : BuildPackageName() - attr.property : Top - attr.property.%1,%4 : ZomFast - -rule ImportDeclaration: ONEOF(SingleTypeImportDeclaration, - TypeImportOnDemandDeclaration, - SingleStaticImportDeclaration, - StaticImportOnDemandDeclaration) - attr.property : Top - -rule SingleTypeImportDeclaration: "import" + TypeName + ';' - attr.action : BuildSingleTypeImport(%2) -rule TypeImportOnDemandDeclaration: "import" + PackageOrTypeName + '.' + '*' + ';' - attr.action : BuildAllTypeImport(%2) -rule SingleStaticImportDeclaration: "import" + "static" + TypeName + '.' + Identifier + ';' - attr.action : BuildField(%3, %4) - attr.action : BuildSingleStaticImport() -rule StaticImportOnDemandDeclaration: "import" + "static" + TypeName + '.' + '*' + ';' - attr.action : BuildAllStaticImport(%3) diff --git a/src/MapleFE/java/expr.spec b/src/MapleFE/java/expr.spec deleted file mode 100644 index 6ac6ad72eb76dcb9f28715a0ff5125c6ab09b6a2..0000000000000000000000000000000000000000 --- a/src/MapleFE/java/expr.spec +++ /dev/null @@ -1,293 +0,0 @@ -# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. -# -# OpenArkFE is licensed under the Mulan PSL v2. -# You can use this software according to the terms and conditions of the Mulan PSL v2. -# You may obtain a copy of Mulan PSL v2 at: -# -# http://license.coscl.org.cn/MulanPSL2 -# -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -# FIT FOR A PARTICULAR PURPOSE. -# See the Mulan PSL v2 for more details. -# - - -rule PackageName : ONEOF(Identifier, PackageName + '.' + Identifier) - attr.action.%2 : BuildField(%1, %3) - -rule TypeName : ONEOF(Identifier, PackageOrTypeName + '.' + Identifier) - attr.action.%2 : BuildField(%1, %3) - -rule PackageOrTypeName : ONEOF(Identifier, PackageOrTypeName + '.' + Identifier) - attr.action.%2 : BuildField(%1, %3) - -rule ExpressionName : ONEOF(Identifier, AmbiguousName + '.' + Identifier) - attr.action.%2 : BuildField(%1, %3) - -rule MethodName : Identifier - -rule AmbiguousName : ONEOF(Identifier, AmbiguousName + '.' + Identifier) - attr.action.%2 : BuildField(%1, %3) - -rule Class : "class" -rule ClassLiteral : ONEOF(TypeName + ZEROORMORE('[' + ']') + '.' + Class, - NumericType + ZEROORMORE('[' + ']') + '.' + Class, - "boolean" + ZEROORMORE('[' + ']') + '.' + Class, - "void" + '.' + Class) - attr.property : Single - -rule PrimaryNoNewArray_single : ONEOF( - Literal, - ClassLiteral, - "this", - TypeName + '.' + "this", - '(' + Expression + ')', - ClassInstanceCreationExpression) - attr.action.%4 : BuildField(%1, %3) - attr.action.%5 : BuildParenthesis(%2) - attr.property : Single - -rule PrimaryNoNewArray : ONEOF( - PrimaryNoNewArray_single, - FieldAccess, - ArrayAccess, - MethodInvocation, - MethodReference) - -# There was a child rule. -# ExpressionName + '.' + UnqualifiedClassInstanceCreationExpression, -# But Primary contains ExpressionName. It's a duplication, so I removed it. -rule ClassInstanceCreationExpression : ONEOF( - UnqualifiedClassInstanceCreationExpression, - Primary + '.' + UnqualifiedClassInstanceCreationExpression) - -rule UnqualifiedClassInstanceCreationExpression : - "new" + ZEROORONE(TypeArguments) + ClassOrInterfaceTypeToInstantiate + - '(' + ZEROORONE(ArgumentList) + ')' + ZEROORONE(ClassBody) - attr.action : BuildNewOperation(%3, %5, %7) - -rule ClassOrInterfaceTypeToInstantiate : - ZEROORMORE(Annotation) + Identifier + ZEROORMORE('.' + ZEROORMORE(Annotation) + Identifier) + - ZEROORONE(TypeArgumentsOrDiamond) - attr.action : BuildUserType(%2) - attr.action : AddTypeArgument(%4) - -rule TypeArgumentsOrDiamond : ONEOF( - TypeArguments, - "<>") - -rule ArgumentList : Expression + ZEROORMORE(',' + Expression) - -rule ArrayInitializer : '{' + ZEROORONE(VariableInitializerList) + ZEROORONE(',') + '}' -rule ArrayCreationExpression : ONEOF( - "new" + PrimitiveType + DimExprs + ZEROORONE(Dims), - "new" + ClassOrInterfaceType + DimExprs + ZEROORONE(Dims), - "new" + PrimitiveType + Dims + ArrayInitializer, - "new" + ClassOrInterfaceType + Dims + ArrayInitializer) - -rule DimExprs : DimExpr + ZEROORMORE(DimExpr) - -rule DimExpr : ZEROORMORE(Annotation) + '[' + Expression + ']' - -rule ArrayAccess : ONEOF( - ExpressionName + '[' + Expression + ']', - PrimaryNoNewArray + '[' + Expression + ']') - -rule FieldAccess : ONEOF( - Primary + '.' + Identifier, - "super" + '.' + Identifier, - TypeName + '.' + "super" + '.' + Identifier) - attr.action.%1 : BuildField(%1, %3) - -# It's possible MethodInvocation includes a MethodReference, like -# A::B(a,b) -rule MethodInvocation : ONEOF( - MethodName + '(' + ZEROORONE(ArgumentList) + ')', - TypeName + '.' + ZEROORONE(TypeArguments) + Identifier + '(' + ZEROORONE(ArgumentList) + ')', - ExpressionName + '.' + ZEROORONE(TypeArguments) + Identifier + '(' + ZEROORONE(ArgumentList) + ')', - Primary + '.' + ZEROORONE(TypeArguments) + Identifier + '(' + ZEROORONE(ArgumentList) + ')', - "super" + '.' + ZEROORONE(TypeArguments) + Identifier + '(' + ZEROORONE(ArgumentList) + ')', - TypeName + '.' + "super" + '.' + ZEROORONE(TypeArguments) + Identifier + '(' + ZEROORONE(ArgumentList) + ')') - attr.action.%1 : BuildCall(%1) - attr.action.%1 : AddArguments(%3) - attr.action.%2 : BuildField(%1, %4) - attr.action.%2 : BuildCall() - attr.action.%2 : AddArguments(%6) - -rule ArgumentList : Expression + ZEROORMORE(',' + Expression) - attr.action.%1: BuildExprList(%1, %2) - -rule MethodReference : ONEOF( - ExpressionName + "::" + ZEROORONE(TypeArguments) + Identifier, - Primary + "::" + ZEROORONE(TypeArguments) + Identifier, - ReferenceType + "::" + ZEROORONE(TypeArguments) + Identifier, - "super" + "::" + ZEROORONE(TypeArguments) + Identifier, - TypeName + '.' + "super" + "::" + ZEROORONE(TypeArguments) + Identifier, - ClassType + "::" + ZEROORONE(TypeArguments) "new", - ArrayType + "::" + "new") - -rule PostfixExpression : ONEOF( - Primary, - ExpressionName, - PostIncrementExpression, - PostDecrementExpression) - -rule PostIncrementExpression : PostfixExpression + "++" - attr.action : BuildPostfixOperation(%2, %1) -rule PostDecrementExpression : PostfixExpression + "--" - attr.action : BuildPostfixOperation(%2, %1) - -rule UnaryExpression : ONEOF( - PreIncrementExpression, - PreDecrementExpression, - '+' + UnaryExpression, - '-' + UnaryExpression, - UnaryExpressionNotPlusMinus) - attr.action.%3,%4 : BuildUnaryOperation(%1, %2) - -rule PreIncrementExpression : "++" + UnaryExpression - attr.action : BuildUnaryOperation(%1, %2) - -rule PreDecrementExpression : "--" + UnaryExpression - attr.action : BuildUnaryOperation(%1, %2) - -rule UnaryExpressionNotPlusMinus : ONEOF( - PostfixExpression, - '~' + UnaryExpression, - '!' + UnaryExpression, - CastExpression) - -rule CastExpression : ONEOF( - '(' + PrimitiveType + ')' + UnaryExpression, - '(' + ReferenceType + ZEROORMORE(AdditionalBound) + ')' + UnaryExpressionNotPlusMinus, - '(' + ReferenceType + ZEROORMORE(AdditionalBound) + ')' + LambdaExpression) - attr.action.%1 : BuildCast(%2, %4) - attr.action.%2,%3 : BuildCast(%2, %5) - -rule MultiplicativeExpression : ONEOF( - UnaryExpression, - MultiplicativeExpression + '*' + UnaryExpression, - MultiplicativeExpression + '/' + UnaryExpression, - MultiplicativeExpression + '%' + UnaryExpression) - -rule AdditiveExpression : ONEOF( - MultiplicativeExpression, - AdditiveExpression + '+' + MultiplicativeExpression, - AdditiveExpression + '-' + MultiplicativeExpression) - attr.action.%2,%3 : BuildBinaryOperation(%1, %2, %3) - -rule ShiftExpression : ONEOF( - AdditiveExpression, - ShiftExpression + "<<" + AdditiveExpression, - ShiftExpression + ">>" + AdditiveExpression, - ShiftExpression + ">>>" + AdditiveExpression) - attr.action.%2,%3,%4 : BuildBinaryOperation(%1, %2, %3) - -rule RelationalExpression : ONEOF( - ShiftExpression, - RelationalExpression + '<' + ShiftExpression, - RelationalExpression + '>' + ShiftExpression, - RelationalExpression + "<=" + ShiftExpression, - RelationalExpression + ">=" + ShiftExpression, - RelationalExpression + "instanceof" + ReferenceType) - attr.action.%2,%3,%4,%5 : BuildBinaryOperation(%1, %2, %3) - -rule EqualityExpression : ONEOF( - RelationalExpression, - EqualityExpression + "==" + RelationalExpression, - EqualityExpression + "!=" + RelationalExpression) - attr.action.%2,%3 : BuildBinaryOperation(%1, %2, %3) - -rule AndExpression : ONEOF( - EqualityExpression, - AndExpression + '&' + EqualityExpression) - attr.action.%2 : BuildBinaryOperation(%1, %2, %3) - -rule ExclusiveOrExpression : ONEOF( - AndExpression, - ExclusiveOrExpression + '^' + AndExpression) - attr.action.%2 : BuildBinaryOperation(%1, %2, %3) - -rule InclusiveOrExpression : ONEOF( - ExclusiveOrExpression, - InclusiveOrExpression + '|' + ExclusiveOrExpression) - attr.action.%2 : BuildBinaryOperation(%1, %2, %3) - -rule ConditionalAndExpression : ONEOF( - InclusiveOrExpression, - ConditionalAndExpression + "&&" + InclusiveOrExpression) - attr.action.%2 : BuildBinaryOperation(%1, %2, %3) - -rule ConditionalOrExpression : ONEOF( - ConditionalAndExpression, - ConditionalOrExpression + "||" + ConditionalAndExpression) - attr.action.%2 : BuildBinaryOperation(%1, %2, %3) - -rule ConditionalExpression : ONEOF( - ConditionalOrExpression, - ConditionalOrExpression + '?' + Expression + ':' + ConditionalExpression, - ConditionalOrExpression + '?' + Expression + ':' + LambdaExpression) - -rule AssignmentExpression : ONEOF( - ConditionalExpression, - Assignment) - -rule Assignment : LeftHandSide + AssignmentOperator + Expression - attr.action : BuildAssignment(%1, %2, %3) - -rule LeftHandSide : ONEOF( - ExpressionName, - FieldAccess, - ArrayAccess) - -rule AssignmentOperator : ONEOF('=', "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|=") - -rule LambdaExpression : LambdaParameters + "->" + LambdaBody - attr.action : BuildLambda(%1, %3) - -rule LambdaParameters : ONEOF( - '(' + ZEROORONE(LambdaParameterList) + ')', - Identifier) - -rule LambdaParameterList : ONEOF( - LambdaParameter + ZEROORMORE(',' + LambdaParameter), - Identifier + ZEROORMORE(',' + Identifier)) - -rule LambdaParameter : ONEOF( - ZEROORMORE(VariableModifier) + LambdaParameterType + VariableDeclaratorId, - VariableArityParameter) - -rule LambdaParameterType : ONEOF(UnannType, "var") - -rule VariableArityParameter : ZEROORMORE(VariableModifier) + UnannType + ZEROORMORE(Annotation) + "..." + Identifier - -rule LambdaBody : ONEOF(Expression, Block) - -rule ConstantExpression : Expression - -rule Primary : ONEOF( - PrimaryNoNewArray, - ArrayCreationExpression) - -rule Expression : ONEOF( - ExpressionName, - Primary, - UnaryExpression, - BinaryExpression, - ConditionalExpression, - LambdaExpression, - AssignmentExpression) - -rule BinaryExpression : ONEOF ( - MultiplicativeExpression, - AdditiveExpression, - ShiftExpression, - RelationalExpression, - EqualityExpression, - AndExpression, - ExclusiveOrExpression, - InclusiveOrExpression, - ConditionalAndExpression, - ConditionalOrExpression) - diff --git a/src/MapleFE/java/identifier.spec b/src/MapleFE/java/identifier.spec index a482d95b78ac4e237121b90f6677d208c2333b5c..6cfe3baf6e1b7b01004cdd387139257599dd0990 100644 --- a/src/MapleFE/java/identifier.spec +++ b/src/MapleFE/java/identifier.spec @@ -14,8 +14,6 @@ # An identifier is an unlimited-length sequence of Java letters and Java digits, the # first of which must be a Java letter # -# TODO: So far we dont support unicode which are not major goal right now. - rule JavaChar : ONEOF(CHAR, '_' , '$') rule CharOrDigit : ONEOF(JavaChar, DIGIT) rule Identifier : JavaChar + ZEROORMORE(CharOrDigit) diff --git a/src/MapleFE/java/include/lang_builtin.def b/src/MapleFE/java/include/lang_builtin.def new file mode 100644 index 0000000000000000000000000000000000000000..8c127c72a426bb6113253cdf59a103a11785e8fb --- /dev/null +++ b/src/MapleFE/java/include/lang_builtin.def @@ -0,0 +1,14 @@ +// Copyright (C) [2022] Futurewei Technologies, Inc. All rights reverved. +// +// OpenArkFE is licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// + diff --git a/src/MapleFE/java/include/lang_keywords.def b/src/MapleFE/java/include/lang_keywords.def new file mode 100644 index 0000000000000000000000000000000000000000..cc571c8c9d42f70245f634ca76206bf0196ab253 --- /dev/null +++ b/src/MapleFE/java/include/lang_keywords.def @@ -0,0 +1,71 @@ +// Copyright (C) [2021] Futurewei Technologies Inc. All rights reverved. +// +// OpenArkFE is licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// + +LANGKEYWORD(boolean) +LANGKEYWORD(byte) +LANGKEYWORD(char) +LANGKEYWORD(class) +LANGKEYWORD(double) +LANGKEYWORD(enum) +LANGKEYWORD(float) +LANGKEYWORD(int) +LANGKEYWORD(interface) +LANGKEYWORD(long) +LANGKEYWORD(package) +LANGKEYWORD(short) +LANGKEYWORD(void) + +LANGKEYWORD(var) + +LANGKEYWORD(break) +LANGKEYWORD(case) +LANGKEYWORD(catch) +LANGKEYWORD(continue) +LANGKEYWORD(default) +LANGKEYWORD(do) +LANGKEYWORD(else) +LANGKEYWORD(finally) +LANGKEYWORD(for) +LANGKEYWORD(goto) +LANGKEYWORD(if) +LANGKEYWORD(return) +LANGKEYWORD(switch) +LANGKEYWORD(try) +LANGKEYWORD(while) + +LANGKEYWORD(abstract) +LANGKEYWORD(const) +LANGKEYWORD(volatile) + +LANGKEYWORD(assert) +LANGKEYWORD(new) + +LANGKEYWORD(instanceof) +LANGKEYWORD(extends) +LANGKEYWORD(implements) +LANGKEYWORD(import) +LANGKEYWORD(super) +LANGKEYWORD(synchronized) +// LANGKEYWORD(this) +LANGKEYWORD(throw) +LANGKEYWORD(throws) +LANGKEYWORD(transient) + +LANGKEYWORD(final) +LANGKEYWORD(native) +LANGKEYWORD(private) +LANGKEYWORD(protected) +LANGKEYWORD(public) +LANGKEYWORD(static) +LANGKEYWORD(strictfp) diff --git a/src/MapleFE/java/include/lang_spec.h b/src/MapleFE/java/include/lang_spec.h index b461f71a033dd0257f66e5f00f5f6b73a52bda48..8f02be06ff2494d211b5641e9846c506592c6185 100644 --- a/src/MapleFE/java/include/lang_spec.h +++ b/src/MapleFE/java/include/lang_spec.h @@ -21,6 +21,7 @@ #include "stringutil.h" #include "token.h" +#include "lexer.h" namespace maplefe { @@ -34,5 +35,11 @@ public: }; extern LitData ProcessLiteral(LitId type, const char *str); + +// +class JavaLexer : public Lexer { +}; + } + #endif diff --git a/src/MapleFE/java/include/vfy_java.h b/src/MapleFE/java/include/vfy_java.h index ba1fbaeb9e0a4101d442a184fcca674f91a444ff..89ab484fe50ea29420ba4fd72a3f00513f7fc057 100644 --- a/src/MapleFE/java/include/vfy_java.h +++ b/src/MapleFE/java/include/vfy_java.h @@ -26,7 +26,7 @@ namespace maplefe { class VerifierJava : public Verifier { private: public: - VerifierJava(){} + VerifierJava(ModuleNode *m) : Verifier(m) {} ~VerifierJava(){} void VerifyGlobalScope(); diff --git a/src/MapleFE/java/literal.spec b/src/MapleFE/java/literal.spec index 87f8a49652cbc3bea76b89b52b505c008f6e0981..68eae0bdf7f3a0718916e1d537c690b58d569fc9 100644 --- a/src/MapleFE/java/literal.spec +++ b/src/MapleFE/java/literal.spec @@ -124,7 +124,15 @@ rule BooleanLiteral : ONEOF ("true", "false") # I decided to simplify the unicode escape a little bit. I don't want to # handle all odd cases. rule UnicodeEscape: '\' + 'u' + HEXDIGIT + HEXDIGIT + HEXDIGIT + HEXDIGIT -rule RawInputCharacter : ONEOF(ASCII, ESCAPE) + +# [NOTE] Becareful of ' over here. It's duplicated in ESCAPE as '\' + '''. There is a reason. +# When the lexer read a string "doesn't", which is wrong since Java request ' be escaped but +# many code does NOT escape, the string in memory is "doesn't" too. The system Reading function +# which is in C doesn't escape '. So I duplicate here to catch this case. +# +# Please see test case java2mpl/literal-string-2.java for example. +# +rule RawInputCharacter : ONEOF(ASCII, ''', ESCAPE) rule SingleCharacter: ONEOF(UnicodeEscape, RawInputCharacter) rule OctalEscape : ONEOF('\' + '0', '\' + '1') @@ -135,7 +143,10 @@ rule CharacterLiteral : ''' + ONEOF(SingleCharacter, EscapeSequence) + ''' ######################################################################### ## String ## ######################################################################### -rule StringLiteral : '"' + ZEROORMORE(RawInputCharacter) + '"' +# The UnicodeEscape is limited from \u0000 to \u00ff. +rule StringUnicodeEscape: '\' + 'u' + '0' + '0' + HEXDIGIT + HEXDIGIT +rule StringCharater: ONEOF(StringUnicodeEscape, RawInputCharacter) +rule StringLiteral : '"' + ZEROORMORE(StringCharater) + '"' ######################################################################### ## Null ## diff --git a/src/MapleFE/java/operator.spec b/src/MapleFE/java/operator.spec index b5c472571074f25f96b1b5203fde4dc7c842734f..5f561f909f2bb78e7ce8a15fd7178bfb7c845c47 100644 --- a/src/MapleFE/java/operator.spec +++ b/src/MapleFE/java/operator.spec @@ -20,6 +20,11 @@ # 2. The rule part, defining the language restrictions of each operator. ########################################################################## +# NOTE +# Some languages could have one synatx belonging to both separator and operators. +# eg., ':' in Java 8, it's both a separator colon and operator select. +# We need avoid such duplication in .spec files. + STRUCT Operator : ONEOF( # Arithmetic ("+", Add), @@ -64,6 +69,4 @@ STRUCT Operator : ONEOF( (">>>=", ZextAssign), # ("->", Arrow), - (":", Select), - ("?", Cond), ("<>", Diamond)) diff --git a/src/MapleFE/java/separator.spec b/src/MapleFE/java/separator.spec index 1363b2d7b0e21c862e3384129d652f50b5c48b7d..db9df6f5cad9161df16d0ad6ecbff01866f9dc9d 100644 --- a/src/MapleFE/java/separator.spec +++ b/src/MapleFE/java/separator.spec @@ -31,6 +31,7 @@ STRUCT Separator : ((" ", Whitespace), (".", Dot), ("...", Dotdotdot), (":", Colon), + ("?", Select), ("::", Of), ("@", At), ("#", Pound)) diff --git a/src/MapleFE/java/src/Makefile b/src/MapleFE/java/src/Makefile index 5c8aae7fcff64d30beae6ba5ead94393877700e2..7715078eb86192d2422d3f29aec0b0c0a0a5c5aa 100644 --- a/src/MapleFE/java/src/Makefile +++ b/src/MapleFE/java/src/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# Copyright (C) [2020-2021] Futurewei Technologies, Inc. All rights reverved. # # OpenArkFE is licensed under the Mulan PSL v2. # You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -13,27 +13,37 @@ # include ../../Makefile.in +BUILDBIN=$(BUILDDIR)/bin BUILD=$(BUILDDIR)/java -$(shell $(MKDIR_P) $(BUILD)) +BUILDGEN=$(BUILDDIR)/gen +BUILDASTGEN=$(BUILDDIR)/ast_gen/shared +$(shell $(MKDIR_P) $(BUILD) $(BUILDGEN)) SRC=$(wildcard *.cpp) OBJ :=$(patsubst %.cpp,%.o,$(SRC)) DEP :=$(patsubst %.cpp,%.d,$(SRC)) -OBJS :=$(foreach obj,$(OBJ), $(BUILD)/$(obj)) -DEPS :=$(foreach dep,$(DEP), $(BUILD)/$(dep)) +SRCG := $(wildcard $(BUILDGEN)/gen*.cpp) +OBJG := $(patsubst %.cpp, %.o, $(SRCG)) +DEPG := $(patsubst %.cpp, %.d, $(SRCG)) + +OBJS :=$(foreach obj,$(OBJ), $(BUILD)/$(obj)) $(OBJG) +DEPS :=$(foreach dep,$(DEP), $(BUILD)/$(dep)) $(DEPG) INCLUDES := -I $(MAPLEFE_ROOT)/shared/include \ -I $(MAPLEFE_ROOT)/java/include \ -I $(MAPLEFE_ROOT)/autogen/include \ - -I . $(MAPLEALL_INC) + -I ${BUILDDIR}/ast_gen/shared \ + -I $(BUILDGEN) $(MAPLEALL_INC) + +INCLUDEGEN := -I $(BUILDGEN) -I $(MAPLEFE_ROOT)/shared/include -TARGET=java2mpl +TARGET=java2ast -SHAREDLIB = $(BUILDDIR)/shared/shared.a +SHAREDLIB = $(BUILDDIR)/shared/shared.a $(BUILDASTGEN)/genast.a -.PHONY: all $(TARGET) -all: $(TARGET) +.PHONY: all +all: $(BUILD)/$(TARGET) -include $(DEPS) .PHONY: clean @@ -43,7 +53,7 @@ vpath %.d $(BUILD) # Pattern Rules $(BUILD)/%.o : %.cpp - $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ $(BUILD)/%.d : %.cpp @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $< > $@ @@ -51,14 +61,20 @@ $(BUILD)/%.d : %.cpp @sed -e 's|.*:|$(BUILD)/$*.o:|' < $(BUILD)/$*.d.tmp > $(BUILD)/$*.d @rm -f $(BUILD)/$*.d.tmp +$(BUILDGEN)/%.o : $(BUILDGEN)/%.cpp $(BUILDGEN)/%.d + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDEGEN) -w -c $< -o $@ + +$(BUILDGEN)/%.d : $(BUILDGEN)/%.cpp + @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDEGEN) $< > $@ + @mv -f $(BUILDGEN)/$*.d $(BUILDGEN)/$*.d.tmp + @sed -e 's|.*:|$(BUILDGEN)/$*.o:|' < $(BUILDGEN)/$*.d.tmp > $(BUILDGEN)/$*.d + @rm -f $(BUILDGEN)/$*.d.tmp + # TARGET depends on OBJS and shared OBJS from shared directory # as well as mapleall libraries -$(TARGET): $(OBJS) $(SHAREDLIB) - $(LD) -o $(BUILD)/$(TARGET) $(OBJS) $(SHAREDLIB) $(MAPLELIBS) - -#.cpp.o: -# $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $*.cpp -o $(BUILD)/$*.o -# $(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $*.cpp > $(BUILD)/$*.d +$(BUILD)/$(TARGET): $(OBJS) $(SHAREDLIB) + @mkdir -p $(BUILDBIN) + $(LD) -o $(BUILDBIN)/$(TARGET) $(OBJS) $(SHAREDLIB) $(MAPLELIBS) clean: rm -rf $(BUILD) diff --git a/src/MapleFE/java/src/ast2mpl_java.cpp b/src/MapleFE/java/src/ast2mpl_java.cpp deleted file mode 100644 index ca77eaaa32c95629b3a6b89eb088e175ee9c78f3..0000000000000000000000000000000000000000 --- a/src/MapleFE/java/src/ast2mpl_java.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. -* -* OpenArkFE is licensed under the Mulan PSL v2. -* You can use this software according to the terms and conditions of the Mulan PSL v2. -* You may obtain a copy of Mulan PSL v2 at: -* -* http://license.coscl.org.cn/MulanPSL2 -* -* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -* FIT FOR A PARTICULAR PURPOSE. -* See the Mulan PSL v2 for more details. -*/ - -#include "ast2mpl_java.h" - -namespace maplefe { - -maple::MIRType *A2MJava::MapPrimType(PrimTypeNode *ptnode) { - maple::PrimType prim; - switch (ptnode->GetPrimType()) { - case TY_Boolean: prim = maple::PTY_u1; break; - case TY_Byte: prim = maple::PTY_u8; break; - case TY_Short: prim = maple::PTY_i16; break; - case TY_Int: prim = maple::PTY_i32; break; - case TY_Long: prim = maple::PTY_i64; break; - case TY_Char: prim = maple::PTY_u16; break; - case TY_Float: prim = maple::PTY_f32; break; - case TY_Double: prim = maple::PTY_f64; break; - case TY_Void: prim = maple::PTY_void; break; - case TY_Null: prim = maple::PTY_void; break; - default: MASSERT("Unsupported PrimType"); break; - } - - maple::TyIdx tid(prim); - return maple::GlobalTables::GetTypeTable().GetTypeFromTyIdx(tid); -} - -const char *A2MJava::Type2Label(const maple::MIRType *type) { - maple::PrimType pty = type->GetPrimType(); - switch (pty) { - case maple::PTY_u1: return "Z"; - case maple::PTY_u8: return "B"; - case maple::PTY_i16: return "S"; - case maple::PTY_u16: return "C"; - case maple::PTY_i32: return "I"; - case maple::PTY_i64: return "J"; - case maple::PTY_f32: return "F"; - case maple::PTY_f64: return "D"; - case maple::PTY_void: return "V"; - default: return "L"; - } -} - -} diff --git a/src/MapleFE/java/src/lang_spec.cpp b/src/MapleFE/java/src/lang_spec.cpp index 522e67ad1630e3b14304cf89b34d97ac49bd3e77..7585961fd230765c5e5504e0f9598465fbd7ee2c 100644 --- a/src/MapleFE/java/src/lang_spec.cpp +++ b/src/MapleFE/java/src/lang_spec.cpp @@ -13,6 +13,7 @@ * See the Mulan PSL v2 for more details. */ #include "lang_spec.h" +#include "stringpool.h" namespace maplefe { @@ -149,7 +150,7 @@ LitData ProcessLiteral(LitId id, const char *str) { case LT_StringLiteral: { const char *s = s2v.StringToString(value_text); data.mType = LT_StringLiteral; - data.mData.mStr = s; + data.mData.mStrIdx = gStringPool.GetStrIdx(s); break; } case LT_NullLiteral: { // Just need set the id @@ -164,4 +165,14 @@ LitData ProcessLiteral(LitId id, const char *str) { return data; } +///////////////////////////////////////////////////////////////////////////////////// +// Implementation of Java Lexer +///////////////////////////////////////////////////////////////////////////////////// + +Lexer* CreateLexer() { + Lexer *lexer = new JavaLexer(); + return lexer; +} + + } diff --git a/src/MapleFE/java/src/main.cpp b/src/MapleFE/java/src/main.cpp index e5a0e5092add3d5b21454be0f8674d9b6b22637d..e90b50d01f5137deaea432f63fb09184bf69b3b2 100644 --- a/src/MapleFE/java/src/main.cpp +++ b/src/MapleFE/java/src/main.cpp @@ -17,8 +17,10 @@ #include "common_header_autogen.h" #include "ruletable_util.h" #include "gen_summary.h" +#include "gen_aststore.h" +#include "gen_astdump.h" +#include "gen_astgraph.h" #include "vfy_java.h" -#include "ast2mpl_java.h" static void help() { std::cout << "java2mpl sourcefile [options]:\n" << std::endl; @@ -35,6 +37,8 @@ static void help() { std::cout << " --trace-patch-was-succ : Trace Patching of WasSucc nodes" << std::endl; std::cout << " --trace-warning : Print Warning" << std::endl; std::cout << " --trace-a2m : Trace MPL Builder" << std::endl; + std::cout << " --dump-ast : Dump AST in text format" << std::endl; + std::cout << " --dump-dot : Dump AST in dot format" << std::endl; } int main (int argc, char *argv[]) { @@ -45,7 +49,9 @@ int main (int argc, char *argv[]) { maplefe::Parser *parser = new maplefe::Parser(argv[1]); - bool trace_a2m = false; + bool dump_ast = false; + bool dump_dot = false; + bool succ; // Parse the argument for (unsigned i = 2; i < argc; i++) { @@ -71,8 +77,10 @@ int main (int argc, char *argv[]) { parser->mTracePatchWasSucc = true; } else if (!strncmp(argv[i], "--trace-warning", 15) && (strlen(argv[i]) == 15)) { parser->mTraceWarning = true; - } else if (!strncmp(argv[i], "--trace-a2m", 11) && (strlen(argv[i]) == 11)) { - trace_a2m = true; + } else if (!strncmp(argv[i], "--dump-ast", 10) && (strlen(argv[i]) == 10)) { + dump_ast = true; + } else if (!strncmp(argv[i], "--dump-dot", 10) && (strlen(argv[i]) == 10)) { + dump_dot = true; } else { std::cerr << "unknown option " << argv[i] << std::endl; exit(-1); @@ -80,18 +88,40 @@ int main (int argc, char *argv[]) { } parser->InitRecursion(); - parser->Parse(); + succ = parser->Parse(); + if (!succ) { + delete parser; + return 1; + } + + // the module from parser + maplefe::ModuleNode *module = parser->GetModule(); - maplefe::VerifierJava vfy_java; + maplefe::VerifierJava vfy_java(module); vfy_java.Do(); - maplefe::A2MJava *a2m = new maplefe::A2MJava(maplefe::gModule.mFileName); - a2m->ProcessAST(trace_a2m); + if(dump_ast) { + maplefe::AstDump astdump(module); + astdump.Dump("ts2ast: Initial AST", &std::cout); + } - a2m->mMirModule->OutputAsciiMpl("", ".mpl"); + if(dump_dot) { + maplefe::AstGraph graph(module); + graph.DumpGraph("ts2ast: Initial AST", &std::cout); + } - delete parser; - delete a2m; + maplefe::AstStore saveAst(module); + saveAst.StoreInAstBuf(); + maplefe::AstBuffer &ast_buf = saveAst.GetAstBuf(); + + std::ofstream ofs; + std::string fname(module->GetFilename()); + fname += ".ast"; + ofs.open(fname, std::ofstream::out); + const char *addr = (const char *)(&(ast_buf[0])); + ofs.write(addr, ast_buf.size()); + ofs.close(); + delete parser; return 0; } diff --git a/src/MapleFE/java/src/vfy_java.cpp b/src/MapleFE/java/src/vfy_java.cpp index e77e3b6bff5177a52f307303d3f540fe21fb8b19..53efd9c35ca3c4fc47ac81a45d759d7b0ade4587 100644 --- a/src/MapleFE/java/src/vfy_java.cpp +++ b/src/MapleFE/java/src/vfy_java.cpp @@ -24,19 +24,15 @@ namespace maplefe { // Collect all types, decls of global scope all at once. void VerifierJava::VerifyGlobalScope() { - mCurrScope = gModule.mRootScope; - std::vector::iterator tree_it = gModule.mTrees.begin(); - for (; tree_it != gModule.mTrees.end(); tree_it++) { - ASTTree *asttree = *tree_it; - TreeNode *tree = asttree->mRootNode; + mCurrScope = mASTModule->mRootScope; + for (unsigned i = 0; i < mASTModule->GetTreesNum(); i++) { + TreeNode *tree = mASTModule->GetTree(i); mCurrScope->TryAddDecl(tree); mCurrScope->TryAddType(tree); - } + } - tree_it = gModule.mTrees.begin(); - for (; tree_it != gModule.mTrees.end(); tree_it++) { - ASTTree *asttree = *tree_it; - TreeNode *tree = asttree->mRootNode; + for (unsigned i = 0; i < mASTModule->GetTreesNum(); i++) { + TreeNode *tree = mASTModule->GetTree(i); VerifyTree(tree); } } diff --git a/src/MapleFE/java/stmt.spec b/src/MapleFE/java/stmt.spec index 4e4922f23196015f1a6aa75527cbdd8e44dc19fc..ea54785ffea55213637b31e913ea1544959965c9 100644 --- a/src/MapleFE/java/stmt.spec +++ b/src/MapleFE/java/stmt.spec @@ -12,6 +12,289 @@ # See the Mulan PSL v2 for more details. # +rule PackageName : ONEOF(Identifier, PackageName + '.' + Identifier) + attr.action.%2 : BuildField(%1, %3) + +rule TypeName : ONEOF(Identifier, PackageOrTypeName + '.' + Identifier) + attr.action.%2 : BuildField(%1, %3) + +rule PackageOrTypeName : ONEOF(Identifier, PackageOrTypeName + '.' + Identifier) + attr.action.%2 : BuildField(%1, %3) + +rule ExpressionName : ONEOF(Identifier, AmbiguousName + '.' + Identifier) + attr.action.%2 : BuildField(%1, %3) + +rule MethodName : Identifier + +rule AmbiguousName : ONEOF(Identifier, AmbiguousName + '.' + Identifier) + attr.action.%2 : BuildField(%1, %3) + +rule Class : "class" +rule ClassLiteral : ONEOF(TypeName + ZEROORMORE('[' + ']') + '.' + Class, + NumericType + ZEROORMORE('[' + ']') + '.' + Class, + "boolean" + ZEROORMORE('[' + ']') + '.' + Class, + "void" + '.' + Class) + attr.property : Single + +rule PrimaryNoNewArray_single : ONEOF( + Literal, + ClassLiteral, + "this", + TypeName + '.' + "this", + '(' + Expression + ')', + ClassInstanceCreationExpression) + attr.action.%4 : BuildField(%1, %3) + attr.action.%5 : BuildParenthesis(%2) + attr.property : Single + +rule PrimaryNoNewArray : ONEOF( + PrimaryNoNewArray_single, + FieldAccess, + ArrayAccess, + MethodInvocation, + MethodReference) + +# There was a child rule. +# ExpressionName + '.' + UnqualifiedClassInstanceCreationExpression, +# But Primary contains ExpressionName. It's a duplication, so I removed it. +rule ClassInstanceCreationExpression : ONEOF( + UnqualifiedClassInstanceCreationExpression, + Primary + '.' + UnqualifiedClassInstanceCreationExpression) + +rule UnqualifiedClassInstanceCreationExpression : + "new" + ZEROORONE(TypeArguments) + ClassOrInterfaceTypeToInstantiate + + '(' + ZEROORONE(ArgumentList) + ')' + ZEROORONE(ClassBody) + attr.action : BuildNewOperation(%3, %5, %7) + +rule ClassOrInterfaceTypeToInstantiate : + ZEROORMORE(Annotation) + Identifier + ZEROORMORE('.' + ZEROORMORE(Annotation) + Identifier) + + ZEROORONE(TypeArgumentsOrDiamond) + attr.action : BuildUserType(%2) + attr.action : AddTypeGenerics(%4) + +rule TypeArgumentsOrDiamond : ONEOF( + TypeArguments, + "<>") + +rule ArrayInitializer : '{' + ZEROORONE(VariableInitializerList) + ZEROORONE(',') + '}' +rule ArrayCreationExpression : ONEOF( + "new" + PrimitiveType + DimExprs + ZEROORONE(Dims), + "new" + ClassOrInterfaceType + DimExprs + ZEROORONE(Dims), + "new" + PrimitiveType + Dims + ArrayInitializer, + "new" + ClassOrInterfaceType + Dims + ArrayInitializer) + +rule DimExprs : DimExpr + ZEROORMORE(DimExpr) + +rule DimExpr : ZEROORMORE(Annotation) + '[' + Expression + ']' + +rule ArrayAccess : ONEOF( + ExpressionName + '[' + Expression + ']', + PrimaryNoNewArray + '[' + Expression + ']') + +rule FieldAccess : ONEOF( + Primary + '.' + Identifier, + "super" + '.' + Identifier, + TypeName + '.' + "super" + '.' + Identifier) + attr.action.%1 : BuildField(%1, %3) + +# It's possible MethodInvocation includes a MethodReference, like +# A::B(a,b) +rule MethodInvocation : ONEOF( + MethodName + '(' + ZEROORONE(ArgumentList) + ')', + TypeName + '.' + ZEROORONE(TypeArguments) + Identifier + '(' + ZEROORONE(ArgumentList) + ')', + ExpressionName + '.' + ZEROORONE(TypeArguments) + Identifier + '(' + ZEROORONE(ArgumentList) + ')', + Primary + '.' + ZEROORONE(TypeArguments) + Identifier + '(' + ZEROORONE(ArgumentList) + ')', + "super" + '.' + ZEROORONE(TypeArguments) + Identifier + '(' + ZEROORONE(ArgumentList) + ')', + TypeName + '.' + "super" + '.' + ZEROORONE(TypeArguments) + Identifier + '(' + ZEROORONE(ArgumentList) + ')') + attr.action.%1 : BuildCall(%1) + attr.action.%1 : AddArguments(%3) + attr.action.%2 : BuildField(%1, %4) + attr.action.%2 : BuildCall() + attr.action.%2 : AddArguments(%6) + attr.action.%3,%4,%5 : BuildField(%1, %4) + attr.action.%3,%4,%5 : BuildCall() + attr.action.%3,%4,%5 : AddArguments(%6) + +rule ArgumentList : Expression + ZEROORMORE(',' + Expression) + attr.action.%1: BuildExprList(%1, %2) + +rule MethodReference : ONEOF( + ExpressionName + "::" + ZEROORONE(TypeArguments) + Identifier, + Primary + "::" + ZEROORONE(TypeArguments) + Identifier, + ReferenceType + "::" + ZEROORONE(TypeArguments) + Identifier, + "super" + "::" + ZEROORONE(TypeArguments) + Identifier, + TypeName + '.' + "super" + "::" + ZEROORONE(TypeArguments) + Identifier, + ClassType + "::" + ZEROORONE(TypeArguments) "new", + ArrayType + "::" + "new") + +rule PostfixExpression : ONEOF( + Primary, + ExpressionName, + PostIncrementExpression, + PostDecrementExpression) + +rule PostIncrementExpression : PostfixExpression + "++" + attr.action : BuildPostfixOperation(%2, %1) +rule PostDecrementExpression : PostfixExpression + "--" + attr.action : BuildPostfixOperation(%2, %1) + +rule UnaryExpression : ONEOF( + PreIncrementExpression, + PreDecrementExpression, + '+' + UnaryExpression, + '-' + UnaryExpression, + UnaryExpressionNotPlusMinus) + attr.action.%3,%4 : BuildUnaryOperation(%1, %2) + +rule PreIncrementExpression : "++" + UnaryExpression + attr.action : BuildUnaryOperation(%1, %2) + +rule PreDecrementExpression : "--" + UnaryExpression + attr.action : BuildUnaryOperation(%1, %2) + +rule UnaryExpressionNotPlusMinus : ONEOF( + PostfixExpression, + '~' + UnaryExpression, + '!' + UnaryExpression, + CastExpression) + +rule CastExpression : ONEOF( + '(' + PrimitiveType + ')' + UnaryExpression, + '(' + ReferenceType + ZEROORMORE(AdditionalBound) + ')' + UnaryExpressionNotPlusMinus, + '(' + ReferenceType + ZEROORMORE(AdditionalBound) + ')' + LambdaExpression) + attr.action.%1 : BuildCast(%2, %4) + attr.action.%2,%3 : BuildCast(%2, %5) + +rule MultiplicativeExpression : ONEOF( + UnaryExpression, + MultiplicativeExpression + '*' + UnaryExpression, + MultiplicativeExpression + '/' + UnaryExpression, + MultiplicativeExpression + '%' + UnaryExpression) + attr.action.%2,%3,%4 : BuildBinaryOperation(%1, %2, %3) + +rule AdditiveExpression : ONEOF( + MultiplicativeExpression, + AdditiveExpression + '+' + MultiplicativeExpression, + AdditiveExpression + '-' + MultiplicativeExpression) + attr.action.%2,%3 : BuildBinaryOperation(%1, %2, %3) + +rule ShiftExpression : ONEOF( + AdditiveExpression, + ShiftExpression + "<<" + AdditiveExpression, + ShiftExpression + ">>" + AdditiveExpression, + ShiftExpression + ">>>" + AdditiveExpression) + attr.action.%2,%3,%4 : BuildBinaryOperation(%1, %2, %3) + +rule RelationalExpression : ONEOF( + ShiftExpression, + RelationalExpression + '<' + ShiftExpression, + RelationalExpression + '>' + ShiftExpression, + RelationalExpression + "<=" + ShiftExpression, + RelationalExpression + ">=" + ShiftExpression, + RelationalExpression + "instanceof" + ReferenceType) + attr.action.%2,%3,%4,%5 : BuildBinaryOperation(%1, %2, %3) + attr.action.%6 : BuildInstanceOf(%1, %3) + +rule EqualityExpression : ONEOF( + RelationalExpression, + EqualityExpression + "==" + RelationalExpression, + EqualityExpression + "!=" + RelationalExpression) + attr.action.%2,%3 : BuildBinaryOperation(%1, %2, %3) + +rule AndExpression : ONEOF( + EqualityExpression, + AndExpression + '&' + EqualityExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +rule ExclusiveOrExpression : ONEOF( + AndExpression, + ExclusiveOrExpression + '^' + AndExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +rule InclusiveOrExpression : ONEOF( + ExclusiveOrExpression, + InclusiveOrExpression + '|' + ExclusiveOrExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +rule ConditionalAndExpression : ONEOF( + InclusiveOrExpression, + ConditionalAndExpression + "&&" + InclusiveOrExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +rule ConditionalOrExpression : ONEOF( + ConditionalAndExpression, + ConditionalOrExpression + "||" + ConditionalAndExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +rule ConditionalExpression : ONEOF( + ConditionalOrExpression, + ConditionalOrExpression + '?' + Expression + ':' + ConditionalExpression, + ConditionalOrExpression + '?' + Expression + ':' + LambdaExpression) + +rule AssignmentExpression : ONEOF( + ConditionalExpression, + Assignment) + +rule Assignment : LeftHandSide + AssignmentOperator + Expression + attr.action : BuildAssignment(%1, %2, %3) + +rule LeftHandSide : ONEOF( + ExpressionName, + FieldAccess, + ArrayAccess) + +rule AssignmentOperator : ONEOF('=', "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|=") + +rule LambdaExpression : LambdaParameters + "->" + LambdaBody + attr.action : BuildLambda(%1, %3) + +rule LambdaParameters : ONEOF( + '(' + ZEROORONE(LambdaParameterList) + ')', + Identifier) + +rule LambdaParameterList : ONEOF( + LambdaParameter + ZEROORMORE(',' + LambdaParameter), + Identifier + ZEROORMORE(',' + Identifier)) + +rule LambdaParameter : ONEOF( + ZEROORMORE(VariableModifier) + LambdaParameterType + VariableDeclaratorId, + VariableArityParameter) + attr.action.%1: BuildDecl(%2, %3) + +rule LambdaParameterType : ONEOF(UnannType, "var") + +rule VariableArityParameter : ZEROORMORE(VariableModifier) + UnannType + ZEROORMORE(Annotation) + "..." + Identifier + +rule LambdaBody : ONEOF(Expression, Block) + +rule ConstantExpression : Expression + +rule Primary : ONEOF( + PrimaryNoNewArray, + ArrayCreationExpression) + +rule Expression : ONEOF( + ExpressionName, + Primary, + UnaryExpression, + BinaryExpression, + ConditionalExpression, + LambdaExpression, + AssignmentExpression) + +rule BinaryExpression : ONEOF ( + MultiplicativeExpression, + AdditiveExpression, + ShiftExpression, + RelationalExpression, + EqualityExpression, + AndExpression, + ExclusiveOrExpression, + InclusiveOrExpression, + ConditionalAndExpression, + ConditionalOrExpression) + + rule LocalVariableDeclarationStatement : LocalVariableDeclaration + ';' rule LocalVariableDeclaration : ZEROORMORE(VariableModifier) + UnannType + VariableDeclaratorList @@ -86,6 +369,8 @@ rule IfThenStatement : "if" + '(' + Expression + ')' + Statement attr.action: BuildCondBranch(%3) attr.action: AddCondBranchTrueStatement(%5) +## " This line is to make my vim show right color for the below contents. + rule IfThenElseStatement : "if" + '(' + Expression + ')' + StatementNoShortIf + "else" + Statement attr.action: BuildCondBranch(%3) attr.action: AddCondBranchTrueStatement(%5) @@ -125,7 +410,6 @@ rule SwitchStatement : "switch" + '(' + Expression + ')' + SwitchBlock attr.action : BuildSwitch(%3, %5) rule SwitchBlock : '{' + ZEROORMORE(ZEROORMORE(SwitchBlockStatementGroup) + ZEROORMORE(SwitchLabel)) + '}' - attr.action : BuildAllCases(%2) rule SwitchBlockStatementGroup : SwitchLabels + BlockStatements attr.action : BuildOneCase(%1, %2) @@ -187,6 +471,7 @@ rule ReturnStatement : "return" + ZEROORONE(Expression) + ';' rule ThrowStatement : "throw" + Expression + ';' rule SynchronizedStatement : "synchronized" + '(' + Expression + ')' + Block + attr.action : AddSyncToBlock(%3, %5) rule TryStatement : ONEOF( "try" + Block + Catches, @@ -217,3 +502,339 @@ rule VariableAccess : ONEOF( ExpressionName, FieldAccess) +################################################################################### +# This file defines the Java Block/Class/Interface statement. +################################################################################### + +rule ClassDeclaration : ONEOF(NormalClassDeclaration, EnumDeclaration) + attr.property : Single, Top +rule NormalClassDeclaration : ZEROORMORE(ClassModifier) + "class" + Identifier + + ZEROORONE(TypeParameters) + ZEROORONE(Superclass) + + ZEROORONE(Superinterfaces) + ClassBody + attr.action : BuildClass(%3) + attr.action : AddModifier(%1) + attr.action : AddClassBody(%7) + attr.action : AddSuperClass(%5) + attr.action : AddSuperInterface(%6) + attr.property.%1,%4,%5,%6 : ZomFast + +rule ClassAttr : ONEOF("public", "protected", "private", "abstract", "static", "final", "strictfp") + attr.property : Single +rule ClassModifier : ONEOF(Annotation, ClassAttr) + attr.property : Single + +# 1. Generic class +# 2. TypeParameter will be defined in type.spec +rule TypeParameters : '<' + TypeParameterList + '>' +rule TypeParameterList : TypeParameter + ZEROORMORE(',' + TypeParameter) +rule TypeParameter : ZEROORMORE(TypeParameterModifier) + Identifier + ZEROORONE(TypeBound) +rule TypeParameterModifier : Annotation +rule TypeBound : ONEOF("extends" + TypeVariable, + "extends" + ClassOrInterfaceType + ZEROORMORE(AdditionalBound)) +rule AdditionalBound : '&' + InterfaceType + +# ClassType and InterfaceType are defined in type.spec +rule Superclass : "extends" + ClassType +rule Superinterfaces : "implements" + InterfaceTypeList +rule InterfaceTypeList : InterfaceType + ZEROORMORE(',' + InterfaceType) + +# class body +rule ClassBody : "{" + ZEROORMORE(ClassBodyDeclaration) + "}" + attr.action: BuildBlock(%2) + attr.property.%2 : ZomFast + +rule ClassBodyDeclaration : ONEOF(ClassMemberDeclaration, + InstanceInitializer, + StaticInitializer, + ConstructorDeclaration) + attr.property : Single + +rule InstanceInitializer : Block + attr.action: BuildInstInit(%1) +rule StaticInitializer : "static" + Block + attr.action: BuildInstInit(%2) + attr.action: AddModifierTo(%2, %1) + +rule ClassMemberDeclaration : ONEOF(FieldDeclaration, + MethodDeclaration, + ClassDeclaration, + InterfaceDeclaration, + ';') + attr.property : Single + +rule FieldDeclaration : ZEROORMORE(FieldModifier) + UnannType + VariableDeclaratorList + ';' + attr.action: BuildDecl(%2, %3) + attr.action: AddModifier(%1) + +rule MethodDeclaration : ZEROORMORE(MethodModifier) + MethodHeader + MethodBody + attr.action: AddModifierTo(%2, %1) + attr.action: AddFunctionBodyTo(%2, %3) + +rule MethodBody : ONEOF(Block, ';') + attr.property : Single +rule MethodHeader : ONEOF(Result + MethodDeclarator + ZEROORONE(Throws), + TypeParameters + ZEROORMORE(Annotation) + Result + MethodDeclarator + + ZEROORONE(Throws)) + attr.action.%1: AddType(%2, %1) + attr.action.%1: AddThrowsTo(%2, %3) + attr.action.%2: AddType(%4, %3) + attr.action.%2: AddThrowsTo(%4, %5) + attr.property : Single + +rule Result : ONEOF(UnannType, "void") + attr.property : Single +rule MethodDeclarator : Identifier + '(' + ZEROORONE(FormalParameterList) + ')' + ZEROORONE(Dims) + attr.action: BuildFunction(%1) + attr.action: AddParams(%3) + attr.action: AddDims(%5) + +rule Throws : "throws" + ExceptionTypeList + attr.action: PassChild(%2) + +rule ExceptionTypeList : ExceptionType + ZEROORMORE(',' + ExceptionType) +rule ExceptionType : ONEOF(ClassType, TypeVariable) + +rule MethodAttr : ONEOF("public", "protected", "private", "abstract", "static", + "final", "synchronized", "native", "strictfp") + attr.property : Single + +rule MethodModifier : ONEOF(Annotation, MethodAttr) + attr.property : Single + +rule FormalParameterListNoReceiver : ONEOF(FormalParameters + ',' + LastFormalParameter, + LastFormalParameter) + +# ReceiverParameter and FormalParameterListNoReceiver could match at the same +# but with different num of tokens. Here is an example +# foo(T T.this) +# The NoReceiver could match "T T", while Receiver match "T T.this". +# Although later it figures out NoReceiver is wrong, but at this rule, both rule work. +# If we put NoReceiver as the 1st child and set property 'Single', we will miss +# Receiver which is the correct one. +# +# So I move Receiver to be the 1st child, since NoReceiver is not correct matching +# if Receiver works. +rule FormalParameterList : ONEOF(ReceiverParameter, FormalParameterListNoReceiver) + attr.property : Single + +# We don't do any action. Just let it pass a PassNode +rule FormalParameters : ONEOF(FormalParameter + ZEROORMORE(',' + FormalParameter), + ReceiverParameter + ZEROORMORE(',' + FormalParameter)) + attr.property : Single + +rule FormalParameter : ZEROORMORE(VariableModifier) + UnannType + VariableDeclaratorId + attr.action: BuildDecl(%2, %3) + attr.action: AddModifier(%1) +rule ReceiverParameter : ZEROORMORE(Annotation) + UnannType + ZEROORONE(Identifier + '.') + "this" + attr.action: BuildDecl(%2, %3) + +rule LastFormalParameter : ONEOF(ZEROORMORE(VariableModifier) + UnannType + ZEROORMORE(Annotation) + + "..." + VariableDeclaratorId, + FormalParameter) + attr.action.%1: BuildDecl(%2, %5) + attr.action.%1: AddModifier(%1) + attr.property : Single + + +rule FieldAttr : ONEOF("public", "protected", "private", "static", "final", "transient", "volatile") + attr.property : Single +rule FieldModifier : ONEOF(Annotation, FieldAttr) + attr.property : Single + +################################################################ +# Constructor # +################################################################ +rule ConstructorDeclaration : ZEROORMORE(ConstructorModifier) + ConstructorDeclarator + + ZEROORONE(Throws) + ConstructorBody + attr.action : AddFunctionBodyTo(%2, %4) + +rule ConstructorAttr : ONEOF("public", "protected", "private") + attr.property : Single +rule ConstructorModifier : ONEOF(Annotation, ConstructorAttr) + attr.property : Single +rule ConstructorDeclarator : ZEROORONE(TypeParameters) + SimpleTypeName + '(' + + ZEROORONE(FormalParameterList) + ')' + attr.action : BuildConstructor(%2) + attr.action: AddParams(%4) +rule SimpleTypeName : Identifier +rule ConstructorBody : '{' + ZEROORONE(ExplicitConstructorInvocation) + + ZEROORONE(BlockStatements) + '}' + attr.action : BuildBlock(%3) + +# Although ExpressionName and Primary are not excluding each other, given the rest +# of the concatenate elements this is a 'Single' rule. +rule ExplicitConstructorInvocation : ONEOF( + ZEROORONE(TypeArguments) + "this" + '(' + ZEROORONE(ArgumentList) + ')' + ';', + ZEROORONE(TypeArguments) + "super" + '(' + ZEROORONE(ArgumentList) + ')' + ';', + ExpressionName + '.' + ZEROORONE(TypeArguments) + "super" + '(' + ZEROORONE(ArgumentList) + ')' + ';', + Primary + '.' + ZEROORONE(TypeArguments) + "super" + '(' + ZEROORONE(ArgumentList) + ')' + ';') + attr.property : Single + +###################################################################### +# Enum # +###################################################################### +rule EnumDeclaration: ZEROORMORE(ClassModifier) + "enum" + Identifier + + ZEROORONE(Superinterfaces) + EnumBody + attr.action : BuildClass(%3) + attr.action : SetClassIsJavaEnum() + attr.action : AddModifier(%1) + attr.action : AddSuperInterface(%4) + attr.action : AddClassBody(%5) + +# This returns a PassNode with some ConstantNode and BlockNode. The +# different between ConstantNode and LiteralNode can be found in their definition. +rule EnumBody: '{' + ZEROORONE(EnumConstantList) + ZEROORONE(',') + + ZEROORONE(EnumBodyDeclarations) + '}' + attr.action: BuildBlock(%2) + attr.action: AddToBlock(%4) + +# This returns a PassNode +rule EnumConstantList: EnumConstant + ZEROORMORE(',' + EnumConstant) + +# AddInitTo() will handle this complicated JavaEnum style initial value of identifier +rule EnumConstant: ZEROORMORE(EnumConstantModifier) + Identifier + + ZEROORONE('(' + ZEROORONE(ArgumentList) + ')') + ZEROORONE(ClassBody) + attr.action : AddInitTo(%2, %3) + attr.action : AddInitTo(%2, %4) + +rule EnumConstantModifier: Annotation + +# This returns a PassNode with a set of BlockNode +rule EnumBodyDeclarations: ';' + ZEROORMORE(ClassBodyDeclaration) + +###################################################################### +# Block # +###################################################################### + +# 1st and 3rd children don't exclude each other. However, if both of them +# match, they will match the same sequence of tokens, being a +# LocalVariableDeclarationStatement. So don't need traverse 3rd any more. +rule BlockStatement : ONEOF(LocalVariableDeclarationStatement, + ClassDeclaration, + Statement) + attr.property : Single + +rule BlockStatements : BlockStatement + ZEROORMORE(BlockStatement) + attr.property.%2 : ZomFast +rule Block : '{' + ZEROORONE(BlockStatements) + '}' + attr.action: BuildBlock(%2) + + +###################################################################### +# Interface # +###################################################################### +rule InterfaceDeclaration : ONEOF(NormalInterfaceDeclaration, AnnotationTypeDeclaration) + attr.property : Single, Top + +rule NormalInterfaceDeclaration : ZEROORMORE(InterfaceModifier) + "interface" + Identifier + + ZEROORONE(TypeParameters) + ZEROORONE(ExtendsInterfaces) + InterfaceBody + attr.action : BuildInterface(%3) + attr.action : AddInterfaceBody(%6) + +rule InterfaceAttr : ONEOF("public", "protected", "private", "abstract", "static", "strictfp") + attr.property : Single +rule InterfaceModifier : ONEOF(Annotation, InterfaceAttr) + attr.property : Single +rule ExtendsInterfaces : "extends" + InterfaceTypeList +rule InterfaceBody : '{' + ZEROORMORE(InterfaceMemberDeclaration) + '}' + attr.action : BuildBlock(%2) + attr.property.%2 : ZomFast + +rule InterfaceMemberDeclaration : ONEOF(ConstantDeclaration, + InterfaceMethodDeclaration, + ClassDeclaration, + InterfaceDeclaration, + ';') + attr.property : Single + +# constant decl is also called field decl. In interface, field must have a variable initializer +# However, the rules below don't tell this limitation. +rule ConstantDeclaration : ZEROORMORE(ConstantModifier) + UnannType + VariableDeclaratorList + ';' +rule ConstantAttr : ONEOF("public", "static", "final") + attr.property : Single +rule ConstantModifier : ONEOF(Annotation, ConstantAttr) + attr.property : Single + +rule InterfaceMethodDeclaration : ZEROORMORE(InterfaceMethodModifier) + MethodHeader + MethodBody + attr.action: AddModifierTo(%2, %1) + attr.action: AddFunctionBodyTo(%2, %3) +rule InterfaceMethodAttr : ONEOF("public", "abstract", "default", "static", "strictfp") + attr.property : Single +rule InterfaceMethodModifier : ONEOF(Annotation, InterfaceMethodAttr) + attr.property : Single + +###################################################################### +# Annotation Type # +###################################################################### +rule AnnotationTypeDeclaration : ZEROORMORE(InterfaceModifier) + '@' + "interface" + + Identifier + AnnotationTypeBody + attr.action : BuildAnnotationType(%4) + attr.action : AddModifier(%1) + attr.action : AddAnnotationTypeBody(%5) + +rule AnnotationTypeBody : '{' + ZEROORMORE(AnnotationTypeMemberDeclaration) + '}' + attr.action : BuildBlock(%2) +rule AnnotationTypeMemberDeclaration : ONEOF(AnnotationTypeElementDeclaration, + ConstantDeclaration, + ClassDeclaration, + InterfaceDeclaration, + ';') + attr.property : Single +rule AnnotationTypeElementDeclaration : ZEROORMORE(AnnotationTypeElementModifier) + UnannType + + Identifier + '(' + ')' + ZEROORONE(Dims) + + ZEROORONE(DefaultValue) + ';' +rule AnnotationTypeElementAttr : ONEOF("public", "abstract") + attr.property : Single +rule AnnotationTypeElementModifier : ONEOF(Annotation, AnnotationTypeElementAttr) + attr.property : Single +rule DefaultValue : "default" + ElementValue + +###################################################################### +# Annotation # +###################################################################### +rule Annotation : ONEOF(NormalAnnotation, + MarkerAnnotation, + SingleElementAnnotation) + +rule NormalAnnotation : '@' + TypeName + '(' + ZEROORONE(ElementValuePairList) + ')' + attr.action : BuildAnnotation(%2) + +rule MarkerAnnotation : '@' + TypeName + attr.action : BuildAnnotation(%2) + +rule SingleElementAnnotation : '@' + TypeName + '(' + ElementValue + ')' + attr.action : BuildAnnotation(%2) + +rule ElementValuePairList : ElementValuePair + ZEROORMORE(',' + ElementValuePair) +rule ElementValuePair : Identifier + '=' + ElementValue +rule ElementValue : ONEOF(ConditionalExpression, + ElementValueArrayInitializer, + Annotation) +rule ElementValueArrayInitializer : '{' + ZEROORONE(ElementValueList) + ZEROORONE(',') + '}' +rule ElementValueList : ElementValue + ZEROORMORE(',' + ElementValue) + +###################################################################### +# Package # +###################################################################### +rule PackageModifier: Annotation +rule PackageDeclaration: ZEROORMORE(PackageModifier) + "package" + Identifier + ZEROORMORE('.' + Identifier) + ';' + attr.action : BuildField(%3, %4) + attr.action : BuildPackageName() + attr.property : Top + attr.property.%1,%4 : ZomFast + +rule ImportDeclaration: ONEOF(SingleTypeImportDeclaration, + TypeImportOnDemandDeclaration, + SingleStaticImportDeclaration, + StaticImportOnDemandDeclaration) + attr.property : Top + +rule SingleTypeImportDeclaration: "import" + TypeName + ';' + attr.action : BuildSingleTypeImport(%2) +rule TypeImportOnDemandDeclaration: "import" + PackageOrTypeName + '.' + '*' + ';' + attr.action : BuildAllTypeImport(%2) +rule SingleStaticImportDeclaration: "import" + "static" + TypeName + '.' + Identifier + ';' + attr.action : BuildField(%3, %5) + attr.action : BuildSingleStaticImport() +rule StaticImportOnDemandDeclaration: "import" + "static" + TypeName + '.' + '*' + ';' + attr.action : BuildAllStaticImport(%3) diff --git a/src/MapleFE/java/type.spec b/src/MapleFE/java/type.spec index 6a8990b563038b3e2f1256dd137ed226386f8351..d0339d802c7f076b7b25e5b1861000747331ef07 100644 --- a/src/MapleFE/java/type.spec +++ b/src/MapleFE/java/type.spec @@ -118,6 +118,7 @@ rule ReferenceType : ONEOF(ClassOrInterfaceType, TypeVariable, ArrayType) # Final one ########################### rule TYPE: ONEOF(PrimitiveType, ReferenceType, NullType) +rule Type : TYPE ##################################################################################### # Abnormal types # diff --git a/src/MapleFE/java/type_conv.spec b/src/MapleFE/java/type_conv.spec deleted file mode 100644 index aa140d750f2be14c30d1a82688fceb9cf866dc44..0000000000000000000000000000000000000000 --- a/src/MapleFE/java/type_conv.spec +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. -# -# OpenArkFE is licensed under the Mulan PSL v2. -# You can use this software according to the terms and conditions of the Mulan PSL v2. -# You may obtain a copy of Mulan PSL v2 at: -# -# http://license.coscl.org.cn/MulanPSL2 -# -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -# FIT FOR A PARTICULAR PURPOSE. -# See the Mulan PSL v2 for more details. -# -####################################################################### -# There are over 10 kinds of type conversion in Java. This file # -# defines the rules of type conversion in different categories. # -# # -# There are many details putting many flavors in the semantics. # -# They can be implemented in java/src/*.cpp. Such as when convert # -# 'float' to 'Float', it diverges when the value is 'NaN'. # -# Situations like this will be handled in specified functions. # -####################################################################### - - -####################################################################### -# Identity Conversion # -####################################################################### - - -####################################################################### -# Widening Primitive Conversion # -####################################################################### - - -####################################################################### -# Narrowing Primitive Conversion # -####################################################################### - - -####################################################################### -# Widening Reference Conversion # -####################################################################### - - -####################################################################### -# Narrowing Reference Conversion # -####################################################################### - - -####################################################################### -# Boxing Conversion # -####################################################################### - - -####################################################################### -# Unboxing Conversion # -####################################################################### - - -####################################################################### -# Unchecked Conversion # -####################################################################### - - -####################################################################### -# Capture Conversion # -####################################################################### - - -####################################################################### -# String Conversion # -####################################################################### - - -####################################################################### -# Forbidden Conversion # -####################################################################### - - -####################################################################### -# Value Set Conversion # -####################################################################### - - -####################################################################### -# Boxing/Unboxing conversion is conversion between primitive types # -# and their corresponding Java reference types. # -# This could also happen in other similar lanaguages. # -# # -# 1. Since reference types are not part of Autogen, they are not # -# handled in the supported_types.spec. # -# 2. Reference types here will be only recognized through keyword, # -# The generated files will handle the conversion. # -# # -# TODO: There is one thing I will figure out later, i.e., see if we # -# need generate the 'new' operation in the Maple IR # -####################################################################### - -# The syntax of Boxing is a duplex -# PrimType: Use the types supported in autogen/supported_types.spec -# RefType: Use the keyword of reference types -# - -STRUCT Boxing : ONEOF((Boolean, "Boolean"), - (Byte, "Byte"), - (Short, "Short"), - (Char, "Character"), - (Int, "Integer"), - (Long, "Long"), - (Float, "Float"), - (Double, "Double")) - -STRUCT UnBoxing : ONEOF(("Boolean", Boolean), - ("Byte", Byte), - ("Short", Short), - ("Char", Char), - ("Int", Int), - ("Long", Long), - ("Float", Float), - ("Double", Double)) - diff --git a/src/MapleFE/ladetect/Makefile b/src/MapleFE/ladetect/Makefile index ac28904e9a9334189058b9c9d33c477270ca9fc1..3badd03259474113eedfb80b0f9aed5609b63823 100644 --- a/src/MapleFE/ladetect/Makefile +++ b/src/MapleFE/ladetect/Makefile @@ -1,46 +1,70 @@ +# Copyright (C) [2020-2021] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + include ../Makefile.in # create build first BUILD=$(BUILDDIR)/ladetect -$(shell $(MKDIR_P) $(BUILD)) +BUILDGEN=$(BUILDDIR)/gen +$(shell $(MKDIR_P) $(BUILD) $(BUILDGEN)) -# TEMPVAR=$(shell rm -rf $(LANG)) -# TEMPVAR=$(shell mkdir -p $(LANG)) -# TEMPVAR=$(shell cp ../$(LANG)/include/gen_*.h $(LANG)/) -# TEMPVAR=$(shell cp ../$(LANG)/src/gen_*.cpp $(LANG)/) -# TEMPVAR=$(shell mkdir -p $(BUILD)) -# TEMPVAR=$(shell mkdir -p $(BUILD)/$(LANG)) +SRCG := $(wildcard $(BUILDGEN)/gen_*.cpp) +OBJG := $(patsubst %.cpp, %.o, $(SRCG)) +DEPG := $(patsubst %.cpp, %.d, $(SRCG)) -LANGSRC=$(shell ls $(LANG)/*.cpp) -SRC := $(LANGSRC) $(wildcard *.cpp) +SRC := $(wildcard *.cpp) OBJ := $(patsubst %.cpp, %.o, $(SRC)) +OBJL := $(foreach obj, $(OBJ), $(BUILD)/$(obj)) DEP := $(patsubst %.cpp, %.d, $(SRC)) +DEPL := $(foreach dep, $(DEP), $(BUILD)/$(dep)) -OBJS := $(foreach obj, $(OBJ), $(BUILD)/$(obj)) -DEPS := $(foreach dep, $(DEP), $(BUILD)/$(dep)) +OBJS := $(OBJG) $(OBJL) +DEPS := $(DEPG) $(DEPL) INCLUDES := -I $(MAPLEFE_ROOT)/ladetect \ - -I $(MAPLEFE_ROOT)/ladetect/$(LANG) \ - -I $(MAPLEFE_ROOT)/shared/include + -I $(MAPLEFE_ROOT)/shared/include \ + -I $(MAPLEFE_ROOT)/$(SRCLANG)/include \ + -I $(BUILDGEN) + +INCLUDEGEN := -I $(BUILDGEN) -I $(MAPLEFE_ROOT)/shared/include + SHAREDLIB = $(BUILDDIR)/shared/shared.a TARGET = ladetect .PHONY: all -all: $(TARGET) +all: $(BUILD)/$(TARGET) -$(TARGET) : $(OBJS) $(SHAREDLIB) +$(BUILD)/$(TARGET) : $(OBJS) $(SHAREDLIB) $(LD) -o $(BUILD)/$(TARGET) $(OBJS) $(SHAREDLIB) + (cd $(BUILD); ./$(TARGET)) -include $(DEPS) .PHONY: clean -vpath %.cpp $(MAPLEFE_ROOT)/shared/src vpath %.o $(BUILD) vpath %.d $(BUILD) -CXXFLAGS := $(CXXFLAGS) -I ../$(LANG)/ +$(BUILDGEN)/%.o : $(BUILDGEN)/%.cpp $(BUILDGEN)/%.d + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDEGEN) -w -c $< -o $@ + +$(BUILDGEN)/%.d : $(BUILDGEN)/%.cpp + @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDEGEN) $< > $@ + @mv -f $(BUILDGEN)/$*.d $(BUILDGEN)/$*.d.tmp + @sed -e 's|.*:|$(BUILDGEN)/$*.o:|' < $(BUILDGEN)/$*.d.tmp > $(BUILDGEN)/$*.d + @rm -f $(BUILDGEN)/$*.d.tmp #Pattern Rules $(BUILD)/%.o : %.cpp $(BUILD)/%.d @@ -52,10 +76,5 @@ $(BUILD)/%.d : %.cpp @sed -e 's|.*:|$(BUILD)/$*.o:|' < $(BUILD)/$*.d.tmp > $(BUILD)/$*.d @rm -f $(BUILD)/$*.d.tmp - -#.cpp.o: -# $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $*.cpp -o $(BUILD)/$*.o -# $(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $*.cpp > $(BUILD)/$*.d - clean: - rm -rf $(BUILD) + rm -rf $(BUILD) $(OBJG) $(DEPG) diff --git a/src/MapleFE/ladetect/la_detect.cpp b/src/MapleFE/ladetect/la_detect.cpp index c1eba89defe7c1517e0548ebf3f891381a92bf1c..49757bab478a9dc1923ba914f572f824646fe25b 100644 --- a/src/MapleFE/ladetect/la_detect.cpp +++ b/src/MapleFE/ladetect/la_detect.cpp @@ -15,7 +15,7 @@ #include "common_header_autogen.h" #include "ruletable_util.h" -#include "gen_summary.h" +#include "rule_summary.h" #include "la_detect.h" #include "container.h" @@ -266,6 +266,7 @@ TResult LADetector::DetectRuleTable(RuleTable *rt, ContTreeNode *p) break; case ET_Zeroorone: case ET_Zeroormore: + case ET_ASI: res = DetectZeroorXXX(rt, node); break; case ET_Concatenate: @@ -351,7 +352,7 @@ TResult LADetector::DetectOneof(RuleTable *rule_table, ContTreeNode return result; } -// Zeroormore and Zeroorone has the same way to handle. +// Zeroormore and Zeroorone and ASI has the same way to handle. TResult LADetector::DetectZeroorXXX(RuleTable *rule_table, ContTreeNode *tree_node) { TResult result = TRS_NA; MASSERT((rule_table->mNum == 1) && "zeroormore node has more than one elements?"); @@ -488,7 +489,7 @@ void LADetector::Release() { } // To write the external decl of all LookAheadTable of each rule. -// +// // extern LookAheadTable TblStatementLookAheadTable; // extern LookAhead *TblStatementLookAhead; // ... @@ -597,14 +598,13 @@ void LADetector::WriteCppFile() { mCppFile->WriteOneLine("}", 1); } -// Write the recursion to java/gen_recursion.h and java/gen_recursion.cpp +// Write the recursion to gen/genmore_lookahead.h and gen/genmore_lookahead.cpp void LADetector::Write() { - std::string lang_path_header("../../java/include/"); - std::string lang_path_cpp("../../java/src/"); + std::string lang_path("../gen/"); - std::string file_name = lang_path_cpp + "gen_lookahead.cpp"; + std::string file_name = lang_path + "genmore_lookahead.cpp"; mCppFile = new Write2File(file_name); - file_name = lang_path_header + "gen_lookahead.h"; + file_name = lang_path + "gen_lookahead.h"; mHeaderFile = new Write2File(file_name); WriteHeaderFile(); diff --git a/src/MapleFE/ladetect/la_detect.h b/src/MapleFE/ladetect/la_detect.h index 18a1bcbd8a8fd2e4f4cfad834fed7a53fdf4f76e..46fe89d1a9677b41d3b3c5df319fd28946d7a4c5 100644 --- a/src/MapleFE/ladetect/la_detect.h +++ b/src/MapleFE/ladetect/la_detect.h @@ -62,7 +62,7 @@ public: void AddDependent(RuleTable *rt) {mDependents.PushBack(rt);} void Release() {mDependents.Release();} -}; +}; // Return result of most detect functions. enum TResult { diff --git a/src/MapleFE/recdetect/Makefile b/src/MapleFE/recdetect/Makefile index 6d436ee84cde07134c4d5222729a46aaa40b283e..025b900d399d63e2cab3d3bb9e35a7a9eedb3ca9 100644 --- a/src/MapleFE/recdetect/Makefile +++ b/src/MapleFE/recdetect/Makefile @@ -1,46 +1,67 @@ +# Copyright (C) [2020-2021] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + include ../Makefile.in # create build first BUILD=$(BUILDDIR)/recdetect -$(shell $(MKDIR_P) $(BUILD)) +BUILDGEN=$(BUILDDIR)/gen +$(shell $(MKDIR_P) $(BUILD) $(BUILDGEN)) -# TEMPVAR=$(shell rm -rf $(LANG)) -# TEMPVAR=$(shell mkdir -p $(LANG)) -# TEMPVAR=$(shell cp ../$(LANG)/include/gen_*.h $(LANG)/) -# TEMPVAR=$(shell cp ../$(LANG)/src/gen_*.cpp $(LANG)/) -# TEMPVAR=$(shell mkdir -p $(BUILD)) -# TEMPVAR=$(shell mkdir -p $(BUILD)/$(LANG)) +SRCG := $(wildcard $(BUILDGEN)/gen_*.cpp) +OBJG := $(patsubst %.cpp, %.o, $(SRCG)) +DEPG := $(patsubst %.cpp, %.d, $(SRCG)) -LANGSRC=$(shell ls $(LANG)/*.cpp) -SRC := $(LANGSRC) $(wildcard *.cpp) +SRC := $(wildcard *.cpp) OBJ := $(patsubst %.cpp, %.o, $(SRC)) +OBJL := $(foreach obj, $(OBJ), $(BUILD)/$(obj)) DEP := $(patsubst %.cpp, %.d, $(SRC)) +DEPL := $(foreach dep, $(DEP), $(BUILD)/$(dep)) + +OBJS := $(OBJG) $(OBJL) +DEPS := $(DEPG) $(DEPL) -OBJS := $(foreach obj, $(OBJ), $(BUILD)/$(obj)) -DEPS := $(foreach dep, $(DEP), $(BUILD)/$(dep)) +INCLUDES := -I $(MAPLEFE_ROOT)/recdetect \ + -I $(MAPLEFE_ROOT)/shared/include \ + -I $(BUILDGEN) -INCLUDES := -I $(MAPLEFE_ROOT)/recdetect/include \ - -I $(MAPLEFE_ROOT)/recdetect/$(LANG) \ - -I $(MAPLEFE_ROOT)/shared/include SHAREDLIB = $(BUILDDIR)/shared/shared.a TARGET = recdetect .PHONY: all -all: $(TARGET) +all: $(BUILD)/$(TARGET) -$(TARGET) : $(OBJS) $(SHAREDLIB) +$(BUILD)/$(TARGET) : $(OBJS) $(SHAREDLIB) $(LD) -o $(BUILD)/$(TARGET) $(OBJS) $(SHAREDLIB) + (cd $(BUILD); ./$(TARGET)) -include $(DEPS) .PHONY: clean -vpath %.cpp $(MAPLEFE_ROOT)/shared/src vpath %.o $(BUILD) vpath %.d $(BUILD) -CXXFLAGS := $(CXXFLAGS) -I ../$(LANG)/ +$(BUILDGEN)/%.o : $(BUILDGEN)/%.cpp $(BUILDGEN)/%.d + $(CXX) $(CXXFLAGS) -fpermissive -I $(BUILDGEN) -w -c $< -o $@ + +$(BUILDGEN)/%.d : $(BUILDGEN)/%.cpp + @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $< > $@ + @mv -f $(BUILDGEN)/$*.d $(BUILDGEN)/$*.d.tmp + @sed -e 's|.*:|$(BUILDGEN)/$*.o:|' < $(BUILDGEN)/$*.d.tmp > $(BUILDGEN)/$*.d + @rm -f $(BUILDGEN)/$*.d.tmp #Pattern Rules $(BUILD)/%.o : %.cpp $(BUILD)/%.d @@ -52,10 +73,5 @@ $(BUILD)/%.d : %.cpp @sed -e 's|.*:|$(BUILD)/$*.o:|' < $(BUILD)/$*.d.tmp > $(BUILD)/$*.d @rm -f $(BUILD)/$*.d.tmp - -#.cpp.o: -# $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $*.cpp -o $(BUILD)/$*.o -# $(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $*.cpp > $(BUILD)/$*.d - clean: - rm -rf $(BUILD) + rm -rf $(BUILD) $(OBJG) $(DEPG) diff --git a/src/MapleFE/recdetect/rec_detect.cpp b/src/MapleFE/recdetect/rec_detect.cpp index 8de48d23fff2b8abc31c11d9ef14c6b4df1dc342..8193ebd46c6978641d2dcd2c91896cdb838f4f33 100644 --- a/src/MapleFE/recdetect/rec_detect.cpp +++ b/src/MapleFE/recdetect/rec_detect.cpp @@ -16,7 +16,7 @@ #include "common_header_autogen.h" #include "ruletable_util.h" #include "rec_detect.h" -#include "gen_summary.h" +#include "rule_summary.h" namespace maplefe { @@ -27,7 +27,7 @@ namespace maplefe { // the recursions. We differentiate a recursion using the first node, ie, the topmost // node in the tree in this recursion. // 2) Each node (ie rule table) could have multiple recursions. -// 3) Recursions could include children recursions inside. +// 3) Recursions could include children recursions inside. // // [NOTE] The key point in recursion detector is to make sure for each loop, there // should be one and only one recursion counted, even if there are multiple @@ -346,6 +346,7 @@ TResult RecDetector::DetectRuleTable(RuleTable *rt, ContTreeNode *p) break; case ET_Zeroorone: case ET_Zeroormore: + case ET_ASI: res = DetectZeroorXXX(rt, node); break; case ET_Concatenate: @@ -422,7 +423,7 @@ TResult RecDetector::DetectOneof(RuleTable *rule_table, ContTreeNode return result; } -// Zeroormore and Zeroorone has the same way to handle. +// Zeroormore and Zeroorone and ASI has the same way to handle. TResult RecDetector::DetectZeroorXXX(RuleTable *rule_table, ContTreeNode *p) { TResult result = TRS_NA; MASSERT((rule_table->mNum == 1) && "zeroormore node has more than one elements?"); @@ -548,7 +549,7 @@ TResult RecDetector::DetectData(RuleTable *rule_table, ContTreeNode // At any point when we want to return, we need take the remaining elements // to ToDo list, if they are not in any of InProcess, Done and ToDo. - + TResult RecDetector::DetectConcatenate(RuleTable *rule_table, ContTreeNode *p) { // We use 'res' to record the status of the leading children. TRS_MaybeZero is good // for the beginning as it means it's empty right now. @@ -571,7 +572,7 @@ TResult RecDetector::DetectConcatenate(RuleTable *rule_table, ContTreeNodemNum == 1); TableData *data = rt->mData; @@ -1123,7 +1125,7 @@ void RecDetector::WriteRecursionGroups() { } group += "};"; mCppFile->WriteOneLine(group.c_str(), group.size()); - } + } // LeftRecursion **recursion_groups[N] = {RecursionGroup_1, RecursionGroup_2...}; // LeftRecursion ***gRecursionGroups = recursion_groups; @@ -1146,7 +1148,7 @@ void RecDetector::WriteRecursionGroups() { // We want to dump like below. // unsigned gRule2GroupNum = X; -// +// void RecDetector::WriteRule2Group() { std::string comment = "// Rule2Group mapping"; @@ -1357,12 +1359,11 @@ void RecDetector::WriteRule2Recursion() { // Write the recursion to java/gen_recursion.h and java/gen_recursion.cpp void RecDetector::Write() { - std::string lang_path_header("../../java/include/"); - std::string lang_path_cpp("../../java/src/"); + std::string lang_path("../gen/"); - std::string file_name = lang_path_cpp + "gen_recursion.cpp"; + std::string file_name = lang_path + "genmore_recursion.cpp"; mCppFile = new Write2File(file_name); - file_name = lang_path_header + "gen_recursion.h"; + file_name = lang_path + "gen_recursion.h"; mHeaderFile = new Write2File(file_name); WriteHeaderFile(); diff --git a/src/MapleFE/scripts/build_mapleall.sh b/src/MapleFE/scripts/build_mapleall.sh index a37d1634def7e2988d4bc89a29ee234cfb97e03e..c1c5d7375cdb59f496a9c361166f40eab0b2a456 100755 --- a/src/MapleFE/scripts/build_mapleall.sh +++ b/src/MapleFE/scripts/build_mapleall.sh @@ -13,13 +13,18 @@ # See the Mulan PSL v2 for more details. # +set -e + if [ ! -d $MAPLEALL_ROOT ]; then cd $MAPLE_ROOT - git clone https://gitee.com/openarkcompiler/OpenArkCompiler.git + git clone https://gitee.com/openarkcompiler/OpenArkCompiler.git -b dev_MapleFE fi cd $MAPLEALL_ROOT +git checkout dev_MapleFE git pull source build/envsetup.sh arm debug make setup -make +make clobber +make maple +make irbuild diff --git a/src/MapleFE/scripts/maplefe-autogen.py b/src/MapleFE/scripts/maplefe-autogen.py new file mode 100755 index 0000000000000000000000000000000000000000..f0ffce0cf1f8723de889853653e340c32e058df9 --- /dev/null +++ b/src/MapleFE/scripts/maplefe-autogen.py @@ -0,0 +1,1375 @@ +#!/usr/bin/env python3 +from os import path, environ +import subprocess +import hashlib +import yaml + +# +# Needs to install the following packages on Ubuntu 18.04 or 20.04 +# sudo apt install -y clang-tools-10 clang-format-10 libyaml-cpp-dev +# + +root_dir = path.dirname(path.dirname(path.realpath(__file__))) + '/' +builddir = environ.get('BUILDDIR') +output_dir = builddir + '/ast_gen/' if builddir != None else root_dir + "output/typescript/ast_gen/" +maplefe_dir = root_dir + 'shared/' +# initial_yaml = output_dir + 'maplefe/index.yaml' # For higher version of clang-doc +initial_yaml = output_dir + 'maplefe.yaml' # For version 10 +treenode_yaml = output_dir + 'maplefe/TreeNode.yaml' + +if not hasattr(yaml, "cyaml"): + print("Note: You may install package 'libyaml-cpp-dev' to speed up YAML parsing.") + +license_notice = [ +"""/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +// Generated by maplefe-autogen.py +""" +] # license_notice + +compile_commands = [ +f""" +[ + {{ "directory": "{maplefe_dir}src" + "command": "clang++ -std=c++17 -DDEBUG -fpermissive -I {maplefe_dir}include -w -c ast_builder.cpp", + "file": "ast_builder.cpp", + "output": "{output_dir}" + }} +] +""" +] # compile_commands + +bash_commands = [ +f""" +cd {maplefe_dir}src || exit 1 +rm -f {output_dir}yaml.log +clang-doc-10 ast_builder.cpp -p {output_dir} --format=yaml -output={output_dir} +""" +] # bash_commands + +def exec_command(cmd): + subprocess.call(cmd, shell=True) + +def create(filename, lines): + with open(filename, "w") as f: + for line in lines: + f.write(line + "\n") + +def append(filename, lines): + with open(filename, "a") as f: + for line in lines: + f.write(line + "\n") + +def finalize(filename, lines): + append(filename, lines) + exec_command('clang-format-10 -i --style="{ColumnLimit: 120}" ' + filename) + print("Generated " + filename) + +exec_command('bash -c "mkdir -p ' + output_dir + 'shared"') +create(output_dir + 'compile_commands.json', compile_commands) +create(output_dir + 'ast.sh', bash_commands) +exec_command('bash ' + output_dir + 'ast.sh') + +################################################################################ +# # +# Common code to handle YAML files # +# # +################################################################################ + +# Dump all content in a dictionary to ast_gen/yaml.log +def log(dictionary, indent, msg = ""): + global log_buf + if indent == 0: log_buf = [msg] + indstr = " . " * indent + for key, value in dictionary.items(): + if key == "USR": continue + prefix = indstr + key + ' : ' + if isinstance(value, dict): + log_buf.append(prefix + "{") + log(value, indent + 1) + log_buf.append(indstr+ " }") + elif isinstance(value, list): + log_buf.append(prefix + "[") + for elem in value: + if isinstance(elem, dict): + log(elem, indent + 1) + else: + log_buf.append(indstr + " " + str(elem)) + log_buf.append(indstr+ " ]") + else: + log_buf.append(prefix + str(value)) + log_buf.append(indstr + "---") + if indent == 0: + append(output_dir + 'yaml.log', log_buf) + +# Handle a YAML file with a callback +def handle_yaml(filename, callback, saved_yaml = {}): + if filename not in saved_yaml: + print(str(len(saved_yaml) + 1) + ": Processing " + filename + " ...") + with open(filename) as stream: + loader = yaml.cyaml.CLoader if hasattr(yaml, "cyaml") else yaml.Loader + yaml_data = yaml.load(stream, Loader=loader) + saved_yaml[filename] = yaml_data + log(yaml_data, 0, "YAML file: " + filename) + else: + yaml_data = saved_yaml[filename] + callback(yaml_data) + +# Get the pointed-to type, e.g. FunctionNode of "class maplefe::FunctionNode *" +def get_pointed(mtype): + loc = mtype.find("class maplefe::") + return mtype[loc + 15:-2] if loc >= 0 and mtype[-6:] == "Node *" else None + +# Get enum type, e.g. ImportProperty of "enum maplefe::ImportProperty" +def get_enum_type(mtype): + loc = mtype.find("maplefe::") + return mtype[loc + 9:] if loc >= 0 else None + +# Get the enum list for given enum name +def get_enum_list(dictionary, enum_name): + assert dictionary != None + enums = dictionary["ChildEnums"] + for e in enums: + for key, value in e.items(): + if key == "Name" and value == enum_name: + return e["Members"] + return [] + +# Generate functions for enum types, e.g. "const char *GetEnumOprId(OprId k);" for enum OprId +def gen_enum_func(dictionary): + global include_file, src_file, gen_args + hcode = [''] + xcode = [''] + for each in dictionary["ChildEnums"]: + name = each["Name"] + hcode.append("static const char* GetEnum" + name + "(" + name + " k);") + xcode.extend(["const char* " + gen_args[1] + "::GetEnum" + name + "(" + name + " k) {", + "switch(k) {"]) + for e in get_enum_list(dictionary, name): + xcode.append('case ' + e + ': return "' + e + '";') + xcode.extend(['default: MASSERT(0 && "Unexpected enumerator");', + '}', + 'return "UNEXPECTED ' + name + '";', + '}\n']) + append(src_file, xcode) + append(include_file, hcode) + +# Generate code for class node which is derived from TreeNode +def gen_handler_ast_node(dictionary): + global include_file, src_file, gen_args + code = [''] + node_name = dictionary["Name"]; + assert dictionary["TagType"] == "Class" + + member_functions = {} + child_functions = dictionary.get("ChildFunctions") + if child_functions != None: + for c in child_functions: + name = c.get("Name") + member_functions[name] = "R-" + str(c.get("ReturnType").get("Type").get("Name")) + + # gen_func_definition() for the code at the beginning of current function body + code.append(gen_func_definition(dictionary, node_name)) + members = dictionary.get("Members") + if members != None: + declloc = dictionary.get("DefLocation") + if gen_func_decl_location() and declloc != None and isinstance(declloc, dict): + fname = declloc.get("Filename") + floc = fname.find("shared/") + code.append("// Declared at " + fname[floc:] + ":" + str(declloc.get("LineNumber"))) + + for m in members: + name = m.get("Name") + assert name[0:1] == "m" + otype = m.get("Type").get("Name") + if otype == "_Bool": otype = "bool" + + plural = "Get" + name[1:] + + # m*Children to GetChild*() + if name[-8:] == "Children": + singular = "Get" + name[1:-3] + + # m*Catches to GetCatch*(), m*Classes to GetClass*() + elif name[-4:] == "ches" or name[-4:] == "shes" or name[-4:] == "sses" or name[-4:] == "xes" : + singular = "Get" + name[1:-2] + + # mIs* to Is*() for boolean type + elif name[:3] == "mIs" and otype == "bool": + plural = name[1:] + singular = name[1:] + + # Default singular without the endding 's' + else: + singular = "Get" + name[1:-1] + + ntype = get_pointed(otype) + access = m.get("Access") + accessstr = access if access != None else "" + if ntype != None: + if member_functions.get(plural) != None: + # gen_call_child_node() for child node in current function body + code.append(gen_call_child_node(dictionary, node_name, name, ntype, "node->" + plural + "()")) + else: + # It is an ERROR if no member function for the child node + code.append("Error!; // " + gen_call_child_node(dictionary, node_name, name, ntype, "node->" + plural + "()")) + elif ((otype == "SmallVector" or otype == "SmallList" or otype == "ExprListNode") + and member_functions.get(plural + "Num") != None + and (member_functions.get(singular) != None or member_functions.get(singular + "AtIndex") != None)): + func_name = singular if member_functions.get(singular) != None else singular + "AtIndex" + rtype = member_functions[func_name][2:] + if rtype == "_Bool": rtype = "bool" + ntype = get_pointed(rtype) + if (ntype != None or gen_call_handle_values()) and gen_children_num(plural) != None: + # gen_call_children_node() for list or vector of nodes before entering the loop + code.append(gen_call_children_node(dictionary, node_name, name, otype + "<" + rtype + ">", "node->" + plural + "Num()")) + code.append("for(unsigned i = 0; i < " + gen_children_num(plural) + "; ++i) {") + if ntype != None: + # gen_call_nth_child_node() for the nth child node in the loop for the list or vector + code.append(gen_call_nth_child_node(dictionary, node_name, name, ntype, "node->" + func_name + "(i)")) + else: + # gen_call_nth_child_value() for the nth child value in the loop for the list or vector + code.append(gen_call_nth_child_value(dictionary, node_name, name, rtype, "node->" + func_name + "(i)")) + code.append("}") + code.append(gen_call_children_node_end(dictionary, node_name, name, otype + "<" + rtype + ">", "node->" + plural + "Num()")) + elif gen_call_handle_values(): + if member_functions.get(plural) != None: + # gen_call_child_value() for child value in current function body + code.append(gen_call_child_value(dictionary, node_name, name, otype, "node->" + plural + "()")) + else: + # It is an ERROR if no member function for the child value + code.append("Error!; // " + gen_call_child_value(dictionary, node_name, name, otype, "node->" + plural + "()")) + + # gen_func_definition_end() for the code at the end of current function body + code.append(gen_func_definition_end(dictionary, node_name)) + append(src_file, code) + + code = [] + code.append(gen_func_declaration(dictionary, node_name)) + append(include_file, code) + +# Generate handler for TreeNode +def gen_handler_ast_TreeNode(dictionary): + global include_file, src_file, gen_args + code = [''] + code.append(gen_func_declaration(dictionary, "TreeNode")) + append(include_file, code) + + code = [''] + code.append(gen_func_definition(dictionary, "TreeNode")) + + code.append("switch(" + gen_switch_expr() + ") {") + for flag in get_enum_list(dictionary, "NodeKind"): + code.append("case " + flag + ":"); + node_name = flag[3:] + "Node" + filename = output_dir + 'maplefe/' + node_name + '.yaml' + if path.exists(filename): + # gen_call_child_node() for visiting child node + code.append(gen_call_child_node(dictionary, node_name, "", node_name, "static_cast<" + node_name + "*>(node)")) + elif node_name == "NullNode": + code.append("// Ignore NullNode") + else: + # it is an ERROR if the node kind is out of range + code.append("Error!!! // " + gen_call_child_node(dictionary, node_name, "", node_name, "static_cast<" + node_name + "*>(node)")) + code.append("break;"); + code.append('default: MASSERT(0 && "Unexpected node kind");') + code.append("}") + code.append(gen_func_definition_end(dictionary, "TreeNode")) + append(src_file, code) + +# Handle each node which has TreeNode as its base +def gen_handler_ast_node_file(dictionary): + base = dictionary.get("Bases") + if base != None: + basename = base[0].get("Name") + if basename == "TreeNode": + gen_handler_ast_node(dictionary) + +# Check each child records +def gen_handler(dictionary): + child_records = dictionary["ChildRecords"] + for child in child_records: + value = child["Name"] + filename = output_dir + 'maplefe/' + value + '.yaml' + if path.exists(filename): + handle_yaml(filename, gen_handler_ast_node_file) + # Generate handler for TreeNode + gen_handler_ast_TreeNode(dictionary) + +################################################################################ +# # +# Signature of TreeNodes # +# # +################################################################################ + +def gen_signature_of_ast_node(dictionary): + global tn_signature + tn_signature += '\n^' + dictionary["Name"]; + members = dictionary.get("Members") + if members != None: + for m in members: + tn_signature += '\n' + m.get("Name") + ':' + m.get("Type").get("Name") + +def gen_signature_of_ast_nodes(dictionary): + base = dictionary.get("Bases") + basename = base[0].get("Name") if base != None else '' + if basename == "TreeNode": + gen_signature_of_ast_node(dictionary) + +def gen_signature(dictionary): + for child in dictionary["ChildRecords"]: + filename = output_dir + 'maplefe/' + child["Name"] + '.yaml' + if path.exists(filename): + handle_yaml(filename, gen_signature_of_ast_nodes) + +tn_signature = 'Signature:' +handle_yaml(initial_yaml, gen_signature) +handle_yaml(treenode_yaml, gen_signature_of_ast_node) +signature = int(hashlib.sha256(tn_signature.encode('utf-8')).hexdigest()[-15:], 16) +append(output_dir + 'yaml.log', [tn_signature, str(signature)]) + +################################################################################ +# # +# Initialize/finalize include_file and src_file with gen_args # +# # +################################################################################ + +Initialization = 1 +Finalization = 2 +def handle_src_include_files(phase): + global include_file, src_file, gen_args + include_file = output_dir + "shared/" + gen_args[0] + ".h" + src_file = output_dir + "shared/" + gen_args[0] + ".cpp" + + include_start = [ +""" +#ifndef __{gen_args1upper}_HEADER__ +#define __{gen_args1upper}_HEADER__ + +#include "ast_module.h" +#include "ast.h" +#include "ast_type.h" +#include "ast_attr.h" +{gen_args3} + +namespace maplefe {{ + +class {gen_args1} {gen_args4} {{ +""".format(gen_args1upper=gen_args[1].upper(), gen_args1=gen_args[1], gen_args3=gen_args[3], gen_args4=gen_args[4]) +] # include_start + + include_end = [ +""" +}}; + +}} +#endif +""".format() # Use format() to match each pair of "{{" and "}}" +] # include_end + + src_start = [ +""" +#include "{gen_args0}.h" + +namespace maplefe {{ +""".format(gen_args0=gen_args[0]) +] # src_start + + src_end = [ +""" +}} +""".format() # Use format() to match each pair of "{{" and "}}" +] + if phase == Initialization: + create(include_file, license_notice + include_start) + create(src_file, license_notice + src_start) + elif phase == Finalization: + finalize(include_file, include_end) + finalize(src_file, src_end) + +################################################################################ +# # +# AstDump # +# # +################################################################################ + +def get_data_based_on_type(val_type, accessor): + if val_type[-10:] == "ASTScope *" or val_type[-12:] == "ASTScopePool": + return val_type + ': skipped"' + e = get_enum_type(val_type) + if e != None: + return e + ': " + GetEnum' + e + '(' + accessor + ')' + elif val_type == "LitData": + return 'LitData: LitId, " + GetEnumLitId(' + accessor + '.mType) + ", " + GetEnumLitData(' + accessor + ')' + elif val_type == "bool": + return val_type + ', ", ' + accessor + elif val_type == 'unsigned int' or val_type == 'uint32_t' or val_type == 'uint64_t' \ + or val_type == 'unsigned' or val_type == 'int' or val_type == 'int32_t' or val_type == 'int64_t' : + if accessor.find("GetStrIdx()") >= 0: + return val_type + ', " + std::to_string(' + accessor + ') + " => " + (' + accessor \ + + '? "\\""s + gStringPool.GetStringFromStrIdx(' + accessor + ') + "\\""s : "null"s)' + return val_type + ', " + std::to_string(' + accessor + ')' + elif val_type == 'const char *': + return 'const char*, " + (' + accessor + ' ? "\\""s + EncodeLiteral(' + accessor + ') + "\\""s : "null"s)' + elif val_type == 'RegExprData': + return 'RegExprData, Expr: " + "\\""s + ' + accessor + '.mExpr + "\\", Flags: \\""s + (' \ + + accessor + '.mFlags ? ' + accessor + '.mFlags : ""s) + "\\""s' + return val_type + ', " + "value" /* Warning: failed to get value */' + +def short_name(node_type): + return node_type.replace('class ', '').replace('maplefe::', '').replace(' *', '*') + +gen_padding = '' +def padding_name(name): + return gen_padding + name.ljust(7) + +# The follwoing gen_func_* and gen_call* functions are for AstDump +gen_children_num = lambda pl: 'node->' + pl + 'Num()' +gen_switch_expr = lambda: 'node->GetKind()' +gen_func_decl_location = lambda: True +gen_call_handle_values = lambda: True +gen_func_declaration = lambda dictionary, node_name: \ + "void " + gen_args[2] + node_name + "(" + node_name + "* node);" +gen_func_definition = lambda dictionary, node_name: \ + "void " + gen_args[1] + "::" + gen_args[2] + node_name + "(" + node_name + "* node) {" \ + + ('if (node == nullptr){return;}' if node_name == "TreeNode" else '\nif(DumpFB("' + node_name \ + + '", node)) { MASSERT(node->Is' + node_name.replace('Node', '()') + ');') +gen_call_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + ('Dump("' + padding_name(field_name) + ': ' + short_name(node_type) + '*", ' + accessor + ');\n' \ + if field_name != '' else '') + gen_args[2] + short_name(node_type) + '(' + accessor + ');' +gen_call_child_value = lambda dictionary, node_name, field_name, val_type, accessor: \ + 'Dump("' + padding_name(field_name) + ': "s + "' + get_data_based_on_type(val_type, accessor) + ');' +gen_call_children_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + 'DumpLB("' + padding_name(field_name) + ': ' + short_name(node_type) + ', size=", ' + accessor+ ');' +gen_call_children_node_end = lambda dictionary, node_name, field_name, node_type, accessor: 'DumpLE(' + accessor + ');' +gen_call_nth_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + 'Dump(std::to_string(i + 1) + ": ' + short_name(node_type) + '*", ' + accessor + ');\n' \ + + gen_args[2] + short_name(node_type) + '(' + accessor + ');' +gen_call_nth_child_value = lambda dictionary, node_name, field_name, val_type, accessor: \ + 'Dump(std::to_string(i) + ". ' + get_data_based_on_type(val_type, accessor) + ');' +gen_func_definition_end = lambda dictionary, node_name: \ + 'return;\n}' if node_name == "TreeNode" else 'DumpFE();\n}\nreturn;\n}' + +# +# Generate source files for dumping AST +# +gen_args = [ + "gen_astdump", # Filename + "AstDump", # Class name + "AstDump", # Prefix of function name + """ +#include +using namespace std::string_literals; +""", # Extra include directives + "", # Base class + ] +astdump = gen_args[0] +astdumpclass = gen_args[1] +prefixfuncname = gen_args[2] + +astdump_init = [ +""" +private: +ModuleNode *mASTModule; +std::ostream *mOs; +int indent; +std::string indstr; + +public: +{gen_args1}(ModuleNode *m) : mASTModule(m), mOs(nullptr), indent(0) {{ +indstr = std::string(256, \' \'); +for(int i = 2; i < 256; i += 4) +indstr.at(i) = \'.\'; +}} + +void Dump(const char *title, std::ostream *os) {{ + mOs = os; + *mOs << "{gen_args1}: " << title << " {{\\n"; + {gen_args2}TreeNode(mASTModule); + *mOs << "}}\\n"; +}} + +static std::string EncodeLiteral(std::string str) {{ + std::string enc; + bool esc = false; + for (auto&c : str) {{ + if(esc) {{ + switch(c) {{ + //case 'a': c = '\\a'; break; '\a' is 'a' in Javascript + case 'b': c = '\\b'; break; + case 'f': c = '\\f'; break; + case 'n': c = '\\n'; break; + case 'r': c = '\\r'; break; + case 't': c = '\\t'; break; + case 'v': c = '\\v'; break; + case '\\'': c = '\\''; break; + case '\\"': c = '"'; break; + default: enc += '\\\\'; + }} + esc = false; + }} else if(c == '\\\\') {{ + esc = true; + continue; + }} + switch(c) {{ + case '"': enc += "\\\\\\""; break; + case '\\b': enc += "\\\\b"; break; + case '\\f': enc += "\\\\f"; break; + case '\\n': enc += "\\\\n"; break; + case '\\r': enc += "\\\\r"; break; + case '\\t': enc += "\\\\t"; break; + case '\\v': enc += "\\\\v"; break; + default: enc += c; // TODO: Unicode support + }} + }} + return enc; +}} + +static std::string GetEnumLitData(LitData lit) {{ + switch (lit.mType) {{ + case LT_IntegerLiteral: + {{ std::stringstream s; + s << lit.mData.mInt; + return s.str(); + }} + case LT_FPLiteral: + return std::to_string(lit.mData.mFloat); + case LT_DoubleLiteral: + return std::to_string(lit.mData.mDouble); + case LT_BooleanLiteral: + return lit.mData.mBool ? "true" : "false"; + case LT_CharacterLiteral: + {{ std::string s = std::string(1, lit.mData.mChar.mData.mChar); + return EncodeLiteral(s); + }} + case LT_StringLiteral: + {{ std::string s = std::string(gStringPool.GetStringFromStrIdx(lit.mData.mStrIdx)); + return EncodeLiteral(s); + }} + case LT_NullLiteral: + return "null"; + case LT_ThisLiteral: + return "this"; + case LT_SuperLiteral: + return "super"; + case LT_VoidLiteral: + return "void 0"; + case LT_NA: + return "NA"; + default: + MASSERT(0 && "Unexpected LitData"); + }} + return "Unexpected"; +}} + +private: +void Dump(const std::string& msg) {{ + *mOs << indstr.substr(0, indent) << msg << std::endl; +}} + +void Dump(const std::string& msg, TreeNode *node) {{ + *mOs << indstr.substr(0, indent) << msg << (node ? "" : ", null") << std::endl; +}} + +void Dump(const std::string& msg, bool val) {{ + *mOs << indstr.substr(0, indent) << msg << (val ? "true" : "false") << std::endl; +}} + +TreeNode* DumpFB(const std::string& msg, TreeNode* node) {{ + if (node != nullptr) {{ + *mOs << indstr.substr(0, indent + 2) << msg; + indent += 4; + *mOs << " {{" << std::endl; + DumpTreeNode(node); + }} + return node; +}} + +void DumpFE() {{ + indent -= 4; + *mOs << indstr.substr(0, indent + 2) << "}}" << std::endl; +}} + +void DumpLB(const std::string& msg, unsigned size) {{ + *mOs << indstr.substr(0, indent) << msg << size << (size ? " [" : "") << std::endl; + indent += 4; +}} + +void DumpLE(unsigned size) {{ + indent -= 4; + if(size) + *mOs << indstr.substr(0, indent + 2) << "]" << std::endl; +}} +""".format(gen_args1=gen_args[1], gen_args2=gen_args[2]) +] # astdump_init + +handle_src_include_files(Initialization) +append(include_file, astdump_init) +handle_yaml(initial_yaml, gen_handler) +append(include_file, ['','public:']) +handle_yaml(initial_yaml, gen_enum_func) +gen_args[2] = "Dump" +gen_padding = "^ " +gen_call_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + ('Dump("' + padding_name(field_name) + ': ' + short_name(node_type) \ + + '*, " + (' + accessor + ' ? "NodeId=" + std::to_string(' + accessor \ + + '->GetNodeId()) : "null"s));\n' if field_name == "mParent" else \ + 'Dump("' + padding_name(field_name) + ': ' + short_name(node_type) + '*", ' + accessor + ');\n' \ + + prefixfuncname + short_name(node_type) + '(' + accessor + ');') if field_name != '' else '' +gen_call_nth_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + 'Dump(std::to_string(i + 1) + ": ' + short_name(node_type) + '*", ' + accessor + ');\n' \ + + "Ast" + gen_args[2] + short_name(node_type) + '(' + accessor + ');' +handle_yaml(treenode_yaml, gen_handler_ast_node) +handle_src_include_files(Finalization) + +################################################################################ +# # +# AstVisitor # +# # +################################################################################ + +def gen_setter(accessor): + return accessor.replace("Get", "Set").replace("()", "(n)").replace("(i)", "(i,n)") + +# The follwoing gen_func_* and gen_call* functions are for AstVisitor +gen_call_handle_values = lambda: False +gen_func_declaration = lambda dictionary, node_name: \ + 'virtual ' + node_name + '* ' + gen_args[2] + node_name + '(' + node_name + '* node);' +gen_func_definition = lambda dictionary, node_name: \ + node_name + '* ' + gen_args[1] + '::' + gen_args[2] + node_name + '(' + node_name \ + + '* node) {\nif(node != nullptr' + (' && !IsVisited(node)) {' \ + + '\nif(mTrace){std::cout << "Visiting ' + node_name + ', id=" << node->GetNodeId() << "..." << std::endl;}' \ + + '\nBaseTreeNode(node);' if node_name != 'TreeNode' else ') {') +gen_call_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + ('if(auto t = ' + accessor + ') {' + 'auto n = ' + gen_args[5] + node_type + '(t);' \ + + 'if(n != t){' + gen_setter(accessor) + ';}}' if field_name != "mParent" else '') \ + if field_name != '' else 'return ' + gen_args[5] + node_type + '(' + accessor + ');\n' +gen_call_children_node = lambda dictionary, node_name, field_name, node_type, accessor: '' +gen_call_children_node_end = lambda dictionary, node_name, field_name, node_type, accessor: '' +gen_call_nth_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + 'if(auto t = ' + accessor + ') { auto n = ' + gen_args[5] + node_type + '(t);' \ + + 'if(n != t) {' + gen_setter(accessor) + ';}}' +gen_func_definition_end = lambda dictionary, node_name: '}\nreturn node;\n}' + +# ------------------------------------------------------- +gen_args = [ + "gen_astvisitor", # Filename + "AstVisitor", # Class name + "Visit", # Prefix of function name + "", # Extra include directives + "", # Base class + "Visit", # In body + ] +astvisitor = gen_args[0] +astvisitorclass = gen_args[1] + +astvisitor_init = [ +""" +private: +bool mTrace; +BitVector mVisited; + +public: +{gen_args1}(bool t = false) : mTrace(t) {{}} + +TreeNode* {gen_args2}(TreeNode* node) {{ + mVisited.ClearAll(); + return {gen_args2}TreeNode(node); +}} + +virtual bool IsVisited(TreeNode* node) {{ + if(mVisited.GetBit(node->GetNodeId())) + return true; + mVisited.SetBit(node->GetNodeId()); + return false; +}} +""".format(gen_args1=gen_args[1], gen_args2=gen_args[2]) +] # astvisitor_init + +# Example to extract code pieces starting from initial_yaml +handle_src_include_files(Initialization) +append(include_file, astvisitor_init) +handle_yaml(initial_yaml, gen_handler) +gen_args[2] = "Base" +handle_yaml(treenode_yaml, gen_handler_ast_node) +handle_src_include_files(Finalization) + +################################################################################ +# # +# AstGraph # +# # +################################################################################ + +# The follwoing gen_func_* and gen_call* functions are for AstGraph +gen_func_declaration = lambda dictionary, node_name: \ + 'void ' + gen_args[2] + node_name + '(' + node_name + '* node);' +gen_func_definition = lambda dictionary, node_name: \ + 'void ' + gen_args[1] + '::' + gen_args[2] + node_name + '(' + node_name + '* node) {' \ + + '\nif(node != nullptr' + (' && PutNode(node)) {\nHandleTreeNode(node);' \ + if node_name != "TreeNode" else ') {') +gen_call_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + 'if(auto t = ' + accessor + ') {' + ('PutEdge(node, t, "' + field_name[1:] + \ + '", NK_' + node_type.replace('Node', '').replace('Tree', 'Null') + ');' \ + if field_name != '' else '') + gen_args[2] + node_type + '(t);}' +gen_call_nth_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + 'if(auto t = ' + accessor + ') { PutChildEdge(node, t, "' + field_name[1:] \ + + '", i, NK_' + node_type.replace('Node', '').replace('Tree', 'Null') \ + + '); ' + gen_args[2] + node_type + '(t);}' +gen_func_definition_end = lambda dictionary, node_name: '}\n}' + +# ------------------------------------------------------- +gen_args = [ + "gen_astgraph", # Filename + "AstGraph", # Class name + "DumpGraph", # Prefix of function name + """ +#include "stringpool.h" +#include "{astdump}.h" +#include +#include +#include +#include """.format(astdump = astdump), # Extra include directives + "", # Base class + ] + +astgraph_init = [ +""" +public: +{gen_args1}(TreeNode *m) : mRoot(m), mOs(nullptr) {{}} + +#define NodeName(n,s) ({astdumpclass}::GetEnumNodeKind((n)->GetKind()) + 3) << s << n->GetNodeId() +#define EnumVal(t,e,m) {astdumpclass}::GetEnum##e((static_cast(n))->Get##m()) +#define NodeColor(c) "\\",style=filled,color=white,fillcolor=\\""#c + +void {gen_args2}(const char *title, std::ostream *os) {{ + mNodes.clear(); + mOs = os; + mTitle = title; + *mOs << "digraph AST_Module {{\\nrankdir=LR;\\n"; + {gen_args2}TreeNode(mRoot); + *mOs << "}}\\n"; +}} + +bool PutNode(TreeNode *n) {{ + if(n && mNodes.find(n) == mNodes.end()) {{ + mNodes.insert(n); + *mOs << NodeName(n,\'_\') << " [label=\\"" << NodeName(n,',') << "\\\\n"; + std::string tid(EnumVal(TreeNode, TypeId, TypeId)); + if(tid != "TY_None" || n->GetTypeIdx() != 0) *mOs << "<" << tid << " " << n->GetTypeIdx() << ">\\\\n"; + + switch(n->GetKind()) {{ + case NK_Module: {{ + auto fn = static_cast(n)->GetFilename(); + if(auto p = std::strrchr(fn, '/')) + fn = p + 1; + *mOs << fn << "\\\\n" << mTitle << "\\",shape=\\"box"; break; + }} + case NK_Function: *mOs << (n->GetStrIdx() ? n->GetName() : "_anonymous_") << NodeColor(lightcoral); break; + case NK_Lambda: *mOs << NodeColor(pink); break; + case NK_Call: *mOs << NodeColor(burlywood); break; + case NK_Class: *mOs << (n->GetStrIdx() ? n->GetName() : ""); break; + case NK_Block: *mOs << NodeColor(lightcyan); break; + case NK_CondBranch: *mOs << NodeColor(lightblue); break; + case NK_Return: *mOs << NodeColor(tan); break; + case NK_Break: *mOs << NodeColor(peachpuff); break; + case NK_Continue: *mOs << NodeColor(paleturquoise); break; + case NK_SwitchCase: + case NK_SwitchLabel: + case NK_Switch: *mOs << NodeColor(powderblue); break; + case NK_ForLoop: *mOs << EnumVal(ForLoopNode, ForLoopProp, Prop); + case NK_WhileLoop: + case NK_DoLoop: *mOs << NodeColor(lightskyblue); break; + case NK_Identifier: *mOs << "\\\\\\"" << n->GetName() << "\\\\\\"" << NodeColor(wheat); break; + case NK_Decl: *mOs << EnumVal(DeclNode, DeclProp, Prop) << NodeColor(palegoldenrod); break; + case NK_PrimType: *mOs << EnumVal(PrimTypeNode, TypeId, PrimType) << NodeColor(lemonchiffon); break; + case NK_BinOperator: *mOs << EnumVal(BinOperatorNode, OprId, OprId); + case NK_TerOperator: + *mOs << NodeColor(palegreen); break; + case NK_UnaOperator: *mOs << EnumVal(UnaOperatorNode, OprId, OprId); + case NK_InstanceOf: + case NK_TypeOf: *mOs << NodeColor(lightgreen); break; + case NK_Literal: {{ + std::string s({astdumpclass}::GetEnumLitData(static_cast(n)->GetData())); + std::replace(s.begin(), s.end(), '"', ':'); + *mOs << s; + break; + }} + case NK_Pass: *mOs << NodeColor(darkgrey); break; + case NK_AsType: *mOs << NodeColor(bisque); break; + case NK_New: *mOs << NodeColor(khaki); break; + case NK_Try: *mOs << NodeColor(plum); break; + case NK_Catch: *mOs << NodeColor(thistle); break; + case NK_Finally: *mOs << NodeColor(thistle); break; + case NK_Throw: *mOs << NodeColor(plum); break; + case NK_Dimension: *mOs << static_cast(n)->GetDimensionsNum() << " dim(s)"; break; + case NK_UserType: *mOs << EnumVal(UserTypeNode, UT_Type, Type); break; + case NK_XXportAsPair: *mOs << (static_cast(n)->IsDefault() ? "default" : ""); + *mOs << (static_cast(n)->IsRef() ? " ref" : " copy"); break; + case NK_Struct: *mOs << EnumVal(StructNode, StructProp, Prop); *mOs << "\\\\n" << n->GetName(); break; + }} + if(n->IsStmt()) + *mOs << "\\",penwidth=2,color=\\"tomato"; + *mOs << "\\"];\\n"; + return true; + }} + return false; +}} + +void PutEdge(TreeNode *from, TreeNode *to, const char *field, NodeKind k) {{ + if(to) + *mOs << NodeName(from,\'_\') << " -> " << NodeName(to,\'_\') << "[label=" << field + << (to->GetParent() == from ? ",arrowhead=diamond" : "") << "];\\n"; +}} + +void PutChildEdge(TreeNode *from, TreeNode *to, const char *field, unsigned idx, NodeKind k) {{ + if(to) + *mOs << NodeName(from,\'_\') << " -> " << NodeName(to,\'_\') << "[label=\\"" << field + << "[" << idx << "]\\"" << (to->GetParent() == from ? ",arrowhead=diamond" : "") << "];\\n"; +}} + +void HandleTreeNode(TreeNode *node) {{ + if (auto t = node->GetLabel()) {{ + PutEdge(node, t, "Label", NK_Null); + DumpGraphTreeNode(t); + }} + for (unsigned i = 0; i < node->GetAsTypesNum(); ++i) + if (auto t = node->GetAsTypeAtIndex(i)) {{ + PutChildEdge(node, t, "AsTypes", i, NK_AsType); + DumpGraphAsTypeNode(t); + }} +}} + +private: +TreeNode *mRoot; +std::ostream *mOs; +std::set mNodes; +const char *mTitle; +""".format(gen_args1=gen_args[1], gen_args2=gen_args[2], astdumpclass=astdumpclass) +] # astgraph_init + +handle_src_include_files(Initialization) +append(include_file, astgraph_init) +handle_yaml(initial_yaml, gen_handler) +handle_src_include_files(Finalization) + +################################################################################ +# # +# Emitter # +# # +################################################################################ + +def get_data_based_on_type(val_type, accessor): + e = get_enum_type(val_type) + if e == "ASTScope *": + return e + ': " + "' + accessor + '");' + elif e != None: + return astdumpclass + '::GetEnum' + e + '(' + accessor + ')' + elif val_type == "LitData": + return astdumpclass + '::GetEnumLitData(' + accessor + ')' + elif val_type == "bool": + return 'std::to_string(' + accessor + ')' + elif val_type == 'unsigned int' or val_type == 'uint32_t' or val_type == 'uint64_t' \ + or val_type == 'unsigned' or val_type == 'int' or val_type == 'int32_t' or val_type == 'int64_t' : + return 'std::to_string(' + accessor + ')' + elif val_type == 'const char *': + return 'std::to_string(' + accessor + ' ? std::string("\\"") + ' + accessor + ' + "\\"" : "null")' + return 'Warning: failed to get value with ' + val_type + ", " + accessor + +def short_name(node_type): + return node_type.replace('class ', '').replace('maplefe::', '').replace(' *', '*') + +# The follwoing gen_func_* and gen_call* functions are for Emitter +gen_func_decl_location = lambda: False +gen_call_handle_values = lambda: True +gen_func_declaration = lambda dictionary, node_name: \ + "virtual std::string " + gen_args[2] + node_name + "(" + node_name + "* node);" +gen_func_definition = lambda dictionary, node_name: \ + "std::string " + gen_args[1] + "::" + gen_args[2] + node_name + "(" + node_name + "* node) {" \ + + 'if (node == nullptr) \nreturn std::string();' \ + + ('' if node_name == "TreeNode" else \ + 'std::string str;') +gen_call_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + 'if(auto n = ' + accessor + ') {str += " "s + ' + gen_args[2] + short_name(node_type) + '(n);}' \ + if field_name != '' else \ + 'return ' + gen_args[2] + short_name(node_type) + '(' + accessor + ');' +gen_call_child_value = lambda dictionary, node_name, field_name, val_type, accessor: \ + 'str += " "s + ' + get_data_based_on_type(val_type, accessor) + ';' +gen_call_nth_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + 'if(i)str+= ", "s; if(auto n = ' + accessor + ') {str += " "s + ' + gen_args[2] + short_name(node_type) + '(n);}' +gen_call_nth_child_value = lambda dictionary, node_name, field_name, val_type, accessor: \ + 'str += " "s + ' + get_data_based_on_type(val_type, accessor) + ';' +gen_func_definition_end = lambda dictionary, node_name: \ + 'mPrecedence = \'\\030\'; if(node->IsStmt()) str += ";\\n"s;' \ + + 'return str;}' if node_name != "TreeNode" else 'return std::string();}' + +# +gen_args = [ + "gen_emitter", # Filename + "Emitter", # Class name + "Emit", # Prefix of function name + """ +#include "ast_handler.h" +#include "{astdump}.h" +using namespace std::string_literals; +""".format(astdump = astdump), # Extra include directives + "" + "", # Base class + ] + +astemit_init = [ +""" +protected: +using Precedence = unsigned char; +Precedence mPrecedence; + +Module_Handler *mHandler; + +public: +{gen_args1}(Module_Handler *h) : mHandler(h) {{}} + +std::string {gen_args2}(const char *title); +std::string GetEnding(TreeNode *n); +std::string Clean(std::string &s); +std::string GetBaseFilename(); +std::string GetModuleName(const char *p = nullptr); + +ModuleNode *GetASTModule() {{ return mHandler->GetASTModule(); }} + +""".format(gen_args1=gen_args[1], gen_args2=gen_args[2]) +] # astemit_init + +if False: + handle_src_include_files(Initialization) + append(src_file, ['using namespace std::string_literals;']) + append(include_file, astemit_init) + handle_yaml(initial_yaml, gen_handler) + handle_src_include_files(Finalization) + +################################################################################ +# # +# AstStore # +# # +################################################################################ + +def get_data_based_on_type(val_type, accessor): + if val_type[-10:] == "ASTScope *" or val_type[-12:] == "ASTScopePool": + return '; // Skip ' + val_type + e = get_enum_type(val_type) + if e != None: + return 'WriteValue(static_cast(' + accessor + '));' + elif val_type == "bool": + return 'WriteValue(static_cast(' + accessor + '));' + elif val_type == 'unsigned int' or val_type == 'uint32_t' or val_type == 'uint64_t' \ + or val_type == 'unsigned' or val_type == 'int' or val_type == 'int32_t' or val_type == 'int64_t' : + return ('AddStrIdx(' + accessor + ');' if accessor.find("GetStrIdx()") >= 0 else '') \ + + 'WriteValue(static_cast(' + accessor + '));' + elif val_type == "LitData": + return 'if(' + accessor + '.mType == LT_StringLiteral) AddStrIdx(' + accessor + '.mData.mStrIdx);' \ + + 'WriteValue(static_cast(' + accessor + '.mType));' \ + + 'WriteValue(' + accessor + '.mData.mInt64);' + elif val_type == 'const char *': + return 'WriteString(' + accessor + ');' + elif val_type == 'RegExprData': + return 'WriteString(' + accessor + '.mExpr);\nWriteString(' + accessor + '.mFlags);' + return 'Failed to get value with ' + val_type + ", " + accessor + ';' + +def short_name(node_type): + return node_type.replace('class ', '').replace('maplefe::', '').replace(' *', '*') + +# The follwoing gen_func_* and gen_call* functions are for AstStore +# +gen_func_decl_location = lambda: False +gen_call_handle_values = lambda: True +gen_func_declaration = lambda dictionary, node_name: \ + "void " + gen_args[2] + node_name + "(" + node_name + "* node);" +gen_func_definition = lambda dictionary, node_name: \ + "void " + gen_args[1] + "::" + gen_args[2] + node_name + "(" + node_name + "* node) {" \ + + ('' if node_name == "TreeNode" else 'WriteNode(node);') +gen_call_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + 'WriteAddress(' + accessor + '); // ' + field_name + ': ' + node_type if field_name != '' else \ + gen_args[2] + short_name(node_type) + '(' + accessor + ');' +gen_call_child_value = lambda dictionary, node_name, field_name, val_type, accessor: \ + get_data_based_on_type(val_type, accessor) + ' // ' + field_name + ': ' + val_type +gen_call_children_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + 'WriteLength(' + accessor + '); // ' + field_name + ': ' + node_type +gen_call_nth_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + 'WriteAddress(' + accessor + '); // ' + field_name + ': ' + node_type +gen_call_nth_child_value = lambda dictionary, node_name, field_name, val_type, accessor: \ + get_data_based_on_type(val_type, accessor) + ' // ' + field_name + ': ' + val_type +gen_func_definition_end = lambda dictionary, node_name: '}' +# +gen_args = [ + "gen_aststore", # Filename + "AstStore", # Class name + "Store", # Prefix of function name + """ +#include "stringpool.h" +#include "{astvisitor}.h" +#include +#include +#include +namespace maplefe {{ +using AstBuffer = std::vector; +using AstNodeVec = std::vector; +}} +""".format(astvisitor=astvisitor), + ": public " + astvisitorclass, # Base class + ] + +#tag_control = 'true' +tag_control = "tag != 'A' && tag != 'V'" + +aststore_init = [ +""" +private: +ModuleNode *mASTModule; +AstBuffer mAstBuf {{'M', 'P'}}; +AstBuffer *mBufPtr; +std::set mStrIdxSet; + +public: +{gen_args1}(ModuleNode *m) : mASTModule(m) {{}} + +AstBuffer& GetAstBuf() {{return mAstBuf;}} + +bool {gen_args2}InAstBuf() {{ + AstBuffer node_buf; + mAstBuf.erase(mAstBuf.begin() + 2, mAstBuf.end()); + mBufPtr = &mAstBuf; + WriteNum('L', {signature}LL); + mAstBuf.reserve(32768); // For performance + node_buf.reserve(32768); + mBufPtr = &node_buf; + VisitTreeNode(mASTModule); + mBufPtr = &mAstBuf; + WriteStrIdxTable(); + mAstBuf.insert(mAstBuf.end(), node_buf.begin(), node_buf.end()); + mStrIdxSet.clear(); + return true; +}} + +bool IsVisited(TreeNode* node) {{ + if({astvisitorclass}::IsVisited(node)) + return true; + {gen_args2}TreeNode(node); + return false; +}} + +// Tags: +// 'N': Beginning of a tree node +// 'A': address of a child tree node +// 'V': value of a field in a tree node +// 'L': list/vector of chrildren in a tree node +// 'S': char string of a field in a tree node +// 'T': StrIdx Table +// The initial version will keep all tags, and some of them can be optimized out + +// LEB128, same as for MapleIR +void WriteNum(uint8_t tag, int64_t x) {{ + if({tag_control}) + mBufPtr->push_back(tag); + while (x < -0x40 || x >= 0x40) {{ + mBufPtr->push_back(static_cast((static_cast(x) & 0x7F) + 0x80)); + x = x >> 7; + }} + mBufPtr->push_back(static_cast(static_cast(x) & 0x7F)); +}} + +void WriteNode(TreeNode *node) {{ + AstBuffer *tmp = mBufPtr; + mBufPtr = &mAstBuf; + WriteNum('N', static_cast(node->GetKind())); + WriteNum('V', static_cast(node->GetNodeId())); + mBufPtr = tmp; + //WriteNum('N', static_cast(node->GetKind())); + WriteTreeNode(node); // Base TreeNode +}} + +void WriteAddress(TreeNode *node) {{ + if(node) + WriteNum('A', static_cast(node->GetNodeId())); + else + WriteNum('A', -1); +}} + +void WriteValue(int64_t val) {{ + WriteNum('V', val); +}} + +void WriteLength(unsigned len) {{ + WriteNum('L', static_cast(len)); +}} + +void WriteString(const char *str) {{ + if(const char *p = str) {{ + WriteNum('S', static_cast(std::strlen(p) + 1)); + do {{ + mBufPtr->push_back(static_cast(*p)); + }} while(*p++); + }} else + WriteNum('S', 0); +}} + +void WriteStrIdxTable() {{ + WriteNum('T', static_cast(mStrIdxSet.size())); + for(auto s: mStrIdxSet) {{ + WriteValue(s); + WriteString(gStringPool.GetStringFromStrIdx(s)); + }} +}} + +void AddStrIdx(unsigned idx) {{ + if(idx) + mStrIdxSet.insert(idx); +}} + +""".format(signature=signature, gen_args1=gen_args[1], gen_args2=gen_args[2], \ + astvisitorclass=astvisitorclass, tag_control=tag_control) +] # aststore_init + +handle_src_include_files(Initialization) +append(src_file, ['using namespace std::string_literals;']) +append(include_file, aststore_init) +handle_yaml(initial_yaml, gen_handler) +gen_args[2] = "Write" +handle_yaml(treenode_yaml, gen_handler_ast_node) +handle_src_include_files(Finalization) + +################################################################################ +# # +# AstLoad # +# # +################################################################################ + +def gen_setter(accessor): + return accessor.replace("Get", "Set").replace("()", "(n)").replace("(i)", "(i,n)").replace("Is", "SetIs") + +def gen_add_setter(accessor): + return accessor.replace("Get", "Add").replace("AtIndex", "").replace("(i)", "(n)") + +def short_name(node_type): + return node_type.replace('class ', '').replace('maplefe::', '').replace(' *', '*') + +def set_data_based_on_type(val_type, accessor, setter): + if val_type[-10:] == "ASTScope *" or val_type[-12:] == "ASTScopePool": + return '; /* Skip ' + val_type + ' */' + e = get_enum_type(val_type) + if e != None: + return e + ' n = static_cast<' + e + '>(ReadValue());' + setter(accessor) + ';' + elif val_type == "bool": + return val_type + ' n = static_cast<' + val_type + '>(ReadValue());' + setter(accessor) + ';' + elif val_type == 'unsigned int' or val_type == 'uint32_t' or val_type == 'uint64_t' \ + or val_type == 'unsigned' or val_type == 'int' or val_type == 'int32_t' or val_type == 'int64_t' : + return (val_type + ' n = static_cast<' + val_type + '>(ReadValue());' if accessor.find("GetStrIdx()") < 0 \ + else val_type + ' n = static_cast<' + val_type + '>(mStrMap[ReadValue()]);') \ + + (setter(accessor) + ';' if accessor.find("GetNodeId()") < 0 else '/* ' + setter(accessor) + '; */') + elif val_type == "LitData": + return val_type + ' n; n.mType = static_cast(ReadValue());if(n.mType == LT_StringLiteral)' \ + + 'n.mData.mInt64 = mStrMap[ReadValue()]; else n.mData.mInt64 = ReadValue();' + setter(accessor) + ';' + elif val_type == 'const char *': + return val_type + ' n = ReadString();' + setter(accessor) + ';' + elif val_type == 'RegExprData': + return val_type + ' n; n.mExpr = ReadString(); n.mFlags = ReadString();' + setter(accessor) + ';' + return 'Failed to get value with ' + val_type + ", " + accessor + ';' + +# The follwoing gen_func_* and gen_call* functions are for AstLoad +# +gen_children_num = lambda pl: 'num' +gen_func_decl_location = lambda: False +gen_call_handle_values = lambda: True +gen_func_declaration = lambda dictionary, node_name: \ + "void " + gen_args[2] + node_name + '(' + node_name + ' *node);' +gen_func_definition = lambda dictionary, node_name: \ + "void " + gen_args[1] + "::" + gen_args[2] + node_name + '(' + node_name + ' *node) {\n' \ + + ('' if node_name == "TreeNode" else 'InitTreeNode(node);') +gen_call_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + '{' + node_type + '* n = static_cast<' + node_type + '*>(ReadAddress()); ' + gen_setter(accessor) \ + + '; } // ' + field_name + ': ' + node_type \ + if field_name != '' else gen_args[2] + short_name(node_type) + '(static_cast<' + short_name(node_name) + '*>(node));' +gen_call_child_value = lambda dictionary, node_name, field_name, val_type, accessor: \ + '{' + set_data_based_on_type(val_type, accessor, gen_setter) + '} // ' + field_name + ': ' + val_type +gen_call_children_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + '{unsigned num = ReadLength(); // ' + field_name + ': ' + node_type +gen_call_nth_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + node_type + '* n = static_cast<' + node_type + '*>(ReadAddress()); ' + gen_add_setter(accessor) \ + + '; // ' + field_name + ': ' + node_type +gen_call_nth_child_value = lambda dictionary, node_name, field_name, val_type, accessor: \ + '{' + set_data_based_on_type(val_type, accessor, gen_add_setter) + '} // ' + field_name + ': ' + val_type +gen_call_children_node_end = lambda dictionary, node_name, field_name, node_type, accessor: '}' +gen_func_definition_end = lambda dictionary, node_name: 'return;}' +# +gen_args = [ + "gen_astload", # Filename + "AstLoad", # Class name + "Load", # Prefix of function name + """ +#include "stringpool.h" +#include "ast_mempool.h" +#include "{astvisitor}.h" +#include +#include +#include +#include +namespace maplefe {{ +using AstBuffer = std::vector; +using AstBufIter = std::vector::iterator; +using AstNodeVec = std::vector; +using AstNodeMap = std::unordered_map; +using AstStrMap = std::unordered_map; +}} +""".format(astvisitor=astvisitor), + "" # Base class + ] + +astload_init = [ +""" +private: +AstBufIter it; +AstBufIter end; +AstStrMap mStrMap; // key: previous str id, val: new str id +AstNodeMap mNodeMap; // key: previous node id, val: TreeNode* + +public: +ModuleNode *{gen_args2}FromAstBuf(AstBuffer &buf) {{ + it = buf.begin(); + end = buf.end(); + return Next(); +}} + +ModuleNode *Next() {{ + if(it == end) + return nullptr; + bool check = *it++ == 'M'; + check &= *it++ == 'P'; + if(!check) {{ + std::cerr << "Error: Unknown file type." << std::endl; + return nullptr; + }} + int64_t sig = ReadNum('L'); + if(sig != {signature}LL) {{ + std::cerr << "Error: Unknown signature " << sig << ". Expected {signature}." << std::endl; + return nullptr; + }} + AstNodeVec node_vec; + while(*it != 'T') + node_vec.push_back(CreateNode()); + ModuleNode *module = static_cast(node_vec.front()); + ReadStrIdxTable(); + for(auto iter = node_vec.begin(); iter != node_vec.end(); ++iter) + ReadNode(*iter); + mStrMap.clear(); + mNodeMap.clear(); + return module; +}} + +TreeNode *CreateNode() {{ + NodeKind k = static_cast(ReadNum('N')); + unsigned id = static_cast(ReadNum('V')); + TreeNode *node = CreateTreeNode(k); + mNodeMap[id] = node; + return node; +}} + +// LEB128, same as for MapleIR +int64_t ReadNum(uint8_t tag) {{ + if({tag_control}) {{ + bool check = tag == *it++; + MASSERT(check); + }} + uint64_t n = 0; + int64_t y = 0; + uint64_t b = static_cast(*it++); + while (b >= 0x80) {{ + y += ((b - 0x80) << n); + n += 7; + b = static_cast(*it++); + }} + b = (b & 0x3F) - (b & 0x40); + return y + (b << n); +}} + +void ReadNode(TreeNode *node) {{ + //NodeKind k = static_cast(ReadNum('N')); + //MASSERT(k == node->GetKind()); + LoadTreeNode(node); +}} + +TreeNode *ReadAddress() {{ + int64_t n = ReadNum('A'); + return n != -1 ? mNodeMap[static_cast(n)] : nullptr; +}} + +int64_t ReadValue() {{ + return ReadNum('V'); +}} + +int64_t ReadLength() {{ + return ReadNum('L'); +}} + +const char *ReadString() {{ + int64_t len = ReadNum('S'); + if(len) {{ + const char *res = gStringPool.FindString(reinterpret_cast(&(*it))); + it += len; + return res; + }} else + return nullptr; +}} + +void ReadStrIdxTable() {{ + int64_t num = ReadNum('T'); + for(int64_t i = 0; i < num; ++i) {{ + unsigned id = static_cast(ReadValue()); + const char *s = ReadString(); + unsigned nid = gStringPool.GetStrIdx(s); + mStrMap[id] = nid; + }} +}} + +""".format(signature=signature, gen_args1=gen_args[1], gen_args2=gen_args[2], \ + astvisitorclass=astvisitorclass, tag_control=tag_control) +] # astload_init + +handle_src_include_files(Initialization) +append(src_file, ['using namespace std::string_literals;']) +append(include_file, astload_init) +handle_yaml(initial_yaml, gen_handler) +gen_args[2] = "Init" +gen_func_declaration = lambda dictionary, node_name: \ + 'void ' + gen_args[2] + node_name + '(TreeNode *node);' +gen_func_definition = lambda dictionary, node_name: \ + 'void ' + gen_args[1] + "::" + gen_args[2] + node_name + '(TreeNode *node) {' +gen_func_definition_end = lambda dictionary, node_name: '}' +handle_yaml(treenode_yaml, gen_handler_ast_node) +gen_args[2] = "Create" +gen_switch_expr = lambda: 'k' +gen_children_num = lambda pl: None +gen_call_handle_values = lambda: False +gen_func_declaration = lambda dictionary, node_name: \ + node_name + "* " + gen_args[2] + node_name + "(NodeKind k);" +gen_func_definition = lambda dictionary, node_name: \ + node_name + "* " + gen_args[1] + "::" + gen_args[2] + node_name + "(NodeKind k) {\n" \ + + (node_name + ' *node;' if node_name == "TreeNode" else \ + node_name + ' *node = new (gTreePool.NewTreeNode(sizeof(' + node_name + '))) ' + node_name + '();') +gen_call_child_node = lambda dictionary, node_name, field_name, node_type, accessor: \ + '' if field_name != '' else 'node = ' + gen_args[2] + short_name(node_type) + '(k);' +gen_call_children_node = lambda dictionary, node_name, field_name, node_type, accessor: '' +gen_call_nth_child_node = lambda dictionary, node_name, field_name, node_type, accessor: '' +gen_call_children_node_end = lambda dictionary, node_name, field_name, node_type, accessor: '' +gen_func_definition_end = lambda dictionary, node_name: 'return node;}' +handle_yaml(initial_yaml, gen_handler) +handle_src_include_files(Finalization) diff --git a/src/MapleFE/scripts/perf-java.sh b/src/MapleFE/scripts/perf-java.sh new file mode 100755 index 0000000000000000000000000000000000000000..b838fd3675cf0b76f7ba0a6bc9aee3d477e59d70 --- /dev/null +++ b/src/MapleFE/scripts/perf-java.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# This script is to measure the runtime performance of java2ast and other executables +# If perf is not installed yet, please install the package linux-tools-common with all dependencies +TS2AST=$(dirname $0)/../output/java/bin/java2ast +CMD="sudo perf record -e cpu-cycles,cache-misses --call-graph fp -F 10000 -o perf.data" +if [ $# -eq 0 ]; then + echo "Usage: $0 " + echo " $0 " + exit 1 +elif [ $# -eq 1 -a "$(basename $1)" != "$(basename $1 .ts)" ]; then + echo $CMD $TS2AST "$@" + $CMD $TS2AST "$@" +else + echo $CMD "$@" + $CMD "$@" +fi +echo sudo perf report +sudo perf report diff --git a/src/MapleFE/scripts/perf.sh b/src/MapleFE/scripts/perf.sh new file mode 100755 index 0000000000000000000000000000000000000000..7d3c9bbbd695f5b0d3896bd344bc96d72839da3b --- /dev/null +++ b/src/MapleFE/scripts/perf.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# This script is to measure the runtime performance of ts2ast and other executables +# If perf is not installed yet, please install the package linux-tools-common with all dependencies +TS2AST=$(dirname $0)/../output/typescript/bin/ts2ast +CMD="sudo perf record -e cpu-cycles,cache-misses --call-graph fp -F 10000 -o perf.data" +if [ $# -eq 0 ]; then + echo "Usage: $0 " + echo " $0 " + exit 1 +elif [ $# -eq 1 -a "$(basename $1)" != "$(basename $1 .ts)" ]; then + echo $CMD $TS2AST "$@" + $CMD $TS2AST "$@" +else + echo $CMD "$@" + $CMD "$@" +fi +echo sudo perf report +sudo perf report diff --git a/src/MapleFE/shared/Makefile b/src/MapleFE/shared/Makefile index 23e7e196bb2a0b8fc522c57cf1eff8239f2bbef3..a36bf4408e58eba9d2274287221a13d0f1b632a0 100644 --- a/src/MapleFE/shared/Makefile +++ b/src/MapleFE/shared/Makefile @@ -1,10 +1,24 @@ +# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + include ../Makefile.in all: $(MAKE) -C src clean: - rm -rf $(MAPLEFE_ROOT)/$(BUILDDIR)/shared + rm -rf $(BUILDDIR)/shared test: $(MAKE) -C ../test p diff --git a/src/MapleFE/shared/include/appnode_pool.h b/src/MapleFE/shared/include/appnode_pool.h new file mode 100644 index 0000000000000000000000000000000000000000..70ed2959f21e195c79841fe5e62039dd866d3ad9 --- /dev/null +++ b/src/MapleFE/shared/include/appnode_pool.h @@ -0,0 +1,49 @@ +/* +* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ +////////////////////////////////////////////////////////////////////////////// +// This file contains the Memory Pool for AppealNode which are dynamically // +// allocated. // +////////////////////////////////////////////////////////////////////////////// + +#ifndef __APPNODE_POOL_H__ +#define __APPNODE_POOL_H__ + +#include "mempool.h" + +namespace maplefe { + +class AppealNode; + +// this Pool contains two types of dynamic memory. +// (1) Those managed by mMP. This is where all the AppealNode come from. +// (2) Those managed by some containers in some AppealNode. For example, the +// SmallVector of children nodes. These are maintained by containers. +// +class AppealNodePool { +private: + MemPool mMP; +public: + AppealNodePool(){} + ~AppealNodePool() {mMP.Release();} + + void SetBlockSize(unsigned s) {mMP.SetBlockSize(s);} + AppealNode* NewAppealNode(); + + // Clear all data, keep the memory + void Clear() {mMP.Clear();} +}; + +} +#endif diff --git a/src/MapleFE/shared/include/ast.h b/src/MapleFE/shared/include/ast.h index 43c2c003e0633608e04028c107833e4a391f670d..347f8d443493ec5bb3bf048c33a8f7d29e0328a6 100644 --- a/src/MapleFE/shared/include/ast.h +++ b/src/MapleFE/shared/include/ast.h @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -46,6 +46,7 @@ // A Function node have its arguments as children node. The return value is not counted. // +#include "stringpool.h" #include "ast_mempool.h" #include "container.h" @@ -54,6 +55,8 @@ namespace maplefe { +#define SETPARENT(n) if(n && !n->IsPrimType()) n->SetParent(this) + enum NodeKind { #undef NODEKIND #define NODEKIND(K) NK_##K, @@ -69,36 +72,102 @@ enum NodeKind { // if needed in order to invoke the derived class destructor. class AnnotationNode; +class AsTypeNode; +class IdentifierNode; +class FunctionNode; +class UserTypeNode; +class ComputedNameNode; +class ASTScope; + class TreeNode { protected: NodeKind mKind; + unsigned mNodeId; TreeNode *mParent; TreeNode *mLabel; // label of a statement, or expression. - const char *mName; + unsigned mStrIdx; + unsigned mTypeIdx; // typetable index + TypeId mTypeId; // typeId of the node + ASTScope *mScope; + + bool mIsStmt; // if a node is a statement + bool mIsOptional; // if a node is optionally existing during runtime. + // This design is first coming from Javascript. + bool mIsNonNull; // if a node is asserted to be non-null. + // This design is first coming from Typescript. + bool mIsRest; // A spread or rest syntax in Javascript. + bool mIsConst; // A constant node. Readonly. + + // This is a feature coming from TypeScript. Almost every expression in Typescript has + // this information. So it's here. + SmallVector mAsTypes; + public: - TreeNode() {mKind = NK_Null; mLabel = NULL; mParent = NULL; mName = NULL;} + TreeNode(NodeKind k, unsigned i) + : mKind(k), mLabel(nullptr), mParent(nullptr), mStrIdx(i), mIsStmt(false), mTypeId(TY_None), mTypeIdx(0), + mScope(nullptr), mIsOptional(false), mIsNonNull(false), mIsRest(false), mIsConst(false) {} + TreeNode(NodeKind k) : TreeNode(k, 0) {} + //TreeNode() : TreeNode(NK_Null, 0) {} virtual ~TreeNode() {} #undef NODEKIND #define NODEKIND(K) bool Is##K() const {return mKind == NK_##K;} #include "ast_nk.def" - bool IsScope() {return IsBlock() || IsClass() || IsFunction() || IsInterface();} +#undef TYPE +#undef PRIMTYPE +#define TYPE(K) bool IsTypeId##K() const {return mTypeId == TY_##K;} +#define PRIMTYPE(K) bool IsTypeId##K() const {return mTypeId == TY_##K;} +#include "supported_types.def" + + bool IsScope() {return IsBlock() || IsClass() || IsFunction() || IsInterface() || IsModule();} bool TypeEquivalent(TreeNode*); - NodeKind GetKind() {return mKind;} + void SetKind(NodeKind k) {} // Not allowed to change its kind + void SetNodeId(unsigned id) {mNodeId = id;} void SetParent(TreeNode *p) {mParent = p;} - void SetLabel (TreeNode *p) {mLabel = p;} + void SetLabel (TreeNode *p) {mLabel = p; SETPARENT(p);} + void SetTypeId(TypeId id) {mTypeId = id;} + void SetTypeIdx(unsigned id) {mTypeIdx = id;} + void SetScope(ASTScope *s) {mScope = s;} + + NodeKind GetKind() {return mKind;} + unsigned GetNodeId() {return mNodeId;} TreeNode* GetParent() {return mParent;} TreeNode* GetLabel() {return mLabel;} - - virtual const char* GetName() {return mName;} - virtual void SetName(const char *s) {mName = s;} + TypeId GetTypeId() {return mTypeId;} + unsigned GetTypeIdx() {return mTypeIdx;} + ASTScope *GetScope() {return mScope;} + + bool IsStmt() {return mIsStmt;} + void SetIsStmt(bool b = true) {mIsStmt = b;} + bool IsOptional() {return mIsOptional;} + void SetIsOptional(bool b = true){mIsOptional = b;} + bool IsNonNull() {return mIsNonNull;} + void SetIsNonNull(bool b = true) {mIsNonNull = b;} + bool IsRest() {return mIsRest;} + void SetIsRest(bool b = true) {mIsRest = b;} + bool IsConst() {return mIsConst;} + void SetIsConst(bool b = true) {mIsConst = b;} + bool IsThis() {return mStrIdx == gStringPool.GetStrIdx("this");} + + virtual unsigned GetStrIdx() {return mStrIdx;} + virtual void SetStrIdx(unsigned id) {mStrIdx = id;} + virtual const char *GetName() {return gStringPool.GetStringFromStrIdx(mStrIdx);} + virtual void SetStrIdx(std::string str) {mStrIdx = gStringPool.GetStrIdx(str);} virtual void ReplaceChild(TreeNode *oldchild, TreeNode *newchild){} virtual void AddAttr(AttrId) {} virtual void AddAnnotation(AnnotationNode *n){} - virtual void Dump(unsigned){} + // AsType related + unsigned GetAsTypesNum() {return mAsTypes.GetNum();} + void AddAsType(AsTypeNode *n) {mAsTypes.PushBack(n);} + void AddAsTypes(TreeNode *n); + AsTypeNode* GetAsTypeAtIndex(unsigned i) {return mAsTypes.ValueAtIndex(i);} + void SetAsTypeAtIndex(unsigned i, AsTypeNode* n) {*(mAsTypes.RefAtIndex(i)) = n;} + + virtual void Dump(unsigned){} + virtual void D(){Dump(0); std::cout << std::endl;} void DumpIndentation(unsigned); void DumpLabel(unsigned); @@ -112,15 +181,171 @@ public: class PackageNode : public TreeNode { private: + TreeNode *mPackage; public: - PackageNode(){mKind = NK_Package;} - PackageNode(const char *s) {mKind = NK_Package; mName = s;} + PackageNode() : TreeNode(NK_Package) {} + PackageNode(unsigned id) : TreeNode(NK_Package, id) {} ~PackageNode() {} - void SetName(const char *s) {mName = s;} + TreeNode* GetPackage() {return mPackage;} + void SetPackage(TreeNode *t) {mPackage = t;} + + void SetName(unsigned id) {mStrIdx = id;} + void Dump(unsigned indent); +}; + +////////////////////////////////////////////////////////////////////////// +// XXportAsPair Node +// In JS, the import or export support: xxport {x as y} +// Its kind of like a mapping of internal name to extern name. +// +// Regarding 'default' and 'everything' (*), there are some rules of saving +// in the XXportAsPairNode. First, let's look at the variaties of combinations +// of default and *. +// +// 1) import * as x +// mIsEverything = true +// mAfter = x +// 2) import default as x +// 3) export x as default +// 4) export * +// mIsEverything = true +// mAfter = nullptr, mBefore = nullptr +// 5) export default declaration +// 6) export = x // This exports a single object. +// mIsSingle = true +// mBefore = x +// 7) import x = require("y") // The counterpart of export = xxx +// mIsSingle = true; +// mBefore = y +// mAfter = x +// For all these cases, we set mIsDefault or mIsEverything, and save the +// possible 'x' to mBefore. +////////////////////////////////////////////////////////////////////////// + +class XXportAsPairNode : public TreeNode { +private: + bool mIsDefault; // import or export 'default' + bool mIsEverything; // import or export '*', which is everything + bool mIsSingle; // export = xxx + bool mIsRef; // export is reference, otherwise is copy + bool mAsNamespace; // export as namespace xxx; + TreeNode *mBefore; // In usual cases, name before 'as' + TreeNode *mAfter; // In usual cases, name after 'as' + +public: + XXportAsPairNode() : TreeNode(NK_XXportAsPair), + mIsDefault(false), mIsEverything(false), mIsSingle(false), mIsRef(true), mAsNamespace(false), + mBefore(nullptr), mAfter(nullptr) {} + ~XXportAsPairNode() {} + + bool IsDefault() {return mIsDefault;} + void SetIsDefault(bool b = true) {mIsDefault = b;} + + bool IsEverything() {return mIsEverything;} + void SetIsEverything(bool b = true) {mIsEverything = b;} + + bool IsSingle() {return mIsSingle;} + void SetIsSingle(bool b = true) {mIsSingle = b;} + + bool IsRef() {return mIsRef;} + void SetIsRef(bool b = true) {mIsRef = b;} + + bool GetAsNamespace() {return mAsNamespace;} + void SetAsNamespace(bool b = true) {mAsNamespace = b;} + + TreeNode* GetBefore() {return mBefore;} + void SetBefore(TreeNode *t) {mBefore = t; SETPARENT(t);} + + TreeNode* GetAfter() {return mAfter;} + void SetAfter(TreeNode *t) {mAfter = t; SETPARENT(t);} + + void Dump(unsigned indent); +}; + +////////////////////////////////////////////////////////////////////////// +// Declare Nodes +// C/C++ extern decl, +// Typescript declare. +// +// A declare node could declare more than one declarations, like +// declare global { +// interface a {} +// var b; +// .. +// } +////////////////////////////////////////////////////////////////////////// + +class DeclareNode : public TreeNode { +private: + SmallVector mDecls; + SmallVector mAttrs; + bool mIsGlobal;// +public: + DeclareNode() : TreeNode(NK_Declare), mIsGlobal(false) {} + ~DeclareNode(){mAttrs.Release(); mDecls.Release();} + + bool IsGlobal() {return mIsGlobal;} + void SetIsGlobal(bool b = true) {mIsGlobal = b;} + + // Attributes related + unsigned GetAttrsNum() const {return mAttrs.GetNum();} + void AddAttr(AttrId a) {mAttrs.PushBack(a);} + AttrId GetAttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + void SetAttrAtIndex(unsigned i, AttrId n) {*(mAttrs.RefAtIndex(i)) = n;} + + // Declares + unsigned GetDeclsNum() const {return mDecls.GetNum();} + void AddDecl(TreeNode*); + TreeNode* GetDeclAtIndex(unsigned i) {return mDecls.ValueAtIndex(i);} + void SetDeclAtIndex(unsigned i, TreeNode *n) {*(mDecls.RefAtIndex(i)) = n;} + + void Dump(unsigned indent); +}; + +////////////////////////////////////////////////////////////////////////// +// Export Nodes +// export first comes from Javascript. +// +// If Export only exports a decl or a statement, it will be saved in +// mPairs as the only pair. This is the same in ImportNode. +////////////////////////////////////////////////////////////////////////// + +class ExportNode : public TreeNode { +private: + TreeNode *mTarget; // the exported package in Java or module in JS + SmallVector mPairs; + SmallVector mAnnotations; //annotation or pragma + bool mIsExportType; + +public: + ExportNode() : TreeNode(NK_Export), mTarget(nullptr), mIsExportType(false) {} + ~ExportNode(){} + + void SetTarget(TreeNode *t) {mTarget = t; SETPARENT(t);} + TreeNode* GetTarget() {return mTarget;} + + bool IsExportType() {return mIsExportType;} + void SetIsExportType(bool b = true) {mIsExportType = b;} + + unsigned GetPairsNum() {return mPairs.GetNum();} + XXportAsPairNode* GetPair(unsigned i) {return mPairs.ValueAtIndex(i);} + void SetPair(unsigned i, XXportAsPairNode* n) {*(mPairs.RefAtIndex(i)) = n; SETPARENT(n);} + void AddPair(TreeNode *p); + void AddDefaultPair(TreeNode *p); + void AddSinglePair(TreeNode *before, TreeNode *after); + + // Annotation/Pragma related + unsigned GetAnnotationsNum() {return mAnnotations.GetNum();} + void AddAnnotation(AnnotationNode *n) {mAnnotations.PushBack(n);} + AnnotationNode* GetAnnotationAtIndex(unsigned i) {return mAnnotations.ValueAtIndex(i);} + void SetAnnotationAtIndex(unsigned i, AnnotationNode* n) {*(mAnnotations.RefAtIndex(i)) = n;} + void ClearAnnotation() {mAnnotations.Clear();} + void Dump(unsigned indent); }; + ////////////////////////////////////////////////////////////////////////// // Import Node // Java import, c/c++ include, are the same scenarios. We just save the @@ -129,7 +354,9 @@ public: // We also borrow the idea of system directory vs. local directory from c/c++. ////////////////////////////////////////////////////////////////////////// +// The property is useful in Java right now. Javascript use the XXportAsPair. enum ImportProperty { + ImpNone = 0, ImpType = 1, // Java like, import type ImpStatic = 1 << 1, // Java like, import static field. // If we don't specify the data type of imported, it's @@ -141,15 +368,33 @@ enum ImportProperty { ImpSystem = 1 << 5 }; +inline ImportProperty& operator|=(ImportProperty& t, ImportProperty p) { + return t = static_cast(static_cast(t) | static_cast(p)); +} + +inline ImportProperty operator&(ImportProperty p, ImportProperty q) { + return static_cast(static_cast(p) & static_cast(q)); +} + class ImportNode : public TreeNode { private: - unsigned mProperty; + ImportProperty mProperty; + + // Solely for javascript right now. + // In many languages, mPairs could be empty. In such case it import the whole module. + SmallVector mPairs; + + // the imported target, a package in Java, or a module in JS + TreeNode *mTarget; + public: - ImportNode() {mName = NULL; mProperty = 0; mKind = NK_Import;} - ~ImportNode(){} + ImportNode() : TreeNode(NK_Import), mProperty(ImpNone), mTarget(nullptr) {} + ~ImportNode(){mPairs.Release();} - void SetName(const char *s) {mName = s;} - const char* GetName() {return mName;} + void SetProperty(ImportProperty p) {mProperty = p;} + ImportProperty GetProperty() {return mProperty;} + void SetTarget(TreeNode *n) {mTarget = n; SETPARENT(n);} + TreeNode* GetTarget() {return mTarget;} void SetImportType() {mProperty |= ImpType;} void SetImportStatic() {mProperty |= ImpStatic;} @@ -164,6 +409,13 @@ public: bool IsImportLocal() {return mProperty & ImpLocal;} bool IsImportSystem() {return mProperty & ImpSystem;} + unsigned GetPairsNum() {return mPairs.GetNum();} + XXportAsPairNode* GetPair(unsigned i) {return mPairs.ValueAtIndex(i);} + void SetPair(unsigned i, XXportAsPairNode* n) {*(mPairs.RefAtIndex(i)) = n;} + void AddPair(TreeNode *p); + void AddDefaultPair(TreeNode *p); + void AddSinglePair(TreeNode *before, TreeNode *after); + void Dump(unsigned indent); }; @@ -195,13 +447,13 @@ private: OprId mOprId; TreeNode *mOpnd; public: - UnaOperatorNode(OprId id) : mOprId(id), mOpnd(NULL), mIsPost(false) - {mKind = NK_UnaOperator;} - UnaOperatorNode() : mOpnd(NULL), mIsPost(false) {mKind = NK_UnaOperator;} + UnaOperatorNode(OprId id) : TreeNode(NK_UnaOperator), + mOprId(id), mOpnd(nullptr), mIsPost(false) {} + UnaOperatorNode() : UnaOperatorNode(OPR_NA) {} ~UnaOperatorNode() {} void SetIsPost(bool b) {mIsPost = b;} - void SetOpnd(TreeNode* t) {mOpnd = t; t->SetParent(this);} + void SetOpnd(TreeNode* t) {mOpnd = t; SETPARENT(t);} void SetOprId(OprId o) {mOprId = o;} bool IsPost() {return mIsPost;} @@ -214,30 +466,143 @@ public: }; class BinOperatorNode : public TreeNode { -public: +private: OprId mOprId; TreeNode *mOpndA; TreeNode *mOpndB; public: - BinOperatorNode(OprId id) : mOprId(id) {mKind = NK_BinOperator;} - BinOperatorNode() {mKind = NK_BinOperator;} + BinOperatorNode(OprId id) : TreeNode(NK_BinOperator), mOprId(id) {} + BinOperatorNode() : BinOperatorNode(OPR_NA) {} ~BinOperatorNode() {} + OprId GetOprId() {return mOprId;} + TreeNode* GetOpndA() {return mOpndA;} + TreeNode* GetOpndB() {return mOpndB;} + void SetOprId(OprId o) {mOprId = o;} + void SetOpndA(TreeNode* t) {mOpndA = t; SETPARENT(t);} + void SetOpndB(TreeNode* t) {mOpndB = t; SETPARENT(t);} + void ReplaceChild(TreeNode*, TreeNode*); void Dump(unsigned); }; +// TerOperatorNode is for an expression like +// a > b ? c : d class TerOperatorNode : public TreeNode { -public: - OprId mOprId; +private: TreeNode *mOpndA; TreeNode *mOpndB; TreeNode *mOpndC; public: - TerOperatorNode(OprId id) : mOprId(id) {mKind = NK_TerOperator;} - TerOperatorNode() {mKind = NK_TerOperator;} + TerOperatorNode() : TreeNode(NK_TerOperator) {} ~TerOperatorNode() {} + TreeNode* GetOpndA() {return mOpndA;} + TreeNode* GetOpndB() {return mOpndB;} + TreeNode* GetOpndC() {return mOpndC;} + void SetOpndA(TreeNode* t) {mOpndA = t; SETPARENT(t);} + void SetOpndB(TreeNode* t) {mOpndB = t; SETPARENT(t);} + void SetOpndC(TreeNode* t) {mOpndC = t; SETPARENT(t);} + + void Dump(unsigned); +}; + +////////////////////////////////////////////////////////////////////////// +// TypeAliasNode +// The syntax is type alias in Typescript, typedef in c/c++ +////////////////////////////////////////////////////////////////////////// + +class TypeAliasNode : public TreeNode { +private: + UserTypeNode *mId; + TreeNode *mAlias; +public: + TypeAliasNode() : TreeNode(NK_TypeAlias), mId(nullptr), mAlias(nullptr){} + ~TypeAliasNode() {} + + UserTypeNode* GetId() {return mId;} + void SetId(UserTypeNode *id); + + TreeNode* GetAlias() {return mAlias;} + void SetAlias(TreeNode *n); + + void Dump(unsigned); +}; + +////////////////////////////////////////////////////////////////////////// +// ConditionalType +// The syntax is n Typescript, +// type-a extends type-b ? type-c : type-d +////////////////////////////////////////////////////////////////////////// + +class ConditionalTypeNode : public TreeNode { +private: + TreeNode *mTypeA; + TreeNode *mTypeB; + TreeNode *mTypeC; + TreeNode *mTypeD; +public: + ConditionalTypeNode() : TreeNode(NK_ConditionalType), + mTypeA(nullptr), mTypeB(nullptr), mTypeC(nullptr), mTypeD(nullptr){} + ~ConditionalTypeNode() {} + + TreeNode* GetTypeA() {return mTypeA;} + TreeNode* GetTypeB() {return mTypeB;} + TreeNode* GetTypeC() {return mTypeC;} + TreeNode* GetTypeD() {return mTypeD;} + void SetTypeA(TreeNode *n) {mTypeA = n; SETPARENT(n);} + void SetTypeB(TreeNode *n) {mTypeB = n; SETPARENT(n);} + void SetTypeC(TreeNode *n) {mTypeC = n; SETPARENT(n);} + void SetTypeD(TreeNode *n) {mTypeD = n; SETPARENT(n);} + + void Dump(unsigned); +}; + +////////////////////////////////////////////////////////////////////////// +// AstType +// The syntax is like: variable as type-a as type-b ... +// It tells what type is the 'variable' +////////////////////////////////////////////////////////////////////////// + +class AsTypeNode : public TreeNode { +private: + TreeNode *mType; +public: + AsTypeNode() : TreeNode(NK_AsType), mType(nullptr) {} + ~AsTypeNode() {} + + TreeNode* GetType() {return mType;} + void SetType(TreeNode *t) {mType = t; SETPARENT(t);} + + void Dump(unsigned indent); +}; + +////////////////////////////////////////////////////////////////////////// +// TypeParameter +////////////////////////////////////////////////////////////////////////// + +class TypeParameterNode : public TreeNode { +private: + TreeNode *mId; // The name of the type parameter + TreeNode *mDefault; // The default value of this type parameter. + // some languages support default value. + TreeNode *mExtends; // The constraint of this type parameter. + // In Typescript, the syntax is like: T + +public: + TypeParameterNode() : TreeNode(NK_TypeParameter), mId(nullptr), mDefault(nullptr), + mExtends(nullptr) {} + ~TypeParameterNode() {} + + TreeNode* GetId() {return mId;} + void SetId(TreeNode* t) {mId = t; SETPARENT(t);} + + TreeNode* GetDefault() {return mDefault;} + void SetDefault(TreeNode* t) {mDefault = t; SETPARENT(t);} + + TreeNode* GetExtends() {return mExtends;} + void SetExtends(TreeNode* t) {mExtends = t; SETPARENT(t);} + void Dump(unsigned); }; @@ -255,27 +620,100 @@ private: TreeNode *mId; // A name could be like Outer.Inner // Hard to give a const char* as name. // So give it an id. - SmallVector mParams; // + // In Typescript, it could be a lambda: + // new (...) => Type + // in which mArgs and mBody are not used. + SmallVector mArgs; // BlockNode *mBody; // When body is not empty, it's an // anonymous class. + SmallVector mAttrs; public: - NewNode() : mId(NULL), mBody(NULL) {mKind = NK_New;} - ~NewNode() {mParams.Release();} + NewNode() : TreeNode(NK_New), mId(nullptr), mBody(nullptr) {} + ~NewNode() {mArgs.Release();} TreeNode* GetId() {return mId;} - void SetId(TreeNode *n) {mId = n;} + void SetId(TreeNode *n) {mId = n; SETPARENT(n);} BlockNode* GetBody() {return mBody;} void SetBody(BlockNode *n) {mBody = n;} - unsigned GetParamsNum() {return mParams.GetNum();} - TreeNode* GetParam(unsigned i) {return mParams.ValueAtIndex(i);} - void AddParam(TreeNode *t) {mParams.PushBack(t);} + unsigned GetArgsNum() {return mArgs.GetNum();} + TreeNode* GetArg(unsigned i) {return mArgs.ValueAtIndex(i);} + void SetArg(unsigned i, TreeNode* n) {*(mArgs.RefAtIndex(i)) = n; SETPARENT(n);} + void AddArg(TreeNode *t) {mArgs.PushBack(t); SETPARENT(t);} + + // Attributes related + unsigned GetAttrsNum() {return mAttrs.GetNum();} + void AddAttr(AttrId a) {mAttrs.PushBack(a);} + AttrId GetAttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + void SetAttrAtIndex(unsigned i, AttrId n) {*(mAttrs.RefAtIndex(i)) = n;} void ReplaceChild(TreeNode *oldone, TreeNode *newone); void Dump(unsigned); }; class DeleteNode : public TreeNode { +private: + TreeNode *mExpr; +public: + DeleteNode() : TreeNode(NK_Delete), mExpr(nullptr) {} + ~DeleteNode(){} + + TreeNode* GetExpr() {return mExpr;} + void SetExpr(TreeNode *t) {mExpr = t; SETPARENT(t);} + + void Dump(unsigned); +}; + +////////////////////////////////////////////////////////////////////////// +// AnnotationNode +// +// Pragma or Annotation are language constructs to help (1) compiler +// (2) runtime (3) other tools, to better analyze or execute the program. +// It doesn't change the program behaviour, but may be improve static +// and/or dynamic analysis and/or performance. +// +// We have a dedicated AnnotationNode here. The program/annotation syntax +// could be complicated, eg. c99 introduce function call like pragma. +// +// The difference between Java annotation and C/c++ pragma is annotation +// is user defined and pragma is compiler/system defined. In another word +// Java annoation has unlimited number while pragmas are limited. +////////////////////////////////////////////////////////////////////////// + +// AnnotationTypeNode defines a new Annotation +class AnnotationTypeNode : public TreeNode { +private: + IdentifierNode *mId; +public: + AnnotationTypeNode() : TreeNode(NK_AnnotationType) {} + ~AnnotationTypeNode() {} + IdentifierNode* GetId() {return mId;} + void SetId(IdentifierNode *n) {mId = n;} + void Dump(unsigned); +}; + +// Annotation/Pragma is complicated, but everything starts from the +// name. So at construction, we will take in the name at first. +// Later we will initialize mType, mExpr based on the 'name' and other +// expression. +class AnnotationNode : public TreeNode { +private: + TreeNode *mId; + AnnotationTypeNode *mType; + SmallVector mArgs; +public: + AnnotationNode() : TreeNode(NK_Annotation), mId(nullptr), mType(nullptr) {} + ~AnnotationNode(){mArgs.Release();} + + TreeNode* GetId() {return mId;} + void SetId(TreeNode *n) {mId = n; SETPARENT(n);} + AnnotationTypeNode* GetType() {return mType;} + void SetType(AnnotationTypeNode *n) {mType = n; SETPARENT(n);} + + unsigned GetArgsNum() {return mArgs.GetNum();} + TreeNode* GetArgAtIndex(unsigned i) {return mArgs.ValueAtIndex(i);} + void SetArgAtIndex(unsigned i, TreeNode* n) {*(mArgs.RefAtIndex(i)) = n;} + void AddArg(TreeNode *n){mArgs.PushBack(n); SETPARENT(n);} }; ////////////////////////////////////////////////////////////////////////// @@ -307,16 +745,13 @@ class DimensionNode : public TreeNode { private: SmallVector mDimensions; public: - DimensionNode() {mKind = NK_Dimension;} + DimensionNode() : TreeNode(NK_Dimension) {} ~DimensionNode(){Release();} - unsigned GetDimsNum() {return mDimensions.GetNum();} - unsigned GetNthDim(unsigned n) {return mDimensions.ValueAtIndex(n);} // 0 means unspecified. - void SetNthDim(unsigned n, unsigned i) { - unsigned *addr = mDimensions.RefAtIndex(n); - *addr = i; - } - void AddDim(unsigned i = 0) {mDimensions.PushBack(i);} + unsigned GetDimensionsNum() {return mDimensions.GetNum();} + unsigned GetDimension(unsigned i) {return mDimensions.ValueAtIndex(i);} // 0 means unspecified. + void SetDimension(unsigned i, unsigned n) {*(mDimensions.RefAtIndex(i)) = n;} + void AddDimension(unsigned i = 0) {mDimensions.PushBack(i);} void Merge(const TreeNode*); void Release() {mDimensions.Release();} @@ -331,77 +766,84 @@ private: TreeNode *mType; // PrimTypeNode or UserTypeNode TreeNode *mInit; // Init value DimensionNode *mDims; + + SmallVector mAnnotations; //annotation or pragma + public: - IdentifierNode(const char *s) : mType(NULL), mInit(NULL), mDims(NULL){ - mKind = NK_Identifier; - SetName(s); } - IdentifierNode(const char *s, TreeNode *t) : mType(t), mInit(NULL), mDims(NULL) { - mKind = NK_Identifier; - SetName(s);} - ~IdentifierNode(){} + IdentifierNode(unsigned id, TreeNode *t) : TreeNode(NK_Identifier, id), + mType(t), mInit(nullptr), mDims(nullptr) {} + IdentifierNode(unsigned id) : IdentifierNode(id, nullptr) {} + IdentifierNode() : IdentifierNode(0, nullptr) {} + ~IdentifierNode(){Release();} TreeNode* GetType() {return mType;} TreeNode* GetInit() {return mInit;} + DimensionNode* GetDims() {return mDims;} - void SetType(TreeNode *t) {mType = t;} - void SetInit(TreeNode *t) {mInit = t;} - void SetDims(DimensionNode *t) {mDims = t;} + void SetType(TreeNode *t) {mType = t; SETPARENT(t);} + void SetInit(TreeNode *t) {mInit = t; SETPARENT(t);} + void ClearInit() {mInit = nullptr;} + void SetDims(DimensionNode *t) {mDims = t; SETPARENT(t);} - unsigned GetDimsNum() {return mDims->GetDimsNum();} + unsigned GetDimsNum() {return mDims->GetDimensionsNum();} + unsigned GetDim(unsigned n) {return mDims->GetDimension(n);} // 0 means unspecified. bool IsArray() {return mDims && GetDimsNum() > 0;} - unsigned AddDim(unsigned i = 0){mDims->AddDim(i);} // 0 means unspecified - unsigned GetNthNum(unsigned n) {return mDims->GetNthDim(n);} // 0 means unspecified. - void SetNthNum(unsigned n, unsigned i) {mDims->SetNthDim(n, i);} + void AddDim(unsigned i = 0){mDims->AddDimension(i);} // 0 means unspecified + unsigned GetNthNum(unsigned n) {return mDims->GetDimension(n);} // 0 means unspecified. + void SetNthNum(unsigned n, unsigned i) {mDims->SetDimension(n, i);} // Attributes related - unsigned GetAttrsNum() const {return mAttrs.GetNum();} - void AddAttr(AttrId a) {mAttrs.PushBack(a);} - AttrId AttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + unsigned GetAttrsNum() const {return mAttrs.GetNum();} + void AddAttr(AttrId a) {mAttrs.PushBack(a);} + AttrId GetAttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + void SetAttrAtIndex(unsigned i, AttrId n) {*(mAttrs.RefAtIndex(i)) = n;} + + // Annotation/Pragma related + unsigned GetAnnotationsNum() {return mAnnotations.GetNum();} + void AddAnnotation(AnnotationNode *n) {mAnnotations.PushBack(n); SETPARENT(n);} + AnnotationNode* GetAnnotationAtIndex(unsigned i) {return mAnnotations.ValueAtIndex(i);} + void SetAnnotationAtIndex(unsigned i, AnnotationNode* n) {*(mAnnotations.RefAtIndex(i)) = n;} - void Release() { if (mDims) mDims->Release();} + void Release(); void Dump(unsigned); }; ////////////////////////////////////////////////////////////////////////// -// AnnotationNode -// -// Pragma or Annotation are language constructs to help (1) compiler -// (2) runtime (3) other tools, to better analyze or execute the program. -// It doesn't change the program behaviour, but may be improve static -// and/or dynamic analysis and/or performance. -// -// We have a dedicated AnnotationNode here. The program/annotation syntax -// could be complicated, eg. c99 introduce function call like pragma. -// -// The difference between Java annotation and C/c++ pragma is annotation -// is user defined and pragma is compiler/system defined. In another word -// Java annoation has unlimited number while pragmas are limited. +// DeclNode +// A DeclNode defines one single variable or a VarList. +// The type info and init expr are both inside the IdentifierNode. +// DeclNode only tells this is a declaration. ////////////////////////////////////////////////////////////////////////// -// AnnotationTypeNode defines a new Annotation -class AnnotationTypeNode : public TreeNode { -private: - IdentifierNode *mId; -public: - void SetId(IdentifierNode *n) {mId = n;} - void Dump(unsigned); +// special property of Javascript +enum DeclProp { + JS_Var, + JS_Let, + JS_Const, + DP_NA }; -// Annotation/Pragma is complicated, but everything starts from the -// name. So at construction, we will take in the name at first. -// Later we will initialize mType, mExpr based on the 'name' and other -// expression. -class AnnotationNode : public TreeNode { +class DeclNode : public TreeNode { private: - IdentifierNode *mId; - AnnotationTypeNode *mType; - TreeNode *mExpr; + TreeNode *mVar; + TreeNode *mInit; // Init value + DeclProp mProp; public: - AnnotationNode() : mId(NULL), mType(NULL), mExpr(NULL) { - mKind = NK_Annotation;} - ~AnnotationNode(){} + DeclNode(TreeNode *t) : TreeNode(NK_Decl), + mVar(t), mInit(nullptr), mProp(DP_NA) {SETPARENT(t);} + DeclNode() : DeclNode(nullptr) {} + ~DeclNode(){} - void SetId(IdentifierNode *n) {mId = n;} + TreeNode* GetVar() {return mVar;} + TreeNode* GetInit() {return mInit;} + + void SetVar(TreeNode *t) {mVar = t; SETPARENT(t);} + void SetInit(TreeNode *t) {mInit = t; SETPARENT(t);} + + DeclProp GetProp() {return mProp;} + void SetProp(DeclProp p) {mProp = p;} + + void Dump(unsigned); }; ////////////////////////////////////////////////////////////////////////// @@ -414,16 +856,16 @@ private: TreeNode *mDestType; TreeNode *mExpr; public: - CastNode() : mDestType(NULL), mExpr(NULL) {mKind = NK_Cast;} + CastNode() : TreeNode(NK_Cast), mDestType(nullptr), mExpr(nullptr) {} ~CastNode(){} TreeNode* GetDestType() {return mDestType;} void SetDestType(TreeNode *t) {mDestType = t;} TreeNode* GetExpr() {return mExpr;} - void SetExpr(TreeNode *t) {mExpr = t;} + void SetExpr(TreeNode *t) {mExpr = t; SETPARENT(t);} - const char* GetName(); + const char* GetDumpName(); void Dump(unsigned); }; @@ -443,44 +885,328 @@ class ParenthesisNode : public TreeNode { private: TreeNode *mExpr; public: - ParenthesisNode() : mExpr(NULL) {mKind = NK_Parenthesis;} + ParenthesisNode() : TreeNode(NK_Parenthesis), mExpr(nullptr) {} ~ParenthesisNode(){} - TreeNode* GetExpr() {return mExpr;} - void SetExpr(TreeNode *t) {mExpr = t; t->SetParent(this);} + TreeNode* GetExpr() {return mExpr;} + void SetExpr(TreeNode *t) {mExpr = t; SETPARENT(t);} + + void Dump(unsigned); +}; + +////////////////////////////////////////////////////////////////////////// +// FieldNode +// This is used for field reference. The field could be a member field or +// a member function. +////////////////////////////////////////////////////////////////////////// + +class FieldNode : public TreeNode { +private: + TreeNode *mUpper; // The upper enclosing structure + TreeNode *mField; +public: + FieldNode() : TreeNode(NK_Field), mField(nullptr), mUpper(nullptr) {} + ~FieldNode(){} + + TreeNode* GetField() {return mField;} + void SetField(TreeNode *f) {mField = f; SETPARENT(f);} + + TreeNode *GetUpper() {return mUpper;} + void SetUpper(TreeNode *n) { + TreeNode *up = n; + while (up->IsParenthesis()) { + ParenthesisNode *pn = (ParenthesisNode*)up; + up = pn->GetExpr(); + } + mUpper = up; + SETPARENT(up); + } + + void Dump(unsigned); +}; + +////////////////////////////////////////////////////////////////////////// +// Array Related Nodes +// ArrayElementNode, ArrayLiteralNode. +////////////////////////////////////////////////////////////////////////// + +// Array element is a[b][c]. +class ArrayElementNode : public TreeNode { +private: + TreeNode *mArray; + SmallVector mExprs; // index expressions. +public: + ArrayElementNode() : TreeNode(NK_ArrayElement), mArray(nullptr) {} + ~ArrayElementNode() {Release();} + + TreeNode* GetArray() {return mArray;} + void SetArray(TreeNode *n) {mArray = n; SETPARENT(n);} + + unsigned GetExprsNum() {return mExprs.GetNum();} + TreeNode* GetExprAtIndex(unsigned i) {return mExprs.ValueAtIndex(i);} + void SetExprAtIndex(unsigned i, TreeNode* n) {*(mExprs.RefAtIndex(i)) = n; SETPARENT(n);} + void AddExpr(TreeNode *n){mExprs.PushBack(n); SETPARENT(n);} + + void Release() {mExprs.Release();} + void Dump(unsigned); +}; + + +// Array literal is [1, 2 , 0, -4]. It's an arrya of literals. +// It could also be multi-dim array literal like [[1,2],[2,3]] +class ArrayLiteralNode : public TreeNode { +private: + SmallVector mLiterals; +public: + ArrayLiteralNode() : TreeNode(NK_ArrayLiteral) {} + ~ArrayLiteralNode() {Release();} + + unsigned GetLiteralsNum() {return mLiterals.GetNum();} + TreeNode* GetLiteral(unsigned i) {return mLiterals.ValueAtIndex(i);} + void SetLiteral(unsigned i, TreeNode* n) {*(mLiterals.RefAtIndex(i)) = n; SETPARENT(n);} + void AddLiteral(TreeNode *n){mLiterals.PushBack(n); SETPARENT(n);} + + void Release() {mLiterals.Release();} + void Dump(unsigned); +}; + +////////////////////////////////////////////////////////////////////////// +// BindingPattern +// It's used in Destructuring scenarios. It comes from Javascript. +// It takes out elements from structs or arrays and form a new one. +// It may bind elements to some new variables. I believe this is the reason +// it's called BindingXXX +////////////////////////////////////////////////////////////////////////// + +class BindingElementNode : public TreeNode { +private: + TreeNode *mVariable; // The new variable to bind element to + TreeNode *mElement; // the elements in the source struct or array +public: + BindingElementNode() : TreeNode(NK_BindingElement), + mVariable(nullptr), mElement(nullptr) {} + ~BindingElementNode() {} + + TreeNode* GetVariable() {return mVariable;} + void SetVariable(TreeNode* n) {mVariable = n; SETPARENT(n);} + TreeNode* GetElement() {return mElement;} + void SetElement(TreeNode* n) {mElement = n; SETPARENT(n);} + + void Dump(unsigned); +}; + +enum BindPattProp { + BPP_ArrayBinding, + BPP_ObjectBinding, + BPP_NA +}; + +class BindingPatternNode : public TreeNode { +private: + BindPattProp mProp; + SmallVector mElements; // mostly BindingElementNode, also could be + // a nested BindingPatternNode. + TreeNode *mType; // The type + TreeNode *mInit; // An initializer +public: + BindingPatternNode() : + TreeNode(NK_BindingPattern), mInit(nullptr), mType(nullptr), mProp(BPP_NA) {} + ~BindingPatternNode() {Release();} + + BindPattProp GetProp() {return mProp;} + void SetProp(BindPattProp n) {mProp = n;} + + unsigned GetElementsNum() {return mElements.GetNum();} + TreeNode* GetElement(unsigned i) {return mElements.ValueAtIndex(i);} + void SetElement(unsigned i, TreeNode* n) {*(mElements.RefAtIndex(i)) = n;} + void AddElement(TreeNode *n); + + TreeNode* GetType() {return mType;} + void SetType(TreeNode* n) {mType = n; SETPARENT(n);} + TreeNode* GetInit() {return mInit;} + void SetInit(TreeNode* n) {mInit = n; SETPARENT(n);} + + void Release() {mElements.Release();} + void Dump(unsigned); +}; + + +////////////////////////////////////////////////////////////////////////// +// Struct Node +// This is first coming from C struct. Typescript 'interface' has the +// similar structure. +// +// Index signature of Typescript make it complicated. Here is an example. +// interface Foo{ +// [key: string]: number; +// } +// +// let bar: Foo = {}; +// bar['key1'] = 1; +// +////////////////////////////////////////////////////////////////////////// + +enum StructProp { + SProp_CStruct, + SProp_TSInterface, + SProp_TSEnum, + SProp_NA +}; + +class NumIndexSigNode : public TreeNode{ +public: + TreeNode *mKey; + TreeNode *mDataType; + + void SetKey(TreeNode *t) {mKey = t;} + TreeNode* GetKey() {return mKey;} + void SetDataType(TreeNode *t) {mDataType = t;} + TreeNode* GetDataType() {return mDataType;} + + NumIndexSigNode() : TreeNode(NK_NumIndexSig), mDataType(nullptr), mKey(nullptr) {} + ~NumIndexSigNode(){} + void Dump(unsigned); +}; + +class StrIndexSigNode : public TreeNode{ +public: + TreeNode *mKey; + TreeNode *mDataType; + + void SetKey(TreeNode *t) {mKey = t; SETPARENT(t);} + TreeNode* GetKey() {return mKey;} + void SetDataType(TreeNode *t) {mDataType = t; SETPARENT(t);} + TreeNode* GetDataType() {return mDataType;} + + StrIndexSigNode() : TreeNode(NK_StrIndexSig), mDataType(nullptr), mKey(nullptr) {} + ~StrIndexSigNode(){} + void Dump(unsigned); +}; + +// C++ struct or Typescript interface. +// The methods in Typescript interface has no function body. +class StructNode : public TreeNode { +private: + StructProp mProp; + IdentifierNode *mStructId; + SmallVector mTypeParams; + SmallVector mFields; + SmallVector mMethods; + SmallVector mSupers; + + // These are for 'number' or 'string' index data type + NumIndexSigNode *mNumIndexSig; + StrIndexSigNode *mStrIndexSig; + +public: + StructNode(IdentifierNode *n) : TreeNode(NK_Struct), mStructId(n), mProp(SProp_NA), + mNumIndexSig(nullptr), mStrIndexSig(nullptr) {SETPARENT(n);} + StructNode() : StructNode(nullptr) {} + ~StructNode() {Release();} + + StructProp GetProp() {return mProp;} + IdentifierNode* GetStructId() {return mStructId;} + void SetProp(StructProp p) {mProp = p;} + void SetStructId(IdentifierNode *n) {mStructId = n; SETPARENT(n);} + + NumIndexSigNode* GetNumIndexSig() {return mNumIndexSig;} + StrIndexSigNode* GetStrIndexSig() {return mStrIndexSig;} + void SetNumIndexSig(NumIndexSigNode *t) {mNumIndexSig = t;} + void SetStrIndexSig(StrIndexSigNode *t) {mStrIndexSig = t;} + + // TypeParameter + unsigned GetTypeParamsNum() {return mTypeParams.GetNum();} + void AddTypeParam(TreeNode *n); + TypeParameterNode* GetTypeParamAtIndex(unsigned i) {return mTypeParams.ValueAtIndex(i);} + void SetTypeParamAtIndex(unsigned i, TypeParameterNode* n) {*(mTypeParams.RefAtIndex(i)) = n;} + + unsigned GetFieldsNum() {return mFields.GetNum();} + TreeNode* GetField(unsigned i) {return mFields.ValueAtIndex(i);} + void SetField(unsigned i, TreeNode* n) {*(mFields.RefAtIndex(i)) = n; SETPARENT(n);} + void AddField(TreeNode *n) {mFields.PushBack(n); SETPARENT(n);} + + unsigned GetSupersNum() {return mSupers.GetNum();} + TreeNode* GetSuper(unsigned i) {return mSupers.ValueAtIndex(i);} + void SetSuper(unsigned i, TreeNode* n) {*(mSupers.RefAtIndex(i)) = n;} + void AddSuper(TreeNode *n); + + unsigned GetMethodsNum() {return mMethods.GetNum();} + FunctionNode* GetMethod(unsigned i) {return mMethods.ValueAtIndex(i);} + void SetMethod(unsigned i, FunctionNode* n) {*(mMethods.RefAtIndex(i)) = n;} + void AddMethod(FunctionNode *n) {mMethods.PushBack(n);} + + void AddChild(TreeNode *); + + void Release() {mFields.Release(); mMethods.Release(); mSupers.Release(); mTypeParams.Release();} + void Dump(unsigned); +}; + +// We define StructLiteral for C/C++ struct literal, TS/JS object literal. +// It contains a list of duple +// +// In Javascript, the GetAccessor/SetAccessor makes it complicated. +// We save the XetAccessor as a field literal with fieldname being func +// name and literal being function node itself. + +// mFieldName could be nullptr, like {3, 4} or {a, b}, 3, 4, a and b are literals without +// a name. but mLiteral may not be nullptr. +class FieldLiteralNode : public TreeNode{ +public: + TreeNode *mFieldName; // Generally a field is an identifier. However, in JS/TS + // it could be a literal string or numeric. + TreeNode *mLiteral; + + void SetFieldName(TreeNode *id) {mFieldName = id; SETPARENT(id);} + void SetLiteral(TreeNode *id) {mLiteral = id; SETPARENT(id);} + + TreeNode* GetFieldName() {return mFieldName;} + TreeNode* GetLiteral() {return mLiteral;} + + FieldLiteralNode() : mFieldName(nullptr), TreeNode(NK_FieldLiteral) {} + ~FieldLiteralNode(){} +}; + +class StructLiteralNode : public TreeNode { +private: + SmallVector mFields; +public: + StructLiteralNode() : TreeNode(NK_StructLiteral) {} + ~StructLiteralNode(){Release();} + + unsigned GetFieldsNum() {return mFields.GetNum();} + FieldLiteralNode* GetField(unsigned i) {return mFields.ValueAtIndex(i);} + void SetField(unsigned i, FieldLiteralNode* n) {*(mFields.RefAtIndex(i)) = n; SETPARENT(n);} + void AddField(TreeNode *n); void Dump(unsigned); }; ////////////////////////////////////////////////////////////////////////// -// FieldNode -// This is used for field reference. It includes both member field and -// member function. +// Namespace Node +// Typescript namespace has only a list of children which could be any +// kind of declaration or statement. So I simply keep their original +// nodes. ////////////////////////////////////////////////////////////////////////// -class FieldNode : public TreeNode { +class NamespaceNode : public TreeNode { private: - TreeNode *mUpper; // The upper enclosing structure - IdentifierNode *mField; + SmallVector mElements; + TreeNode *mId; // the name of namespace public: - FieldNode() : TreeNode(), mField(NULL), mUpper(NULL) {mKind = NK_Field;} - ~FieldNode(){} + NamespaceNode() : TreeNode(NK_Namespace), mId(nullptr) {} + ~NamespaceNode() {Release();} - void Init(); + void SetId(TreeNode *id) {mId = id; SETPARENT(id);} + TreeNode* GetId() {return mId;} - IdentifierNode* GetField() {return mField;} - void SetField(IdentifierNode *f) {mField = f;} + unsigned GetElementsNum() {return mElements.GetNum();} + TreeNode* GetElementAtIndex(unsigned i) {return mElements.ValueAtIndex(i);} + void SetElementAtIndex(unsigned i, TreeNode* n) {*(mElements.RefAtIndex(i)) = n;} + void AddElement(TreeNode* n) {mElements.PushBack(n); SETPARENT(n);} - TreeNode *GetUpper() {return mUpper;} - void SetUpper(TreeNode *n) { - TreeNode *up = n; - while (up->IsParenthesis()) { - ParenthesisNode *pn = (ParenthesisNode*)up; - up = pn->GetExpr(); - } - mUpper = up; - } + void AddBody(TreeNode *); + void Release() {mElements.Release();} void Dump(unsigned); }; @@ -494,11 +1220,12 @@ class VarListNode : public TreeNode { private: SmallVector mVars; public: - VarListNode() {mKind = NK_VarList;} - ~VarListNode() {} + VarListNode() : TreeNode(NK_VarList) {} + ~VarListNode() {Release();} - unsigned GetNum() {return mVars.GetNum();} - IdentifierNode* VarAtIndex(unsigned i) {return mVars.ValueAtIndex(i);} + unsigned GetVarsNum() {return mVars.GetNum();} + IdentifierNode* GetVarAtIndex(unsigned i) {return mVars.ValueAtIndex(i);} + void SetVarAtIndex(unsigned i, IdentifierNode* n) {*(mVars.RefAtIndex(i)) = n;} void AddVar(IdentifierNode *n); void Merge(TreeNode*); @@ -516,11 +1243,12 @@ class ExprListNode : public TreeNode { private: SmallVector mExprs; public: - ExprListNode() {mKind = NK_ExprList;} + ExprListNode() : TreeNode(NK_ExprList) {} ~ExprListNode() {} - unsigned GetNum() {return mExprs.GetNum();} - TreeNode* ExprAtIndex(unsigned i) {return mExprs.ValueAtIndex(i);} + unsigned GetExprsNum() {return mExprs.GetNum();} + TreeNode* GetExprAtIndex(unsigned i) {return mExprs.ValueAtIndex(i);} + void SetExprAtIndex(unsigned i, TreeNode* n) {*(mExprs.RefAtIndex(i)) = n;} void AddExpr(TreeNode *n) {mExprs.PushBack(n);} void Merge(TreeNode*); @@ -528,23 +1256,182 @@ public: void Dump(unsigned); }; +////////////////////////////////////////////////////////////////////////// +// TemplateLiteral Nodes +// TemplateLiteral node is created from the corresponding TempLit Token, +// copying the raw mStrings from token. +// Later on, call parser special API to create AST nodes for the patterns. +// After that, only mStrings and mTrees are used. +////////////////////////////////////////////////////////////////////////// + +class TemplateLiteralNode : public TreeNode { +private: + // mStrings save pairs. + SmallVector mStrings; + + // It's tree nodes of pairs of . So it would be pairs + // of , For any missing element, a nullptr is saved + // in its position. + // Even index elements are for formats, Odd index elements are for placeholder. + SmallVector mTrees; + +public: + TemplateLiteralNode() : TreeNode(NK_TemplateLiteral) {} + ~TemplateLiteralNode(){mStrings.Release(); mTrees.Release();} + + unsigned GetStringsNum() {return mStrings.GetNum();} + const char* GetStringAtIndex(unsigned i) {return mStrings.ValueAtIndex(i);} + void SetStringAtIndex(unsigned i, const char* n) {*(mStrings.RefAtIndex(i)) = n;} + void AddString(const char *n) {mStrings.PushBack(n);} + + unsigned GetTreesNum() {return mTrees.GetNum();} + TreeNode* GetTreeAtIndex(unsigned i) {return mTrees.ValueAtIndex(i);} + void SetTreeAtIndex(unsigned i, TreeNode *n) {*(mTrees.RefAtIndex(i)) = n; SETPARENT(n);} + void AddTree(TreeNode *n) {mTrees.PushBack(n); SETPARENT(n);} + + void Dump(unsigned); +}; + +// We define a global vector for TemplateLiteralNode created after all parsing. +extern SmallVector gTemplateLiteralNodes; + ////////////////////////////////////////////////////////////////////////// // Literal Nodes ////////////////////////////////////////////////////////////////////////// class LiteralNode : public TreeNode { private: - LitData mData; + LitData mData; + + // The regular type information is stored in LitData which is common practice. + // However, in languages like Typescript, it does allow special literals like 'this' + // to have a dedicated type. So here comes 'mType'. + TreeNode *mType; + + // Typescript allows a string literal to be used as an Identifier, so it allows + // an init value. + TreeNode *mInit; + private: void InitName(); public: - LiteralNode(LitData d) : mData(d) { - mKind = NK_Literal; InitName(); - } + LiteralNode(LitData d) : TreeNode(NK_Literal), mData(d), mType(nullptr), mInit(nullptr) {} + LiteralNode() : LiteralNode({.mType = LT_NA, .mData.mInt = 0}) {} ~LiteralNode(){} LitData GetData() {return mData;} + void SetData(LitData d) {mData = d;} + + TreeNode* GetType() {return mType;} + void SetType(TreeNode *t) {mType = t; SETPARENT(t);} + TreeNode* GetInit() {return mInit;} + void SetInit(TreeNode *t) {mInit = t; SETPARENT(t);} + + bool IsThis() {return mData.mType == LT_ThisLiteral;} + + void Dump(unsigned); +}; + +////////////////////////////////////////////////////////////////////////// +// RegExpr Nodes +////////////////////////////////////////////////////////////////////////// + +class RegExprNode : public TreeNode { +private: + RegExprData mData; +public: + RegExprNode() : TreeNode(NK_RegExpr) {mData.mExpr = nullptr; mData.mFlags = nullptr;} + ~RegExprNode(){} + + RegExprData GetData() {return mData;} + void SetData(RegExprData d) {mData = d;} + + void Dump(unsigned); +}; + +////////////////////////////////////////////////////////////////////////// +// ThrowNode +// This is the throw statement. +// In Java some functions throw exception in declaration, and they are +// saved in FunctionNode::mThrows. +////////////////////////////////////////////////////////////////////////// + +class ThrowNode : public TreeNode { +private: + SmallVector mExceptions; +public: + ThrowNode() : TreeNode(NK_Throw) {} + ~ThrowNode(){} + + unsigned GetExceptionsNum() {return mExceptions.GetNum();} + TreeNode* GetExceptionAtIndex(unsigned i) {return mExceptions.ValueAtIndex(i);} + void SetExceptionAtIndex(unsigned i, TreeNode* n) {*(mExceptions.RefAtIndex(i)) = n;} + void AddException(TreeNode *n); + + void Dump(unsigned); +}; + +////////////////////////////////////////////////////////////////////////// +// Try, Catch, Finally +// I can build one single TryNode to contain all the information. However, +// I built all three types of nodes, since some language could have complex +// syntax of catch or finally. +////////////////////////////////////////////////////////////////////////// + +class CatchNode : public TreeNode { +private: + SmallVector mParams; // In Java, this sould be exception node. + BlockNode *mBlock; +public: + CatchNode() : TreeNode(NK_Catch), mBlock(nullptr) {} + ~CatchNode(){} + + BlockNode* GetBlock() {return mBlock;} + void SetBlock(BlockNode *n) {mBlock = n;} + + unsigned GetParamsNum() {return mParams.GetNum();} + TreeNode* GetParamAtIndex(unsigned i) {return mParams.ValueAtIndex(i);} + void SetParamAtIndex(unsigned i, TreeNode* n) {*(mParams.RefAtIndex(i)) = n; SETPARENT(n);} + void AddParam(TreeNode *n); + + void Dump(unsigned); +}; + +class FinallyNode : public TreeNode { +private: + BlockNode *mBlock; +public: + FinallyNode() : TreeNode(NK_Finally), mBlock(nullptr) {} + ~FinallyNode(){} + + BlockNode* GetBlock() {return mBlock;} + void SetBlock(BlockNode *n) {mBlock = n;} + + void Dump(unsigned); +}; + +class TryNode : public TreeNode { +private: + BlockNode *mBlock; + FinallyNode *mFinally; + SmallVector mCatches; // There could be >1 catches. + +public: + TryNode() : TreeNode(NK_Try), mBlock(nullptr), mFinally(nullptr) {} + ~TryNode(){} + + BlockNode* GetBlock() {return mBlock;} + void SetBlock(BlockNode *n) {mBlock = n;} + + FinallyNode* GetFinally() {return mFinally;} + void SetFinally(FinallyNode *n) {mFinally = n;} + + unsigned GetCatchesNum() {return mCatches.GetNum();} + CatchNode* GetCatchAtIndex(unsigned i) {return mCatches.ValueAtIndex(i);} + void SetCatchAtIndex(unsigned i, CatchNode* n) {*(mCatches.RefAtIndex(i)) = n;} + void AddCatch(TreeNode *n); + void Dump(unsigned); }; @@ -557,8 +1444,8 @@ private: // right now I only put a name for it. It could have more properties. IdentifierNode *mException; public: - ExceptionNode() : mException(NULL) {mKind = NK_Exception;} - ExceptionNode(IdentifierNode *inode) : mException(inode) {mKind = NK_Exception;} + ExceptionNode(IdentifierNode *inode) : TreeNode(NK_Exception), mException(inode) {} + ExceptionNode() : ExceptionNode(nullptr) {} ~ExceptionNode(){} IdentifierNode* GetException() {return mException;} @@ -575,10 +1462,26 @@ class ReturnNode : public TreeNode { private: TreeNode *mResult; public: - ReturnNode() : mResult(NULL) {mKind = NK_Return;} + ReturnNode() : TreeNode(NK_Return), mResult(nullptr) {} ~ReturnNode(){} - void SetResult(TreeNode *t) {mResult = t;} + void SetResult(TreeNode *t) {mResult = t; SETPARENT(t);} + TreeNode* GetResult() { return mResult; } + void Dump(unsigned); +}; + +class YieldNode : public TreeNode { +private: + TreeNode *mResult; + bool mIsTransfer; // In TS, yeild* tranfers to another generator +public: + YieldNode() : TreeNode(NK_Yield), mResult(nullptr), mIsTransfer(false) {} + ~YieldNode(){} + + void SetIsTransfer(bool b = true) {mIsTransfer = b;} + bool IsTransfer() {return mIsTransfer;} + + void SetResult(TreeNode *t) {mResult = t; SETPARENT(t);} TreeNode* GetResult() { return mResult; } void Dump(unsigned); }; @@ -592,9 +1495,9 @@ public: CondBranchNode(); ~CondBranchNode(){} - void SetCond(TreeNode *t) {mCond = t; t->SetParent(this);} - void SetTrueBranch(TreeNode *t) {mTrueBranch = t; t->SetParent(this);} - void SetFalseBranch(TreeNode *t){mFalseBranch = t; t->SetParent(this);} + void SetCond(TreeNode *t) {mCond = t; SETPARENT(t);} + void SetTrueBranch(TreeNode *t) {mTrueBranch = t; SETPARENT(t);} + void SetFalseBranch(TreeNode *t){mFalseBranch = t; SETPARENT(t);} TreeNode* GetCond() {return mCond;} TreeNode* GetTrueBranch() {return mTrueBranch;} @@ -608,50 +1511,97 @@ class BreakNode : public TreeNode { private: TreeNode* mTarget; public: - BreakNode() {mKind = NK_Break; mTarget = NULL;} + BreakNode() : TreeNode(NK_Break), mTarget(nullptr) {} ~BreakNode(){} TreeNode* GetTarget() {return mTarget;} - void SetTarget(TreeNode* t){mTarget = t;} + void SetTarget(TreeNode* t){mTarget = t; SETPARENT(t);} + void Dump(unsigned); +}; + + +// Continue statement. Continue targets could be one identifier or empty. +class ContinueNode : public TreeNode { +private: + TreeNode* mTarget; +public: + ContinueNode() : TreeNode(NK_Continue), mTarget(nullptr) {} + ~ContinueNode(){} + + TreeNode* GetTarget() {return mTarget;} + void SetTarget(TreeNode* t){mTarget = t; SETPARENT(t);} void Dump(unsigned); }; +// Javascript makes for loop complicated. It creates two special syntax as below +// for (var in set) {...} +// for (var of set) {...} +// We use FL_Prop to differentiate them with regular for loop. +enum ForLoopProp { + FLP_Regular, // this is the default property + FLP_JSIn, + FLP_JSOf, + FLP_NA +}; + class ForLoopNode : public TreeNode { private: - SmallVector mInit; + ForLoopProp mProp; + + // Regular for loop + SmallVector mInits; TreeNode *mCond; - SmallVector mUpdate; - TreeNode *mBody; // This is a block node + SmallVector mUpdates; + + // JS In or JS Of + TreeNode *mVariable; + TreeNode *mSet; + + // shared by all kinds + TreeNode *mBody; // This could be a single statement, or a block node + public: - ForLoopNode() {mCond = NULL; mBody = NULL; mKind = NK_ForLoop;} + ForLoopNode() : TreeNode(NK_ForLoop), + mCond(nullptr), mBody(nullptr), mVariable(nullptr), mSet(nullptr), mProp(FLP_Regular) {} ~ForLoopNode() {Release();} - void AddInit(TreeNode *t) {mInit.PushBack(t);} - void AddUpdate(TreeNode *t) {mUpdate.PushBack(t);} - void SetCond(TreeNode *t) {mCond = t;} - void SetBody(TreeNode *t) {mBody = t;} - - unsigned GetInitNum() {return mInit.GetNum();} - unsigned GetUpdateNum() {return mUpdate.GetNum();} - TreeNode* InitAtIndex(unsigned i) {return mInit.ValueAtIndex(i);} - TreeNode* UpdateAtIndex(unsigned i) {return mUpdate.ValueAtIndex(i);} + void AddInit(TreeNode *t); + void AddUpdate(TreeNode *t); + void SetCond(TreeNode *t) {mCond = t; SETPARENT(t);} + void SetBody(TreeNode *t) {mBody = t; SETPARENT(t);} + + unsigned GetInitsNum() {return mInits.GetNum();} + unsigned GetUpdatesNum() {return mUpdates.GetNum();} + TreeNode* GetInitAtIndex(unsigned i) {return mInits.ValueAtIndex(i);} + void SetInitAtIndex(unsigned i, TreeNode* n) {*(mInits.RefAtIndex(i)) = n;} + TreeNode* GetUpdateAtIndex(unsigned i) {return mUpdates.ValueAtIndex(i);} + void SetUpdateAtIndex(unsigned i, TreeNode* n) {*(mUpdates.RefAtIndex(i)) = n;} TreeNode* GetCond() {return mCond;} TreeNode* GetBody() {return mBody;} - void Release() {mInit.Release(); mUpdate.Release();} + ForLoopProp GetProp() {return mProp;} + void SetProp(ForLoopProp p) {mProp = p;} + + TreeNode* GetVariable() {return mVariable;} + void SetVariable(TreeNode *t) {mVariable = t; SETPARENT(t);} + + TreeNode* GetSet() {return mSet;} + void SetSet(TreeNode *t) {mSet = t; SETPARENT(t);} + + void Release() {mInits.Release(); mUpdates.Release();} void Dump(unsigned); }; class WhileLoopNode : public TreeNode { private: TreeNode *mCond; - TreeNode *mBody; // This is a block node + TreeNode *mBody; // This could be a single statement, or a block node public: - WhileLoopNode() {mCond = NULL; mBody = NULL; mKind = NK_WhileLoop;} + WhileLoopNode() : TreeNode(NK_WhileLoop), mCond(nullptr), mBody(nullptr) {} ~WhileLoopNode() {Release();} - void SetCond(TreeNode *t) {mCond = t;} - void SetBody(TreeNode *t) {mBody = t;} + void SetCond(TreeNode *t) {mCond = t; SETPARENT(t);} + void SetBody(TreeNode *t) {mBody = t; SETPARENT(t);} TreeNode* GetCond() {return mCond;} TreeNode* GetBody() {return mBody;} @@ -662,13 +1612,13 @@ public: class DoLoopNode : public TreeNode { private: TreeNode *mCond; - TreeNode *mBody; // This is a block node + TreeNode *mBody; // This could be a single statement, or a block node public: - DoLoopNode() {mCond = NULL; mBody = NULL; mKind = NK_DoLoop;} + DoLoopNode() : TreeNode(NK_DoLoop), mCond(nullptr), mBody(nullptr) {} ~DoLoopNode(){Release();} - void SetCond(TreeNode *t) {mCond = t;} - void SetBody(TreeNode *t) {mBody = t;} + void SetCond(TreeNode *t) {mCond = t; SETPARENT(t);} + void SetBody(TreeNode *t) {mBody = t; SETPARENT(t);} TreeNode* GetCond() {return mCond;} TreeNode* GetBody() {return mBody;} @@ -689,11 +1639,11 @@ private: bool mIsDefault; // default lable TreeNode *mValue; // the constant expression public: - SwitchLabelNode() : mIsDefault(false), mValue(NULL) {mKind = NK_SwitchLabel;} + SwitchLabelNode() : TreeNode(NK_SwitchLabel), mIsDefault(false), mValue(nullptr) {} ~SwitchLabelNode(){} void SetIsDefault(bool b) {mIsDefault = b;} - void SetValue(TreeNode *t){mValue = t;} + void SetValue(TreeNode *t){mValue = t; SETPARENT(t);} bool IsDefault() {return mIsDefault;} TreeNode* GetValue() {return mValue;} @@ -709,16 +1659,19 @@ private: SmallVector mStmts; public: - SwitchCaseNode() {mKind = NK_SwitchCase;} + SwitchCaseNode() :TreeNode(NK_SwitchCase) {} ~SwitchCaseNode() {Release();} unsigned GetLabelsNum() {return mLabels.GetNum();} - TreeNode* GetLabelAtIndex(unsigned i) {return mLabels.ValueAtIndex(i);} void AddLabel(TreeNode*); + SwitchLabelNode* GetLabelAtIndex(unsigned i) {return mLabels.ValueAtIndex(i);} + void SetLabelAtIndex(unsigned i, SwitchLabelNode* n) {*(mLabels.RefAtIndex(i)) = n;} unsigned GetStmtsNum() {return mStmts.GetNum();} TreeNode* GetStmtAtIndex(unsigned i) {return mStmts.ValueAtIndex(i);} + void SetStmtAtIndex(unsigned i, TreeNode* n) {*(mStmts.RefAtIndex(i)) = n; SETPARENT(n);} void AddStmt(TreeNode*); + void PopStmt() {mStmts.PopBack();} void Release() {mStmts.Release(); mLabels.Release();} void Dump(unsigned); @@ -726,18 +1679,22 @@ public: class SwitchNode : public TreeNode { private: - TreeNode *mCond; + TreeNode *mExpr; SmallVector mCases; public: - SwitchNode() : mCond(NULL) {mKind = NK_Switch;} + SwitchNode() : TreeNode(NK_Switch), mExpr(nullptr) {} ~SwitchNode() {Release();} - TreeNode* GetCond() {return mCond;} - void SetCond(TreeNode *c) {mCond = c;} + TreeNode* GetExpr() {return mExpr;} + void SetExpr(TreeNode *c) {mExpr = c; SETPARENT(c);} unsigned GetCasesNum() {return mCases.GetNum();} - TreeNode* GetCaseAtIndex(unsigned i) {return mCases.ValueAtIndex(i);} - void AddCase(TreeNode *c); + SwitchCaseNode* GetCaseAtIndex(unsigned i) {return mCases.ValueAtIndex(i);} + void SetCaseAtIndex(unsigned i, SwitchCaseNode* n) {*(mCases.RefAtIndex(i)) = n;} + void AddCase(SwitchCaseNode* n) {mCases.PushBack(n); SETPARENT(n);} + + void AddSwitchCase(TreeNode *t); + SwitchCaseNode* SwitchLabelToCase(SwitchLabelNode*); void Release() {mCases.Release();} void Dump(unsigned); @@ -754,13 +1711,13 @@ private: TreeNode *mExpr; TreeNode *mMsg; public: - AssertNode() : mExpr(NULL), mMsg(NULL) {mKind = NK_Assert;} + AssertNode() : TreeNode(NK_Assert), mExpr(nullptr), mMsg(nullptr) {} ~AssertNode(){} TreeNode* GetExpr() {return mExpr;} TreeNode* GetMsg() {return mMsg;} - void SetExpr(TreeNode *t) {mExpr = t;} - void SetMsg(TreeNode *t) {mMsg = t;} + void SetExpr(TreeNode *t) {mExpr = t; SETPARENT(t);} + void SetMsg(TreeNode *t) {mMsg = t; SETPARENT(t);} void Dump(unsigned); }; @@ -773,20 +1730,31 @@ class CallNode : public TreeNode { private: TreeNode *mMethod; ExprListNode mArgs; + SmallVector mTypeArguments; + TemplateLiteralNode *mTaggedTemplate; public: - CallNode() : mMethod(NULL){mKind = NK_Call;} - ~CallNode(){} + CallNode() : TreeNode(NK_Call), mMethod(nullptr), mTaggedTemplate(nullptr) {} + ~CallNode(){Release();} void Init(); TreeNode* GetMethod() {return mMethod;} - void SetMethod(TreeNode *t) {mMethod = t;} + void SetMethod(TreeNode *t) {mMethod = t; SETPARENT(t);} - void AddArg(TreeNode *t); - unsigned GetArgsNum() {return mArgs.GetNum();} - TreeNode* GetArg(unsigned index) {return mArgs.ExprAtIndex(index);} + TemplateLiteralNode* GetTaggedTemplate() {return mTaggedTemplate;} + void SetTaggedTemplate(TemplateLiteralNode *t) {mTaggedTemplate = t; SETPARENT(t);} - void Release() {mArgs.Release();} + void AddArg(TreeNode *t) {mArgs.Merge(t); SETPARENT(t);} + unsigned GetArgsNum() {return mArgs.GetExprsNum();} + TreeNode* GetArg(unsigned index) {return mArgs.GetExprAtIndex(index);} + void SetArg(unsigned i, TreeNode* n) {mArgs.SetExprAtIndex(i, n); SETPARENT(n);} + + unsigned GetTypeArgumentsNum() {return mTypeArguments.GetNum();} + TreeNode* GetTypeArgumentAtIndex(unsigned i) {return mTypeArguments.ValueAtIndex(i);} + void SetTypeArgumentAtIndex(unsigned i, TreeNode* n) {*(mTypeArguments.RefAtIndex(i)) = n; SETPARENT(n);} + void AddTypeArgument(TreeNode *); + + void Release() {mArgs.Release(); mTypeArguments.Release();} void Dump(unsigned); }; @@ -817,22 +1785,32 @@ public: bool mIsInstInit; // Instance Initializer SmallVector mAttrs; + TreeNode *mSync; // Java allows a sync object on a Block. + public: - BlockNode(){mKind = NK_Block; mIsInstInit = false;} + BlockNode() : TreeNode(NK_Block), mIsInstInit(false), mSync(nullptr) {} ~BlockNode() {Release();} // Instance Initializer and Attributes related bool IsInstInit() {return mIsInstInit;} - void SetIsInstInit() {mIsInstInit = true;} - unsigned GetAttrsNum() {return mAttrs.GetNum();} - void AddAttr(AttrId a) {mAttrs.PushBack(a);} - AttrId AttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + void SetIsInstInit(bool b = true) {mIsInstInit = b;} + unsigned GetAttrsNum() {return mAttrs.GetNum();} + void AddAttr(AttrId a) {mAttrs.PushBack(a);} + AttrId GetAttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + void SetAttrAtIndex(unsigned i, AttrId n) {*(mAttrs.RefAtIndex(i)) = n;} + + void SetSync(TreeNode *n) {mSync = n;} + TreeNode* GetSync() {return mSync;} unsigned GetChildrenNum() {return mChildren.GetNum();} TreeNode* GetChildAtIndex(unsigned i) {return mChildren.ValueAtIndex(i);} - void AddChild(TreeNode *c) {mChildren.PushBack(c); c->SetParent(this);} + void SetChildAtIndex(unsigned i, TreeNode* n) {*(mChildren.RefAtIndex(i)) = n; SETPARENT(n);} + void AddChild(TreeNode *c); void ClearChildren() {mChildren.Clear();} + void InsertStmtAfter(TreeNode *new_stmt, TreeNode *exist_stmt); + void InsertStmtBefore(TreeNode *new_stmt, TreeNode *exist_stmt); + void Release() {mChildren.Release();} void Dump(unsigned); }; @@ -850,11 +1828,25 @@ private: SmallVector mAttrs; SmallVector mAnnotations; //annotation or pragma SmallVector mThrows; // exceptions it can throw - TreeNode *mType; // return type + SmallVector mTypeParams; + TreeNode *mFuncName; // function name, usually an identifier + TreeNode *mRetType; // return type SmallVector mParams; // BlockNode *mBody; DimensionNode *mDims; - bool mIsConstructor; + TreeNode *mAssert; // In typescript, a function could have asserts + // like: func () : asserts v is string + // or a type predicate signature, like + // func() : v is string + // So mAssert could be either an AssertNode or + // an IsNode. + bool mIsConstructor; + bool mIsGetAccessor; + bool mIsSetAccessor; + bool mIsGenerator; // JS/TS generator + bool mIsIterator; // JS/TS iterator + bool mIsCallSignature; // no func name, no func body + bool mIsConstructSignature; // no func name, no func body, and is a construct sig in TS public: FunctionNode(); @@ -864,40 +1856,69 @@ public: // the PassNode in the tree. void CleanUp(); - BlockNode* GetBody() {return mBody;} - void AddBody(BlockNode *b) {mBody = b; b->SetParent(this); CleanUp();} + TreeNode* GetFuncName() {return mFuncName;} + void SetFuncName(TreeNode *n) {mFuncName = n; SETPARENT(n);} - bool IsConstructor() {return mIsConstructor;} - void SetIsConstructor() {mIsConstructor = true;} + BlockNode* GetBody() {return mBody;} + void SetBody(BlockNode *b) {mBody = b; SETPARENT(b); if(b) CleanUp();} + + TreeNode* GetAssert() {return mAssert;} + void SetAssert(TreeNode *b) {mAssert = b; SETPARENT(b);} + + bool IsConstructor() {return mIsConstructor;} + void SetIsConstructor(bool b = true) {mIsConstructor = b;} + bool IsGenerator() {return mIsGenerator;} + void SetIsGenerator(bool b = true) {mIsGenerator = b;} + bool IsIterator() {return mIsIterator;} + void SetIsIterator(bool b = true) {mIsIterator = b;} + bool IsGetAccessor() {return mIsGetAccessor;} + void SetIsGetAccessor(bool b = true) {mIsGetAccessor = b;} + bool IsSetAccessor() {return mIsSetAccessor;} + void SetIsSetAccessor(bool b = true) {mIsSetAccessor = b;} + bool IsCallSignature() {return mIsCallSignature;} + void SetIsCallSignature(bool b = true) {mIsCallSignature = b;} + bool IsConstructSignature() {return mIsConstructSignature;} + void SetIsConstructSignature(bool b = true) {mIsConstructSignature = b;} unsigned GetParamsNum() {return mParams.GetNum();} TreeNode* GetParam(unsigned i) {return mParams.ValueAtIndex(i);} - void AddParam(TreeNode *t) {mParams.PushBack(t); t->SetParent(this);} - + void SetParam(unsigned i, TreeNode* n) {*(mParams.RefAtIndex(i)) = n; SETPARENT(n);} + void AddParam(TreeNode *t) {mParams.PushBack(t); SETPARENT(t);} + void ClearParam() {mParams.Clear();} + // Attributes related - unsigned GetAttrsNum() {return mAttrs.GetNum();} - void AddAttr(AttrId a) {mAttrs.PushBack(a);} - AttrId AttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + unsigned GetAttrsNum() {return mAttrs.GetNum();} + void AddAttr(AttrId a) {mAttrs.PushBack(a);} + AttrId GetAttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + void SetAttrAtIndex(unsigned i, AttrId n) {*(mAttrs.RefAtIndex(i)) = n;} // Annotation/Pragma related unsigned GetAnnotationsNum() {return mAnnotations.GetNum();} void AddAnnotation(AnnotationNode *n) {mAnnotations.PushBack(n);} - AnnotationNode* AnnotationAtIndex(unsigned i) {return mAnnotations.ValueAtIndex(i);} + AnnotationNode* GetAnnotationAtIndex(unsigned i) {return mAnnotations.ValueAtIndex(i);} + void SetAnnotationAtIndex(unsigned i, AnnotationNode* n) {*(mAnnotations.RefAtIndex(i)) = n;} // Exception/throw related - unsigned GetThrowNum() {return mThrows.GetNum();} - void AddThrow(ExceptionNode *n){mThrows.PushBack(n);} - ExceptionNode* ThrowAtIndex(unsigned i) {return mThrows.ValueAtIndex(i);} + unsigned GetThrowsNum() {return mThrows.GetNum();} + void AddThrow(ExceptionNode *n) {mThrows.PushBack(n);} + ExceptionNode* GetThrowAtIndex(unsigned i) {return mThrows.ValueAtIndex(i);} + void SetThrowAtIndex(unsigned i, ExceptionNode* n) {*(mThrows.RefAtIndex(i)) = n;} - void SetType(TreeNode *t) {mType = t;} - TreeNode* GetType(){return mType;} + unsigned GetTypeParamsNum() {return mTypeParams.GetNum();} + TreeNode* GetTypeParamAtIndex(unsigned i) {return mTypeParams.ValueAtIndex(i);} + void SetTypeParamAtIndex(unsigned i, TreeNode* n) {*(mTypeParams.RefAtIndex(i)) = n; SETPARENT(n);} + void AddTypeParam(TreeNode *); + void SetRetType(TreeNode *t) {mRetType = t; SETPARENT(t);} + TreeNode* GetRetType(){return mRetType;} + + DimensionNode* GetDims() {return mDims;} void SetDims(DimensionNode *t) {mDims = t;} - unsigned GetDimsNum() {return mDims->GetDimsNum();} - bool IsArray() {return mDims && GetDimsNum() > 0;} - unsigned AddDim(unsigned i = 0){mDims->AddDim(i);} // 0 means unspecified - unsigned GetNthNum(unsigned n) {return mDims->GetNthDim(n);} // 0 means unspecified. - void SetNthNum(unsigned n, unsigned i) {mDims->SetNthDim(n, i);} + unsigned GetDimsNum() {return mDims->GetDimensionsNum();} + bool IsArray() {return mDims && mDims->GetDimensionsNum() > 0;} + void AddDim(unsigned i = 0){mDims->AddDimension(i);} // 0 means unspecified + unsigned GetNthDim(unsigned n) {return mDims->GetDimension(n);} // 0 means unspecified. + void SetNthDim(unsigned n, unsigned i) {mDims->SetDimension(n, i);} // Override equivalent. bool OverrideEquivalent(FunctionNode*); @@ -922,10 +1943,26 @@ private: SmallVector mFields; SmallVector mMethods; public: - InterfaceNode() : mIsAnnotation(false) {mKind = NK_Interface;} + InterfaceNode() : TreeNode(NK_Interface), mIsAnnotation(false) {} ~InterfaceNode() {} + unsigned GetSuperInterfacesNum() {return mSuperInterfaces.GetNum();} + void AddSuperInterface(InterfaceNode* a) {mSuperInterfaces.PushBack(a);} + InterfaceNode* GetSuperInterfaceAtIndex(unsigned i) {return mSuperInterfaces.ValueAtIndex(i);} + void SetSuperInterfaceAtIndex(unsigned i, InterfaceNode* n) {*(mSuperInterfaces.RefAtIndex(i)) = n;} + + unsigned GetFieldsNum() {return mFields.GetNum();} + void AddField(IdentifierNode* n) {mFields.PushBack(n); SETPARENT(n);} + IdentifierNode* GetField(unsigned i) {return mFields.ValueAtIndex(i);} + void SetField(unsigned i, IdentifierNode* n) {*(mFields.RefAtIndex(i)) = n; SETPARENT(n);} + + unsigned GetMethodsNum() {return mMethods.GetNum();} + void AddMethod(FunctionNode* a) {mMethods.PushBack(a);} + FunctionNode* GetMethod(unsigned i) {return mMethods.ValueAtIndex(i);} + void SetMethod(unsigned i, FunctionNode* n) {*(mMethods.RefAtIndex(i)) = n;} + void SetIsAnnotation(bool b) {mIsAnnotation = b;} + bool IsAnnotation() {return mIsAnnotation;} void Construct(BlockNode *); void Dump(unsigned); @@ -933,25 +1970,6 @@ public: ////////////////////////////////////////////////////////////////////////// // Class Nodes -// & -// ClassBody -->BlockNode -// In reality there is no such thing as ClassBody, since this 'body' will -// eventually become fields and methods of a class. However, during parsing -// the children are processed before parents, which means we need to have -// all fields and members ready before the class. So we come up with -// this ClassBody to temporarily hold these subtrees, and let the class -// to interpret it in the future. Once the class is done, this ClassBody -// is useless. In the real implementation, ClassBody is actually a BlockNode. -// -// NOTE. There is one important thing to know is This design is following -// the common rules of Java/C++, where a declaration of field or -// method has the scope of the whole class. This means it can be -// used before the declaratioin. There is no order of first decl then -// use. So we can do a Construct() which collect all Fields & Methods. -// -// However, we still keep mBody, which actually tells the order of -// the original program. Any language requiring order could use mBody -// to implement. ////////////////////////////////////////////////////////////////////////// class ClassNode : public TreeNode { @@ -960,46 +1978,101 @@ private: // and special semantic rules. We define JavaEnum here too. For other // languages like C/C++ which have very simply Enum, we will have a // dedicated EnumNode for them. - bool mJavaEnum; + bool mIsJavaEnum; - SmallVector mSuperClasses; - SmallVector mSuperInterfaces; - SmallVector mAttributes; - BlockNode *mBody; + SmallVector mSuperClasses; + SmallVector mSuperInterfaces; + SmallVector mAttributes; + SmallVector mAnnotations; //annotation or pragma + SmallVector mTypeParams; - SmallVector mFields; // aka Field + SmallVector mFields; // a Field could be identifier or computed name SmallVector mMethods; SmallVector mConstructors; SmallVector mInstInits; // instance initializer SmallVector mLocalClasses; SmallVector mLocalInterfaces; + SmallVector mImports; + SmallVector mExports; + + SmallVector mDeclares; // First coming from TS. public: - ClassNode(){mKind = NK_Class; mJavaEnum = false; mBody = NULL;} + ClassNode() : TreeNode(NK_Class), mIsJavaEnum(false) {} ~ClassNode() {Release();} - bool IsJavaEnum() {return mJavaEnum;} - void SetJavaEnum(){mJavaEnum = true;} - - void AddSuperClass(ClassNode *n) {mSuperClasses.PushBack(n);} - void AddSuperInterface(InterfaceNode *n) {mSuperInterfaces.PushBack(n);} - void AddAttr(AttrId a) {mAttributes.PushBack(a);} - void AddBody(BlockNode *b) {mBody = b; b->SetParent(this);} - - unsigned GetFieldsNum() {return mFields.GetNum();} - unsigned GetMethodsNum() {return mMethods.GetNum();} - unsigned GetConstructorNum() {return mConstructors.GetNum();} - unsigned GetInstInitsNum() {return mInstInits.GetNum();} - unsigned GetLocalClassesNum() {return mLocalClasses.GetNum();} - unsigned GetLocalInterfacesNum(){return mLocalInterfaces.GetNum();} - IdentifierNode* GetField(unsigned i) {return mFields.ValueAtIndex(i);} - FunctionNode* GetMethod(unsigned i) {return mMethods.ValueAtIndex(i);} - FunctionNode* GetConstructor(unsigned i) {return mConstructors.ValueAtIndex(i);} + bool IsJavaEnum() {return mIsJavaEnum;} + void SetIsJavaEnum(bool b = true){mIsJavaEnum = b;} + + // Annotation/Pragma related + unsigned GetAnnotationsNum() {return mAnnotations.GetNum();} + void AddAnnotation(AnnotationNode *n) {mAnnotations.PushBack(n);} + AnnotationNode* GetAnnotationAtIndex(unsigned i) {return mAnnotations.ValueAtIndex(i);} + void SetAnnotationAtIndex(unsigned i, AnnotationNode* n) {*(mAnnotations.RefAtIndex(i)) = n;} + + // TypeParameter + unsigned GetTypeParamsNum() {return mTypeParams.GetNum();} + void AddTypeParam(TreeNode *n); + TypeParameterNode* GetTypeParamAtIndex(unsigned i) {return mTypeParams.ValueAtIndex(i);} + void SetTypeParamAtIndex(unsigned i, TypeParameterNode* n) {*(mTypeParams.RefAtIndex(i)) = n;} + + void AddSuperClass(TreeNode *n); + unsigned GetSuperClassesNum() {return mSuperClasses.GetNum();} + TreeNode* GetSuperClass(unsigned i) {return mSuperClasses.ValueAtIndex(i);} + void SetSuperClass(unsigned i, TreeNode* n) {*(mSuperClasses.RefAtIndex(i)) = n;} + + void AddSuperInterface(TreeNode *n); + unsigned GetSuperInterfacesNum() {return mSuperInterfaces.GetNum();} + TreeNode* GetSuperInterface(unsigned i) {return mSuperInterfaces.ValueAtIndex(i);} + void SetSuperInterface(unsigned i, TreeNode* n) {*(mSuperInterfaces.RefAtIndex(i)) = n;} + + void AddAttr(AttrId a) {mAttributes.PushBack(a);} + void AddAttribute(AttrId a) {mAttributes.PushBack(a);} + + void AddField(TreeNode *n) {mFields.PushBack(n); SETPARENT(n);} + void AddMethod(FunctionNode *n) {mMethods.PushBack(n);} + void AddConstructor(FunctionNode *n) {mConstructors.PushBack(n);} + void AddInstInit(BlockNode *n) {mInstInits.PushBack(n);} + void AddLocalClass(ClassNode *n) {mLocalClasses.PushBack(n);} + void AddLocalInterface(InterfaceNode *n) {mLocalInterfaces.PushBack(n);} + void AddImport(ImportNode *n) {mImports.PushBack(n);} + void AddExport(ExportNode *n) {mExports.PushBack(n);} + void AddDeclare(DeclareNode *n) {mDeclares.PushBack(n);} + + + unsigned GetAttributesNum() {return mAttributes.GetNum();} + unsigned GetFieldsNum() {return mFields.GetNum();} + unsigned GetMethodsNum() {return mMethods.GetNum();} + unsigned GetConstructorsNum() {return mConstructors.GetNum();} + unsigned GetInstInitsNum() {return mInstInits.GetNum();} + unsigned GetLocalClassesNum() {return mLocalClasses.GetNum();} + unsigned GetLocalInterfacesNum() {return mLocalInterfaces.GetNum();} + unsigned GetImportsNum() {return mImports.GetNum();} + unsigned GetExportsNum() {return mExports.GetNum();} + unsigned GetDeclaresNum() {return mDeclares.GetNum();} + + AttrId GetAttribute(unsigned i) {return mAttributes.ValueAtIndex(i);} + void SetAttribute(unsigned i, AttrId n) {*(mAttributes.RefAtIndex(i)) = n;} + TreeNode* GetField(unsigned i) {return mFields.ValueAtIndex(i);} + void SetField(unsigned i, TreeNode* n) {*(mFields.RefAtIndex(i)) = n; SETPARENT(n);} + FunctionNode* GetMethod(unsigned i) {return mMethods.ValueAtIndex(i);} + void SetMethod(unsigned i, FunctionNode* n) {*(mMethods.RefAtIndex(i)) = n;} + FunctionNode* GetConstructor(unsigned i) {return mConstructors.ValueAtIndex(i);} + void SetConstructor(unsigned i, FunctionNode* n) {*(mConstructors.RefAtIndex(i)) = n;} BlockNode* GetInstInit(unsigned i) {return mInstInits.ValueAtIndex(i);} + void SetInstInit(unsigned i, BlockNode* n) {*(mInstInits.RefAtIndex(i)) = n;} ClassNode* GetLocalClass(unsigned i) {return mLocalClasses.ValueAtIndex(i);} - InterfaceNode* GetLocalInterface(unsigned i) {return mLocalInterfaces.ValueAtIndex(i);} - - void Construct(); + void SetLocalClass(unsigned i, ClassNode* n) {*(mLocalClasses.RefAtIndex(i)) = n;} + InterfaceNode* GetLocalInterface(unsigned i) {return mLocalInterfaces.ValueAtIndex(i);} + void SetLocalInterface(unsigned i, InterfaceNode* n) {*(mLocalInterfaces.RefAtIndex(i)) = n;} + ImportNode* GetImport(unsigned i) {return mImports.ValueAtIndex(i);} + void SetImport(unsigned i, ImportNode* n) {*(mImports.RefAtIndex(i)) = n;} + ExportNode* GetExport(unsigned i) {return mExports.ValueAtIndex(i);} + void SetExport(unsigned i, ExportNode* n) {*(mExports.RefAtIndex(i)) = n;} + DeclareNode* GetDeclare(unsigned i) {return mDeclares.ValueAtIndex(i);} + void SetDeclare(unsigned i, DeclareNode* n) {*(mDeclares.RefAtIndex(i)) = n;} + + void Construct(BlockNode*); void Release(); void Dump(unsigned); }; @@ -1018,69 +2091,332 @@ class PassNode : public TreeNode { private: SmallVector mChildren; public: - PassNode() {mKind = NK_Pass;} + PassNode() : TreeNode(NK_Pass) {} ~PassNode() {Release();} unsigned GetChildrenNum() {return mChildren.GetNum();} - TreeNode* GetChild(unsigned idx) {return mChildren.ValueAtIndex(idx);} - void SetChild(unsigned idx, TreeNode *t) {*(mChildren.RefAtIndex(idx)) = t;} + TreeNode* GetChild(unsigned i) {return mChildren.ValueAtIndex(i);} + void SetChild(unsigned i, TreeNode* n) {*(mChildren.RefAtIndex(i)) = n;} - void AddChild(TreeNode *c) {mChildren.PushBack(c); c->SetParent(this);} + void AddChild(TreeNode *c) {mChildren.PushBack(c); SETPARENT(c);} void Dump(unsigned); void Release() {mChildren.Release();} }; //////////////////////////////////////////////////////////////////////////// // Lambda Expression +// Java Lambda expression and JS arrow function have similar syntax. +// Also in Typescript, FunctionType and Constructor Type have the similar syntax. +// We put them in the same node. //////////////////////////////////////////////////////////////////////////// +// This property tells categories of LambdaNode +enum LambdaProperty { + LP_JavaLambda, + LP_JSArrowFunction, + LP_NA +}; + class LambdaNode : public TreeNode { private: - SmallVector mParams; - TreeNode *mBody; // the body is block. + LambdaProperty mProperty; + TreeNode *mRetType; // The return type. nullptr as Java Lambda. + SmallVector mParams; // A param could be an IdentifierNode or DeclNode. + TreeNode *mBody; // the body could be an expression, or block. + // nullptr as TS FunctionType and ConstructorType + SmallVector mTypeParams; + SmallVector mAttrs; public: - LambdaNode() {mBody = NULL; mKind = NK_Lambda;} + LambdaNode() : TreeNode(NK_Lambda), + mBody(nullptr), mProperty(LP_JSArrowFunction), mRetType(nullptr) {} ~LambdaNode(){Release();} - void AddParam(IdentifierNode *n) {mParams.PushBack(n); n->SetParent(this);} - void SetBody(TreeNode *n) {mBody = n; n->SetParent(this);} + + TreeNode* GetBody() {return mBody;} + void SetBody(TreeNode *n) {mBody = n; SETPARENT(n);} + + LambdaProperty GetProperty() {return mProperty;} + void SetProperty(LambdaProperty p) {mProperty = p;} + + TreeNode* GetRetType() {return mRetType;} + void SetRetType(TreeNode* t) {mRetType = t; SETPARENT(t);} + + unsigned GetParamsNum() {return mParams.GetNum();} + TreeNode* GetParam(unsigned i) {return mParams.ValueAtIndex(i);} + void SetParam(unsigned i, TreeNode* n) {*(mParams.RefAtIndex(i)) = n; SETPARENT(n);} + void AddParam(TreeNode *n) {mParams.PushBack(n); SETPARENT(n);} + + // TypeParameter + unsigned GetTypeParamsNum() {return mTypeParams.GetNum();} + void AddTypeParam(TreeNode *n); + TypeParameterNode* GetTypeParamAtIndex(unsigned i) {return mTypeParams.ValueAtIndex(i);} + void SetTypeParamAtIndex(unsigned i, TypeParameterNode* n) {*(mTypeParams.RefAtIndex(i)) = n;} + + // Attributes related + unsigned GetAttrsNum() const {return mAttrs.GetNum();} + void AddAttr(AttrId a) {mAttrs.PushBack(a);} + AttrId GetAttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + void SetAttrAtIndex(unsigned i, AttrId n) {*(mAttrs.RefAtIndex(i)) = n;} void Release() {mParams.Release();} void Dump(unsigned); }; //////////////////////////////////////////////////////////////////////////// -// The AST Tree +// InstanceOf Expression +// This is first created for Java's instanceof operation. It has the form of +// left instanceof right. +//////////////////////////////////////////////////////////////////////////// + +class InstanceOfNode : public TreeNode { +private: + TreeNode *mLeft; + TreeNode *mRight; +public: + InstanceOfNode() : TreeNode(NK_InstanceOf), mLeft(nullptr), mRight(nullptr) {} + ~InstanceOfNode(){Release();} + + TreeNode* GetLeft() {return mLeft;} + void SetLeft(TreeNode *n) {mLeft = n; SETPARENT(n);} + TreeNode* GetRight() {return mRight;} + void SetRight(TreeNode *n){mRight = n; SETPARENT(n);} + + void Dump(unsigned); +}; + +//////////////////////////////////////////////////////////////////////////// +// TypeOf Expression +// First coming from typescript. +//////////////////////////////////////////////////////////////////////////// + +class TypeOfNode : public TreeNode { +private: + TreeNode *mExpr; +public: + TypeOfNode() : TreeNode(NK_TypeOf), mExpr(nullptr) {} + ~TypeOfNode(){Release();} + + TreeNode* GetExpr() {return mExpr;} + void SetExpr(TreeNode *n) {mExpr = n; SETPARENT(n);} + + void Dump(unsigned); +}; + +//////////////////////////////////////////////////////////////////////////// +// KeyOf Expression +// First coming from typescript. +//////////////////////////////////////////////////////////////////////////// + +class KeyOfNode : public TreeNode { +private: + TreeNode *mExpr; +public: + KeyOfNode() : TreeNode(NK_KeyOf), mExpr(nullptr) {} + ~KeyOfNode(){Release();} + + TreeNode* GetExpr() {return mExpr;} + void SetExpr(TreeNode *n) {mExpr = n; SETPARENT(n);} + + void Dump(unsigned); +}; + +//////////////////////////////////////////////////////////////////////////// +// Infer Expression +// First coming from typescript. +//////////////////////////////////////////////////////////////////////////// + +class InferNode : public TreeNode { +private: + TreeNode *mExpr; +public: + InferNode() : TreeNode(NK_Infer), mExpr(nullptr) {} + ~InferNode(){Release();} + + TreeNode* GetExpr() {return mExpr;} + void SetExpr(TreeNode *n) {mExpr = n; SETPARENT(n);} + + void Dump(unsigned); +}; + +//////////////////////////////////////////////////////////////////////////// +// In Expression +// First coming from Javascript. It's like +// A is IN B. +// B is a set of properties. A is one of the properties. +//////////////////////////////////////////////////////////////////////////// + +class InNode : public TreeNode { +private: + TreeNode *mLeft; + TreeNode *mRight; +public: + InNode() : TreeNode(NK_In), mLeft(nullptr), mRight(nullptr) {} + ~InNode(){Release();} + + TreeNode* GetLeft() {return mLeft;} + void SetLeft(TreeNode *n) {mLeft = n; SETPARENT(n);} + TreeNode* GetRight() {return mRight;} + void SetRight(TreeNode *n){mRight = n; SETPARENT(n);} + + void Dump(unsigned); +}; + +//////////////////////////////////////////////////////////////////////////// +// ComputedName Expression +// First coming from Javascript. It's like +// [ xxx ] //////////////////////////////////////////////////////////////////////////// -class AppealNode; -class ASTBuilder; +enum CompNameProp { + CNP_NA = 0, + CNP_Rem_ReadOnly = 1, + CNP_Add_ReadOnly = 1 << 1, + CNP_Rem_Optional = 1 << 2, + CNP_Add_Optional = 1 << 3, +}; + +class ComputedNameNode : public TreeNode { +private: + unsigned mProp; + TreeNode *mExpr; + TreeNode *mInit; + TreeNode *mExtendType; // This is the type extending expression + // of the mapped property + SmallVector mAttrs; +public: + ComputedNameNode() : TreeNode(NK_ComputedName), + mProp(CNP_NA), mExpr(nullptr), mExtendType(nullptr), mInit(nullptr) {} + ~ComputedNameNode(){Release();} + + void Release() {mAttrs.Release();} + + unsigned GetProp() {return mProp;} + void SetProp(unsigned p) {mProp = mProp | p;} + + TreeNode* GetExpr() {return mExpr;} + void SetExpr(TreeNode *n) {mExpr = n; SETPARENT(n);} + TreeNode* GetInit() {return mInit;} + void SetInit(TreeNode *n) {mInit = n; SETPARENT(n);} + TreeNode* GetExtendType() {return mExtendType;} + void SetExtendType(TreeNode *n) {mExtendType = n; SETPARENT(n);} + + // Attributes related + unsigned GetAttrsNum() const {return mAttrs.GetNum();} + void AddAttr(AttrId a) {mAttrs.PushBack(a);} + AttrId GetAttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + void SetAttrAtIndex(unsigned i, AttrId n) {*(mAttrs.RefAtIndex(i)) = n;} + + void Dump(unsigned); +}; + +//////////////////////////////////////////////////////////////////////////// +// Is Expression +// First coming from Typescript. It's like +// A is B. +// B is usually a type. +//////////////////////////////////////////////////////////////////////////// -class ASTTree { +class IsNode : public TreeNode { +private: + TreeNode *mLeft; + TreeNode *mRight; public: - TreePool mTreePool; - TreeNode *mRootNode; + IsNode() : TreeNode(NK_Is), mLeft(nullptr), mRight(nullptr) {} + ~IsNode(){Release();} + + TreeNode* GetLeft() {return mLeft;} + void SetLeft(TreeNode *n) {mLeft = n; SETPARENT(n);} + TreeNode* GetRight() {return mRight;} + void SetRight(TreeNode *n){mRight = n; SETPARENT(n);} + + void Dump(unsigned); +}; +//////////////////////////////////////////////////////////////////////////// +// Await node +// 'await' is waiting on some expression to finish. +//////////////////////////////////////////////////////////////////////////// + +class AwaitNode : public TreeNode { private: - // We need a set of functions to deal with some common manipulations of - // most languages during AST Building. You can disable it if some functions - // are not what you want. - TreeNode* Manipulate(AppealNode*); - TreeNode* Manipulate2Binary(TreeNode*, TreeNode*); - TreeNode* Manipulate2Cast(TreeNode*, TreeNode*); + TreeNode *mExpr; +public: + AwaitNode() : TreeNode(NK_Await), mExpr(nullptr) {} + ~AwaitNode() {} + + TreeNode* GetExpr() {return mExpr;} + void SetExpr(TreeNode *n) {mExpr = n; SETPARENT(n);} + + void Dump(unsigned); +}; + +//////////////////////////////////////////////////////////////////////////// +// Tuple Type +// [label : type, label : type, ...] +//////////////////////////////////////////////////////////////////////////// +class NameTypePairNode : public TreeNode { +private: + TreeNode *mVar; + TreeNode *mType; public: - ASTTree(); - ~ASTTree(); + NameTypePairNode() : TreeNode(NK_NameTypePair), mVar(nullptr), mType(nullptr) {} + ~NameTypePairNode() {} + + TreeNode* GetVar() {return mVar;} + TreeNode* GetType() {return mType;} + void SetVar(TreeNode* t) {mVar = t; SETPARENT(t);} + void SetType(TreeNode* t) {mType = t; SETPARENT(t);} + + void Dump(unsigned); +}; - TreeNode* NewTreeNode(AppealNode*); +class TupleTypeNode : public TreeNode { +private: + SmallVector mFields; +public: + TupleTypeNode() : TreeNode(NK_TupleType) {} + ~TupleTypeNode() {Release();} - TreeNode* BuildBinaryOperation(TreeNode *, TreeNode *, OprId); - TreeNode* BuildPassNode(); + unsigned GetFieldsNum() {return mFields.GetNum();} + NameTypePairNode* GetField(unsigned i) {return mFields.ValueAtIndex(i);} + void SetField(unsigned i, NameTypePairNode* n) {*(mFields.RefAtIndex(i)) = n; SETPARENT(n);} + void AddField(NameTypePairNode *n) {mFields.PushBack(n); SETPARENT(n);} + void AddChild(TreeNode *n); + void Release() {mFields.Release();} void Dump(unsigned); +}; + +////////////////////////////////////////////////////// +// Triple Slash Directive +////////////////////////////////////////////////////// + +enum TripleSlashProp { + TSP_Path, + TSP_Types, + TSP_Lib, + TSP_NoDefaultLib, + TSP_NA +}; +class TripleSlashNode : public TreeNode { +private: + TripleSlashProp mProp; + TreeNode *mValue; +public: + TripleSlashNode() : TreeNode(NK_TripleSlash) {mValue = NULL; mProp = TSP_NA;} + ~TripleSlashNode() {} + + TreeNode* GetValue() {return mValue;} + void SetValue(TreeNode *n) {mValue = n; SETPARENT(n);} + + TripleSlashProp GetProp() {return mProp;} + void SetProp(TripleSlashProp p) {mProp = p;} + + void Dump(unsigned); }; + } #endif diff --git a/src/MapleFE/shared/include/ast_attr.h b/src/MapleFE/shared/include/ast_attr.h index 0678308c2835bc11074831bed84f2d47ac2a8624..326a9444cc24a4896c2dc072172b953776bb96aa 100644 --- a/src/MapleFE/shared/include/ast_attr.h +++ b/src/MapleFE/shared/include/ast_attr.h @@ -40,13 +40,16 @@ class AttrNode : public TreeNode { private: AttrId mId; public: - AttrNode() {mKind = NK_Attr; mId = ATTR_NA;} + AttrNode() : TreeNode(NK_Attr), mId(ATTR_NA) {} ~AttrNode(){} AttrId GetId() {return mId;} void SetId(AttrId id) {mId = id;} }; +extern const char* FindAttrKeyword(AttrId id); +extern AttrId FindAttrId(const char *keyword); + /////////////////////////////////////////////////////////////////////////////// // AttrPool // The size of AttrNode is fixed, so it's good to use MemPool for the storage. diff --git a/src/MapleFE/shared/include/ast_builder.h b/src/MapleFE/shared/include/ast_builder.h index 7890fd3c700bb4b29ac8ed8234aef5aeaa0ca56c..74ab70396f1a38e847fe91b4cacc9c21d4dec524 100644 --- a/src/MapleFE/shared/include/ast_builder.h +++ b/src/MapleFE/shared/include/ast_builder.h @@ -17,6 +17,7 @@ #define __AST_BUILDER_HEADER__ #include "ast.h" +#include "ast_module.h" #include "ast_mempool.h" namespace maplefe { @@ -49,24 +50,29 @@ class ASTScope; class ASTBuilder { private: - bool mTrace; + bool mTrace; + ModuleNode *mASTModule; // The last created node. It will be referenced by the // following AddModifier() or other functions. - TreeNode *mLastTreeNode; + TreeNode *mLastTreeNode; + + // Sometimes we call BuildIdentifier() to build an identifier node + // from keywords or any reserved words. This is allowed in Typescript. + // We save the Name of the keyword for BuildIdentifier(). + const char *mNameForBuildIdentifier; public: // information for a single action unsigned mActionId; std::vector mParams; - TreePool *mTreePool; public: - ASTBuilder() : mTreePool(NULL), mTrace(false) {} + ASTBuilder(ModuleNode *m) : mASTModule(m), mTrace(false), mLastTreeNode(NULL), mNameForBuildIdentifier(NULL) {} ~ASTBuilder() {} void SetTrace(bool b) {mTrace = b;} - void SetTreePool(TreePool *p) {mTreePool = p;} + void SetModule(ModuleNode *m) {mASTModule = m;} void AddParam(Param p) {mParams.push_back(p);} void ClearParams() {mParams.clear();} @@ -74,104 +80,18 @@ public: // Create Functions for Token TreeNode* CreateTokenTreeNode(const Token*); + TreeNode* BuildIdentifier(const Token*); + TreeNode* BuildIdentifier(const TreeNode*); TreeNode* Build(); - TreeNode* BuildPackageName(); - - TreeNode* BuildSingleTypeImport(); - TreeNode* BuildAllTypeImport(); - TreeNode* BuildSingleStaticImport(); - TreeNode* BuildAllStaticImport(); - TreeNode* BuildAllImport(); - - TreeNode* BuildBlock(); - TreeNode* AddToBlock(); - TreeNode* CvtToBlock(TreeNode *tnode); - - TreeNode* BuildUnaryOperation(); - TreeNode* BuildPostfixOperation(); - TreeNode* BuildBinaryOperation(); - TreeNode* BuildCast(); - TreeNode* BuildParenthesis(); - TreeNode* BuildLambda(); - - TreeNode* BuildDecl(); - TreeNode* BuildField(); - TreeNode* BuildVarList(); - - TreeNode* AddInitTo(); - TreeNode* AddTypeTo(); - TreeNode* AddModifier(); - TreeNode* AddModifierTo(); - - // Callsite - TreeNode* AddArguments(); - TreeNode* BuildCall(); - TreeNode* BuildExprList(); +#undef ACTION +#define ACTION(K) TreeNode* K(); +#include "supported_actions.def" - // Function related + void AddArguments(TreeNode *call, TreeNode *args); void AddParams(TreeNode *func, TreeNode *params); - TreeNode* AddParams(); - TreeNode* BuildFunction(); - TreeNode* BuildConstructor(); - TreeNode* AddFunctionBody(); - TreeNode* AddFunctionBodyTo(); - - TreeNode* BuildClass(); - TreeNode* SetClassIsJavaEnum(); - TreeNode* AddClassBody(); - TreeNode* AddSuperClass(); - TreeNode* AddSuperInterface(); - TreeNode* BuildInstInit(); - - // Annotation related - TreeNode* BuildAnnotationType(); - TreeNode* BuildAnnotation(); - TreeNode* AddAnnotationTypeBody(); - - // Interface related - TreeNode* BuildInterface(); - TreeNode* AddInterfaceBody(); - - // Dimension Related - TreeNode* BuildDim(); - TreeNode* BuildDims(); - TreeNode* AddDims(); - TreeNode* AddDimsTo(); - - // Statements, Control Flow - TreeNode* BuildAssignment(); - TreeNode* BuildReturn(); - TreeNode* BuildCondBranch(); - TreeNode* AddCondBranchTrueStatement(); - TreeNode* AddCondBranchFalseStatement(); - TreeNode* AddLabel(); - TreeNode* BuildBreak(); - TreeNode* BuildForLoop(); - TreeNode* BuildWhileLoop(); - TreeNode* BuildDoLoop(); - TreeNode* BuildNewOperation(); - TreeNode* BuildDeleteOperation(); - TreeNode* BuildAssert(); - - SwitchCaseNode* SwitchLabelToCase(SwitchLabelNode*); - TreeNode* BuildSwitchLabel(); - TreeNode* BuildDefaultSwitchLabel(); - TreeNode* BuildOneCase(); - TreeNode* BuildAllCases(); - TreeNode* BuildSwitch(); - - // Exception, throw - TreeNode* BuildThrows(); - TreeNode* AddThrowsTo(); - - // User Type related - TreeNode* BuildUserType(); - TreeNode* AddTypeArgument(); }; -// A global builder is good enough. -extern ASTBuilder gASTBuilder; } #endif diff --git a/src/MapleFE/shared/include/ast_fixup.h b/src/MapleFE/shared/include/ast_fixup.h new file mode 100644 index 0000000000000000000000000000000000000000..af36113470ee6ddd9d5ab4115d554b5a2a1eaeea --- /dev/null +++ b/src/MapleFE/shared/include/ast_fixup.h @@ -0,0 +1,59 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __AST_FIXUP_H__ +#define __AST_FIXUP_H__ + +#include "ast_module.h" +#include "ast.h" +#include "gen_astvisitor.h" + +namespace maplefe { + +// FixUpVisitor is to fix up some tree nodes after the AST is created +class FixUpVisitor : public AstVisitor { + private: + ModuleNode *mASTModule; + bool mUpdated; + + public: + FixUpVisitor(ModuleNode *m) : mASTModule(m), mUpdated(false) {} + + bool FixUp(); + + // Fix up OprId of a UnaOperatorNode + // OPR_Add --> OPR_Plus + // OPR_Sub --> OPR_Minus + // OPR_Inc && !IsPost() --> OPR_PreInc + // OPR_Dec && !IsPost() --> OPR_DecInc + // + UnaOperatorNode *VisitUnaOperatorNode(UnaOperatorNode *node); + + // Fix up literal boolean 'true' or 'false' as a type + UserTypeNode *VisitUserTypeNode(UserTypeNode *node); + + // Fix up the name string of a UserTypeNode + // Fix up literal boolean 'true' or 'false' + IdentifierNode *VisitIdentifierNode(IdentifierNode *node); + + // Update mFilename of a ModuleNode with a connonical absolute path + ModuleNode *VisitModuleNode(ModuleNode *node); + + // Replace a PassNode with a CallNode for tagged template literal + PassNode *VisitPassNode(PassNode *node); +}; + +} +#endif diff --git a/src/MapleFE/shared/include/ast_mempool.h b/src/MapleFE/shared/include/ast_mempool.h index f9a5c32e4958b1067ffc5b8628a9069cfcff22ef..62db391d1624da5da6d9f04376d5b78268756b54 100644 --- a/src/MapleFE/shared/include/ast_mempool.h +++ b/src/MapleFE/shared/include/ast_mempool.h @@ -54,5 +54,6 @@ public: // is out of the control of mMP. }; +extern TreePool gTreePool; } #endif diff --git a/src/MapleFE/shared/include/ast_module.h b/src/MapleFE/shared/include/ast_module.h index bc4de35a93412d29ab3afe0697899e677052f15a..58e6b19e1a0289949de47e4911f4ccc071203648 100644 --- a/src/MapleFE/shared/include/ast_module.h +++ b/src/MapleFE/shared/include/ast_module.h @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -23,42 +23,74 @@ namespace maplefe { -class ASTTree; -class ASTScope; +enum SrcLang { + SrcLangUnknown, + SrcLangJava, + SrcLangJavaScript, + SrcLangTypeScript, + SrcLangC, +}; // The module is a member of class Parser. -class ASTModule { +class ModuleNode : public TreeNode { public: - const char *mFileName; + const char *mFilename; PackageNode *mPackage; - SmallVector mImports; public: - std::vector mTrees; // All trees in the module. There is no root tree - // which covers all the others. - // Everything else will be treated as a TreeNode, not a tree, - // even if it's a local class. - // Memory is released in ~ASTModule(); + SmallList mTrees; // All trees in the module. ASTScope *mRootScope; // the scope corresponding to a module. All other scopes // are children of mRootScope. ASTScopePool mScopePool; // All the scopes are store in this pool. It also contains - // a vector of ASTScope pointer for traversal. + // a vector of ASTScope pointer for traversal. + SrcLang mSrcLang; + + bool mIsAmbient; // In Typescript there is an ambient module containing + // only declarations. public: - ASTModule(); - ~ASTModule(); + ModuleNode(); + ~ModuleNode(); + + bool IsAmbient() {return mIsAmbient;} + void SetIsAmbient(bool b = true) {mIsAmbient = b;} + + void SetFilename(const char *f) {mFilename = f;} + const char *GetFilename() {return mFilename;} + + void SetPackage(PackageNode *p); + PackageNode *GetPackage() {return mPackage;}; - void SetFileName(const char *f) {mFileName = f;} - void SetPackage(PackageNode *p); - void AddImport(ImportNode *imp) {mImports.PushBack(imp);} + void SetSrcLang(SrcLang l); + SrcLang GetSrcLang(); + std::string GetSrcLangString(); - void AddTree(ASTTree* t) { mTrees.push_back(t); } + unsigned GetTreesNum() {return mTrees.GetNum();} + TreeNode* GetTree(unsigned i) {return mTrees.ValueAtIndex(i);} + void SetTree(unsigned i, TreeNode* t) {*(mTrees.RefAtIndex(i)) = t;} + void AddTree(TreeNode* t); + void AddTreeFront(TreeNode* t); + + void InsertAfter(TreeNode *new_stmt, TreeNode *exist_stmt) { + mTrees.LocateValue(exist_stmt); + mTrees.InsertAfter(new_stmt); + if(new_stmt) new_stmt->SetParent(this); + } + void InsertBefore(TreeNode *new_stmt, TreeNode *exist_stmt) { + mTrees.LocateValue(exist_stmt); + mTrees.InsertBefore(new_stmt); + if(new_stmt) new_stmt->SetParent(this); + } + + ASTScope* GetRootScope() {return mRootScope;} + void SetRootScope(ASTScope *s) {mRootScope = s;} + + ASTScopePool& GetScopePool() {return mScopePool;} + void SetScopePool(ASTScopePool &s) {mScopePool = s;} ASTScope* NewScope(ASTScope *p); + ASTScope* NewScope(ASTScope *p, TreeNode *t); - void Dump(); + void Dump(unsigned); }; -// Assume currently only one global module is being processed. -extern ASTModule gModule; - } #endif diff --git a/src/MapleFE/shared/include/ast_nk.def b/src/MapleFE/shared/include/ast_nk.def index 7ce9f893576a8bf8ce4965f593ab37b38c6d246c..091b6931090a7a6a88b7c0b802624032fbf30ddc 100644 --- a/src/MapleFE/shared/include/ast_nk.def +++ b/src/MapleFE/shared/include/ast_nk.def @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -16,35 +16,86 @@ // This file defines the AST Node Kind list. It is shared nodes among different languages. // Each language can have its own unique set of noke kind list, and be included too. +NODEKIND(Module) NODEKIND(Package) + +NODEKIND(XXportAsPair) // JS has: import {x as y}, and export {x as y} NODEKIND(Import) +NODEKIND(Export) +NODEKIND(Declare) // c/c++ extern decl, or typescript 'declare' +NODEKIND(Decl) NODEKIND(Identifier) NODEKIND(Field) NODEKIND(Dimension) NODEKIND(Attr) + +// A pair of +NODEKIND(NameTypePair) + +// Type related NODEKIND(PrimType) NODEKIND(PrimArrayType) +NODEKIND(ArrayType) NODEKIND(UserType) +NODEKIND(TypeParameter) +NODEKIND(AsType) +NODEKIND(TypeAlias) +NODEKIND(ConditionalType) // Conditional types in Typescript +NODEKIND(TupleType) // tuple types in Typescript +NODEKIND(FunctionType) +// NODEKIND(Cast) NODEKIND(Parenthesis) +// For de-structuring syntax, first in JS +NODEKIND(BindingElement) +NODEKIND(BindingPattern) + +// Struct +NODEKIND(Struct) +NODEKIND(StructLiteral) +NODEKIND(FieldLiteral) + +// define two spcial nodes for typescript index signature +NODEKIND(NumIndexSig) +NODEKIND(StrIndexSig) + +// Typescript, computed name +NODEKIND(ComputedName) + +// Array related +NODEKIND(ArrayElement) +NODEKIND(ArrayLiteral) + // VarList is for identifier list only. // ExprList is for all kinds of node. NODEKIND(VarList) NODEKIND(ExprList) +NODEKIND(TemplateLiteral) +NODEKIND(RegExpr) + NODEKIND(Literal) NODEKIND(UnaOperator) NODEKIND(BinOperator) NODEKIND(TerOperator) NODEKIND(Lambda) +NODEKIND(InstanceOf) +NODEKIND(TypeOf) +NODEKIND(KeyOf) +NODEKIND(In) +NODEKIND(Is) +NODEKIND(Infer) + +NODEKIND(TripleSlash) // TS triple-slash directive NODEKIND(Block) NODEKIND(Function) NODEKIND(Class) NODEKIND(Interface) +NODEKIND(Namespace) // First come from Typescript namespace. // Annotation, Pragma in c/c++, has no effects for execution, but has meanings // for compiler or runtime. @@ -55,13 +106,23 @@ NODEKIND(Interface) NODEKIND(AnnotationType) NODEKIND(Annotation) +NODEKIND(Try) +NODEKIND(Catch) +NODEKIND(Finally) NODEKIND(Exception) +// This is for the throw statement. Not the "exceptions thrown by functions". +NODEKIND(Throw) + +NODEKIND(Await) + // These are statement nodes, or control flow related nodes. They are // common in most languages. NODEKIND(Return) +NODEKIND(Yield) NODEKIND(CondBranch) NODEKIND(Break) +NODEKIND(Continue) NODEKIND(ForLoop) NODEKIND(WhileLoop) NODEKIND(DoLoop) diff --git a/src/MapleFE/shared/include/ast_scope.h b/src/MapleFE/shared/include/ast_scope.h index c74c2f2c52ac9a34e6a86602b6c8506411724dd1..088072c362f6c492203110f4d0689223a2281428 100644 --- a/src/MapleFE/shared/include/ast_scope.h +++ b/src/MapleFE/shared/include/ast_scope.h @@ -40,7 +40,7 @@ private: // tree with it. It actually related to the module. Local scope always // has a local TreeNode with it. TreeNode *mTree; - + SmallVector mChildren; // Local User types like local class,etc. @@ -51,33 +51,53 @@ private: // So TreeNode is the only choice for it. SmallVector mDecls; + // Imported Decles + SmallVector mImportedDecls; + + // Exported Decles + SmallVector mExportedDecls; + public: ASTScope() : mParent(NULL), mTree(NULL) {} - ASTScope(ASTScope *p); + ASTScope(ASTScope *p) : mTree(NULL) { SetParent(p); } + ASTScope(ASTScope *p, TreeNode *t) { SetParent(p); SetTree(t); } ~ASTScope() {Release();} // It's the caller's duty to make sure p is not NULL - void SetParent(ASTScope *p) {mParent = p; p->AddChild(this);} + void SetParent(ASTScope *p) {mParent = p; if(p) p->AddChild(this);} ASTScope* GetParent() {return mParent;} TreeNode* GetTree() {return mTree;} - void SetTree(TreeNode* t) {mTree = t;} + void SetTree(TreeNode* t) {mTree = t; if(t) t->SetScope(this);} void AddChild(ASTScope*); + unsigned GetChildrenNum() {return mChildren.GetNum();} unsigned GetDeclNum() {return mDecls.GetNum();} + unsigned GetImportedDeclNum() {return mImportedDecls.GetNum();} + unsigned GetExportedDeclNum() {return mExportedDecls.GetNum();} unsigned GetTypeNum() {return mTypes.GetNum();} + ASTScope* GetChild(unsigned i) {return mChildren.ValueAtIndex(i);} TreeNode* GetDecl(unsigned i) {return mDecls.ValueAtIndex(i);} + TreeNode* GetImportedDecl(unsigned i) {return mImportedDecls.ValueAtIndex(i);} + TreeNode* GetExportedDecl(unsigned i) {return mExportedDecls.ValueAtIndex(i);} TreeNode* GetType(unsigned i) {return mTypes.ValueAtIndex(i);} - TreeNode* FindDeclOf(IdentifierNode*); - TreeNode* FindTypeOf(IdentifierNode*); + TreeNode* FindDeclOf(unsigned stridx, bool deep = true); + TreeNode* FindExportedDeclOf(unsigned stridx); + TreeNode* FindTypeOf(unsigned stridx); void AddDecl(TreeNode *n) {mDecls.PushBack(n);} + void AddImportDecl(TreeNode *n) {mImportedDecls.PushBack(n);} + void AddExportDecl(TreeNode *n) {mExportedDecls.PushBack(n);} void AddType(TreeNode *n) {mTypes.PushBack(n);} void TryAddDecl(TreeNode *n); void TryAddType(TreeNode *n); + bool IsAncestor(ASTScope *ancestor); + + void Dump(unsigned indent = 0); + virtual void Release(); }; @@ -94,7 +114,7 @@ private: public: ASTScopePool() {} ~ASTScopePool(); - + ASTScope* NewScope(ASTScope *parent); }; diff --git a/src/MapleFE/shared/include/ast_type.h b/src/MapleFE/shared/include/ast_type.h index 66c0b296680a5e7ee38ac468a7684b630aa0c3b8..0f4afe5ee73d61dff5d91d629ab2d40b51d7d471 100644 --- a/src/MapleFE/shared/include/ast_type.h +++ b/src/MapleFE/shared/include/ast_type.h @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -36,21 +36,20 @@ // Right now, I just let each instance represent a separate type, and will // come back to this. // -// So we a TreeNode of the type identifier can be a type, and we don't have -// to give any special data struct for it. A user type is created as a treenode -// (IdentifierNode) at the beginning, but later we will do consolidation, -// and it may be turned into a function, struct, etc. So a TreeNode is good here. -// -// // We define 3 different types. // 1. UserType // It's an identifier which defines a class, interface, struct, etc. +// It also includes DimensionNode to tell if it's array. // 2. PrimType // This is coming from language's type keyword which are primitive types. // PrimType-s have limited number, and we pre-created AST nodes for them. // All same prim type nodes are pointing to the same one. // 3. PrimArrayType // This is a special case. e.g. int[] +// +// The reason we split primary types into PrimType and PrimArrayType is to +// share the same PrimType since they can be predefined in the Prim Pool. +// ////////////////////////////////////////////////////////////////////////// #ifndef __AST_TYPE_H__ @@ -65,32 +64,130 @@ namespace maplefe { /////////////////////////////////////////////////////////////////////////////// // UserTypeNode +// User type is complicated in Typescript. It could a union or intersection +// of other types. /////////////////////////////////////////////////////////////////////////////// +enum UT_Type { + UT_Regular, // the normal user type, it could be just a name. + UT_Union, // Union of two other types. + UT_Inter, // Intersection of other types. +}; + class UserTypeNode : public TreeNode { private: - IdentifierNode *mId; - SmallVector mTypeArguments; + // A regular UT always has an Id (or name), or lambda, etc. + // A union or intersection UT may or may not have an ID. + TreeNode *mId; + + UT_Type mType; + DimensionNode *mDims; + + // the set of types in union or intersection. + SmallVector mUnionInterTypes; + + // There are two scenarios type generic info are used. + // 1. It's a type argument + // 2. It's a type parameter. Type parameter may have default value. + SmallVector mTypeGenerics; + + SmallVector mAttrs; + public: - UserTypeNode() : mId(NULL) {mKind = NK_UserType;} - UserTypeNode(IdentifierNode *n) : mId(n) {mKind = NK_UserType;} + UserTypeNode(TreeNode *n) : TreeNode(NK_UserType), + mId(n), mType(UT_Regular), mDims(NULL) { SETPARENT(n); } + UserTypeNode() : UserTypeNode(NULL) {} ~UserTypeNode(){Release();} - IdentifierNode* GetId() {return mId;} - void SetId(IdentifierNode *n) {mId = n;} + TreeNode* GetId() {return mId;} + void SetId(TreeNode *n) {mId = n; SETPARENT(n);} - const char* GetName() {return mId->GetName();} + unsigned GetUnionInterTypesNum() {return mUnionInterTypes.GetNum();} + void AddUnionInterType(TreeNode *n, bool front = false); + TreeNode* GetUnionInterType(unsigned i) {return mUnionInterTypes.ValueAtIndex(i);} + void SetUnionInterType(unsigned i, TreeNode* n) {*(mUnionInterTypes.RefAtIndex(i)) = n; SETPARENT(n);} - unsigned TypeArgsNum() {return mTypeArguments.GetNum();} - void AddTypeArg(IdentifierNode *n) {mTypeArguments.PushBack(n);} - void AddTypeArgs(TreeNode *n); + unsigned GetTypeGenericsNum() {return mTypeGenerics.GetNum();} + void AddTypeGeneric(TreeNode *n); + TreeNode* GetTypeGeneric(unsigned i) {return mTypeGenerics.ValueAtIndex(i);} + void SetTypeGeneric(unsigned i, TreeNode* n) {*(mTypeGenerics.RefAtIndex(i)) = n; SETPARENT(n);} + + UT_Type GetType() {return mType;} + void SetType(UT_Type t) {mType = t;} + + DimensionNode* GetDims() {return mDims;} + void SetDims(DimensionNode *d) {mDims = d;} + + unsigned GetDimsNum() {return mDims->GetDimensionsNum();} + bool IsArray() {return mDims && GetDimsNum() > 0;} + void AddDim(unsigned i = 0){mDims->AddDimension(i);} // 0 means unspecified + unsigned GetNthNum(unsigned n) {return mDims->GetDimension(n);} // 0 means unspecified. + void SetNthNum(unsigned n, unsigned i) {mDims->SetDimension(n, i);} + + // Attributes related + unsigned GetAttrsNum() const {return mAttrs.GetNum();} + void AddAttr(AttrId a) {mAttrs.PushBack(a);} + AttrId GetAttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + void SetAttrAtIndex(unsigned i, AttrId n) {*(mAttrs.RefAtIndex(i)) = n;} bool TypeEquivalent(UserTypeNode *); - void Release() {mTypeArguments.Release();} + void Release() {mTypeGenerics.Release(); mUnionInterTypes.Release();} void Dump(unsigned); }; +/////////////////////////////////////////////////////////////////////////////// +// ArrayTypeNode +// It is used to specify Array types, including element type and dimensions +/////////////////////////////////////////////////////////////////////////////// + +class ArrayTypeNode : public TreeNode { +private: + TreeNode *mElemType; + DimensionNode *mDims; + SmallVector mAttrs; + +public: + ArrayTypeNode() : TreeNode(NK_ArrayType), mElemType(NULL), mDims(NULL) {} + ~ArrayTypeNode(){} + + void SetElemType(TreeNode *n) {mElemType = n; SETPARENT(n);} + void SetDims(DimensionNode *d) {mDims = d; SETPARENT(d);} + TreeNode* GetElemType() {return mElemType;} + DimensionNode* GetDims() {return mDims;} + + // Attributes related + unsigned GetAttrsNum() const {return mAttrs.GetNum();} + void AddAttr(AttrId a) {mAttrs.PushBack(a);} + AttrId GetAttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + void SetAttrAtIndex(unsigned i, AttrId n) {*(mAttrs.RefAtIndex(i)) = n;} + + void Dump(unsigned); +}; + +/////////////////////////////////////////////////////////////////////////////// +// FunctionTypeNode +// It is used to specify function types with its parameters and return type +/////////////////////////////////////////////////////////////////////////////// +class FunctionTypeNode : public TreeNode { +private: + SmallVector mParams; // type index of formal parameters + // and return which is the last one + +public: + FunctionTypeNode() : TreeNode(NK_FunctionType) {} + ~FunctionTypeNode(){} + + unsigned GetParamsNum() {return mParams.GetNum();} + unsigned GetParam(unsigned i) {return mParams.ValueAtIndex(i);} + void SetParam(unsigned i, unsigned n) {*(mParams.RefAtIndex(i)) = n;} + void AddParam(unsigned i) {mParams.PushBack(i);} + void ClearParam() {mParams.Clear();} + + bool IsEqual(FunctionTypeNode *f); + void Dump(unsigned); +}; + /////////////////////////////////////////////////////////////////////////////// // PrimTypeNode & PrimTypePool // The size of PrimTypeNode is fixed, so it's good to use container for the storage. @@ -100,13 +197,18 @@ public: class PrimTypeNode : public TreeNode { private: TypeId mPrimType; // primitive type + bool mIsUnique; // This is specifically for TS "unique symbol". TS creates many + // opaque syntax. public: - PrimTypeNode() {mKind = NK_PrimType;} + PrimTypeNode() : TreeNode(NK_PrimType), mIsUnique(false) {} ~PrimTypeNode(){} + bool IsUnique() {return mIsUnique;} + void SetIsUnique(bool b = true) {mIsUnique = b;} + TypeId GetPrimType() {return mPrimType;} void SetPrimType(TypeId id) {mPrimType = id; } - const char* GetName(); // type name + const char* GetTypeName(); // type name void Dump(unsigned); }; @@ -115,29 +217,34 @@ class PrimArrayTypeNode : public TreeNode { private: PrimTypeNode *mPrim; DimensionNode *mDims; + SmallVector mAttrs; + public: - PrimArrayTypeNode() : mPrim(NULL), mDims(NULL) {mKind = NK_PrimArrayType;} + PrimArrayTypeNode() : TreeNode(NK_PrimArrayType), mPrim(NULL), mDims(NULL) {} ~PrimArrayTypeNode(){} - void SetPrim(PrimTypeNode *p) {mPrim = p;} - void SetDims(DimensionNode *d) {mDims = d;} + void SetPrim(PrimTypeNode *p) {mPrim = p; SETPARENT(p);} + void SetDims(DimensionNode *d) {mDims = d; SETPARENT(d);} PrimTypeNode* GetPrim() {return mPrim;} DimensionNode* GetDims(){return mDims;} + // Attributes related + unsigned GetAttrsNum() const {return mAttrs.GetNum();} + void AddAttr(AttrId a) {mAttrs.PushBack(a);} + AttrId GetAttrAtIndex(unsigned i) {return mAttrs.ValueAtIndex(i);} + void SetAttrAtIndex(unsigned i, AttrId n) {*(mAttrs.RefAtIndex(i)) = n;} + void Dump(unsigned); }; class PrimTypePool { private: - TreePool mTreePool; SmallVector mTypes; - - void Init(); - public: PrimTypePool(); ~PrimTypePool(); + void Init(); PrimTypeNode* FindType(const char *keyword); PrimTypeNode* FindType(TypeId id); }; diff --git a/src/MapleFE/shared/include/comment.h b/src/MapleFE/shared/include/comment.h index a468e1050557464db7c7f6ff1b223ec4c363daf2..d0ee240ad04a1104eb8a441438c1cefe1f28fc29 100644 --- a/src/MapleFE/shared/include/comment.h +++ b/src/MapleFE/shared/include/comment.h @@ -21,7 +21,7 @@ // |-->literals // |-->separators // |-->operators -// +// // This categorization is shared among all languages. [NOTE] If anything // in a new language is exceptional, please add to this. // @@ -36,7 +36,7 @@ namespace maplefe { -typedef enum { +typedef enum COMM_Type { COMM_EOL, //End of Line, // COMM_TRA //Traditional, /* ... */ }COMM_Type; @@ -46,7 +46,7 @@ private: COMM_Type CommType; public: Comment(COMM_Type ct) : CommType(ct) {EType = ET_CM;} - + bool IsEndOfLine() {return CommType == COMM_EOL;} bool IsTraditional() {return CommType == COMM_TRA;} }; diff --git a/src/MapleFE/shared/include/common_header_autogen.h b/src/MapleFE/shared/include/common_header_autogen.h index febf115539c59beeaf07f53a8b18f414cf3e1a5e..221b853d73d383f0147b0ce9c8a90358a84e1f8f 100644 --- a/src/MapleFE/shared/include/common_header_autogen.h +++ b/src/MapleFE/shared/include/common_header_autogen.h @@ -27,12 +27,9 @@ #include "gen_literal.h" #include "gen_iden.h" #include "gen_type.h" -#include "gen_expr.h" #include "gen_stmt.h" -#include "gen_block.h" #include "gen_separator.h" #include "gen_operator.h" #include "gen_keyword.h" -#include "gen_summary.h" #endif diff --git a/src/MapleFE/shared/include/container.h b/src/MapleFE/shared/include/container.h index 4859a7af047fd098ba2fcae063dde1fc64e1e159..828a8379e00034339b1eeca24fbc55045b9a79f9 100644 --- a/src/MapleFE/shared/include/container.h +++ b/src/MapleFE/shared/include/container.h @@ -1,5 +1,6 @@ /* * Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) 2022 Tencent. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -32,8 +33,11 @@ #ifndef __CONTAINER_H__ #define __CONTAINER_H__ +#include +#include #include "mempool.h" #include "massert.h" +#include "macros.h" namespace maplefe { @@ -45,9 +49,13 @@ namespace maplefe { class ContainerMemPool : public MemPool { public: unsigned mElemSize; + unsigned mElemNumPerBlock; public: + ContainerMemPool() : mElemSize(1) {} + + void SetBlockSize(unsigned i) {mBlockSize = i; mElemNumPerBlock = mBlockSize / mElemSize;} char* AddrOfIndex(unsigned index); - void SetElemSize(unsigned i) {mElemSize = i;} + void SetElemSize(unsigned i) {mElemSize = i; mElemNumPerBlock = mBlockSize/mElemSize;} char* AllocElem() {return Alloc(mElemSize);} }; @@ -77,7 +85,10 @@ public: void PushBack(T t) { char *addr = mMemPool.AllocElem(); - *(T*)addr = t; + if(std::is_class::value) + new (addr) T(t); + else + *(T*)addr = t; mNum++; } @@ -107,7 +118,10 @@ public: // It's the caller's duty to make sure ith element is valid. void SetElem(unsigned i, T t) { char *addr = mMemPool.AddrOfIndex(i); - *(T*)addr = t; + if(std::is_class::value) + new (addr) T(t); + else + *(T*)addr = t; } bool Find(T t) { @@ -472,7 +486,7 @@ private: // Add more elements, on the knob. // This is common scenario. To implement, it requires a temporary // pointer to the located knob. This temp knob is used ONLY when - // paired operations, PairedFindOrCreateKnob() and PairedAddElem() + // paired operations, PairedFindOrCreateKnob() and PairedAddElem() Knob *mTempKnob; private: @@ -765,6 +779,338 @@ public: } }; +//////////////////////////////////////////////////////////////////////// +// GuamianFast uses unordered map to store the Knob-s in order to +// speed up the searching with big number of data. +//////////////////////////////////////////////////////////////////////// + +template class GuamianFast { +private: + struct Elem{ + E mData; + Elem *mNext; + }; + + // Sometimes people need save certain additional information to + // each knob. So we define mData. + struct Knob{ + D mData; + Elem *mChildren; // pointing to the first child + }; + + MemPool mMemPool; + std::unordered_map mKnobs; + + // allocate a new knob + Knob* NewKnob() { + Knob *knob = (Knob*)mMemPool.Alloc(sizeof(Knob)); + knob->mData = 0; + knob->mChildren = NULL; + return knob; + } + + // allocate a new element + Elem* NewElem() { + Elem *elem = (Elem*)mMemPool.Alloc(sizeof(Elem)); + elem->mNext = NULL; + elem->mData = 0; + return elem; + } + + // Sometimes people want to have a sequence of operations like, + // Get the knob, + // Add one element, on the knob + // Add more elements, on the knob. + // This is common scenario. To implement, it requires a temporary + // pointer to the located knob. This temp knob is used ONLY when + // paired operations, PairedFindOrCreateKnob() and PairedAddElem() + struct { + Knob *mKnob; + K mKey; + }mTempKnob; + +private: + // Just try to find the Knob. + // return NULL if fails. + Knob* FindKnob(K key) { + Knob *result = NULL; + auto search = mKnobs.find(key); + if (search != mKnobs.end()) + result = search->second; + return result; + } + + // Try to find the Knob. Create one if failed. + Knob* FindOrCreateKnob(K key) { + Knob *knob = FindKnob(key); + if (!knob) { + knob = NewKnob(); + mKnobs.insert(std::make_pair(key, knob)); + } + return knob; + } + + // Add an element to knob. It's the caller's duty to assure + // knob is not NULL. + void AddElem(Knob *knob, E data) { + Elem *elem = knob->mChildren; + Elem *found = NULL; + while (elem) { + if (elem->mData == data) { + found = elem; + break; + } + elem = elem->mNext; + } + + if (!found) { + Elem *e = NewElem(); + e->mData = data; + e->mNext = knob->mChildren; + knob->mChildren = e; + } + } + + // return true : if find the element + // false : if fail + bool FindElem(Knob *knob, E data) { + Elem *elem = knob->mChildren; + while (elem) { + if (elem->mData == data) + return true; + elem = elem->mNext; + } + return false; + } + + // Remove elem from the list. If elem doesn't exist, exit quietly. + // It's caller's duty to assure elem exists. + void RemoveElem(Knob *knob, E data) { + Elem *elem = knob->mChildren; + Elem *elem_prev = NULL; + Elem *target = NULL; + while (elem) { + if (elem->mData == data) { + target = elem; + break; + } + elem_prev = elem; + elem = elem->mNext; + } + + if (target) { + if (target == knob->mChildren) + knob->mChildren = target->mNext; + else + elem_prev->mNext = target->mNext; + } + } + + // Move the element to be the first child of knob. + // It's the caller's duty to make sure 'data' does exist + // in knob's children. + void MoveElemToHead(Knob *knob, E data) { + Elem *target_elem = NULL; + Elem *elem = knob->mChildren; + Elem *elem_prev = NULL; + while (elem) { + if (elem->mData == data) { + target_elem = elem; + break; + } + elem_prev = elem; + elem = elem->mNext; + } + + if (target_elem && (target_elem != knob->mChildren)) { + elem_prev->mNext = target_elem->mNext; + target_elem->mNext = knob->mChildren; + knob->mChildren = target_elem; + } + } + + // Try to find the first child of Knob k. Return the data. + // found is set to false if fails, or true. + // [NOTE] It's the user's responsibilty to make sure the Knob + // of 'key' exists. + E FindFirstElem(Knob *knob, bool &found) { + Elem *e = knob->mChildren; + if (!e) { + found = false; + return 0; + } + found = true; + return e->mData; + } + + // return num of elements in knob. + // It's caller's duty to assure knob is not NULL. + unsigned NumOfElem(Knob *knob) { + Elem *e = knob->mChildren; + unsigned c = 0; + while(e) { + c++; + e = e->mNext; + } + return c; + } + + // Return the idx-th element in knob. + // It's caller's duty to assure the validity of return value. + // It doesn't check validity here. + // Index starts from 0. + E GetElemAtIndex(Knob *knob, unsigned idx) { + Elem *e = knob->mChildren; + unsigned c = 0; + E data; + while(e) { + if (c == idx) { + data = e->mData; + break; + } + c++; + e = e->mNext; + } + return data; + } + +public: + GuamianFast() {mTempKnob.mKnob = NULL;} + ~GuamianFast(){Release();} + + void AddElem(K key, E data) { + Knob *knob = FindOrCreateKnob(key); + AddElem(knob, data); + } + + // If 'data' doesn't exist, it ends quietly + void RemoveElem(K key, E data) { + Knob *knob = FindOrCreateKnob(key); + RemoveElem(knob, data); + } + + // Try to find the first child of Knob k. Return the data. + // found is set to false if fails, or true. + // [NOTE] It's the user's responsibilty to make sure the Knob + // of 'key' exists. + E FindFirstElem(K key, bool &found) { + Knob *knob = FindKnob(key); + if (!knob) { + found = false; + return 0; // return value doesn't matter when fails. + } + E data = FindFirstElem(knob, found); + return data; + } + + // return true : if find the element + // false : if fail + bool FindElem(K key, E data) { + Knob *knob = FindKnob(key); + if (!knob) + return false; + return FindElem(knob, data); + } + + // Move element to be the header + // If 'data' doesn't exist, it ends quietly. + void MoveElemToHead(K key, E data) { + Knob *knob = FindKnob(key); + if (!knob) + return; + MoveElemToHead(knob, data); + } + + ///////////////////////////////////////////////////////// + // Paired operations start with finding a knob. It can + // be either PairedFindKnob() or PairedFindOrCreateKnob() + // Following that, there could be any number of operations + // like searching, adding, moving an element. + ///////////////////////////////////////////////////////// + + void PairedFindOrCreateKnob(K key) { + mTempKnob.mKnob = FindOrCreateKnob(key); + mTempKnob.mKey = key; + } + + bool PairedFindKnob(K key) { + mTempKnob.mKnob = FindKnob(key); + mTempKnob.mKey = key; + if (mTempKnob.mKnob) + return true; + else + return false; + } + + void PairedAddElem(E data) { + AddElem(mTempKnob.mKnob, data); + } + + // If 'data' doesn't exist, it ends quietly + void PairedRemoveElem(E data) { + RemoveElem(mTempKnob.mKnob, data); + } + + bool PairedFindElem(E data) { + return FindElem(mTempKnob.mKnob, data); + } + + // If 'data' doesn't exist, it ends quietly. + void PairedMoveElemToHead(E data) { + MoveElemToHead(mTempKnob.mKnob, data); + } + + E PairedFindFirstElem(bool &found) { + return FindFirstElem(mTempKnob.mKnob, found); + } + + // return num of elements in current temp knob. + // It's caller's duty to assure knob is not NULL. + unsigned PairedNumOfElem() { + return NumOfElem(mTempKnob.mKnob); + } + + // Return the idx-th element in knob. + // It's caller's duty to assure the validity of return value. + // It doesn't check validity here. + // Index starts from 0. + E PairedGetElemAtIndex(unsigned idx) { + return GetElemAtIndex(mTempKnob.mKnob, idx); + } + + // Reduce the element at index exc_idx. + // It's caller's duty to assure the element exists. + void PairedReduceElems(unsigned exc_idx) { + ReduceElems(mTempKnob.mKnob, exc_idx); + } + + void PairedSetKnobData(D d) { + mTempKnob.mKnob->mData = d; + } + + D PairedGetKnobData() { + return mTempKnob.mKnob->mData; + } + + K PairedGetKnobKey() { + return mTempKnob.mKey; + } + + ///////////////////////////////////////////////////////// + // Other functions + ///////////////////////////////////////////////////////// + + void Clear(){ + mTempKnob.mKnob = NULL; + mKnobs.clear(); + mMemPool.Clear(); + } + + void Release(){ + mMemPool.Release(); + } +}; + ////////////////////////////////////////////////////////////////////////////////////// // Tree // This is a regular tree. It simply maintains the basic operations of a tree, like @@ -779,7 +1125,7 @@ public: // We first give each node certain children. If it needs more, an allocation from // memory pool is needed. -#define TREE_MAX_CHILDREN_NUM 12 +#define TREE_MAX_CHILDREN_NUM 20 #define TREE_CHILDREN_NUM 4 template class ContTreeNode { @@ -916,5 +1262,29 @@ public: } }; +///////////////////////////////////////////////////////////////////////////// +// Bit Vector +///////////////////////////////////////////////////////////////////////////// + +class BitVector : public MemPool { +private: + unsigned mBVSize; // number of bits + char* GetAddr(unsigned); // return the address of bit +public: + BitVector(); + BitVector(unsigned); + ~BitVector(){} + + void ClearAll() {WipeOff();} + void ClearBit(unsigned); + void SetBit(unsigned); + bool GetBit(unsigned); + void SetBVSize(unsigned i) {mBVSize = i;} + unsigned GetBVSize() {return mBVSize;} + bool Equal(BitVector *bv); + void And(BitVector *bv); + void Or(BitVector *bv); +}; + } #endif diff --git a/src/MapleFE/shared/include/diagnose.h b/src/MapleFE/shared/include/diagnose.h index a554325c11e705e317739040ebb29f84c6b4318b..5f769bc9621a18e37320e1e49cb27b8d0831d635 100644 --- a/src/MapleFE/shared/include/diagnose.h +++ b/src/MapleFE/shared/include/diagnose.h @@ -31,7 +31,7 @@ public: unsigned Col; char Msg[256]; public: - DiagMessage(const char*, unsigned, unsigned, const char*); + DiagMessage(const char*, unsigned, unsigned, const char*); } // We save OBJECT not POINTER of DiagMessage in Diagnose. diff --git a/src/MapleFE/shared/include/element.h b/src/MapleFE/shared/include/element.h index be10ef628f11f42fa58b495c8891261e60ca1cde..27b68a46e0c4cb3da2cc168de1c33498bdad356f 100644 --- a/src/MapleFE/shared/include/element.h +++ b/src/MapleFE/shared/include/element.h @@ -33,7 +33,7 @@ namespace maplefe { -typedef enum { +typedef enum ELMT_Type { ET_WS, // White Space ET_CM, // Comment ET_TK, // Token diff --git a/src/MapleFE/shared/include/fileread.h b/src/MapleFE/shared/include/fileread.h index dd106348fd3d9e18a5952bdb41f04dd87c449694..e71d2ba6cadf296303e9c9d1b0098be096f77c42 100644 --- a/src/MapleFE/shared/include/fileread.h +++ b/src/MapleFE/shared/include/fileread.h @@ -49,7 +49,7 @@ public: void MoveCursor(int i) {mCurChar += i; mPos += i;} // i can be <0. void MoveToEndOfLine() {mPos = mCurLine.size();} - bool MoveUntil(const char*); + bool MoveUntil(const char*); bool Good() { return mDefFile.good(); } bool EndOfLine() {return mPos == mCurLine.size();} diff --git a/src/MapleFE/shared/include/lexer.h b/src/MapleFE/shared/include/lexer.h index 4dfd0e1abc052b006f5856f9ad3e247c8614812d..00a3f708629d9e8e8d347b56e6e942b241c768fb 100644 --- a/src/MapleFE/shared/include/lexer.h +++ b/src/MapleFE/shared/include/lexer.h @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -46,6 +46,7 @@ public: TokenPool mTokenPool; unsigned mPredefinedTokenNum; // number of predefined tokens. bool mTrace; + bool mLineMode; // Lex just one line public: FILE *srcfile; @@ -54,6 +55,7 @@ public: ssize_t current_line_size; uint32_t curidx; uint32_t _linenum; + uint32_t _total_linenum; // total line number of the file bool endoffile; int ReadALine(); // read a line from def file. @@ -73,7 +75,11 @@ public: } } - void SetTrace() {mTrace = true;} + void SetTrace() {mTrace = true;} + bool GetTrace() {return mTrace;} + + void SetLineMode() {mLineMode = true;} + void ResetLineMode(){mLineMode = false;} bool EndOfLine() { return curidx == current_line_size; } bool EndOfFile() { return endoffile; } @@ -81,7 +87,7 @@ public: void ResetPos(); void PrepareForFile(const std::string filename); - void PrepareForString(const std::string &src); + void PrepareForString(const char *); int GetCuridx() const { return curidx; } void SetCuridx(int i) { curidx = i; } @@ -98,6 +104,11 @@ public: friend class Parser; + // These two functions are both due to weird literal or template literal + // in script language which allows \n directly in their literals. + void ClearLeadingNewLine(); // clear the leading \n in line. + void AddEndingNewLine(); // add the ending \n in a line. + // These are for autogen table testing Token* LexToken(); // always return token until end of file. Token* LexTokenNoNewLine(); // try to get token untile end of line. @@ -108,24 +119,29 @@ public: // They won't move 'curidx' if target is not hit. /////////////////////////////////////////////////////////////////////////////////// - SepId GetSeparator(); - OprId GetOperator(); - LitData GetLiteral(); - const char* GetKeyword(); - const char* GetIdentifier(); - bool GetComment(); + SepId GetSeparator(); + OprId GetOperator(); + LitData GetLiteral(); + const char* GetKeyword(); + const char* GetIdentifier(); + bool GetComment(); + + Token* FindRegExprToken(); + + // For most languages, this does nothing. TS/JS are doing something. + virtual bool CharIsSeparator(const char c) {return false;} + + virtual TempLitData* GetTempLit() {return NULL;} + virtual bool FindNextTLFormat(unsigned start, std::string& s, unsigned& end) {return false;} + virtual bool FindNextTLPlaceHolder(unsigned start, std::string& s, unsigned& end) {return false;} + + virtual bool FindTripleSlash() {return false;} // replace keyword/opr/sep... with tokens //void PlantTokens(); //void PlantTraverseRuleTable(RuleTable*); //void PlantTraverseTableData(TableData*); - // - Token* FindSeparatorToken(SepId id); - Token* FindOperatorToken(OprId id); - Token* FindKeywordToken(const char *key); - Token* FindCommentToken(); - // When we start walk a rule table to find a token, do we need check if // the following data is a separator? bool mCheckSeparator; diff --git a/src/MapleFE/shared/include/log.h b/src/MapleFE/shared/include/log.h index 9e5cb2f8aab714adfd4c7a53f94111f2950a55b3..1130cfc96091d4d06010da5dbb6f10fcf70ba8a7 100644 --- a/src/MapleFE/shared/include/log.h +++ b/src/MapleFE/shared/include/log.h @@ -13,7 +13,7 @@ * See the Mulan PSL v2 for more details. */ ///////////////////////////////////////////////////////////////////// -// Log file +// Log file // ///////////////////////////////////////////////////////////////////// @@ -34,7 +34,7 @@ private: std::ofstream mFile; public: - typedef enum { + typedef enum Level { LOG_NONE, LOG_DEBUG, LOG_INFO, @@ -42,10 +42,10 @@ public: LOG_ERROR, LOG_FATAL }Level; - + Log() {mFile.open("log");} ~Log(){mFile.close();} - + Log& operator<<(float f); Log& operator<<(int i); diff --git a/src/MapleFE/shared/include/mempool.h b/src/MapleFE/shared/include/mempool.h index c7a85ff0de8f4988468fb3645053cb7eb6119680..3112dafdc3b22f7882cee0daa02d74ca10f25cff 100644 --- a/src/MapleFE/shared/include/mempool.h +++ b/src/MapleFE/shared/include/mempool.h @@ -50,9 +50,6 @@ struct Block { Block *prev; // prev block }; -// So far there is nothing like free list. Everything will be released when -// StaticMemPool is destructed. -// class MemPool{ protected: Block *mCurrBlock; // Currently available block @@ -67,7 +64,8 @@ public: char* Alloc(unsigned); void Release(unsigned i); // release the last occupied i bytes. - void Clear(); // remove all data, but keep memory. + void WipeOff(int c = 0); // wipe off all data with c + void Clear(); // free up all block, dont wipe data, Keep memory. void Release(); // Allow users to free memory explicitly. }; diff --git a/src/MapleFE/shared/include/parser.h b/src/MapleFE/shared/include/parser.h index da040f8e7478857dc490779cc8051c133af7f8f2..5b4a1072bc48fd4bce6da0d79d0ffe37756fbfdb 100644 --- a/src/MapleFE/shared/include/parser.h +++ b/src/MapleFE/shared/include/parser.h @@ -1,7 +1,8 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. +* Copyright 2022 Tencent. All rights reverved. * -* OpenArkFE is licensed under the Mulan PSL v2. +* MapleFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * @@ -23,10 +24,12 @@ #include "lexer.h" #include "ast_module.h" +#include "ast_builder.h" #include "container.h" #include "recursion.h" #include "succ_match.h" -#include "gen_summary.h" +#include "rule_summary.h" +#include "appnode_pool.h" namespace maplefe { @@ -38,14 +41,17 @@ class TableData; class ASTTree; class TreeNode; -typedef enum { +typedef enum AppealStatus { FailWasFailed, FailNotRightToken, + FailNotRightString, FailNotIdentifier, FailNotLiteral, + FailNotRegExpr, FailChildrenFailed, Fail2ndOf1st, FailLookAhead, + FailASI, // Succ : Really does the matching, will be saved in SuccMatch // SuccWasSucc : Was matched, not tried traversal for a second timewill, @@ -54,13 +60,21 @@ typedef enum { // in RecurionNodes where it does multiple instances of // traversal. But it doesn't make any change compared // to the last real Succ. It will NOT be saved in SuccMatch + // SuccASI: TS/JS auto-semicolon-insert Succ, SuccWasSucc, SuccStillWasSucc, + SuccASI, AppealStatus_NA }AppealStatus; +typedef enum { + ParseSucc, + ParseFail, + ParseEOF +} ParseStatus; + // As in Left Recursion scenario, a rule can have multiple matches on a start token. // Each AppealNode represents an instance in the recursion, and it matches different // number of tokens. However, truth is the parent nodes matches more than children @@ -68,14 +82,21 @@ typedef enum { class AppealNode{ private: - // In theory a tree shouldn't merge. But we do allow merge in the recursion - // parsing. mParent is the first level parent. mSecondParents are second level, and - // they are used during manipulation at certain phases like connecting instances - // of recursion. However, after SortOut, only mParent is valid. AppealNode *mParent; - SmallVector mSecondParents; + + // We do allow the tree to merge in the recursion parsing. + // they are used during manipulation at certain phases like connecting instances + // of recursion, if a recursion have multiple cycles with one same leading node. + // The leading node will be connected multiple times. See ConnectPrevious(). + // + // However, in sort out, we traverse from parent to child, and these 'secondary' + // parents are never used. So, I decided not to have dedicated data structure to + // record these 'second' parents. + // + // SmallVector mSecondParents; unsigned mStartIndex; // index of start matching token + unsigned mChildIndex; // index as a child in the parent rule table. bool mSorted; // already sorted out? bool mIsPseudo; // A pseudo node, mainly used for sub trees connection // It has no real program meaning, but can be used @@ -92,15 +113,14 @@ private: TreeNode *mAstTreeNode; // The AST tree node of this AppealNode. public: - unsigned GetSecondParentsNum() {return mSecondParents.GetNum();} - AppealNode* GetSecondParent(unsigned i) {return mSecondParents.ValueAtIndex(i);} - void ClearSecondParents() {mSecondParents.Clear();} AppealNode* GetParent() {return mParent;} void SetParent(AppealNode *n) {mParent = n;} void AddParent(AppealNode *n); - unsigned GetStartIndex() {return mStartIndex;} - void SetStartIndex(unsigned i){mStartIndex = i;} + unsigned GetStartIndex() {return mStartIndex;} + void SetStartIndex(unsigned i){mStartIndex = i;} + unsigned GetChildIndex() {return mChildIndex;} + void SetChildIndex(unsigned i){mChildIndex = i;} bool IsPseudo() {return mIsPseudo;} void SetIsPseudo(){mIsPseudo = true;} @@ -117,6 +137,7 @@ public: unsigned GetMatchNum() {return mMatches.GetNum();} unsigned GetMatch(unsigned i) {return mMatches.ValueAtIndex(i);} + void ClearMatch() {mMatches.Clear();} void AddMatch(unsigned i); unsigned LongestMatch(); // find the longest match. bool FindMatch(unsigned m); // if 'm' exists? @@ -125,12 +146,6 @@ public: public: bool mIsTable; // A AppealNode could relate to either rule table or token. - unsigned int mSimplifiedIndex; // After SimplifyShrinkEdges, a node could be moved to - // connect to a new 'parent' node, replacing its ancestor. - // To make AST building work, it needs to inherit ancestor's - // index in the rule table. - -public: union { RuleTable *mTable; Token *mToken; @@ -143,7 +158,7 @@ public: Token *mAltToken; // The alt token it matches. - std::vector mChildren; + SmallVector mChildren; // I use an additional vector for the sorted out children. Why do we have two duplicated // children vectors? The reason is coming from sortout. After SortOut we need remove some @@ -154,28 +169,30 @@ public: // During AST tree generation, for the SuccWasSucc child we need find the original matching // tree. That means the original mChildren vector needs to be traversed to locate that tree. // So we keep mChildren untouched and define a second vector for the SortOut-ed children. - std::vector mSortedChildren; + SmallVector mSortedChildren; // A Succ mResult doesn't mean 'really' matching tokens. e.g. Zeroorxxx rules could // match nothing, but it is succ. AppealStatus mResult; AppealNode() {mData.mTable=NULL; mParent = NULL; - mResult = AppealStatus_NA; mSimplifiedIndex = 0; mIsTable = true; + mResult = AppealStatus_NA; mIsTable = true; mStartIndex = 0; mSorted = false; mFinalMatch = 0; m1stAltTokenMatched = false; mAltToken = NULL; - mIsPseudo = false; mAstTreeNode = NULL; mAstCreated = false;} - ~AppealNode(){mMatches.Release();} + mIsPseudo = false; mAstTreeNode = NULL; mAstCreated = false; + mChildIndex = 0; + // These two don't need big memory. So set block size to 128. + mChildren.SetBlockSize(128); mSortedChildren.SetBlockSize(128); } + ~AppealNode() {Release();} + void Release(){mMatches.Release(); mChildren.Release(); mSortedChildren.Release();} - void AddChild(AppealNode *n) { mChildren.push_back(n); } - void RemoveChild(AppealNode *n); - void ClearChildren() { mChildren.clear(); } + void AddChild(AppealNode *n) { mChildren.PushBack(n); } + void ClearChildren() { mChildren.Clear(); } void ReplaceSortedChild(AppealNode *existing, AppealNode *replacement); - void AddSortedChild(AppealNode *n) { mSortedChildren.push_back(n); } - bool GetSortedChildIndex(AppealNode*, unsigned &); - AppealNode* GetSortedChildByIndex(unsigned idx); - AppealNode* FindSpecChild(TableData *tdata, unsigned match); + void AddSortedChild(AppealNode *n) { mSortedChildren.PushBack(n); } + AppealNode* GetSortedChild(unsigned idx); + AppealNode* FindIndexedChild(unsigned match, unsigned index); bool IsSucc() { return (mResult == Succ) || (mResult == SuccWasSucc) || @@ -195,11 +212,6 @@ public: void SetToken(Token *t) { mIsTable = false; mData.mToken = t; } RuleTable* GetTable() { return mData.mTable; } Token* GetToken() { return mData.mToken; } - - bool SuccEqualTo(AppealNode*); - - // If 'this' is a descendant of 'p'. - bool DescendantOf(AppealNode *p); }; class RecursionTraversal; @@ -215,14 +227,22 @@ struct RecStackEntry { } }; +//////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////// + class Parser { -private: +protected: friend class RecursionTraversal; // Matching on alternative tokens needs a state machine. - bool mInAltTokensMatching; // once it's true, mCurToken is frozen. - unsigned mNextAltTokenIndex; // index of next alt token to be matched. - unsigned mATMToken; // the current input token being processed. + bool mInAltTokensMatching; // once it's true, mCurToken is frozen. + unsigned mNextAltTokenIndex; // index of next alt token to be matched. + unsigned mATMToken; // the current input token being processed. + ModuleNode *mASTModule; // the AST Module + ASTBuilder *mASTBuilder; // the AST Builder + + AppealNodePool mAppealNodePool; public: Lexer *mLexer; @@ -242,16 +262,24 @@ public: bool mTracePatchWasSucc; // trace patching was succ node. bool mTraceWarning; // print the warning. + TreeNode *mNormalModeRoot;// For NormalMode, the root node after BuildAST. + + TreeNode *mLineModeRoot; // For LineMode, the root node after BuildAST. + bool mLineMode; // LineMode is for parsing a single line of source code. + // It could be from a string in memory, or read from URL. + // It's common in dynamic loading of code in web application. + void SetLexerTrace() {mLexer->SetTrace();} void DumpIndentation(); void DumpEnterTable(const char *tablename, unsigned indent); void DumpExitTable(const char *tablename, unsigned indent, AppealNode*); + void DumpExitTable(const char *tablename, unsigned indent, AppealStatus, AppealNode *n = NULL); void DumpAppeal(RuleTable *table, unsigned token); void DumpSuccTokens(AppealNode*); void DumpSortOut(AppealNode *root, const char * /*hint*/); void DumpSortOutNode(AppealNode*); -private: +public: SmallVector mActiveTokens; // vector for tokens during matching. unsigned mCurToken; // index in mActiveTokens, the next token to be matched. unsigned mPending; // index in mActiveTokens, the first pending token. @@ -262,22 +290,26 @@ private: void UpdateSuccInfo(unsigned, AppealNode*); bool TraverseStmt(); + bool TraverseTempLiteral(); bool TraverseRuleTable(RuleTable*, AppealNode*, AppealNode *&); bool TraverseRuleTableRegular(RuleTable*, AppealNode*); - bool TraverseRuleTablePre(AppealNode*); bool TraverseTableData(TableData*, AppealNode*, AppealNode *&); bool TraverseConcatenate(RuleTable*, AppealNode*); bool TraverseOneof(RuleTable*, AppealNode*); bool TraverseZeroormore(RuleTable*, AppealNode*); bool TraverseZeroorone(RuleTable*, AppealNode*); + virtual bool TraverseASI(RuleTable*, AppealNode*, AppealNode *&) {return false;} // There are some special cases we can speed up the traversal. // 1. If the target is a token, we just need compare mCurToken with it. // 2. If the target is a special rule table, like literal, identifier, we just // need check the type of mCurToken. + bool TraverseStringSucc(Token*, AppealNode*, AppealNode *&); bool TraverseToken(Token*, AppealNode*, AppealNode *&); bool TraverseLiteral(RuleTable*, AppealNode*); bool TraverseIdentifier(RuleTable*, AppealNode*); + bool TraverseTemplateLiteral(RuleTable*, AppealNode*); + bool TraverseRegularExpression(RuleTable*, AppealNode*); void TraverseSpecialTableSucc(RuleTable*, AppealNode*); bool IsVisited(RuleTable*); @@ -295,6 +327,7 @@ private: bool MoveCurToken(); // move mCurToken one step. Token* GetActiveToken(unsigned); // Get an active token. + void InsertToken(unsigned, Token*); // // Appealing System std::vector mAppealNodes; @@ -324,8 +357,19 @@ private: void SupplementalSortOut(AppealNode *root, AppealNode *target); // Build AST, for each top level construct. - ASTTree* BuildAST(); - + TreeNode* BuildAST(); + // We need a set of functions to deal with some common manipulations of + // most languages during AST Building. You can disable it if some functions + // are not what you want. + TreeNode* NewTreeNode(AppealNode*); + TreeNode* Manipulate(AppealNode*); + TreeNode* Manipulate2Binary(TreeNode*, TreeNode*); + TreeNode* Manipulate2Cast(TreeNode*, TreeNode*); + TreeNode* BuildBinaryOperation(TreeNode *, TreeNode *, OprId); + TreeNode* BuildPassNode(); + + // Handle TemplateLiteralNodes + void ParseTemplateLiterals(); ////////////////////////////////////////////////////////////// // The following section is all about left recursion parsing @@ -348,15 +392,30 @@ public: ~Parser(); void SetVerbose(int i) { mLexer->SetVerbose(i); } - int GetVerbose() { mLexer->GetVerbose(); } + int GetVerbose() { return mLexer->GetVerbose(); } + + ModuleNode* GetModule() {return mASTModule;} void Dump(); bool Parse(); - bool ParseStmt(); + ParseStatus ParseStmt(); + void InitRecursion(); unsigned LexOneLine(); + + bool TokenMerge(Token *); + + // These are language specific. + virtual bool TokenSplit(Token *) {return false;} + virtual Token* GetRegExpr(Token *t) {return t;} }; +// Each language will have its own implementation of lexer. Most of lexer +// are shared with some special functions being language specific. +// +// The implementation of this function is in lang/src/lang_spec.cpp. +extern Lexer* CreateLexer(); + } #endif diff --git a/src/MapleFE/shared/include/parser_rec.h b/src/MapleFE/shared/include/parser_rec.h index bc64dfb455cbb1ebc16ce066ce49bc3750488883..bd79654e3d31e1ad1d2f15b31613052c9df37b69 100644 --- a/src/MapleFE/shared/include/parser_rec.h +++ b/src/MapleFE/shared/include/parser_rec.h @@ -42,7 +42,7 @@ public: public: RecPath(){}; ~RecPath() {mPath.Release();} - + }; enum RecTraInstance { @@ -82,7 +82,7 @@ private: // // In each iteration, the first time a LeadNode is visited, it will be saved // in this vector. The second time it's visited, it should go to connect - // with the node in the previous instance. + // with the node in the previous instance or set as Failed2ndOf1st. SmallVector mVisitedLeadNodes; // Visited Recursion Node. This is a per-iteration data too. diff --git a/src/MapleFE/shared/include/recursion.h b/src/MapleFE/shared/include/recursion.h index c60575600ddfe6ebc0ec4d2d112e7ece575edf91..20e19e421fae6838f12601b36da880ab50c9e039 100644 --- a/src/MapleFE/shared/include/recursion.h +++ b/src/MapleFE/shared/include/recursion.h @@ -32,7 +32,7 @@ namespace maplefe { struct LeftRecursion { RuleTable *mRuleTable; unsigned mNum; // How many recursions - unsigned **mCircles; // + unsigned **mCircles; // }; extern LeftRecursion **gLeftRecursions; // diff --git a/src/MapleFE/shared/include/rule_summary.h b/src/MapleFE/shared/include/rule_summary.h new file mode 100644 index 0000000000000000000000000000000000000000..e6803bcd73b5f35eb5b870cb2e33d32d6c272942 --- /dev/null +++ b/src/MapleFE/shared/include/rule_summary.h @@ -0,0 +1,73 @@ +/* +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. +* Copyright 2022 Tencent. All rights reverved. +* +* MapleFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#ifndef __RULE_SUMMARY_H__ +#define __RULE_SUMMARY_H__ +#include "ruletable.h" +#include "succ_match.h" +#include "token.h" +namespace maplefe { +typedef struct { + const RuleTable *mAddr; + const char *mName; + unsigned mIndex; +}RuleTableSummary; +extern RuleTableSummary gRuleTableSummarys[]; +extern unsigned RuleTableNum; +extern const char* GetRuleTableName(const RuleTable*); +class BitVector; +extern BitVector gFailed[]; +class SuccMatch; +extern SuccMatch gSucc[]; +extern unsigned gTopRulesNum; +extern RuleTable* gTopRules[]; + +// The rule tables of autogen reserved rules. +extern RuleTable TblCHAR; +extern RuleTable TblDIGIT; +extern RuleTable TblASCII; +extern RuleTable TblESCAPE; +extern RuleTable TblHEXDIGIT; +extern RuleTable TblUTF8; +extern RuleTable TblIRREGULAR_CHAR; + +extern RuleTable TblNoLineTerminator; +extern RuleTable TblTemplateLiteral; +extern RuleTable TblRegularExpression; +extern RuleTable TblExpression; +extern RuleTable TblType; + +// +extern RuleTable TblIdentifier; +extern RuleTable TblLiteral; +extern RuleTable TblIntegerLiteral; +extern RuleTable TblFPLiteral; +extern RuleTable TblBooleanLiteral; +extern RuleTable TblCharacterLiteral; +extern RuleTable TblStringLiteral; +extern RuleTable TblNullLiteral; + +// The tokens defined by system +extern unsigned gSystemTokensNum; +extern unsigned gOperatorTokensNum; +extern unsigned gSeparatorTokensNum; +extern unsigned gKeywordTokensNum; +extern Token gSystemTokens[]; +extern unsigned gAltTokensNum; +extern AltToken gAltTokens[]; + +} +#endif diff --git a/src/MapleFE/shared/include/ruletable.h b/src/MapleFE/shared/include/ruletable.h index b671bc95f73671792d056b72931f931250b234e9..2464e7c6eaaafaf414c2420b5780d9f3a72e63e7 100644 --- a/src/MapleFE/shared/include/ruletable.h +++ b/src/MapleFE/shared/include/ruletable.h @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -14,7 +14,7 @@ */ ////////////////////////////////////////////////////////////////////////// // This file contains all the information to describe the tables that -// autogen creates. +// autogen creates. ////////////////////////////////////////////////////////////////////////// #ifndef __RULE_TABLE_H__ @@ -36,21 +36,23 @@ namespace maplefe { // keyword, separator, operator with tokens. This happens in memory. // The reason we need token is to save the time of matching a rule. Lexer // returns a set of tokens, so it's faster if parts of a rule are tokens -// to compare. +// to compare. /////////////////////////////////////////////////////////////////////////// // The list of RuleTable Entry types -typedef enum { +typedef enum EntryType { ET_Oneof, // one of (...) ET_Zeroormore, // zero or more of (...) ET_Zeroorone, // zero or one ( ... ) ET_Concatenate,// Elem + Elem + Elem + ET_ASI, // Typescript Auto-Semicolon-Insertion. This is to + // parse the missing simicolon of TS/JS ET_Data, // data, further categorized into DT_Char, DT_String, ... ET_Null }EntryType; // List of data types -typedef enum { +typedef enum DataType { DT_Char, // It's a literal elements, char, 'c'. DT_String, // It's a literal elements, string "abc". DT_Type, // It's a type id @@ -97,6 +99,8 @@ enum RuleProp { // match, and it's ok. However, some concatenate rules do require // certain sub-rules NOT to match the longest so that the later // sub-rules can match, and so the whole rule. + RP_NoAltToken = 16, // don't do alternative token matching for some special tokens + // inside the current rule. }; // A rule has a limited set of beginning tokens. These are called LookAhead. @@ -117,7 +121,7 @@ enum LAType { struct LookAhead { LAType mType; // the type of look ahead union{ - char mChar; + unsigned char mChar; const char *mString; unsigned mTokenId; }mData; @@ -153,6 +157,8 @@ struct TypeKeyword { const char *mText; TypeId mId; }; +extern TypeKeyword TypeKeywordTable[]; +extern unsigned TypeKeywordTableSize; ////////////////////////////////////////////////////////////////////// // Attribute Table // @@ -163,6 +169,8 @@ struct AttrKeyword { const char *mText; AttrId mId; }; +extern AttrKeyword AttrKeywordTable[]; +extern unsigned AttrKeywordTableSize; ////////////////////////////////////////////////////////////////////// // Separator Table // @@ -174,6 +182,8 @@ struct SepTableEntry { const char *mText; SepId mId; }; +extern SepTableEntry SepTable[]; +extern unsigned SepTableSize; ////////////////////////////////////////////////////////////////////// // Operator Table // @@ -185,6 +195,8 @@ struct OprTableEntry { const char *mText; OprId mId; }; +extern OprTableEntry OprTable[]; +extern unsigned OprTableSize; ////////////////////////////////////////////////////////////////////// // Keyword Table // @@ -195,6 +207,8 @@ struct OprTableEntry { struct KeywordTableEntry { const char *mText; }; +extern KeywordTableEntry KeywordTable[]; +extern unsigned KeywordTableSize; } #endif diff --git a/src/MapleFE/shared/include/ruletable_util.h b/src/MapleFE/shared/include/ruletable_util.h index 618b9ea6f53f8e982bef2058265978fca359e8bd..851feb3ea37a4e98ab90486910d5a96b2c8cc6ee 100644 --- a/src/MapleFE/shared/include/ruletable_util.h +++ b/src/MapleFE/shared/include/ruletable_util.h @@ -46,7 +46,7 @@ namespace maplefe { // The most straightforward idea is to put the function pointers in the rule table // with additional information. However, the signatures of a function makes the idea // complicated. -// +// // So I finally decided to have an Id for each check function, and Id is written into // the rule tables by Autogen. diff --git a/src/MapleFE/shared/include/stringmap.h b/src/MapleFE/shared/include/stringmap.h index cbfc6ca0f3264346552073612246bd06090fefa2..66fe263e81b040fe88d8663bc47dd3937044b7ac 100644 --- a/src/MapleFE/shared/include/stringmap.h +++ b/src/MapleFE/shared/include/stringmap.h @@ -16,7 +16,7 @@ // // StringMap is heavily used in the StringPool. It's used to locate the address // of string in the StringPool. Here is how it works: -// (1) std::string ---> Hash value, --> Locate the Bucket in StringMap +// (1) std::string ---> Hash value, --> Locate the Bucket in StringMap // --> get the addr from StringMapEntry // (2) If conflicted in the Bucket, iterate to find the right StringMapEntry // (3) If not found, a) Add std::string to the StringPool @@ -38,13 +38,17 @@ class StringPool; class StringMapEntry { public: char *Addr; // Addr in the string pool - StringMapEntry *Next; + unsigned StrIdx; // String index + StringMapEntry *Next; public: - StringMapEntry() { Addr = NULL; Next = NULL; } - StringMapEntry(char *A) { Addr = A; Next = NULL; } - StringMapEntry(char *A, StringMapEntry *E) { Addr = A; Next = E; } + StringMapEntry() { Addr = NULL; StrIdx = 0; Next = NULL; } + StringMapEntry(char *A, unsigned idx) { Addr = A; StrIdx = idx; Next = NULL; } + StringMapEntry(char *A, unsigned idx, StringMapEntry *E) { Addr = A; StrIdx = idx; Next = E; } ~StringMapEntry() {} + + char *GetAddr() { return Addr; } + unsigned GetStrIdx() { return StrIdx; } }; class StringMap { @@ -62,8 +66,8 @@ public: void SetPool(StringPool *p) {mPool = p;} unsigned BucketNoFor(const std::string &s); - char* LookupAddrFor(const std::string &s); - void InsertEntry(char *, unsigned); + StringMapEntry *LookupEntryFor(const std::string &s); + StringMapEntry *InsertEntry(char *, unsigned, unsigned); }; } diff --git a/src/MapleFE/shared/include/stringpool.h b/src/MapleFE/shared/include/stringpool.h index da076c9df949007d46dc8bd6427d3591fd9ae007..fd8dfee8ab8012e29a2bf5586db57f588e7d1721 100644 --- a/src/MapleFE/shared/include/stringpool.h +++ b/src/MapleFE/shared/include/stringpool.h @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -23,7 +23,10 @@ #include #include +#include +#include #include +#include "massert.h" namespace maplefe { @@ -44,21 +47,52 @@ private: StringMap *mMap; std::vector mBlocks; int mFirstAvail; // -1 means no available. + bool mUseAltStr; // use alter string + + std::vector mLongStrings; // for strings longer than block size, + // we allocate them by malloc. + + std::vector mStringTable; + + // alternate string which can be used for obfuscation + std::unordered_set mAltStrIdxSet; + std::unordered_map mAltStrIdxMap; + + friend class StringMap; public: + StringPool(); + ~StringPool(); + + void SetUseAltStr(bool b) { mUseAltStr = b; } + void AddAltStrIdx(unsigned idx) { mAltStrIdxSet.insert(idx); } + unsigned GetAltStrSize() { return mAltStrIdxSet.size(); } + bool IsAltStrIdx(unsigned idx) { + return mAltStrIdxSet.find(idx) != mAltStrIdxSet.end(); + } + void AddAltStrIdxMap(unsigned orig, unsigned alt) { mAltStrIdxMap[orig] = alt; } + void SetAltStrIdxMap(); + char* AllocBlock(); char* Alloc(const size_t); char* Alloc(const std::string&); char* Alloc(const char*); -public: - StringPool(); - ~StringPool(); - // If not found, add into StringPool const char* FindString(const std::string&); const char* FindString(const char*); const char* FindString(const char*, size_t); + + unsigned GetStrIdx(const std::string&); + unsigned GetStrIdx(const char*); + unsigned GetStrIdx(const char*, size_t); + + unsigned GetSize() {return mStringTable.size();} + + const char *GetStringFromStrIdx(unsigned idx); + + void Dump(); + void DumpAlt(); }; // Lexing, Parsing, AST Building and IR Building all share one global diff --git a/src/MapleFE/shared/include/stringutil.h b/src/MapleFE/shared/include/stringutil.h index b0b66a32775d6401c8986e2e9be95c4533ea1880..83b5000f7ab44e2a760291119308688d2b950485 100644 --- a/src/MapleFE/shared/include/stringutil.h +++ b/src/MapleFE/shared/include/stringutil.h @@ -31,7 +31,7 @@ namespace maplefe { // http://license.coscl.org.cn/MulanPSL2 static inline unsigned HashString(const std::string &s) { unsigned Result = 0; - for (size_t i = 0; i < s.size(); i++) + for (size_t i = 0; i < s.size(); i++) Result = Result * 33 + (unsigned char)s[i]; return Result; } diff --git a/src/MapleFE/shared/include/succ_match.h b/src/MapleFE/shared/include/succ_match.h index bfe143e66d32dd57ffed591c059e0b9b6eb7879d..648dc0be294fdb3a04afba79679b5ecb3596c819 100644 --- a/src/MapleFE/shared/include/succ_match.h +++ b/src/MapleFE/shared/include/succ_match.h @@ -1,7 +1,8 @@ /* * Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright 2022 Tencent. All rights reverved. * -* OpenArkFE is licensed under the Mulan PSL v2. +* MapleFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * @@ -37,7 +38,7 @@ namespace maplefe { // on every recursion group in a wavefront manner. Although after each iteration of // the wavefront we got succ/fail info, but it's not complete yet. This field tells // if we have reached the fixed point or not. -// +// // The second 'unsigned' in mMatches is not used, since putting IsDone in mNodes // is enough. // @@ -47,8 +48,8 @@ namespace maplefe { class AppealNode; class SuccMatch { private: - Guamian mNodes; - Guamian mMatches; + GuamianFast mNodes; + GuamianFast mMatches; public: SuccMatch(){} diff --git a/src/MapleFE/shared/include/supported.h b/src/MapleFE/shared/include/supported.h index 9ed0f51d2601ccfb2dac1a7a58bf83367c737218..2b1e6ad41d92056dc07bdb83cfd66f1e5428be2c 100644 --- a/src/MapleFE/shared/include/supported.h +++ b/src/MapleFE/shared/include/supported.h @@ -24,8 +24,10 @@ namespace maplefe { // The list of all supported types. This covers all the languages. // NOTE: autogen also relies on this set of supported separators #undef TYPE +#undef PRIMTYPE #define TYPE(T) TY_##T, -typedef enum { +#define PRIMTYPE(T) TY_##T, +typedef enum TypeId { #include "supported_types.def" TY_NA }TypeId; @@ -34,7 +36,7 @@ TY_NA // NOTE: autogen also relies on this set of supported separators #undef SEPARATOR #define SEPARATOR(T) SEP_##T, -typedef enum { +typedef enum SepId { #include "supported_separators.def" SEP_NA }SepId; @@ -43,16 +45,16 @@ SEP_NA // NOTE: autogen also relies on this set of supported operators. #undef OPERATOR #define OPERATOR(T, D) OPR_##T, -typedef enum { +typedef enum OprId { #include "supported_operators.def" OPR_NA }OprId; #define LITERAL(T) LT_##T, -typedef enum { +typedef enum LitId { #include "supported_literals.def" LT_NA // N/A, in java, Null is legal type with only one value 'null' - // reference, a literal. So LT_Null is actually legal. + // reference, a literal. So LT_Null is actually legal. // So I put LT_NA for the illegal literal }LitId; @@ -64,7 +66,6 @@ enum AttrId { ATTR_NA }; - // TODO: The action id will come from both the shared part and language specific part. // Some language may have its own special action to build AST. // For now I just put everything together in order to expediate the overall diff --git a/src/MapleFE/shared/include/supported_actions.def b/src/MapleFE/shared/include/supported_actions.def index 30ca48756cfeb342538e299d4c8b04bbccc4537b..ef4710d3862514ff281d00f5f277cbf93d708a66 100644 --- a/src/MapleFE/shared/include/supported_actions.def +++ b/src/MapleFE/shared/include/supported_actions.def @@ -28,29 +28,96 @@ // It also shows the internal parameters when parser creates the AST tree node. // Please refer autogen/README.ACTIONS for details. +ACTION(BuildModule) +ACTION(AddModuleBody) +ACTION(SetIsAmbient) + ACTION(BuildPackageName) // These are about import/include ACTION(BuildSingleTypeImport) // style like java single type import ACTION(BuildAllTypeImport) // style like java ondemand type import ACTION(BuildSingleStaticImport) // style like java single static import -ACTION(BuildAllStaticImport) // style like java ondemand static import +ACTION(BuildAllStaticImport) // style like java on-demand static import ACTION(BuildAllImport) // style like c/c++ include all in .h file +ACTION(BuildExternalDeclaration) // c/c++ external decl, typescript declare. +ACTION(BuildGlobalExternalDeclaration) // typescript global declare. + +// Special actions for JS import/export +ACTION(BuildImport) +ACTION(BuildExport) +ACTION(SetIsXXportType) +ACTION(SetPairs) +ACTION(SetDefaultPairs) +ACTION(SetSinglePairs) +ACTION(SetFromModule) +ACTION(SetIsEverything) // Apply to all pairs in import/export +ACTION(SetAsNamespace) // Apply to all pairs in import/export + +ACTION(BuildXXportAsPair) // normal pair +ACTION(BuildXXportAsPairEverything) // '*' +ACTION(BuildXXportAsPairDefault) // 'default' + + ACTION(BuildBlock) ACTION(AddToBlock) +ACTION(AddSyncToBlock) // Java allows a sync obj to block + +ACTION(BuildAwait) ACTION(BuildCast) ACTION(BuildParenthesis) ACTION(BuildBinaryOperation) ACTION(BuildUnaryOperation) +ACTION(BuildTernaryOperation) ACTION(BuildPostfixOperation) +ACTION(BuildInstanceOf) +ACTION(BuildIn) +ACTION(BuildIs) +ACTION(BuildTypeOf) +ACTION(BuildKeyOf) +ACTION(BuildInfer) + ACTION(BuildLambda) +ACTION(SetJavaLambda) // java lambda +ACTION(SetArrowFunction) // JS arrow function + +// This is very special function, it changes other +// keyword, attr node or anything into a new identifier node +ACTION(BuildIdentifier) + +ACTION(BuildLiteral) // For variable declaration, expression ACTION(BuildDecl) +ACTION(SetJSVar) +ACTION(SetJSLet) +ACTION(SetJSConst) + ACTION(BuildField) ACTION(BuildVarList) +ACTION(BuildComputedName) + +ACTION(BuildBindingElement) +ACTION(BuildBindingPattern) +ACTION(SetObjectBinding) +ACTION(SetArrayBinding) + +// For struct +ACTION(BuildStruct) +ACTION(SetTSInterface) +ACTION(SetTSEnum) +ACTION(AddStructField) +ACTION(BuildFieldLiteral) +ACTION(BuildStructLiteral) + +ACTION(BuildStrIndexSig) +ACTION(BuildNumIndexSig) + +// For Array +ACTION(BuildArrayElement) +ACTION(BuildArrayLiteral) // For function ACTION(AddParams) @@ -58,6 +125,13 @@ ACTION(BuildFunction) ACTION(BuildConstructor) ACTION(AddFunctionBody) ACTION(AddFunctionBodyTo) +ACTION(SetGetAccessor) // TS 'get' accessor +ACTION(SetSetAccessor) // TS 'set' accessor +ACTION(SetCallSignature) // TS call signature +ACTION(SetConstructSignature) // TS construct signature +ACTION(SetIsGenerator) // JS generator +ACTION(SetIsIterator) // JS iterator +ACTION(AddAssert) // For callsite ACTION(BuildCall) @@ -72,10 +146,15 @@ ACTION(AddSuperInterface) ACTION(AddClassBody) ACTION(BuildInstInit) +ACTION(BuildNamespace) +ACTION(AddNamespaceBody) + ACTION(AddModifier) ACTION(AddModifierTo) +ACTION(AddInit) ACTION(AddInitTo) -ACTION(AddTypeTo) +ACTION(AddType) +ACTION(AddAsType) // Annotation. ACTION(BuildAnnotationType) @@ -92,6 +171,17 @@ ACTION(BuildDims) ACTION(AddDims) ACTION(AddDimsTo) +// Set a tree node as ... properties +ACTION(SetIsStmt) +ACTION(SetIsOptional) +ACTION(SetIsNonNull) +ACTION(SetIsRest) +ACTION(SetIsConst) +ACTION(SetIsUnique) + +ACTION(BuildYield) +ACTION(SetIsTransfer) + // statment, control flow ACTION(BuildAssignment) ACTION(BuildAssert) @@ -101,7 +191,10 @@ ACTION(AddCondBranchTrueStatement) ACTION(AddCondBranchFalseStatement) ACTION(AddLabel) ACTION(BuildBreak) +ACTION(BuildContinue) ACTION(BuildForLoop) +ACTION(BuildForLoop_In) //This is Javascript, for (.. in ..){} +ACTION(BuildForLoop_Of) //This is Javascript, for (.. of ..){} ACTION(BuildWhileLoop) ACTION(BuildDoLoop) ACTION(BuildNewOperation) @@ -110,13 +203,41 @@ ACTION(BuildDeleteOperation) ACTION(BuildSwitchLabel) ACTION(BuildDefaultSwitchLabel) ACTION(BuildOneCase) -ACTION(BuildAllCases) ACTION(BuildSwitch) // Exceptions, Throws ACTION(BuildThrows) ACTION(AddThrowsTo) +// Try, Catch, Finally +ACTION(BuildTry) +ACTION(BuildCatch) +ACTION(BuildFinally) +ACTION(AddCatch) +ACTION(AddFinally) + // User Types ACTION(BuildUserType) -ACTION(AddTypeArgument) +ACTION(BuildTupleType) // Comes from Typescript. +ACTION(AddTypeGenerics) // add type arguments or type parameters or type generics +ACTION(BuildUnionUserType) // build union type +ACTION(BuildInterUserType) // build intersect type +ACTION(BuildArrayType) // From Spec point of view, + // In languages like TS, dimension info is attached to type. + // In C/C++, dimension info is attached to identifier. + // However, the AST design is up to each implementation. +ACTION(BuildNeverArrayType) // Special 'never' array type. + +ACTION(BuildTypeAlias) +ACTION(BuildAsType) +ACTION(BuildConditionalType) + +ACTION(BuildTypeParameter) +ACTION(AddTypeParameterExtends) + +ACTION(BuildNameTypePair) + +ACTION(BuildTripleSlash) // TS triple-slash directive. + +// This is a special action to pass a child to parent +ACTION(PassChild) diff --git a/src/MapleFE/shared/include/supported_attributes.def b/src/MapleFE/shared/include/supported_attributes.def index 789de310f700b762f4ad4767e933e4a266aefe1b..86cc52600ea92b50476cd939557b8f7b454150ac 100644 --- a/src/MapleFE/shared/include/supported_attributes.def +++ b/src/MapleFE/shared/include/supported_attributes.def @@ -27,3 +27,8 @@ ATTRIBUTE(public) ATTRIBUTE(static) ATTRIBUTE(strictfp) ATTRIBUTE(default) +ATTRIBUTE(synchronized) +ATTRIBUTE(async) +ATTRIBUTE(readonly) // Typescript +ATTRIBUTE(getter) // Javascript getter function +ATTRIBUTE(setter) // Javascript setter function diff --git a/src/MapleFE/shared/include/supported_literals.def b/src/MapleFE/shared/include/supported_literals.def index 5bcf1a4f1353113fa837622cd83be46873a8554c..7ad1d28105b9ce2485cb6a90e5850ea2554fa430 100644 --- a/src/MapleFE/shared/include/supported_literals.def +++ b/src/MapleFE/shared/include/supported_literals.def @@ -26,4 +26,5 @@ LITERAL(CharacterLiteral) LITERAL(StringLiteral) LITERAL(NullLiteral) LITERAL(ThisLiteral) - +LITERAL(SuperLiteral) +LITERAL(VoidLiteral) diff --git a/src/MapleFE/shared/include/supported_operators.def b/src/MapleFE/shared/include/supported_operators.def index 7b96ce06c84e8e4bb3075af322ac198f9214569f..2ffa34dd44fa1f53b361757b863c4d9ae861e8b4 100644 --- a/src/MapleFE/shared/include/supported_operators.def +++ b/src/MapleFE/shared/include/supported_operators.def @@ -15,6 +15,12 @@ // This file defines the operators supported by AutoGen and MapleFE +// NOTE +// 1. Add/Sub will be used as binary only after AST building. +// Plus/Minus will be the unary +// 2. Inc/Dec will be used as post after AST building. +// PreInc/PreDec will be pre operators. + OPERATOR(Add, Binary|Unary) OPERATOR(Sub, Binary|Unary) OPERATOR(Mul, Binary) @@ -23,6 +29,13 @@ OPERATOR(Mod, Binary) OPERATOR(Inc, Pre|Post) OPERATOR(Dec, Pre|Post) +OPERATOR(Exp, Binary) + +OPERATOR(Plus, Unary) +OPERATOR(Minus, Unary) +OPERATOR(PreInc, Pre) +OPERATOR(PreDec, Pre) + OPERATOR(EQ, Binary) OPERATOR(NE, Binary) OPERATOR(GT, Binary) @@ -57,10 +70,16 @@ OPERATOR(BxorAssign, Binary) OPERATOR(ZextAssign, Binary) OPERATOR(Arrow, Binary) -OPERATOR(Select, Ternary) -OPERATOR(Cond, Ternary) - // In Java, there is a special type argument, <>, meaning no arguments. // It could appear in other languages. So I define Diamond. OPERATOR(Diamond, Unary) + +// This part comes from JS/TS +OPERATOR(StEq, Binary) +OPERATOR(StNe, Binary) +OPERATOR(ArrowFunction, Binary) +OPERATOR(NullCoalesce, Binary) +OPERATOR(NullAssign, Binary) +OPERATOR(TripleSlash, Binary) // triple slash directive + diff --git a/src/MapleFE/shared/include/supported_separators.def b/src/MapleFE/shared/include/supported_separators.def index a179c40679834dda7a12331f1e6fc44c0829b9d2..40298b4bb0afe66cac276efaf21fae8da10eff0d 100644 --- a/src/MapleFE/shared/include/supported_separators.def +++ b/src/MapleFE/shared/include/supported_separators.def @@ -25,8 +25,12 @@ SEPARATOR(Semicolon) SEPARATOR(Comma) SEPARATOR(Dot) SEPARATOR(Dotdotdot) -SEPARATOR(Colon) +SEPARATOR(Select) // ? +SEPARATOR(Colon) // : SEPARATOR(Of) SEPARATOR(At) SEPARATOR(Pound) SEPARATOR(Whitespace) +SEPARATOR(Tab) // Horizontal Tab, 0x09 +SEPARATOR(ArrowFunction) // first coming from JS, => +SEPARATOR(Optional) // first coming from JS, ?. diff --git a/src/MapleFE/shared/include/supported_types.def b/src/MapleFE/shared/include/supported_types.def index df5a396d5641b0055c2cf84ca54f63d8276310fd..c16bd4a934d49783017babb74231ece08d02a74d 100644 --- a/src/MapleFE/shared/include/supported_types.def +++ b/src/MapleFE/shared/include/supported_types.def @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -16,14 +16,40 @@ // This file defines the complete set of primitive types supported in Autogen // and the parser. -TYPE(Boolean) -TYPE(Byte) -TYPE(Short) -TYPE(Int) -TYPE(Long) -TYPE(Char) -TYPE(Float) -TYPE(Double) +TYPE(None) + +PRIMTYPE(Boolean) +PRIMTYPE(Byte) +PRIMTYPE(Short) +PRIMTYPE(Int) +PRIMTYPE(Long) +PRIMTYPE(Char) +PRIMTYPE(Float) +PRIMTYPE(Double) + +// keep these two after primitive types as we are going to create +// primitive types for them as well +TYPE(Number) // First come from JS +TYPE(String) // First come from JS + TYPE(Void) // Although this is not a type, it does categorize the types. TYPE(Null) // The Null type. It is a type. +TYPE(Unknown) // First come from TS 3.0 +TYPE(Never) // First come from TS +TYPE(Undefined) // First come from JS +TYPE(Symbol) // First come from JS +TYPE(Any) // First come from JS +TYPE(Date) + +TYPE(Array) +TYPE(Object) +TYPE(Function) // function/lambda decl +TYPE(Class) // class/interface decl +TYPE(Module) // import/export module +TYPE(Namespace) // namespace +TYPE(User) // user types +TYPE(Merge) // merge of two types, unexpected + +// last entry +TYPE(Max) diff --git a/src/MapleFE/shared/include/token.h b/src/MapleFE/shared/include/token.h index 71e9119486fbdf2448ff1f218ed36b3c04984ec9..f2406ee14ead46ea4581bf5a584ed6531026a84a 100644 --- a/src/MapleFE/shared/include/token.h +++ b/src/MapleFE/shared/include/token.h @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -30,20 +30,24 @@ #ifndef __Token_H__ #define __Token_H__ +#include #include #include "char.h" #include "stringutil.h" #include "supported.h" +#include "container.h" namespace maplefe { -typedef enum { +typedef enum TK_Type { TT_ID, // Identifier TT_KW, // Keyword TT_LT, // Literal TT_SP, // separator TT_OP, // operator TT_CM, // comment + TT_TL, // template literal. coming from Javascript first. + TT_RE, // regular expression, coming from most script languages. TT_NA // N.A. }TK_Type; @@ -59,12 +63,13 @@ typedef enum { struct LitData { LitId mType; union { - int mInt; + long mInt; float mFloat; double mDouble; bool mBool; Char mChar; - const char *mStr; // the string is allocated in gStringPool + unsigned mStrIdx; // the string is allocated in gStringPool + int64_t mInt64; // for serialization }mData; }; @@ -90,13 +95,36 @@ struct AltToken { unsigned mAltTokenId; }; +// We define the data of template literal token. +// TemplateLiteral data contains: formate and placeholder. +// They are saved as pair . If either is missing, NULL +// is saved in its position. +struct TempLitData { + SmallVector mStrings; +}; + +// Regular expressions have two data. One is the expression, +// the other is the flags. Both are saved as strings. +struct RegExprData { + const char *mExpr; + const char *mFlags; +}; + struct Token { TK_Type mTkType; + + unsigned mLineNum; // line num + unsigned mColNum; // column num + bool mLineBegin; // first token of line? + bool mLineEnd; // last token of line? + union { const char *mName; // Identifier, Keyword. In the gStringPool LitData mLitData; SepId mSepId; OprId mOprId; + TempLitData *mTempLitData; + RegExprData mRegExprData; }mData; AltToken *mAltTokens; @@ -107,17 +135,34 @@ struct Token { bool IsLiteral() const { return mTkType == TT_LT; } bool IsKeyword() const { return mTkType == TT_KW; } bool IsComment() const { return mTkType == TT_CM; } + bool IsTempLit() const { return mTkType == TT_TL; } + bool IsRegExpr() const { return mTkType == TT_RE; } void SetIdentifier(const char *name) {mTkType = TT_ID; mData.mName = name;} void SetLiteral(LitData data) {mTkType = TT_LT; mData.mLitData = data;} + void SetTempLit(TempLitData *data) {mTkType = TT_TL; mData.mTempLitData = data;} + void SetRegExpr(RegExprData data) {mTkType = TT_RE; mData.mRegExprData = data;} + + const char* GetName() const; + LitData GetLitData() const {return mData.mLitData;} + OprId GetOprId() const {return mData.mOprId;} + SepId GetSepId() const {return mData.mSepId;} + bool IsWhiteSpace() const {return mData.mSepId == SEP_Whitespace;} + bool IsTab() const {return mData.mSepId == SEP_Tab;} + TempLitData* GetTempLitData() const {return mData.mTempLitData;} + RegExprData GetRegExpr() const {return mData.mRegExprData;} + + // This is handle only Operator, Separator, and Keyword. All others return false. + bool Equal(Token *); - const char* GetName() const; - LitData GetLitData() const {return mData.mLitData;} - OprId GetOprId() const {return mData.mOprId;} - SepId GetSepId() const {return mData.mSepId;} - bool IsWhiteSpace() const {return mData.mSepId == SEP_Whitespace;} void Dump(); }; + // + Token* FindSeparatorToken(SepId id); + Token* FindOperatorToken(OprId id); + Token* FindKeywordToken(const char *key); + Token* FindCommentToken(); + } #endif diff --git a/src/MapleFE/shared/include/typetable.h b/src/MapleFE/shared/include/typetable.h new file mode 100644 index 0000000000000000000000000000000000000000..d53b17719156f086fefca6fbc7d2f9ec02844e92 --- /dev/null +++ b/src/MapleFE/shared/include/typetable.h @@ -0,0 +1,91 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ +////////////////////////////////////////////////////////////////////////////// +// This file contains the Memory Pool for String pool. // +// // +// A String is stored in the pool with an ending '\0'. // +////////////////////////////////////////////////////////////////////////////// + +#ifndef __TYPETABLE_H__ +#define __TYPETABLE_H__ + +#include +#include +#include +#include +#include "massert.h" +#include "ast.h" +#include "ast_type.h" + +namespace maplefe { + +class TypeEntry { + private: + TreeNode *mType; + TypeId mTypeId; + + public: + TypeEntry() : mType(NULL), mTypeId(TY_None) {} + TypeEntry(TreeNode *node); + ~TypeEntry(){}; + + TypeId GetTypeId() { return mTypeId; } + TreeNode *GetType() { return mType; } + + void SetTypeId(TypeId i) { mTypeId = i; } + void SetType(TreeNode *n) { mType = n; } +}; + +class TypeTable { +private: + std::vector mTypeTable; + std::unordered_map mNodeId2TypeIdxMap; + std::unordered_map mTypeId2TypeMap; + std::unordered_set mPrimTypeId; + std::unordered_set mFuncTypeIdx; + unsigned mPrimSize; + unsigned mPreBuildSize; + +public: + TypeTable() {}; + ~TypeTable() { mTypeTable.clear(); }; + + unsigned size() { return mTypeTable.size(); } + unsigned GetPreBuildSize() { return mPreBuildSize; } + + bool IsPrimTypeId(TypeId tid) { return mPrimTypeId.find(tid) != mPrimTypeId.end(); } + unsigned GetPrimSize() { return mPrimSize; } + TreeNode *CreatePrimType(std::string name, TypeId tid); + TreeNode *CreateBuiltinType(std::string name, TypeId tid); + + void AddPrimTypeId(TypeId tid); + void AddPrimAndBuiltinTypes(); + bool AddType(TreeNode *node); + + TypeEntry *GetTypeEntryFromTypeIdx(unsigned tidx); + TreeNode *GetTypeFromTypeIdx(unsigned tidx); + TreeNode *GetTypeFromTypeId(TypeId tid) { return mTypeId2TypeMap[tid]; } + TreeNode *GetTypeFromStrIdx(unsigned strid); + + unsigned GetOrCreateFunctionTypeIdx(FunctionTypeNode *type); + + void Dump(); +}; + +extern TypeTable gTypeTable; + + +} +#endif // __TYPETABLE_H__ diff --git a/src/MapleFE/shared/include/vfy.h b/src/MapleFE/shared/include/vfy.h index 208fbac48e56d9d79723eab468e09b3ab29761b9..279052d38eae4bf06f6a70f8b8bf7a5f37921741 100644 --- a/src/MapleFE/shared/include/vfy.h +++ b/src/MapleFE/shared/include/vfy.h @@ -18,7 +18,7 @@ // which takes an ASTModule recently generated. At this point we have a complete // module with AST trees created by ASTBuilder. // -// The verification is a top-down traversal on the AST trees. +// The verification is a top-down traversal on the AST trees. // // It carries on more than one jobs. // Verification : Checks the validity of semanteme @@ -41,6 +41,7 @@ #include "ast.h" #include "ast_attr.h" #include "ast_type.h" +#include "ast_module.h" #include "container.h" #include "vfy_log.h" @@ -51,7 +52,8 @@ class TreeNode; class Verifier { protected: - VfyLog mLog; + VfyLog mLog; + ModuleNode *mASTModule; ASTScope *mCurrScope; @@ -72,7 +74,7 @@ protected: virtual void VerifyType(IdentifierNode*); public: - Verifier(); + Verifier(ModuleNode *m); ~Verifier(); void Do(); diff --git a/src/MapleFE/shared/src/Makefile b/src/MapleFE/shared/src/Makefile index 0ee1fc974c86b0f241dedbf40cd28ac587716001..e09a8359da282bcbcfa5eb587cfb226eff3a9939 100644 --- a/src/MapleFE/shared/src/Makefile +++ b/src/MapleFE/shared/src/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# Copyright (C) [2020-2021] Futurewei Technologies, Inc. All rights reverved. # # OpenArkFE is licensed under the Mulan PSL v2. # You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -24,24 +24,36 @@ OBJS :=$(foreach obj,$(OBJ), $(BUILD)/$(obj)) LIBOBJS :=$(patsubst $(BUILD)/main.o,,$(OBJS)) DEPS :=$(foreach dep,$(DEP), $(BUILD)/$(dep)) -INCLUDES := -I $(MAPLEFE_ROOT)/shared/include \ - -I $(MAPLEFE_ROOT)/$(LANG)/include \ - -I . $(MAPLEALL_INC) +GENDIR:=${BUILDDIR}/gen -SHAREDLIB = shared.a +SRCG:=$(wildcard ${GENDIR}/gen_*.cpp) +OBJG:=$(patsubst %.cpp,%.o,$(SRCG)) +DEPG:=$(patsubst %.cpp,%.d,$(SRCG)) -.PHONY: all -all: $(SHAREDLIB) +GENASTDIR:=${BUILDDIR}/ast_gen/shared + +ASTSRCG:=$(wildcard ${GENASTDIR}/*.cpp) +ASTOBJG:=$(patsubst %.cpp,%.o,$(ASTSRCG)) +ASTDEPG:=$(patsubst %.cpp,%.d,$(ASTSRCG)) + +INCLUDES := -I $(MAPLEFE_ROOT)/shared/include -I ${GENASTDIR} -I ${GENDIR} + +SHAREDLIB := shared.a +GENASTLIB := genast.a +GENLIB := gen.a + +.PHONY: all gen_doc clean + +all: $(BUILD)/$(SHAREDLIB) $(GENASTDIR)/$(GENASTLIB) $(GENDIR)/$(GENLIB) -include $(DEPS) -.PHONY: clean vpath %.o $(BUILD) vpath %.d $(BUILD) #Pattern Rules $(BUILD)/%.o : %.cpp - $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ $(BUILD)/%.d : %.cpp @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $< > $@ @@ -49,8 +61,31 @@ $(BUILD)/%.d : %.cpp @sed -e 's|.*:|$(BUILD)/$*.o:|' < $(BUILD)/$*.d.tmp > $(BUILD)/$*.d @rm -f $(BUILD)/$*.d.tmp -$(SHAREDLIB) : $(OBJS) +$(GENASTDIR)/%.cpp : gendoc + +gen_doc: + (cd $(MAPLEFE_ROOT); ./scripts/maplefe-autogen.py) + +$(GENASTDIR)/%.o : $(GENASTDIR)/%.cpp + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ + +$(GENASTDIR)/%.d : $(GENASTDIR)/%.cpp + @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $< > $@ + +$(GENDIR)/%.o : $(GENDIR)/%.cpp + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ + +$(GENDIR)/%.d : $(GENDIR)/%.cpp + @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $< > $@ + +$(BUILD)/$(SHAREDLIB) : $(LIBOBJS) /usr/bin/ar rcs $(BUILD)/$(SHAREDLIB) $(LIBOBJS) +$(GENASTDIR)/$(GENASTLIB) : $(ASTOBJG) + /usr/bin/ar rcs $(GENASTDIR)/$(GENASTLIB) $(ASTOBJG) + +$(GENDIR)/$(GENLIB) : $(OBJG) + /usr/bin/ar rcs $(GENDIR)/$(GENLIB) $(OBJG) + clean: rm -rf $(BUILD) diff --git a/src/MapleFE/autogen/include/block_gen.h b/src/MapleFE/shared/src/appnode_pool.cpp similarity index 54% rename from src/MapleFE/autogen/include/block_gen.h rename to src/MapleFE/shared/src/appnode_pool.cpp index d2fbf1a80990fba82bf22399f9032a21c2bd280a..a2014c6148fb925f6a2f33eafa9efd9213d4af04 100644 --- a/src/MapleFE/autogen/include/block_gen.h +++ b/src/MapleFE/shared/src/appnode_pool.cpp @@ -12,28 +12,15 @@ * FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. */ -//////////////////////////////////////////////////////////////// -// Block Generation -//////////////////////////////////////////////////////////////// - -#ifndef __BLOCK_GEN_H__ -#define __BLOCK_GEN_H__ - -#include "base_gen.h" +#include "appnode_pool.h" +#include "parser.h" namespace maplefe { -class BlockGen : public BaseGen { -public: - BlockGen(const char *dfile, const char *hfile, const char *cfile) : - BaseGen(dfile, hfile, cfile) {} - ~BlockGen(){} - - void Generate(); - void GenCppFile(); - void GenHeaderFile(); -}; - +AppealNode* AppealNodePool::NewAppealNode() { + AppealNode *node = (AppealNode*)mMP.Alloc(sizeof(AppealNode)); + new (node) AppealNode(); + return node; } -#endif +} diff --git a/src/MapleFE/shared/src/ast.cpp b/src/MapleFE/shared/src/ast.cpp index d33f7a7669a0975e4bef3bf5acb229b8672c1140..f42e21d7ff0442a6825f5ca3dcb6e92968630f91 100644 --- a/src/MapleFE/shared/src/ast.cpp +++ b/src/MapleFE/shared/src/ast.cpp @@ -54,228 +54,26 @@ static const char* GetOperatorName(OprId opr) { }; ////////////////////////////////////////////////////////////////////////////////////// -// ASTTree -////////////////////////////////////////////////////////////////////////////////////// - -ASTTree::ASTTree() { - mRootNode = NULL; - gASTBuilder.SetTreePool(&mTreePool); -} - -ASTTree::~ASTTree() { -} - -// Create tree node. Its children have been created tree nodes. -// There are couple issueshere. -// -// 1. An sorted AppealNode could have NO tree node, because it may have NO RuleAction to -// create the sub tree. This happens if the RuleTable is just a temporary intermediate -// table created by Autogen, or its rule is just ONEOF without real syntax. Here -// is an example. -// -// The AST after BuildAST() for a simple statment: c=a+b; -// -// ======= Simplify Trees Dump SortOut ======= -// [1] Table TblExpressionStatement@0: 2,3, -// [2:1] Table TblAssignment@0: 4,5,6, -// [3] Token -// [4:1] Token -// [5:2] Token -// [6:3] Table TblArrayAccess_sub1@2: 7,8, <-- supposed to get a binary expression -// [7:1] Token <-- a -// [8:2] Table TblUnaryExpression_sub1@3: 9,10, <-- +b -// [9] Token -// [10:2] Token -// -// Node [1] won't have a tree node at all since it has no Rule Action attached. -// Node [6] won't have a tree node either. -// -// 2. A binary operation like a+b could be parsed as (1) expression: a, and (2) a -// unary operation: +b. This is because we parse them in favor to ArrayAccess before -// Binary Operation. Usually to handle this issue, in some system like ANTLR, -// they require you to list the priority, by writing rules from higher priority to -// lower priority. -// -// We are going to do a consolidation of the sub-trees, by converting smaller trees -// to a more compact bigger trees. However, to do this we want to set some rules. -// *) The parent AppealNode of these sub-trees has no tree node. So the conversion -// helps make the tree complete. - -TreeNode* ASTTree::NewTreeNode(AppealNode *appeal_node) { - TreeNode *sub_tree = NULL; - - if (appeal_node->IsToken()) { - sub_tree = gASTBuilder.CreateTokenTreeNode(appeal_node->GetToken()); - return sub_tree; - } - - RuleTable *rule_table = appeal_node->GetTable(); - - for (unsigned i = 0; i < rule_table->mNumAction; i++) { - Action *action = rule_table->mActions + i; - gASTBuilder.mActionId = action->mId; - gASTBuilder.ClearParams(); - - for (unsigned j = 0; j < action->mNumElem; j++) { - // find the appeal node child - unsigned elem_idx = action->mElems[j]; - AppealNode *child = appeal_node->GetSortedChildByIndex(elem_idx); - Param p; - p.mIsEmpty = true; - // There are 3 cases to handle. - // 1. child is token, we pass the token to param. - // 2. child is a sub appeal tree, but has no legal AST tree. For example, - // a parameter list: '(' + param-lists + ')'. - // if param-list is empty, it has no AST tree. - // In this case, we sset mIsEmpty to true. - // 3. chidl is a sub appeal tree, and has a AST tree too. - if (child) { - TreeNode *tree_node = child->GetAstTreeNode(); - if (!tree_node) { - if (child->IsToken()) { - p.mIsEmpty = false; - p.mIsTreeNode = false; - p.mData.mToken = child->GetToken(); - } - } else { - p.mIsEmpty = false; - p.mIsTreeNode = true; - p.mData.mTreeNode = tree_node; - } - } - gASTBuilder.AddParam(p); - } - - // For multiple actions of a rule, there should be only action which create tree. - // The others are just for adding attribute or else, and return the same tree - // with additional attributes. - sub_tree = gASTBuilder.Build(); - } - - if (sub_tree) - return sub_tree; - - // It's possible that the Rule has no action, meaning it cannot create tree node. - // Now we have to do some manipulation. Please check if you need all of them. - sub_tree = Manipulate(appeal_node); - - // It's possible that the sub tree is actually empty. For example, in a Parameter list - // ( params ). If 'params' is empty, it returns NULL. - - return sub_tree; -} - -// It's possible that we get NULL tree. -TreeNode* ASTTree::Manipulate(AppealNode *appeal_node) { - TreeNode *sub_tree = NULL; +// TreeNode +////////////////////////////////////////////////////////////////////////////////////// - std::vector child_trees; - std::vector::iterator cit = appeal_node->mSortedChildren.begin(); - for (; cit != appeal_node->mSortedChildren.end(); cit++) { - AppealNode *a_node = *cit; - TreeNode *t_node = a_node->GetAstTreeNode(); - if (t_node) - child_trees.push_back(t_node); - } +void TreeNode::AddAsTypes(TreeNode *type) { + if (!type) + return; - // If we have one and only one child's tree node, we take it. - if (child_trees.size() == 1) { - sub_tree = child_trees[0]; - if (sub_tree) - return sub_tree; - else - MERROR("We got a broken AST tree, not connected sub tree."); - } - - // For the tree having two children, there are a few approaches to further - // manipulate them in order to obtain better AST. - // - // 1. There are cases like (type)value, but they are not recoganized as cast. - // Insteand they are seperated into two nodes, one is (type), the other value. - // So we define ParenthesisNode for (type), and build a CastNode over here. - // - // 2. There are cases like a+b could be parsed as "a" and "+b", a symbol and a - // unary operation. However, we do prefer binary operation than unary. So a - // combination is needed here, especially when the parent node is NULL. - if (child_trees.size() == 2) { - TreeNode *child_a = child_trees[0]; - TreeNode *child_b = child_trees[1]; - - sub_tree = Manipulate2Cast(child_a, child_b); - if (sub_tree) - return sub_tree; - - sub_tree = Manipulate2Binary(child_a, child_b); - if (sub_tree) - return sub_tree; - } - - // In the end, if we still have no suitable solution to create the tree, - // we will put subtrees into a PassNode to pass to parent. - if (child_trees.size() > 0) { - PassNode *pass = (PassNode*)BuildPassNode(); - std::vector::iterator child_it = child_trees.begin(); - for (; child_it != child_trees.end(); child_it++) - pass->AddChild(*child_it); - return pass; - } - - // It's possible that we get a Null tree. - return sub_tree; -} - -TreeNode* ASTTree::Manipulate2Cast(TreeNode *child_a, TreeNode *child_b) { - if (child_a->IsParenthesis()) { - ParenthesisNode *type = (ParenthesisNode*)child_a; - CastNode *n = (CastNode*)mTreePool.NewTreeNode(sizeof(CastNode)); - new (n) CastNode(); - n->SetDestType(type->GetExpr()); - n->SetExpr(child_b); - return n; - } - return NULL; -} - -TreeNode* ASTTree::Manipulate2Binary(TreeNode *child_a, TreeNode *child_b) { - if (child_b->IsUnaOperator()) { - UnaOperatorNode *unary = (UnaOperatorNode*)child_b; - unsigned property = GetOperatorProperty(unary->GetOprId()); - if ((property & Binary) && (property & Unary)) { - std::cout << "Convert unary --> binary" << std::endl; - TreeNode *unary_sub = unary->GetOpnd(); - TreeNode *binary = BuildBinaryOperation(child_a, unary_sub, unary->GetOprId()); - return binary; - } + if (type->IsPass()) { + PassNode *pass_node = (PassNode*)type; + for (unsigned i = 0; i < pass_node->GetChildrenNum(); i++) + AddAsTypes(pass_node->GetChild(i)); + } else if (type->IsAsType()) { + AsTypeNode *asn = (AsTypeNode*)type; + AddAsType(asn); + SETPARENT(asn); + } else { + MERROR("unsupported as-type in AddAsType."); } - return NULL; -} - -void ASTTree::Dump(unsigned indent) { - DUMP0("== Sub Tree =="); - mRootNode->Dump(indent); - std::cout << std::endl; -} - -TreeNode* ASTTree::BuildBinaryOperation(TreeNode *childA, TreeNode *childB, OprId id) { - BinOperatorNode *n = (BinOperatorNode*)mTreePool.NewTreeNode(sizeof(BinOperatorNode)); - new (n) BinOperatorNode(id); - n->mOpndA = childA; - n->mOpndB = childB; - childA->SetParent(n); - childB->SetParent(n); - return n; } -TreeNode* ASTTree::BuildPassNode() { - PassNode *n = (PassNode*)mTreePool.NewTreeNode(sizeof(PassNode)); - new (n) PassNode(); - return n; -} - -////////////////////////////////////////////////////////////////////////////////////// -// TreeNode -////////////////////////////////////////////////////////////////////////////////////// - // return true iff: // both are type nodes, either UserTypeNode or PrimTypeNode, and // they are type equal. @@ -318,19 +116,231 @@ void TreeNode::DumpIndentation(unsigned ind) { void PackageNode::Dump(unsigned indent) { DumpIndentation(indent); DUMP0_NORETURN("package "); - DUMP0_NORETURN(mName); + mPackage->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// DeclareNode +////////////////////////////////////////////////////////////////////////////////////// + +void DeclareNode::AddDecl(TreeNode *t) { + if (!t) + return; + + if (t->IsPass()) { + PassNode *n = (PassNode*)t; + for (unsigned i = 0; i < n->GetChildrenNum(); i++) { + TreeNode *child = n->GetChild(i); + AddDecl(child); + } + } else { + mDecls.PushBack(t); + SETPARENT(t); + } +} + +void DeclareNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("declare "); + + for (unsigned i = 0; i < mDecls.GetNum(); i++) { + TreeNode *tree = mDecls.ValueAtIndex(i); + tree->Dump(0); + } } ////////////////////////////////////////////////////////////////////////////////////// // ImportNode ////////////////////////////////////////////////////////////////////////////////////// +void ImportNode::AddPair(TreeNode *t) { + if (t->IsPass()) { + PassNode *n = (PassNode*)t; + for (unsigned i = 0; i < n->GetChildrenNum(); i++) { + TreeNode *child = n->GetChild(i); + AddPair(child); + } + } else if (t->IsXXportAsPair()) { + mPairs.PushBack((XXportAsPairNode*)t); + SETPARENT(t); + } else { + // We create a new pair to save 't'. + XXportAsPairNode *n = (XXportAsPairNode*)gTreePool.NewTreeNode(sizeof(XXportAsPairNode)); + new (n) XXportAsPairNode(); + n->SetBefore(t); + mPairs.PushBack(n); + SETPARENT(n); + } +} + +void ImportNode::AddDefaultPair(TreeNode *t) { + if (t->IsPass()) { + PassNode *n = (PassNode*)t; + for (unsigned i = 0; i < n->GetChildrenNum(); i++) { + TreeNode *child = n->GetChild(i); + AddDefaultPair(child); + } + } else if (t->IsXXportAsPair()) { + XXportAsPairNode *p = (XXportAsPairNode*)t; + p->SetIsDefault(); + mPairs.PushBack((XXportAsPairNode*)p); + SETPARENT(p); + } else { + // We create a new pair to save 't'. + XXportAsPairNode *n = (XXportAsPairNode*)gTreePool.NewTreeNode(sizeof(XXportAsPairNode)); + new (n) XXportAsPairNode(); + n->SetBefore(t); + n->SetIsDefault(); + mPairs.PushBack(n); + SETPARENT(n); + } +} + +void ImportNode::AddSinglePair(TreeNode *before, TreeNode *after) { + // We create a new pair + XXportAsPairNode *n = (XXportAsPairNode*)gTreePool.NewTreeNode(sizeof(XXportAsPairNode)); + new (n) XXportAsPairNode(); + n->SetBefore(before); + n->SetAfter(after); + n->SetIsSingle(); + mPairs.PushBack(n); + SETPARENT(n); +} + void ImportNode::Dump(unsigned indent) { DumpIndentation(indent); DUMP0_NORETURN("import "); if (IsImportStatic()) DUMP0_NORETURN("static "); - DUMP0_NORETURN(mName); + + if (mPairs.GetNum() > 0) { + DUMP0_NORETURN('{'); + for (unsigned i = 0; i < mPairs.GetNum(); i++) { + XXportAsPairNode *p = GetPair(i); + p->Dump(0); + if (i < mPairs.GetNum() - 1) + DUMP0_NORETURN(','); + } + DUMP0_NORETURN("} "); + } + + if (mTarget) + mTarget->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// ExportNode +////////////////////////////////////////////////////////////////////////////////////// + +void ExportNode::AddPair(TreeNode *t) { + if (t->IsPass()) { + PassNode *n = (PassNode*)t; + for (unsigned i = 0; i < n->GetChildrenNum(); i++) { + TreeNode *child = n->GetChild(i); + AddPair(child); + } + } else if (t->IsXXportAsPair()) { + mPairs.PushBack((XXportAsPairNode*)t); + SETPARENT(t); + } else { + // We create a new pair to save 't'. + XXportAsPairNode *n = (XXportAsPairNode*)gTreePool.NewTreeNode(sizeof(XXportAsPairNode)); + new (n) XXportAsPairNode(); + n->SetBefore(t); + mPairs.PushBack(n); + SETPARENT(n); + } +} + +void ExportNode::AddDefaultPair(TreeNode *t) { + if (t->IsPass()) { + PassNode *n = (PassNode*)t; + for (unsigned i = 0; i < n->GetChildrenNum(); i++) { + TreeNode *child = n->GetChild(i); + AddPair(child); + } + } else if (t->IsXXportAsPair()) { + XXportAsPairNode *p = (XXportAsPairNode*)t; + p->SetIsDefault(); + mPairs.PushBack(p); + SETPARENT(t); + } else { + // We create a new pair to save 't'. + XXportAsPairNode *n = (XXportAsPairNode*)gTreePool.NewTreeNode(sizeof(XXportAsPairNode)); + new (n) XXportAsPairNode(); + n->SetBefore(t); + n->SetIsDefault(); + mPairs.PushBack(n); + SETPARENT(n); + } +} + +void ExportNode::AddSinglePair(TreeNode *before, TreeNode *after) { + // We create a new pair + XXportAsPairNode *n = (XXportAsPairNode*)gTreePool.NewTreeNode(sizeof(XXportAsPairNode)); + new (n) XXportAsPairNode(); + n->SetBefore(before); + n->SetAfter(after); + n->SetIsSingle(); + mPairs.PushBack(n); + SETPARENT(n); +} + +void ExportNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("export "); + if (mIsExportType) + DUMP0_NORETURN("type "); + + if (mPairs.GetNum() > 0) { + DUMP0_NORETURN('{'); + for (unsigned i = 0; i < mPairs.GetNum(); i++) { + XXportAsPairNode *p = GetPair(i); + p->Dump(0); + if (i < mPairs.GetNum() - 1) + DUMP0_NORETURN(','); + } + DUMP0_NORETURN("} "); + } + + if (mTarget) + mTarget->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// XXportAsPair +////////////////////////////////////////////////////////////////////////////////////// + +void XXportAsPairNode::Dump(unsigned indent) { + DumpIndentation(indent); + if (IsEverything()) { + DUMP0_NORETURN(" *"); + if (mBefore) { + DUMP0_NORETURN(" as "); + mBefore->Dump(0); + } + } else if (IsDefault()) { + DUMP0_NORETURN(" default"); + if (mBefore) { + DUMP0_NORETURN(" as "); + mBefore->Dump(0); + } + } else if (IsSingle()) { + DUMP0_NORETURN(" SINGLE "); + if (mBefore) + mBefore->Dump(0); + if (mAfter) { + DUMP0_NORETURN(" as "); + mAfter->Dump(0); + } + } else { + MASSERT(mBefore); + mBefore->Dump(0); + if (mAfter) { + DUMP0_NORETURN(" as "); + mAfter->Dump(0); + } + } } ////////////////////////////////////////////////////////////////////////////////////// @@ -358,15 +368,12 @@ void AnnotationTypeNode::Dump(unsigned indent) { // CastNode ////////////////////////////////////////////////////////////////////////////////////// -const char* CastNode::GetName() { - if (mName) - return mName; +const char* CastNode::GetDumpName() { std::string name = "("; name += mDestType->GetName(); name += ")"; name += mExpr->GetName(); - mName = gStringPool.FindString(name); - return mName; + return gStringPool.FindString(name); } void CastNode::Dump(unsigned indent) { @@ -390,6 +397,19 @@ void AssertNode::Dump(unsigned indent) { mMsg->Dump(0); } +////////////////////////////////////////////////////////////////////////////////////// +// TerOpeartorNode +////////////////////////////////////////////////////////////////////////////////////// + +void TerOperatorNode::Dump(unsigned indent) { + DumpIndentation(indent); + mOpndA->Dump(0); + DUMP0_NORETURN(" ? "); + mOpndB->Dump(0); + DUMP0_NORETURN(" : "); + mOpndC->Dump(0); +} + ////////////////////////////////////////////////////////////////////////////////////// // BinOperatorNode ////////////////////////////////////////////////////////////////////////////////////// @@ -429,11 +449,13 @@ void UnaOperatorNode::Dump(unsigned indent) { const char *name = GetOperatorName(mOprId); DumpIndentation(indent); if (IsPost()) { - mOpnd->Dump(indent + 2); + mOpnd->Dump(0); + DUMP0_NORETURN(' '); DUMP0(name); } else { - DUMP0(name); - mOpnd->Dump(indent + 2); + DUMP0_NORETURN(name); + DUMP0_NORETURN(' '); + mOpnd->Dump(0); } } @@ -441,17 +463,73 @@ void UnaOperatorNode::Dump(unsigned indent) { // FieldNode ////////////////////////////////////////////////////////////////////////////////////// -// Right now it's major work is to init the name -void FieldNode::Init() { - std::string name = mUpper->GetName(); - name += '.'; - name += mField->GetName(); - mName = gStringPool.FindString(name); +void FieldNode::Dump(unsigned indent) { + DumpIndentation(indent); + mUpper->Dump(0); + DUMP0_NORETURN('.'); + mField->Dump(0); } -void FieldNode::Dump(unsigned indent) { +////////////////////////////////////////////////////////////////////////////////////// +// TypeAlias Node +////////////////////////////////////////////////////////////////////////////////////// + +void TypeAliasNode::SetId(UserTypeNode *id) { + mId = id; + SETPARENT(mId); +} + +void TypeAliasNode::SetAlias(TreeNode *n) { + mAlias = n; + SETPARENT(mAlias); +} + +void TypeAliasNode::Dump(unsigned indent) { DumpIndentation(indent); - DUMP0_NORETURN(mName); + DUMP0_NORETURN(" type "); + mId->Dump(0); + DUMP0_NORETURN(" = "); + mAlias->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// ConditionalType Node +////////////////////////////////////////////////////////////////////////////////////// + +void ConditionalTypeNode::Dump(unsigned indent) { + DumpIndentation(indent); + mTypeA->Dump(0); + DUMP0_NORETURN(" extends "); + mTypeB->Dump(0); + DUMP0_NORETURN(" ? "); + mTypeC->Dump(0); + DUMP0_NORETURN(" : "); + mTypeD->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// AsType Node +////////////////////////////////////////////////////////////////////////////////////// + +void AsTypeNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN(" as "); + TreeNode *type = GetType(); + type->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// type parameter & type argument +////////////////////////////////////////////////////////////////////////////////////// + +void TypeParameterNode::Dump(unsigned indent) { + DumpIndentation(indent); + TreeNode *id = GetId(); + DUMP0_NORETURN(id->GetName()); + if (mDefault) { + DUMP0_NORETURN("="); + DUMP0_NORETURN(mDefault->GetName()); + } } ////////////////////////////////////////////////////////////////////////////////////// @@ -464,9 +542,9 @@ void NewNode::ReplaceChild(TreeNode *old_child, TreeNode *new_child) { SetId(new_child); return; } else { - for (unsigned i = 0; i < GetParamsNum(); i++) { - if (GetParam(i) == old_child) - mParams.SetElem(i, new_child); + for (unsigned i = 0; i < GetArgsNum(); i++) { + if (GetArg(i) == old_child) + mArgs.SetElem(i, new_child); } } } @@ -475,30 +553,64 @@ void NewNode::Dump(unsigned indent) { DumpIndentation(indent); DUMP0_NORETURN("new "); TreeNode *id = GetId(); - id->Dump(0); - //DUMP0_NORETURN(id->GetName()); + if (id->IsLambda()) { + LambdaNode *lmd = (LambdaNode*)id; + lmd->Dump(0); + } else { + DUMP0_NORETURN(id->GetName()); + DUMP0_NORETURN("("); + for (unsigned i = 0; i < GetArgsNum(); i++) { + TreeNode *arg = GetArg(i); + arg->Dump(0); + if (i < GetArgsNum() - 1) + DUMP0_NORETURN(","); + } + DUMP0_NORETURN(")"); + } +} + +////////////////////////////////////////////////////////////////////////////////////// +// DeleteNode +////////////////////////////////////////////////////////////////////////////////////// + +void DeleteNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN(" delete "); + if (mExpr) + mExpr->Dump(0); } ////////////////////////////////////////////////////////////////////////////////////// // CallNode ////////////////////////////////////////////////////////////////////////////////////// -void CallNode::Init() { - // Init the mName; - if (mMethod->IsIdentifier() || mMethod->IsField()) { - mName = mMethod->GetName(); +void CallNode::AddTypeArgument(TreeNode *arg) { + if (arg->IsPass()) { + PassNode *n = (PassNode*)arg; + for (unsigned i = 0; i < n->GetChildrenNum(); i++) { + TreeNode *child = n->GetChild(i); + AddTypeArgument(child); + } } else { - MASSERT(0 && "Unsupported method type in CallNode"); + mTypeArguments.PushBack(arg); + SETPARENT(arg); } } -void CallNode::AddArg(TreeNode *arg) { - mArgs.Merge(arg); -} - void CallNode::Dump(unsigned indent) { DumpIndentation(indent); - DUMP0_NORETURN(mName); + mMethod->Dump(0); + if (GetTypeArgumentsNum() > 0) { + DUMP0_NORETURN("<"); + for (unsigned i = 0; i < GetTypeArgumentsNum(); i++) { + TreeNode *arg = GetTypeArgumentAtIndex(i); + arg->Dump(0); + if (i < GetTypeArgumentsNum() - 1) + DUMP0_NORETURN(","); + } + DUMP0_NORETURN(">"); + } + DUMP0_NORETURN("("); mArgs.Dump(0); DUMP0_NORETURN(")"); @@ -515,8 +627,8 @@ void DimensionNode::Merge(const TreeNode *node) { if (node->IsDimension()) { DimensionNode *n = (DimensionNode *)node; - for (unsigned i = 0; i < n->GetDimsNum(); i++) - AddDim(n->GetNthDim(i)); + for (unsigned i = 0; i < n->GetDimensionsNum(); i++) + AddDimension(n->GetDimension(i)); } else if (node->IsPass()) { PassNode *n = (PassNode*)node; for (unsigned i = 0; i < n->GetChildrenNum(); i++) { @@ -532,9 +644,22 @@ void DimensionNode::Merge(const TreeNode *node) { // IdentifierNode ////////////////////////////////////////////////////////////////////////////////////// +void IdentifierNode::Release() { + if (mDims) + mDims->Release(); + mAttrs.Release(); + mAnnotations.Release(); +} + void IdentifierNode::Dump(unsigned indent) { DumpIndentation(indent); - DUMP0_NORETURN(mName); + if (mIsRest) + DUMP0_NORETURN("..."); + DUMP0_NORETURN(GetName()); + if (mIsOptional) + DUMP0_NORETURN('?'); + if (IsNonNull()) + DUMP0_NORETURN('!'); if (mInit) { DUMP0_NORETURN('='); mInit->Dump(0); @@ -546,12 +671,283 @@ void IdentifierNode::Dump(unsigned indent) { } } +////////////////////////////////////////////////////////////////////////////////////// +// DeclNode +////////////////////////////////////////////////////////////////////////////////////// + +void DeclNode::Dump(unsigned indent) { + DumpIndentation(indent); + switch (mProp) { + case JS_Var: + DUMP0_NORETURN("js_var "); + break; + case JS_Let: + DUMP0_NORETURN("js_let "); + break; + case JS_Const: + DUMP0_NORETURN("js_const "); + break; + default: + break; + } + DUMP0_NORETURN("Decl: "); + mVar->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// ArrayElement and ArrayLiteral +////////////////////////////////////////////////////////////////////////////////////// + +void ArrayElementNode::Dump(unsigned indent) { + DumpIndentation(indent); + mArray->Dump(0); + for (unsigned i = 0; i < mExprs.GetNum(); i++) { + DUMP0_NORETURN("["); + mExprs.ValueAtIndex(i)->Dump(0); + DUMP0_NORETURN("]"); + } +} + +void ArrayLiteralNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("["); + for (unsigned i = 0; i < GetLiteralsNum(); i++) { + GetLiteral(i)->Dump(0); + if (i < GetLiteralsNum() - 1) + DUMP0_NORETURN(","); + } + DUMP0_NORETURN("]"); +} + +////////////////////////////////////////////////////////////////////////////////////// +// BindingElement and BindingPattern +////////////////////////////////////////////////////////////////////////////////////// + +void BindingElementNode::Dump(unsigned indent) { + DumpIndentation(indent); + if (mVariable) + mVariable->Dump(0); + DUMP0_NORETURN(":"); + if (mElement) + mElement->Dump(0); +} + +void BindingPatternNode::AddElement(TreeNode *tree) { + if (tree->IsBindingElement() || tree->IsBindingPattern()) { + mElements.PushBack(tree); + SETPARENT(tree); + } else if (tree->IsPass()) { + PassNode *pass = (PassNode*)tree; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { + TreeNode *child = pass->GetChild(i); + AddElement(child); + } + } else { + MERROR("Unsupported element of binding pattern."); + } +} + +void BindingPatternNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("{"); + for (unsigned i = 0; i < mElements.GetNum(); i++) { + TreeNode *elem = GetElement(i); + elem->Dump(0); + if (i != mElements.GetNum()-1) + DUMP0_NORETURN(", "); + } + DUMP0_NORETURN("}"); +} + +////////////////////////////////////////////////////////////////////////////////////// +// StructNode +////////////////////////////////////////////////////////////////////////////////////// + +void StructNode::AddTypeParam(TreeNode *param) { + if (param->IsPass()) { + PassNode *n = (PassNode*)param; + for (unsigned i = 0; i < n->GetChildrenNum(); i++) { + TreeNode *child = n->GetChild(i); + AddTypeParam(child); + } + } else { + MASSERT(param->IsTypeParameter()); + mTypeParams.PushBack((TypeParameterNode*)param); + SETPARENT(param); + } +} + +void StructNode::AddSuper(TreeNode *the_super) { + if (!the_super) + return; + + if (the_super->IsPass()) { + PassNode *pass_node = (PassNode*)the_super; + for (unsigned i = 0; i < pass_node->GetChildrenNum(); i++) + AddSuper(pass_node->GetChild(i)); + } else { + mSupers.PushBack(the_super); + } +} + +// Child could be a field or index signature. +void StructNode::AddChild(TreeNode *field) { + if (field->IsPass()) { + PassNode *pass = (PassNode*)field; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { + TreeNode *child = pass->GetChild(i); + AddChild(child); + } + } else if (field->IsIdentifier() || + field->IsComputedName() || + field->IsLiteral()) { + AddField(field); + SETPARENT(field); + } else if (field->IsFunction()) { + AddMethod((FunctionNode*)field); + SETPARENT(field); + } else if (field->IsNumIndexSig()) { + SetNumIndexSig((NumIndexSigNode*)field); + SETPARENT(field); + } else if (field->IsStrIndexSig()) { + SetStrIndexSig((StrIndexSigNode*)field); + SETPARENT(field); + } else + MERROR("Unsupported struct field type."); +} + +void NumIndexSigNode::Dump(unsigned indent) { + DumpIndentation(indent); + if (mDataType) + mDataType->Dump(0); +} + +void StrIndexSigNode::Dump(unsigned indent) { + DumpIndentation(indent); + if (mDataType) + mDataType->Dump(0); +} + +void StructNode::Dump(unsigned indent) { + DumpIndentation(indent); + switch (mProp) { + case SProp_CStruct: + DUMP0_NORETURN("struct: "); + break; + case SProp_TSInterface: + DUMP0_NORETURN("ts_interface: "); + break; + case SProp_TSEnum: + DUMP0_NORETURN("ts_enum: "); + break; + default: + break; + } + + if (mStructId) + mStructId->Dump(0); + + if (mTypeParams.GetNum() > 0) { + DUMP0_NORETURN("<"); + for (unsigned i = 0; i < mTypeParams.GetNum(); i++) { + TypeParameterNode *node = mTypeParams.ValueAtIndex(i); + node->Dump(0); + DUMP0_NORETURN(","); + } + DUMP0_NORETURN(">"); + } + + DUMP0_NORETURN(" {"); + + if (mNumIndexSig) { + DUMP0_NORETURN("numeric index type: "); + mNumIndexSig->Dump(0); + } + + if (mStrIndexSig) { + DUMP0_NORETURN("string index type: "); + mStrIndexSig->Dump(0); + } + + for (unsigned i = 0; i < mFields.GetNum(); i++) { + mFields.ValueAtIndex(i)->Dump(0); + if (i != mFields.GetNum()-1) + DUMP0_NORETURN(";"); + } + + for (unsigned i = 0; i < mMethods.GetNum(); i++) { + mMethods.ValueAtIndex(i)->Dump(0); + if (i != mMethods.GetNum()-1) + DUMP0_NORETURN(";"); + } + + DUMP0_NORETURN(" }"); +} + +////////////////////////////////////////////////////////////////////////////////////// +// StructLiteralNode +////////////////////////////////////////////////////////////////////////////////////// + +void StructLiteralNode::AddField(TreeNode *tree) { + if (tree->IsFieldLiteral()) { + FieldLiteralNode *fl = (FieldLiteralNode*)tree; + mFields.PushBack(fl); + SETPARENT(fl); + } else if (tree->IsFunction()) { + FunctionNode *node = (FunctionNode*)tree; + FieldLiteralNode *func_lit = (FieldLiteralNode*)gTreePool.NewTreeNode(sizeof(FieldLiteralNode)); + new (func_lit) FieldLiteralNode(); + TreeNode *func_name = node->GetFuncName(); + if (func_name) { + MASSERT(func_name->IsIdentifier() || func_name->IsComputedName()); + func_lit->SetFieldName(func_name); + } + func_lit->SetLiteral(node); + mFields.PushBack(func_lit); + SETPARENT(func_lit); + } else if (tree->IsLiteral() || + tree->IsIdentifier() || + tree->IsField() || + tree->IsCall() || + tree->IsArrayElement()) { + FieldLiteralNode *fln = (FieldLiteralNode*)gTreePool.NewTreeNode(sizeof(FieldLiteralNode)); + new (fln) FieldLiteralNode(); + fln->SetLiteral(tree); + mFields.PushBack(fln); + SETPARENT(fln); + } else if (tree->IsPass()) { + PassNode *pass = (PassNode*)tree; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { + TreeNode *child = pass->GetChild(i); + AddField(child); + } + } else { + MASSERT(0 && "unsupported."); + } +} + +void StructLiteralNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN(" {"); + for (unsigned i = 0; i < mFields.GetNum(); i++) { + FieldLiteralNode *fl = GetField(i); + if (fl->mFieldName) + fl->mFieldName->Dump(0); + DUMP0_NORETURN(":"); + fl->mLiteral->Dump(0); + if (i != mFields.GetNum()-1) + DUMP0_NORETURN(", "); + } + DUMP0_NORETURN("}"); +} + ////////////////////////////////////////////////////////////////////////////////////// // VarListNode ////////////////////////////////////////////////////////////////////////////////////// void VarListNode::AddVar(IdentifierNode *n) { mVars.PushBack(n); + SETPARENT(n); } // Merge a node. @@ -576,7 +972,6 @@ void VarListNode::Merge(TreeNode *n) { void VarListNode::Dump(unsigned indent) { DumpIndentation(indent); - DUMP0_NORETURN("var:"); for (unsigned i = 0; i < mVars.GetNum(); i++) { //DUMP0_NORETURN(mVars.ValueAtIndex(i)->GetName()); mVars.ValueAtIndex(i)->Dump(0); @@ -585,6 +980,36 @@ void VarListNode::Dump(unsigned indent) { } } +////////////////////////////////////////////////////////////////////////////////////// +// NamespaceNode +////////////////////////////////////////////////////////////////////////////////////// + +void NamespaceNode::AddBody(TreeNode *tree) { + if (tree->IsPass()) { + PassNode *p = (PassNode*)tree; + for (unsigned i = 0; i < p->GetChildrenNum(); i++) { + TreeNode *child = p->GetChild(i); + AddBody(child); + } + } else { + AddElement(tree); + SETPARENT(tree); + } +} + +void NamespaceNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("namespace "); + if (mId) + mId->Dump(0); + DUMP_RETURN(); + for (unsigned i = 0; i < mElements.GetNum(); i++) { + DumpIndentation(indent + 2); + mElements.ValueAtIndex(i)->Dump(0); + DUMP_RETURN(); + } +} + ////////////////////////////////////////////////////////////////////////////////////// // ExprListNode ////////////////////////////////////////////////////////////////////////////////////// @@ -594,8 +1019,8 @@ void VarListNode::Dump(unsigned indent) { void ExprListNode::Merge(TreeNode *n) { if (n->IsExprList()) { ExprListNode *expr_list = (ExprListNode*)n; - for (unsigned i = 0; i < expr_list->GetNum(); i++) - AddExpr(expr_list->ExprAtIndex(i)); + for (unsigned i = 0; i < expr_list->GetExprsNum(); i++) + AddExpr(expr_list->GetExprAtIndex(i)); } else if (n->IsPass()) { PassNode *p = (PassNode*)n; for (unsigned i = 0; i < p->GetChildrenNum(); i++) { @@ -606,11 +1031,29 @@ void ExprListNode::Merge(TreeNode *n) { AddExpr(n); } -void ExprListNode::Dump(unsigned indent) { +void ExprListNode::Dump(unsigned indent) { + DumpIndentation(indent); + for (unsigned i = 0; i < mExprs.GetNum(); i++) { + mExprs.ValueAtIndex(i)->Dump(0); + if (i != mExprs.GetNum()-1) + DUMP0_NORETURN(","); + } +} + +////////////////////////////////////////////////////////////////////////////////////// +// TemplateLiteralNode +////////////////////////////////////////////////////////////////////////////////////// + +void TemplateLiteralNode::Dump(unsigned indent) { DumpIndentation(indent); - for (unsigned i = 0; i < mExprs.GetNum(); i++) { - mExprs.ValueAtIndex(i)->Dump(0); - if (i != mExprs.GetNum()-1) + DUMP0_NORETURN(" template-literal: "); + for (unsigned i = 0; i < mTrees.GetNum(); i++) { + TreeNode *n = mTrees.ValueAtIndex(i); + if (n) + n->Dump(0); + else + DUMP0_NORETURN("NULL"); + if (i < mStrings.GetNum() - 1) DUMP0_NORETURN(","); } } @@ -624,11 +1067,11 @@ void LiteralNode::InitName() { switch (mData.mType) { case LT_NullLiteral: s = "null"; - mName = gStringPool.FindString(s); + mStrIdx = gStringPool.GetStrIdx(s); break; case LT_ThisLiteral: s = "this"; - mName = gStringPool.FindString(s); + mStrIdx = gStringPool.GetStrIdx(s); break; case LT_IntegerLiteral: case LT_DoubleLiteral: @@ -639,7 +1082,7 @@ void LiteralNode::InitName() { case LT_NA: default: s = ""; - mName = gStringPool.FindString(s); + mStrIdx = gStringPool.GetStrIdx(s); break; } } @@ -657,7 +1100,9 @@ void LiteralNode::Dump(unsigned indent) { DUMP0_NORETURN(mData.mData.mFloat); break; case LT_StringLiteral: - DUMP0_NORETURN(mData.mData.mStr); + DUMP0_NORETURN("\""); + DUMP0_NORETURN(gStringPool.GetStringFromStrIdx(mData.mData.mStrIdx)); + DUMP0_NORETURN("\""); break; case LT_BooleanLiteral: if(mData.mData.mBool == true) @@ -679,11 +1124,115 @@ void LiteralNode::Dump(unsigned indent) { case LT_ThisLiteral: DUMP0_NORETURN("this"); break; + case LT_SuperLiteral: + DUMP0_NORETURN("super"); + break; + case LT_VoidLiteral: + DUMP0_NORETURN("void"); + break; case LT_NA: default: DUMP0_NORETURN("NA Token:"); break; } + + if (mInit) { + DUMP0_NORETURN(" = "); + mInit->Dump(0); + } +} + +////////////////////////////////////////////////////////////////////////////////////// +// RegExprNode +////////////////////////////////////////////////////////////////////////////////////// + +void RegExprNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP1_NORETURN("reg expr : ", mData.mExpr); + if (mData.mFlags) + DUMP1_NORETURN(" ", mData.mFlags); +} + +////////////////////////////////////////////////////////////////////////////////////// +// ThrowNode +////////////////////////////////////////////////////////////////////////////////////// + +void ThrowNode::AddException(TreeNode *t) { + if (t->IsPass()) { + PassNode *pass_node = (PassNode*)t; + for (unsigned i = 0; i < pass_node->GetChildrenNum(); i++) + AddException(pass_node->GetChild(i)); + } else { + mExceptions.PushBack(t); + SETPARENT(t); + } +} + +void ThrowNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("throw "); + for (unsigned i = 0; i < GetExceptionsNum(); i++) { + TreeNode *t = GetExceptionAtIndex(i); + t->Dump(0); + if (i < GetExceptionsNum() - 1) + DUMP0_NORETURN(", "); + } + DUMP_RETURN(); +} + +////////////////////////////////////////////////////////////////////////////////////// +// Try, Catch, Finally nodes +////////////////////////////////////////////////////////////////////////////////////// + +void TryNode::AddCatch(TreeNode *t) { + if (t->IsPass()) { + PassNode *pass_node = (PassNode*)t; + for (unsigned i = 0; i < pass_node->GetChildrenNum(); i++) + AddCatch(pass_node->GetChild(i)); + } else { + MASSERT(t->IsCatch()); + mCatches.PushBack((CatchNode*)t); + SETPARENT(t); + } +} + +void TryNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("try "); + if (mBlock) + mBlock->Dump(indent + 2); + for (unsigned i = 0; i < GetCatchesNum(); i++) { + CatchNode *c = GetCatchAtIndex(i); + c->Dump(indent); + } + if (mFinally) + mFinally->Dump(indent); +} + +void CatchNode::AddParam(TreeNode *t) { + if (t->IsPass()) { + PassNode *pass_node = (PassNode*)t; + for (unsigned i = 0; i < pass_node->GetChildrenNum(); i++) + AddParam(pass_node->GetChild(i)); + } else { + mParams.PushBack(t); + SETPARENT(t); + } +} + +void CatchNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("catch("); + DUMP0_NORETURN(")"); + if (mBlock) + mBlock->Dump(indent + 2); +} + +void FinallyNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("finally "); + if (mBlock) + mBlock->Dump(indent + 2); } ////////////////////////////////////////////////////////////////////////////////////// @@ -706,13 +1255,20 @@ void ReturnNode::Dump(unsigned ind) { GetResult()->Dump(0); } -CondBranchNode::CondBranchNode() { - mKind = NK_CondBranch; - mCond = NULL; - mTrueBranch = NULL; - mFalseBranch = NULL; +void YieldNode::Dump(unsigned ind) { + DumpLabel(ind); + DumpIndentation(ind); + if (mIsTransfer) + DUMP0_NORETURN("yield* "); + else + DUMP0_NORETURN("yield "); + if (GetResult()) + GetResult()->Dump(0); } +CondBranchNode::CondBranchNode() : TreeNode(NK_CondBranch), + mCond(NULL), mTrueBranch(NULL), mFalseBranch(NULL) {} + void CondBranchNode::Dump(unsigned ind) { DumpLabel(ind); DumpIndentation(ind); @@ -732,11 +1288,61 @@ void CondBranchNode::Dump(unsigned ind) { void BreakNode::Dump(unsigned ind) { DumpLabel(ind); DumpIndentation(ind); - DUMP0_NORETURN("break "); - GetTarget()->Dump(0); + DUMP0_NORETURN("break:"); + if (GetTarget()) + GetTarget()->Dump(0); + DUMP_RETURN(); +} + +void ContinueNode::Dump(unsigned ind) { + DumpLabel(ind); + DumpIndentation(ind); + DUMP0_NORETURN("continue:"); + if (GetTarget()) + GetTarget()->Dump(0); DUMP_RETURN(); } +// 't' could be a decl with multiple var which are contained in +// a pass node. +void ForLoopNode::AddInit(TreeNode *t) { + if (t->IsDecl()) { + DeclNode *decl = (DeclNode*)t; + TreeNode *var = decl->GetVar(); + if (var && var->IsPass()) { + PassNode *pass = (PassNode*)var; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { + DeclNode *n = (DeclNode*)gTreePool.NewTreeNode(sizeof(DeclNode)); + new (n) DeclNode(); + n->SetVar(pass->GetChild(i)); + n->SetProp(decl->GetProp()); + AddInit(n); + } + } else { + mInits.PushBack(t); + SETPARENT(t); + } + } else if (t->IsPass()) { + PassNode *pass = (PassNode*)t; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) + AddInit(pass->GetChild(i)); + } else { + mInits.PushBack(t); + SETPARENT(t); + } +} + +void ForLoopNode::AddUpdate(TreeNode *t) { + if (t->IsPass()) { + PassNode *pass = (PassNode*)t; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) + AddUpdate(pass->GetChild(i)); + } else { + mUpdates.PushBack(t); + SETPARENT(t); + } +} + void ForLoopNode::Dump(unsigned ind) { DumpLabel(ind); DumpIndentation(ind); @@ -771,55 +1377,100 @@ void SwitchLabelNode::Dump(unsigned ind) { } void SwitchCaseNode::AddLabel(TreeNode *t) { - std::list working_list; - working_list.push_back(t); - while (!working_list.empty()) { - TreeNode *t = working_list.front(); - working_list.pop_front(); - if (t->IsPass()) { - PassNode *labels = (PassNode*)t; - for (unsigned i = 0; i < labels->GetChildrenNum(); i++) - working_list.push_back(labels->GetChild(i)); - } else { - MASSERT(t->IsSwitchLabel()); - mLabels.PushBack((SwitchLabelNode*)t); - } + if (t->IsPass()) { + PassNode *pass = (PassNode*)t; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) + AddLabel(pass->GetChild(i)); + } else { + MASSERT(t->IsSwitchLabel()); + mLabels.PushBack((SwitchLabelNode*)t); + SETPARENT(t); } } void SwitchCaseNode::AddStmt(TreeNode *t) { - std::list working_list; - working_list.push_back(t); - while (!working_list.empty()) { - TreeNode *t = working_list.front(); - working_list.pop_front(); - if (t->IsPass()) { - PassNode *stmts = (PassNode*)t; - for (unsigned i = 0; i < stmts->GetChildrenNum(); i++) - working_list.push_back(stmts->GetChild(i)); - } else { - mStmts.PushBack(t); - } + if (t->IsPass()) { + PassNode *pass = (PassNode*)t; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) + AddStmt(pass->GetChild(i)); + } else { + mStmts.PushBack(t); + SETPARENT(t); } } void SwitchCaseNode::Dump(unsigned ind) { } -void SwitchNode::AddCase(TreeNode *tree) { - std::list working_list; - working_list.push_back(tree); - while (!working_list.empty()) { - TreeNode *t = working_list.front(); - working_list.pop_front(); - if (t->IsPass()) { - PassNode *cases = (PassNode*)t; - for (unsigned i = 0; i < cases->GetChildrenNum(); i++) - working_list.push_back(cases->GetChild(i)); - } else { - MASSERT(t->IsSwitchCase()); - mCases.PushBack((SwitchCaseNode*)t); +SwitchCaseNode* SwitchNode::SwitchLabelToCase(SwitchLabelNode *label) { + SwitchCaseNode *case_node = + (SwitchCaseNode*)gTreePool.NewTreeNode(sizeof(SwitchCaseNode)); + new (case_node) SwitchCaseNode(); + case_node->AddLabel(label); + return case_node; +} + +void SwitchNode::AddSwitchCase(TreeNode *t) { + if (t->IsPass()) { + PassNode *cases = (PassNode*)t; + for (unsigned i = 0; i < cases->GetChildrenNum(); i++) + AddSwitchCase(cases->GetChild(i)); + } else if (t->IsSwitchCase()) { + // Need go through the statements in this case. Some stmt like + // default : xxx + // are parsed as a labeled stmt inside this case, which they + // are actually a case of switch. + SwitchCaseNode *the_case = (SwitchCaseNode*)t; + SwitchCaseNode *new_case = NULL; + unsigned stmt_num = the_case->GetStmtsNum(); + for (unsigned i = 0; i < stmt_num; i++) { + TreeNode *stmt = the_case->GetStmtAtIndex(i); + TreeNode *label = stmt->GetLabel(); + if (label) { + MASSERT(label->IsIdentifier()); + IdentifierNode *id = (IdentifierNode*)label; + const char *name = id->GetName(); + + // If it's a default case, all remaining statements belong + // to this default case. + if (!strncmp(name, "default", 7) && (strlen(name) == 7)) { + // 1. clear the label of stmt. + stmt->SetLabel(NULL); + // 2. build switch label + SwitchLabelNode *default_label = + (SwitchLabelNode*)gTreePool.NewTreeNode(sizeof(SwitchLabelNode)); + new (default_label) SwitchLabelNode(); + default_label->SetIsDefault(true); + // 3. build the switch case + new_case = (SwitchCaseNode*)gTreePool.NewTreeNode(sizeof(SwitchCaseNode)); + new (new_case) SwitchCaseNode(); + // 4. set the label and stmt for this case. + new_case->AddLabel(default_label); + new_case->AddStmt(stmt); + // 5. add all remaining stmts to new_case + for (unsigned j = i+1; j < stmt_num; j++) { + TreeNode *rem_stmt = the_case->GetStmtAtIndex(j); + new_case->AddStmt(rem_stmt); + } + // 6. remove the stmts added to new_case from the_case + for (unsigned j = i; j < stmt_num; j++) + the_case->PopStmt(); + break; + } + } + } + + AddCase(the_case); + SETPARENT(the_case); + if (new_case) { + AddCase(new_case); + SETPARENT(new_case); } + + } else if (t->IsSwitchLabel()) { + SwitchCaseNode *casenode = SwitchLabelToCase((SwitchLabelNode*)t); + AddCase(casenode); + SETPARENT(casenode); } } @@ -832,6 +1483,47 @@ void SwitchNode::Dump(unsigned ind) { // BlockNode ////////////////////////////////////////////////////////////////////////////////////// +void BlockNode::AddChild(TreeNode *tree) { + if (tree->IsDecl()) { + DeclNode *decl = (DeclNode*)tree; + TreeNode *var = decl->GetVar(); + if (var && var->IsPass()) { + PassNode *pass = (PassNode*)var; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { + DeclNode *n = (DeclNode*)gTreePool.NewTreeNode(sizeof(DeclNode)); + new (n) DeclNode(); + n->SetVar(pass->GetChild(i)); + n->SetProp(decl->GetProp()); + AddChild(n); + } + } else { + mChildren.PushBack(tree); + SETPARENT(tree); + } + } else if (tree->IsPass()) { + PassNode *passnode = (PassNode*)tree; + for (unsigned j = 0; j < passnode->GetChildrenNum(); j++) { + TreeNode *child = passnode->GetChild(j); + AddChild(child); + } + } else { + mChildren.PushBack(tree); + SETPARENT(tree); + } +} + +void BlockNode::InsertStmtAfter(TreeNode *new_stmt, TreeNode *exist_stmt) { + mChildren.LocateValue(exist_stmt); + mChildren.InsertAfter(new_stmt); + SETPARENT(new_stmt); +} + +void BlockNode::InsertStmtBefore(TreeNode *new_stmt, TreeNode *exist_stmt) { + mChildren.LocateValue(exist_stmt); + mChildren.InsertBefore(new_stmt); + SETPARENT(new_stmt); +} + void BlockNode::Dump(unsigned ind) { DumpLabel(ind); for (unsigned i = 0; i < GetChildrenNum(); i++) { @@ -859,35 +1551,113 @@ void PassNode::Dump(unsigned ind) { // ClassNode ////////////////////////////////////////////////////////////////////////////////////// +void ClassNode::AddTypeParam(TreeNode *param) { + if (param->IsPass()) { + PassNode *n = (PassNode*)param; + for (unsigned i = 0; i < n->GetChildrenNum(); i++) { + TreeNode *child = n->GetChild(i); + AddTypeParam(child); + } + } else { + MASSERT(param->IsTypeParameter()); + mTypeParams.PushBack((TypeParameterNode*)param); + SETPARENT(param); + } +} + +void ClassNode::AddSuperClass(TreeNode *the_super) { + if (!the_super) + return; + + if (the_super->IsPass()) { + PassNode *pass_node = (PassNode*)the_super; + for (unsigned i = 0; i < pass_node->GetChildrenNum(); i++) + AddSuperClass(pass_node->GetChild(i)); + } else { + mSuperClasses.PushBack(the_super); + SETPARENT(the_super); + } +} + +void ClassNode::AddSuperInterface(TreeNode *the_super) { + if (!the_super) + return; + + if (the_super->IsPass()) { + PassNode *pass_node = (PassNode*)the_super; + for (unsigned i = 0; i < pass_node->GetChildrenNum(); i++) + AddSuperInterface(pass_node->GetChild(i)); + } else { + mSuperInterfaces.PushBack(the_super); + SETPARENT(the_super); + } +} + // When the class body, a BlockNode, is added to the ClassNode, we need further // categorize the subtrees into members, methods, local classes, interfaces, etc. -void ClassNode::Construct() { - for (unsigned i = 0; i < mBody->GetChildrenNum(); i++) { - TreeNode *tree_node = mBody->GetChildAtIndex(i); - tree_node->SetParent(this); - if (tree_node->IsVarList()) { - VarListNode *vlnode = (VarListNode*)tree_node; - for (unsigned i = 0; i < vlnode->GetNum(); i++) { - IdentifierNode *inode = vlnode->VarAtIndex(i); - inode->SetParent(this); - mFields.PushBack(inode); - } - } else if (tree_node->IsIdentifier()) - mFields.PushBack((IdentifierNode*)tree_node); - else if (tree_node->IsFunction()) { +void ClassNode::Construct(BlockNode *block) { + for (unsigned i = 0; i < block->GetChildrenNum(); i++) { + TreeNode *tree_node = block->GetChildAtIndex(i); + SETPARENT(tree_node); + if (tree_node->IsDecl()) { + DeclNode *decl = (DeclNode*)tree_node; + TreeNode *var = decl->GetVar(); + if (var->IsVarList()) { + VarListNode *vlnode = (VarListNode*)var; + for (unsigned i = 0; i < vlnode->GetVarsNum(); i++) { + IdentifierNode *inode = vlnode->GetVarAtIndex(i); + SETPARENT(inode); + mFields.PushBack(inode); + } + } else if (var->IsIdentifier() || var->IsComputedName() || var->IsLiteral()) { + // string literal is allowed to be a field. + mFields.PushBack(var); + SETPARENT(var); + } else + MERROR("Unsupported class field."); + } else if (tree_node->IsNumIndexSig() || tree_node->IsStrIndexSig()) { + mFields.PushBack(tree_node); + SETPARENT(tree_node); + } else if (tree_node->IsFunction()) { FunctionNode *f = (FunctionNode*)tree_node; + // There is an ugly case from Typescript, which use keyword 'constructor' + // as an identifier. This causes a constructor to be recoganized as normal function. + // We do adjustment here. + TreeNode *name = f->GetFuncName(); + if (name && name->IsIdentifier()) { + IdentifierNode *id = (IdentifierNode*)name; + const char *name_str = id->GetName(); + if (!strncmp(name_str, "constructor", 11) && (strlen(name_str) == 11)) { + f->SetFuncName(NULL); + f->SetStrIdx(0); + f->SetIsConstructor(); + } + } if (f->IsConstructor()) mConstructors.PushBack(f); else mMethods.PushBack(f); - } else if (tree_node->IsClass()) + SETPARENT(f); + } else if (tree_node->IsClass()) { mLocalClasses.PushBack((ClassNode*)tree_node); - else if (tree_node->IsInterface()) + SETPARENT(tree_node); + } else if (tree_node->IsInterface()) { mLocalInterfaces.PushBack((InterfaceNode*)tree_node); - else if (tree_node->IsBlock()) { + SETPARENT(tree_node); + } else if (tree_node->IsBlock()) { BlockNode *block = (BlockNode*)tree_node; MASSERT(block->IsInstInit() && "unnamed block in class is not inst init?"); mInstInits.PushBack(block); + SETPARENT(tree_node); + } else if (tree_node->IsImport()) { + mImports.PushBack((ImportNode*)tree_node); + SETPARENT(tree_node); + } else if (tree_node->IsExport()) { + mExports.PushBack((ExportNode*)tree_node); + SETPARENT(tree_node); + } else if (tree_node->IsDeclare()) { + mDeclares.PushBack((DeclareNode*)tree_node); + SETPARENT(tree_node); } else MASSERT("Unsupported tree node in class body."); } @@ -899,20 +1669,35 @@ void ClassNode::Release() { mSuperClasses.Release(); mSuperInterfaces.Release(); mAttributes.Release(); + mAnnotations.Release(); + mTypeParams.Release(); mFields.Release(); mMethods.Release(); mLocalClasses.Release(); mLocalInterfaces.Release(); + mImports.Release(); + mExports.Release(); + mDeclares.Release(); } void ClassNode::Dump(unsigned indent) { DumpIndentation(indent); if (IsJavaEnum()) - DUMP1_NORETURN("class[JavaEnum] ", mName); + DUMP1_NORETURN("class[JavaEnum] ", GetName()); else - DUMP1_NORETURN("class ", mName); + DUMP1_NORETURN("class ", GetName()); DUMP_RETURN(); + if (mTypeParams.GetNum() > 0) { + DUMP0_NORETURN("<"); + for (unsigned i = 0; i < mTypeParams.GetNum(); i++) { + TypeParameterNode *node = mTypeParams.ValueAtIndex(i); + node->Dump(0); + DUMP0_NORETURN(","); + } + DUMP0_NORETURN(">"); + } + DumpIndentation(indent + 2); DUMP0("Fields: "); for (unsigned i = 0; i < mFields.GetNum(); i++) { @@ -956,28 +1741,65 @@ void ClassNode::Dump(unsigned indent) { TreeNode *node = mLocalInterfaces.ValueAtIndex(i); node->Dump(indent + 4); } + + if (mImports.GetNum() > 0) { + DumpIndentation(indent + 2); + DUMP0("Imports: "); + } + for (unsigned i = 0; i < mImports.GetNum(); i++) { + TreeNode *node = mImports.ValueAtIndex(i); + node->Dump(indent + 4); + } + + if (mExports.GetNum() > 0) { + DumpIndentation(indent + 2); + DUMP0("Exports: "); + } + for (unsigned i = 0; i < mExports.GetNum(); i++) { + TreeNode *node = mExports.ValueAtIndex(i); + node->Dump(indent + 4); + } + + if (mDeclares.GetNum() > 0) { + DumpIndentation(indent + 2); + DUMP0("Declares: "); + } + for (unsigned i = 0; i < mDeclares.GetNum(); i++) { + TreeNode *node = mDeclares.ValueAtIndex(i); + node->Dump(indent + 4); + } } ////////////////////////////////////////////////////////////////////////////////////// // FunctionNode ////////////////////////////////////////////////////////////////////////////////////// -FunctionNode::FunctionNode() { - mKind = NK_Function; - mName = NULL; - mType = NULL; - mBody = NULL; - mDims = NULL; - mIsConstructor = false; +FunctionNode::FunctionNode() : TreeNode(NK_Function), + mFuncName(NULL), mRetType(NULL), mBody(NULL), mDims(NULL), + mIsConstructor(false), mIsGenerator(false), mIsIterator(false), mIsGetAccessor(false), + mIsSetAccessor(false), mIsCallSignature(false), mIsConstructSignature(false), + mAssert(NULL) {} + +void FunctionNode::AddTypeParam(TreeNode *param) { + if (param->IsPass()) { + PassNode *n = (PassNode*)param; + for (unsigned i = 0; i < n->GetChildrenNum(); i++) { + TreeNode *child = n->GetChild(i); + AddTypeParam(child); + } + } else { + mTypeParams.PushBack(param); + SETPARENT(param); + } } // This is to tell if both FunctionNodes have same return type // and parameter types. So languages require Type Erasure at first, like Java. // Type erasure should be done earlier in language specific process. bool FunctionNode::OverrideEquivalent(FunctionNode *fun) { - if (!mType->TypeEquivalent(fun->GetType())) + if (!mRetType->TypeEquivalent(fun->GetRetType())) return false; - if (GetName() != fun->GetName()) + if (GetStrIdx() != fun->GetStrIdx()) return false; if (GetParamsNum() != fun->GetParamsNum()) return false; @@ -1021,6 +1843,8 @@ void FunctionNode::CleanUp() { } else { // If pass node is the header, insert before next. // If pass node is the last or any one else, insert after prev. + next = NULL; + prev = NULL; if (i == 0) { next = mBody->GetChildAtIndex(1); } else { @@ -1061,12 +1885,46 @@ void FunctionNode::CleanUp() { void FunctionNode::Dump(unsigned indent) { DumpIndentation(indent); if (mIsConstructor) - DUMP1_NORETURN("constructor ", mName); - else - DUMP1_NORETURN("func ", mName); + DUMP0_NORETURN("constructor "); + else if (mIsGetAccessor) + DUMP0_NORETURN("get "); + else if (mIsSetAccessor) + DUMP0_NORETURN("set "); + else if (mIsGenerator) + DUMP0_NORETURN("generator "); + else + DUMP0_NORETURN("func "); + + if (mStrIdx) + DUMP0_NORETURN(GetName()); + if (mFuncName && mFuncName->IsOptional()) + DUMP0_NORETURN("?"); + + if (GetTypeParamsNum() > 0) { + DUMP0_NORETURN("<"); + for (unsigned i = 0; i < GetTypeParamsNum(); i++) { + TreeNode *arg = GetTypeParamAtIndex(i); + arg->Dump(0); + if (i < GetTypeParamsNum() - 1) + DUMP0_NORETURN(","); + } + DUMP0_NORETURN(">"); + } // dump parameters - DUMP0_NORETURN("()"); + DUMP0_NORETURN("("); + for (unsigned i = 0; i < GetParamsNum(); i++) { + TreeNode *param = GetParam(i); + param->Dump(0); + if (i < GetParamsNum() - 1) + DUMP0_NORETURN(","); + } + DUMP0_NORETURN(")"); + + if (mAssert) { + DUMP0_NORETURN(" : "); + mAssert->Dump(0); + } // dump throws DUMP0_NORETURN(" throws: "); @@ -1085,13 +1943,30 @@ void FunctionNode::Dump(unsigned indent) { // LambdaNode ////////////////////////////////////////////////////////////////////////////////////// +void LambdaNode::AddTypeParam(TreeNode *param) { + if (param->IsPass()) { + PassNode *n = (PassNode*)param; + for (unsigned i = 0; i < n->GetChildrenNum(); i++) { + TreeNode *child = n->GetChild(i); + AddTypeParam(child); + } + } else { + MASSERT(param->IsTypeParameter()); + mTypeParams.PushBack((TypeParameterNode*)param); + SETPARENT(param); + } +} + void LambdaNode::Dump(unsigned indent) { DumpIndentation(indent); std::string dump; dump += "("; for (unsigned i = 0; i < mParams.GetNum(); i++) { - IdentifierNode *in = mParams.ValueAtIndex(i); - dump += in->GetName(); + TreeNode *in = mParams.ValueAtIndex(i); + if(in->IsDecl()) + dump += static_cast(in)->GetVar()->GetName(); + else + dump += in->GetName(); if (i < mParams.GetNum() - 1) dump += ","; } @@ -1101,6 +1976,137 @@ void LambdaNode::Dump(unsigned indent) { mBody->Dump(0); } +////////////////////////////////////////////////////////////////////////////////////// +// InstanceOfNode +////////////////////////////////////////////////////////////////////////////////////// + +void InstanceOfNode::Dump(unsigned indent) { + DumpIndentation(indent); + mLeft->Dump(0); + DUMP0_NORETURN(" instanceof "); + mRight->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// InNode +////////////////////////////////////////////////////////////////////////////////////// + +void InNode::Dump(unsigned indent) { + DumpIndentation(indent); + mLeft->Dump(0); + DUMP0_NORETURN(" in "); + mRight->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// MappedPropertyNode +////////////////////////////////////////////////////////////////////////////////////// + +void ComputedNameNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("["); + mExpr->Dump(0); + DUMP0_NORETURN("] : "); + if (mExtendType) + mExtendType->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// IsNode +////////////////////////////////////////////////////////////////////////////////////// + +void IsNode::Dump(unsigned indent) { + DumpIndentation(indent); + mLeft->Dump(0); + DUMP0_NORETURN(" is "); + mRight->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// AwaitNode +////////////////////////////////////////////////////////////////////////////////////// + +void AwaitNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN(" await "); + if (mExpr) + mExpr->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// TypeOfNode +////////////////////////////////////////////////////////////////////////////////////// + +void TypeOfNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN(" typeof "); + mExpr->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// KeyOfNode +////////////////////////////////////////////////////////////////////////////////////// + +void KeyOfNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN(" keyof "); + mExpr->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// InferNode +////////////////////////////////////////////////////////////////////////////////////// + +void InferNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN(" infer "); + mExpr->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// NameTypePairNode +////////////////////////////////////////////////////////////////////////////////////// + +void NameTypePairNode::Dump(unsigned indent) { + DumpIndentation(indent); + if (mVar) + mVar->Dump(0); + DUMP0_NORETURN(" : "); + if (mType) + mType->Dump(0); +} + +////////////////////////////////////////////////////////////////////////////////////// +// TupleTypeNode +////////////////////////////////////////////////////////////////////////////////////// + +// Child should be NameTypePairNode +void TupleTypeNode::AddChild(TreeNode *field) { + if (field->IsPass()) { + PassNode *pass = (PassNode*)field; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { + TreeNode *child = pass->GetChild(i); + AddChild(child); + } + } else { + MASSERT(field->IsNameTypePair()); + NameTypePairNode *node = (NameTypePairNode*)field; + AddField(node); + SETPARENT(node); + } +} + +void TupleTypeNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN(" [ "); + for (unsigned i = 0; i < mFields.GetNum(); i++) { + NameTypePairNode *node = mFields.ValueAtIndex(i); + node->Dump(0); + DUMP0_NORETURN(" , "); + } + DUMP0_NORETURN(" ] "); +} + ////////////////////////////////////////////////////////////////////////////////////// // InterfaceNode ////////////////////////////////////////////////////////////////////////////////////// @@ -1108,12 +2114,12 @@ void LambdaNode::Dump(unsigned indent) { void InterfaceNode::Construct(BlockNode *block) { for (unsigned i = 0; i < block->GetChildrenNum(); i++) { TreeNode *tree_node = block->GetChildAtIndex(i); - tree_node->SetParent(this); + SETPARENT(tree_node); if (tree_node->IsVarList()) { VarListNode *vlnode = (VarListNode*)tree_node; - for (unsigned i = 0; i < vlnode->GetNum(); i++) { - IdentifierNode *inode = vlnode->VarAtIndex(i); - inode->SetParent(this); + for (unsigned i = 0; i < vlnode->GetVarsNum(); i++) { + IdentifierNode *inode = vlnode->GetVarAtIndex(i); + SETPARENT(inode); mFields.PushBack(inode); } } else if (tree_node->IsIdentifier()) @@ -1128,7 +2134,7 @@ void InterfaceNode::Construct(BlockNode *block) { void InterfaceNode::Dump(unsigned indent) { DumpIndentation(indent); - DUMP1_NORETURN("interface ", mName); + DUMP1_NORETURN("interface ", GetName()); DUMP_RETURN(); DumpIndentation(indent + 2); @@ -1146,4 +2152,31 @@ void InterfaceNode::Dump(unsigned indent) { node->Dump(indent + 4); } } + +void TripleSlashNode::Dump(unsigned indent) { + DumpIndentation(indent); + DUMP0_NORETURN("trip-slash reference "); + + switch(mProp) { + case TSP_Path: + DUMP0_NORETURN("path = "); + break; + case TSP_Types: + DUMP0_NORETURN("types = "); + break; + case TSP_NoDefaultLib: + DUMP0_NORETURN("no-default-lib = "); + break; + case TSP_Lib: + DUMP0_NORETURN("lib = "); + break; + case TSP_NA: + default: + DUMP0_NORETURN("NA = "); + break; + } + + mValue->Dump(0); +} + } diff --git a/src/MapleFE/shared/src/ast_attr.cpp b/src/MapleFE/shared/src/ast_attr.cpp index 7b4279eb920d603bfa0809ff3bf6c904f6f7b1cc..19b2124b717efe6c259591dec60a9dd85fec112c 100644 --- a/src/MapleFE/shared/src/ast_attr.cpp +++ b/src/MapleFE/shared/src/ast_attr.cpp @@ -18,14 +18,13 @@ #include "ast.h" #include "ruletable.h" #include "ast_attr.h" -#include "gen_attr.h" // for language specific attr keyword #include "massert.h" namespace maplefe { // Inquiry function for language specific attr keyword -static const char* FindAttrKeyword(AttrId id) { - for (unsigned i = 0; i < ATTR_NA; i++) { +const char* FindAttrKeyword(AttrId id) { + for (unsigned i = 0; i < AttrKeywordTableSize; i++) { if (AttrKeywordTable[i].mId == id) return AttrKeywordTable[i].mText; } @@ -33,8 +32,8 @@ static const char* FindAttrKeyword(AttrId id) { } // Inquiry function for language specific attr keyword -static AttrId FindAttrId(const char *keyword) { - for (unsigned i = 0; i < ATTR_NA; i++) { +AttrId FindAttrId(const char *keyword) { + for (unsigned i = 0; i < AttrKeywordTableSize; i++) { if (strncmp(AttrKeywordTable[i].mText, keyword, strlen(keyword)) == 0 && strlen(keyword) == strlen(AttrKeywordTable[i].mText)) return AttrKeywordTable[i].mId; diff --git a/src/MapleFE/shared/src/ast_builder.cpp b/src/MapleFE/shared/src/ast_builder.cpp index 011cafb03f24d84d32a0967d9a5faddc0ad0bc02..016d6a9ae7466c363596d053f3a6e289141f05e6 100644 --- a/src/MapleFE/shared/src/ast_builder.cpp +++ b/src/MapleFE/shared/src/ast_builder.cpp @@ -17,6 +17,7 @@ #include "token.h" #include "ruletable.h" +#include "stringpool.h" #include "ast_builder.h" #include "ast_scope.h" #include "ast_attr.h" @@ -26,8 +27,6 @@ namespace maplefe { -ASTBuilder gASTBuilder; - //////////////////////////////////////////////////////////////////////////////////////// // For the time being, we simply use a big switch-case. Later on we could use a more // flexible solution. @@ -51,17 +50,48 @@ TreeNode* ASTBuilder::Build() { TreeNode* ASTBuilder::CreateTokenTreeNode(const Token *token) { unsigned size = 0; if (token->IsIdentifier()) { - IdentifierNode *n = (IdentifierNode*)mTreePool->NewTreeNode(sizeof(IdentifierNode)); - new (n) IdentifierNode(token->GetName()); + IdentifierNode *n = (IdentifierNode*)gTreePool.NewTreeNode(sizeof(IdentifierNode)); + unsigned idx = gStringPool.GetStrIdx(token->GetName()); + new (n) IdentifierNode(idx); mLastTreeNode = n; return n; } else if (token->IsLiteral()) { LitData data = token->GetLitData(); - LiteralNode *n = (LiteralNode*)mTreePool->NewTreeNode(sizeof(LiteralNode)); + LiteralNode *n = (LiteralNode*)gTreePool.NewTreeNode(sizeof(LiteralNode)); new (n) LiteralNode(data); mLastTreeNode = n; return n; + } else if (token->IsTempLit()) { + TemplateLiteralNode *n = (TemplateLiteralNode*)gTreePool.NewTreeNode(sizeof(TemplateLiteralNode)); + new (n) TemplateLiteralNode(); + + // copy mStrings&mPlaceHolders to n + TempLitData *tld = token->GetTempLitData(); + for (unsigned i = 0; i < tld->mStrings.GetNum(); i++) { + const char *s = tld->mStrings.ValueAtIndex(i); + n->AddString(s); + } + + // release memeory of SmallVector of mStrings. + tld->mStrings.Release(); + delete tld; + + gTemplateLiteralNodes.PushBack(n); + mLastTreeNode = n; + return n; + + } else if (token->IsRegExpr()) { + RegExprNode *n = (RegExprNode*)gTreePool.NewTreeNode(sizeof(RegExprNode)); + new (n) RegExprNode(); + + RegExprData d = token->GetRegExpr(); + n->SetData(d); + + mLastTreeNode = n; + return n; + } else if (token->IsKeyword()) { + mNameForBuildIdentifier = NULL; const char *keyword = token->GetName(); // If it's an attribute AttrNode *n = gAttrPool.GetAttrNode(keyword); @@ -73,18 +103,29 @@ TreeNode* ASTBuilder::CreateTokenTreeNode(const Token *token) { PrimTypeNode *type = gPrimTypePool.FindType(keyword); if (type) { mLastTreeNode = type; + mNameForBuildIdentifier = keyword; return type; } - // We define special literal tree node for 'this'. + // We define special literal tree node for 'this', 'super'. if ((strlen(token->GetName()) == 4) && !strncmp(token->GetName(), "this", 4)) { LitData data; data.mType = LT_ThisLiteral; - LiteralNode *n = (LiteralNode*)mTreePool->NewTreeNode(sizeof(LiteralNode)); + LiteralNode *n = (LiteralNode*)gTreePool.NewTreeNode(sizeof(LiteralNode)); + new (n) LiteralNode(data); + mLastTreeNode = n; + return n; + } else if ((strlen(token->GetName()) == 5) && !strncmp(token->GetName(), "super", 5)) { + LitData data; + data.mType = LT_SuperLiteral; + LiteralNode *n = (LiteralNode*)gTreePool.NewTreeNode(sizeof(LiteralNode)); new (n) LiteralNode(data); mLastTreeNode = n; return n; } + // Otherwise, it doesn't create any tree node. + // But we pass the keyword name to future possible BuildIdentifier. + mNameForBuildIdentifier = keyword; } // Other tokens shouldn't be involved in the tree creation. @@ -99,24 +140,30 @@ static void add_attribute_to(TreeNode *tree, TreeNode *attr) { MASSERT(attr->IsAttr()); AttrNode *attr_node = (AttrNode*)attr; AttrId aid = attr_node->GetId(); - if (tree->IsVarList()) { + + if (tree->IsPass()) { + PassNode *pass_node = (PassNode*)tree; + for (unsigned i = 0; i < pass_node->GetChildrenNum(); i++) { + TreeNode *child = pass_node->GetChild(i); + add_attribute_to(child, attr); + } + } else if (tree->IsVarList()) { VarListNode *vl = (VarListNode*)tree; - for (unsigned i = 0; i < vl->GetNum(); i++) { - IdentifierNode *inode = vl->VarAtIndex(i); + for (unsigned i = 0; i < vl->GetVarsNum(); i++) { + IdentifierNode *inode = vl->GetVarAtIndex(i); inode->AddAttr(aid); } - return; - } else if (tree->IsBlock()){ - BlockNode *b = (BlockNode*)tree; - if (b->IsInstInit()) { - b->AddAttr(aid); - return; + } else if (tree->IsExprList()) { + ExprListNode *vl = (ExprListNode*)tree; + for (unsigned i = 0; i < vl->GetExprsNum(); i++) { + TreeNode *child = vl->GetExprAtIndex(i); + add_attribute_to(child, attr); } } else { - ClassNode *klass = (ClassNode*)tree; - klass->AddAttr(aid); - return; + // The basse TreeNode has a virtual AddAttr(). + tree->AddAttr(aid); } + return; } // It's the caller to assure tree is valid, meaning something could carry type. @@ -124,39 +171,243 @@ static void add_type_to(TreeNode *tree, TreeNode *type) { if (tree->IsIdentifier()) { IdentifierNode *in = (IdentifierNode*)tree; in->SetType(type); + } else if (tree->IsLiteral()) { + LiteralNode *lit = (LiteralNode*)tree; + lit->SetType(type); + } else if (tree->IsLambda()) { + LambdaNode *lam = (LambdaNode*)tree; + lam->SetRetType(type); } else if (tree->IsVarList()) { VarListNode *vl = (VarListNode*)tree; - for (unsigned i = 0; i < vl->GetNum(); i++) - vl->VarAtIndex(i)->SetType(type); + for (unsigned i = 0; i < vl->GetVarsNum(); i++) + vl->GetVarAtIndex(i)->SetType(type); } else if (tree->IsFunction()) { FunctionNode *func = (FunctionNode*)tree; - func->SetType(type); + func->SetRetType(type); + } else if (tree->IsBindingPattern()) { + BindingPatternNode *bp = (BindingPatternNode*)tree; + bp->SetType(type); + } else if (tree->IsComputedName()) { + ComputedNameNode *mp = (ComputedNameNode*)tree; + mp->SetExtendType(type); } else { MERROR("Unsupported tree node in add_type_to()"); } } //////////////////////////////////////////////////////////////////////////////////////// -// Major Functions to build the tree +// BuildModule +//////////////////////////////////////////////////////////////////////////////////////// + +// Take one argument, the module name +TreeNode* ASTBuilder::BuildModule() { + ModuleNode *n = (ModuleNode*)gTreePool.NewTreeNode(sizeof(ModuleNode)); + new (n) ModuleNode(); + + MASSERT(mParams.size() == 1); + Param p_a = mParams[0]; + if (!p_a.mIsEmpty && p_a.mIsTreeNode) { + TreeNode *tree = p_a.mData.mTreeNode; + if (tree->IsIdentifier()) { + const char *name = tree->GetName(); + n->SetFilename(name); + } else if (tree->IsLiteral()) { + LiteralNode *lit = (LiteralNode*)tree; + LitData data = lit->GetData(); + MASSERT(data.mType == LT_StringLiteral); + const char *name = gStringPool.GetStringFromStrIdx(data.mData.mStrIdx); + n->SetFilename(name); + } else { + MERROR("Unsupported module name."); + } + } + + mLastTreeNode = n; + return mLastTreeNode; +} + +// It takes no argument. +TreeNode* ASTBuilder::SetIsAmbient() { + MASSERT(mLastTreeNode->IsModule()); + ModuleNode *mod = (ModuleNode*)mLastTreeNode; + mod->SetIsAmbient(); + return mLastTreeNode; +} + +// Takes one parameter which is the tree of module body. +TreeNode* ASTBuilder::AddModuleBody() { + if (mTrace) + std::cout << "In AddModuleBody" << std::endl; + + Param p_body = mParams[0]; + if (!p_body.mIsEmpty) { + if (!p_body.mIsTreeNode) + MERROR("The module body is not a tree node."); + TreeNode *tn = p_body.mData.mTreeNode; + + MASSERT(mLastTreeNode->IsModule()); + ModuleNode *mod = (ModuleNode*)mLastTreeNode; + mod->AddTree(tn); + } + + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// BuildIdentifier +//////////////////////////////////////////////////////////////////////////////////////// + +// 1. It takes one argument, the target to build into identifier. +// 2. It takes no argument, then mLastTreeNode is the target. +// It could be a token or tree. +TreeNode* ASTBuilder::BuildIdentifier() { + if (mParams.size() == 1) { + Param target = mParams[0]; + if (!target.mIsEmpty) { + if (target.mIsTreeNode) { + TreeNode *tn = target.mData.mTreeNode; + return BuildIdentifier(tn); + } else { + Token *tn = target.mData.mToken; + return BuildIdentifier(tn); + } + } + return NULL; + } + + if (mNameForBuildIdentifier) { + IdentifierNode *n = (IdentifierNode*)gTreePool.NewTreeNode(sizeof(IdentifierNode)); + unsigned idx = gStringPool.GetStrIdx(mNameForBuildIdentifier); + new (n) IdentifierNode(idx); + mLastTreeNode = n; + mNameForBuildIdentifier = NULL; + return n; + } else if (mLastTreeNode->IsIdentifier()) { + return mLastTreeNode; + } else if (mLastTreeNode->IsAttr()) { + AttrNode *an = (AttrNode*)mLastTreeNode; + AttrId aid = an->GetId(); + + IdentifierNode *n = (IdentifierNode*)gTreePool.NewTreeNode(sizeof(IdentifierNode)); + unsigned idx = gStringPool.GetStrIdx(FindAttrKeyword(aid)); + new (n) IdentifierNode(idx); + mLastTreeNode = n; + return n; + } else if (mLastTreeNode->IsPrimType()) { + PrimTypeNode *prim_type = (PrimTypeNode*)mLastTreeNode; + IdentifierNode *n = (IdentifierNode*)gTreePool.NewTreeNode(sizeof(IdentifierNode)); + unsigned idx = gStringPool.GetStrIdx(prim_type->GetTypeName()); + new (n) IdentifierNode(idx); + mLastTreeNode = n; + return n; + } else if (mLastTreeNode->IsLiteral()) { + LiteralNode *lit = (LiteralNode*)mLastTreeNode; + LitData data = lit->GetData(); + if (data.mType == LT_ThisLiteral) { + IdentifierNode *n = (IdentifierNode*)gTreePool.NewTreeNode(sizeof(IdentifierNode)); + unsigned idx = gStringPool.GetStrIdx("this"); + new (n) IdentifierNode(idx); + mLastTreeNode = n; + return n; + } else { + MERROR("Unsupported node type in BuildIdentifier()"); + } + } else { + MERROR("Unsupported node type in BuildIdentifier()"); + } +} + +// Build IdentifierNode from a token. +TreeNode* ASTBuilder::BuildIdentifier(const Token *token) { + const char *name = token->GetName(); + MASSERT(name); + IdentifierNode *n = (IdentifierNode*)gTreePool.NewTreeNode(sizeof(IdentifierNode)); + unsigned idx = gStringPool.GetStrIdx(name); + new (n) IdentifierNode(idx); + mLastTreeNode = n; + return n; +} + +// Build IdentifierNode from a TreeNode. +TreeNode* ASTBuilder::BuildIdentifier(const TreeNode *tree) { + if (!tree) + return NULL; + + if (tree->IsAttr()) { + AttrNode *an = (AttrNode*)tree; + AttrId aid = an->GetId(); + IdentifierNode *n = (IdentifierNode*)gTreePool.NewTreeNode(sizeof(IdentifierNode)); + unsigned idx = gStringPool.GetStrIdx(FindAttrKeyword(aid)); + new (n) IdentifierNode(idx); + mLastTreeNode = n; + return n; + } else if (tree->IsLiteral()) { + LiteralNode *lit = (LiteralNode*)tree; + LitData data = lit->GetData(); + if (data.mType == LT_ThisLiteral) { + IdentifierNode *n = (IdentifierNode*)gTreePool.NewTreeNode(sizeof(IdentifierNode)); + unsigned idx = gStringPool.GetStrIdx("this"); + new (n) IdentifierNode(idx); + mLastTreeNode = n; + return n; + } + } + + return NULL; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// NameTypePair +//////////////////////////////////////////////////////////////////////////////////////// + +// It could takes (1) two arguments, name and type +// (2) one argument, the name +TreeNode* ASTBuilder::BuildNameTypePair() { + if (mTrace) + std::cout << "In BuildNameTypePair" << std::endl; + + NameTypePairNode *n = (NameTypePairNode*)gTreePool.NewTreeNode(sizeof(NameTypePairNode)); + new (n) NameTypePairNode(); + mLastTreeNode = n; + + if (mParams.size() == 2) { + Param p_a = mParams[0]; + Param p_b = mParams[1]; + + if (!p_a.mIsEmpty && p_a.mIsTreeNode) + n->SetVar(p_a.mData.mTreeNode); + + if (!p_b.mIsEmpty && p_b.mIsTreeNode) + n->SetType(p_b.mData.mTreeNode); + } else { + Param p_b = mParams[0]; + if (!p_b.mIsEmpty && p_b.mIsTreeNode) + n->SetType(p_b.mData.mTreeNode); + } + + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// Interfaces for Java style package and import //////////////////////////////////////////////////////////////////////////////////////// TreeNode* ASTBuilder::BuildPackageName() { - MASSERT(!gModule.mPackage); + MASSERT(!mASTModule->mPackage); MASSERT(mLastTreeNode->IsField() || mLastTreeNode->IsIdentifier()); - PackageNode *n = (PackageNode*)mTreePool->NewTreeNode(sizeof(PackageNode)); + PackageNode *n = (PackageNode*)gTreePool.NewTreeNode(sizeof(PackageNode)); new (n) PackageNode(); - const char *name = mLastTreeNode->GetName(); - n->SetName(name); + n->SetPackage(mLastTreeNode); - gModule.SetPackage(n); + mASTModule->SetPackage(n); mLastTreeNode = n; return mLastTreeNode; } TreeNode* ASTBuilder::BuildSingleTypeImport() { - ImportNode *n = (ImportNode*)mTreePool->NewTreeNode(sizeof(ImportNode)); + ImportNode *n = (ImportNode*)gTreePool.NewTreeNode(sizeof(ImportNode)); new (n) ImportNode(); n->SetImportSingle(); n->SetImportType(); @@ -167,13 +418,13 @@ TreeNode* ASTBuilder::BuildSingleTypeImport() { TreeNode *tree = p.mData.mTreeNode; MASSERT(tree->IsIdentifier() || tree->IsField()); - n->SetName(tree->GetName()); + n->SetTarget(tree); mLastTreeNode = n; return mLastTreeNode; } TreeNode* ASTBuilder::BuildAllTypeImport() { - ImportNode *n = (ImportNode*)mTreePool->NewTreeNode(sizeof(ImportNode)); + ImportNode *n = (ImportNode*)gTreePool.NewTreeNode(sizeof(ImportNode)); new (n) ImportNode(); n->SetImportAll(); n->SetImportType(); @@ -184,20 +435,20 @@ TreeNode* ASTBuilder::BuildAllTypeImport() { TreeNode *tree = p.mData.mTreeNode; MASSERT(tree->IsIdentifier() || tree->IsField()); - n->SetName(tree->GetName()); + n->SetTarget(tree); mLastTreeNode = n; return mLastTreeNode; } // It takes the mLastTreeNode as parameter TreeNode* ASTBuilder::BuildSingleStaticImport() { - ImportNode *n = (ImportNode*)mTreePool->NewTreeNode(sizeof(ImportNode)); + ImportNode *n = (ImportNode*)gTreePool.NewTreeNode(sizeof(ImportNode)); new (n) ImportNode(); n->SetImportSingle(); n->SetImportType(); MASSERT(mLastTreeNode->IsIdentifier() || mLastTreeNode->IsField()); - n->SetName(mLastTreeNode->GetName()); + n->SetTarget(mLastTreeNode); n->SetImportStatic(); mLastTreeNode = n; return mLastTreeNode; @@ -211,8 +462,307 @@ TreeNode* ASTBuilder::BuildAllStaticImport() { } TreeNode* ASTBuilder::BuildAllImport() { + ImportNode *n = (ImportNode*)gTreePool.NewTreeNode(sizeof(ImportNode)); + new (n) ImportNode(); + n->SetImportAll(); + mLastTreeNode = n; + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////////////// +// Interfaces for Javascript style export and import +//////////////////////////////////////////////////////////////////////////////////////// + +// Takes no argument. +TreeNode* ASTBuilder::BuildImport() { + ImportNode *n = (ImportNode*)gTreePool.NewTreeNode(sizeof(ImportNode)); + new (n) ImportNode(); + + mLastTreeNode = n; + return mLastTreeNode; +} + +// Takes no argument. +TreeNode* ASTBuilder::BuildExport() { + ExportNode *n = (ExportNode*)gTreePool.NewTreeNode(sizeof(ExportNode)); + new (n) ExportNode(); + + mLastTreeNode = n; + return mLastTreeNode; +} + +// It set mLastTreeNode to a type import/export. +TreeNode* ASTBuilder::SetIsXXportType() { + if (mLastTreeNode->IsImport()) { + ImportNode *inode = (ImportNode*)mLastTreeNode; + inode->SetImportType(); + } else if (mLastTreeNode->IsExport()) { + ExportNode *enode = (ExportNode*)mLastTreeNode; + enode->SetIsExportType(); + } else { + MERROR("Unsupported action."); + } + + return mLastTreeNode; +} + +// It takes one argument, the pairs. +// The pairs could be complicated in Javascript. We will let ImportNode or +// ExportNode to handle by themselves. +TreeNode* ASTBuilder::SetPairs() { + TreeNode *pairs = NULL; + Param p = mParams[0]; + if (!p.mIsEmpty && p.mIsTreeNode) { + pairs = p.mData.mTreeNode; + if (mLastTreeNode->IsImport()) { + ImportNode *inode = (ImportNode*)mLastTreeNode; + inode->AddPair(pairs); + } else if (mLastTreeNode->IsExport()) { + ExportNode *enode = (ExportNode*)mLastTreeNode; + enode->AddPair(pairs); + } + } + + return mLastTreeNode; +} + +TreeNode* ASTBuilder::SetDefaultPairs() { + TreeNode *pairs = NULL; + Param p = mParams[0]; + if (!p.mIsEmpty && p.mIsTreeNode) { + pairs = p.mData.mTreeNode; + if (mLastTreeNode->IsImport()) { + ImportNode *inode = (ImportNode*)mLastTreeNode; + inode->AddDefaultPair(pairs); + } else if (mLastTreeNode->IsExport()) { + ExportNode *enode = (ExportNode*)mLastTreeNode; + enode->AddDefaultPair(pairs); + } + } + + return mLastTreeNode; +} + +// It takes +// 1. One argument: the mBefore object. Usually happens in +// export = x +// 2. Two arguments: the mBefore and mAfter. In TS, it has +// import x = require(y) +// [NOTE] In .spec file, put the arguments in order of +// SetSinglePairs(before, after) + +TreeNode* ASTBuilder::SetSinglePairs() { + TreeNode *before = NULL; + TreeNode *after = NULL; + + if (mParams.size() == 2) { + Param p = mParams[0]; + if (!p.mIsEmpty && p.mIsTreeNode) + before = p.mData.mTreeNode; + p = mParams[1]; + if (!p.mIsEmpty && p.mIsTreeNode) + after = p.mData.mTreeNode; + } else { + MASSERT(mParams.size() == 1); + Param p = mParams[0]; + if (!p.mIsEmpty && p.mIsTreeNode) + before = p.mData.mTreeNode; + } + + if (mLastTreeNode->IsImport()) { + ImportNode *inode = (ImportNode*)mLastTreeNode; + inode->AddSinglePair(before, after); + } else if (mLastTreeNode->IsExport()) { + ExportNode *enode = (ExportNode*)mLastTreeNode; + enode->AddSinglePair(before, after); + } + + return mLastTreeNode; +} + +// Takes one argument, the 'from' module +TreeNode* ASTBuilder::SetFromModule() { + Param p = mParams[0]; + if (!p.mIsEmpty && p.mIsTreeNode) { + TreeNode *t = p.mData.mTreeNode; + if (mLastTreeNode->IsImport()) { + ImportNode *inode = (ImportNode*)mLastTreeNode; + inode->SetTarget(t); + } else if (mLastTreeNode->IsExport()) { + ExportNode *enode = (ExportNode*)mLastTreeNode; + enode->SetTarget(t); + } + } + return mLastTreeNode; +} + +// Take no argument, or one argument. +// (1) If no argument, it applies to all pairs of import/export. +// This happens right after BuildImport or BuildExport, and there is no existing +// pairs. In this case, we create a new pair and sets it to *. +// (2) If one argument, it's the new name of '*' (aka the Everything), +// and is saved in mAfter of the pair. +// +// In either case, we need create a new and the only pair for XXport node. +TreeNode* ASTBuilder::SetIsEverything() { + XXportAsPairNode *n = (XXportAsPairNode*)gTreePool.NewTreeNode(sizeof(XXportAsPairNode)); + new (n) XXportAsPairNode(); + n->SetIsEverything(); + + if (mParams.size() == 1) { + Param p = mParams[0]; + if (!p.mIsEmpty && p.mIsTreeNode) { + TreeNode *expr = p.mData.mTreeNode; + n->SetBefore(expr); + } + } + + if (mLastTreeNode->IsImport()) { + ImportNode *inode = (ImportNode*)mLastTreeNode; + MASSERT(!inode->GetPairsNum()); + inode->AddPair(n); + } else if (mLastTreeNode->IsExport()) { + ExportNode *enode = (ExportNode*)mLastTreeNode; + MASSERT(!enode->GetPairsNum()); + enode->AddPair(n); + } + + return mLastTreeNode; +} + +// Right now it takes no argument. mLastTreeNode is the implicit argument +TreeNode* ASTBuilder::SetAsNamespace() { + MASSERT(mLastTreeNode->IsXXportAsPair()); + XXportAsPairNode *pair = (XXportAsPairNode*)mLastTreeNode; + pair->SetAsNamespace(); + return mLastTreeNode; +} + +// 1. It takes two arguments, before and after. +// 2. It takes one argument, before. +TreeNode* ASTBuilder::BuildXXportAsPair() { + + TreeNode *before = NULL; + TreeNode *after = NULL; + + Param p = mParams[0]; + if (!p.mIsEmpty && p.mIsTreeNode) { + before = p.mData.mTreeNode; + } + + if (mParams.size() == 2) { + p = mParams[1]; + if (!p.mIsEmpty) { + if (p.mIsTreeNode) { + after = p.mData.mTreeNode; + } else { + after = BuildIdentifier(p.mData.mToken); + } + } + } + + XXportAsPairNode *n = (XXportAsPairNode*)gTreePool.NewTreeNode(sizeof(XXportAsPairNode)); + new (n) XXportAsPairNode(); + + if (before) + n->SetBefore(before); + if (after) + n->SetAfter(after); + + mLastTreeNode = n; + return mLastTreeNode; +} + +// It takes one arguments, the 'x' in the '* as x'. +TreeNode* ASTBuilder::BuildXXportAsPairEverything() { + MASSERT(mParams.size() == 1); + + TreeNode *tree = NULL; + + Param p = mParams[0]; + if (!p.mIsEmpty && p.mIsTreeNode) { + tree = p.mData.mTreeNode; + } + + XXportAsPairNode *n = (XXportAsPairNode*)gTreePool.NewTreeNode(sizeof(XXportAsPairNode)); + new (n) XXportAsPairNode(); + n->SetIsEverything(); + + if (tree) + n->SetBefore(tree); + + mLastTreeNode = n; + return mLastTreeNode; +} + +// It takes one arguments, the name after 'as'. +TreeNode* ASTBuilder::BuildXXportAsPairDefault() { + MASSERT(mParams.size() == 1); + + TreeNode *tree = NULL; + + Param p = mParams[0]; + if (!p.mIsEmpty && p.mIsTreeNode) { + tree = p.mData.mTreeNode; + } + + XXportAsPairNode *n = (XXportAsPairNode*)gTreePool.NewTreeNode(sizeof(XXportAsPairNode)); + new (n) XXportAsPairNode(); + n->SetIsDefault(); + + if (tree) + n->SetBefore(tree); + + mLastTreeNode = n; + return mLastTreeNode; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// BuildExternalDeclaration and BuildGlobalExternalDeclaration +///////////////////////////////////////////////////////////////////////////////////////// + +// It takes one arguments +TreeNode* ASTBuilder::BuildExternalDeclaration() { + MASSERT(mParams.size() == 1); + + TreeNode *tree = NULL; + + Param p = mParams[0]; + if (!p.mIsEmpty && p.mIsTreeNode) { + tree = p.mData.mTreeNode; + } + + DeclareNode *n = (DeclareNode*)gTreePool.NewTreeNode(sizeof(DeclareNode)); + new (n) DeclareNode(); + n->AddDecl(tree); + + mLastTreeNode = n; + return mLastTreeNode; +} + +// It takes one arguments +TreeNode* ASTBuilder::BuildGlobalExternalDeclaration() { + MASSERT(mParams.size() == 1); + + TreeNode *tree = NULL; + + Param p = mParams[0]; + if (!p.mIsEmpty && p.mIsTreeNode) { + tree = p.mData.mTreeNode; + } + + DeclareNode *n = (DeclareNode*)gTreePool.NewTreeNode(sizeof(DeclareNode)); + new (n) DeclareNode(); + n->AddDecl(tree); + n->SetIsGlobal(); + + mLastTreeNode = n; + return mLastTreeNode; } +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + // Takes one argument, the expression of the parenthesis TreeNode* ASTBuilder::BuildParenthesis() { if (mTrace) @@ -225,7 +775,7 @@ TreeNode* ASTBuilder::BuildParenthesis() { MASSERT(!p.mIsEmpty && p.mIsTreeNode); expr = p.mData.mTreeNode; - ParenthesisNode *n = (ParenthesisNode*)mTreePool->NewTreeNode(sizeof(ParenthesisNode)); + ParenthesisNode *n = (ParenthesisNode*)gTreePool.NewTreeNode(sizeof(ParenthesisNode)); new (n) ParenthesisNode(); n->SetExpr(expr); @@ -247,7 +797,7 @@ TreeNode* ASTBuilder::BuildCast() { TreeNode *desttype = p_a.mData.mTreeNode; TreeNode *expr = p_b.mData.mTreeNode; - CastNode *n = (CastNode*)mTreePool->NewTreeNode(sizeof(CastNode)); + CastNode *n = (CastNode*)gTreePool.NewTreeNode(sizeof(CastNode)); new (n) CastNode(); n->SetDestType(desttype); @@ -257,6 +807,35 @@ TreeNode* ASTBuilder::BuildCast() { return n; } +// It takes one parameter, the word tells what literal it is. +TreeNode* ASTBuilder::BuildLiteral() { + if (mTrace) + std::cout << "In BuildLiteral" << std::endl; + + MASSERT(mParams.size() == 1); + Param p_a = mParams[0]; + MASSERT(p_a.mIsTreeNode); + + TreeNode *tree = p_a.mData.mTreeNode; + bool is_void = false; + if (tree->IsPrimType()) { + PrimTypeNode *prim = (PrimTypeNode*)tree; + if (prim->GetPrimType() == TY_Void) + is_void = true; + } + + if (is_void) { + LitData data; + data.mType = LT_VoidLiteral; + LiteralNode *n = (LiteralNode*)gTreePool.NewTreeNode(sizeof(LiteralNode)); + new (n) LiteralNode(data); + mLastTreeNode = n; + return n; + } else { + MERROR("Unspported in BuildLiteral()."); + } +} + // For first parameter has to be an operator. TreeNode* ASTBuilder::BuildUnaryOperation() { @@ -272,7 +851,7 @@ TreeNode* ASTBuilder::BuildUnaryOperation() { MASSERT(token->IsOperator() && "First param of Unary Operator is not an operator token?"); // create the sub tree - UnaOperatorNode *n = (UnaOperatorNode*)mTreePool->NewTreeNode(sizeof(UnaOperatorNode)); + UnaOperatorNode *n = (UnaOperatorNode*)gTreePool.NewTreeNode(sizeof(UnaOperatorNode)); new (n) UnaOperatorNode(token->GetOprId()); // set 1st param @@ -282,7 +861,6 @@ TreeNode* ASTBuilder::BuildUnaryOperation() { TreeNode *tn = CreateTokenTreeNode(p_b.mData.mToken); n->SetOpnd(tn); } - n->GetOpnd()->SetParent(n); mLastTreeNode = n; return n; @@ -313,52 +891,234 @@ TreeNode* ASTBuilder::BuildBinaryOperation() { MASSERT(token->IsOperator() && "Second param of Binary Operator is not an operator token?"); // create the sub tree - BinOperatorNode *n = (BinOperatorNode*)mTreePool->NewTreeNode(sizeof(BinOperatorNode)); + BinOperatorNode *n = (BinOperatorNode*)gTreePool.NewTreeNode(sizeof(BinOperatorNode)); new (n) BinOperatorNode(token->GetOprId()); mLastTreeNode = n; // set 1st param if (p_a.mIsTreeNode) - n->mOpndA = p_a.mData.mTreeNode; + n->SetOpndA(p_a.mData.mTreeNode); else { TreeNode *tn = CreateTokenTreeNode(p_a.mData.mToken); - n->mOpndA = tn; + n->SetOpndA(tn); } - n->mOpndA->SetParent(n); // set 2nd param if (p_c.mIsTreeNode) - n->mOpndB = p_c.mData.mTreeNode; + n->SetOpndB(p_c.mData.mTreeNode); else { TreeNode *tn = CreateTokenTreeNode(p_c.mData.mToken); - n->mOpndB = tn; + n->SetOpndB(tn); } - n->mOpndB->SetParent(n); return n; } -// Assignment is actually a binary operator. -TreeNode* ASTBuilder::BuildAssignment() { +// For second parameter has to be an operator. +TreeNode* ASTBuilder::BuildTernaryOperation() { if (mTrace) - std::cout << "In assignment --> BuildBinary" << std::endl; - return BuildBinaryOperation(); -} + std::cout << "In BuildTernaryOperation" << std::endl; + + MASSERT(mParams.size() == 3 && "Ternary Operator has NO 3 params?"); + Param p_a = mParams[0]; + Param p_b = mParams[1]; + Param p_c = mParams[2]; + + // create the sub tree + TerOperatorNode *n = (TerOperatorNode*)gTreePool.NewTreeNode(sizeof(TerOperatorNode)); + new (n) TerOperatorNode(); + mLastTreeNode = n; + + MASSERT(p_a.mIsTreeNode); + n->SetOpndA(p_a.mData.mTreeNode); + + MASSERT(p_b.mIsTreeNode); + n->SetOpndB(p_b.mData.mTreeNode); + + MASSERT(p_c.mIsTreeNode); + n->SetOpndC(p_c.mData.mTreeNode); + + return n; +} + +// Takes one argument. Set the tree as a statement. +// We still return the previous mLastTreeNode. +TreeNode* ASTBuilder::SetIsStmt() { + if (mTrace) + std::cout << "In SetIsStmt" << std::endl; + + Param p_tree = mParams[0]; + if (!p_tree.mIsEmpty) { + MASSERT(p_tree.mIsTreeNode); + TreeNode *treenode = p_tree.mData.mTreeNode; + treenode->SetIsStmt(); + } + + return mLastTreeNode; +} + +// 1. Takes one argument. Set the tree as an optional node. +// 2. Takes no argument. Set mLastTreeNode as optional. +// We still return the previous mLastTreeNode. +TreeNode* ASTBuilder::SetIsOptional() { + if (mTrace) + std::cout << "In SetIsOptional" << std::endl; + + TreeNode *treenode = NULL; + if (mParams.size() > 0) { + Param p_tree = mParams[0]; + if (!p_tree.mIsEmpty) { + if (p_tree.mIsTreeNode) + treenode = p_tree.mData.mTreeNode; + else + treenode = BuildIdentifier(p_tree.mData.mToken); + } + } else { + treenode = mLastTreeNode; + } + + MASSERT(treenode); + if (treenode->IsFunction()) { + FunctionNode *f = (FunctionNode*)mLastTreeNode; + f->GetFuncName()->SetIsOptional(); + } else { + treenode->SetIsOptional(); + } + + return mLastTreeNode; +} + +// Takes one argument. Set the tree as a non null node. +// We still return the previous mLastTreeNode. +TreeNode* ASTBuilder::SetIsNonNull() { + if (mTrace) + std::cout << "In SetIsNonNull" << std::endl; + + Param p_tree = mParams[0]; + if (!p_tree.mIsEmpty) { + MASSERT(p_tree.mIsTreeNode); + TreeNode *treenode = p_tree.mData.mTreeNode; + treenode->SetIsNonNull(); + } + + return mLastTreeNode; +} + +// Takes one argument. Set the tree as a rest or spread node. +// We still return the previous mLastTreeNode. +TreeNode* ASTBuilder::SetIsRest() { + if (mTrace) + std::cout << "In SetIsRest" << std::endl; + + Param p_tree = mParams[0]; + if (!p_tree.mIsEmpty) { + MASSERT(p_tree.mIsTreeNode); + TreeNode *treenode = p_tree.mData.mTreeNode; + treenode->SetIsRest(); + } + + return mLastTreeNode; +} + +// Takes one argument. Set the tree as a constant node. +// Or takes no argument. Set mLastTreeNode as constant. +// We still return the previous mLastTreeNode. +TreeNode* ASTBuilder::SetIsConst() { + if (mTrace) + std::cout << "In SetIsConst" << std::endl; + + TreeNode *treenode = NULL; + + if (mParams.size() == 1) { + Param p_tree = mParams[0]; + if (!p_tree.mIsEmpty) { + MASSERT(p_tree.mIsTreeNode); + treenode = p_tree.mData.mTreeNode; + } + } else { + treenode = mLastTreeNode; + } + + treenode->SetIsConst(); + + mLastTreeNode = treenode; + return mLastTreeNode; +} + +// Takes one argument, which is a primary type node. Set the type as unique. +// Or takes no argument. Use mLastTreeNode as the argument. +TreeNode* ASTBuilder::SetIsUnique() { + if (mTrace) + std::cout << "In SetIsUnique" << std::endl; + + TreeNode *treenode = NULL; + + if (mParams.size() == 1) { + Param p_tree = mParams[0]; + if (!p_tree.mIsEmpty) { + MASSERT(p_tree.mIsTreeNode); + treenode = p_tree.mData.mTreeNode; + } + } else { + treenode = mLastTreeNode; + } + + MASSERT(treenode); + MASSERT(treenode->IsPrimType()); + PrimTypeNode *p = (PrimTypeNode*)treenode; + p->SetIsUnique(); + + return treenode; +} + + +// Assignment is actually a binary operator. +TreeNode* ASTBuilder::BuildAssignment() { + if (mTrace) + std::cout << "In assignment --> BuildBinary" << std::endl; + return BuildBinaryOperation(); +} // Takes one argument, the result expression +// Or takes 0 argument, and it's a simple return stmt. TreeNode* ASTBuilder::BuildReturn() { if (mTrace) std::cout << "In BuildReturn" << std::endl; - ReturnNode *result = (ReturnNode*)mTreePool->NewTreeNode(sizeof(ReturnNode)); + ReturnNode *result = (ReturnNode*)gTreePool.NewTreeNode(sizeof(ReturnNode)); new (result) ReturnNode(); - Param p_result = mParams[0]; - if (!p_result.mIsEmpty) { - if (!p_result.mIsTreeNode) - MERROR("The return value is not a tree node."); - TreeNode *result_value = p_result.mData.mTreeNode; - result->SetResult(result_value); + if (mParams.size() == 1) { + Param p_result = mParams[0]; + if (!p_result.mIsEmpty) { + if (!p_result.mIsTreeNode) + MERROR("The return value is not a tree node."); + TreeNode *result_value = p_result.mData.mTreeNode; + result->SetResult(result_value); + } + } + + mLastTreeNode = result; + return mLastTreeNode; +} + +// Takes one argument, the result expression +// Or takes 0 argument, and it's a simple return stmt. +TreeNode* ASTBuilder::BuildYield() { + if (mTrace) + std::cout << "In BuildYield" << std::endl; + + YieldNode *result = (YieldNode*)gTreePool.NewTreeNode(sizeof(YieldNode)); + new (result) YieldNode(); + + if (mParams.size() == 1) { + Param p_result = mParams[0]; + if (!p_result.mIsEmpty) { + if (!p_result.mIsTreeNode) + MERROR("The return value is not a tree node."); + TreeNode *result_value = p_result.mData.mTreeNode; + result->SetResult(result_value); + } } mLastTreeNode = result; @@ -370,7 +1130,7 @@ TreeNode* ASTBuilder::BuildCondBranch() { if (mTrace) std::cout << "In BuildCondBranch" << std::endl; - CondBranchNode *cond_branch = (CondBranchNode*)mTreePool->NewTreeNode(sizeof(CondBranchNode)); + CondBranchNode *cond_branch = (CondBranchNode*)gTreePool.NewTreeNode(sizeof(CondBranchNode)); new (cond_branch) CondBranchNode(); Param p_cond = mParams[0]; @@ -397,7 +1157,7 @@ TreeNode* ASTBuilder::AddCondBranchTrueStatement() { if (!p_true.mIsEmpty) { if (!p_true.mIsTreeNode) MERROR("The condition expr is not a tree node."); - TreeNode *true_expr = CvtToBlock(p_true.mData.mTreeNode); + TreeNode *true_expr = p_true.mData.mTreeNode; cond_branch->SetTrueBranch(true_expr); } @@ -414,7 +1174,7 @@ TreeNode* ASTBuilder::AddCondBranchFalseStatement() { if (!p_false.mIsEmpty) { if (!p_false.mIsTreeNode) MERROR("The condition expr is not a tree node."); - TreeNode *false_expr = CvtToBlock(p_false.mData.mTreeNode); + TreeNode *false_expr = p_false.mData.mTreeNode; cond_branch->SetFalseBranch(false_expr); } @@ -447,27 +1207,56 @@ TreeNode* ASTBuilder::AddLabel() { return tree; } -// BuildBreak takes one argument, an identifer node of empty. +// BuildBreak takes 1) one argument, an identifer node +// 2) empty TreeNode* ASTBuilder::BuildBreak() { if (mTrace) std::cout << "In BuildBreak " << std::endl; - BreakNode *break_node = (BreakNode*)mTreePool->NewTreeNode(sizeof(BreakNode)); + BreakNode *break_node = (BreakNode*)gTreePool.NewTreeNode(sizeof(BreakNode)); new (break_node) BreakNode(); - MASSERT(mParams.size() == 1 && "BuildBreak has NO 1 params?"); - Param p_target = mParams[0]; - if (!p_target.mIsEmpty) { - MASSERT(p_target.mIsTreeNode && "Target in BuildBreak is not a tree."); - TreeNode *target = p_target.mData.mTreeNode; - MASSERT(target->IsIdentifier() && "Target in BuildBreak is not an identifier."); - break_node->SetTarget(target); + TreeNode *target = NULL; + + if (mParams.size() == 1) { + Param p_target = mParams[0]; + if (!p_target.mIsEmpty) { + MASSERT(p_target.mIsTreeNode && "Target in BuildBreak is not a tree."); + target = p_target.mData.mTreeNode; + MASSERT(target->IsIdentifier() && "Target in BuildBreak is not an identifier."); + break_node->SetTarget(target); + } } mLastTreeNode = break_node; return break_node; } +// BuildContinue takes 1) one argument, an identifer node +// 2) empty +TreeNode* ASTBuilder::BuildContinue() { + if (mTrace) + std::cout << "In BuildContinue " << std::endl; + + ContinueNode *continue_node = (ContinueNode*)gTreePool.NewTreeNode(sizeof(ContinueNode)); + new (continue_node) ContinueNode(); + + TreeNode *target = NULL; + + if (mParams.size() == 1) { + Param p_target = mParams[0]; + if (!p_target.mIsEmpty) { + MASSERT(p_target.mIsTreeNode && "Target in BuildContinue is not a tree."); + target = p_target.mData.mTreeNode; + MASSERT(target->IsIdentifier() && "Target in BuildContinue is not an identifier."); + continue_node->SetTarget(target); + } + } + + mLastTreeNode = continue_node; + return continue_node; +} + // BuildForLoop takes four arguments. // 1. init statement, could be a list // 2. cond expression, should be a boolean expresion. @@ -477,7 +1266,7 @@ TreeNode* ASTBuilder::BuildForLoop() { if (mTrace) std::cout << "In BuildForLoop " << std::endl; - ForLoopNode *for_loop = (ForLoopNode*)mTreePool->NewTreeNode(sizeof(ForLoopNode)); + ForLoopNode *for_loop = (ForLoopNode*)gTreePool.NewTreeNode(sizeof(ForLoopNode)); new (for_loop) ForLoopNode(); MASSERT(mParams.size() == 4 && "BuildForLoop has NO 4 params?"); @@ -518,7 +1307,7 @@ TreeNode* ASTBuilder::BuildForLoop() { Param p_body = mParams[3]; if (!p_body.mIsEmpty) { MASSERT(p_body.mIsTreeNode && "ForLoop body is not a treenode."); - TreeNode *body = CvtToBlock(p_body.mData.mTreeNode); + TreeNode *body = p_body.mData.mTreeNode; for_loop->SetBody(body); } @@ -526,11 +1315,142 @@ TreeNode* ASTBuilder::BuildForLoop() { return mLastTreeNode; } +// BuildForLoop_In takes 3 or 2 arguments. +// If 3 arguments +// 1. The decl of variable. +// 2. The first explicit arg. This is the set of data +// 3. The body. +// If 2 arguments +// 1. The implicit arg, mLastTreeNode. This is a decl of variable. +// 2. The first explicit arg. This is the set of data +// 3. The body. +TreeNode* ASTBuilder::BuildForLoop_In() { + if (mTrace) + std::cout << "In BuildForLoop_In " << std::endl; + + ForLoopNode *for_loop = (ForLoopNode*)gTreePool.NewTreeNode(sizeof(ForLoopNode)); + new (for_loop) ForLoopNode(); + for_loop->SetProp(FLP_JSIn); + + TreeNode *the_var = NULL; + TreeNode *the_set = NULL; + TreeNode *the_body = NULL; + + if (mParams.size() == 3) { + Param p_var = mParams[0]; + if (!p_var.mIsEmpty) { + MASSERT(p_var.mIsTreeNode); + the_var = p_var.mData.mTreeNode; + } + + Param p_set = mParams[1]; + if (!p_set.mIsEmpty) { + MASSERT(p_set.mIsTreeNode); + the_set = p_set.mData.mTreeNode; + } + + Param p_body = mParams[2]; + if (!p_body.mIsEmpty) { + MASSERT(p_body.mIsTreeNode); + the_body = p_body.mData.mTreeNode; + } + } else { + MASSERT(mParams.size() == 2); + + the_var = mLastTreeNode; + + Param p_set = mParams[0]; + if (!p_set.mIsEmpty) { + MASSERT(p_set.mIsTreeNode); + the_set = p_set.mData.mTreeNode; + } + + Param p_body = mParams[1]; + if (!p_body.mIsEmpty) { + MASSERT(p_body.mIsTreeNode); + the_body = p_body.mData.mTreeNode; + } + } + + for_loop->SetVariable(the_var); + for_loop->SetSet(the_set); + for_loop->SetBody(the_body); + + mLastTreeNode = for_loop; + return mLastTreeNode; +} + +// BuildForLoop_Of takes 3 or 2 arguments. +// If 3 arguments +// 1. The decl of variable. +// 2. The first explicit arg. This is the set of data +// 3. The body. +// If 2 arguments +// 1. The implicit arg, mLastTreeNode. This is a decl of variable. +// 2. The first explicit arg. This is the set of data +// 3. The body. +TreeNode* ASTBuilder::BuildForLoop_Of() { + if (mTrace) + std::cout << "In BuildForLoop_Of " << std::endl; + + ForLoopNode *for_loop = (ForLoopNode*)gTreePool.NewTreeNode(sizeof(ForLoopNode)); + new (for_loop) ForLoopNode(); + for_loop->SetProp(FLP_JSOf); + + TreeNode *the_var = NULL; + TreeNode *the_set = NULL; + TreeNode *the_body = NULL; + + if (mParams.size() == 3) { + Param p_var = mParams[0]; + if (!p_var.mIsEmpty) { + MASSERT(p_var.mIsTreeNode); + the_var = p_var.mData.mTreeNode; + } + + Param p_set = mParams[1]; + if (!p_set.mIsEmpty) { + MASSERT(p_set.mIsTreeNode); + the_set = p_set.mData.mTreeNode; + } + + Param p_body = mParams[2]; + if (!p_body.mIsEmpty) { + MASSERT(p_body.mIsTreeNode); + the_body = p_body.mData.mTreeNode; + } + } else { + MASSERT(mParams.size() == 2); + + the_var = mLastTreeNode; + + Param p_set = mParams[0]; + if (!p_set.mIsEmpty) { + MASSERT(p_set.mIsTreeNode); + the_set = p_set.mData.mTreeNode; + } + + Param p_body = mParams[1]; + if (!p_body.mIsEmpty) { + MASSERT(p_body.mIsTreeNode); + the_body = p_body.mData.mTreeNode; + } + } + + for_loop->SetVariable(the_var); + for_loop->SetSet(the_set); + for_loop->SetBody(the_body); + + mLastTreeNode = for_loop; + return mLastTreeNode; +} + + TreeNode* ASTBuilder::BuildWhileLoop() { if (mTrace) std::cout << "In BuildWhileLoop " << std::endl; - WhileLoopNode *while_loop = (WhileLoopNode*)mTreePool->NewTreeNode(sizeof(WhileLoopNode)); + WhileLoopNode *while_loop = (WhileLoopNode*)gTreePool.NewTreeNode(sizeof(WhileLoopNode)); new (while_loop) WhileLoopNode(); MASSERT(mParams.size() == 2 && "BuildWhileLoop has NO 2 params?"); @@ -545,7 +1465,7 @@ TreeNode* ASTBuilder::BuildWhileLoop() { Param p_body = mParams[1]; if (!p_body.mIsEmpty) { MASSERT(p_body.mIsTreeNode && "WhileLoop body is not a treenode."); - TreeNode *body = CvtToBlock(p_body.mData.mTreeNode); + TreeNode *body = p_body.mData.mTreeNode; while_loop->SetBody(body); } @@ -557,7 +1477,7 @@ TreeNode* ASTBuilder::BuildDoLoop() { if (mTrace) std::cout << "In BuildDoLoop " << std::endl; - DoLoopNode *do_loop = (DoLoopNode*)mTreePool->NewTreeNode(sizeof(DoLoopNode)); + DoLoopNode *do_loop = (DoLoopNode*)gTreePool.NewTreeNode(sizeof(DoLoopNode)); new (do_loop) DoLoopNode(); MASSERT(mParams.size() == 2 && "BuildDoLoop has NO 2 params?"); @@ -572,7 +1492,7 @@ TreeNode* ASTBuilder::BuildDoLoop() { Param p_body = mParams[1]; if (!p_body.mIsEmpty) { MASSERT(p_body.mIsTreeNode && "DoLoop body is not a treenode."); - TreeNode *body = CvtToBlock(p_body.mData.mTreeNode); + TreeNode *body = p_body.mData.mTreeNode; do_loop->SetBody(body); } @@ -586,7 +1506,7 @@ TreeNode* ASTBuilder::BuildSwitchLabel() { std::cout << "In BuildSwitchLabel " << std::endl; SwitchLabelNode *label = - (SwitchLabelNode*)mTreePool->NewTreeNode(sizeof(SwitchLabelNode)); + (SwitchLabelNode*)gTreePool.NewTreeNode(sizeof(SwitchLabelNode)); new (label) SwitchLabelNode(); MASSERT(mParams.size() == 1 && "BuildSwitchLabel has NO 1 params?"); @@ -606,110 +1526,79 @@ TreeNode* ASTBuilder::BuildDefaultSwitchLabel() { if (mTrace) std::cout << "In BuildDefaultSwitchLabel " << std::endl; SwitchLabelNode *label = - (SwitchLabelNode*)mTreePool->NewTreeNode(sizeof(SwitchLabelNode)); + (SwitchLabelNode*)gTreePool.NewTreeNode(sizeof(SwitchLabelNode)); new (label) SwitchLabelNode(); label->SetIsDefault(true); mLastTreeNode = label; return label; } -// BuildOneCase takes two arguments, the expression of a label and a -// and the statements under the label. Both the label and the statements -// could be a PassNode, and I need look into it. We don't want to carry -// PassNode into the SwitchCaseNode. +// BuildOneCase takes +// 1. two arguments, the expression of a label and the statements under the label. +// 2. One arguemnt, which is the statements. The label is mLastTreeNode. TreeNode* ASTBuilder::BuildOneCase() { if (mTrace) std::cout << "In BuildOneCase " << std::endl; SwitchCaseNode *case_node = - (SwitchCaseNode*)mTreePool->NewTreeNode(sizeof(SwitchCaseNode)); + (SwitchCaseNode*)gTreePool.NewTreeNode(sizeof(SwitchCaseNode)); new (case_node) SwitchCaseNode(); - MASSERT(mParams.size() == 2 && "BuildOneCase has NO 1 params?"); + TreeNode *label = NULL; + TreeNode *stmt = NULL; - Param p_label = mParams[0]; - MASSERT(!p_label.mIsEmpty); - MASSERT(p_label.mIsTreeNode && "Labels in BuildOneCase is not a tree."); - TreeNode *label = p_label.mData.mTreeNode; - case_node->AddLabel(label); + if (mParams.size() == 2) { + Param p_label = mParams[0]; + if (!p_label.mIsEmpty) { + MASSERT(p_label.mIsTreeNode && "Labels in BuildOneCase is not a tree."); + label = p_label.mData.mTreeNode; + } + Param p_stmt = mParams[1]; + if (!p_stmt.mIsEmpty) { + MASSERT(p_stmt.mIsTreeNode && "Stmts in BuildOneCase is not a tree."); + stmt = p_stmt.mData.mTreeNode; + } + } else { + label = mLastTreeNode; + Param p_stmt = mParams[0]; + if (!p_stmt.mIsEmpty) { + MASSERT(p_stmt.mIsTreeNode && "Stmts in BuildOneCase is not a tree."); + stmt = p_stmt.mData.mTreeNode; + } + } - Param p_stmt = mParams[1]; - MASSERT(!p_stmt.mIsEmpty); - MASSERT(p_stmt.mIsTreeNode && "Stmts in BuildOneCase is not a tree."); - TreeNode *stmt = p_stmt.mData.mTreeNode; - case_node->AddStmt(stmt); + if (label) + case_node->AddLabel(label); + if (stmt) + case_node->AddStmt(stmt); mLastTreeNode = case_node; return case_node; } -SwitchCaseNode* ASTBuilder::SwitchLabelToCase(SwitchLabelNode *label) { - SwitchCaseNode *case_node = - (SwitchCaseNode*)mTreePool->NewTreeNode(sizeof(SwitchCaseNode)); - new (case_node) SwitchCaseNode(); - case_node->AddLabel(label); - return case_node; -} - -// This takes one argument, which is all SwitchCaseNode-s. It could be -// a PassNode. We don't handle it at all. We simply forward this tree node -// up to the parent, which should be final Switch Node. -TreeNode* ASTBuilder::BuildAllCases() { - if (mTrace) - std::cout << "In BuildAllCases " << std::endl; - - MASSERT(mParams.size() == 1 && "BuildAllCases has NO 1 params?"); - Param p_cases = mParams[0]; - MASSERT(!p_cases.mIsEmpty); - MASSERT(p_cases.mIsTreeNode && "Cases in BuildAllCases is not a tree."); - TreeNode *cases = p_cases.mData.mTreeNode; - - // We want to make sure every tree node after BuildAllCases() is - // a SwitchCaseNode. This will ease the handling in future AST process. - // So for those SwitchLabelNode which only have no statement, will be - // converted to a SwitchCaseNode. - - if (cases->IsPass()) { - PassNode *pass = (PassNode*)cases; - for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { - TreeNode *child = pass->GetChild(i); - if (child->IsSwitchLabel()) { - SwitchCaseNode *newcase = SwitchLabelToCase((SwitchLabelNode*)child); - pass->SetChild(i, newcase); - } - } - } else if (cases->IsSwitchLabel()) { - SwitchLabelNode *label = (SwitchLabelNode*)cases; - SwitchCaseNode *newcase = SwitchLabelToCase(label); - cases = newcase; - } - - mLastTreeNode = cases; - return cases; -} - TreeNode* ASTBuilder::BuildSwitch() { if (mTrace) std::cout << "In BuildSwitch " << std::endl; SwitchNode *switch_node = - (SwitchNode*)mTreePool->NewTreeNode(sizeof(SwitchNode)); + (SwitchNode*)gTreePool.NewTreeNode(sizeof(SwitchNode)); new (switch_node) SwitchNode(); MASSERT(mParams.size() == 2 && "BuildSwitch has NO 1 params?"); - Param p_cond = mParams[0]; - MASSERT(!p_cond.mIsEmpty); - MASSERT(p_cond.mIsTreeNode && "Condition in BuildSwitch is not a tree."); - TreeNode *cond = p_cond.mData.mTreeNode; - switch_node->SetCond(cond); + Param p_expr = mParams[0]; + MASSERT(!p_expr.mIsEmpty); + MASSERT(p_expr.mIsTreeNode && "Expression in BuildSwitch is not a tree."); + TreeNode *expr = p_expr.mData.mTreeNode; + switch_node->SetExpr(expr); Param p_cases = mParams[1]; MASSERT(!p_cases.mIsEmpty); MASSERT(p_cases.mIsTreeNode && "Cases in BuildSwitch is not a tree."); TreeNode *cases = p_cases.mData.mTreeNode; - switch_node->AddCase(cases); + + switch_node->AddSwitchCase(cases); mLastTreeNode = switch_node; return switch_node; @@ -723,118 +1612,610 @@ TreeNode* ASTBuilder::BuildSwitch() { // We need have a list of pending declarations until the scope is created. //////////////////////////////////////////////////////////////////////////////// -// AddTypeTo takes two parameters, 1) tree; 2) type -TreeNode* ASTBuilder::AddTypeTo() { +// AddType takes two parameters, 1) tree; 2) type +// or takes one parameter, type, and apply it to mLastTreeNode +TreeNode* ASTBuilder::AddType() { if (mTrace) - std::cout << "In AddTypeTo " << std::endl; + std::cout << "In AddType " << std::endl; - MASSERT(mParams.size() == 2 && "BinaryDecl has NO 2 params?"); - Param p_type = mParams[1]; - Param p_name = mParams[0]; + TreeNode *node = NULL; + TreeNode *tree_type = NULL; + + if (mParams.size() == 2) { + Param p_type = mParams[1]; + Param p_name = mParams[0]; - MASSERT(!p_type.mIsEmpty && p_type.mIsTreeNode - && "Not appropriate type node in AddTypeTo()"); - TreeNode *tree_type = p_type.mData.mTreeNode; + if(!p_type.mIsEmpty && p_type.mIsTreeNode) + tree_type = p_type.mData.mTreeNode; - if (!p_name.mIsTreeNode) - MERROR("The variable name should be a IdentifierNode already, but actually NOT?"); - TreeNode *node = p_name.mData.mTreeNode; + if (!p_name.mIsTreeNode) + MERROR("The variable name should be a IdentifierNode already, but actually NOT?"); + node = p_name.mData.mTreeNode; + + } else { + Param p_type = mParams[0]; + if(!p_type.mIsEmpty && p_type.mIsTreeNode) + tree_type = p_type.mData.mTreeNode; + node = mLastTreeNode; + } - add_type_to(node, tree_type); + if (tree_type) + add_type_to(node, tree_type); - return node; + mLastTreeNode = node; + return mLastTreeNode; } -// BuildDecl takes two parameters, 1) type; 2) name -TreeNode* ASTBuilder::BuildDecl() { +// AddType takes two parameters, 1) tree; 2) type +// or takes one parameter, type, and apply it to mLastTreeNode +TreeNode* ASTBuilder::AddAsType() { if (mTrace) - std::cout << "In BuildDecl" << std::endl; - - MASSERT(mParams.size() == 2 && "BinaryDecl has NO 2 params?"); - Param p_type = mParams[0]; - Param p_name = mParams[1]; + std::cout << "In AddAsType " << std::endl; - MASSERT(!p_type.mIsEmpty && p_type.mIsTreeNode - && "Not appropriate type node in BuildDecl()"); - TreeNode *tree_type = p_type.mData.mTreeNode; + TreeNode *node = NULL; + TreeNode *tree_type = NULL; - if (!p_name.mIsTreeNode) - MERROR("The variable name should be a IdentifierNode already, but actually NOT?"); - TreeNode *node = p_name.mData.mTreeNode; + if (mParams.size() == 2) { + Param p_type = mParams[1]; + Param p_name = mParams[0]; + if(!p_type.mIsEmpty) { + if(p_type.mIsTreeNode) + tree_type = p_type.mData.mTreeNode; + else + MERROR("The variable name should be a IdentifierNode already, but actually NOT?"); + } + node = p_name.mData.mTreeNode; + } else { + Param p_type = mParams[0]; + if(!p_type.mIsEmpty && p_type.mIsTreeNode) + tree_type = p_type.mData.mTreeNode; + node = mLastTreeNode; + } - add_type_to(node, tree_type); + if (tree_type) { + node->AddAsTypes(tree_type); + } mLastTreeNode = node; - return node; + return mLastTreeNode; } -// BuildField takes two parameters, -// 1) upper enclosing node, could be another field. -// 2) name of this field. -TreeNode* ASTBuilder::BuildField() { +// BuildDecl usually takes two parameters, 1) type; 2) name +// It can also take only one parameter: name. +// It can also take zero parameter, it's mLastTreeNode handled. +TreeNode* ASTBuilder::BuildDecl() { if (mTrace) - std::cout << "In BuildField" << std::endl; + std::cout << "In BuildDecl" << std::endl; - MASSERT(mParams.size() == 2 && "BuildField has NO 2 params?"); - Param p_var_a = mParams[0]; - Param p_var_b = mParams[1]; + TreeNode *tree_type = NULL; + TreeNode *var = NULL; - // Both variable should have been created as tree node. - if (!p_var_a.mIsTreeNode || !p_var_b.mIsTreeNode) { - MERROR("The param in BuildField is not a treenode"); + if (mParams.size() == 2) { + Param p_type = mParams[0]; + Param p_name = mParams[1]; + if(!p_type.mIsEmpty && p_type.mIsTreeNode) + tree_type = p_type.mData.mTreeNode; + + if (!p_name.mIsTreeNode) + MERROR("The variable name should be a IdentifierNode already, but actually NOT?"); + var = p_name.mData.mTreeNode; + + if (tree_type) + add_type_to(var, tree_type); + + } else if (mParams.size() == 1) { + Param p_name = mParams[0]; + if (!p_name.mIsTreeNode) + MERROR("The variable name should be a IdentifierNode already, but actually NOT?"); + var = p_name.mData.mTreeNode; + } else { + var = mLastTreeNode; } - // The second param should be an IdentifierNode - TreeNode *node_a = p_var_a.mIsEmpty ? NULL : p_var_a.mData.mTreeNode; - TreeNode *node_b = p_var_b.mIsEmpty ? NULL : p_var_b.mData.mTreeNode; + DeclNode *decl = decl = (DeclNode*)gTreePool.NewTreeNode(sizeof(DeclNode)); + new (decl) DeclNode(var); - FieldNode *field = NULL; + mLastTreeNode = decl; + return decl; +} - if (node_b->IsPass()) { - TreeNode *upper = node_a; - PassNode *pass = (PassNode*)node_b; - for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { - TreeNode *child = pass->GetChild(i); - MASSERT(child->IsIdentifier()); +TreeNode* ASTBuilder::SetJSVar() { + MASSERT(mLastTreeNode->IsDecl()); + DeclNode *decl = (DeclNode*)mLastTreeNode; + decl->SetProp(JS_Var); + return mLastTreeNode; +} - field = (FieldNode*)mTreePool->NewTreeNode(sizeof(FieldNode)); - new (field) FieldNode(); - field->SetUpper(upper); - field->SetField((IdentifierNode*)child); - field->Init(); +TreeNode* ASTBuilder::SetJSLet() { + MASSERT(mLastTreeNode->IsDecl()); + DeclNode *decl = (DeclNode*)mLastTreeNode; + decl->SetProp(JS_Let); + return mLastTreeNode; +} - upper = field; - } +TreeNode* ASTBuilder::SetJSConst() { + MASSERT(mLastTreeNode->IsDecl()); + DeclNode *decl = (DeclNode*)mLastTreeNode; + decl->SetProp(JS_Const); + return mLastTreeNode; +} + +////////////////////////////////////////////////////////////////////////////////// +// ArrayElement, ArrayLiteral +////////////////////////////////////////////////////////////////////////////////// + +// It takes two or more than two params. +// The first is the array. +// The second is the first dimension expression +// So on so forth. + +TreeNode* ASTBuilder::BuildArrayElement() { + if (mTrace) + std::cout << "In BuildArrayElement" << std::endl; + + MASSERT(mParams.size() >= 2); + + Param p_array = mParams[0]; + MASSERT(p_array.mIsTreeNode); + TreeNode *array = p_array.mData.mTreeNode; + MASSERT(array->IsIdentifier() || + array->IsArrayElement() || + array->IsField() || + array->IsUserType() || + array->IsBinOperator() || + array->IsCall() || + (array->IsLiteral() && ((LiteralNode*)array)->IsThis()) || + array->IsTupleType() || + array->IsStruct() || + array->IsNew() || + array->IsTypeOf() || + array->IsCast() || + array->IsPrimType()); + + ArrayElementNode *array_element = NULL; + if (array->IsIdentifier() || + array->IsField() || + array->IsUserType() || + array->IsBinOperator() || + array->IsCall() || + array->IsTupleType() || + (array->IsLiteral() && ((LiteralNode*)array)->IsThis()) || + array->IsStruct() || + array->IsNew() || + array->IsTypeOf() || + array->IsCast() || + array->IsPrimType()) { + array_element = (ArrayElementNode*)gTreePool.NewTreeNode(sizeof(ArrayElementNode)); + new (array_element) ArrayElementNode(); + array_element->SetArray(array); } else { - MASSERT(node_b->IsIdentifier()); - field = (FieldNode*)mTreePool->NewTreeNode(sizeof(FieldNode)); - new (field) FieldNode(); - field->SetUpper(node_a); - field->SetField((IdentifierNode*)node_b); - field->Init(); + array_element = (ArrayElementNode*)array; } - mLastTreeNode = field; + unsigned num = mParams.size() - 1; + for (unsigned i = 0; i < num; i++) { + Param p_index = mParams[i+1]; + MASSERT(p_index.mIsTreeNode); + TreeNode *index = p_index.mData.mTreeNode; + array_element->AddExpr(index); + } + + mLastTreeNode = array_element; return mLastTreeNode; } -// BuildVariableList takes two parameters, var 1 and var 2 -TreeNode* ASTBuilder::BuildVarList() { +// It takes only one parameter, the literals. +TreeNode* ASTBuilder::BuildArrayLiteral() { if (mTrace) - std::cout << "In build Variable List" << std::endl; + std::cout << "In BuildArrayLiteral" << std::endl; - MASSERT(mParams.size() == 2 && "BuildVarList has NO 2 params?"); - Param p_var_a = mParams[0]; - Param p_var_b = mParams[1]; + MASSERT(mParams.size() == 1); - // Both variable should have been created as tree node. - if (!p_var_a.mIsTreeNode || !p_var_b.mIsTreeNode) { - MERROR("The var in BuildVarList is not a treenode"); + // The parameter could be empty, meaning the literal is like: []. + // But it still is a array literal, and we create one for it with 0 expressions. + ArrayLiteralNode *array_literal = (ArrayLiteralNode*)gTreePool.NewTreeNode(sizeof(ArrayLiteralNode)); + new (array_literal) ArrayLiteralNode(); + + Param p_literals = mParams[0]; + if (!p_literals.mIsEmpty) { + MASSERT(p_literals.mIsTreeNode); + TreeNode *literals = p_literals.mData.mTreeNode; + MASSERT(literals->IsLiteral() || + literals->IsIdentifier() || + literals->IsNew() || + literals->IsExprList() || + literals->IsArrayLiteral() || + literals->IsStructLiteral() || + literals->IsFieldLiteral() || + literals->IsCall() || + literals->IsArrayElement() || + literals->IsField() || + literals->IsBinOperator() || + literals->IsUnaOperator() || + literals->IsTerOperator() || + literals->IsRegExpr() || + literals->IsFunction() || + literals->IsTemplateLiteral() || + literals->IsLambda()); + if (literals->IsExprList()) { + ExprListNode *el = (ExprListNode*)literals; + for (unsigned i = 0; i < el->GetExprsNum(); i++) { + TreeNode *expr = el->GetExprAtIndex(i); + MASSERT(expr->IsLiteral() || + expr->IsNew() || + expr->IsArrayLiteral() || + expr->IsFieldLiteral() || + expr->IsStructLiteral() || + expr->IsIdentifier() || + expr->IsCall() || + expr->IsArrayElement() || + expr->IsField() || + expr->IsBinOperator() || + expr->IsUnaOperator() || + expr->IsTerOperator() || + expr->IsRegExpr() || + expr->IsFunction() || + expr->IsTemplateLiteral() || + expr->IsLambda()); + array_literal->AddLiteral(expr); + } + } else { + array_literal->AddLiteral(literals); + } } - TreeNode *node_a = p_var_a.mIsEmpty ? NULL : p_var_a.mData.mTreeNode; - TreeNode *node_b = p_var_b.mIsEmpty ? NULL : p_var_b.mData.mTreeNode; - + mLastTreeNode = array_literal; + return mLastTreeNode; +} + +////////////////////////////////////////////////////////////////////////////////// +// BindingElement and BindingPattern +////////////////////////////////////////////////////////////////////////////////// + +// It could take: +// 1) Two arguments, 'variable' name and 'element' to bind +// 2) one argument, the 'element' +TreeNode* ASTBuilder::BuildBindingElement() { + if (mTrace) + std::cout << "In BuildBindingElement" << std::endl; + + BindingElementNode *be_node = NULL; + + if (mParams.size() == 2) { + Param p_variable = mParams[0]; + MASSERT(p_variable.mIsTreeNode); + TreeNode *variable = p_variable.mData.mTreeNode; + + Param p_element = mParams[1]; + MASSERT(p_element.mIsTreeNode); + TreeNode *element = p_element.mData.mTreeNode; + + // There are a few cases. + // 1. If element is an existing binding element, we just add the 'variable'. + // 2. If element is a binding pattern, we need create new binding element. + // 3. If element is anything else, we need create new binding element. + if (element->IsBindingElement()) { + be_node = (BindingElementNode*)element; + be_node->SetVariable(variable); + } else { + be_node = (BindingElementNode*)gTreePool.NewTreeNode(sizeof(BindingElementNode)); + new (be_node) BindingElementNode(); + be_node->SetVariable(variable); + be_node->SetElement(element); + } + } else if (mParams.size() == 1) { + Param p_element = mParams[0]; + MASSERT(p_element.mIsTreeNode); + TreeNode *element = p_element.mData.mTreeNode; + + be_node = (BindingElementNode*)gTreePool.NewTreeNode(sizeof(BindingElementNode)); + new (be_node) BindingElementNode(); + be_node->SetElement(element); + } else { + MASSERT(0 && "unsupported number of arguments in BuildBindingElemnt."); + } + + mLastTreeNode = be_node; + return mLastTreeNode; +} + +// It could take: +// 1) zero arguments. it is an empty binding pattern. +// 2) one argument, the 'element' or passnode containing list of elements. +TreeNode* ASTBuilder::BuildBindingPattern() { + if (mTrace) + std::cout << "In BuildBindingPattern" << std::endl; + + BindingPatternNode *bp = NULL; + + if (mParams.size() == 1) { + Param p_element = mParams[0]; + MASSERT(p_element.mIsTreeNode); + TreeNode *element = p_element.mData.mTreeNode; + + bp = (BindingPatternNode*)gTreePool.NewTreeNode(sizeof(BindingPatternNode)); + new (bp) BindingPatternNode(); + bp->AddElement(element); + } else if (mParams.size() == 0) { + // an empty binding pattern + bp = (BindingPatternNode*)gTreePool.NewTreeNode(sizeof(BindingPatternNode)); + new (bp) BindingPatternNode(); + } else { + MASSERT(0 && "unsupported number of arguments in BuildBindingElemnt."); + } + + mLastTreeNode = bp; + return mLastTreeNode; +} + +TreeNode* ASTBuilder::SetArrayBinding() { + MASSERT(mLastTreeNode->IsBindingPattern()); + BindingPatternNode *b = (BindingPatternNode*)mLastTreeNode; + b->SetProp(BPP_ArrayBinding); + return mLastTreeNode; +} + +TreeNode* ASTBuilder::SetObjectBinding() { + MASSERT(mLastTreeNode->IsBindingPattern()); + BindingPatternNode *b = (BindingPatternNode*)mLastTreeNode; + b->SetProp(BPP_ObjectBinding); + return mLastTreeNode; +} + +////////////////////////////////////////////////////////////////////////////////// +// StructNode, StructLiteralNode, FieldLiteralNode +////////////////////////////////////////////////////////////////////////////////// + +// It takes two parameters: name of key, the data type. +TreeNode* ASTBuilder::BuildNumIndexSig() { + if (mTrace) + std::cout << "In BuildNumIndexSig" << std::endl; + + Param p_key = mParams[0]; + MASSERT(p_key.mIsTreeNode); + TreeNode *key = p_key.mData.mTreeNode; + + Param p_data = mParams[1]; + MASSERT(p_data.mIsTreeNode); + TreeNode *data = p_data.mData.mTreeNode; + + NumIndexSigNode *sig = (NumIndexSigNode*)gTreePool.NewTreeNode(sizeof(NumIndexSigNode)); + new (sig) NumIndexSigNode(); + sig->SetKey(key); + sig->SetDataType(data); + + mLastTreeNode = sig; + return mLastTreeNode; +} + +// It takes two parameters: name of key, the data type. +TreeNode* ASTBuilder::BuildStrIndexSig() { + if (mTrace) + std::cout << "In BuildStrIndexSig" << std::endl; + + Param p_key = mParams[0]; + MASSERT(p_key.mIsTreeNode); + TreeNode *key = p_key.mData.mTreeNode; + + Param p_data = mParams[1]; + MASSERT(p_data.mIsTreeNode); + TreeNode *data = p_data.mData.mTreeNode; + + StrIndexSigNode *sig = (StrIndexSigNode*)gTreePool.NewTreeNode(sizeof(StrIndexSigNode)); + new (sig) StrIndexSigNode(); + sig->SetKey(key); + sig->SetDataType(data); + + mLastTreeNode = sig; + return mLastTreeNode; +} + +// It takes only one parameter: name. +// Or it take no param, meaning the name is empty. +TreeNode* ASTBuilder::BuildStruct() { + if (mTrace) + std::cout << "In BuildStruct" << std::endl; + + TreeNode *name = NULL; + + if (mParams.size() == 1) { + Param p_name = mParams[0]; + MASSERT(p_name.mIsTreeNode); + name = p_name.mData.mTreeNode; + MASSERT(name->IsIdentifier()); + } + + StructNode *struct_node = (StructNode*)gTreePool.NewTreeNode(sizeof(StructNode)); + new (struct_node) StructNode((IdentifierNode*)name); + + mLastTreeNode = struct_node; + return mLastTreeNode; +} + +// It take no param. +TreeNode* ASTBuilder::BuildTupleType() { + if (mTrace) + std::cout << "In BuildTupleType" << std::endl; + + TupleTypeNode *tuple_type = (TupleTypeNode*)gTreePool.NewTreeNode(sizeof(TupleTypeNode)); + new (tuple_type) TupleTypeNode(); + + mLastTreeNode = tuple_type; + return mLastTreeNode; +} + +// It takes only one parameter: Field. +TreeNode* ASTBuilder::AddStructField() { + if (mTrace) + std::cout << "In AddStructField" << std::endl; + Param p_field = mParams[0]; + if (!p_field.mIsEmpty) { + MASSERT(p_field.mIsTreeNode); + TreeNode *field = p_field.mData.mTreeNode; + + if (mLastTreeNode->IsStruct()) { + StructNode *struct_node = (StructNode*)mLastTreeNode; + struct_node->AddChild(field); + } else if (mLastTreeNode->IsTupleType()) { + TupleTypeNode *tt = (TupleTypeNode*)mLastTreeNode; + tt->AddChild(field); + } else { + MERROR("Unsupported in AddStructField()"); + } + } + return mLastTreeNode; +} + +TreeNode* ASTBuilder::SetTSInterface() { + MASSERT(mLastTreeNode->IsStruct()); + StructNode *s = (StructNode*)mLastTreeNode; + s->SetProp(SProp_TSInterface); + return mLastTreeNode; +} + +TreeNode* ASTBuilder::SetTSEnum() { + MASSERT(mLastTreeNode->IsStruct()); + StructNode *s = (StructNode*)mLastTreeNode; + s->SetProp(SProp_TSEnum); + return mLastTreeNode; +} + +// Build FieldLiteral +// It takes two param, field name and field value (a literal). +TreeNode* ASTBuilder::BuildFieldLiteral() { + if (mTrace) + std::cout << "In BuildFieldLiteral" << std::endl; + + TreeNode *field = NULL; + Param p_field = mParams[0]; + if (p_field.mIsTreeNode) { + field = p_field.mData.mTreeNode; + } else { + field = BuildIdentifier(p_field.mData.mToken); + } + + Param p_value = mParams[1]; + MASSERT(p_value.mIsTreeNode); + TreeNode *value = p_value.mData.mTreeNode; + + FieldLiteralNode *field_literal = (FieldLiteralNode*)gTreePool.NewTreeNode(sizeof(FieldLiteralNode)); + new (field_literal) FieldLiteralNode(); + field_literal->SetFieldName(field); + field_literal->SetLiteral(value); + + mLastTreeNode = field_literal; + return mLastTreeNode; +} + +// 1) It takes no param. We create an empty struct litreal. +// 2) It takes one param. The param could a FieldLiteralNode or +// a PassNode containing multiple FieldLiteralNode. +// +// The param could also be a GetAccessor/SetAccessor in Javascript, +// which is a function node. We take the name of function as field name, +// the FunctionNode as the value. +TreeNode* ASTBuilder::BuildStructLiteral() { + if (mTrace) + std::cout << "In BuildStructLiteral" << std::endl; + + TreeNode *literal = NULL; + + if (mParams.size() == 1) { + Param p_literal = mParams[0]; + MASSERT(p_literal.mIsTreeNode); + literal = p_literal.mData.mTreeNode; + } + + StructLiteralNode *struct_literal = (StructLiteralNode*)gTreePool.NewTreeNode(sizeof(StructLiteralNode)); + new (struct_literal) StructLiteralNode(); + + if (literal) + struct_literal->AddField(literal); + + mLastTreeNode = struct_literal; + return mLastTreeNode; +} + +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +// BuildField takes two parameters, +// 1) upper enclosing node, could be another field. +// 2) name of this field. +TreeNode* ASTBuilder::BuildField() { + if (mTrace) + std::cout << "In BuildField" << std::endl; + + MASSERT(mParams.size() == 2 && "BuildField has NO 2 params?"); + Param p_var_a = mParams[0]; + Param p_var_b = mParams[1]; + + // Both variable should have been created as tree node. + MASSERT(p_var_a.mIsTreeNode); + + // The second param should be an IdentifierNode + TreeNode *node_a = p_var_a.mIsEmpty ? NULL : p_var_a.mData.mTreeNode; + TreeNode *node_b = NULL; + if (!p_var_b.mIsEmpty) { + if (p_var_b.mIsTreeNode) { + node_b = p_var_b.mData.mTreeNode; + if (!node_b->IsIdentifier() && !node_b->IsComputedName()) { + TreeNode *id = BuildIdentifier(node_b); + if (id) + node_b = id; + } + } else { + node_b = BuildIdentifier(p_var_b.mData.mToken); + } + } + + FieldNode *field = NULL; + + if (node_b->IsPass()) { + TreeNode *upper = node_a; + PassNode *pass = (PassNode*)node_b; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { + TreeNode *child = pass->GetChild(i); + MASSERT(child->IsIdentifier()); + + field = (FieldNode*)gTreePool.NewTreeNode(sizeof(FieldNode)); + new (field) FieldNode(); + field->SetUpper(upper); + field->SetField((IdentifierNode*)child); + + upper = field; + } + } else { + MASSERT(node_b->IsIdentifier() || + node_b->IsCall() || + node_b->IsUserType()); + field = (FieldNode*)gTreePool.NewTreeNode(sizeof(FieldNode)); + new (field) FieldNode(); + field->SetUpper(node_a); + field->SetField(node_b); + } + + mLastTreeNode = field; + return mLastTreeNode; +} + +// BuildVariableList takes two parameters, var 1 and var 2 +TreeNode* ASTBuilder::BuildVarList() { + if (mTrace) + std::cout << "In build Variable List" << std::endl; + + MASSERT(mParams.size() == 2 && "BuildVarList has NO 2 params?"); + Param p_var_a = mParams[0]; + Param p_var_b = mParams[1]; + + // Both variable should have been created as tree node. + if (!p_var_a.mIsTreeNode || !p_var_b.mIsTreeNode) { + MERROR("The var in BuildVarList is not a treenode"); + } + + TreeNode *node_a = p_var_a.mIsEmpty ? NULL : p_var_a.mData.mTreeNode; + TreeNode *node_b = p_var_b.mIsEmpty ? NULL : p_var_b.mData.mTreeNode; + // There are a few different scenarios. // (1) node_a is a VarListNode, and we dont care about node_b // (2) node_a is an IdentifierNode, node_b is a VarListNode @@ -851,7 +2232,7 @@ TreeNode* ASTBuilder::BuildVarList() { node_ret->Merge(node_a); } else { // both nodes are not VarListNode - node_ret = (VarListNode*)mTreePool->NewTreeNode(sizeof(VarListNode)); + node_ret = (VarListNode*)gTreePool.NewTreeNode(sizeof(VarListNode)); new (node_ret) VarListNode(); if (node_a) node_ret->Merge(node_a); @@ -866,37 +2247,110 @@ TreeNode* ASTBuilder::BuildVarList() { } // Attach the modifier(s) to mLastTreeNode. +// It takes: +// 1. One argument, which is the solo modifier. +// 2. Two arguments, which happens mostly in Typescript, like +// + readonly +// - readonly +// + ? +// - ? TreeNode* ASTBuilder::AddModifier() { if (mTrace) std::cout << "In AddModifier" << std::endl; - Param p_mod = mParams[0]; - if (p_mod.mIsEmpty) { - if (mTrace) - std::cout << " do nothing." << std::endl; - return mLastTreeNode; - } + if (mParams.size() == 1) { + Param p_mod = mParams[0]; + if (p_mod.mIsEmpty) { + if (mTrace) + std::cout << " do nothing." << std::endl; + return mLastTreeNode; + } - if (!p_mod.mIsTreeNode) - MERROR("The modifier is not a treenode"); - TreeNode *mod= p_mod.mData.mTreeNode; + TreeNode *mod = NULL; + if (!p_mod.mIsTreeNode) { + Token *token = p_mod.mData.mToken; + if (token->IsSeparator() && token->GetSepId()==SEP_Pound) { + // This is a '#' in front of class member in Javascript. + // This is a 'private' modifier. + AttrNode *an = gAttrPool.GetAttrNode(ATTR_private); + MASSERT(an); + mod = an; + } else { + MERROR("The modifier is not a treenode"); + } + } else { + mod= p_mod.mData.mTreeNode; + } - if (mod->IsPass()) { - PassNode *pass = (PassNode*)mod; - for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { - TreeNode *child = pass->GetChild(i); - if (child->IsAnnotation()) { - AnnotationNode *a = (AnnotationNode*)child; - mLastTreeNode->AddAnnotation(a); + if (mod->IsPass()) { + PassNode *pass = (PassNode*)mod; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { + TreeNode *child = pass->GetChild(i); + if (child->IsAnnotation()) { + AnnotationNode *a = (AnnotationNode*)child; + mLastTreeNode->AddAnnotation(a); + } else { + add_attribute_to(mLastTreeNode, child); + } + } + } else if (mod->IsAnnotation()) { + AnnotationNode *a = (AnnotationNode*)mod; + mLastTreeNode->AddAnnotation(a); + } else { + add_attribute_to(mLastTreeNode, mod); + } + } else if (mParams.size() == 2) { + // the two modifiers are in fixed order, with +/- at first + // readonly/? the second. + bool add = false; // add opr if true, rem if false + bool readonly = false; + bool optional = false; + Param p_opr = mParams[0]; + if (p_opr.mIsEmpty) { + add = true; + } else { + MASSERT(!p_opr.mIsTreeNode); + Token *token= p_opr.mData.mToken; + if (token->GetOprId() == OPR_Add) + add = true; + else if (token->GetOprId() == OPR_Sub) + add = false; + else + MERROR("unsupported opr id."); + } + + Param p_prop = mParams[1]; + if (!p_prop.mIsEmpty) { + if (!p_prop.mIsTreeNode) { + Token *token= p_prop.mData.mToken; + MASSERT(token->IsSeparator() && (token->GetSepId() == SEP_Select)); + optional = true; + } else { + TreeNode *tree = p_prop.mData.mTreeNode; + MASSERT(tree->IsAttr()); + AttrNode *attr = (AttrNode*)tree; + MASSERT(attr->GetId() == ATTR_readonly); + readonly = true; + } + + MASSERT(mLastTreeNode->IsComputedName()); + ComputedNameNode *cnn = (ComputedNameNode*)mLastTreeNode; + if (add) { + if (readonly) + cnn->SetProp((unsigned)CNP_Add_ReadOnly); + else if (optional) + cnn->SetProp((unsigned)CNP_Add_Optional); + else + MERROR("unsupported property."); } else { - add_attribute_to(mLastTreeNode, child); + if (readonly) + cnn->SetProp((unsigned)CNP_Rem_ReadOnly); + else if (optional) + cnn->SetProp((unsigned)CNP_Rem_Optional); + else + MERROR("unsupported property."); } } - } else if (mod->IsAnnotation()) { - AnnotationNode *a = (AnnotationNode*)mod; - mLastTreeNode->AddAnnotation(a); - } else { - add_attribute_to(mLastTreeNode, mod); } return mLastTreeNode; @@ -943,55 +2397,151 @@ TreeNode* ASTBuilder::AddModifierTo() { return tree; } -TreeNode* ASTBuilder::AddInitTo() { +// It takes one argument, the init. +// Apply init to mLastTreeNode +TreeNode* ASTBuilder::AddInit() { if (mTrace) - std::cout << "In AddInitTo" << std::endl; - Param p_decl = mParams[0]; - Param p_init; + std::cout << "In AddInit" << std::endl; - // If there is no init value, return NULL. - if (mParams.size() == 1) - return NULL; + MASSERT(mParams.size() == 1); - p_init = mParams[1]; + Param p_init = mParams[0]; if (p_init.mIsEmpty) return NULL; - // Both variable should have been created as tree node. - if (!p_decl.mIsTreeNode || !p_init.mIsTreeNode) - MERROR("The decl or init is not a treenode in AddInitTo()"); + if (!p_init.mIsTreeNode) + MERROR("The init is not a treenode in AddInit()"); - TreeNode *node_decl = p_decl.mData.mTreeNode; TreeNode *node_init = p_init.mData.mTreeNode; - if (!node_decl->IsIdentifier()) - MERROR("The target of AddInitTo should be an indentifier node. Not?"); + if (mLastTreeNode->IsIdentifier()) { + IdentifierNode *in = (IdentifierNode*)mLastTreeNode; + in->SetInit(node_init); + return in; + } else if (mLastTreeNode->IsBindingPattern()) { + BindingPatternNode *in = (BindingPatternNode*)mLastTreeNode; + in->SetInit(node_init); + return in; + } else if (mLastTreeNode->IsTypeParameter()) { + TypeParameterNode *in = (TypeParameterNode*)mLastTreeNode; + in->SetDefault(node_init); + return in; + } else { + MERROR("The target of AddInit is unsupported."); + } +} + +// It takes (1) two arguments or (2) one argument +TreeNode* ASTBuilder::AddInitTo() { + if (mTrace) + std::cout << "In AddInitTo" << std::endl; + + TreeNode *node_decl = NULL; + TreeNode *node_init = NULL; + + // If there is no init value, return NULL. + if (mParams.size() == 1) { + Param p_init = mParams[0]; + if (p_init.mIsEmpty) + return NULL; + node_init = p_init.mData.mTreeNode; + node_decl = mLastTreeNode; + } else { + Param p_decl = mParams[0]; + Param p_init; + p_init = mParams[1]; + if (p_init.mIsEmpty) + return NULL; + + // Both variable should have been created as tree node. + if (!p_decl.mIsTreeNode || !p_init.mIsTreeNode) + MERROR("The decl or init is not a treenode in AddInitTo()"); + + node_decl = p_decl.mData.mTreeNode; + node_init = p_init.mData.mTreeNode; + } + + if (node_decl->IsIdentifier()) { + IdentifierNode *in = (IdentifierNode*)node_decl; + in->SetInit(node_init); + return in; + } else if (node_decl->IsBindingPattern()) { + BindingPatternNode *in = (BindingPatternNode*)node_decl; + in->SetInit(node_init); + return in; + } else if (node_decl->IsComputedName()) { + ComputedNameNode *in = (ComputedNameNode*)node_decl; + in->SetInit(node_init); + return in; + } else if (node_decl->IsLiteral()) { + LiteralNode *in = (LiteralNode*)node_decl; + in->SetInit(node_init); + return in; + } else { + MERROR("The target of AddInitTo is unsupported."); + } +} + +// This takes just one argument which is the namespace name. +TreeNode* ASTBuilder::BuildNamespace() { + if (mTrace) + std::cout << "In BuildNamespace" << std::endl; + + Param p_name = mParams[0]; + MASSERT(p_name.mIsTreeNode); + TreeNode *node_name = p_name.mData.mTreeNode; + + MASSERT(node_name->IsIdentifier() || node_name->IsField()); - IdentifierNode *in = (IdentifierNode*)node_decl; - in->SetInit(node_init); + NamespaceNode *ns = (NamespaceNode*)gTreePool.NewTreeNode(sizeof(NamespaceNode)); + new (ns) NamespaceNode(); + ns->SetId(node_name); - return in; + mLastTreeNode = ns; + return mLastTreeNode; } +// Takes one parameter which is the tree of namespace body. +TreeNode* ASTBuilder::AddNamespaceBody() { + if (mTrace) + std::cout << "In AddNamespaceBody" << std::endl; + + Param p_body = mParams[0]; + if (!p_body.mIsEmpty) { + if(!p_body.mIsTreeNode) + MERROR("The namespace body is not a tree node."); + TreeNode *tree = p_body.mData.mTreeNode; + + MASSERT(mLastTreeNode->IsNamespace()); + NamespaceNode *ns = (NamespaceNode*)mLastTreeNode; + ns->AddBody(tree); + } + + return mLastTreeNode; +} // This takes just one argument which is the class name. TreeNode* ASTBuilder::BuildClass() { if (mTrace) std::cout << "In BuildClass" << std::endl; - Param p_name = mParams[0]; - - if (!p_name.mIsTreeNode) - MERROR("The class name is not a treenode in BuildClass()"); - TreeNode *node_name = p_name.mData.mTreeNode; + IdentifierNode *in = NULL; - if (!node_name->IsIdentifier()) - MERROR("The class name should be an indentifier node. Not?"); - IdentifierNode *in = (IdentifierNode*)node_name; + Param p_name = mParams[0]; + if (!p_name.mIsEmpty) { + if (!p_name.mIsTreeNode) + MERROR("The class name is not a treenode in BuildClass()"); + TreeNode *node_name = p_name.mData.mTreeNode; + + if (!node_name->IsIdentifier()) + MERROR("The class name should be an indentifier node. Not?"); + in = (IdentifierNode*)node_name; + } - ClassNode *node_class = (ClassNode*)mTreePool->NewTreeNode(sizeof(ClassNode)); + ClassNode *node_class = (ClassNode*)gTreePool.NewTreeNode(sizeof(ClassNode)); new (node_class) ClassNode(); - node_class->SetName(in->GetName()); + if (in) + node_class->SetStrIdx(in->GetStrIdx()); mLastTreeNode = node_class; return mLastTreeNode; @@ -999,7 +2549,7 @@ TreeNode* ASTBuilder::BuildClass() { TreeNode* ASTBuilder::SetClassIsJavaEnum() { ClassNode *klass = (ClassNode*)mLastTreeNode; - klass->SetJavaEnum(); + klass->SetIsJavaEnum(); return mLastTreeNode; } @@ -1008,7 +2558,7 @@ TreeNode* ASTBuilder::BuildBlock() { if (mTrace) std::cout << "In BuildBlock" << std::endl; - BlockNode *block = (BlockNode*)mTreePool->NewTreeNode(sizeof(BlockNode)); + BlockNode *block = (BlockNode*)gTreePool.NewTreeNode(sizeof(BlockNode)); new (block) BlockNode(); Param p_subtree = mParams[0]; @@ -1062,19 +2612,27 @@ TreeNode* ASTBuilder::AddToBlock() { return mLastTreeNode; } -// if tnode is not a BlockNode, wrap it into a BlockNode -TreeNode* ASTBuilder::CvtToBlock(TreeNode *tnode) { +// This takes just two arguments. First is the sync object, second the block +// It returns the block with sync added. +TreeNode* ASTBuilder::AddSyncToBlock() { if (mTrace) - std::cout << "In CvtToBlock" << std::endl; + std::cout << "In AddSyncToBlock" << std::endl; - if (tnode->IsBlock()) { - return tnode; - } + Param p_sync = mParams[0]; + MASSERT(!p_sync.mIsEmpty && p_sync.mIsTreeNode); + TreeNode *sync_tree = p_sync.mData.mTreeNode; - BlockNode *block = (BlockNode*)mTreePool->NewTreeNode(sizeof(BlockNode)); - new (block) BlockNode(); - block->AddChild(tnode); - return block; + Param p_block = mParams[1]; + MASSERT(!p_block.mIsEmpty && p_block.mIsTreeNode); + TreeNode *b = p_block.mData.mTreeNode; + MASSERT(b->IsBlock()); + BlockNode *block = (BlockNode*)b; + + block->SetSync(sync_tree); + + // set last tree node + mLastTreeNode = block; + return mLastTreeNode; } // This takes just one argument which either a block node, or the root of sub tree @@ -1109,14 +2667,41 @@ TreeNode* ASTBuilder::BuildInstInit() { TreeNode* ASTBuilder::AddSuperClass() { if (mTrace) std::cout << "In AddSuperClass" << std::endl; - Param p_attr = mParams[0]; + Param p_super = mParams[0]; + if (p_super.mIsEmpty) + return mLastTreeNode; + + MASSERT(p_super.mIsTreeNode); + TreeNode *t_super = p_super.mData.mTreeNode; + + if (mLastTreeNode->IsClass()) { + ClassNode *sn = (ClassNode*)mLastTreeNode; + sn->AddSuperClass(t_super); + } + return mLastTreeNode; } +// It takes one argument, the super interface. +// Add it to the mLastTreeNode. TreeNode* ASTBuilder::AddSuperInterface() { if (mTrace) std::cout << "In AddSuperInterface" << std::endl; - Param p_attr = mParams[0]; + Param p_super = mParams[0]; + if (p_super.mIsEmpty) + return mLastTreeNode; + + MASSERT(p_super.mIsTreeNode); + TreeNode *t_super = p_super.mData.mTreeNode; + + if (mLastTreeNode->IsStruct()) { + StructNode *sn = (StructNode*)mLastTreeNode; + sn->AddSuper(t_super); + } else if (mLastTreeNode->IsClass()) { + ClassNode *sn = (ClassNode*)mLastTreeNode; + sn->AddSuperInterface(t_super); + } + return mLastTreeNode; } @@ -1126,16 +2711,24 @@ TreeNode* ASTBuilder::AddClassBody() { std::cout << "In AddClassBody" << std::endl; Param p_body = mParams[0]; - if (!p_body.mIsTreeNode) + if (p_body.mIsEmpty) + return mLastTreeNode; + + if (!p_body.mIsTreeNode) MERROR("The class body is not a tree node."); - TreeNode *tree_node = p_body.mData.mTreeNode; - MASSERT(tree_node->IsBlock() && "Class body is not a BlockNode?"); - BlockNode *block = (BlockNode*)tree_node; + + TreeNode *tn = p_body.mData.mTreeNode; + if (!tn->IsBlock()) { + BlockNode *block = (BlockNode*)gTreePool.NewTreeNode(sizeof(BlockNode)); + new (block) BlockNode(); + block->AddChild(tn); + tn = block; + } + BlockNode *block = (BlockNode*)(tn); MASSERT(mLastTreeNode->IsClass() && "Class is not a ClassNode?"); ClassNode *klass = (ClassNode*)mLastTreeNode; - klass->AddBody(block); - klass->Construct(); + klass->Construct(block); return mLastTreeNode; } @@ -1155,7 +2748,7 @@ TreeNode* ASTBuilder::BuildAnnotationType() { MERROR("The annotation type name should be an indentifier node. Not?"); IdentifierNode *in = (IdentifierNode*)node_name; - AnnotationTypeNode *annon_type = (AnnotationTypeNode*)mTreePool->NewTreeNode(sizeof(AnnotationTypeNode)); + AnnotationTypeNode *annon_type = (AnnotationTypeNode*)gTreePool.NewTreeNode(sizeof(AnnotationTypeNode)); new (annon_type) AnnotationTypeNode(); annon_type->SetId(in); @@ -1180,12 +2773,9 @@ TreeNode* ASTBuilder::BuildAnnotation() { MERROR("The annotationtype name is not a treenode in BuildAnnotation()"); TreeNode *iden = p_name.mData.mTreeNode; - if (!iden->IsIdentifier()) - MERROR("The annotation name is NOT an indentifier node."); - - AnnotationNode *annot = (AnnotationNode*)mTreePool->NewTreeNode(sizeof(AnnotationNode)); + AnnotationNode *annot = (AnnotationNode*)gTreePool.NewTreeNode(sizeof(AnnotationNode)); new (annot) AnnotationNode(); - annot->SetId((IdentifierNode*)iden); + annot->SetId(iden); // set last tree node and return it. mLastTreeNode = annot; @@ -1205,9 +2795,9 @@ TreeNode* ASTBuilder::BuildInterface() { MERROR("The name is NOT an indentifier node."); IdentifierNode *in = (IdentifierNode*)node_name; - InterfaceNode *interf = (InterfaceNode*)mTreePool->NewTreeNode(sizeof(InterfaceNode)); + InterfaceNode *interf = (InterfaceNode*)gTreePool.NewTreeNode(sizeof(InterfaceNode)); new (interf) InterfaceNode(); - interf->SetName(in->GetName()); + interf->SetStrIdx(in->GetStrIdx()); // set last tree node and return it. mLastTreeNode = interf; @@ -1238,9 +2828,9 @@ TreeNode* ASTBuilder::BuildDim() { if (mTrace) std::cout << "In BuildDim" << std::endl; - DimensionNode *dim = (DimensionNode*)mTreePool->NewTreeNode(sizeof(DimensionNode)); + DimensionNode *dim = (DimensionNode*)gTreePool.NewTreeNode(sizeof(DimensionNode)); new (dim) DimensionNode(); - dim->AddDim(); + dim->AddDimension(); // set last tree node and return it. mLastTreeNode = dim; @@ -1309,7 +2899,7 @@ TreeNode* ASTBuilder::AddDimsTo() { mLastTreeNode = node_a; } else if (node_a->IsPrimType()) { PrimTypeNode *pt = (PrimTypeNode*)node_a; - PrimArrayTypeNode *pat = (PrimArrayTypeNode*)mTreePool->NewTreeNode(sizeof(PrimArrayTypeNode)); + PrimArrayTypeNode *pat = (PrimArrayTypeNode*)gTreePool.NewTreeNode(sizeof(PrimArrayTypeNode)); new (pat) PrimArrayTypeNode(); pat->SetPrim(pt); pat->SetDims(dim); @@ -1349,77 +2939,121 @@ TreeNode* ASTBuilder::AddDims() { return mLastTreeNode; } -//////////////////////////////////////////////////////////////////////////////// -// New & Delete operation related -//////////////////////////////////////////////////////////////////////////////// - // This is a help function which adds parameters to a function decl. // It's the caller's duty to assure 'func' and 'params' are non null. -void ASTBuilder::AddParams(TreeNode *func, TreeNode *params) { - if (params->IsIdentifier()) { - // one single parameter at call site - IdentifierNode *inode = (IdentifierNode*)params; - if (func->IsFunction()) - ((FunctionNode*)func)->AddParam(inode); - else if (func->IsNew()) - ((NewNode*)func)->AddParam(inode); - else - MERROR("Unsupported yet."); - } else if (params->IsVarList()) { - // a list of decls at function declaration - VarListNode *vl = (VarListNode*)params; - for (unsigned i = 0; i < vl->GetNum(); i++) { - IdentifierNode *inode = vl->VarAtIndex(i); +void ASTBuilder::AddParams(TreeNode *func, TreeNode *decl_params) { + if (decl_params->IsDecl()) { + DeclNode *decl = (DeclNode*)decl_params; + TreeNode *params = decl->GetVar(); + // a param could be a 'this' literal, binding pattern, etc + if (params->IsIdentifier() || params->IsLiteral() || params->IsBindingPattern()) { + // one single parameter at call site if (func->IsFunction()) - ((FunctionNode*)func)->AddParam(inode); - else if (func->IsNew()) - ((NewNode*)func)->AddParam(inode); + ((FunctionNode*)func)->AddParam(params); + else if (func->IsLambda()) + ((LambdaNode*)func)->AddParam(params); else MERROR("Unsupported yet."); + } else if (params->IsVarList()) { + // a list of decls at function declaration + VarListNode *vl = (VarListNode*)params; + for (unsigned i = 0; i < vl->GetVarsNum(); i++) { + IdentifierNode *inode = vl->GetVarAtIndex(i); + if (func->IsFunction()) + ((FunctionNode*)func)->AddParam(inode); + else if (func->IsLambda()) + ((LambdaNode*)func)->AddParam(inode); + else + MERROR("Unsupported yet."); + } + } else { + MERROR("Unsupported yet."); } - } else if (params->IsPass()) { - // a list of identifiers at call site. - PassNode *pass = (PassNode*)params; + } else if (decl_params->IsPass()) { + PassNode *pass = (PassNode*)decl_params; for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { TreeNode *child = pass->GetChild(i); - if (func->IsFunction()) - ((FunctionNode*)func)->AddParam(child); - else if (func->IsNew()) - ((NewNode*)func)->AddParam(child); - else - MERROR("Unsupported yet."); + AddParams(func, child); } + } else if (decl_params->IsIdentifier()) { + // sometimes, the parameter is just an identifier in Javascript. + // Like the SetAccessor + if (func->IsFunction()) + ((FunctionNode*)func)->AddParam(decl_params); + else if (func->IsLambda()) + ((LambdaNode*)func)->AddParam(decl_params); + else + MERROR("Unsupported yet."); + } else if (decl_params->IsStruct()) { + if (func->IsFunction()) + ((FunctionNode*)func)->AddParam(decl_params); + else if (func->IsLambda()) + ((LambdaNode*)func)->AddParam(decl_params); + else + MERROR("Unsupported yet."); + } else { + MERROR("Unsupported yet."); } } +// AddAssert takes one parameter, the asserts expression, and apply it to mLastTreeNode +TreeNode* ASTBuilder::AddAssert() { + if (mTrace) + std::cout << "In AddAssert " << std::endl; + + FunctionNode *f = NULL; + TreeNode *a = NULL; + + Param p_type = mParams[0]; + if(!p_type.mIsEmpty && p_type.mIsTreeNode) { + a = p_type.mData.mTreeNode; + MASSERT(mLastTreeNode->IsFunction()); + f = (FunctionNode*)mLastTreeNode; + } + + if (f && a) + f->SetAssert(a); + + return mLastTreeNode; +} +//////////////////////////////////////////////////////////////////////////////// +// New & Delete operation related +//////////////////////////////////////////////////////////////////////////////// + +// This function takes one, two or three arguments. +// 1. The id of the class/interface/function/..., or a lambda +// 2. The arguments, could be empty +// 3. In some cases there is a third argument, for function body. TreeNode* ASTBuilder::BuildNewOperation() { if (mTrace) std::cout << "In BuildNewOperation " << std::endl; - NewNode *new_node = (NewNode*)mTreePool->NewTreeNode(sizeof(NewNode)); + NewNode *new_node = (NewNode*)gTreePool.NewTreeNode(sizeof(NewNode)); new (new_node) NewNode(); - MASSERT(mParams.size() == 3 && "BuildNewOperation has NO 3 params?"); - Param p_a = mParams[0]; - Param p_b = mParams[1]; - Param p_c = mParams[2]; - // Name could not be empty + Param p_a = mParams[0]; if (p_a.mIsEmpty) MERROR("The name in BuildNewOperation() is empty?"); MASSERT(p_a.mIsTreeNode && "Name of new expression is not a tree?"); TreeNode *name = p_a.mData.mTreeNode; new_node->SetId(name); - - TreeNode *node_b = p_b.mIsEmpty ? NULL : p_b.mData.mTreeNode; - if (node_b) - AddParams(new_node, node_b); - TreeNode *node_c = p_c.mIsEmpty ? NULL : p_c.mData.mTreeNode; - if (node_c) { - MASSERT(node_c->IsBlock() && "ClassBody is not a block?"); - BlockNode *b = (BlockNode*)node_c; - new_node->SetBody(b); + if (mParams.size() > 1) { + Param p_b = mParams[1]; + TreeNode *node_b = p_b.mIsEmpty ? NULL : p_b.mData.mTreeNode; + if (node_b) + AddArguments(new_node, node_b); + } + + if (mParams.size() > 2) { + Param p_c = mParams[2]; + TreeNode *node_c = p_c.mIsEmpty ? NULL : p_c.mData.mTreeNode; + if (node_c) { + MASSERT(node_c->IsBlock() && "ClassBody is not a block?"); + BlockNode *b = (BlockNode*)node_c; + new_node->SetBody(b); + } } mLastTreeNode = new_node; @@ -1427,6 +3061,20 @@ TreeNode* ASTBuilder::BuildNewOperation() { } TreeNode* ASTBuilder::BuildDeleteOperation() { + if (mTrace) + std::cout << "In BuildDelete" << std::endl; + + Param l_param = mParams[0]; + MASSERT(!l_param.mIsEmpty); + MASSERT(l_param.mIsTreeNode); + TreeNode *expr = l_param.mData.mTreeNode; + + DeleteNode *d_node = (DeleteNode*)gTreePool.NewTreeNode(sizeof(DeleteNode)); + new (d_node) DeleteNode(); + d_node->SetExpr(expr); + + mLastTreeNode = d_node; + return mLastTreeNode; } //////////////////////////////////////////////////////////////////////////////// @@ -1439,7 +3087,7 @@ TreeNode* ASTBuilder::BuildAssert() { if (mTrace) std::cout << "In BuildAssert " << std::endl; - AssertNode *assert_node = (AssertNode*)mTreePool->NewTreeNode(sizeof(AssertNode)); + AssertNode *assert_node = (AssertNode*)gTreePool.NewTreeNode(sizeof(AssertNode)); new (assert_node) AssertNode(); MASSERT(mParams.size() >= 1 && "BuildAssert has NO expression?"); @@ -1475,7 +3123,7 @@ TreeNode* ASTBuilder::BuildCall() { if (mTrace) std::cout << "In BuildCall" << std::endl; - CallNode *call = (CallNode*)mTreePool->NewTreeNode(sizeof(CallNode)); + CallNode *call = (CallNode*)gTreePool.NewTreeNode(sizeof(CallNode)); new (call) CallNode(); // The default is having no param. @@ -1484,12 +3132,16 @@ TreeNode* ASTBuilder::BuildCall() { if (!ParamsEmpty()) { Param p_method = mParams[0]; if (!p_method.mIsTreeNode) - MERROR("The function name is not a treenode in BuildFunction()"); + MERROR("The function name is not a treenode in BuildCall()"); method = p_method.mData.mTreeNode; } + // In Typescript, get/set are keywords of attributes. But it also allowed to be + // function name. So we need transfer this AttrNode to IdentifierNode. + if (method && method->IsAttr()) + method = BuildIdentifier(method); + call->SetMethod(method); - call->Init(); mLastTreeNode = call; return mLastTreeNode; @@ -1499,43 +3151,67 @@ TreeNode* ASTBuilder::BuildCall() { // identifier, call, or any valid expression. // // This AddArguments can be used for CallNode, NewNode, etc. -// Right now I just support CallNode. NewNode will be moved from AddParams() -// to here. TreeNode* ASTBuilder::AddArguments() { if (mTrace) std::cout << "In AddArguments" << std::endl; Param p_params = mParams[0]; - TreeNode *params = NULL; + TreeNode *args = NULL; if (!p_params.mIsEmpty) { if (!p_params.mIsTreeNode) MERROR("The parameters is not a treenode in AddArguments()"); - params = p_params.mData.mTreeNode; + args = p_params.mData.mTreeNode; } - if (!params) + if (!args) return mLastTreeNode; - CallNode *call = (CallNode*)mLastTreeNode; + AddArguments(mLastTreeNode, args); - if (params->IsVarList()) { - VarListNode *vl = (VarListNode*)params; - for (unsigned i = 0; i < vl->GetNum(); i++) { - IdentifierNode *inode = vl->VarAtIndex(i); - call->AddArg(inode); + return mLastTreeNode; +} + +// 'call' could be a CallNode or NewNode. +// 'args' could be identifier, literal, expr, etc. +void ASTBuilder::AddArguments(TreeNode *call, TreeNode *args) { + CallNode *callnode = NULL; + NewNode *newnode = NULL; + AnnotationNode *annotation = NULL; + if (call->IsCall()) + callnode = (CallNode*)call; + else if (call->IsNew()) + newnode = (NewNode*)call; + else if (call->IsAnnotation()) + annotation = (AnnotationNode*)call; + else + MERROR("Unsupported call node."); + + if (args->IsVarList()) { + VarListNode *vl = (VarListNode*)args; + for (unsigned i = 0; i < vl->GetVarsNum(); i++) { + IdentifierNode *inode = vl->GetVarAtIndex(i); + if (callnode) + callnode->AddArg(inode); + else if (newnode) + newnode->AddArg(inode); + else if (annotation) + annotation->AddArg(inode); } - } else if (params->IsPass()) { - PassNode *pass = (PassNode*)params; + } else if (args->IsPass()) { + PassNode *pass = (PassNode*)args; for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { TreeNode *child = pass->GetChild(i); - call->AddArg(child); + AddArguments(call, child); } } else { - call->AddArg(params); + if (callnode) + callnode->AddArg(args); + else if (newnode) + newnode->AddArg(args); + else if (annotation) + annotation->AddArg(args); } - - return mLastTreeNode; } // BuildVariableList takes two parameters, var 1 and var 2 @@ -1564,7 +3240,7 @@ TreeNode* ASTBuilder::BuildExprList() { node_ret->Merge(node_a); } else { // both nodes are not ExprListNode - node_ret = (ExprListNode*)mTreePool->NewTreeNode(sizeof(ExprListNode)); + node_ret = (ExprListNode*)gTreePool.NewTreeNode(sizeof(ExprListNode)); new (node_ret) ExprListNode(); if (node_a) node_ret->Merge(node_a); @@ -1582,6 +3258,7 @@ TreeNode* ASTBuilder::BuildExprList() { // FunctionNode related //////////////////////////////////////////////////////////////////////////////// +// Takes only one argument, the params, and add it to mLastTreeNode TreeNode* ASTBuilder::AddParams() { if (mTrace) std::cout << "In AddParams" << std::endl; @@ -1598,25 +3275,41 @@ TreeNode* ASTBuilder::AddParams() { } // This takes just one argument which is the function name. +// The name could empty which is allowed in languages like JS. TreeNode* ASTBuilder::BuildFunction() { if (mTrace) std::cout << "In BuildFunction" << std::endl; - Param p_name = mParams[0]; - - if (!p_name.mIsTreeNode) - MERROR("The function name is not a treenode in BuildFunction()"); - TreeNode *node_name = p_name.mData.mTreeNode; + TreeNode *node_name = NULL; + + if (mParams.size() > 0) { + Param p_name = mParams[0]; + // In JS/TS the name could be empty. + if (!p_name.mIsEmpty) { + if (p_name.mIsTreeNode) { + node_name = p_name.mData.mTreeNode; + if (node_name->IsAttr()) { + node_name = BuildIdentifier(node_name); + } else if (!node_name->IsIdentifier() && + !node_name->IsComputedName() && + !node_name->IsLiteral() && + !node_name->IsField()) + MERROR("The function name should be an indentifier node. Not?"); + } else { + node_name = BuildIdentifier(p_name.mData.mToken); + } + } + } - if (!node_name->IsIdentifier()) - MERROR("The function name should be an indentifier node. Not?"); - IdentifierNode *in = (IdentifierNode*)node_name; + FunctionNode *f = (FunctionNode*)gTreePool.NewTreeNode(sizeof(FunctionNode)); + new (f) FunctionNode(); - FunctionNode *function = (FunctionNode*)mTreePool->NewTreeNode(sizeof(FunctionNode)); - new (function) FunctionNode(); - function->SetName(node_name->GetName()); + if (node_name) { + f->SetFuncName(node_name); + f->SetStrIdx(node_name->GetStrIdx()); + } - mLastTreeNode = function; + mLastTreeNode = f; return mLastTreeNode; } @@ -1640,11 +3333,17 @@ TreeNode* ASTBuilder::AddFunctionBody() { // It's possible that the func body is empty, such as in the // function header declaration. Usually it's just a token ';'. Param p_body = mParams[0]; - if (p_body.mIsTreeNode) { + if (!p_body.mIsEmpty) { + MASSERT(p_body.mIsTreeNode); TreeNode *tree_node = p_body.mData.mTreeNode; MASSERT(tree_node->IsBlock() && "Class body is not a BlockNode?"); BlockNode *block = (BlockNode*)tree_node; - func->AddBody(block); + func->SetBody(block); + } else { + // It is an 'empty' function body. Not a NULL pointer of function body. + BlockNode *block = (BlockNode*)gTreePool.NewTreeNode(sizeof(BlockNode)); + new (block) BlockNode(); + func->SetBody(block); } mLastTreeNode = func; @@ -1668,24 +3367,194 @@ TreeNode* ASTBuilder::AddFunctionBodyTo() { // It's possible that the func body is empty, such as in the // function header declaration. Usually it's just a token ';'. Param p_body = mParams[1]; - if (p_body.mIsTreeNode) { + if (!p_body.mIsEmpty && p_body.mIsTreeNode) { TreeNode *tree_node = p_body.mData.mTreeNode; MASSERT(tree_node->IsBlock() && "Class body is not a BlockNode?"); BlockNode *block = (BlockNode*)tree_node; - func->AddBody(block); + func->SetBody(block); } mLastTreeNode = func; return mLastTreeNode; } +// It take no arugment. It uses mLastTreeNode which is +// a function node. +TreeNode* ASTBuilder::SetIsGenerator() { + MASSERT(mLastTreeNode->IsFunction()); + FunctionNode *node = (FunctionNode*)mLastTreeNode; + node->SetIsGenerator(); + return mLastTreeNode; +} + +// It take no arugment. It uses mLastTreeNode which is +// a function node. +TreeNode* ASTBuilder::SetIsIterator() { + MASSERT(mLastTreeNode->IsFunction()); + FunctionNode *node = (FunctionNode*)mLastTreeNode; + node->SetIsIterator(); + return mLastTreeNode; +} + +// It take no arugment. It uses mLastTreeNode which is +// a yield node. +TreeNode* ASTBuilder::SetIsTransfer() { + MASSERT(mLastTreeNode->IsYield()); + YieldNode *node = (YieldNode*)mLastTreeNode; + node->SetIsTransfer(); + return mLastTreeNode; +} + +// It take no arugment. It uses mLastTreeNode which is +// a function node. +TreeNode* ASTBuilder::SetGetAccessor() { + MASSERT(mLastTreeNode->IsFunction()); + FunctionNode *node = (FunctionNode*)mLastTreeNode; + node->SetIsGetAccessor(); + return mLastTreeNode; +} + +// It take no arugment. It uses mLastTreeNode which is +// a function node. +TreeNode* ASTBuilder::SetSetAccessor() { + MASSERT(mLastTreeNode->IsFunction()); + FunctionNode *node = (FunctionNode*)mLastTreeNode; + node->SetIsSetAccessor(); + return mLastTreeNode; +} + +// It take no arugment. It uses mLastTreeNode which is +// a function node. +TreeNode* ASTBuilder::SetCallSignature() { + MASSERT(mLastTreeNode->IsFunction()); + FunctionNode *node = (FunctionNode*)mLastTreeNode; + node->SetIsCallSignature(); + return mLastTreeNode; +} + +// It take no arugment. It uses mLastTreeNode which is +// a function node. +TreeNode* ASTBuilder::SetConstructSignature() { + MASSERT(mLastTreeNode->IsFunction()); + FunctionNode *node = (FunctionNode*)mLastTreeNode; + node->SetIsConstructSignature(); + return mLastTreeNode; +} + //////////////////////////////////////////////////////////////////////////////// -// Other Functions +// Try, Catch, Throw //////////////////////////////////////////////////////////////////////////////// -// This takes just one argument which is the tree passed from the -// children. It could be single IdentifierNode, or a PassNode with -// more than one tree nodes. +// Takes one argument which is the block. +TreeNode* ASTBuilder::BuildTry() { + if (mTrace) + std::cout << "In BuildTry" << std::endl; + + Param p_block = mParams[0]; + + MASSERT(p_block.mIsTreeNode); + TreeNode *block = p_block.mData.mTreeNode; + + TryNode *try_node = (TryNode*)gTreePool.NewTreeNode(sizeof(TryNode)); + new (try_node) TryNode(); + try_node->SetBlock((BlockNode*)block); + + mLastTreeNode = try_node; + return mLastTreeNode; +} + +// Takes one arguments, the catch clause +// Add to mLastTreeNode which is a TryNode. +TreeNode* ASTBuilder::AddCatch() { + if (mTrace) + std::cout << "In AddCatch " << std::endl; + + Param p_catch = mParams[0]; + MASSERT(p_catch.mIsTreeNode); + TreeNode *catch_node = p_catch.mData.mTreeNode; + + TryNode *try_node = (TryNode*)mLastTreeNode; + try_node->AddCatch(catch_node); + + return mLastTreeNode; +} + +// Takes one arguments, the finally clause +// Add to mLastTreeNode which is a TryNode. +TreeNode* ASTBuilder::AddFinally() { + if (mTrace) + std::cout << "In AddFinally " << std::endl; + + Param p_finally = mParams[0]; + MASSERT(p_finally.mIsTreeNode); + TreeNode *finally_node = p_finally.mData.mTreeNode; + MASSERT(finally_node->IsFinally()); + + TryNode *try_node = (TryNode*)mLastTreeNode; + try_node->SetFinally((FinallyNode*)finally_node); + + return mLastTreeNode; +} + +// Takes one argument which is the block. +TreeNode* ASTBuilder::BuildFinally() { + if (mTrace) + std::cout << "In BuildFinally" << std::endl; + + Param p_block = mParams[0]; + + MASSERT(p_block.mIsTreeNode); + TreeNode *block = p_block.mData.mTreeNode; + + FinallyNode *finally_node = (FinallyNode*)gTreePool.NewTreeNode(sizeof(FinallyNode)); + new (finally_node) FinallyNode(); + finally_node->SetBlock((BlockNode*)block); + + mLastTreeNode = finally_node; + return mLastTreeNode; +} + +// 1. Takes two arguments, the parameters and the block +// 2. Takes one argument, the block +TreeNode* ASTBuilder::BuildCatch() { + if (mTrace) + std::cout << "In BuildCatch" << std::endl; + + TreeNode *params = NULL; + TreeNode *block = NULL; + + if (mParams.size() == 2) { + Param p_params = mParams[0]; + Param p_block = mParams[1]; + + MASSERT(p_params.mIsTreeNode); + params = p_params.mData.mTreeNode; + + MASSERT(p_block.mIsTreeNode); + block = p_block.mData.mTreeNode; + } else { + Param p_block = mParams[0]; + MASSERT(p_block.mIsTreeNode); + block = p_block.mData.mTreeNode; + } + + CatchNode *catch_node = (CatchNode*)gTreePool.NewTreeNode(sizeof(CatchNode)); + new (catch_node) CatchNode(); + + if (params) + catch_node->AddParam(params); + catch_node->SetBlock((BlockNode*)block); + + mLastTreeNode = catch_node; + return mLastTreeNode; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Throw Functions +//////////////////////////////////////////////////////////////////////////////// + +// This takes just one argument which is the exception(s) thrown. TreeNode* ASTBuilder::BuildThrows() { if (mTrace) std::cout << "In BuildThrows" << std::endl; @@ -1694,12 +3563,14 @@ TreeNode* ASTBuilder::BuildThrows() { if (!p_throws.mIsTreeNode) MERROR("The exceptions is not a treenode in BuildThrows()"); - TreeNode *node_throws = p_throws.mData.mTreeNode; + TreeNode *exceptions = p_throws.mData.mTreeNode; + + ThrowNode *throw_node = (ThrowNode*)gTreePool.NewTreeNode(sizeof(ThrowNode)); + new (throw_node) ThrowNode(); - if (!node_throws->IsIdentifier() && !node_throws->IsPass()) - MERROR("The throws should be an indentifier node or pass node. Not?"); + throw_node->AddException(exceptions); - mLastTreeNode = node_throws; + mLastTreeNode = throw_node; return mLastTreeNode; } @@ -1724,7 +3595,7 @@ TreeNode* ASTBuilder::AddThrowsTo() { TreeNode *tree_node = p_body.mData.mTreeNode; if (tree_node->IsIdentifier()) { IdentifierNode *id = (IdentifierNode*)tree_node; - ExceptionNode *exception = (ExceptionNode*)mTreePool->NewTreeNode(sizeof(ExceptionNode)); + ExceptionNode *exception = (ExceptionNode*)gTreePool.NewTreeNode(sizeof(ExceptionNode)); new (exception) ExceptionNode(id); func->AddThrow(exception); } else if (tree_node->IsPass()) { @@ -1733,7 +3604,7 @@ TreeNode* ASTBuilder::AddThrowsTo() { TreeNode *child = pass->GetChild(i); if (child->IsIdentifier()) { IdentifierNode *id = (IdentifierNode*)child; - ExceptionNode *exception = (ExceptionNode*)mTreePool->NewTreeNode(sizeof(ExceptionNode)); + ExceptionNode *exception = (ExceptionNode*)gTreePool.NewTreeNode(sizeof(ExceptionNode)); new (exception) ExceptionNode(id); func->AddThrow(exception); } else { @@ -1747,6 +3618,27 @@ TreeNode* ASTBuilder::AddThrowsTo() { return mLastTreeNode; } +//////////////////////////////////////////////////////////////////////////////// +// Pass a Child +// We only pass tree node. It should not be a token. +//////////////////////////////////////////////////////////////////////////////// + +TreeNode* ASTBuilder::PassChild() { + if (mTrace) + std::cout << "In PassChild" << std::endl; + + TreeNode *node = NULL; + Param p = mParams[0]; + if (!p.mIsEmpty) { + if (!p.mIsTreeNode) + MERROR("The child is not a treenode."); + node = p.mData.mTreeNode; + } + + mLastTreeNode = node; + return mLastTreeNode; +} + //////////////////////////////////////////////////////////////////////////////// // User Type Functions //////////////////////////////////////////////////////////////////////////////// @@ -1758,26 +3650,107 @@ TreeNode* ASTBuilder::BuildUserType() { Param p_id = mParams[0]; if (!p_id.mIsTreeNode) MERROR("The Identifier of user type is not a treenode."); + TreeNode *id = p_id.mData.mTreeNode; - TreeNode *node = p_id.mData.mTreeNode; - if (!node->IsIdentifier()) - MERROR("The Identifier of user type is not an identifier."); - IdentifierNode *id = (IdentifierNode*)node; - - UserTypeNode *user_type = (UserTypeNode*)mTreePool->NewTreeNode(sizeof(UserTypeNode)); + UserTypeNode *user_type = (UserTypeNode*)gTreePool.NewTreeNode(sizeof(UserTypeNode)); new (user_type) UserTypeNode(id); mLastTreeNode = user_type; return mLastTreeNode; } -TreeNode* ASTBuilder::AddTypeArgument() { +TreeNode* ASTBuilder::BuildTypeParameter() { + if (mTrace) + std::cout << "In BuildTypeParameter" << std::endl; + + Param p_id = mParams[0]; + if (!p_id.mIsTreeNode) + MERROR("The Identifier of type parameter is not a treenode."); + TreeNode *id = p_id.mData.mTreeNode; + + TypeParameterNode *tp = (TypeParameterNode*)gTreePool.NewTreeNode(sizeof(TypeParameterNode)); + new (tp) TypeParameterNode(); + tp->SetId(id); + + mLastTreeNode = tp; + return mLastTreeNode; +} + +// It takes one argument, the constraint which could be empty. +TreeNode* ASTBuilder::AddTypeParameterExtends() { if (mTrace) - std::cout << "In AddTypeArgument" << std::endl; + std::cout << "In AddTypeParameterExtends" << std::endl; + + Param p_id = mParams[0]; + if (p_id.mIsEmpty) + return mLastTreeNode; + + MASSERT(p_id.mIsTreeNode); + TreeNode *id = p_id.mData.mTreeNode; + + MASSERT(mLastTreeNode->IsTypeParameter()); + TypeParameterNode *tp = (TypeParameterNode*)mLastTreeNode; + tp->SetExtends(id); + + mLastTreeNode = tp; + return mLastTreeNode; +} + + +// Takes one argument, the as 'type'. +TreeNode* ASTBuilder::BuildAsType() { + if (mTrace) + std::cout << "In BuildAsType" << std::endl; + + Param p_id = mParams[0]; + if (!p_id.mIsTreeNode) + MERROR("The Identifier of type parameter is not a treenode."); + TreeNode *id = p_id.mData.mTreeNode; + + AsTypeNode *tp = (AsTypeNode*)gTreePool.NewTreeNode(sizeof(AsTypeNode)); + new (tp) AsTypeNode(); + tp->SetType(id); + + mLastTreeNode = tp; + return mLastTreeNode; +} + +// Takes four argument, type a, type b, type c , type d. +TreeNode* ASTBuilder::BuildConditionalType() { + if (mTrace) + std::cout << "In BuildConditionalType" << std::endl; + + Param p_a = mParams[0]; + TreeNode *type_a = p_a.mData.mTreeNode; + Param p_b = mParams[1]; + TreeNode *type_b = p_b.mData.mTreeNode; + Param p_c = mParams[2]; + TreeNode *type_c = p_c.mData.mTreeNode; + Param p_d = mParams[3]; + TreeNode *type_d = p_d.mData.mTreeNode; + + ConditionalTypeNode *tp = (ConditionalTypeNode*)gTreePool.NewTreeNode(sizeof(ConditionalTypeNode)); + new (tp) ConditionalTypeNode(); + tp->SetTypeA(type_a); + tp->SetTypeB(type_b); + tp->SetTypeC(type_c); + tp->SetTypeD(type_d); + + mLastTreeNode = tp; + return mLastTreeNode; +} + + +// It takes one argument, the type param or type arg +TreeNode* ASTBuilder::AddTypeGenerics() { + if (mTrace) + std::cout << "In AddTypeGenerics" << std::endl; if (mParams.size() == 0) return mLastTreeNode; Param p_args = mParams[0]; + if (p_args.mIsEmpty) + return mLastTreeNode; // Some language allows special syntax as type arguments, like <> in Java. // It's just a token. @@ -1787,22 +3760,273 @@ TreeNode* ASTBuilder::AddTypeArgument() { TreeNode *args = p_args.mData.mTreeNode; MASSERT(args); - UserTypeNode *type_node = (UserTypeNode*)mLastTreeNode; - type_node->AddTypeArgs(args); + if (mLastTreeNode->IsTypeAlias()) { + TypeAliasNode *type_alias = (TypeAliasNode*)mLastTreeNode; + UserTypeNode *n = type_alias->GetId(); + n->AddTypeGeneric(args); + } else if (mLastTreeNode->IsUserType()) { + UserTypeNode *type_node = (UserTypeNode*)mLastTreeNode; + type_node->AddTypeGeneric(args); + } else if (mLastTreeNode->IsCall()) { + CallNode *call = (CallNode*)mLastTreeNode; + call->AddTypeArgument(args); + } else if (mLastTreeNode->IsFunction()) { + FunctionNode *func = (FunctionNode*)mLastTreeNode; + func->AddTypeParam(args); + } else if (mLastTreeNode->IsClass()) { + ClassNode *c = (ClassNode*)mLastTreeNode; + c->AddTypeParam(args); + } else if (mLastTreeNode->IsStruct()) { + StructNode *c = (StructNode*)mLastTreeNode; + c->AddTypeParam(args); + } else if (mLastTreeNode->IsLambda()) { + LambdaNode *c = (LambdaNode*)mLastTreeNode; + c->AddTypeParam(args); + } else { + MERROR("Unsupported node in AddTypeGenerics()"); + } + + return mLastTreeNode; +} + +// It takes two arguments to build a union type, child-a and child-b +// A child could be a prim type or user type, or even a union user type. +TreeNode* ASTBuilder::BuildUnionUserType() { + if (mTrace) + std::cout << "In BuildUnionUserType" << std::endl; + + UserTypeNode *user_type = NULL; + + Param p_a = mParams[0]; + MASSERT (p_a.mIsTreeNode); + TreeNode *child_a = p_a.mData.mTreeNode; + + Param p_b = mParams[1]; + MASSERT (p_b.mIsTreeNode); + TreeNode *child_b = p_b.mData.mTreeNode; + + if (child_a->IsUserType()) { + UserTypeNode *ut = (UserTypeNode*)child_a; + // for case like : (a | b)[] | c + // We won't merge c into the array type. + if (ut->GetType() == UT_Union && !ut->GetDims()) { + user_type = ut; + user_type->AddUnionInterType(child_b); + } + } + + if (child_b->IsUserType()) { + UserTypeNode *ut = (UserTypeNode*)child_b; + if (ut->GetType() == UT_Union && !ut->GetDims()) { + // assert, both children cannot be UnionUserType at the same time. + MASSERT(!user_type); + user_type = ut; + user_type->AddUnionInterType(child_a, true); + } + } + + if (!user_type) { + user_type = (UserTypeNode*)gTreePool.NewTreeNode(sizeof(UserTypeNode)); + new (user_type) UserTypeNode(); + user_type->SetType(UT_Union); + user_type->AddUnionInterType(child_a); + user_type->AddUnionInterType(child_b); + } + + mLastTreeNode = user_type; + return mLastTreeNode; +} + +// It takes two arguments to build a intersection type, child-a and child-b +// A child could be a prim type or user type. +TreeNode* ASTBuilder::BuildInterUserType() { + if (mTrace) + std::cout << "In BuildInterUserType" << std::endl; + + UserTypeNode *user_type = NULL; + + Param p_a = mParams[0]; + MASSERT (p_a.mIsTreeNode); + TreeNode *child_a = p_a.mData.mTreeNode; + + Param p_b = mParams[1]; + MASSERT (p_b.mIsTreeNode); + TreeNode *child_b = p_b.mData.mTreeNode; + + if (child_a->IsUserType()) { + UserTypeNode *ut = (UserTypeNode*)child_a; + if (ut->GetType() == UT_Inter) { + user_type = ut; + user_type->AddUnionInterType(child_b); + } + } + + if (child_b->IsUserType()) { + UserTypeNode *ut = (UserTypeNode*)child_b; + if (ut->GetType() == UT_Inter) { + // assert, both children cannot be UnionUserType at the same time. + MASSERT(!user_type); + user_type = ut; + user_type->AddUnionInterType(child_a, true); + } + } + + if (!user_type) { + user_type = (UserTypeNode*)gTreePool.NewTreeNode(sizeof(UserTypeNode)); + new (user_type) UserTypeNode(); + user_type->SetType(UT_Inter); + user_type->AddUnionInterType(child_a); + user_type->AddUnionInterType(child_b); + } + + mLastTreeNode = user_type; + return mLastTreeNode; +} + +// It takes two arguments. The alias name, and they orig type. +TreeNode* ASTBuilder::BuildTypeAlias() { + if (mTrace) + std::cout << "In BuildTypeAlias" << std::endl; + + Param p_name = mParams[0]; + MASSERT (p_name.mIsTreeNode); + TreeNode *name = p_name.mData.mTreeNode; + MASSERT(name->IsIdentifier()); + IdentifierNode *id = (IdentifierNode*)name; + + UserTypeNode *user_type = (UserTypeNode*)gTreePool.NewTreeNode(sizeof(UserTypeNode)); + new (user_type) UserTypeNode(); + user_type->SetId(id); + + Param p_orig = mParams[1]; + MASSERT (p_orig.mIsTreeNode); + TreeNode *orig = p_orig.mData.mTreeNode; + + TypeAliasNode *type_alias = (TypeAliasNode*)gTreePool.NewTreeNode(sizeof(TypeAliasNode)); + new (type_alias) TypeAliasNode(); + type_alias->SetId(user_type); + type_alias->SetAlias(orig); + + mLastTreeNode = type_alias; + return mLastTreeNode; +} + +// It takes at least one argument, the basic type. +TreeNode* ASTBuilder::BuildNeverArrayType() { + if (mTrace) + std::cout << "In BuildNeverArrayType" << std::endl; + + PrimTypeNode *prim_type = gPrimTypePool.FindType(TY_Never); + PrimArrayTypeNode *prim_array_type = (PrimArrayTypeNode*)gTreePool.NewTreeNode(sizeof(PrimArrayTypeNode)); + new (prim_array_type) PrimArrayTypeNode(); + prim_array_type->SetPrim(prim_type); + + DimensionNode *dims = (DimensionNode*)gTreePool.NewTreeNode(sizeof(DimensionNode)); + new (dims) DimensionNode(); + dims->AddDimension(0); + + prim_array_type->SetDims(dims); + mLastTreeNode = prim_array_type; + + return mLastTreeNode; +} + +// It takes at least one argument, the basic type. +// The rest argument represent the dimensions. +// +// [NOTE] For each dimension, we are using a trick. If the size of a dimension is unknown, +// we use the same tree node of 'basic type'. + +TreeNode* ASTBuilder::BuildArrayType() { + if (mTrace) + std::cout << "In BuildArrayType" << std::endl; + + Param p_basic = mParams[0]; + MASSERT (p_basic.mIsTreeNode); + TreeNode *basic = p_basic.mData.mTreeNode; + + UserTypeNode *user_type = NULL; // we return either user_type + PrimTypeNode *prim_type = NULL; // + PrimArrayTypeNode *prim_array_type = NULL; // or prim_array_type + + DimensionNode *dims = NULL; + + // This is a weird behavior in Typescript. A type key word can be identifier also. + // I need check here. + if (basic->IsIdentifier()) { + IdentifierNode *id = (IdentifierNode*)basic; + const char *id_name = id->GetName(); + if (id_name) { + PrimTypeNode *pt = gPrimTypePool.FindType(id_name); + if (pt) + basic = pt; + } + } + + if (basic->IsPrimArrayType()) { + prim_array_type = (PrimArrayTypeNode*)basic; + dims = prim_array_type->GetDims(); + } else if (basic->IsUserType()) { + user_type = (UserTypeNode*)basic; + dims = user_type->GetDims(); + } else if (basic->IsPrimType()) { + prim_type = (PrimTypeNode*)basic; + prim_array_type = (PrimArrayTypeNode*)gTreePool.NewTreeNode(sizeof(PrimArrayTypeNode)); + new (prim_array_type) PrimArrayTypeNode(); + prim_array_type->SetPrim(prim_type); + } else { + user_type = (UserTypeNode*)gTreePool.NewTreeNode(sizeof(UserTypeNode)); + new (user_type) UserTypeNode(); + user_type->SetId(basic); + } + + if (!dims) { + dims = (DimensionNode*)gTreePool.NewTreeNode(sizeof(DimensionNode)); + new (dims) DimensionNode(); + } + + for (unsigned i = 1; i < mParams.size(); i++) { + Param p_dim = mParams[i]; + MASSERT (p_dim.mIsTreeNode); + TreeNode *dim = p_dim.mData.mTreeNode; + // Right now we just add all 0 to dim. + if (dim == basic) + dims->AddDimension(0); + else + dims->AddDimension(0); + } + + if (user_type) { + if (!user_type->GetDims()) + user_type->SetDims(dims); + mLastTreeNode = user_type; + } else { + MASSERT(prim_array_type); + if (!prim_array_type->GetDims()) + prim_array_type->SetDims(dims); + mLastTreeNode = prim_array_type; + } return mLastTreeNode; } //////////////////////////////////////////////////////////////////////////////// -// Lambda Expression +// LambdaNode +// As stated in the ast.h, LambdaNode could be different syntax construct in +// different languages. //////////////////////////////////////////////////////////////////////////////// +// It could take +// 1) One parameter, which is the parameter list. +// 2) two parameters, the parameter list and the body TreeNode* ASTBuilder::BuildLambda() { if (mTrace) std::cout << "In BuildLambda" << std::endl; - Param p_params = mParams[0]; TreeNode *params_node = NULL; + TreeNode *body_node = NULL; + + Param p_params = mParams[0]; if (!p_params.mIsEmpty) { if (!p_params.mIsTreeNode) MERROR("Lambda params is not a tree node."); @@ -1810,26 +4034,294 @@ TreeNode* ASTBuilder::BuildLambda() { params_node = p_params.mData.mTreeNode; } - Param p_body = mParams[1]; - TreeNode *body_node = NULL; - if (!p_body.mIsEmpty) { - if (!p_body.mIsTreeNode) - MERROR("Lambda Body is not a tree node."); - else - body_node = CvtToBlock(p_body.mData.mTreeNode); + if (mParams.size() == 2) { + Param p_body = mParams[1]; + if (!p_body.mIsEmpty) { + if (!p_body.mIsTreeNode) + MERROR("Lambda Body is not a tree node."); + else + body_node = p_body.mData.mTreeNode; + } } - LambdaNode *lambda = (LambdaNode*)mTreePool->NewTreeNode(sizeof(LambdaNode)); + LambdaNode *lambda = (LambdaNode*)gTreePool.NewTreeNode(sizeof(LambdaNode)); new (lambda) LambdaNode(); if (params_node) { - if (params_node->IsIdentifier()) + if (params_node->IsIdentifier()) { lambda->AddParam((IdentifierNode*)params_node); + } else { + AddParams(lambda, params_node); + } } - lambda->SetBody(body_node); + if (body_node) + lambda->SetBody(body_node); mLastTreeNode = lambda; return mLastTreeNode; } + +// It take no arugment. It uses mLastTreeNode which is +// a lambda node. +TreeNode* ASTBuilder::SetJavaLambda() { + MASSERT(mLastTreeNode->IsLambda()); + LambdaNode *node = (LambdaNode*)mLastTreeNode; + node->SetProperty(LP_JavaLambda); + return mLastTreeNode; +} + +// It take no arugment. It uses mLastTreeNode which is +// a lambda node. +TreeNode* ASTBuilder::SetArrowFunction() { + MASSERT(mLastTreeNode->IsLambda()); + LambdaNode *node = (LambdaNode*)mLastTreeNode; + node->SetProperty(LP_JSArrowFunction); + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////// +// InstanceOf Expression +//////////////////////////////////////////////////////////////////////////////// + +TreeNode* ASTBuilder::BuildInstanceOf() { + if (mTrace) + std::cout << "In BuildInstanceOf" << std::endl; + + Param l_param = mParams[0]; + MASSERT(!l_param.mIsEmpty); + MASSERT(l_param.mIsTreeNode); + TreeNode *left = l_param.mData.mTreeNode; + + Param r_param = mParams[1]; + MASSERT(!r_param.mIsEmpty); + MASSERT(r_param.mIsTreeNode); + TreeNode *right = r_param.mData.mTreeNode; + + InstanceOfNode *instanceof = (InstanceOfNode*)gTreePool.NewTreeNode(sizeof(InstanceOfNode)); + new (instanceof) InstanceOfNode(); + + instanceof->SetLeft(left); + instanceof->SetRight(right); + + mLastTreeNode = instanceof; + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////// +// In Expression +//////////////////////////////////////////////////////////////////////////////// + +TreeNode* ASTBuilder::BuildIn() { + if (mTrace) + std::cout << "In BuildIn" << std::endl; + + Param l_param = mParams[0]; + MASSERT(!l_param.mIsEmpty); + MASSERT(l_param.mIsTreeNode); + TreeNode *left = l_param.mData.mTreeNode; + + Param r_param = mParams[1]; + MASSERT(!r_param.mIsEmpty); + MASSERT(r_param.mIsTreeNode); + TreeNode *right = r_param.mData.mTreeNode; + + InNode *innode = (InNode*)gTreePool.NewTreeNode(sizeof(InNode)); + new (innode) InNode(); + + innode->SetLeft(left); + innode->SetRight(right); + + mLastTreeNode = innode; + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////// +// ComputedNameNode Expression +//////////////////////////////////////////////////////////////////////////////// + +TreeNode* ASTBuilder::BuildComputedName() { + if (mTrace) + std::cout << "In BuildComputedName" << std::endl; + + Param l_param = mParams[0]; + MASSERT(!l_param.mIsEmpty); + MASSERT(l_param.mIsTreeNode); + TreeNode *in = l_param.mData.mTreeNode; + + ComputedNameNode *innode = (ComputedNameNode*)gTreePool.NewTreeNode(sizeof(ComputedNameNode)); + new (innode) ComputedNameNode(); + innode->SetExpr(in); + + mLastTreeNode = innode; + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////// +// Is Expression +//////////////////////////////////////////////////////////////////////////////// + +TreeNode* ASTBuilder::BuildIs() { + if (mTrace) + std::cout << "In BuildIs" << std::endl; + + Param l_param = mParams[0]; + MASSERT(!l_param.mIsEmpty); + MASSERT(l_param.mIsTreeNode); + TreeNode *left = l_param.mData.mTreeNode; + + Param r_param = mParams[1]; + MASSERT(!r_param.mIsEmpty); + MASSERT(r_param.mIsTreeNode); + TreeNode *right = r_param.mData.mTreeNode; + + IsNode *isnode = (IsNode*)gTreePool.NewTreeNode(sizeof(IsNode)); + new (isnode) IsNode(); + + isnode->SetLeft(left); + isnode->SetRight(right); + + mLastTreeNode = isnode; + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////// +// TypeOf Expression +//////////////////////////////////////////////////////////////////////////////// + +// It takes (1) one argument +// (2) zero argument. Use mLastTreeNode as the argument. +TreeNode* ASTBuilder::BuildTypeOf() { + if (mTrace) + std::cout << "In BuildTypeOf" << std::endl; + + TreeNode *expr = NULL; + + if (mParams.size() == 0) { + expr = mLastTreeNode; + } else { + Param l_param = mParams[0]; + MASSERT(l_param.mIsTreeNode); + expr = l_param.mData.mTreeNode; + } + + TypeOfNode *typeof = (TypeOfNode*)gTreePool.NewTreeNode(sizeof(TypeOfNode)); + new (typeof) TypeOfNode(); + + typeof->SetExpr(expr); + + mLastTreeNode = typeof; + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////// +// KeyOf Expression +//////////////////////////////////////////////////////////////////////////////// + +TreeNode* ASTBuilder::BuildKeyOf() { + if (mTrace) + std::cout << "In BuildKeyOf" << std::endl; + + Param l_param = mParams[0]; + MASSERT(!l_param.mIsEmpty); + MASSERT(l_param.mIsTreeNode); + TreeNode *expr = l_param.mData.mTreeNode; + + KeyOfNode *keyof = (KeyOfNode*)gTreePool.NewTreeNode(sizeof(KeyOfNode)); + new (keyof) KeyOfNode(); + + keyof->SetExpr(expr); + + mLastTreeNode = keyof; + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////// +// Infer Expression +//////////////////////////////////////////////////////////////////////////////// + +TreeNode* ASTBuilder::BuildInfer() { + if (mTrace) + std::cout << "In BuildInfer" << std::endl; + + Param l_param = mParams[0]; + MASSERT(!l_param.mIsEmpty); + MASSERT(l_param.mIsTreeNode); + TreeNode *expr = l_param.mData.mTreeNode; + + InferNode *infer = (InferNode*)gTreePool.NewTreeNode(sizeof(InferNode)); + new (infer) InferNode(); + + infer->SetExpr(expr); + + mLastTreeNode = infer; + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////// +// Triple Slash Directive of TypeScript +//////////////////////////////////////////////////////////////////////////////// + +TreeNode* ASTBuilder::BuildTripleSlash() { + if (mTrace) + std::cout << "In BuildTripleSlash" << std::endl; + + Param l_param = mParams[0]; + MASSERT(!l_param.mIsEmpty); + MASSERT(l_param.mIsTreeNode); + TreeNode *left = l_param.mData.mTreeNode; + + Param r_param = mParams[1]; + MASSERT(!r_param.mIsEmpty); + MASSERT(r_param.mIsTreeNode); + TreeNode *right = r_param.mData.mTreeNode; + + TripleSlashNode *tsnode = (TripleSlashNode*)gTreePool.NewTreeNode(sizeof(TripleSlashNode)); + new (tsnode) TripleSlashNode(); + + TripleSlashProp prop = TSP_NA; + if (left->IsIdentifier()) { + // no-default-lib + if ((strlen(left->GetName()) == 14) && !strncmp(left->GetName(), "no-default-lib", 14)) + prop = TSP_NoDefaultLib; + // lib + if ((strlen(left->GetName()) == 3) && !strncmp(left->GetName(), "lib", 3)) + prop = TSP_Lib; + // types + if ((strlen(left->GetName()) == 5) && !strncmp(left->GetName(), "types", 5)) + prop = TSP_Types; + // path + if ((strlen(left->GetName()) == 4) && !strncmp(left->GetName(), "path", 4)) + prop = TSP_Path; + } + tsnode->SetProp(prop); + + tsnode->SetValue(right); + + mLastTreeNode = tsnode; + return mLastTreeNode; +} + +//////////////////////////////////////////////////////////////////////////////// +// Await +//////////////////////////////////////////////////////////////////////////////// + +// For first parameter has to be an operator. +TreeNode* ASTBuilder::BuildAwait() { + if (mTrace) + std::cout << "In BuildAwait" << std::endl; + + MASSERT(mParams.size() == 1); + Param p_a = mParams[0]; + MASSERT(!p_a.mIsEmpty && p_a.mIsTreeNode); + TreeNode *expr = p_a.mData.mTreeNode; + + AwaitNode *n = (AwaitNode*)gTreePool.NewTreeNode(sizeof(AwaitNode)); + new (n) AwaitNode(); + n->SetExpr(expr); + + mLastTreeNode = n; + return n; +} + } diff --git a/src/MapleFE/shared/src/ast_fixup.cpp b/src/MapleFE/shared/src/ast_fixup.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30e8a26cc7475faacf088f8897946ef85b0e4c1f --- /dev/null +++ b/src/MapleFE/shared/src/ast_fixup.cpp @@ -0,0 +1,169 @@ +/* +* Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include "ast_fixup.h" +#include "stringpool.h" + +namespace maplefe { + +bool FixUpVisitor::FixUp() { + Visit(mASTModule); + return mUpdated; +} + +// Fix up mOprId of a UnaOperatorNode +UnaOperatorNode *FixUpVisitor::VisitUnaOperatorNode(UnaOperatorNode *node) { + switch(node->GetOprId()) { + case OPR_Add: + node->SetOprId(OPR_Plus); + mUpdated = true; + break; + case OPR_Sub: + node->SetOprId(OPR_Minus); + mUpdated = true; + case OPR_Minus: + if (TreeNode *n = node->GetOpnd(); n && n->IsLiteral()) { + LiteralNode *lit = static_cast(n); + LitData data = lit->GetData(); + switch(data.mType) { + case LT_IntegerLiteral: + data.mData.mInt = -data.mData.mInt; + break; + case LT_FPLiteral: + data.mData.mFloat = -data.mData.mFloat; + break; + case LT_DoubleLiteral: + data.mData.mDouble = -data.mData.mDouble; + break; + default: + goto skip; + } + lit->SetData(data); + lit->SetParent(node->GetParent()); + mUpdated = true; + return (UnaOperatorNode *)lit; + } + skip: + break; + case OPR_Inc: + if(!node->IsPost()) { + node->SetOprId(OPR_PreInc); + mUpdated = true; + } + break; + case OPR_Dec: + if(!node->IsPost()) { + node->SetOprId(OPR_PreDec); + mUpdated = true; + } + } + return AstVisitor::VisitUnaOperatorNode(node); +} + +// Fix up the name string of a UserTypeNode +// Fix up literal boolean 'true' or 'false' as a type +UserTypeNode *FixUpVisitor::VisitUserTypeNode(UserTypeNode *node) { + auto id = node->GetId(); + + // Java FE 'java2mpl' needs this + if(id) + if(auto n = id->GetStrIdx()) + if(node->GetStrIdx() != n) { + node->SetStrIdx(n); + mUpdated = true; + } + + if(id && id->IsIdentifier()) { + auto n = id->GetStrIdx(); + auto true_id = gStringPool.GetStrIdx("true"); + if(n == true_id || n == gStringPool.GetStrIdx("false")) { + if(node->GetType() == UT_Regular + && node->GetDims() == nullptr + && node->GetUnionInterTypesNum() == 0 + && node->GetTypeGenericsNum() == 0 + && node->GetAttrsNum() == 0 + && node->GetAsTypesNum() == 0) { + mUpdated = true; + LitData data; + data.mType = LT_BooleanLiteral; + data.mData.mBool = n == true_id; + LiteralNode *lit = new (gTreePool.NewTreeNode(sizeof(LiteralNode))) LiteralNode(data); + return (UserTypeNode*)lit; + } + } + } + return AstVisitor::VisitUserTypeNode(node); +} + +// Fix up literal 'true' or 'false' +IdentifierNode *FixUpVisitor::VisitIdentifierNode(IdentifierNode *node) { + auto p = node->GetParent(); + if(p && node->GetInit() == nullptr && + (p->IsFieldLiteral() || p->IsTerOperator() || p->IsIdentifier() || p->IsBinOperator())) { + if(auto n = node->GetStrIdx()) { + auto true_id = gStringPool.GetStrIdx("true"); + if(n == true_id || n == gStringPool.GetStrIdx("false")) { + mUpdated = true; + LitData data; + data.mType = LT_BooleanLiteral; + data.mData.mBool = n == true_id; + LiteralNode *lit = new (gTreePool.NewTreeNode(sizeof(LiteralNode))) LiteralNode(data); + return (IdentifierNode*)lit; + } + } + } + return AstVisitor::VisitIdentifierNode(node); +} + +// Fix up the filename of a ModuleNode +ModuleNode *FixUpVisitor::VisitModuleNode(ModuleNode *node) { + const char* filename = node->GetFilename(); + std::filesystem::path orig = filename; + std::filesystem::path uniq; + try { + uniq = std::filesystem::canonical(orig); + } + catch(std::filesystem::filesystem_error const& ex) { + // Use orig if std::filesystem::filesystem_error is thrown + uniq = orig; + } + std::string p = uniq.string(); + if(p != filename) { + const char *res = gStringPool.FindString(p.c_str()); + node->SetFilename(res); + mUpdated = true; + } + return AstVisitor::VisitModuleNode(node);; +} + +// Fux up a PassNode for tagged template literal +PassNode *FixUpVisitor::VisitPassNode(PassNode *node) { + AstVisitor::VisitPassNode(node); + unsigned num = node->GetChildrenNum(); + if (num == 2) { + TreeNode *child0 = node->GetChild(0); + TreeNode *child1 = node->GetChild(1); + if (child0 && child1 && child1->IsTemplateLiteral()) { + CallNode *call = new (gTreePool.NewTreeNode(sizeof(CallNode))) CallNode(); + call->SetMethod(child0); + call->SetTaggedTemplate(static_cast(child1)); + return (PassNode*)call; + } + } + return node; +} + +} diff --git a/src/MapleFE/shared/src/ast_mempool.cpp b/src/MapleFE/shared/src/ast_mempool.cpp index 1c9cf527a47f364bdc67cbb5abc5e0ff9ea02c05..6c52307703272dd690bcb109e88c9d62843fea55 100644 --- a/src/MapleFE/shared/src/ast_mempool.cpp +++ b/src/MapleFE/shared/src/ast_mempool.cpp @@ -17,16 +17,21 @@ namespace maplefe { +TreePool gTreePool; + TreePool::~TreePool() { Release(); } char* TreePool::NewTreeNode(unsigned size) { char *addr = mMP.Alloc(size); - mTreeNodes.push_back((TreeNode*)addr); + TreeNode *tree = (TreeNode*)addr; + mTreeNodes.push_back(tree); + unsigned id = mTreeNodes.size(); + tree->SetNodeId(id); return addr; } - + void TreePool::Release() { // step 1. Release the containers in each tree node. std::vector::iterator it = mTreeNodes.begin(); diff --git a/src/MapleFE/shared/src/ast_module.cpp b/src/MapleFE/shared/src/ast_module.cpp index 02e80f41f33b89072c5b716b6007f194af1da0a9..9cab6e95aaf3856b52ef1283fdef66b794d7a798 100644 --- a/src/MapleFE/shared/src/ast_module.cpp +++ b/src/MapleFE/shared/src/ast_module.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -18,45 +18,98 @@ namespace maplefe { -ASTModule gModule; - -ASTModule::ASTModule() { +ModuleNode::ModuleNode() : TreeNode(NK_Module), mPackage(NULL), mSrcLang(SrcLangUnknown), + mIsAmbient(false) { mRootScope = mScopePool.NewScope(NULL); - mPackage = NULL; + mRootScope->SetTree(this); + this->SetScope(mRootScope); } -ASTModule::~ASTModule() { - // free trees - std::vector::iterator it = mTrees.begin(); - for (; it != mTrees.end(); it++) { - ASTTree *tree = *it; - if (tree) - delete tree; - } - mTrees.clear(); - - mImports.Release(); +ModuleNode::~ModuleNode() { + mTrees.Release(); } // AFAIK, all languages allow only one package name if it allows. -void ASTModule::SetPackage(PackageNode *p) { +void ModuleNode::SetPackage(PackageNode *p) { MASSERT(!mPackage); mPackage = p; } +void ModuleNode::SetSrcLang(SrcLang l) { + mSrcLang = l; +} + +SrcLang ModuleNode::GetSrcLang() { + return mSrcLang; +} + +std::string ModuleNode::GetSrcLangString() { + switch (mSrcLang) { + case SrcLangJava: return "Java"; + case SrcLangTypeScript: return "TypeScript"; + case SrcLangJavaScript: return "JavaScript"; + case SrcLangC: return "C"; + default: break; + } + return "Unknown"; +} + +void ModuleNode::AddTreeFront(TreeNode *tree) { + mTrees.PushFront(tree); + tree->SetParent(this); +} + +// The tree could be PassNode +void ModuleNode::AddTree(TreeNode *tree) { + if (tree->IsDecl()) { + DeclNode *decl = (DeclNode*)tree; + TreeNode *var = decl->GetVar(); + if (var && var->IsPass()) { + PassNode *pass = (PassNode*)var; + for (unsigned i = 0; i < pass->GetChildrenNum(); i++) { + DeclNode *n = (DeclNode*)gTreePool.NewTreeNode(sizeof(DeclNode)); + new (n) DeclNode(); + n->SetVar(pass->GetChild(i)); + n->SetProp(decl->GetProp()); + AddTree(n); + } + } else { + mTrees.PushBack(tree); + tree->SetParent(this); + } + } else if (tree->IsPass()) { + PassNode *pass_node = (PassNode*)tree; + for (unsigned i = 0; i < pass_node->GetChildrenNum(); i++) { + TreeNode *child = pass_node->GetChild(i); + AddTree(child); + } + } else { + mTrees.PushBack(tree); + tree->SetParent(this); + } +} + // Return a new scope newly created. // Set the parent<->child relation between it and p. -ASTScope* ASTModule::NewScope(ASTScope *p) { +ASTScope* ModuleNode::NewScope(ASTScope *p) { + ASTScope *newscope = mScopePool.NewScope(p); + return newscope; +} + +ASTScope* ModuleNode::NewScope(ASTScope *p, TreeNode *t) { ASTScope *newscope = mScopePool.NewScope(p); + newscope->SetTree(t); + t->SetScope(newscope); return newscope; } -void ASTModule::Dump() { +void ModuleNode::Dump(unsigned indent) { std::cout << "============= Module ===========" << std::endl; - std::vector::iterator tree_it = mTrees.begin(); - for (; tree_it != mTrees.end(); tree_it++) { - ASTTree *tree = *tree_it; + for (unsigned i = 0; i < mTrees.GetNum(); i++) { + TreeNode *tree = GetTree(i); + DUMP0("== Sub Tree =="); tree->Dump(0); + DUMP_RETURN(); } } } diff --git a/src/MapleFE/shared/src/ast_scope.cpp b/src/MapleFE/shared/src/ast_scope.cpp index 8f416244c0097928eb237ee76796721ccfe288fd..f1e5505be67a6b5e36140edc8200f9c4c4f62fd3 100644 --- a/src/MapleFE/shared/src/ast_scope.cpp +++ b/src/MapleFE/shared/src/ast_scope.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -14,51 +14,69 @@ */ #include "ast_scope.h" +#include "gen_astdump.h" namespace maplefe { -ASTScope::ASTScope(ASTScope *parent) { - mParent = NULL; - mTree = NULL; - if (parent) - SetParent(parent); -} - void ASTScope::AddChild(ASTScope *s) { for (unsigned i = 0; i < mChildren.GetNum(); i++) { - ASTScope *scope = mChildren.ValueAtIndex(i); - if (s == scope) + if (s == GetChild(i)) { return; + } } mChildren.PushBack(s); s->SetParent(this); } -// We are using name address to decide if two names are equal, since we have a -// string pool with any two equal strings will be at the same address. -TreeNode* ASTScope::FindDeclOf(IdentifierNode *inode) { - for (unsigned i = 0; i < GetDeclNum(); i++) { - TreeNode *tree = GetDecl(i); - if (tree->IsIdentifier()) { - IdentifierNode *id = (IdentifierNode*)tree; - MASSERT(id->GetType() && "Identifier has no type?"); +// This is to find the decl having the name as stridx +// starting from local scope +TreeNode* ASTScope::FindDeclOf(unsigned stridx, bool deep) { + ASTScope *scope = this; + while (scope) { + for (unsigned i = 0; i < scope->GetDeclNum(); i++) { + TreeNode *tree = scope->GetDecl(i); + if (tree->GetStrIdx() == stridx) { + return tree; + } } - if (tree->GetName() == inode->GetName()) + for (unsigned i = 0; i < scope->GetImportedDeclNum(); i++) { + TreeNode *tree = scope->GetImportedDecl(i); + if (tree->GetStrIdx() == stridx) { + return tree; + } + } + // search parent scope if deep is set + scope = deep ? scope->mParent : NULL; + } + return NULL; +} + +// This is to find the exported decl having the name as stridx +TreeNode* ASTScope::FindExportedDeclOf(unsigned stridx) { + for (unsigned i = 0; i < GetExportedDeclNum(); i++) { + TreeNode *tree = GetExportedDecl(i); + if (tree->GetStrIdx() == stridx) { return tree; + } } return NULL; } -// This is to find the type having the same name as 'inode'. +// This is to find the type having the name as stridx. // -// We are using name address to decide if two names are equal, since we have a -// string pool with any two equal strings will be at the same address. -TreeNode* ASTScope::FindTypeOf(IdentifierNode *inode) { - for (unsigned i = 0; i < GetTypeNum(); i++) { - TreeNode *tree = GetType(i); - if (tree->GetName() == inode->GetName()) - return tree; +// starting from local scope +TreeNode* ASTScope::FindTypeOf(unsigned stridx) { + ASTScope *scope = this; + while (scope) { + for (unsigned i = 0; i < scope->GetTypeNum(); i++) { + TreeNode *tree = scope->GetType(i); + if (tree->GetStrIdx() == stridx) { + return tree; + } + } + // search parent scope + scope = scope->mParent; } return NULL; } @@ -78,8 +96,8 @@ void ASTScope::TryAddDecl(TreeNode *tree) { mDecls.PushBack(inode); } else if (tree->IsVarList()) { VarListNode *vl = (VarListNode*)tree; - for (unsigned i = 0; i < vl->GetNum(); i++) { - IdentifierNode *inode = vl->VarAtIndex(i); + for (unsigned i = 0; i < vl->GetVarsNum(); i++) { + IdentifierNode *inode = vl->GetVarAtIndex(i); if (inode->GetType()) mDecls.PushBack(inode); } @@ -117,4 +135,86 @@ ASTScope* ASTScopePool::NewScope(ASTScope *parent) { mScopes.push_back(s); return s; } + +bool ASTScope::IsAncestor(ASTScope *ancestor) { + ASTScope *p = this; + while (p) { + if (p == ancestor) { + return true; + } + p = p->GetParent(); + } + return false; +} + +void ASTScope::Dump(unsigned indent) { + mTree->DumpIndentation(indent); + std::cout << "scope: " << AstDump::GetEnumNodeKind(mTree->GetKind()) << " " << mTree->GetName() << " " << mTree->GetNodeId() << std::endl; + for (unsigned i = 0; i < GetDeclNum(); i++) { + TreeNode *node = GetDecl(i); + std::string str = ""; + switch (node->GetKind()) { + case NK_Identifier: str = " var: "; break; + case NK_Decl: str = " decl: "; break; + case NK_Function: str = " func: "; break; + case NK_Struct: str = " struct: "; break; + case NK_Class: str = " class: "; break; + case NK_Namespace: str = " namespace: "; break; + } + if (str.length()) { + node->DumpIndentation(indent); + std::string name = node->GetStrIdx() ? node->GetName() : "-"; + std::cout << str << name << " " << node->GetNodeId() << std::endl; + } + } + + for (unsigned i = 0; i < GetImportedDeclNum(); i++) { + TreeNode *node = GetImportedDecl(i); + std::string str = ""; + switch (node->GetKind()) { + case NK_Identifier: str = " var: - Imported "; break; + case NK_Decl: str = " decl: - Imported "; break; + case NK_Function: str = " func: - Imported "; break; + case NK_Struct: str = " struct: - Imported "; break; + case NK_Class: str = " class: - Imported "; break; + case NK_Namespace: str = " namespace: - Imported "; break; + } + if (str.length()) { + node->DumpIndentation(indent); + std::string name = node->GetStrIdx() ? node->GetName() : "-"; + std::cout << str << name << " " << node->GetNodeId() << std::endl; + } + } + + for (unsigned i = 0; i < GetExportedDeclNum(); i++) { + TreeNode *node = GetExportedDecl(i); + std::string str = ""; + switch (node->GetKind()) { + case NK_Identifier: str = " var: - Exported "; break; + case NK_Decl: str = " decl: - Exported "; break; + case NK_Function: str = " func: - Exported "; break; + case NK_Struct: str = " struct: - Exported "; break; + case NK_Class: str = " class: - Exported "; break; + case NK_Namespace: str = " namespace: - Exported "; break; + } + if (str.length()) { + node->DumpIndentation(indent); + std::string name = node->GetStrIdx() ? node->GetName() : "-"; + std::cout << str << name << " " << node->GetNodeId() << std::endl; + } + } + + for (unsigned i = 0; i < GetTypeNum(); i++) { + TreeNode *node = GetType(i); + node->DumpIndentation(indent); + std::string name = node->GetStrIdx() ? node->GetName() : "-"; + std::cout << " type: " << name << " " << node->GetTypeIdx() << std::endl; + } + + for (unsigned i = 0; i < GetChildrenNum(); i++) { + ASTScope *scope = GetChild(i); + scope->Dump(indent + 2); + } +} + } diff --git a/src/MapleFE/shared/src/ast_type.cpp b/src/MapleFE/shared/src/ast_type.cpp index ac170c9028beaef569783c841bc1a9201326eb05..74ab86984068083463faea968862b181c685d6b0 100644 --- a/src/MapleFE/shared/src/ast_type.cpp +++ b/src/MapleFE/shared/src/ast_type.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -16,8 +16,8 @@ #include #include "ast_type.h" -#include "gen_type.h" // for language specific type keyword #include "ruletable.h" +#include "rule_summary.h" #include "ast.h" #include "massert.h" @@ -27,15 +27,65 @@ namespace maplefe { // UserTypeNode // ////////////////////////////////////////////////////////////////////////// -void UserTypeNode::AddTypeArgs(TreeNode *args) { - if (args->IsIdentifier()) { - IdentifierNode *inode = (IdentifierNode*)args; - AddTypeArg(inode); +void UserTypeNode::AddUnionInterType(TreeNode *args, bool front) { + if (args->IsIdentifier() || + args->IsPrimType() || + args->IsPrimArrayType() || + args->IsUserType() || + args->IsLiteral() || + args->IsLambda() || + args->IsTypeOf() || + args->IsTupleType() || + args->IsArrayElement() || + args->IsConditionalType() || + args->IsNew() || + args->IsKeyOf() || + args->IsImport() || + args->IsField() || + args->IsTemplateLiteral() || + args->IsStruct()) { + mUnionInterTypes.PushBack(args); + if (front) { + for(unsigned i = mUnionInterTypes.GetNum() - 1; i > 0; --i) + mUnionInterTypes.SetElem(i, mUnionInterTypes.ValueAtIndex(i-1)); + mUnionInterTypes.SetElem(0, args); + } + SETPARENT(args); + } else if (args->IsPass()) { + PassNode *p = (PassNode*)args; + for (unsigned i = 0; i < p->GetChildrenNum(); i++) { + TreeNode *a = p->GetChild(i); + AddTypeGeneric(a); + } + } else { + MASSERT(0 && "Unsupported tree node in UserTypeNode::AddUnionInterType()"); + } +} + +void UserTypeNode::AddTypeGeneric(TreeNode *args) { + if (args->IsIdentifier() || + args->IsPrimType() || + args->IsPrimArrayType() || + args->IsUserType() || + args->IsTypeParameter() || + args->IsLiteral() || + args->IsTypeOf() || + args->IsArrayElement() || + args->IsStruct() || + args->IsTupleType() || + args->IsLambda() || + args->IsKeyOf() || + args->IsField() || + args->IsConditionalType() || + args->IsTemplateLiteral() || + args->IsInfer()) { + mTypeGenerics.PushBack(args); + SETPARENT(args); } else if (args->IsPass()) { PassNode *p = (PassNode*)args; for (unsigned i = 0; i < p->GetChildrenNum(); i++) { TreeNode *a = p->GetChild(i); - AddTypeArgs(a); + AddTypeGeneric(a); } } else { MASSERT(0 && "Unsupported tree node in UserTypeNode::AddTypeArgs()"); @@ -46,25 +96,60 @@ void UserTypeNode::AddTypeArgs(TreeNode *args) { bool UserTypeNode::TypeEquivalent(UserTypeNode *type) { // For now, I just check the name. The name is in the global string pool, // so two same names should be in the same address. - if (GetName() == type->GetName()) + if (GetStrIdx() == type->GetStrIdx()) return true; else return false; } void UserTypeNode::Dump(unsigned ind) { - mId->Dump(0); - unsigned size = mTypeArguments.GetNum(); + if (mType == UT_Union) + DUMP0_NORETURN("union "); + else if (mType == UT_Inter) + DUMP0_NORETURN("intersect "); + + if (mId) + mId->Dump(0); + + unsigned size = mTypeGenerics.GetNum(); if (size > 0) { DUMP0_NORETURN('<'); for (unsigned i = 0; i < size; i++) { - IdentifierNode *inode = mTypeArguments.ValueAtIndex(i); + TreeNode *inode = mTypeGenerics.ValueAtIndex(i); inode->Dump(0); if (i < size - 1) DUMP0_NORETURN(','); } DUMP0_NORETURN('>'); } + + size = mUnionInterTypes.GetNum(); + if (size > 0) { + DUMP0_NORETURN(" = "); + for (unsigned i = 0; i < size; i++) { + TreeNode *inode = mUnionInterTypes.ValueAtIndex(i); + inode->Dump(0); + if (i < size - 1) { + if (mType == UT_Union) + DUMP0_NORETURN(" | "); + else if (mType == UT_Inter) + DUMP0_NORETURN(" & "); + } + } + } + + if (mDims) { + for (unsigned i = 0; i < GetDimsNum(); i++) + DUMP0_NORETURN("[]"); + } +} + +////////////////////////////////////////////////////////////////////////// +// ArrayTypeNode // +////////////////////////////////////////////////////////////////////////// + +void ArrayTypeNode::Dump(unsigned ind) { + DUMP0_NORETURN("array-TBD"); } ////////////////////////////////////////////////////////////////////////// @@ -80,7 +165,7 @@ void PrimArrayTypeNode::Dump(unsigned ind) { ////////////////////////////////////////////////////////////////////////// static const char* FindPrimTypeName(TypeId id) { - for (unsigned i = 0; i < TY_NA; i++) { + for (unsigned i = 0; i < TypeKeywordTableSize; i++) { if (TypeKeywordTable[i].mId == id) return TypeKeywordTable[i].mText; } @@ -88,7 +173,7 @@ static const char* FindPrimTypeName(TypeId id) { } static TypeId FindPrimTypeId(const char *keyword) { - for (unsigned i = 0; i < TY_NA; i++) { + for (unsigned i = 0; i < TypeKeywordTableSize; i++) { if (strncmp(TypeKeywordTable[i].mText, keyword, strlen(keyword)) == 0 && strlen(keyword) == strlen(TypeKeywordTable[i].mText)) return TypeKeywordTable[i].mId; @@ -96,42 +181,64 @@ static TypeId FindPrimTypeId(const char *keyword) { return TY_NA; } +////////////////////////////////////////////////////////////////////////// +// FunctionTypeNode // +////////////////////////////////////////////////////////////////////////// + +bool FunctionTypeNode::IsEqual(FunctionTypeNode *node) { + bool result = true; + if (node->GetParamsNum() != GetParamsNum()) { + result = false; + } else { + for (unsigned i = 0; i < GetParamsNum(); i++) { + if (node->GetParam(i) != GetParam(i)) { + result = false; + break; + } + } + } + return result; +} + +void FunctionTypeNode::Dump(unsigned ind) { + DUMP0_NORETURN("functiontype-TBD"); +} + ////////////////////////////////////////////////////////////////////////// // PrimTypeNode // ////////////////////////////////////////////////////////////////////////// -const char* PrimTypeNode::GetName() { +const char* PrimTypeNode::GetTypeName() { const char *name = FindPrimTypeName(GetPrimType()); return name; } void PrimTypeNode::Dump(unsigned indent) { + if (mIsUnique) + DUMP0_NORETURN("unique "); + DumpIndentation(indent); - DUMP0_NORETURN(GetName()); + DUMP0_NORETURN(GetTypeName()); } ////////////////////////////////////////////////////////////////////////// // PrimTypePool // ////////////////////////////////////////////////////////////////////////// -// The global Pool for +// The global Pool for PrimTypePool gPrimTypePool; -PrimTypePool::PrimTypePool() { - // 1024 per block could be better. - mTreePool.SetBlockSize(1024); - Init(); -} +PrimTypePool::PrimTypePool() {} PrimTypePool::~PrimTypePool() { mTypes.Release(); } void PrimTypePool::Init() { - for (unsigned i = 0; i < TY_NA; i++) { - PrimTypeNode *n = (PrimTypeNode*)mTreePool.NewTreeNode(sizeof(PrimTypeNode)); + for (unsigned i = 0; i < TypeKeywordTableSize; i++) { + PrimTypeNode *n = (PrimTypeNode*)gTreePool.NewTreeNode(sizeof(PrimTypeNode)); new (n) PrimTypeNode(); - n->SetPrimType((TypeId)i); + n->SetPrimType((TypeId)TypeKeywordTable[i].mId); mTypes.PushBack(n); } } @@ -145,7 +252,7 @@ PrimTypeNode* PrimTypePool::FindType(const char *keyword) { } PrimTypeNode* PrimTypePool::FindType(TypeId id) { - for (unsigned i = 0; i < TY_NA; i++) { + for (unsigned i = 0; i < TypeKeywordTableSize; i++) { PrimTypeNode *type_float = mTypes.ValueAtIndex(6); PrimTypeNode *type = mTypes.ValueAtIndex(i); if (type->GetPrimType() == id) diff --git a/src/MapleFE/shared/src/container.cpp b/src/MapleFE/shared/src/container.cpp index ac5de846898990cc2d4ba5e58dc6485ef9a7e757..923c67715a734ca319d914a062f616c8abffbea2 100644 --- a/src/MapleFE/shared/src/container.cpp +++ b/src/MapleFE/shared/src/container.cpp @@ -18,6 +18,7 @@ ////////////////////////////////////////////////////////////////////////////// #include +#include #include "container.h" #include "massert.h" @@ -25,9 +26,8 @@ namespace maplefe { char* ContainerMemPool::AddrOfIndex(unsigned index) { - unsigned num_in_blk = mBlockSize / mElemSize; - unsigned blk = index / num_in_blk; - unsigned index_in_blk = index % num_in_blk; + unsigned blk = index / mElemNumPerBlock; + unsigned index_in_blk = index % mElemNumPerBlock; Block *block = mBlocks; for (unsigned i = 0; i < blk; i++) { @@ -37,4 +37,140 @@ char* ContainerMemPool::AddrOfIndex(unsigned index) { char *addr = block->addr + index_in_blk * mElemSize; return addr; } + +//////////////////////////////////////////////////////////////////////////////// +// Bit Vector +//////////////////////////////////////////////////////////////////////////////// + +BitVector::BitVector() : mBVSize(0) { + SetBlockSize(1024); +} + +BitVector::BitVector(unsigned n) : mBVSize(n) { + SetBlockSize(1024); + Alloc(n); +} + +void BitVector::ClearBit(unsigned idx) { + unsigned byte_idx = idx / 8; + unsigned blk_idx = byte_idx / mBlockSize; + Block *block = mBlocks; + for (unsigned i = 0; i < blk_idx; i++) { + block = block->next; + if (!block) + MERROR("ClearBit at unknown location."); + } + + unsigned bit_idx = idx % 8; + char mask = ~(1 << bit_idx); + + char *addr = block->addr + byte_idx % mBlockSize; + *addr = (*addr) & mask; +} + +void BitVector::SetBit(unsigned idx) { + unsigned byte_idx = idx / 8; + unsigned blk_idx = byte_idx / mBlockSize; + Block *block = mBlocks; + unsigned block_num = 0; + for (; block && (block_num < blk_idx); block_num++) { + block = block->next; + } + + // Out of memory. Need to allocate. + // For each block allocated, the random data need be wiped off. + if (!block) { + unsigned blocks_to_alloc = blk_idx + 1 - block_num; + for (unsigned i = 0; i < blocks_to_alloc; i++) { + char *addr = AllocBlock(); + memset((void*)addr, 0, mBlockSize); + } + + // get the block again + block = mBlocks; + for (unsigned i = 0; i < blk_idx; i++) + block = block->next; + } + + unsigned bit_idx = idx % 8; + char *addr = block->addr + byte_idx % mBlockSize; + *addr = (*addr) | (1 << bit_idx); +} + +// return true if the bit is set, or else false. +bool BitVector::GetBit(unsigned idx) { + unsigned byte_idx = idx / 8; + unsigned blk_idx = byte_idx / mBlockSize; + Block *block = mBlocks; + unsigned block_num = 0; + for (; block && (block_num < blk_idx); block_num++) { + block = block->next; + } + + // Out of memory. Need to allocate. + // For each block allocated, the random data need be wiped off. + if (!block) { + unsigned blocks_to_alloc = blk_idx + 1 - block_num; + for (unsigned i = 0; i < blocks_to_alloc; i++) { + char *addr = AllocBlock(); + memset((void*)addr, 0, mBlockSize); + } + + // get the block again + block = mBlocks; + for (unsigned i = 0; i < blk_idx; i++) + block = block->next; + } + + unsigned bit_idx = idx % 8; + char *addr = block->addr + byte_idx % mBlockSize; + unsigned data = (*addr) & (1 << bit_idx); + if (data != 0) + return true; + else + return false; +} + +// bit wise EQUAL +bool BitVector::Equal(BitVector *bv) { + char *addr = mBlocks->addr; + char *bvaddr = bv->mBlocks->addr; + if (mBVSize != bv->mBVSize) { + return false; + } + + MASSERT(mBVSize < 1024 && "NYI: BitVector length > 1024"); + + for (int i = 0; i < (mBVSize + 3)/4; i++) { + if (*(unsigned *)(addr + i*4) != *(unsigned*)(bvaddr + i*4)) { + return false; + } + } + + return true; +} + +// bit wise AND +void BitVector::And(BitVector *bv) { + char *addr = mBlocks->addr; + char *bvaddr = bv->mBlocks->addr; + MASSERT(mBVSize == bv->mBVSize && "BitVector length not equal"); + MASSERT(mBVSize < 1024 && "NYI: BitVector length > 1024"); + + for (int i = 0; i < (mBVSize + 3)/4; i++) { + *(unsigned *)(addr + i*4) &= *(unsigned*)(bvaddr + i*4); + } +} + +// bit wise OR +void BitVector::Or(BitVector *bv) { + char *addr = mBlocks->addr; + char *bvaddr = bv->mBlocks->addr; + MASSERT(mBVSize == bv->mBVSize && "BitVector length not equal"); + MASSERT(mBVSize < 1024 && "NYI: BitVector length > 1024"); + + for (int i = 0; i < (mBVSize + 3)/4; i++) { + *(unsigned *)(addr + i*4) |= *(unsigned*)(bvaddr + i*4); + } +} } diff --git a/src/MapleFE/shared/src/fileread.cpp b/src/MapleFE/shared/src/fileread.cpp index bb038660434317ec91a529b66ed83924dccf15ea..491d6684b7df5a80b029332bf9af64d595659e9b 100644 --- a/src/MapleFE/shared/src/fileread.cpp +++ b/src/MapleFE/shared/src/fileread.cpp @@ -131,7 +131,7 @@ bool FileReader::SkipTRAComment(){ Assert(0, "No ending */ of traditional comment)"); } } - return false; + return false; } // Skip the next separator designated by 'c'. @@ -173,7 +173,7 @@ bool FileReader::ReadLineNonEmpty(){ if (mCurLine.size() > 0) return true; } - return false; + return false; } // Read line from the file, and return the number of read chars. diff --git a/src/MapleFE/shared/src/lexer.cpp b/src/MapleFE/shared/src/lexer.cpp index 87f83e3689d3e39c78954aef24ade144ddad2437..694f86a8edafedea9ff0584a140a9b0e25777951 100644 --- a/src/MapleFE/shared/src/lexer.cpp +++ b/src/MapleFE/shared/src/lexer.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -17,16 +17,12 @@ #include "massert.h" #include "lexer.h" #include "token.h" -#include "common_header_autogen.h" #include "ruletable_util.h" -#include "gen_summary.h" -#include "gen_token.h" +#include "rule_summary.h" #include "massert.h" #include #include -#include "ruletable_util.h" - namespace maplefe { #define MAX_LINE_SIZE 4096 @@ -44,18 +40,38 @@ int Lexer::ReadALine() { } current_line_size = getline(&line, &linebuf_size, srcfile); + _linenum++; + if (current_line_size <= 0) { // EOF fclose(srcfile); line[0] = '\0'; endoffile = true; } else { - if (line[current_line_size - 1] == '\n') { + // There could be \n\r or \r\n + // Handle the last escape + if ((line[current_line_size - 1] == '\n') || + (line[current_line_size - 1] == '\r')) { + line[current_line_size - 1] = '\0'; + current_line_size--; + } + // Handle the second last escape + if ((line[current_line_size - 1] == '\n') || + (line[current_line_size - 1] == '\r')) { line[current_line_size - 1] = '\0'; current_line_size--; } } curidx = 0; + + // There are some special UTF-8 encoding in the beginning of some file format, like BOM + // with \357\273\277. We skip this mark. + if ( *(line+curidx) == -17 && + *(line+curidx+1) == -69 && + *(line+curidx+2) == -65) { + curidx += 3; + } + return current_line_size; } @@ -73,6 +89,8 @@ Lexer::Lexer() endoffile(false), mPredefinedTokenNum(0), mTrace(false), + mLineMode(false), + _total_linenum(0), _linenum(0) { seencomments.clear(); mCheckSeparator = true; @@ -81,12 +99,21 @@ Lexer::Lexer() } void Lexer::PrepareForFile(const std::string filename) { - // open file + // Find the total line number in the file srcfile = fopen(filename.c_str(), "r"); if (!srcfile) { std::cerr << "cannot open file " << filename << std::endl; exit(1); } + while (getline(&line, &linebuf_size, srcfile) > 0) { + _total_linenum++; + } + + fclose(srcfile); + line[0] = '\0'; + + // open file + srcfile = fopen(filename.c_str(), "r"); // allocate line buffer. linebuf_size = (size_t)MAX_LINE_SIZE; @@ -96,114 +123,202 @@ void Lexer::PrepareForFile(const std::string filename) { } // try to read the first line - if (ReadALine() < 0) { - _linenum = 0; - } else { - _linenum = 1; - } + ReadALine(); } -/////////////////////////////////////////////////////////////////////////// -// Utilities for finding system tokens -// Remember the order of tokens are operators, separators, and keywords. -/////////////////////////////////////////////////////////////////////////// +void Lexer::PrepareForString(const char *str) { + current_line_size = strlen(str); + strncpy(line, str, current_line_size); + line[current_line_size] = '\0'; + curidx = 0; + _linenum = 1; + endoffile = false; +} -Token* Lexer::FindOperatorToken(OprId id) { - Token *token = NULL; - bool found = false; - for (unsigned i = 0; i < gOperatorTokensNum; i++) { - token = &gSystemTokens[i]; - MASSERT(token->mTkType == TT_OP); - if (token->GetOprId() == id) { - found = true; - break; +///////////////////////////////////////////////////////////////////////////// +// Both ClearLeadingNewLine() and AddEndingNewLine() will later be implemented +// as language specific, and they will be overriding functions. +///////////////////////////////////////////////////////////////////////////// + +//1. mLexer could cross the line if it's a template literal in Javascript. +//2. During some language lexing, like Typescript template literal, we +// may add \n in a place holder (the line to be lexed). This \n should +// be removed when lexing the expressions in place holder. +void Lexer::ClearLeadingNewLine() { + while (line[curidx] == '\n') { + curidx ++; + if (curidx == current_line_size) { + ReadALine(); + if (EndOfFile()) + return; } } - MASSERT(found && token); - return token; } -Token* Lexer::FindSeparatorToken(SepId id) { - Token *token = NULL; - bool found = false; - for (unsigned i = gOperatorTokensNum; i < gOperatorTokensNum + gSeparatorTokensNum; i++) { - token = &gSystemTokens[i]; - MASSERT(token->mTkType == TT_SP); - if (token->GetSepId() == id) { - found = true; - break; +// We are starting a new token, if current char is ' or ", +// it's the beginning of a string literal. We traverse until the end of the +// current line, if there is no ending ' or ", it means the string goes to next +// line and we add an ending \n, and concatenate the next line. +void Lexer::AddEndingNewLine() { + bool single_quote = false; + bool double_quote = false; + + if (line[curidx] == '\'') + single_quote = true; + if (line[curidx] == '\"') + double_quote = true; + + if (!single_quote && !double_quote) + return; + + unsigned working_idx = curidx + 1; + + // If we are in escape + bool in_escape = false; + + // Reading a raw data, meaning we get the data through getline() directly. + // If we do ReadALine(), it's not a raw data because the ending \n or \r are removed. + bool raw_data = false; + + while(1) { + + // We reach the end of the line, and not done yet. + // So read in a new line and add \n to the end if it's Not raw data. + if (working_idx == current_line_size) { + // Add ending NewLine + if (!raw_data) { + line[working_idx] = '\n'; + current_line_size++; + working_idx++; + } + + // Read new line. + char *new_buf = NULL; + size_t new_buf_size = 0; + ssize_t new_line_size = getline(&new_buf, &new_buf_size, srcfile); + if (new_line_size <= 0) { // EOF + fclose(srcfile); + MERROR("EOF Error reading multi-line string literal."); + } else { + // add new_buf to line + strncpy(line + working_idx, new_buf, new_line_size); + current_line_size += new_line_size; + } + + free(new_buf); + + in_escape = false; + raw_data = true; } - } - MASSERT(found && token); - return token; -} -// The caller of this function makes sure 'key' is already in the -// string pool of Lexer. -Token* Lexer::FindKeywordToken(const char *key) { - Token *token = NULL; - bool found = false; - for (unsigned i = gOperatorTokensNum + gSeparatorTokensNum; - i < gOperatorTokensNum + gSeparatorTokensNum + gKeywordTokensNum; - i++) { - token = &gSystemTokens[i]; - MASSERT(token->mTkType == TT_KW); - if (strlen(key) == strlen(token->GetName()) && - !strncmp(key, token->GetName(), strlen(key))) { - found = true; - break; + // Handle escape + if (line[working_idx] == '\\') { + if (!in_escape) { + in_escape = true; + working_idx++; + continue; + } } - } - MASSERT(found && token); - return token; -} -// CommentToken is the last predefined token -Token* Lexer::FindCommentToken() { - Token *token = &gSystemTokens[gSystemTokensNum - 1]; - MASSERT((token->mTkType == TT_CM) && "Last system token is not a comment token."); - return token; + // return if string literal end. + if (!in_escape && + ( (line[working_idx] == '\'' && single_quote) || + (line[working_idx] == '\"' && double_quote))) { + if (raw_data) { + // Need remove the ending \n or \r for the regular token reading. + if ((line[current_line_size - 1] == '\n') || + (line[current_line_size - 1] == '\r')) { + line[current_line_size - 1] = '\0'; + current_line_size--; + } + // Handle the second last escape + if ((line[current_line_size - 1] == '\n') || + (line[current_line_size - 1] == '\r')) { + line[current_line_size - 1] = '\0'; + current_line_size--; + } + } + + // Finally We are done! + return; + } + + in_escape = false; + working_idx++; + } } ///////////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////////// -// Read a token until end of file. -// If no remaining tokens in current line, we move to the next line. Token* Lexer::LexToken(void) { + ClearLeadingNewLine(); + AddEndingNewLine(); + if (EndOfFile()) + return NULL; + return LexTokenNoNewLine(); } // Read a token until end of line. // Return NULL if no token read. Token* Lexer::LexTokenNoNewLine(void) { + unsigned old_curidx = curidx; bool is_comment = GetComment(); if (is_comment) { - Token *t = FindCommentToken(); + Token *sys_t = FindCommentToken(); + Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + *t = *sys_t; + t->mLineNum = _linenum; + t->mColNum = old_curidx; if (mTrace) t->Dump(); return t; } - // We try to get system tokens in the order of operator, separtor, and keyword - // This is the same as token_gen.cpp in autogen. There is a reason behind this. - // Some languages could have one synatx belonging to both separator and operators. - // eg., ':' in Java 8, it's both a separator colon and operator select. - // So the order here must be consistent with autogen where it decides ':' a colon or - // select in a rule. - OprId opr = GetOperator(); if (opr != OPR_NA) { - Token *t = FindOperatorToken(opr); + Token *sys_t = FindOperatorToken(opr); + Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + *t = *sys_t; + t->mLineNum = _linenum; + t->mColNum = old_curidx; if (mTrace) t->Dump(); return t; } + // There is a corner case: .2 + // The dot is lexed as separator, and 2 is an integer. But actually it's a decimal. SepId sep = GetSeparator(); + unsigned new_curidx = curidx; + if (sep != SEP_NA) { - Token *t = FindSeparatorToken(sep); + if (sep == SEP_Dot) { + // restore curidx + curidx = old_curidx; + // try decimal literal + LitData ld = GetLiteral(); + if (ld.mType != LT_NA) { + MASSERT(ld.mType == LT_FPLiteral || ld.mType == LT_DoubleLiteral); + Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + t->mLineNum = _linenum; + t->mColNum = old_curidx; + t->SetLiteral(ld); + if (mTrace) + t->Dump(); + return t; + } else { + curidx = new_curidx; + } + } + + Token *sys_t = FindSeparatorToken(sep); + Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + *t = *sys_t; + t->mLineNum = _linenum; + t->mColNum = old_curidx; if (mTrace) t->Dump(); return t; @@ -211,7 +326,11 @@ Token* Lexer::LexTokenNoNewLine(void) { const char *keyword = GetKeyword(); if (keyword != NULL) { - Token *t = FindKeywordToken(keyword); + Token *sys_t = FindKeywordToken(keyword); + Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + *t = *sys_t; + t->mLineNum = _linenum; + t->mColNum = old_curidx; if (mTrace) t->Dump(); return t; @@ -219,7 +338,9 @@ Token* Lexer::LexTokenNoNewLine(void) { LitData ld = GetLiteral(); if (ld.mType != LT_NA) { - Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + t->mLineNum = _linenum; + t->mColNum = old_curidx; t->SetLiteral(ld); if (mTrace) t->Dump(); @@ -228,8 +349,21 @@ Token* Lexer::LexTokenNoNewLine(void) { const char *identifier = GetIdentifier(); if (identifier != NULL) { - Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); t->SetIdentifier(identifier); + t->mLineNum = _linenum; + t->mColNum = old_curidx; + if (mTrace) + t->Dump(); + return t; + } + + TempLitData* tldata = GetTempLit(); + if (tldata != NULL) { + Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + t->mLineNum = _linenum; + t->mColNum = old_curidx; + t->SetTempLit(tldata); if (mTrace) t->Dump(); return t; @@ -238,6 +372,98 @@ Token* Lexer::LexTokenNoNewLine(void) { return NULL; } +// We only look for the reg expr ending with / and a few flags like 'g'. +// Flags include: d, g, i, m, s, u, y. +// Anything else finishes the flag. +// +// The content in the reg expr could be any character, we just allow +// all char excluding /. +// +// [NOTE] This function will later be implemented as an overriden function +// of a child class of Lexer. Each lang will have its own +// implementation of this function. +Token* Lexer::FindRegExprToken() { + + // for a regular expr, /a\b/g + // curidx is pointing to 'a' right now. + unsigned old_cur_idx = curidx; + unsigned work_idx = curidx; + unsigned expr_beg_idx = curidx; // the first char of reg expr. + unsigned expr_length = 0; + unsigned flag_beg_idx = 0; // the first char of flags. + unsigned flag_length = 0; // the number of char of flags. + + bool on_flags = false; + + // In Typescript, [ ] includes characters and the escape inside + // is defferent than outside. / is considered non-escape. + bool on_bracket = false; // + + while (work_idx < current_line_size) { + if (line[work_idx] == '[') { + on_bracket = true; + expr_length++; + } else if (on_bracket && line[work_idx] == ']') { + on_bracket = false; + expr_length++; + } else if (line[work_idx] == '/') { + if (on_bracket) { + expr_length++; + } else { + flag_beg_idx = work_idx + 1; + on_flags = true; + } + } else if (line[work_idx] == '\\') { + // An escape. + expr_length += 2; + work_idx += 2; + continue; + } else if (on_flags) { + if (line[work_idx] == 'd' || + line[work_idx] == 'g' || + line[work_idx] == 'i' || + line[work_idx] == 'm' || + line[work_idx] == 's' || + line[work_idx] == 'u' || + line[work_idx] == 'y') + flag_length++; + else + break; + } else { + expr_length++; + } + work_idx++; + } + + if (expr_length > 0) { + // set curidx + curidx = work_idx; + + const char *addr_expr = NULL; + std::string s(line + expr_beg_idx, expr_length); + addr_expr = gStringPool.FindString(s); + + const char *addr_flag = NULL; + if (flag_length > 0) { + std::string sf(line + flag_beg_idx, flag_length); + addr_flag = gStringPool.FindString(sf); + } + + RegExprData reg = {addr_expr, addr_flag}; + + Token *t = (Token*)mTokenPool.NewToken(sizeof(Token)); + t->SetRegExpr(reg); + if (mTrace) { + std::cout << "Find a reg expr: "; + t->Dump(); + } + return t; + + } else { + return NULL; + } +} + // Returen the separator ID, if it's. Or SEP_NA. SepId Lexer::GetSeparator() { return TraverseSepTable(); @@ -310,14 +536,24 @@ LitData Lexer::GetLiteral() { // This is the end of line // (2) /* .. */ // This is the traditional comments +// (3) #! +// This is the common Shebang. We takes it as a comment. // // Return true if a comment is read. The contents are ignore. bool Lexer::GetComment() { + if (FindTripleSlash()) + return false; + if (line[curidx] == '/' && line[curidx+1] == '/') { curidx = current_line_size; return true; } + if (line[curidx] == '#' && line[curidx+1] == '!') { + curidx = current_line_size; + return true; + } + // Handle comments in /* */ // If there is a /* without ending */, the rest of code until the end of the current // source file will be treated as comment. @@ -333,7 +569,6 @@ bool Lexer::GetComment() { len = ReadALine(); if (len < 0) return true; - _linenum++; // a new line read. } if ((line[curidx] == '*' && line[curidx+1] == '/')) { get_ending = true; @@ -414,14 +649,23 @@ bool Lexer::TraverseTableData(TableData *data) { case DT_String: { if( !strncmp(line + curidx, data->mData.mString, strlen(data->mData.mString))) { + bool special_need_check = false; + if (!strncmp(data->mData.mString, "false", 5) && (strlen(data->mData.mString) == 5)) + special_need_check = true; + if (!strncmp(data->mData.mString, "true", 4) && (strlen(data->mData.mString) == 4)) + special_need_check = true; // Need to make sure the following text is a separator curidx += strlen(data->mData.mString); - if (mCheckSeparator && (TraverseSepTable() != SEP_NA) && (TraverseOprTable() != OPR_NA)) { - // TraverseSepTable() moves 'curidx', need restore it - curidx = old_pos + strlen(data->mData.mString); - // Put into gStringPool - gStringPool.FindString(data->mData.mString); - found = true; + if (mCheckSeparator || special_need_check) { + if ((TraverseSepTable() != SEP_NA) || + (TraverseOprTable() != OPR_NA) || + EndOfLine()) { + // TraverseSepTable() moves 'curidx', need restore it + curidx = old_pos + strlen(data->mData.mString); + // Put into gStringPool + gStringPool.FindString(data->mData.mString); + found = true; + } } else { found = true; } @@ -472,7 +716,7 @@ bool Lexer::MatchToken(Token *token) { case TT_OP: { // Pick the longest matching operator. unsigned longest = 0; - for (unsigned i = 0; i < OPR_NA; i++) { + for (unsigned i = 0; i < OprTableSize; i++) { OprTableEntry e = OprTable[i]; if ((e.mId == token->GetOprId()) && !strncmp(line + curidx, e.mText, strlen(e.mText))) { @@ -490,7 +734,7 @@ bool Lexer::MatchToken(Token *token) { case TT_SP: { // Pick the longest matching separator. unsigned longest = 0; - for (unsigned i = 0; i < SEP_NA; i++) { + for (unsigned i = 0; i < SepTableSize; i++) { SepTableEntry e = SepTable[i]; if ((e.mId == token->GetSepId()) && !strncmp(line + curidx, e.mText, strlen(e.mText))) { @@ -656,11 +900,35 @@ bool Lexer::TraverseSecondTry(const RuleTable *rule_table) { bool Lexer::Traverse(const RuleTable *rule_table) { + if (rule_table == &TblUTF8) { + char c = *(line + curidx); + unsigned i = (unsigned)c; + if(i >= 0x80) { + curidx += 1; + return true; + } else { + return false; + } + } + // CHAR, DIGIT are reserved rules. It should NOT be changed. We can // expediate the lexing. if (rule_table == &TblCHAR) { char c = *(line + curidx); - if( (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + curidx += 1; + return true; + } else { + return false; + } + } + + // + // [NOTE] Since there is no way to describe special char in .spec files, we decided + // to handle here. + if (rule_table == &TblIRREGULAR_CHAR) { + char c = *(line + curidx); + if(c == '\n' || c == '\\' || (unsigned)c == 127) { curidx += 1; return true; } else { @@ -721,7 +989,7 @@ bool Lexer::Traverse(const RuleTable *rule_table) { } curidx = new_pos; - matched = found; + matched = found; break; } @@ -822,7 +1090,7 @@ const char* Lexer::TraverseKeywordTable() { if (addr) { unsigned saved_curidx = curidx; - // It's a keyword only if the following is a separator + // It's a keyword if the following is a separator // End of current line is a separator too. curidx += len; if ((current_line_size == curidx) || (TraverseSepTable() != SEP_NA)) { @@ -830,10 +1098,24 @@ const char* Lexer::TraverseKeywordTable() { curidx = saved_curidx + len; addr = gStringPool.FindString(addr); return addr; - } else { - // failed, restore curidx - curidx = saved_curidx; } + + // It's a keyword if the following is a operator + curidx = saved_curidx + len; + if ((TraverseOprTable() != OPR_NA)) { + curidx = saved_curidx + len; + addr = gStringPool.FindString(addr); + return addr; + } + + curidx = saved_curidx + len; + if (CharIsSeparator(line[curidx])) { + addr = gStringPool.FindString(addr); + return addr; + } + + // failed, restore curidx + curidx = saved_curidx; } return NULL; } diff --git a/src/MapleFE/shared/src/mempool.cpp b/src/MapleFE/shared/src/mempool.cpp index 7636364d10a9216ca7c0fe93c821b89fda42b8c7..9de4915a7dbefd2de3ac881863ffec0461021b2d 100644 --- a/src/MapleFE/shared/src/mempool.cpp +++ b/src/MapleFE/shared/src/mempool.cpp @@ -23,7 +23,7 @@ ////////////////////////////////////////////////////////////////////////////// #include - +#include #include "mempool.h" #include "massert.h" @@ -129,8 +129,7 @@ void MemPool::Release(unsigned num) { MERROR("Release of num bytes failed."); } -// Removes all data in the memory pool. Reset everything to the beginning -// of the pool. But we keep the memory. +// free all blocks in the memory pool. But we keep the memory. void MemPool::Clear() { mCurrBlock = mBlocks; Block *temp_block = mCurrBlock; @@ -139,5 +138,15 @@ void MemPool::Clear() { temp_block = temp_block->next; } } + +// Wipe off all data. Keep the blocks. +void MemPool::WipeOff(int c) { + Block *temp_block = mBlocks; + while(temp_block) { + memset((void*)temp_block->addr, c, mBlockSize); + temp_block = temp_block->next; + } +} + } diff --git a/src/MapleFE/shared/src/parser.cpp b/src/MapleFE/shared/src/parser.cpp index 6914855dca076c9bb02dc1c48fffcc9021405fef..a3f8139a95310f5d692004b8e687b0ca5c6bbca6 100644 --- a/src/MapleFE/shared/src/parser.cpp +++ b/src/MapleFE/shared/src/parser.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -21,16 +21,19 @@ #include "parser.h" #include "massert.h" #include "token.h" -#include "common_header_autogen.h" #include "ruletable_util.h" -#include "gen_summary.h" -#include "gen_token.h" +#include "rule_summary.h" #include "ast.h" #include "ast_builder.h" +#include "ast_mempool.h" +#include "ast_type.h" #include "parser_rec.h" +#include "ast_fixup.h" namespace maplefe { +SmallVector gTemplateLiteralNodes; + ////////////////////////////////////////////////////////////////////////////////// // Top Issues in Parsing System // @@ -182,15 +185,44 @@ namespace maplefe { ////////////////////////////////////////////////////////////////////////////////// Parser::Parser(const char *name) : filename(name) { - mLexer = new Lexer(); + mLexer = CreateLexer(); const std::string file(name); - gModule.SetFileName(name); + mASTModule = new (gTreePool.NewTreeNode(sizeof(ModuleNode))) ModuleNode(); + mASTModule->SetFilename(name); + mASTBuilder = new ASTBuilder(mASTModule); + gPrimTypePool.Init(); + + mAppealNodePool.SetBlockSize(16*4096); + + // get source language type + std::string::size_type lastDot = file.find_last_of('.'); + if (lastDot == std::string::npos) { + std::cout << "used improper source file" << std::endl; + return; + } + std::string fileExt = file.substr(lastDot); + if (fileExt.compare(".java") == 0) { + mASTModule->mSrcLang = SrcLangJava; + } else if (fileExt.compare(".js") == 0) { + mASTModule->mSrcLang = SrcLangJavaScript; + } else if (fileExt.compare(".ts") == 0) { + mASTModule->mSrcLang = SrcLangTypeScript; + } else if (fileExt.compare(".c") == 0) { + mASTModule->mSrcLang = SrcLangC; + } else { + mASTModule->mSrcLang = SrcLangUnknown; + } + mLexer->PrepareForFile(file); mCurToken = 0; mPending = 0; mEndOfFile = false; + mNormalModeRoot = NULL; + mLineModeRoot = NULL; + mLineMode = false; + mTraceTable = false; mTraceLeftRec = false; mTraceAppeal = false; @@ -220,33 +252,97 @@ void Parser::Dump() { void Parser::ClearFailed() { for (unsigned i = 0; i < RuleTableNum; i++) - gFailed[i].clear(); + gFailed[i].ClearAll(); } // Add one fail case for the table void Parser::AddFailed(RuleTable *table, unsigned token) { - //std::cout << " push " << mCurToken << " from " << table; - gFailed[table->mIndex].push_back(token); + gFailed[table->mIndex].SetBit(token); } // Remove one fail case for the table void Parser::ResetFailed(RuleTable *table, unsigned token) { - std::vector::iterator it = gFailed[table->mIndex].begin();; - for (; it != gFailed[table->mIndex].end(); it++) { - if (*it == token) - break; - } - - if (it != gFailed[table->mIndex].end()) - gFailed[table->mIndex].erase(it); + gFailed[table->mIndex].ClearBit(token); } bool Parser::WasFailed(RuleTable *table, unsigned token) { - std::vector::iterator it = gFailed[table->mIndex].begin(); - for (; it != gFailed[table->mIndex].end(); it++) { - if (*it == token) - return true; + return gFailed[table->mIndex].GetBit(token); +} + +// return true if t can be merged with previous tokens. +// This happens when "-3" is lexed as operator Sub and literal 3. +// For Lexer' stance, this is the right thing to do. However, we do +// need literal -3. +bool Parser::TokenMerge(Token *t) { + if (!t->IsLiteral()) + return false; + unsigned size = mActiveTokens.GetNum(); + if (size < 2) + return false; + + // We take care of a few scenarios. + // = -1 <-- sep is an assignment operator + // [-1 <-- sep is a separtor + // + // Here is also another ugly case in Typescript. + // keyword -1 + // such as: x extends -1 + // In normal sense, if it's a keyword we can merge tokens. + // However, in TS keyword can also be an identifier which means + // keyword - 1 could be an expression. + // In this case, we further look at one more token ahead, so if it's + // identifier keyword -1 + // then we know keyword is not used an identifier and we can merge tokens. + + Token *sep = mActiveTokens.ValueAtIndex(size - 2); + bool is_sep = false; + if (sep->IsSeparator() && + (sep->GetSepId() != SEP_Rparen) && + (sep->GetSepId() != SEP_Rbrack)) + is_sep = true; + if (sep->IsOperator() && + (sep->GetOprId() == OPR_Assign || + sep->GetOprId() == OPR_Bor)) + is_sep = true; + + if (sep->IsKeyword() && mActiveTokens.GetNum() >= 3) { + Token *idn = mActiveTokens.ValueAtIndex(size - 3); + if (idn->IsIdentifier()) + is_sep = true; + } + + if (!is_sep) + return false; + + Token *opr = mActiveTokens.ValueAtIndex(size - 1); + if (!opr->IsOperator()) + return false; + + if ((opr->GetOprId() != OPR_Sub) && (opr->GetOprId() != OPR_Add)) + return false; + + LitData data = t->GetLitData(); + if ((data.mType != LT_IntegerLiteral) && + (data.mType != LT_FPLiteral) && + (data.mType != LT_DoubleLiteral)) + return false; + + if (opr->GetOprId() == OPR_Sub) { + if ((data.mType == LT_IntegerLiteral)) { + data.mData.mInt = (-1) * data.mData.mInt; + } else if (data.mType == LT_FPLiteral) { + data.mData.mFloat = (-1) * data.mData.mFloat; + } else if (data.mType == LT_DoubleLiteral) { + data.mData.mDouble = (-1) * data.mData.mDouble; + } + t->SetLiteral(data); + mActiveTokens.SetElem(size - 1, t); + return true; + } else if (opr->GetOprId() == OPR_Add) { + mActiveTokens.SetElem(size - 1, t); + return true; } + return false; } @@ -257,12 +353,15 @@ unsigned Parser::LexOneLine() { unsigned token_num = 0; Token *t = NULL; + Token *last_token = NULL; + bool line_begin = true; + // Check if there are already pending tokens. if (mCurToken < mActiveTokens.GetNum()) return mActiveTokens.GetNum() - mCurToken; while (!token_num) { - // read untile end of line + // read until end of line while (!mLexer->EndOfLine() && !mLexer->EndOfFile()) { t = mLexer->LexToken(); if (t) { @@ -271,9 +370,33 @@ unsigned Parser::LexOneLine() { if (t->IsWhiteSpace()) is_whitespace = true; } - // Put into the token storage, as Pending tokens. - if (!is_whitespace && !t->IsComment()) { + bool is_tab = false; + if (t->IsSeparator()) { + if (t->IsTab()) + is_tab = true; + } + // Put into the token storage + if (!is_whitespace && !is_tab && !t->IsComment()) { + // 1. if need to merge + if (TokenMerge(t)) + continue; + + // 2. if need split tokens + if (TokenSplit(t)) + continue; + + // 3. handle regular expression + t = GetRegExpr(t); + + if (line_begin) { + t->mLineBegin = true; + line_begin = false; + if (mLexer->GetTrace()) + DUMP0("Set as Line First."); + } + mActiveTokens.PushBack(t); + last_token = t; token_num++; } } else { @@ -282,7 +405,7 @@ unsigned Parser::LexOneLine() { } } // Read in the next line. - if (!token_num) { + if (!token_num && !mLineMode) { if(!mLexer->EndOfFile()) mLexer->ReadALine(); else @@ -290,6 +413,13 @@ unsigned Parser::LexOneLine() { } } + // We are done with a meaningful line + if (token_num) { + last_token->mLineEnd = true; + if (mLexer->GetTrace()) + DUMP0("Set as Line End."); + } + return token_num; } @@ -299,6 +429,11 @@ unsigned Parser::LexOneLine() { bool Parser::MoveCurToken() { mCurToken++; if (mCurToken == mActiveTokens.GetNum()) { + // In line mode, we won't read new line any more. + if (mLineMode) { + mEndOfFile = true; + return true; + } unsigned num = LexOneLine(); if (!num) { mEndOfFile = true; @@ -314,29 +449,87 @@ Token* Parser::GetActiveToken(unsigned i) { return mActiveTokens.ValueAtIndex(i); } +// insert token at position idx. +void Parser::InsertToken(unsigned idx, Token *token) { + if (idx >= mActiveTokens.GetNum()) + MASSERT(0 && "mActiveTokens OutOfBound"); + // enlarge the size by 1. + mActiveTokens.PushBack(NULL); + // Copy each of them forwards. + unsigned i = mActiveTokens.GetNum() - 2; + for (; i >= idx; i--) { + Token *move_t = mActiveTokens.ValueAtIndex(i); + mActiveTokens.SetElem(i + 1, move_t); + } + mActiveTokens.SetElem(idx, token); +} + bool Parser::Parse() { - gASTBuilder.SetTrace(mTraceAstBuild); - bool succ = false; + gTemplateLiteralNodes.Clear(); + mASTBuilder->SetTrace(mTraceAstBuild); + ParseStatus res; while (1) { - succ = ParseStmt(); - if (!succ) + res = ParseStmt(); + if (res == ParseFail || res == ParseEOF) break; } - gModule.Dump(); + if (gTemplateLiteralNodes.GetNum() > 0) + ParseTemplateLiterals(); - return succ; + FixUpVisitor worker(mASTModule); + worker.FixUp(); + + mASTModule->Dump(0); + return (res==ParseFail)? false: true; +} + +void Parser::ParseTemplateLiterals() { + + mLineMode = true; + mLexer->SetLineMode(); + for (unsigned i = 0; i < gTemplateLiteralNodes.GetNum(); i++) { + TemplateLiteralNode *tl = gTemplateLiteralNodes.ValueAtIndex(i); + for (unsigned j = 1; j < tl->GetStringsNum(); j += 2) { + // Create tree node for format + const char *fmt_str = tl->GetStringAtIndex(j-1); + if (fmt_str) { + //Create a string literal node + LitData litdata; + litdata.mType = LT_StringLiteral; + litdata.mData.mStrIdx = gStringPool.GetStrIdx(fmt_str); + LiteralNode *n = (LiteralNode*)gTreePool.NewTreeNode(sizeof(LiteralNode)); + new (n) LiteralNode(litdata); + tl->AddTree(n); + } else { + tl->AddTree(NULL); + } + + const char *ph_str = tl->GetStringAtIndex(j); + if (ph_str) { + mLexer->PrepareForString(ph_str); + // Clear some status + ParseStatus result = ParseStmt(); + MASSERT(result == ParseSucc); + MASSERT(mLineModeRoot); + tl->AddTree(mLineModeRoot); + } else { + tl->AddTree(NULL); + } + } + } + mLineMode = false; + mLexer->ResetLineMode(); } -// Right now I didn't use mempool yet, will come back. -// [TODO] Using mempool. void Parser::ClearAppealNodes() { for (unsigned i = 0; i < mAppealNodes.size(); i++) { AppealNode *node = mAppealNodes[i]; if (node) - delete node; + node->Release(); } mAppealNodes.clear(); + mAppealNodePool.Clear(); } // This is for the appealing of mistaken Fail cases created during the first instance @@ -349,10 +542,7 @@ void Parser::ClearAppealNodes() { void Parser::Appeal(AppealNode *start, AppealNode *root) { MASSERT((root->IsSucc()) && "root->mResult is not Succ."); - // A recursion group could have >1 lead node. 'start' could be a different leadnode - // than 'root'. - - AppealNode *node = start->GetParent(); + AppealNode *node = start; // It's possible that this sub-tree could be separated. For example, the last // instance of RecursionTraversal, which is a Fake Succ, and is separated @@ -375,7 +565,7 @@ void Parser::Appeal(AppealNode *start, AppealNode *root) { // This is the parsing for highest level language constructs. It could be class // in Java/c++, or a function/statement in c/c++. In another word, it's the top // level constructs in a compilation unit (aka Module). -bool Parser::ParseStmt() { +ParseStatus Parser::ParseStmt() { // clear status ClearFailed(); ClearSucc(); @@ -383,21 +573,13 @@ bool Parser::ParseStmt() { mPending = 0; // set the root appealing node - mRootNode = new AppealNode(); + mRootNode = mAppealNodePool.NewAppealNode(); mAppealNodes.push_back(mRootNode); - // mActiveTokens contain some un-matched tokens from last time of TraverseStmt(), - // because at the end of every TraverseStmt() when it finishes its matching it always - // MoveCurToken() which in turn calls LexOneLine() to read new tokens of a new line. - // - // This means in LexOneLine() we also need check if there are already tokens pending. - // - // [TODO] Later on, we will move thoes pending tokens to a separate data structure. - unsigned token_num = LexOneLine(); // No more token, end of file if (!token_num) - return false; + return ParseEOF; // Match the tokens against the rule tables. // In a rule table there are : (1) separtaor, operator, keyword, are already in token @@ -409,7 +591,12 @@ bool Parser::ParseStmt() { if (mTraceTiming) gettimeofday(&start, NULL); - bool succ = TraverseStmt(); + bool succ = false; + if (mLineMode) + succ = TraverseTempLiteral(); + else + succ = TraverseStmt(); + if (mTraceTiming) { gettimeofday(&stop, NULL); std::cout << "Parse Time: " << (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec; @@ -421,7 +608,7 @@ bool Parser::ParseStmt() { if (mTraceTiming) gettimeofday(&start, NULL); - PatchWasSucc(mRootNode->mSortedChildren[0]); + PatchWasSucc(mRootNode->mSortedChildren.ValueAtIndex(0)); if (mTraceTiming) { gettimeofday(&stop, NULL); std::cout << "PatchWasSucc Time: " << (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec; @@ -439,9 +626,11 @@ bool Parser::ParseStmt() { if (mTraceTiming) gettimeofday(&start, NULL); - ASTTree *tree = BuildAST(); + TreeNode *tree = BuildAST(); if (tree) { - gModule.AddTree(tree); + if (!mLineMode) { + mASTModule->AddTree(tree); + } } if (mTraceTiming) { @@ -450,6 +639,71 @@ bool Parser::ParseStmt() { std::cout << " us" << std::endl; } } + return succ? ParseSucc: ParseFail; +} + +// return true : if all tokens in mActiveTokens are matched. +// false : if faled. +// For the place holders in Typescript Template Literal, there are usually two +// syntax, expression and type. + +bool Parser::TraverseTempLiteral() { + bool succ_expr = false; + bool succ_type = false; + unsigned saved_mCurToken = mCurToken; + unsigned new_mCurToken_expr = 0; + unsigned new_mCurToken_type = 0; + + mRootNode->ClearChildren(); + + RuleTable *t = &TblExpression; + AppealNode *child = NULL; + succ_expr = TraverseRuleTable(t, mRootNode, child); + if (succ_expr) { + MASSERT(child || t->mType == ET_ASI); + if (child) + mRootNode->CopyMatch(child); + // Need adjust the mCurToken. A rule could try multiple possible + // children rules, although there is one and only one valid child + // for a Top table. However, the mCurToken could deviate from + // the valid children and reflect the invalid children. + //MASSERT(mRootNode->mChildren.GetNum() == 1); + //AppealNode *topnode = mRootNode->mChildren.ValueAtIndex(0); + //MASSERT(topnode->IsSucc()); + new_mCurToken_expr = mCurToken; + } + + // Type TblType + mCurToken = saved_mCurToken; + t = &TblType; + child = NULL; + succ_type = TraverseRuleTable(t, mRootNode, child); + if (succ_type) { + MASSERT(child || t->mType == ET_ASI); + if (child) + mRootNode->CopyMatch(child); + // Need adjust the mCurToken. A rule could try multiple possible + // children rules, although there is one and only one valid child + // for a Top table. However, the mCurToken could deviate from + // the valid children and reflect the invalid children. + //MASSERT(mRootNode->mChildren.GetNum() == 1); + //AppealNode *topnode = mRootNode->mChildren.ValueAtIndex(0); + //MASSERT(topnode->IsSucc()); + new_mCurToken_type = mCurToken; + } + + mCurToken = new_mCurToken_expr > new_mCurToken_type ? new_mCurToken_expr : new_mCurToken_type; + + bool succ = succ_expr | succ_type; + if (succ) { + mRootNode->mResult = Succ; + SortOut(); + } + + if (!succ) + std::cout << "Illegal syntax detected!" << std::endl; + else + std::cout << "Matched " << mCurToken << " tokens." << std::endl; return succ; } @@ -467,14 +721,16 @@ bool Parser::TraverseStmt() { mRootNode->ClearChildren(); AppealNode *child = NULL; succ = TraverseRuleTable(t, mRootNode, child); - mRootNode->CopyMatch(child); if (succ) { + MASSERT(child || t->mType == ET_ASI); + if (child) + mRootNode->CopyMatch(child); // Need adjust the mCurToken. A rule could try multiple possible - // children rules, although there is one any only one valid child + // children rules, although there is one and only one valid child // for a Top table. However, the mCurToken could deviate from // the valid children and reflect the invalid children. - MASSERT(mRootNode->mChildren.size() == 1); - AppealNode *topnode = mRootNode->mChildren[0]; + MASSERT(mRootNode->mChildren.GetNum() == 1); + AppealNode *topnode = mRootNode->mChildren.ValueAtIndex(0); MASSERT(topnode->IsSucc()); // Top level table should have only one valid matching. Otherwise, @@ -515,39 +771,51 @@ void Parser::DumpEnterTable(const char *table_name, unsigned indent) { } void Parser::DumpExitTable(const char *table_name, unsigned indent, AppealNode *appeal) { + DumpExitTable(table_name, indent, appeal->mResult, appeal); +} + +void Parser::DumpExitTable(const char *table_name, unsigned indent, + AppealStatus reason, AppealNode *appeal) { for (unsigned i = 0; i < indent; i++) std::cout << " "; std::cout << "Exit " << table_name << "@" << mCurToken; - bool succ = appeal->IsSucc(); - AppealStatus reason = appeal->mResult; - if (succ) { - if (reason == SuccWasSucc) - std::cout << " succ@WasSucc" << "}"; - else if (reason == SuccStillWasSucc) - std::cout << " succ@StillWasSucc" << "}"; - else if (reason == Succ) - std::cout << " succ" << "}"; - + if (reason == SuccWasSucc) { + std::cout << " succ@WasSucc" << "}"; DumpSuccTokens(appeal); std::cout << std::endl; - } else { - if (reason == FailWasFailed) - std::cout << " fail@WasFailed" << "}" << std::endl; - else if (reason == FailNotRightToken) - std::cout << " fail@NotRightToken" << "}" << std::endl; - else if (reason == FailNotIdentifier) - std::cout << " fail@NotIdentifer" << "}" << std::endl; - else if (reason == FailNotLiteral) - std::cout << " fail@NotLiteral" << "}" << std::endl; - else if (reason == FailChildrenFailed) - std::cout << " fail@ChildrenFailed" << "}" << std::endl; - else if (reason == Fail2ndOf1st) - std::cout << " fail@2ndOf1st" << "}" << std::endl; - else if (reason == FailLookAhead) - std::cout << " fail@LookAhead" << "}" << std::endl; - else if (reason == AppealStatus_NA) - std::cout << " fail@NA" << "}" << std::endl; - } + } else if (reason == SuccStillWasSucc) { + std::cout << " succ@StillWasSucc" << "}"; + DumpSuccTokens(appeal); + std::cout << std::endl; + } else if (reason == Succ) { + std::cout << " succ" << "}"; + DumpSuccTokens(appeal); + std::cout << std::endl; + } else if (reason == SuccASI) { + std::cout << " succASI" << "}"; + std::cout << std::endl; + } else if (reason == FailWasFailed) + std::cout << " fail@WasFailed" << "}" << std::endl; + else if (reason == FailNotRightToken) + std::cout << " fail@NotRightToken" << "}" << std::endl; + else if (reason == FailNotRightString) + std::cout << " fail@NotRightString" << "}" << std::endl; + else if (reason == FailNotIdentifier) + std::cout << " fail@NotIdentifer" << "}" << std::endl; + else if (reason == FailNotLiteral) + std::cout << " fail@NotLiteral" << "}" << std::endl; + else if (reason == FailNotRegExpr) + std::cout << " fail@NotRegExpr" << "}" << std::endl; + else if (reason == FailChildrenFailed) + std::cout << " fail@ChildrenFailed" << "}" << std::endl; + else if (reason == Fail2ndOf1st) + std::cout << " fail@2ndOf1st" << "}" << std::endl; + else if (reason == FailLookAhead) + std::cout << " fail@LookAhead" << "}" << std::endl; + else if (reason == FailASI) + std::cout << " fail@ASI" << "}" << std::endl; + else if (reason == AppealStatus_NA) + std::cout << " fail@NA" << "}" << std::endl; } void Parser::DumpSuccTokens(AppealNode *appeal) { @@ -577,67 +845,9 @@ void Parser::RemoveSuccNode(unsigned curr_token, AppealNode *node) { succ_match->RemoveNode(node); } -// The PreProcessing of TraverseRuleTable(). -// Under the Wavefront algorithm of recursion group traversal, things are -// are a little complicated. -// 1. If a rule is failed at some token, it could be succ later. For example, -// the 2nd hit in 1st iteration of a recursion node, is failed@2ndof1st, -// but the rule could be succ match later. -// 2. If a rule is succ at some token, it doesn't mean it's finished, and -// there could be more matchings. -// -// Returns true : if SuccMatch is done. - -bool Parser::TraverseRuleTablePre(AppealNode *appeal) { - unsigned saved_mCurToken = mCurToken; - bool is_done = false; - RuleTable *rule_table = appeal->GetTable(); - const char *name = NULL; - if (mTraceTable) - name = GetRuleTableName(rule_table); - - // Check if it was succ. The longest matching is chosen for the next rule table to match. - SuccMatch *succ = &gSucc[rule_table->mIndex]; - if (succ) { - bool was_succ = succ->GetStartToken(mCurToken); - if (was_succ) { - // Those affected by the 1st appearance of 1st instance which returns false. - // 1stOf1st is not add to WasFail, but those affected will be added to WasFail. - // The affected can be succ later. So there is possibility both succ and fail - // exist at the same time. - // - // I still keep this assertion. We will see. Maybe we'll remove it. - MASSERT(!WasFailed(rule_table, mCurToken)); - - is_done = succ->IsDone(); - - unsigned num = succ->GetMatchNum(); - for (unsigned i = 0; i < num; i++) { - unsigned match = succ->GetOneMatch(i); - // WasSucc nodes need Match info, which will be used later - // in the sort out. - appeal->AddMatch(match); - if (match > mCurToken) - mCurToken = match; - } - appeal->mResult = SuccWasSucc; - - // In ZeroorXXX cases, it was successful and has SuccMatch. However, - // it could be a failure. In this case, we shouldn't move mCurToken. - if (num > 0) - MoveCurToken(); - } - } - - if (WasFailed(rule_table, saved_mCurToken)) { - appeal->mResult = FailWasFailed; - } - - return is_done; -} - bool Parser::LookAheadFail(RuleTable *rule_table, unsigned token) { Token *curr_token = GetActiveToken(token); + LookAheadTable latable = gLookAheadTable[rule_table->mIndex]; bool found = false; @@ -651,8 +861,20 @@ bool Parser::LookAheadFail(RuleTable *rule_table, unsigned token) { // which are not recoganized by lexer. break; case LA_Token: - if (curr_token == &gSystemTokens[la.mData.mTokenId]) + if (curr_token->Equal(&gSystemTokens[la.mData.mTokenId])) found = true; + // TemplateLiteral, Regular Expression is treated as a special keyword. + { + Token *t = &gSystemTokens[la.mData.mTokenId]; + if (t->IsKeyword() && !strncmp(t->GetName(), "this_is_for_fake_rule", 21)) { + if (curr_token->IsTempLit() || curr_token->IsRegExpr()) + found = true; + } + if (rule_table == &TblNoLineTerminator) { + if (!curr_token->mLineBegin) + found = true; + } + } break; case LA_Identifier: if (curr_token->IsIdentifier()) @@ -686,16 +908,13 @@ bool Parser::LookAheadFail(RuleTable *rule_table, unsigned token) { // 2. TraverseRuleTable will let the children's traverse to move mCurToken // if they succeeded. // 3. TraverseOneof, TraverseZeroxxxx, TraverseConcatenate follow rule 1&2. -// 4. TraverseRuleTablePre and TraverseLeadNode both exit early, so they -// need follow the rule 1&2. -// 3. TraverseRuleTablePre move mCurToken is succ, and actually it doesn't -// touch mCurToken when fail. +// 3. TraverseLeadNode exit early, so need follow the rule 1&2. // 4. TraverseLeadNode() also follows the rule 1&2. It moves mCurToken // when succ and restore it when fail. // // 'child' is the AppealNode of 'rule_table'. bool Parser::TraverseRuleTable(RuleTable *rule_table, AppealNode *parent, AppealNode *&child) { - if (mEndOfFile) + if (mEndOfFile && mCurToken >= mActiveTokens.GetNum()) return false; mIndentation += 2; @@ -705,45 +924,104 @@ bool Parser::TraverseRuleTable(RuleTable *rule_table, AppealNode *parent, Appeal DumpEnterTable(name, mIndentation); } - // set the apppeal node - AppealNode *appeal = new AppealNode(); - mAppealNodes.push_back(appeal); - appeal->SetTable(rule_table); - appeal->SetStartIndex(mCurToken); - appeal->SetParent(parent); - parent->AddChild(appeal); - child = appeal; + if (rule_table->mType == ET_ASI) { + bool found = TraverseASI(rule_table, parent, child); + if (mTraceTable) { + if (found) + DumpExitTable(name, mIndentation, SuccASI); + else + DumpExitTable(name, mIndentation, FailASI); + } + mIndentation -= 2; + return found; + } + // Lookahead fail is fast to check, even faster than check WasFailed. + if (LookAheadFail(rule_table, mCurToken) && + (rule_table->mType != ET_Zeroormore) && + (rule_table->mType != ET_Zeroorone)) { + if (mTraceTable) + DumpExitTable(name, mIndentation, FailLookAhead); + mIndentation -= 2; + return false; + } + + AppealNode *appeal = NULL; unsigned saved_mCurToken = mCurToken; - bool is_done = TraverseRuleTablePre(appeal); + bool is_done = false; + + // Check if it was succ. The longest matching is chosen for the next rule table to match. + SuccMatch *succ = &gSucc[rule_table->mIndex]; + if (succ) { + bool was_succ = succ->GetStartToken(mCurToken); + if (was_succ) { + // Those affected by the 1st appearance of 1st instance which returns false. + // 1stOf1st is not add to WasFail, but those affected will be added to WasFail. + // The affected can be succ later. So there is possibility both succ and fail + // exist at the same time. + // + // I still keep this assertion. We will see. Maybe we'll remove it. + MASSERT(!WasFailed(rule_table, mCurToken)); + + // set the apppeal node + appeal = mAppealNodePool.NewAppealNode(); + mAppealNodes.push_back(appeal); + appeal->SetTable(rule_table); + appeal->SetStartIndex(mCurToken); + appeal->SetParent(parent); + parent->AddChild(appeal); + child = appeal; + + is_done = succ->IsDone(); + + unsigned num = succ->GetMatchNum(); + for (unsigned i = 0; i < num; i++) { + unsigned match = succ->GetOneMatch(i); + // WasSucc nodes need Match info, which will be used later + // in the sort out. + appeal->AddMatch(match); + if (match > mCurToken) + mCurToken = match; + } + appeal->mResult = SuccWasSucc; + + // In ZeroorXXX cases, it was successful and has SuccMatch. However, + // it could be a failure. In this case, we shouldn't move mCurToken. + if (num > 0) + MoveCurToken(); + } + } unsigned group_id; bool in_group = FindRecursionGroup(rule_table, group_id); // 1. In a recursion, a rule could fail in the first a few instances, // but could match in a later instance. So I need check is_done. + // Here is an example. Node A is one of the circle node. + // (a) In the first recursion instance, A is failed, but luckly it + // gets appealed due to lead node is 2ndOf1st. + // (b) In the second instance, it still fail because its children + // failed. But the whole recursion actually matches tokens, and + // those matching rule tables are not related to A. + // (c) Finally, A matches because leading node goes forward and gives + // A new opportunity. // 2. For A not-in-group rule, a WasFailed is a real fail. - if (appeal->IsFail() && (!in_group || is_done)) { - if (mTraceTable) - DumpExitTable(name, mIndentation, appeal); - mIndentation -= 2; - return false; - } - if (LookAheadFail(rule_table, saved_mCurToken) && - (rule_table->mType != ET_Zeroormore) && - (rule_table->mType != ET_Zeroorone)) { - appeal->mResult = FailLookAhead; - AddFailed(rule_table, saved_mCurToken); + bool was_failed = WasFailed(rule_table, saved_mCurToken); + if (was_failed && (!in_group || is_done)) { if (mTraceTable) - DumpExitTable(name, mIndentation, appeal); + DumpExitTable(name, mIndentation, FailWasFailed); mIndentation -= 2; return false; } // If the rule is NOT in any recursion group, we simply return the result. // If the rule is done, we also simply return the result. - if (appeal->IsSucc()) { + + // If a rule is succ at some token, it doesn't mean it's finished, and + // there could be more matchings. + + if (appeal && appeal->IsSucc()) { if (!in_group || is_done) { if (mTraceTable) DumpExitTable(name, mIndentation, appeal); @@ -752,19 +1030,47 @@ bool Parser::TraverseRuleTable(RuleTable *rule_table, AppealNode *parent, Appeal } else { if (mTraceTable) { DumpIndentation(); - std::cout << "Traverse-Pre WasSucc, mCurToken:" << mCurToken; + std::cout << "Traverse-Pre WasSucc, mCurToken:" << saved_mCurToken; std::cout << std::endl; } } } - RecursionTraversal *rec_tra = FindRecStack(group_id, appeal->GetStartIndex()); + RecursionTraversal *rec_tra = FindRecStack(group_id, saved_mCurToken); // group_id is 0 which is the default value if rule_table is not in a group // Need to reset rec_tra; if (!in_group) rec_tra = NULL; + // This part is to handle a special case: The second appearance in the first instance + // (wave) in the Wavefront algorithm. At this moment, the first appearance in this + // instance hasn't finished its traversal, so there is no previous succ or fail case. + // + // We need to simply return false, but we cannot add them to the Fail mapping. + // A rule is AddFailed() in TraverseRuleTableRegular() which is in the end of this function. + + if (rec_tra && + rec_tra->GetInstance() == InstanceFirst && + rec_tra->LeadNodeVisited(rule_table)) { + rec_tra->AddAppealPoint(parent); + if (mTraceTable) + DumpExitTable(name, mIndentation, Fail2ndOf1st); + mIndentation -= 2; + return false; + } + + // We delay creation of AppealNode as much as possible. + if (!appeal) { + appeal = mAppealNodePool.NewAppealNode(); + mAppealNodes.push_back(appeal); + appeal->SetTable(rule_table); + appeal->SetStartIndex(saved_mCurToken); + appeal->SetParent(parent); + parent->AddChild(appeal); + child = appeal; + } + // If the rule is already traversed in this iteration(instance), we return the result. if (rec_tra && rec_tra->RecursionNodeVisited(rule_table)) { if (mTraceTable) @@ -788,7 +1094,7 @@ bool Parser::TraverseRuleTable(RuleTable *rule_table, AppealNode *parent, Appeal // wave (instance) of the Wavefront traversal, the 1st is not visited, the // 2nd is visited. - if (rec_tra->LeadNodeVisited(rule_table)) { + if (rec_tra->LeadNodeVisited(rule_table)) { if (mTraceLeftRec) { DumpIndentation(); std::cout << ": ConnectPrevious " << GetRuleTableName(rule_table) @@ -807,22 +1113,6 @@ bool Parser::TraverseRuleTable(RuleTable *rule_table, AppealNode *parent, Appeal } } - // This part is to handle a special case: The second appearance in the first instance - // (wave) in the Wavefront algorithm. At this moment, the first appearance in this - // instance hasn't finished its traversal, so there is no previous succ or fail case. - // - // We need to simply return false, but we cannot add them to the Fail mapping. - if (rec_tra && - rec_tra->GetInstance() == InstanceFirst && - rec_tra->LeadNodeVisited(rule_table)) { - rec_tra->AddAppealPoint(appeal); - appeal->mResult = Fail2ndOf1st; - if (mTraceTable) - DumpExitTable(name, mIndentation, appeal); - mIndentation -= 2; - return false; - } - // Restore the mCurToken since TraverseRuleTablePre() update the mCurToken // if succ. And we need use the old mCurToken. mCurToken = saved_mCurToken; @@ -874,12 +1164,24 @@ bool Parser::TraverseRuleTable(RuleTable *rule_table, AppealNode *parent, Appeal // 1. TraverseIdentifier, TraverseLiteral, TraverseOneof, TraverseZeroorXXx, etc // since we konw the relation between parent and children // 2. Or TraverseTableData in this function, because we know the relation. -// 3. Or when TraverseRuleTablePre is succ, also because we know the relation. We -// do it inside TraverseRuleTablePre. +// 3. When TraverseRuleTable pre-check was succ. Because we know the relation. // These are the only places of colleting succ match for a parent node. // bool Parser::TraverseRuleTableRegular(RuleTable *rule_table, AppealNode *appeal) { + // In TraverseToken(), alt tokens are traversed. The intermediate status of matching + // are needed. However, if a matching failed in the middle of alt token serial, the + // status is not cleared in TraverseToken(). It's hard to clear in TraverseToken() + // as it doesn't know the context of traversal. + // + // A better solution is to clear each time entering a top rule table. + if (rule_table->mProperties & RP_Top) { + mInAltTokensMatching = false; + mNextAltTokenIndex = 0; + if (mTraceTable) + std::cout << "Clear alt token status." << std::endl; + } + bool matched = false; unsigned saved_mCurToken = mCurToken; @@ -900,6 +1202,20 @@ bool Parser::TraverseRuleTableRegular(RuleTable *rule_table, AppealNode *appeal) if ((rule_table == &TblLiteral)) return TraverseLiteral(rule_table, appeal); + if ((rule_table == &TblTemplateLiteral)) + return TraverseTemplateLiteral(rule_table, appeal); + + if ((rule_table == &TblRegularExpression)) + return TraverseRegularExpression(rule_table, appeal); + + if (rule_table == &TblNoLineTerminator) { + Token *token = mActiveTokens.ValueAtIndex(mCurToken); + if (token->mLineBegin) + return false; + else + return true; + } + EntryType type = rule_table->mType; switch(type) { case ET_Oneof: @@ -914,14 +1230,22 @@ bool Parser::TraverseRuleTableRegular(RuleTable *rule_table, AppealNode *appeal) case ET_Concatenate: matched = TraverseConcatenate(rule_table, appeal); break; + case ET_ASI: { + AppealNode *child = NULL; + matched = TraverseASI(rule_table, appeal, child); + break; + } case ET_Data: { // This is a rare case where a rule table contains only table, either a token // or a single child rule. In this case, we need merge the child's match into // parent. However, we cannot do the merge in TraverseTableData() since this // function will be used in multiple places where we cannot merge. - AppealNode *child; + AppealNode *child = NULL; matched = TraverseTableData(rule_table->mData, appeal, child); - appeal->CopyMatch(child); + if (child) { + child->SetChildIndex(0); + appeal->CopyMatch(child); + } break; } case ET_Null: @@ -944,30 +1268,102 @@ bool Parser::TraverseRuleTableRegular(RuleTable *rule_table, AppealNode *appeal) // Returns 1. true if succ. // 2. child_node which represents 'token'. -bool Parser::TraverseToken(Token *token, AppealNode *parent, AppealNode *&child_node) { - Token *curr_token = GetActiveToken(mCurToken); - bool found = false; +bool Parser::TraverseStringSucc(Token *token, AppealNode *parent, AppealNode *&child_node) { + AppealNode *appeal = NULL; mIndentation += 2; if (mTraceTable) { - std::string name = "token:"; + std::string name = "string:"; name += token->GetName(); - name += " curr_token:"; - name += curr_token->GetName(); + name += " curr_token matches"; DumpEnterTable(name.c_str(), mIndentation); } - AppealNode *appeal = new AppealNode(); + appeal = mAppealNodePool.NewAppealNode(); child_node = appeal; mAppealNodes.push_back(appeal); - appeal->mResult = FailNotRightToken; - appeal->SetToken(curr_token); + appeal->SetToken(token); appeal->SetStartIndex(mCurToken); appeal->SetParent(parent); parent->AddChild(appeal); + appeal->mResult = Succ; + appeal->AddMatch(mCurToken); + MoveCurToken(); + + if (mTraceTable) { + std::string name; + name = "string:"; + name += token->GetName(); + DumpExitTable(name.c_str(), mIndentation, appeal); + } + + mIndentation -= 2; + return true; +} + +// Returns 1. true if succ. +// 2. child_node which represents 'token'. +bool Parser::TraverseToken(Token *token, AppealNode *parent, AppealNode *&child_node) { + Token *curr_token = GetActiveToken(mCurToken); + bool found = false; + mIndentation += 2; + + if (mTraceTable) { + std::string name = "token:"; + name += token->GetName(); + name += " curr_token:"; + name += curr_token->GetName(); + DumpEnterTable(name.c_str(), mIndentation); + } bool use_alt_token = false; - if (token == curr_token) { + AppealNode *appeal = NULL; + + // [TODO] + // We enable skipping semi-colon. Later we will implement TS specific version of parser + // which overried TraverseToken(). + // We handle one case in the following: + // The rule expects: + // { statement ;} + // But we see : + // { statement } // No ';' + // In this case we can skip the checking of ';' since '}' actually closes everything. + // There are many other cases. Will handle later. + if (token->IsSeparator() && token->GetSepId() == SEP_Semicolon) { + if (curr_token->IsSeparator() && curr_token->GetSepId() == SEP_Rbrace) { + // 1. There are rule like ZEROORMORE(';'). In this case, we don't insert + RuleTable *parent_rt = parent->GetTable(); + bool need_insert = true; + if (parent_rt->mType == ET_Zeroormore || parent_rt->mType == ET_Zeroorone) + need_insert = false; + + // We also require that '}' is the last token, at least the last in this line + // if not the end of file. + if (mActiveTokens.GetNum() > mCurToken + 1) + need_insert = false; + + // 2. we need check cases where we already have one previous ';'. + Token *prev = mActiveTokens.ValueAtIndex(mCurToken - 1); + if (prev != token && need_insert) { + // The simpliest way is to insert a semicolon token in mActiveTokens. + // Just pretend we lex a semicolon. + InsertToken(mCurToken, token); + curr_token = token; + if (mTraceTable) { + std::cout << "Auto-insert one semicolon." << std::endl; + } + } + } + } + + if (token->Equal(curr_token)) { + appeal = mAppealNodePool.NewAppealNode(); + child_node = appeal; + mAppealNodes.push_back(appeal); + appeal->SetToken(curr_token); + appeal->SetStartIndex(mCurToken); + appeal->SetParent(parent); + parent->AddChild(appeal); appeal->mResult = Succ; appeal->AddMatch(mCurToken); found = true; @@ -977,13 +1373,39 @@ bool Parser::TraverseToken(Token *token, AppealNode *parent, AppealNode *&child_ if (curr_token->mAltTokens) { bool alt_found = false; AltToken *pat = curr_token->mAltTokens; - if (token == &gSystemTokens[pat->mAltTokenId]) { + + // Sometimes a rule which has literally good alt tokens doesn't want to be + // considered as alt token matching, eg. + // RelationalExpression : expr + '>' + expr + // This '>' won't be suitable for alt tokens of >> or >>>, because so far + // there is no expr ending with '>'. + bool parent_ok = true; + if (parent->GetTable()->mProperties & RP_NoAltToken) + parent_ok = false; + + if (parent_ok && (token->Equal(&gSystemTokens[pat->mAltTokenId]))) { + appeal = mAppealNodePool.NewAppealNode(); + child_node = appeal; + mAppealNodes.push_back(appeal); + appeal->SetToken(curr_token); + appeal->SetStartIndex(mCurToken); + appeal->SetParent(parent); + parent->AddChild(appeal); + found = true; alt_found = true; mATMToken = mCurToken; + + if (mTraceTable) { + std::cout << "Work on alt token, index : " << mNextAltTokenIndex << std::endl; + } + if (!mInAltTokensMatching) { mInAltTokensMatching = true; appeal->m1stAltTokenMatched = true; + if (mTraceTable) { + std::cout << "Turn On mInAltTokensMatching " << std::endl; + } } mNextAltTokenIndex++; @@ -998,6 +1420,10 @@ bool Parser::TraverseToken(Token *token, AppealNode *parent, AppealNode *&child_ MoveCurToken(); mInAltTokensMatching = false; mNextAltTokenIndex = 0; + if (mTraceTable) { + std::cout << "Work on alt token is successfully finised. Set mNextAltTokenIndex to : " << mNextAltTokenIndex << std::endl; + std::cout << "Turn Off mInAltTokensMatching " << std::endl; + } } } } @@ -1010,7 +1436,10 @@ bool Parser::TraverseToken(Token *token, AppealNode *parent, AppealNode *&child_ else name = "token:"; name += token->GetName(); - DumpExitTable(name.c_str(), mIndentation, appeal); + if (appeal) + DumpExitTable(name.c_str(), mIndentation, appeal); + else + DumpExitTable(name.c_str(), mIndentation, FailNotRightToken); } mIndentation -= 2; @@ -1048,6 +1477,44 @@ bool Parser::TraverseLiteral(RuleTable *rule_table, AppealNode *appeal) { return found; } +// We don't go into TemplateLiteral table. +// 'appeal' is the node for this rule table. This is different than TraverseOneof +// or the others where 'appeal' is actually a parent node. +bool Parser::TraverseTemplateLiteral(RuleTable *rule_table, AppealNode *appeal) { + Token *curr_token = GetActiveToken(mCurToken); + const char *name = GetRuleTableName(rule_table); + bool found = false; + + if (curr_token->IsTempLit()) { + found = true; + TraverseSpecialTableSucc(rule_table, appeal); + } else { + appeal->mResult = FailNotLiteral; + AddFailed(rule_table, mCurToken); + } + + return found; +} + +// We don't go into RegularExpressionLiteral table. +// 'appeal' is the node for this rule table. This is different than TraverseOneof +// or the others where 'appeal' is actually a parent node. +bool Parser::TraverseRegularExpression(RuleTable *rule_table, AppealNode *appeal) { + Token *curr_token = GetActiveToken(mCurToken); + const char *name = GetRuleTableName(rule_table); + bool found = false; + + if (curr_token->IsRegExpr()) { + found = true; + TraverseSpecialTableSucc(rule_table, appeal); + } else { + appeal->mResult = FailNotRegExpr; + AddFailed(rule_table, mCurToken); + } + + return found; +} + // We don't go into Identifier table. // 'appeal' is the node for this rule table. bool Parser::TraverseIdentifier(RuleTable *rule_table, AppealNode *appeal) { @@ -1110,7 +1577,7 @@ bool Parser::TraverseZeroormore(RuleTable *rule_table, AppealNode *appeal) { bool temp_found = TraverseTableData(data, appeal, child); found_subtable |= temp_found; - if (temp_found) { + if (temp_found && child) { unsigned match_num = child->GetMatchNum(); for (unsigned id = 0; id < match_num; id++) { unsigned match = child->GetMatch(id); @@ -1150,13 +1617,16 @@ bool Parser::TraverseZeroormore(RuleTable *rule_table, AppealNode *appeal) { bool Parser::TraverseZeroorone(RuleTable *rule_table, AppealNode *appeal) { MASSERT((rule_table->mNum == 1) && "zeroorone node has more than one elements?"); TableData *data = rule_table->mData; - AppealNode *child; + AppealNode *child = NULL; bool found = TraverseTableData(data, appeal, child); - appeal->CopyMatch(child); + if (child) + appeal->CopyMatch(child); return true; } // 1. Save all the possible matchings from children. +// There is one exception. If the rule-table is a top rule it should +// get the longest match. // 2. As return value we choose the longest matching. // // 'appeal' is the node of 'rule_table'. @@ -1171,8 +1641,8 @@ bool Parser::TraverseOneof(RuleTable *rule_table, AppealNode *appeal) { bool temp_found = TraverseTableData(data, appeal, child); found = found | temp_found; if (temp_found) { - MASSERT(child); - appeal->CopyMatch(child); + if (child) + appeal->CopyMatch(child); if (mCurToken > new_mCurToken) new_mCurToken = mCurToken; @@ -1180,12 +1650,19 @@ bool Parser::TraverseOneof(RuleTable *rule_table, AppealNode *appeal) { mCurToken = old_mCurToken; // Some ONEOF rules can have only children matching current token seq. + // Or the language desiner just want to match the first children rule. if (rule_table->mProperties & RP_Single) { break; } } } + if (found && (rule_table->mProperties & RP_Top)) { + unsigned longest = appeal->LongestMatch(); + appeal->ClearMatch(); + appeal->AddMatch(longest); + } + // move position according to the longest matching mCurToken = new_mCurToken; return found; @@ -1202,7 +1679,7 @@ bool Parser::TraverseOneof(RuleTable *rule_table, AppealNode *appeal) { // e.g. in a rule like below // rule AA : BB + CC + ZEROORONE(xxx) // If ZEROORONE(xxx) doesn't match anything, it sets subtable_succ_tokens to 0. However -// rule AA matches multiple tokens. So final_succ_tokens needs to be calculated carefully. +// rule AA matches 'BB + CC'. So final_succ_tokens needs to be calculated carefully. // 4. We are going to take succ match info from SuccMatch, not from a specific // AppealNode. SuccMatch has the complete info. // @@ -1215,22 +1692,41 @@ bool Parser::TraverseConcatenate(RuleTable *rule_table, AppealNode *appeal) { SmallVector prev_succ_tokens; SmallVector subtable_succ_tokens; - SmallVector final_succ_tokens; unsigned saved_mCurToken = mCurToken; + // prepare the prev_succ_tokens[_num] for the 1st iteration. int last_matched = mCurToken - 1; + prev_succ_tokens.PushBack(last_matched); - // prepare the prev_succ_tokens[_num] for the 1st iteration. - prev_succ_tokens.PushBack(mCurToken - 1); + // This is regarding the matching of Alternative Tokens. For example, + // a> + // >> needs to be matched as two '>'. + // mInAltTokensMatching is used to control if we are in the middle of matching such tokens. + // However, there is a complicated case, that is "c>", which could be matched as part + // RelationshipExpression, and it turned on mInAltTokensMatching. But it actually fails + // to be a RelationshipExpression and mInAltTokensMatching should be turned off. + bool turned_on_AltToken = false; for (unsigned i = 0; i < rule_table->mNum; i++) { - bool is_zeroxxx = false; + bool is_zeroxxx = false; // If the table is Zeroorxxx(), or NoLineTerminator. + bool no_line_term = false; // If the table is NoLineTerminator + bool no_line_term_met = false; // If the table is NoLineTerminator and token is no line term. + bool is_asi = false; + bool is_token = false; + bool old_mInAltTokensMatching = mInAltTokensMatching; + TableData *data = rule_table->mData + i; if (data->mType == DT_Subtable) { - RuleTable *zero_rt = data->mData.mEntry; - if (zero_rt->mType == ET_Zeroormore || zero_rt->mType == ET_Zeroorone) + RuleTable *curr_rt = data->mData.mEntry; + if (curr_rt == &TblNoLineTerminator) + no_line_term = true; + if (curr_rt->mType == ET_Zeroormore || curr_rt->mType == ET_Zeroorone) is_zeroxxx = true; + if (curr_rt->mType == ET_ASI) + is_asi = true; + } else if (data->mType == DT_Token) { + is_token = true; } SmallVector carry_on_prev; @@ -1250,49 +1746,56 @@ bool Parser::TraverseConcatenate(RuleTable *rule_table, AppealNode *appeal) { AppealNode *child = NULL; bool temp_found = TraverseTableData(data, appeal, child); + if (child) + child->SetChildIndex(i); found_subtable |= temp_found; - if (temp_found) { - bool duplicated_with_prev = false; - for (unsigned id = 0; id < child->GetMatchNum(); id++) { - unsigned match = child->GetMatch(id); - if (!subtable_succ_tokens.Find(match)) - subtable_succ_tokens.PushBack(match); - if (match == prev) - duplicated_with_prev = true; + if (temp_found ) { + if (child) { + for (unsigned id = 0; id < child->GetMatchNum(); id++) { + unsigned match = child->GetMatch(id); + if (!subtable_succ_tokens.Find(match)) + subtable_succ_tokens.PushBack(match); + } + } else if (is_asi) { + // ASI succeeded, without child. It means semicolon is skipped. + // Keep prev. NO moving mCurToken. + subtable_succ_tokens.PushBack(prev); } - - // for Zeroorone/Zeroormore node it always returns true. NO matter how - // many tokens it really matches, 'zero' is also a correct match. we - // need take it into account so that the next rule table can try - // on it. [Except it's a duplication] - if (is_zeroxxx && !duplicated_with_prev) - carry_on_prev.PushBack(prev); } } - // Update the final_succ_tokens - // Please read comment 3 before this function. - if (!is_zeroxxx) - final_succ_tokens.Clear(); - - prev_succ_tokens.Clear(); + if ((prev_succ_tokens.GetNum() == 1) && no_line_term) { + unsigned prev = prev_succ_tokens.ValueAtIndex(0); + Token *t = GetActiveToken(prev + 1); + if (!t->mLineBegin) + no_line_term_met = true; + } - if (found_subtable) { + // for Zeroorone/Zeroormore node it always returns true. NO matter how + // many tokens it really matches, 'zero' is also a correct match. we + // need take it into account so that the next rule table can try + // on it. + if (!is_zeroxxx && !no_line_term_met) + prev_succ_tokens.Clear(); + + // is_zeroxxx seems redundant because the traversal should always be true. + // However, it's not true. In mLineMode, mEndOfFile could be set before + // traversing this ZEROORXXX table. It will return false. + // Since we do treat this case as success, so is_zeroxxx is included in this + // condition expression. + if (found_subtable || is_zeroxxx) { for (unsigned id = 0; id < subtable_succ_tokens.GetNum(); id++) { unsigned token = subtable_succ_tokens.ValueAtIndex(id); if (!prev_succ_tokens.Find(token)) prev_succ_tokens.PushBack(token); - if (!final_succ_tokens.Find(token)) - final_succ_tokens.PushBack(token); } - for (unsigned id = 0; id < carry_on_prev.GetNum(); id++) { - unsigned token = carry_on_prev.ValueAtIndex(id); - if (!prev_succ_tokens.Find(token)) - prev_succ_tokens.PushBack(token); + // alert mInAltTokensMatching is turned on + if (is_token && mInAltTokensMatching && !old_mInAltTokensMatching) { + turned_on_AltToken = true; } } else { - // Once a single child rule fails, the 'appeal' fails. + // Once a child rule fails, the 'appeal' fails. found = false; break; } @@ -1301,9 +1804,10 @@ bool Parser::TraverseConcatenate(RuleTable *rule_table, AppealNode *appeal) { mCurToken = saved_mCurToken; if (found) { - for (unsigned id = 0; id < final_succ_tokens.GetNum(); id++) { - unsigned token = final_succ_tokens.ValueAtIndex(id); - appeal->AddMatch(token); + for (unsigned id = 0; id < prev_succ_tokens.GetNum(); id++) { + unsigned token = prev_succ_tokens.ValueAtIndex(id); + if (token != last_matched) + appeal->AddMatch(token); } // mCurToken doesn't have much meaning in current algorithm when // transfer to the next rule table, because the next rule will take @@ -1314,6 +1818,10 @@ bool Parser::TraverseConcatenate(RuleTable *rule_table, AppealNode *appeal) { appeal->mResult = Succ; if (appeal->GetMatchNum() > 0) mCurToken = appeal->LongestMatch() + 1; + } else if (turned_on_AltToken) { + mInAltTokensMatching = false; + if (mTraceTable) + std::cout << "Turned Off mInAltTokensMatching." << std::endl; } return found; @@ -1325,8 +1833,24 @@ bool Parser::TraverseConcatenate(RuleTable *rule_table, AppealNode *appeal) { // Oneof and Zeroormore should be handled differently. // 3. The mCurToken moves if found target, or restore the original location. bool Parser::TraverseTableData(TableData *data, AppealNode *appeal, AppealNode *&child_node) { - if (mEndOfFile) - return false; + // Usually mCurToken is a new token to be matched. So if it's end of file, we simply return false. + // However, (1) if mCurToken is actually an ATMToken, which means it needs to be matched + // multiple times, we are NOT at the end yet. + // (2) If we are traverse a Concatenate rule, and the previous sub-rule has multiple matches, + // and we are trying the current sub-rule, ie. 'data', using one of the matches. + // The lexer actually reaches the EndOfFile in previous matchings, but the mCurToken + // we are working on right now is not the last token. It's one of the previous matches. + // So we need check if we are matching the last token. + if (mEndOfFile && mCurToken >= mActiveTokens.GetNum()) { + if (!(mInAltTokensMatching && (mCurToken == mATMToken))) { + if (data->mType == DT_Subtable) { + RuleTable *t = data->mData.mEntry; + if (t->mType == ET_ASI) + return TraverseASI(t, appeal, child_node); + } + return false; + } + } unsigned old_pos = mCurToken; bool found = false; @@ -1334,10 +1858,14 @@ bool Parser::TraverseTableData(TableData *data, AppealNode *appeal, AppealNode * switch (data->mType) { case DT_Char: + MASSERT(0 && "Hit Char in TableData during matching!"); + break; case DT_String: - //MASSERT(0 && "Hit Char/String in TableData during matching!"); - //TODO: Need compare literal. But so far looks like it's impossible to - // have a literal token able to match a string/char in rules. + if (curr_token->IsIdentifier() && + !strncmp(curr_token->GetName(), data->mData.mString, strlen(data->mData.mString)) && + strlen(curr_token->GetName()) == strlen(data->mData.mString) ){ + found = TraverseStringSucc(curr_token, appeal, child_node); + } break; // separator, operator, keywords are generated as DT_Token. // just need check the pointer of token @@ -1369,18 +1897,23 @@ void Parser::SetIsDone(unsigned group_id, unsigned start_token) { bool found = succ->GetStartToken(start_token); if(found) succ->SetIsDone(); - } + } } void Parser::SetIsDone(RuleTable *rt, unsigned start_token) { // We don't save SuccMatch for TblLiteral and TblIdentifier - if((rt == &TblLiteral) || (rt == &TblIdentifier)) + if((rt == &TblLiteral) || + (rt == &TblIdentifier) || + (rt == &TblRegularExpression) || + (rt == &TblTemplateLiteral)) return; SuccMatch *succ = &gSucc[rt->mIndex]; bool found = succ->GetStartToken(start_token); - MASSERT(found); - succ->SetIsDone(); + if (rt != &TblNoLineTerminator) { + MASSERT(found); + succ->SetIsDone(); + } } ///////////////////////////////////////////////////////////////////////////// @@ -1411,19 +1944,33 @@ void Parser::SetIsDone(RuleTable *rt, unsigned start_token) { // get a single tree. ///////////////////////////////////////////////////////////////////////////// -// We don't want to use recursive. So a deque is used here. +// We don't want to use recursion. So a deque is used here. static std::deque to_be_sorted; void Parser::SortOut() { // we remove all failed children, leaving only succ child - std::vector::iterator it = mRootNode->mChildren.begin(); - for (; it != mRootNode->mChildren.end(); it++) { - AppealNode *n = *it; - if (!n->IsFail() && !n->IsNA()) - mRootNode->mSortedChildren.push_back(n); + AppealNode *root = NULL; + if (!mLineMode) { + for (unsigned i = 0; i < mRootNode->mChildren.GetNum(); i++) { + AppealNode *n = mRootNode->mChildren.ValueAtIndex(i); + if (!n->IsFail() && !n->IsNA()) + mRootNode->mSortedChildren.PushBack(n); + } + MASSERT(mRootNode->mSortedChildren.GetNum()==1); + root = mRootNode->mSortedChildren.ValueAtIndex(0); + } else { + // LineMode could have >1 matching children + // Find the longest match + unsigned longest = mRootNode->LongestMatch(); + for (unsigned i = 0; i < mRootNode->mChildren.GetNum(); i++) { + AppealNode *n = mRootNode->mChildren.ValueAtIndex(i); + if (n->LongestMatch() == longest) { + root = n; + mRootNode->mSortedChildren.PushBack(n); + break; + } + } } - MASSERT(mRootNode->mSortedChildren.size()==1); - AppealNode *root = mRootNode->mSortedChildren.front(); // First sort the root. RuleTable *table = root->GetTable(); @@ -1432,12 +1979,22 @@ void Parser::SortOut() { MASSERT(succ && "root has no SuccMatch?"); bool found = succ->GetStartToken(root->GetStartIndex()); - // Top level tree can have only one match, otherwise, the language + // In regular parsing, Top level tree can have only one match, otherwise, the language // is ambiguous. + // In LineMode parsing, we are parsing an expression, and it could be multiple matching + // with some partial matchings. We pick the longest matching and it should be the same + // as mActiveTokens.GetNum() meaning it matches all token so far. unsigned match_num = succ->GetMatchNum(); - MASSERT(match_num == 1 && "Top level tree has >1 matches?"); - unsigned match = succ->GetOneMatch(0); + unsigned match = 0; + if (mLineMode) { + match = root->LongestMatch(); + MASSERT(match + 1 == mActiveTokens.GetNum()); + } else { + MASSERT(match_num == 1 && "Top level tree has >1 matches?"); + match = succ->GetOneMatch(0); + } root->SetFinalMatch(match); + root->SetSorted(); to_be_sorted.clear(); @@ -1468,7 +2025,7 @@ void Parser::SortOutNode(AppealNode *node) { // during matching. In SortOut, we simple return. However, when generating IR, // the children have to be created. if (node->mResult == SuccWasSucc) { - MASSERT(node->mChildren.size() == 0); + MASSERT(node->mChildren.GetNum() == 0); return; } @@ -1479,16 +2036,15 @@ void Parser::SortOutNode(AppealNode *node) { RuleTable *rule_table = node->GetTable(); // Table Identifier and Literal don't need sort. - if (rule_table == &TblIdentifier || rule_table == &TblLiteral) + if (rule_table == &TblIdentifier || rule_table == &TblLiteral || rule_table == &TblTemplateLiteral) return; // The lead node of a traversal group need special solution, if they are // simply connect to previous instance(s). if (mRecursionAll.IsLeadNode(rule_table)) { bool connect_only = true; - std::vector::iterator it = node->mChildren.begin(); - for (; it != node->mChildren.end(); it++) { - AppealNode *child = *it; + for (unsigned i = 0; i < node->mChildren.GetNum(); i++) { + AppealNode *child = node->mChildren.ValueAtIndex(i); if (!child->IsTable() || child->GetTable() != rule_table) { connect_only = false; break; @@ -1537,15 +2093,14 @@ void Parser::SortOutRecursionHead(AppealNode *parent) { unsigned parent_match = parent->GetFinalMatch(); //Find the first child having the same match as parent. - std::vector::iterator it = parent->mChildren.begin(); - for (; it != parent->mChildren.end(); it++) { - AppealNode *child = *it; + for (unsigned i = 0; i < parent->mChildren.GetNum(); i++) { + AppealNode *child = parent->mChildren.ValueAtIndex(i); if (child->IsFail() || child->IsNA()) continue; bool found = child->FindMatch(parent_match); if (found) { to_be_sorted.push_back(child); - parent->mSortedChildren.push_back(child); + parent->mSortedChildren.PushBack(child); child->SetFinalMatch(parent_match); child->SetSorted(); child->SetParent(parent); @@ -1566,9 +2121,8 @@ void Parser::SortOutOneof(AppealNode *parent) { unsigned parent_match = parent->GetFinalMatch(); unsigned good_children = 0; - std::vector::iterator it = parent->mChildren.begin(); - for (; it != parent->mChildren.end(); it++) { - AppealNode *child = *it; + for (unsigned i = 0; i < parent->mChildren.GetNum(); i++) { + AppealNode *child = parent->mChildren.ValueAtIndex(i); if (child->IsFail() || child->IsNA()) continue; @@ -1583,14 +2137,14 @@ void Parser::SortOutOneof(AppealNode *parent) { child->SetFinalMatch(parent_match); child->SetParent(parent); good_children++; - parent->mSortedChildren.push_back(child); + parent->mSortedChildren.PushBack(child); } } else { bool found = child->FindMatch(parent_match); if (found) { good_children++; to_be_sorted.push_back(child); - parent->mSortedChildren.push_back(child); + parent->mSortedChildren.PushBack(child); child->SetFinalMatch(parent_match); child->SetSorted(); child->SetParent(parent); @@ -1630,9 +2184,8 @@ void Parser::SortOutZeroormore(AppealNode *parent) { SmallVector sorted_children; while(1) { AppealNode *good_child = NULL; - std::vector::iterator it = parent->mChildren.begin(); - for (; it != parent->mChildren.end(); it++) { - AppealNode *child = *it; + for (unsigned i = 0; i < parent->mChildren.GetNum(); i++) { + AppealNode *child = parent->mChildren.ValueAtIndex(i); if (sorted_children.Find(child)) continue; if (child->IsSucc() && child->FindMatch(last_match)) { @@ -1657,7 +2210,7 @@ void Parser::SortOutZeroormore(AppealNode *parent) { for (int i = sorted_children.GetNum() - 1; i >= 0; i--) { AppealNode *child = sorted_children.ValueAtIndex(i); - parent->mSortedChildren.push_back(child); + parent->mSortedChildren.PushBack(child); if (child->IsTable()) to_be_sorted.push_back(child); } @@ -1682,8 +2235,8 @@ void Parser::SortOutZeroorone(AppealNode *parent) { // 2. If the child is succ, the major work of this loop is to verify the child's SuccMatch is // consistent with parent's. - MASSERT((parent->mChildren.size() == 1) && "Zeroorone has >1 valid children?"); - AppealNode *child = parent->mChildren.front(); + MASSERT((parent->mChildren.GetNum() == 1) && "Zeroorone has >1 valid children?"); + AppealNode *child = parent->mChildren.ValueAtIndex(0); if (child->IsFail() || child->IsNA()) return; @@ -1710,7 +2263,7 @@ void Parser::SortOutZeroorone(AppealNode *parent) { } // Finally add the only successful child to mSortedChildren - parent->mSortedChildren.push_back(child); + parent->mSortedChildren.PushBack(child); child->SetParent(parent); } @@ -1742,13 +2295,15 @@ void Parser::SortOutConcatenate(AppealNode *parent) { SmallVector sorted_children; for (int i = rule_table->mNum - 1; i >= 0; i--) { TableData *data = rule_table->mData + i; - AppealNode *child = parent->FindSpecChild(data, last_match); - // It's possible that we find NO child if 'data' is a ZEROORxxx table + AppealNode *child = parent->FindIndexedChild(last_match, i); + // It's possible that we find NO child if 'data' is a ZEROORxxx table or ASI. bool good_child = false; if (!child) { if (data->mType == DT_Subtable) { RuleTable *table = data->mData.mEntry; - if (table->mType == ET_Zeroorone || table->mType == ET_Zeroormore) + if (table->mType == ET_Zeroorone || table->mType == ET_Zeroormore || table == &TblNoLineTerminator) + good_child = true; + if (table->mType == ET_ASI) good_child = true; } MASSERT(good_child); @@ -1769,7 +2324,7 @@ void Parser::SortOutConcatenate(AppealNode *parent) { for (int i = sorted_children.GetNum() - 1; i >= 0; i--) { AppealNode *child = sorted_children.ValueAtIndex(i); - parent->mSortedChildren.push_back(child); + parent->mSortedChildren.PushBack(child); if (child->IsTable()) to_be_sorted.push_back(child); } @@ -1787,21 +2342,21 @@ void Parser::SortOutData(AppealNode *parent) { case DT_Subtable: { // There should be one child node, which represents the subtable. // we just need to add the child node to working list. - MASSERT((parent->mChildren.size() == 1) && "Should have only one child?"); - AppealNode *child = parent->mChildren.front(); + MASSERT((parent->mChildren.GetNum() == 1) && "Should have only one child?"); + AppealNode *child = parent->mChildren.ValueAtIndex(0); child->SetFinalMatch(parent->GetFinalMatch()); child->SetSorted(); to_be_sorted.push_back(child); - parent->mSortedChildren.push_back(child); + parent->mSortedChildren.PushBack(child); child->SetParent(parent); break; } case DT_Token: { // token in table-data created a Child AppealNode // Just keep the child node. Don't need do anything. - AppealNode *child = parent->mChildren.front(); + AppealNode *child = parent->mChildren.ValueAtIndex(0); child->SetFinalMatch(child->GetStartIndex()); - parent->mSortedChildren.push_back(child); + parent->mSortedChildren.PushBack(child); child->SetParent(parent); break; } @@ -1843,12 +2398,9 @@ void Parser::DumpSortOutNode(AppealNode *n) { unsigned dump_id = to_be_dumped_id.front(); to_be_dumped_id.pop_front(); - if (n->mSimplifiedIndex > 0) - std::cout << "[" << dump_id << ":" << n->mSimplifiedIndex<< "] "; - else - std::cout << "[" << dump_id << "] "; + std::cout << "[" << dump_id << ":" << n->GetChildIndex() << "] "; if (n->IsToken()) { - std::cout << "Token" << std::endl; + n->mData.mToken->Dump(); } else { RuleTable *t = n->GetTable(); std::cout << "Table " << GetRuleTableName(t) << "@" << n->GetStartIndex() << ": "; @@ -1856,10 +2408,9 @@ void Parser::DumpSortOutNode(AppealNode *n) { if (n->mResult == SuccWasSucc) std::cout << "WasSucc"; - std::vector::iterator it = n->mSortedChildren.begin(); - for (; it != n->mSortedChildren.end(); it++) { + for (unsigned i = 0; i < n->mSortedChildren.GetNum(); i++) { std::cout << seq_num << ","; - to_be_dumped.push_back(*it); + to_be_dumped.push_back(n->mSortedChildren.ValueAtIndex(i)); to_be_dumped_id.push_back(seq_num++); } std::cout << std::endl; @@ -1905,9 +2456,8 @@ void Parser::FindWasSucc(AppealNode *root) { std::cout << "a token?" << std::endl; } } else { - std::vector::iterator it = node->mSortedChildren.begin(); - for (; it != node->mSortedChildren.end(); it++) - working_list.push_back(*it); + for (unsigned i = 0; i < node->mSortedChildren.GetNum(); i++) + working_list.push_back(node->mSortedChildren.ValueAtIndex(i)); } } return; @@ -1950,7 +2500,7 @@ void Parser::FindPatchingNodes() { // This is another entry point of sort, similar as SortOut(). // The only difference is we use 'reference' as the refrence of final match. void Parser::SupplementalSortOut(AppealNode *root, AppealNode *reference) { - MASSERT(root->mSortedChildren.size()==0 && "root should be un-sorted."); + MASSERT(root->mSortedChildren.GetNum()==0 && "root should be un-sorted."); MASSERT(root->IsTable() && "root should be a table node."); // step 1. Find the last matching token index we want. @@ -2010,8 +2560,8 @@ void Parser::PatchWasSucc(AppealNode *root) { // it's the original tree. We don't want to mess it up. Think about it, if you // copy the mChildren to was_succ, there are duplicated tree nodes. This violates // the definition of the original tree. - for (unsigned j = 0; j < patch->mSortedChildren.size(); j++) - was_succ->AddSortedChild(patch->mSortedChildren[j]); + for (unsigned j = 0; j < patch->mSortedChildren.GetNum(); j++) + was_succ->AddSortedChild(patch->mSortedChildren.ValueAtIndex(j)); } } @@ -2031,7 +2581,7 @@ void Parser::PatchWasSucc(AppealNode *root) { void Parser::SimplifySortedTree() { // start with the only child of mRootNode. std::deque working_list; - working_list.push_back(mRootNode->mSortedChildren[0]); + working_list.push_back(mRootNode->mSortedChildren.ValueAtIndex(0)); while(!working_list.empty()) { AppealNode *node = working_list.front(); @@ -2043,14 +2593,13 @@ void Parser::SimplifySortedTree() { continue; node = SimplifyShrinkEdges(node); - std::vector::iterator it = node->mSortedChildren.begin(); - for (; it != node->mSortedChildren.end(); it++) { - working_list.push_back(*it); + for (unsigned i = 0; i < node->mSortedChildren.GetNum(); i++) { + working_list.push_back(node->mSortedChildren.ValueAtIndex(i)); } } if (mTraceSortOut) - DumpSortOut(mRootNode->mSortedChildren[0], "Simplify AppealNode Trees"); + DumpSortOut(mRootNode->mSortedChildren.ValueAtIndex(0), "Simplify AppealNode Trees"); } // Reduce an edge is (1) Pred has only one succ @@ -2069,31 +2618,31 @@ AppealNode* Parser::SimplifyShrinkEdges(AppealNode *node) { while(1) { // step 1. Check condition (1) (2) - if (node->mSortedChildren.size() != 1) + if (node->mSortedChildren.GetNum() != 1) break; - AppealNode *child = node->mSortedChildren[0]; + AppealNode *child = node->mSortedChildren.ValueAtIndex(0); // step 2. Find out the index of child, through looking into sub-ruletable or token. - // At this point, there is only one sorted child. - unsigned child_index; - bool found = node->GetSortedChildIndex(child, child_index); - if (!found) { - // There is one case where it cannot find child_index. In the left recursion - // parsing, each instance is connected to its previous one through the lead node. - // The connected two nodes are both lead rule table. We need remove one of them. - // - // In this case we don't worry about action since one of them is kept and the - // actions are kept actually. - RuleTable *rt_p = node->GetTable(); - RuleTable *rt_c = child->GetTable(); - MASSERT((rt_p == rt_c)); - MASSERT(mRecursionAll.IsLeadNode(rt_p)); - } else { + // There is one case where it cannot find child_index. In the left recursion + // parsing, each instance is connected to its previous one through the lead node. + // The connected two nodes are both lead rule table. We need remove one of them. + // + // In this case we don't worry about action since one of them is kept and the + // actions are kept actually. + + bool skip = false; + RuleTable *rt_p = node->GetTable(); + RuleTable *rt_c = child->GetTable(); + if (rt_p == rt_c && mRecursionAll.IsLeadNode(rt_p)) + skip = true; + + unsigned child_index = child->GetChildIndex(); + if (!skip) { // step 3. check condition (3) // [NOTE] in RuleAction, element index starts from 1. RuleTable *rt = node->GetTable(); - bool has_action = RuleActionHasElem(rt, child_index); + bool has_action = RuleActionHasElem(rt, child_index + 1); if (has_action) break; } @@ -2103,14 +2652,8 @@ AppealNode* Parser::SimplifyShrinkEdges(AppealNode *node) { AppealNode *parent = node->GetParent(); parent->ReplaceSortedChild(node, child); - // 1. mRootNode won't have RuleAction, so the index is never used. - // 2. 'index' just need be calculated once, at the first ancestor which is 'node' - // transferred into this function. - if (parent != mRootNode && index == 0) { - found = parent->GetSortedChildIndex(node, index); - MASSERT(found && "Could not find child index?"); - } - child->mSimplifiedIndex = index; + index = node->GetChildIndex(); + child->SetChildIndex(index); // step 5. keep going node = child; @@ -2123,20 +2666,20 @@ AppealNode* Parser::SimplifyShrinkEdges(AppealNode *node) { // Build the AST //////////////////////////////////////////////////////////////////////////////////// -ASTTree* Parser::BuildAST() { - ASTTree *tree = new ASTTree(); +TreeNode* Parser::BuildAST() { + mLineModeRoot = NULL; + mNormalModeRoot = NULL; std::stack appeal_stack; - appeal_stack.push(mRootNode->mSortedChildren[0]); + appeal_stack.push(mRootNode->mSortedChildren.ValueAtIndex(0)); // 1) If all children done. Time to create tree node for 'appeal_node' // 2) If some are done, some not. Add the first not-done child to stack while(!appeal_stack.empty()) { AppealNode *appeal_node = appeal_stack.top(); bool children_done = true; - std::vector::iterator it = appeal_node->mSortedChildren.begin(); - for (; it != appeal_node->mSortedChildren.end(); it++) { - AppealNode *child = *it; + for (unsigned i = 0; i < appeal_node->mSortedChildren.GetNum(); i++) { + AppealNode *child = appeal_node->mSortedChildren.ValueAtIndex(i); if (!child->AstCreated()) { appeal_stack.push(child); children_done = false; @@ -2147,24 +2690,219 @@ ASTTree* Parser::BuildAST() { if (children_done) { // Create tree node when there is a rule table, or meanful tokens. MASSERT(!appeal_node->GetAstTreeNode()); - TreeNode *sub_tree = tree->NewTreeNode(appeal_node); + TreeNode *sub_tree = NewTreeNode(appeal_node); if (sub_tree) { appeal_node->SetAstTreeNode(sub_tree); - // mRootNode is overwritten each time until the last one which is + // mNormalModeRoot is overwritten each time until the last one which is // the real root node. - tree->mRootNode = sub_tree; + mNormalModeRoot = sub_tree; } - // pop out the 'appeal_node' appeal_node->SetAstCreated(); appeal_stack.pop(); } } - if (!tree->mRootNode) - MERROR("We got a statement failed to create AST!"); + // The tree could be an empty statement like: ; + + if (mLineMode) + mLineModeRoot = mNormalModeRoot; + + return mNormalModeRoot; +} + +// Create tree node. Its children have been created tree nodes. +// There are couple issueshere. +// +// 1. An sorted AppealNode could have NO tree node, because it may have NO RuleAction to +// create the sub tree. This happens if the RuleTable is just a temporary intermediate +// table created by Autogen, or its rule is just ONEOF without real syntax. Here +// is an example. +// +// The AST after BuildAST() for a simple statment: c=a+b; +// +// ======= Simplify Trees Dump SortOut ======= +// [1] Table TblExpressionStatement@0: 2,3, +// [2:1] Table TblAssignment@0: 4,5,6, +// [3] Token +// [4:1] Token +// [5:2] Token +// [6:3] Table TblArrayAccess_sub1@2: 7,8, <-- supposed to get a binary expression +// [7:1] Token <-- a +// [8:2] Table TblUnaryExpression_sub1@3: 9,10, <-- +b +// [9] Token +// [10:2] Token +// +// Node [1] won't have a tree node at all since it has no Rule Action attached. +// Node [6] won't have a tree node either. +// +// 2. A binary operation like a+b could be parsed as (1) expression: a, and (2) a +// unary operation: +b. This is because we parse them in favor to ArrayAccess before +// Binary Operation. Usually to handle this issue, in some system like ANTLR, +// they require you to list the priority, by writing rules from higher priority to +// lower priority. +// +// We are going to do a consolidation of the sub-trees, by converting smaller trees +// to a more compact bigger trees. However, to do this we want to set some rules. +// *) The parent AppealNode of these sub-trees has no tree node. So the conversion +// helps make the tree complete. + +TreeNode* Parser::NewTreeNode(AppealNode *appeal_node) { + TreeNode *sub_tree = NULL; + + if (appeal_node->IsToken()) { + sub_tree = mASTBuilder->CreateTokenTreeNode(appeal_node->GetToken()); + return sub_tree; + } + + RuleTable *rule_table = appeal_node->GetTable(); + + for (unsigned i = 0; i < rule_table->mNumAction; i++) { + Action *action = rule_table->mActions + i; + mASTBuilder->mActionId = action->mId; + mASTBuilder->ClearParams(); + + for (unsigned j = 0; j < action->mNumElem; j++) { + // find the appeal node child + unsigned elem_idx = action->mElems[j]; + AppealNode *child = appeal_node->GetSortedChild(elem_idx - 1); + Param p; + p.mIsEmpty = true; + // There are 3 cases to handle. + // 1. child is token, we pass the token to param. + // 2. child is a sub appeal tree, but has no legal AST tree. For example, + // a parameter list: '(' + param-lists + ')'. + // if param-list is empty, it has no AST tree. + // In this case, we sset mIsEmpty to true. + // 3. chidl is a sub appeal tree, and has a AST tree too. + if (child) { + TreeNode *tree_node = child->GetAstTreeNode(); + if (!tree_node) { + if (child->IsToken()) { + p.mIsEmpty = false; + p.mIsTreeNode = false; + p.mData.mToken = child->GetToken(); + } + } else { + p.mIsEmpty = false; + p.mIsTreeNode = true; + p.mData.mTreeNode = tree_node; + } + } + mASTBuilder->AddParam(p); + } + + // For multiple actions of a rule, there should be only action which create tree. + // The others are just for adding attribute or else, and return the same tree + // with additional attributes. + sub_tree = mASTBuilder->Build(); + } + + if (sub_tree) + return sub_tree; + + // It's possible that the Rule has no action, meaning it cannot create tree node. + // Now we have to do some manipulation. Please check if you need all of them. + sub_tree = Manipulate(appeal_node); + + // It's possible that the sub tree is actually empty. For example, in a Parameter list + // ( params ). If 'params' is empty, it returns NULL. + + return sub_tree; +} + +// It's possible that we get NULL tree. +TreeNode* Parser::Manipulate(AppealNode *appeal_node) { + TreeNode *sub_tree = NULL; + + std::vector child_trees; + for (unsigned i = 0; i < appeal_node->mSortedChildren.GetNum(); i++) { + AppealNode *a_node = appeal_node->mSortedChildren.ValueAtIndex(i); + TreeNode *t_node = a_node->GetAstTreeNode(); + if (t_node) + child_trees.push_back(t_node); + } + + // If we have one and only one child's tree node, we take it. + if (child_trees.size() == 1) { + sub_tree = child_trees[0]; + if (sub_tree) + return sub_tree; + else + MERROR("We got a broken AST tree, not connected sub tree."); + } + + // For the tree having two children, there are a few approaches to further + // manipulate them in order to obtain better AST. + // + // 1. There are cases like (type)value, but they are not recoganized as cast. + // Insteand they are seperated into two nodes, one is (type), the other value. + // So we define ParenthesisNode for (type), and build a CastNode over here. + // + // 2. There are cases like a+b could be parsed as "a" and "+b", a symbol and a + // unary operation. However, we do prefer binary operation than unary. So a + // combination is needed here, especially when the parent node is NULL. + if (child_trees.size() == 2) { + TreeNode *child_a = child_trees[0]; + TreeNode *child_b = child_trees[1]; + + sub_tree = Manipulate2Cast(child_a, child_b); + if (sub_tree) + return sub_tree; + } + + // In the end, if we still have no suitable solution to create the tree, + // we will put subtrees into a PassNode to pass to parent. + if (child_trees.size() > 0) { + PassNode *pass = (PassNode*)BuildPassNode(); + std::vector::iterator child_it = child_trees.begin(); + for (; child_it != child_trees.end(); child_it++) + pass->AddChild(*child_it); + return pass; + } + + // It's possible that we get a Null tree. + return sub_tree; +} - return tree; +TreeNode* Parser::Manipulate2Cast(TreeNode *child_a, TreeNode *child_b) { + if (child_a->IsParenthesis()) { + ParenthesisNode *type = (ParenthesisNode*)child_a; + CastNode *n = (CastNode*)gTreePool.NewTreeNode(sizeof(CastNode)); + new (n) CastNode(); + n->SetDestType(type->GetExpr()); + n->SetExpr(child_b); + return n; + } + return NULL; +} + +TreeNode* Parser::Manipulate2Binary(TreeNode *child_a, TreeNode *child_b) { + if (child_b->IsUnaOperator()) { + UnaOperatorNode *unary = (UnaOperatorNode*)child_b; + unsigned property = GetOperatorProperty(unary->GetOprId()); + if ((property & Binary) && (property & Unary)) { + std::cout << "Convert unary --> binary" << std::endl; + TreeNode *unary_sub = unary->GetOpnd(); + TreeNode *binary = BuildBinaryOperation(child_a, unary_sub, unary->GetOprId()); + return binary; + } + } + return NULL; +} + +TreeNode* Parser::BuildBinaryOperation(TreeNode *childA, TreeNode *childB, OprId id) { + BinOperatorNode *n = (BinOperatorNode*)gTreePool.NewTreeNode(sizeof(BinOperatorNode)); + new (n) BinOperatorNode(id); + n->SetOpndA(childA); + n->SetOpndB(childB); + return n; +} + +TreeNode* Parser::BuildPassNode() { + PassNode *n = (PassNode*)gTreePool.NewTreeNode(sizeof(PassNode)); + new (n) PassNode(); + return n; } //////////////////////////////////////////////////////////////////////////// @@ -2280,8 +3018,8 @@ bool SuccMatch::IsDone() { void AppealNode::AddParent(AppealNode *p) { if (!mParent || mParent->IsPseudo()) mParent = p; - else - mSecondParents.PushBack(p); + //else + // mSecondParents.PushBack(p); return; } @@ -2324,47 +3062,11 @@ void AppealNode::CopyMatch(AppealNode *another) { mResult = another->mResult; } -// return true if 'parent' is a parent of this. -bool AppealNode::DescendantOf(AppealNode *parent) { - AppealNode *node = mParent; - while (node) { - if (node == parent) - return true; - node = node->mParent; - } - return false; -} - -// Returns true, if both nodes are successful and match the same tokens -// with the same rule table -bool AppealNode::SuccEqualTo(AppealNode *other) { - if (IsSucc() && other->IsSucc() && mStartIndex == other->GetStartIndex()) { - if (IsToken() && other->IsToken()) { - return GetToken() == other->GetToken(); - } else if (IsTable() && other->IsTable()) { - return GetTable() == other->GetTable(); - } - } - return false; -} - -void AppealNode::RemoveChild(AppealNode *child) { - std::vector temp_vector; - std::vector::iterator it = mChildren.begin(); - for (; it != mChildren.end(); it++) { - if (*it != child) - temp_vector.push_back(*it); - } - - mChildren.clear(); - mChildren.assign(temp_vector.begin(), temp_vector.end()); -} - void AppealNode::ReplaceSortedChild(AppealNode *existing, AppealNode *replacement) { unsigned index; bool found = false; - for (unsigned i = 0; i < mSortedChildren.size(); i++) { - if (mSortedChildren[i] == existing) { + for (unsigned i = 0; i < mSortedChildren.GetNum(); i++) { + if (mSortedChildren.ValueAtIndex(i) == existing) { index = i; found = true; break; @@ -2372,126 +3074,32 @@ void AppealNode::ReplaceSortedChild(AppealNode *existing, AppealNode *replacemen } MASSERT(found && "ReplaceSortedChild could not find existing node?"); - mSortedChildren[index] = replacement; + *(mSortedChildren.RefAtIndex(index)) = replacement; replacement->SetParent(this); } -// Returns true : if successfully found the index. -// [NOTE] This is the index in the Rule Spec description, which are used in the -// building of AST. So remember it starts from 1. -// -// The AppealNode tree has many messy nodes generated during second try, or others. -// It's not a good idea to find the index through the tree. The final real solution -// is to go through the RuleTable and locate the child's index. -bool AppealNode::GetSortedChildIndex(AppealNode *child, unsigned &index) { - bool found = false; - MASSERT(IsTable() && "Parent node is not a RuleTable"); - RuleTable *rule_table = GetTable(); - - // In SimplifyShrinkEdge, the tree could be simplified and a node could be given an index - // to his ancestor. - if (child->mSimplifiedIndex != 0) { - index = child->mSimplifiedIndex; - return true; - } - - // If the edge is not shrinked, we just look into the rule tabls or tokens. - for (unsigned i = 0; i < rule_table->mNum; i++) { - TableData *data = rule_table->mData + i; - switch (data->mType) { - case DT_Token: { - Token *t = &gSystemTokens[data->mData.mTokenId]; - if (child->IsToken() && child->GetToken() == t) { - found = true; - index = i+1; - } - break; - } - case DT_Subtable: { - RuleTable *t = data->mData.mEntry; - if (t == &TblIdentifier) { - if (child->IsToken()) { - Token *token = child->GetToken(); - if (token->IsIdentifier()) { - found = true; - index = i+1; - } - } - } else if (t == &TblLiteral) { - if (child->IsToken()) { - Token *token = child->GetToken(); - if (token->IsLiteral()) { - found = true; - index = i+1; - } - } - } else if (child->IsTable() && child->GetTable() == t) { - found = true; - index = i+1; - } - break; - } - case DT_String: - case DT_Char: - break; - default: - MASSERT(0 && "Unknown entry in TableData"); - break; - } - } - - return found; -} - -AppealNode* AppealNode::GetSortedChildByIndex(unsigned index) { - std::vector::iterator it = mSortedChildren.begin(); - for (; it != mSortedChildren.end(); it++) { - AppealNode *child = *it; - unsigned id = 0; - bool found = GetSortedChildIndex(child, id); - MASSERT(found && "sorted child has no index.."); +AppealNode* AppealNode::GetSortedChild(unsigned index) { + for (unsigned i = 0; i < mSortedChildren.GetNum(); i++) { + AppealNode *child = mSortedChildren.ValueAtIndex(i); + unsigned id = child->GetChildIndex(); if (id == index) return child; } return NULL; } -// Look for a specific un-sorted child having the ruletable/token and match. -// There could be multiple, but we return the first good one. -AppealNode* AppealNode::FindSpecChild(TableData *tdata, unsigned match) { +// Look for a specific un-sorted child having the child index and match. +AppealNode* AppealNode::FindIndexedChild(unsigned match, unsigned index) { AppealNode *ret_child = NULL; - - std::vector::iterator it = mChildren.begin(); - for (; it != mChildren.end(); it++) { - AppealNode *child = *it; - if (child->IsSucc() && child->FindMatch(match)) { - switch (tdata->mType) { - case DT_Subtable: { - RuleTable *child_rule = tdata->mData.mEntry; - if (child->IsTable() && child->GetTable() == child_rule) - ret_child = child; - // Literal and Identifier are treated as token. - if (child->IsToken() && (child_rule == &TblLiteral || child_rule == &TblIdentifier)) - ret_child = child; - break; - } - case DT_Token: { - Token *token = &gSystemTokens[tdata->mData.mTokenId]; - if ( child->IsToken() && - ((child->GetToken() == token) || (child->mAltToken == token))) - ret_child = child; - break; - } - case DT_Char: - case DT_String: - case DT_Type: - case DT_Null: - default: - break; - } + for (unsigned i = 0; i < mChildren.GetNum(); i++) { + AppealNode *child = mChildren.ValueAtIndex(i); + if (child->IsSucc() && + child->FindMatch(match) && + (index == child->GetChildIndex())) { + ret_child = child; + break; } } - return ret_child; } diff --git a/src/MapleFE/shared/src/parser_rec.cpp b/src/MapleFE/shared/src/parser_rec.cpp index d5fe65357bf228b316554bd64741c7c55d291d99..615b78d63a065ed6bb1798dcee738794a1654ae6 100644 --- a/src/MapleFE/shared/src/parser_rec.cpp +++ b/src/MapleFE/shared/src/parser_rec.cpp @@ -21,7 +21,7 @@ #include "parser.h" #include "parser_rec.h" #include "ruletable_util.h" -#include "gen_summary.h" +#include "rule_summary.h" namespace maplefe { @@ -182,7 +182,7 @@ bool RecursionTraversal::ConnectPrevious(AppealNode *curr_node) { // will handle the multiple parents issue. curr_node->AddChild(prev_lead); prev_lead->AddParent(curr_node); - + // there should be only one match. MASSERT(!found); found = true; @@ -217,8 +217,12 @@ bool RecursionTraversal::FindInstances() { mVisitedRecursionNodes.Clear(); mLeadNodes.Clear(); - // Find the instance + // Find the instance. + // Remember to reset mEndOfFile since the prev instance could reach the end of file + // We need start from the beginning. mParser->mCurToken = saved_mCurToken; + if (mParser->mEndOfFile) + mParser->mEndOfFile = false; temp_found = FindRestInstance(); } @@ -251,9 +255,9 @@ bool RecursionTraversal::FindFirstInstance() { // Appealing of the mistaken Fail nodes. // - // This is for appealing those affected by the 1st appearance - // of 1st instance which returns false. 1stOf1st is not add to WasFail, but - // those affected will be added to WasFail. + // This is for appealing those affected by the 2nd appearance + // of 2nd instance which returns false. 2ndOf1st is not add to WasFail, but + // those affected will be AddFailed(). // // I still keep an assertion in TraverseRuleTablePre() when it has SuccMatch, // asserting !WasFail. But I believe there are still WasFail at the same time. @@ -281,7 +285,6 @@ bool RecursionTraversal::FindRestInstance() { AppealNode *lead = new AppealNode(); lead->SetStartIndex(mStartToken); lead->SetTable(mRuleTable); - mParser->mAppealNodes.push_back(lead); AddLeadNode(lead); AddVisitedLeadNode(mRuleTable); diff --git a/src/MapleFE/shared/src/recursion.cpp b/src/MapleFE/shared/src/recursion.cpp index dc08a2d1a283582ea43824d381d14ee87ed4b7dd..c67f4e88ccd95427ea286ce43368c5c4d38e1652 100644 --- a/src/MapleFE/shared/src/recursion.cpp +++ b/src/MapleFE/shared/src/recursion.cpp @@ -20,8 +20,7 @@ ///////////////////////////////////////////////////////////////////////////////////// #include "recursion.h" -#include "gen_summary.h" -#include "gen_token.h" +#include "rule_summary.h" #include "token.h" namespace maplefe { @@ -275,7 +274,7 @@ void Recursion::FindFronNodes(unsigned circle_index) { case ET_Oneof: { // Look into every childof 'prev'. If it's not 'next' and // not in 'mRecursionNodes', it's a FronNode. - // + // // [NOTE] This is a per circle algorithm. So a FronNode found here could // be a recursion node in another circle. // Actually if it's Recursion node, we can still include it as FronNode, @@ -290,7 +289,7 @@ void Recursion::FindFronNodes(unsigned circle_index) { fnode.mData.mToken = &gSystemTokens[data->mData.mTokenId]; fron_nodes->PushBack(fnode); //std::cout << " Token " << data->mData.mToken->GetName() << std::endl; - } else if (data->mType = DT_Subtable) { + } else if (data->mType == DT_Subtable) { RuleTable *ruletable = data->mData.mEntry; bool found = IsRecursionNode(ruletable); if (!found && (ruletable != next)) { diff --git a/src/MapleFE/shared/src/ruletable_util.cpp b/src/MapleFE/shared/src/ruletable_util.cpp index 3b6049e2430cfbd3e7cd29d0065d2c57c224a0f5..65dc85557fe634d3dece1f2f5ae82b1f5d576f18 100644 --- a/src/MapleFE/shared/src/ruletable_util.cpp +++ b/src/MapleFE/shared/src/ruletable_util.cpp @@ -16,9 +16,8 @@ #include "ruletable_util.h" #include "lexer.h" -#include "lang_spec.h" #include "massert.h" -#include "common_header_autogen.h" +#include "rule_summary.h" #include "container.h" namespace maplefe { @@ -40,7 +39,7 @@ SepId FindSeparator(const char *str, const char c, unsigned &len) { text = c; unsigned i = 0; - for (; i < SEP_NA; i++) { + for (; i < SepTableSize; i++) { SepTableEntry e = SepTable[i]; if (!strncmp(text.c_str(), e.mText, strlen(e.mText))) { len = strlen(e.mText); @@ -63,7 +62,7 @@ OprId FindOperator(const char *str, const char c, unsigned &len) { text = c; unsigned i = 0; - for (; i < OPR_NA; i++) { + for (; i < OprTableSize; i++) { OprTableEntry e = OprTable[i]; if (!strncmp(text.c_str(), e.mText, strlen(e.mText))) { len = strlen(e.mText); @@ -100,12 +99,20 @@ const char* FindKeyword(const char *str, const char c, unsigned &len) { // Returns true : The rule actions in 'table' involves i-th element // [NOTE] i starts from 1. +// +// If there is an action which has no elem as its argument. It could +// take all element, or any number of element. In this case, we think +// it HasElem. Please look at typescript's stmt.spec. +// rule JSIdentifier: is a good example. +// bool RuleActionHasElem(RuleTable *table, unsigned target_idx) { for (unsigned i = 0; i < table->mNumAction; i++) { Action *act = table->mActions + i; + if (act->mNumElem == 0) + return true; for (unsigned j = 0; j < act->mNumElem; j++) { unsigned index = act->mElems[j]; - if (index = target_idx) + if (index == target_idx) return true; } } diff --git a/src/MapleFE/shared/src/stringmap.cpp b/src/MapleFE/shared/src/stringmap.cpp index 00103b1d35155b00cd0021371cf6b1b935d18b0d..4327e40f7d99d464907d6c7d18599e14d7cca561 100644 --- a/src/MapleFE/shared/src/stringmap.cpp +++ b/src/MapleFE/shared/src/stringmap.cpp @@ -40,17 +40,17 @@ StringMap::~StringMap() { temp = entry->Next; delete entry; entry = temp; - } + } } delete [] mBuckets; } void StringMap::Init(unsigned Num) { - MASSERT((Num & (Num-1)) == 0 && - "Init Size must be a power of 2 or zero!"); - mNumBuckets = Num ? Num : DEFAULT_BUCKETS_NUM; - + MASSERT((Num & (Num-1)) == 0 && + "Init Size must be a power of 2 or zero!"); + mNumBuckets = Num ? Num : DEFAULT_BUCKETS_NUM; + mBuckets = new StringMapEntry[mNumBuckets]; StringMapEntry *E = mBuckets; for (unsigned i = 0; i < mNumBuckets; i++, E++) { @@ -60,20 +60,20 @@ void StringMap::Init(unsigned Num) { } // Get the bucket no for 'S'. -unsigned StringMap::BucketNoFor(const std::string &S) { - unsigned HTSize = mNumBuckets; - if (HTSize == 0) { // Hash table unallocated so far? - Init(DEFAULT_BUCKETS_NUM); - HTSize = mNumBuckets; - } - unsigned FullHashValue = HashString(S); - unsigned BucketNo = FullHashValue & (HTSize-1); - return BucketNo; -} +unsigned StringMap::BucketNoFor(const std::string &S) { + unsigned HTSize = mNumBuckets; + if (HTSize == 0) { // Hash table unallocated so far? + Init(DEFAULT_BUCKETS_NUM); + HTSize = mNumBuckets; + } + unsigned FullHashValue = HashString(S); + unsigned BucketNo = FullHashValue & (HTSize-1); + return BucketNo; +} // Look up to find the address in the string pool of 'S'. // If 'S' is not in the string pool, insert it. -char* StringMap::LookupAddrFor(const std::string &S) { +StringMapEntry *StringMap::LookupEntryFor(const std::string &S) { unsigned BucketNo = BucketNoFor(S); StringMapEntry *E = &mBuckets[BucketNo]; @@ -82,32 +82,37 @@ char* StringMap::LookupAddrFor(const std::string &S) { if (E && !E->Addr && !E->Next) { char *addr = mPool->Alloc(S); E->Addr = addr; - return addr; + E->StrIdx = mPool->mStringTable.size(); + mPool->mStringTable.push_back(addr); + return E; } - + while (E && E->Addr) { - if (S.compare(E->Addr) == 0) - return E->Addr; + if (S.compare(E->Addr) == 0) { + return E; + } E = E->Next; } - - // We cannot find an existing string for 'S'. Need to allocate - char *Addr = mPool->Alloc(S); - InsertEntry(Addr, BucketNo); - return Addr; -} + // We cannot find an existing string for 'S'. Need to allocate + char *addr = mPool->Alloc(S); + unsigned idx = mPool->mStringTable.size(); + mPool->mStringTable.push_back(addr); + E = InsertEntry(addr, idx, BucketNo); + return E; +} // Add a new entry in 'bucket'. // 'addr' is the address in the string pool -void StringMap::InsertEntry(char *addr, unsigned bucket) { +StringMapEntry *StringMap::InsertEntry(char *addr, unsigned idx, unsigned bucket) { StringMapEntry *E = &mBuckets[bucket]; while (E->Next) { E = E->Next; } - StringMapEntry *NewEnt = new StringMapEntry(addr); + StringMapEntry *NewEnt = new StringMapEntry(addr, idx); E->Next = NewEnt; + return NewEnt; } } diff --git a/src/MapleFE/shared/src/stringpool.cpp b/src/MapleFE/shared/src/stringpool.cpp index eb5d6b6861ee0531272edd233e1e58c55078ab9b..3b6e292486e4199e33c3347bc6bc941298d08b41 100644 --- a/src/MapleFE/shared/src/stringpool.cpp +++ b/src/MapleFE/shared/src/stringpool.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -20,10 +20,10 @@ #include #include +#include #include "stringpool.h" #include "stringmap.h" -#include "massert.h" namespace maplefe { @@ -32,9 +32,14 @@ namespace maplefe { StringPool gStringPool; StringPool::StringPool() { + mUseAltStr = false; mMap = new StringMap(); mMap->SetPool(this); mFirstAvail = -1; + // make string idx starting from 1 + mStringTable.push_back(""); + // empty string idx is 1 + mStringTable.push_back(""); } StringPool::~StringPool() { @@ -45,7 +50,16 @@ StringPool::~StringPool() { char *addr = block.Addr; free(addr); } - + mStringTable.clear(); + + // Release the long strings + std::vector::iterator long_it; + for (long_it = mLongStrings.begin(); long_it != mLongStrings.end(); long_it++) { + char *addr = *long_it; + free(addr); + } + mLongStrings.clear(); + // Release the StringMap delete mMap; } @@ -57,11 +71,14 @@ char* StringPool::Alloc(const std::string &s) { // 's' must guarantee to end with NULL char* StringPool::Alloc(const char *s) { size_t size = strlen(s) + 1; + char *addr = NULL; if (size > BLOCK_SIZE) { - MERROR ("Requsted size is bigger than block size"); + addr = (char*)malloc(size); + mLongStrings.push_back(addr); + } else { + addr = Alloc(size); } - char *addr = Alloc(size); MASSERT (addr && "StringPool failed to alloc for string"); strncpy(addr, s, size - 1); @@ -114,24 +131,151 @@ char* StringPool::AllocBlock() { } // This is the public interface to find a string in the pool. -// If not found, add it. +// If not found, allocate in the pool and save in the map. const char* StringPool::FindString(const std::string &s) { - return mMap->LookupAddrFor(s); + return mMap->LookupEntryFor(s)->GetAddr(); } // This is the public interface to find a string in the pool. -// If not found, add it. +// If not found, allocate in the pool and save in the map. const char* StringPool::FindString(const char *str) { std::string s(str); - return mMap->LookupAddrFor(s); + return mMap->LookupEntryFor(s)->GetAddr(); } // This is the public interface to find a string in the pool. -// If not found, add it. +// If not found, allocate in the pool and save in the map. const char* StringPool::FindString(const char *str, size_t len) { std::string s; s.assign(str, len); - return mMap->LookupAddrFor(s); + return mMap->LookupEntryFor(s)->GetAddr(); +} + +// This is the public interface to find a string in the pool. +// If not found, allocate in the pool and save in the map. +unsigned StringPool::GetStrIdx(const std::string &s) { + if (s.empty()) return 1; + return mMap->LookupEntryFor(s)->GetStrIdx(); +} + +// This is the public interface to find a string in the pool. +// If not found, allocate in the pool and save in the map. +unsigned StringPool::GetStrIdx(const char *str) { + if (strlen(str) == 0) return 1; + std::string s(str); + return mMap->LookupEntryFor(s)->GetStrIdx(); +} + +// This is the public interface to find a string in the pool. +// If not found, allocate in the pool and save in the map. +unsigned StringPool::GetStrIdx(const char *str, size_t len) { + if (len == 0) return 1; + std::string s; + s.assign(str, len); + return mMap->LookupEntryFor(s)->GetStrIdx(); +} + +const char *StringPool::GetStringFromStrIdx(unsigned idx) { + MASSERT(idx < mStringTable.size() && "string index out of range"); + if (mUseAltStr) { + if (mAltStrIdxMap.find(idx) != mAltStrIdxMap.end()) { + idx = mAltStrIdxMap[idx]; + } + } + return mStringTable[idx]; +} + +// This is the public interface to setup AltStrIdxMap used for obfuscation +// a name is mapped to a fixed length random unused name. +// starting from 2-letter names, [a-zA-Z] [a-zA-Z], which will cover over 2K names +// AA Aa AB Ab, ...., zz +// if not enough will extend to use 3-letter or 4-letter for over 7 million names +void StringPool::SetAltStrIdxMap() { + // starting from 2-letter names + unsigned len = 2; + bool done = false; + + // names use [A-Z] and [a-z] total 52 letters + int k = 52; + + // total number of names can be handled for len = 4, 3, 2, 1 respectively + int Size[4] = {k*k*k*k, k*k*k, k*k, k}; + + // names, trailing '\0' + char A[5] = {0, 0, 0, 0, 0}; + + // names already encounted, either existing name or new names + std::unordered_set used; + + for (auto stridx : mAltStrIdxSet) { + done = false; + while (!done) { + unsigned offset = 4 - len; + int mod = Size[offset]; + + int n = rand(); + int r = n % mod; + + // check if already encounted + if (used.find(r) != used.end()) { + // expand to use one more leter if close to limit + if (used.size() > mod - Size[offset + 1]) { + len++; + MASSERT(len < 5 && "Need more names"); + } + continue; + } + + // have un-encounted name + used.insert(r); + + int q; + bool odd; + int i = 0; + while (i < len - 1) { + mod = Size[offset + 1 + i]; + q = r / mod; + r = r % mod; + + // char, use upper case for odd number + odd = q%2; + A[i++] = (odd ? 'A' : 'a') + q/2; + } + + // last char, use upper case for odd number + odd = r%2; + A[i] = (odd ? 'A' : 'a') + r/2; + + unsigned size = GetSize(); + unsigned alt = GetStrIdx(A); + // make sure alt is a new string + if (alt == size) { + mAltStrIdxMap[stridx] = alt; + done = true; + } + } + } } + +void StringPool::Dump() { + std::cout << "===================== StringTable =====================" << std::endl; + for (unsigned idx = 1; idx < mStringTable.size(); idx++) { + std::cout << " " << idx << " : " << mStringTable[idx] << std::endl; + } +} + +void StringPool::DumpAlt() { + std::cout << "================= Alt String Map ======================" << std::endl; + unsigned count = 0; + for (auto stridx : mAltStrIdxSet) { + unsigned alt = mAltStrIdxMap[stridx]; + std::cout << "count #" << stridx + << " str " << GetStringFromStrIdx(stridx) + << " --> " + << " alt " << GetStringFromStrIdx(alt) + << std::endl; + } +} + } diff --git a/src/MapleFE/shared/src/stringutil.cpp b/src/MapleFE/shared/src/stringutil.cpp index a3d8a5163c4c2831d9cedcd050eab46ff44c4e5f..f524c99a65609df284a42e5d08f4485a56ea8297 100644 --- a/src/MapleFE/shared/src/stringutil.cpp +++ b/src/MapleFE/shared/src/stringutil.cpp @@ -175,42 +175,24 @@ Char StringToValue::StringToChar(std::string &str) { // When parser read it, it's just a plain text file. So it will see 6 characters actually. // The backslash is itself a character. // After parser read this string into buffer, you can see it in gdb is "test\\n". -// -// 4. StringToValue need convert the two characters into an escape character. -// This is what we are doing here. +// Lexer and Parser will keep what they saw. -const char* StringToValue::StringToString(std::string &str) { +const char* StringToValue::StringToString(std::string &in_str) { std::string target; - for (unsigned i = 0; i < str.size(); i++) { - char c = str[i]; - if ((c == '\\') && (i < str.size() - 1)) { - char c_next = str[i+1]; - char c_target = 0; - if (c_next == 'n') - c_target = '\n'; - else if (c_next == '\\') - c_target = '\\'; - else if (c_next == '\'') - c_target = '\''; - else if (c_next == '\"') - c_target = '\"'; - else if (c_next == 'b') - c_target = '\b'; - else if (c_next == 'f') - c_target = '\f'; - else if (c_next == 'r') - c_target = '\r'; - - if (c_target) { - target += c_target; - i++; - } - } else { - target += c; - } + + // For most languages, the input 'in_str' still contains the leading " or ' and the + // ending " or '. They need to be removed. + std::string str; + + // If empty string literal, return the empty 'target'. + if (in_str.size() == 2) { + const char *s = gStringPool.FindString(target); + return s; + } else { + str.assign(in_str, 1, in_str.size() - 2); } - const char *s = gStringPool.FindString(target); + const char *s = gStringPool.FindString(str); return s; } diff --git a/src/MapleFE/shared/src/token.cpp b/src/MapleFE/shared/src/token.cpp index 38141cea10e3ae09302063c6687fa4ff97b742d3..39b20a15fe084e9007cf60667d4b3233f7e86ce6 100644 --- a/src/MapleFE/shared/src/token.cpp +++ b/src/MapleFE/shared/src/token.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -13,8 +13,13 @@ * See the Mulan PSL v2 for more details. */ #include "token.h" +#include "stringpool.h" +#include "rule_summary.h" #include "massert.h" +#include +#include + namespace maplefe { #undef SEPARATOR @@ -29,7 +34,7 @@ const char* SeparatorTokenGetName(SepId id) { void SeparatorTokenDump(SepId id) { const char *name = SeparatorTokenGetName(id); - DUMP1("Separator Token: ", name); + DUMP1_NORETURN("Separator Token: ", name); return; } @@ -45,34 +50,34 @@ const char* OperatorTokenGetName(OprId id) { void OperatorTokenDump(OprId id) { const char *name = OperatorTokenGetName(id); - DUMP1("Operator Token: ", name); + DUMP1_NORETURN("Operator Token: ", name); return; } void LiteralTokenDump(LitData data) { switch (data.mType) { case LT_IntegerLiteral: - DUMP1("Integer Literal Token:", data.mData.mInt); + DUMP1_NORETURN("Integer Literal Token:", data.mData.mInt); break; case LT_FPLiteral: - DUMP1("Floating Literal Token:", data.mData.mFloat); + DUMP1_NORETURN("Floating Literal Token:", data.mData.mFloat); break; case LT_DoubleLiteral: - DUMP1("Double Literal Token:", data.mData.mDouble); + DUMP1_NORETURN("Double Literal Token:", data.mData.mDouble); break; case LT_BooleanLiteral: - DUMP1("Boolean Literal Token:", data.mData.mBool); + DUMP1_NORETURN("Boolean Literal Token:", data.mData.mBool); break; case LT_CharacterLiteral: { Char the_char = data.mData.mChar; if (the_char.mIsUnicode) - DUMP1("Char Literal Token(Unicode):", the_char.mData.mUniValue); + DUMP1_NORETURN("Char Literal Token(Unicode):", the_char.mData.mUniValue); else - DUMP1("Char Literal Token:", the_char.mData.mChar); + DUMP1_NORETURN("Char Literal Token:", the_char.mData.mChar); break; } case LT_StringLiteral: - DUMP1("String Literal Token:", data.mData.mStr); + DUMP1_NORETURN("String Literal Token:", gStringPool.GetStringFromStrIdx(data.mData.mStrIdx)); break; case LT_NullLiteral: DUMP0("Null Literal Token:"); @@ -104,19 +109,128 @@ void Token::Dump() { OperatorTokenDump(mData.mOprId); break; case TT_ID: - DUMP1("Identifier Token: ", mData.mName); + DUMP1_NORETURN("Identifier Token: ", mData.mName); break; case TT_KW: - DUMP1("Keyword Token: ", mData.mName); + DUMP1_NORETURN("Keyword Token: ", mData.mName); break; case TT_CM: DUMP0("Comment Token: "); break; + case TT_TL: + DUMP0("TemplateLiteral Token: "); + break; + case TT_RE: + DUMP1_NORETURN("RegExpr Token: ", mData.mRegExprData.mExpr); + if (mData.mRegExprData.mFlags) + DUMP1_NORETURN(" : ", mData.mRegExprData.mFlags); + break; case TT_LT: LiteralTokenDump(mData.mLitData); break; default: break; } + + DUMP1_NORETURN(" line: ", mLineNum); + DUMP1_NORETURN(" col: ", mColNum); + if (mLineBegin) + DUMP0_NORETURN(" line-first "); + if (mLineEnd) + DUMP0_NORETURN(" line-last "); + DUMP_RETURN(); } + +bool Token::Equal(Token *t) { + bool equal = false; + switch (mTkType) { + case TT_SP: + if (t->mTkType == TT_SP && + GetSepId() == t->GetSepId()) + equal = true; + break; + case TT_OP: + if (t->mTkType == TT_OP && + GetOprId() == t->GetOprId()) + equal = true; + break; + case TT_KW: + if (t->mTkType == TT_KW && + GetName() == t->GetName()) + equal = true; + break; + case TT_ID: + case TT_CM: + case TT_TL: + case TT_RE: + case TT_LT: + default: + break; + } + + return equal; +} + +/////////////////////////////////////////////////////////////////////////// +// Utilities for finding system tokens +// Remember the order of tokens are operators, separators, and keywords. +/////////////////////////////////////////////////////////////////////////// + +Token* FindOperatorToken(OprId id) { + Token *token = NULL; + bool found = false; + for (unsigned i = 0; i < gOperatorTokensNum; i++) { + token = &gSystemTokens[i]; + MASSERT(token->mTkType == TT_OP); + if (token->GetOprId() == id) { + found = true; + break; + } + } + MASSERT(found && token); + return token; +} + +Token* FindSeparatorToken(SepId id) { + Token *token = NULL; + bool found = false; + for (unsigned i = gOperatorTokensNum; i < gOperatorTokensNum + gSeparatorTokensNum; i++) { + token = &gSystemTokens[i]; + MASSERT(token->mTkType == TT_SP); + if (token->GetSepId() == id) { + found = true; + break; + } + } + MASSERT(found && token); + return token; +} + +// The caller of this function makes sure 'key' is already in the +// string pool of Lexer. +Token* FindKeywordToken(const char *key) { + Token *token = NULL; + bool found = false; + for (unsigned i = gOperatorTokensNum + gSeparatorTokensNum; + i < gOperatorTokensNum + gSeparatorTokensNum + gKeywordTokensNum; + i++) { + token = &gSystemTokens[i]; + MASSERT(token->mTkType == TT_KW); + if (strlen(key) == strlen(token->GetName()) && + !strncmp(key, token->GetName(), strlen(key))) { + found = true; + break; + } + } + MASSERT(found && token); + return token; +} + +// CommentToken is the last predefined token +Token* FindCommentToken() { + Token *token = &gSystemTokens[gSystemTokensNum - 1]; + MASSERT((token->mTkType == TT_CM) && "Last system token is not a comment token."); + return token; +} + } diff --git a/src/MapleFE/shared/src/tokenpool.cpp b/src/MapleFE/shared/src/tokenpool.cpp index 263e76a03ccf5e313500e6e5c9ca953c041fc817..89dfde73e94772499496049360b155e912cb9b3a 100644 --- a/src/MapleFE/shared/src/tokenpool.cpp +++ b/src/MapleFE/shared/src/tokenpool.cpp @@ -23,8 +23,15 @@ char* TokenPool::NewToken(unsigned size) { char *addr = mMemPool.Alloc(size); MASSERT(addr && "MemPool failed to alloc a token."); Token *token = (Token*)addr; + token->mAltTokens = NULL; + token->mLineNum = 0; + token->mColNum = 0; + token->mLineBegin = false; + token->mLineEnd = false; + mTokens.PushBack((Token*)addr); return addr; } + } diff --git a/src/MapleFE/shared/src/typetable.cpp b/src/MapleFE/shared/src/typetable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a1d8a93e96c53f2c8636eafbdebf5d22e352a57 --- /dev/null +++ b/src/MapleFE/shared/src/typetable.cpp @@ -0,0 +1,204 @@ +/* +* Copyright (C) [2021-2022] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ +////////////////////////////////////////////////////////////////////////////// +// // +// This file contains the implementation of string pool. // +// // +////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "typetable.h" +#include "gen_astdump.h" + +namespace maplefe { + +TypeTable gTypeTable; + +TypeEntry::TypeEntry(TreeNode *node) { + mType = node; + if (!node->IsTypeIdNone()) { + mTypeId = node->GetTypeId(); + } else { + switch (node->GetKind()) { + case NK_Struct: + case NK_StructLiteral: + case NK_Class: + case NK_Interface: + mTypeId = TY_Class; + break; + case NK_ArrayLiteral: + mTypeId = TY_Array; + break; + case NK_UserType: + mTypeId = TY_User; + break; + default: + mTypeId = TY_None; + break; + } + } +} + +TreeNode *TypeTable::CreatePrimType(std::string name, TypeId tid) { + unsigned stridx = gStringPool.GetStrIdx(name); + PrimTypeNode *ptype = (PrimTypeNode*)gTreePool.NewTreeNode(sizeof(PrimTypeNode)); + new (ptype) PrimTypeNode(); + ptype->SetStrIdx(stridx); + ptype->SetPrimType(tid); + ptype->SetTypeId(tid); + + mTypeId2TypeMap[tid] = ptype; + return ptype; +} + +TreeNode *TypeTable::CreateBuiltinType(std::string name, TypeId tid) { + unsigned stridx = gStringPool.GetStrIdx(name); + IdentifierNode *id = (IdentifierNode*)gTreePool.NewTreeNode(sizeof(IdentifierNode)); + new (id) IdentifierNode(stridx); + // use TY_Class for Object type + (tid == TY_Object) ? id->SetTypeId(TY_Class) : id->SetTypeId(tid); + + UserTypeNode *utype = (UserTypeNode*)gTreePool.NewTreeNode(sizeof(UserTypeNode)); + new (utype) UserTypeNode(id); + utype->SetStrIdx(stridx); + utype->SetTypeId(TY_Class); + id->SetParent(utype); + + mTypeId2TypeMap[tid] = utype; + return utype; +} + +bool TypeTable::AddType(TreeNode *node) { + unsigned nid = node->GetNodeId(); + if (mNodeId2TypeIdxMap.find(nid) != mNodeId2TypeIdxMap.end()) { + return false; + } + unsigned tidx = mTypeTable.size(); + mNodeId2TypeIdxMap[nid] = tidx; + node->SetTypeIdx(tidx); + if (node->IsUserType()) { + static_cast(node)->GetId()->SetTypeIdx(tidx); + } + TypeEntry *entry = new TypeEntry(node); + mTypeTable.push_back(entry); + return true; +} + +void TypeTable::AddPrimTypeId(TypeId tid) { + mPrimTypeId.insert(tid); +} + +#undef TYPE +#undef PRIMTYPE +void TypeTable::AddPrimAndBuiltinTypes() { + // only initialize once + if (mTypeTable.size() != 0) { + return; + } + + TreeNode *node; + // add a NULL entry so real typeidx starting from 1 + TypeEntry *entry = new TypeEntry(); + mTypeTable.push_back(entry); + + // first are primitive types, and their typeid TY_Xyz is their typeidx as well +#define TYPE(T) +#define PRIMTYPE(T) node = CreatePrimType(#T, TY_##T); AddType(node); AddPrimTypeId(TY_##T); +#include "supported_types.def" + // add additional primitive types for number and string + PRIMTYPE(Number); + PRIMTYPE(String); + + mPrimSize = size(); + +#define TYPE(T) node = CreateBuiltinType(#T, TY_##T); AddType(node); +#define PRIMTYPE(T) + // additional usertype Boolean + TYPE(Boolean); +#include "supported_types.def" + + mPreBuildSize = size(); + return; +} + +TypeEntry *TypeTable::GetTypeEntryFromTypeIdx(unsigned tidx) { + MASSERT(tidx < mTypeTable.size() && "type index out of range"); + return mTypeTable[tidx]; +} + +TreeNode *TypeTable::GetTypeFromTypeIdx(unsigned tidx) { + MASSERT(tidx < mTypeTable.size() && "type index out of range"); + return mTypeTable[tidx]->GetType(); +} + +TreeNode *TypeTable::GetTypeFromStrIdx(unsigned stridx) { + for (auto entry : mTypeTable) { + TreeNode *node = entry->GetType(); + if (node && node->GetStrIdx() == stridx) { + return node; + } + } + return NULL; +} + +unsigned TypeTable::GetOrCreateFunctionTypeIdx(FunctionTypeNode *node) { + for (auto tidx: mFuncTypeIdx) { + TreeNode *type = GetTypeFromTypeIdx(tidx); + FunctionTypeNode *functype = static_cast(type); + bool found = functype->IsEqual(node); + if (found) { + return tidx; + } + } + bool status = AddType(node); + MASSERT(status && "failed to add a functiontype"); + unsigned tidx = node->GetTypeIdx(); + mFuncTypeIdx.insert(tidx); + + std::string str("FuncType__"); + str += std::to_string(tidx); + unsigned stridx = gStringPool.GetStrIdx(str); + node->SetStrIdx(stridx); + + return tidx; +} + +void TypeTable::Dump() { + std::cout << "===================== TypeTable =====================" << std::endl; + std::cout << " tid:type-name: node-kind node-id" << std::endl; + std::cout << "--------------------------------" << std::endl; + unsigned idx = 1; + for (unsigned idx = 1; idx < mTypeTable.size(); idx++) { + TypeEntry *entry = mTypeTable[idx]; + TreeNode *node = entry->GetType(); + TypeId tid = node->GetTypeId(); + if (node->IsUserType()) { + tid = static_cast(node)->GetId()->GetTypeId(); + } + std::cout << " " << idx << " : " << node->GetName() << " : " << + AstDump::GetEnumNodeKind(node->GetKind()) << " " << + AstDump::GetEnumTypeId(tid) << " " << + "(typeid " << tid << ") " << + "(typeidx " << node->GetTypeIdx() << ") " << + "(stridx " << node->GetStrIdx() << ") " << + "(nodeid " << node->GetNodeId() << ")" << std::endl; + } + std::cout << "===================== End TypeTable =====================" << std::endl; +} + +} + diff --git a/src/MapleFE/shared/src/vfy.cpp b/src/MapleFE/shared/src/vfy.cpp index 7ed154992ed6d9486fc6c2539eae18270ac22165..07809d0f89ed58d2191117ee254c9fe0ca949449 100644 --- a/src/MapleFE/shared/src/vfy.cpp +++ b/src/MapleFE/shared/src/vfy.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2020-2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -31,7 +31,7 @@ namespace maplefe { // resursive process. /////////////////////////////////////////////////////////////////////////////// -Verifier::Verifier() { +Verifier::Verifier(ModuleNode *m) : mASTModule(m) { mCurrScope = NULL; mTempParent = NULL; } @@ -52,11 +52,9 @@ void Verifier::Do() { // see java/vfy_java.cpp. void Verifier::VerifyGlobalScope() { - mCurrScope = gModule.mRootScope; - std::vector::iterator tree_it = gModule.mTrees.begin(); - for (; tree_it != gModule.mTrees.end(); tree_it++) { - ASTTree *asttree = *tree_it; - TreeNode *tree = asttree->mRootNode; + mCurrScope = mASTModule->mRootScope; + for (unsigned i = 0; i < mASTModule->GetTreesNum(); i++) { + TreeNode *tree = mASTModule->GetTree(i); // Step 1. Try to add decl. mCurrScope->TryAddDecl(tree); // Step 2. Try to add type. @@ -87,7 +85,7 @@ void Verifier::CollectAllDeclsTypes(ASTScope *scope) { // All fields, methods, local classes, local interfaces are decls. // All local classes/interfaces are types. for (unsigned i = 0; i < klass->GetFieldsNum(); i++) { - IdentifierNode *in = klass->GetField(i); + TreeNode *in = klass->GetField(i); scope->AddDecl(in); } for (unsigned i = 0; i < klass->GetMethodsNum(); i++) { @@ -119,7 +117,7 @@ void Verifier::VerifyIdentifier(IdentifierNode *inode) { ASTScope *scope = mCurrScope; IdentifierNode *decl = NULL; while (scope) { - if (decl = (IdentifierNode*) scope->FindDeclOf(inode)) + if ((decl = (IdentifierNode*) scope->FindDeclOf(inode->GetStrIdx()))) break; scope = scope->GetParent(); } @@ -127,18 +125,24 @@ void Verifier::VerifyIdentifier(IdentifierNode *inode) { if (!decl) { mLog.MissDecl(inode); } else { - // Replace the temp IdentifierNode with the found Decl. - // Sometimes inode and decl are the same, which happens for the declaration statement. - // We will verify decl statement as the others, so its inode is the same as decl. - if (inode != decl) { - // TODO : There are many complicated cases which we will handle in the furture. - // Right now I just put a simple check of mTempParent. - if (mTempParent) - mTempParent->ReplaceChild(inode, decl); - } + // We disabled this part to keep the integerity of TREE. We don't want + // a graph. + // + // // Replace the temp IdentifierNode with the found Decl. + // // Sometimes inode and decl are the same, which happens for the declaration statement. + // // We will verify decl statement as the others, so its inode is the same as decl. + // if (inode != decl) { + // // TODO : There are many complicated cases which we will handle in the furture. + // // Right now I just put a simple check of mTempParent. + // if (mTempParent) + // mTempParent->ReplaceChild(inode, decl); + // } } } +void Verifier::VerifyDecl(DeclNode *tree){ +} + void Verifier::VerifyDimension(DimensionNode *tree){ } @@ -160,8 +164,8 @@ void Verifier::VerifyPrimArrayType(PrimArrayTypeNode *tree){ void Verifier::VerifyVarList(VarListNode *vlnode){ TreeNode *old_temp_parent = mTempParent; mTempParent = vlnode; - for (unsigned i = 0; i < vlnode->GetNum(); i++) { - IdentifierNode *n = vlnode->VarAtIndex(i); + for (unsigned i = 0; i < vlnode->GetVarsNum(); i++) { + IdentifierNode *n = vlnode->GetVarAtIndex(i); VerifyIdentifier(n); } mTempParent = old_temp_parent; @@ -172,14 +176,22 @@ void Verifier::VerifyLiteral(LiteralNode *tree){ return; } +void Verifier::VerifyTemplateLiteral(TemplateLiteralNode *tree){ + return; +} + +void Verifier::VerifyRegExpr(RegExprNode *tree){ + return; +} + void Verifier::VerifyUnaOperator(UnaOperatorNode *tree){ } void Verifier::VerifyBinOperator(BinOperatorNode *binop){ TreeNode *old_temp_parent = mTempParent; mTempParent = binop; - VerifyTree(binop->mOpndA); - VerifyTree(binop->mOpndB); + VerifyTree(binop->GetOpndA()); + VerifyTree(binop->GetOpndB()); mTempParent = old_temp_parent; } @@ -187,7 +199,7 @@ void Verifier::VerifyTerOperator(TerOperatorNode *tree){ } void Verifier::VerifyBlock(BlockNode *block){ - mCurrScope = gModule.NewScope(mCurrScope); + mCurrScope = mASTModule->NewScope(mCurrScope); mCurrScope->SetTree(block); for (unsigned i = 0; i < block->GetChildrenNum(); i++) { @@ -204,7 +216,7 @@ void Verifier::VerifyBlock(BlockNode *block){ // Function body's block is different than a pure BlockNode. void Verifier::VerifyFunction(FunctionNode *func){ ASTScope *old_scope = mCurrScope; - mCurrScope = gModule.NewScope(mCurrScope); + mCurrScope = mASTModule->NewScope(mCurrScope); mCurrScope->SetTree(func); // Add the parameters to the decl. Since we search for the decl of a var from @@ -241,11 +253,11 @@ void Verifier::VerifyFunction(FunctionNode *func){ void Verifier::VerifyClassFields(ClassNode *klass) { // rule 1. No duplicated fields name with another decls. for (unsigned i = 0; i < klass->GetFieldsNum(); i++) { - IdentifierNode *na = klass->GetField(i); + TreeNode *na = klass->GetField(i); bool hit_self = false; for (unsigned j = 0; j < mCurrScope->GetDeclNum(); j++) { TreeNode *nb = mCurrScope->GetDecl(j); - if (na->GetName() == nb->GetName()) { + if (na->GetStrIdx() == nb->GetStrIdx()) { if (nb->IsIdentifier()) { if (!hit_self) hit_self = true; @@ -265,7 +277,7 @@ void Verifier::VerifyClassSuperInterfaces(ClassNode *klass) {} void Verifier::VerifyClass(ClassNode *klass){ // Step 1. Create a new scope - ASTScope *scope = gModule.NewScope(mCurrScope); + ASTScope *scope = mASTModule->NewScope(mCurrScope); mCurrScope = scope; scope->SetTree(klass); @@ -293,18 +305,36 @@ void Verifier::VerifyAnnotationType(AnnotationTypeNode *tree){ void Verifier::VerifyAnnotation(AnnotationNode *tree){ } +void Verifier::VerifyThrow(ThrowNode *tree){ +} + +void Verifier::VerifyTry(TryNode *tree){ +} + +void Verifier::VerifyCatch(CatchNode *tree){ +} + +void Verifier::VerifyFinally(FinallyNode *tree){ +} + void Verifier::VerifyException(ExceptionNode *tree){ } void Verifier::VerifyReturn(ReturnNode *tree){ } +void Verifier::VerifyYield(YieldNode *tree){ +} + void Verifier::VerifyCondBranch(CondBranchNode *tree){ } void Verifier::VerifyBreak(BreakNode *tree){ } +void Verifier::VerifyContinue(ContinueNode *tree){ +} + void Verifier::VerifyForLoop(ForLoopNode *tree){ } @@ -320,7 +350,7 @@ void Verifier::VerifyType(IdentifierNode *inode) { ASTScope *scope = mCurrScope; TreeNode *type = NULL; while (scope) { - if (type = scope->FindTypeOf(inode)) + if ((type = scope->FindTypeOf(inode->GetStrIdx()))) break; scope = scope->GetParent(); } @@ -356,8 +386,8 @@ void Verifier::VerifyNew(NewNode *new_node){ VerifyType(inode); // verify parameters. // A parameter could be any type. We have to verify type by type. - for (unsigned i = 0; i < new_node->GetParamsNum(); i++) { - TreeNode *p = new_node->GetParam(i); + for (unsigned i = 0; i < new_node->GetArgsNum(); i++) { + TreeNode *p = new_node->GetArg(i); if(p->IsIdentifier()) { IdentifierNode *inode = (IdentifierNode*)p; VerifyIdentifier(inode); @@ -386,6 +416,10 @@ void Verifier::VerifyExprList(ExprListNode *tree){ return; } +void Verifier::VerifyNamespace(NamespaceNode *tree){ + return; +} + void Verifier::VerifyCall(CallNode *tree){ return; } @@ -406,14 +440,30 @@ void Verifier::VerifyParenthesis(ParenthesisNode *tree){ return; } +void Verifier::VerifyModule(ModuleNode *tree){ + return; +} + void Verifier::VerifyPackage(PackageNode *tree){ return; } +void Verifier::VerifyDeclare(DeclareNode *tree){ + return; +} + void Verifier::VerifyImport(ImportNode *tree){ return; } +void Verifier::VerifyExport(ExportNode *tree){ + return; +} + +void Verifier::VerifyXXportAsPair(XXportAsPairNode *tree){ + return; +} + void Verifier::VerifyUserType(UserTypeNode *tree){ return; } @@ -421,4 +471,109 @@ void Verifier::VerifyUserType(UserTypeNode *tree){ void Verifier::VerifyLambda(LambdaNode *tree){ return; } + +void Verifier::VerifyInstanceOf(InstanceOfNode *tree){ + return; +} + +void Verifier::VerifyIn(InNode *tree){ + return; +} + +void Verifier::VerifyComputedName(ComputedNameNode *tree){ + return; +} + +void Verifier::VerifyIs(IsNode *tree){ + return; +} + +void Verifier::VerifyAwait(AwaitNode *tree){ + return; +} + +void Verifier::VerifyTypeOf(TypeOfNode *tree){ + return; +} + +void Verifier::VerifyTypeAlias(TypeAliasNode *tree){ + return; +} + +void Verifier::VerifyAsType(AsTypeNode *tree){ + return; +} + +void Verifier::VerifyConditionalType(ConditionalTypeNode *tree){ + return; +} + +void Verifier::VerifyTypeParameter(TypeParameterNode *tree){ + return; +} + +void Verifier::VerifyKeyOf(KeyOfNode *tree){ + return; +} + +void Verifier::VerifyInfer(InferNode *tree){ + return; +} + +void Verifier::VerifyArrayElement(ArrayElementNode *tree){ + return; +} + +void Verifier::VerifyArrayLiteral(ArrayLiteralNode *tree){ + return; +} + +void Verifier::VerifyNumIndexSig(NumIndexSigNode *tree){ + return; +} + +void Verifier::VerifyStrIndexSig(StrIndexSigNode *tree){ + return; +} + +void Verifier::VerifyStruct(StructNode *tree){ + return; +} + +void Verifier::VerifyNameTypePair(NameTypePairNode *tree){ + return; +} + +void Verifier::VerifyTupleType(TupleTypeNode *tree){ + return; +} + +void Verifier::VerifyBindingElement(BindingElementNode *tree){ + return; +} + +void Verifier::VerifyBindingPattern(BindingPatternNode *tree){ + return; +} + +void Verifier::VerifyStructLiteral(StructLiteralNode *tree){ + return; +} + +void Verifier::VerifyFieldLiteral(FieldLiteralNode *tree){ + return; +} + +void Verifier::VerifyArrayType(ArrayTypeNode *tree){ + return; +} + +void Verifier::VerifyTripleSlash(TripleSlashNode *tree){ + return; +} + +void Verifier::VerifyFunctionType(FunctionTypeNode *tree){ + return; +} + } diff --git a/src/MapleFE/test/Makefile b/src/MapleFE/test/Makefile index 09a42a4e3387428f41744a5e252a469072150699..aed83f9c0ad98a99312e7e2785030cbc13cd311a 100644 --- a/src/MapleFE/test/Makefile +++ b/src/MapleFE/test/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# Copyright (C) [2020-2021] Futurewei Technologies, Inc. All rights reverved. # # OpenArkFE is licensed under the Mulan PSL v2. # You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -15,74 +15,104 @@ # for testing batch1/Arithmetic/Add.java: # make Add -build = ../output/test +build = ../output/$(SRCLANG)/test $(shell mkdir -p $(build)) -DIR = . $(wildcard * */* */*/*) +ifeq ($(SRCLANG),java) + FLAGS := --trace-a2m +else ifeq ($(SRCLANG),typescript) + FLAGS1 := --trace-lexer + FLAGS2 := --trace=3 --format-cpp +endif -vpath %.java $(DIR) -vpath %.mpl $(DIR) -vpath %.c $(DIR) -vpath %.cpp $(DIR) +DIRS := . $(shell find $(SRCLANG) -type d) -all: test +vpath %.java $(DIRS) +vpath %.ts $(DIRS) +vpath %.mpl $(DIRS) +vpath %.c $(DIRS) +vpath %.cpp $(DIRS) -autogen: - make -C ../autogen +.PHONY: $(SRCLANG) +.PHONY: mssetup -shared: autogen test - make -C ../shared +$(SRCLANG): + env LANG=en_US.UTF-8 ./new_runtests.pl $(SRCLANG) full: - make -C .. - -clean: - make -C .. clean - -clobber: - make -C .. clobber + make -C .. -j8 rebuild: - make -C .. rebuild + make -C .. rebuild -j8 -tt: - ../output/java/java2mpl tt.java --trace-a2m - @echo "\n======================== tt.mpl ========================" - @cat tt.mpl - @echo "========================================================\n" - ../../mapleall/bin/aarch64-clang-debug/irbuild tt.mpl - ../../mapleall/bin/aarch64-clang-debug/irbuild tt.irb.mpl - diff -uwb tt.irb.mpl tt.irb.irb.mpl +clean: + rm -rf $(build) + +clobber: clean dbg: - gdb --args ../output/java/java2mpl tt.java --trace-a2m + gdb --args ../output/java/java/java2mpl test.java $(FLAGS) + +ifeq ($(SRCLANG),java) -# only run autogen for now -test: - ./runtests.pl all +mssetup: % : %.java @cp $< $(build) - @echo gdb --args ../output/java/java2mpl $(build)/$@.java --trace-a2m - ../output/java/java2mpl $(build)/$@.java --trace-a2m + @echo gdb --args ../output/java/bin/java2ast $(build)/$@.java $(FLAGS1) + @echo gdb --args ../output/java/bin/ast2mpl $(build)/$@.java.ast $(FLAGS2) + ../output/java/bin/java2ast $(build)/$@.java $(FLAGS1) + ../output/java/bin/ast2mpl $(build)/$@.java.ast $(FLAGS2) + @echo "\n======================= $@.java =========================" + @cat -n $(build)/$@.java + @echo "========================================================\n" + @echo gdb --args ../output/java/bin/java2ast $(build)/$@.java $(FLAGS1) + @echo gdb --args ../output/java/bin/ast2mpl $(build)/$@.java.ast $(FLAGS2) @echo "\n======================= $@.mpl =========================" - @cat $(build)/$@.mpl + @cat -n $(build)/$@.mpl @echo "========================================================\n" - ../../mapleall/bin/aarch64-clang-debug/irbuild $(build)/$@.mpl - ../../mapleall/bin/aarch64-clang-debug/irbuild $(build)/$@.irb.mpl + @echo gdb --args ../output/java/bin/java2ast $(build)/$@.java $(FLAGS1) + @echo gdb --args ../output/java/bin/ast2mpl $(build)/$@.java.ast $(FLAGS2) + @cat -n $(build)/$@.mpl + @echo "========================================================\n" + @echo gdb --args ../output/java/java/java2mpl $(build)/$@.java $(FLAGS) + $(MAPLEALL_ROOT)/output/aarch64-clang-debug/bin/irbuild $(build)/$@.mpl + $(MAPLEALL_ROOT)/output/aarch64-clang-debug/bin/irbuild $(build)/$@.irb.mpl diff -uwb $(build)/$@.irb.mpl $(build)/$@.irb.irb.mpl - @echo gdb --args ../output/java/java2mpl $(build)/$@.java --trace-a2m - -% : %.c - cp $< $(build) - @echo "\ngdb command:\n(cd $(BUILDDIR)/autogen/; gdb -args ./sharedfe -verbose=3 ../../test/$(build)/$<)" - (cd $(BUILDDIR)/autogen; ./sharedfe -verbose=3 ../../test/$(build)/$<) - @echo "\ncommand:\n(cd $(BUILDDIR)/autogen/; ./sharedfe ../../test/$(build)/$<)" - @echo "\ngdb command:\n(cd $(BUILDDIR)/autogen/; gdb -args ./sharedfe -verbose=3 ../../test/$(build)/$<)" - -% : %.cpp - cp $< $(build) - @echo "\ngdb command:\n(cd $(BUILDDIR)/autogen/; gdb -args ./sharedfe -verbose=3 ../../test/$(build)/$<)" - (cd $(BUILDDIR)/autogen; ./sharedfe -verbose=3 ../../test/$(build)/$<) - @echo "\ncommand:\n(cd $(BUILDDIR)/autogen/; ./sharedfe ../../test/$(build)/$<)" - @echo "\ngdb command:\n(cd $(BUILDDIR)/autogen/; gdb -args ./sharedfe -verbose=3 ../../test/$(build)/$<)" + +else ifeq ($(SRCLANG),typescript) + +mssetup: + ./msts_test.sh setup + +testms: + ./msts_test.sh + +testmslocal: mssetup + env LANG=en_US.UTF-8 ./new_runtests.pl typescript TypeScript/tests/cases/compiler + +unit: + env LANG=en_US.UTF-8 ./new_runtests.pl typescript typescript/unit_tests + +ms: mssetup + env LANG=en_US.UTF-8 ./new_runtests.pl typescript typescript/ms_tests + +% : %.ts + @cp $< $(build) + @echo gdb --args ../output/typescript/bin/ts2ast $(build)/$@.ts $(FLAGS1) + @echo gdb --args ../output/typescript/bin/ast2cpp $(build)/$@.ts.ast $(FLAGS2) + ../output/typescript/bin/ts2ast $(build)/$@.ts $(FLAGS1) + ../output/typescript/bin/ast2cpp $(build)/$@.ts.ast $(FLAGS2) + @echo "\n======================= $@.ts =========================" + @cat -n $(build)/$@.ts + @echo "========================================================\n" + @echo gdb --args ../output/typescript/bin/ts2ast $(build)/$@.ts $(FLAGS1) + @echo gdb --args ../output/typescript/bin/ast2cpp $(build)/$@.ts.ast $(FLAGS2) + @echo "\n======================= $@.h =========================" + @cat -n $(build)/$@.h + @echo "\n======================= $@.cpp =========================" + @cat -n $(build)/$@.cpp + @echo "========================================================\n" + @echo gdb --args ../output/typescript/bin/ts2ast $(build)/$@.ts $(FLAGS1) + @echo gdb --args ../output/typescript/bin/ast2cpp $(build)/$@.ts.ast $(FLAGS2) +endif diff --git a/src/MapleFE/test/README b/src/MapleFE/test/README index a46d226caf1805245765cf35d1efdf3efde933be..cdbdaa9af05a75e1b81b517a346e09daf8ea2618 100644 --- a/src/MapleFE/test/README +++ b/src/MapleFE/test/README @@ -1,10 +1,43 @@ This directory contains the test framework and test cases. -The test cases are in 3 directories. -1. java2mpl - This is for the Java test cases. They are correct code. -2. errtest - This is for the Java test cases. They are incorrect code. -3. others - This is for the Java test cases. They are taken from 3rd party open source projects, - in order to have a complete coverage of the testing. If you want to reuse the code - please read the LICENSE carefully. + +Directories: +./java +./java/syntaxonly Test cases for syntax check +./java/others Other Java test cases from third-party open source projects. Included the LICENSE for them. +./java/java2mpl Java test cases for java2mpl +./java/openjdk Java test cases +./java/errtest Negative test cases + +./typescript +./typescript/ms_tests TypeScript official test cases. Included the LICENSE for them. +./typescript/unit_tests Unit test cases + +To run TypeScript tests: + 1. source envsetup typescript; cd $MAPLEFE_ROOT/test + 2. Run both unit_tests and ms_tests: + make + Run just unit_tests + make unit + Run just ms_tests + make ms + Run specific typescript test + make + * Tests should be run using make instead of using the .pl scripts directly. + +Tool to dump AST and CFG of a TypeScript test case: + + Usage: astdump.sh [-dot] [-f|--fullscreen] [-p |--pre ] [-a|--ast] [-c|--cfg] [ ...] + + -d | --dot Use Graphviz dot to generate the graph and view it with viewnior + -f | --fullscreen View the generated graph in fullscreen mode. It implies option -dot + -p | --pre Filter graphs with the specified , e.g. -p "CFG_" + -a | --ast Show AST graph. It is equivalent to options "-dot -p AST" + -c | --cfg Show CFG graph. It is equivalent to options "-dot -p CFG" + -h | --help Display usage information + -s | --syntax Syntax highlighting the generated TypeScript code + [ ...] Specify one or more TypeScript files to be processed + +Examples: + cd MapleFE/test/typescript/unit_tests + ../../astdump.sh -a binary-search.ts # Show AST graph + ../../astdump.sh binary-search.ts -c # Show CFG graph diff --git a/src/MapleFE/test/astdump.sh b/src/MapleFE/test/astdump.sh new file mode 100755 index 0000000000000000000000000000000000000000..2260c58f95c703efdf91b6bb871d883f67219a3f --- /dev/null +++ b/src/MapleFE/test/astdump.sh @@ -0,0 +1,209 @@ +#!/bin/bash +function usage { +cat << EOF + +Usage: astdump.sh [-d] [-f] [-p ] [-a] [-c] [-k] [-A] [-C] [-n] [-t|-T] [ ...] + +Short/long options: + -d | --dot Use Graphviz dot to generate the graph and view it with viewnior + -f | --fullscreen View the generated graph in fullscreen mode. It implies option -dot + -p | --pre Filter graphs with the specified , e.g. -p "CFG_" + -a | --ast Show AST graph. It is equivalent to options "-d -p AST" + -c | --cfg Show CFG graph. It is equivalent to options "-d -p CFG" + -s | --syntax Syntax highlighting the generated TypeScript code + -k | --keep Keep generated files *.ts-[0-9]*.out.ts which fail to compile with tsc + -A | --all Process all .ts files in current directory excluding *.ts-[0-9]*.out.ts + -C | --clean Clean up generated files (*.ts-[0-9]*.out.ts) + -n | --name Keep original names by removing "__v[0-9]*" from generated code + -t | --treediff Compare the AST of generated TS code with the one of original TS code + -T | --Treediff Same as -t/--treediff except that it disables tsc for generated TS code + -i | --ignore-imported Ignore all imported modules + [ ...] Specify one or more TypeScript files to be processed +EOF +exit 1 +} +CMDLINE="$0 $*" +GITTS=$(git ls-files "*.ts") +DOT= PRE= LIST= VIEWOP= HIGHLIGHT="cat" TSCERR= KEEP= CLEAN= NAME= TREEDIFF= TSC=yes NOIMPORTED= +while [ $# -gt 0 ]; do + case $1 in + -d|--dot) DOT=dot;; + -f|--fullscreen) VIEWOP="--fullscreen"; DOT=fullscreen;; + -p|--pre) [ $# -ge 2 ] && { PRE="$2"; shift; } || { echo "$1 needs an argument"; exit 1; } ;; + -a|--ast) PRE="AST" ; DOT=ast ; TSCERR=">& /dev/null" ;; + -c|--cfg) PRE="CFG" ; DOT=cfg ; TSCERR=">& /dev/null" ;; + -s|--syntax) HIGHLIGHT="highlight -O xterm256 --syntax ts" ;; + -e|--tscerror) TSCERR= ;; + -k|--keep) KEEP=keep ;; + -C|--clean) CLEAN=clean ;; + -A|--all) LIST="$LIST $(echo $GITTS | xargs grep -l '^ *export ') " + LIST="$LIST $(echo $GITTS | xargs grep -L '^ *export ') " ;; + -n|--name) NAME="original" ;; + -t|--treediff) TREEDIFF="--emit-ts-only"; NAME="original"; TSC=yes ;; + -T|--Treediff) TREEDIFF="--emit-ts-only"; NAME="original"; TSC= ;; + -i|--ignore-imported) NOIMPORTED="--no-imported" ;; + -*) echo "Unknown option $1"; usage;; + *) LIST="$LIST $1" + esac + shift +done +LIST=$(echo $LIST | xargs -n1 | grep -v '\.ts-[0-9][0-9]*\.out\.[d.]*ts' | grep -vF .ts.tmp.ts) +if [ -n "$CLEAN" ]; then + echo Cleaning up generated files... + find -maxdepth 1 -regex '.*\.ts-[0-9]+\.out.[ctj][ps]p*\|.*\.ts-[0-9]+\.[pd][no][gt]\|.*\.ts.[ca][ps][pt]' -exec rm '{}' \; + rm -rf *.ts.orig *.ts.gen *.ts.tmp.ts *[0-9]-dump.out ts2cxx-lock-* + for ts in $LIST $GITTS; do + rm -rf $ts.orig $ts.gen $ts.tmp.ts $ts.*[0-9]-dump.out $ts-*[0-9].out.ts $ts-*[0-9].out.d.ts + done + echo Done. +fi +[ -n "$LIST" ] || { echo Please specify one or more TypeScript files.; usage; } +[ -z "$DOT" ] || [ -x /usr/bin/dot -a -x /usr/bin/viewnior -a -x /usr/bin/highlight ] || sudo apt install graphviz viewnior highlight +TSOUT=$(cd $(dirname $(realpath $0))/../; pwd)/output/typescript +TS2AST=$TSOUT/bin/ts2ast +AST2CPP=$TSOUT/bin/ast2cpp +[ -x "$TS2AST" ] || { echo Cannot execute $TS2AST; exit 1; } +[ -x "$AST2CPP" ] || { echo Cannot execute $AST2CPP; exit 1; } + +# Acquire/release a lock +typeset -i LockVar +LockVar=1 +function AcquireLock { + while [[ $LockVar -ne 0 ]] || sleep 0.3; do + ln -s Lock_$2 $1-lock-$((LockVar=(LockVar+1)%$3)) > /dev/null 2>&1 && break + done +} +function ReleaseLock { + rm -f $1-lock-$LockVar +} +trap "{ pstree -p $$ | tr ')' '\n' | sed 's/.*(//' | xargs kill -9 2> /dev/null; rm -f ts2cxx-lock-*; }" SIGINT SIGQUIT SIGKILL SIGTERM + +PROCID=$$ +rm -rf *$PROCID-dump.out $PROCID-summary.out *$PROCID.out.ts ts2cxx-lock-* +OPT="--target es6 \ + --lib es2015,es2017,dom \ + --module commonjs \ + --downlevelIteration \ + --esModuleInterop \ + --experimentalDecorators" +cnt=0 +for ts in $LIST; do + ts=$(sed 's|^\./||' <<< "$ts") + echo $((++cnt)): $ts + AcquireLock ts2cxx for_$(basename $ts) $(nproc) + (if true; then + set -x + echo --------- + echo "$TS2AST" "$ts" + out=$("$TS2AST" "$ts") + if [ $? -ne 0 ]; then + echo "MSG: Failed, test case (ts2ast)$ts" + else + echo "$AST2CPP" "$ts".ast --trace=2 --emit-ts $TREEDIFF $NOIMPORTED + out=$("$AST2CPP" "$ts".ast --trace=2 --emit-ts $TREEDIFF $NOIMPORTED 2>&1) + [ $? -eq 0 ] || echo "MSG: Failed, test case (ast2cpp)$ts" + fi + echo "$out" + cmd=$(grep -n -e "^// .Beginning of Emitter:" -e "// End of Emitter.$" <<< "$out" | + tail -2 | sed 's/:.*//' | xargs | sed 's/\([^ ]*\) \(.*\)/sed -n \1,$((\2))p/') + if [ "x${cmd:0:4}" = "xsed " ]; then + T=$(sed -e "s/\(.*\)\(\.d\)\(\.ts-$PROCID.out\)/\1\2\3\2/" <<< "$ts-$PROCID.out.ts") + eval $cmd <<< "$out" > "$T" + [ -z "$NAME" ] || sed -i 's/__v[0-9][0-9]*//g' "$T" + echo -e "\n====== TS Reformatted ======\n" + $HIGHLIGHT "$T" + echo TREEDIFF=$TREEDIFF + E= + grep -qm1 "PassNode *{" <<< "$out" && E=",PassNode" + if [ -z "$TREEDIFF" -o -n "$TSC" ]; then + eval tsc $OPT "$T" $TSCERR + else + echo Skipping tsc for tree diff + fi + # --strict --downlevelIteration --esModuleInterop --noImplicitAny --isolatedModules "$T" $TSCERR + if [ $? -ne 0 ]; then + echo "MSG: Failed, test case (tsc-failed$E)$ts" + [ -n "$KEEP" ] || rm -f "$T" + elif [ -z $TREEDIFF ]; then + echo "MSG: Passed, test case $ts" + Passed="$Passed $ts" + [ -n "$KEEP" ] || rm -f "$T" + else + cp $ts $ts.tmp.ts + $TS2AST $ts.tmp.ts + if [ $? -eq 0 ]; then + $AST2CPP $ts.tmp.ts.ast $TREEDIFF | sed -n '/^AstDump:/,/^}/p' | sed 's/\(mStrIdx: unsigned int, \)[0-9]* =>/\1=>/' + fi > $ts.orig + $TS2AST $T + if [ $? -eq 0 ]; then + $AST2CPP $T.ast $TREEDIFF | sed -n '/^AstDump:/,/^}/p' | sed -e "s|/$T|/$ts.tmp.ts|" \ + -e 's/\(mStrIdx: unsigned int, \)[0-9]* =>/\1=>/' + else + E="$E,ts2ast" + fi > $ts.gen + diff $ts.orig $ts.gen + if [ $? -eq 0 -a -s $ts.orig -a -s $ts.gen ]; then + Passed="$Passed $ts" + echo "MSG: Passed, test case $ts" + else + diff -I '[0-9]\. const char\*, "' $ts.orig $ts.gen + if [ $? -eq 0 -a -s $ts.orig -a -s $ts.gen ]; then + Passed="$Passed $ts" + echo "MSG: Passed, test case (const-char*)$ts" + else + echo "MSG: Failed, test case (diff-ast$E)$ts" + fi + fi + echo === "$T"; cat "$T" + echo --- "$ts"; cat "$ts" + echo === + if [ -n "$DOT" ]; then + for tf in $ts.tmp.ts $T; do + echo "=== $tf" + cat $tf + out="$out"$'\n'"$($TS2AST $tf --dump-dot)" + done + fi + [ -n "$KEEP" ] || rm -f "$T" $ts.orig $ts.gen $ts.tmp.ts + fi + fi + if [ -n "$DOT" ]; then + echo --- "$ts"; cat "$ts" + idx=0 + grep -n -e "^digraph $PRE[^{]* {" -e "^}" <<< "$out" | grep -A1 "digraph [^{]* {" | + grep -v ^-- | sed 'N;s/\n/ /' | sed -e 's/:digraph [^{]* { */,/' -e 's/:.*/p/g' | + { while read cmd; do + idx=$((idx+1)) + sed -n $cmd <<< "$out" > "$ts"-$idx.dot + dot -Tpng -o "$ts"-$idx.png "$ts"-$idx.dot + env LC_ALL=C viewnior $VIEWOP "$ts"-$idx.png & + done + wait + rm -f "$ts"-[0-9]*.png "$ts"-[0-9]*.dot; } + fi + ReleaseLock ts2cxx + set +x + fi >& $ts.$PROCID-dump.out + grep -a "^MSG: [PF]a[si][sl]ed," $ts.$PROCID-dump.out >> $PROCID-summary.out + ) & +done +wait +echo Done. +if [ -s $PROCID-summary.out ]; then + msg=$(grep -a "^MSG: [PF]a[si][sl]ed," $PROCID-summary.out) + echo "$CMDLINE" >> $PROCID-summary.out + if true; then + echo + echo "Test case(s) passed:" + grep -a "^MSG: Passed, test case " <<< "$msg" | sed 's/MSG: Passed, test case //' | env LC_ALL=C sort -r | nl + grep -aq -m1 "^MSG: Failed, test case " <<< "$msg" + if [ $? -eq 0 ]; then + echo + echo "Test case(s) failed:" + grep -a "^MSG: Failed," <<< "$msg" | sed 's/MSG: Failed, test case //' | env LC_ALL=C sort | nl + fi + echo + echo Total: $(wc -l <<< "$msg"), Passed: $(grep -ac "^MSG: Passed," <<< "$msg"), Failed: $(grep -ac "^MSG: Failed," <<< "$msg") + grep -a "^MSG: Failed," <<< "$msg" | sed 's/MSG: Failed, test case (\([^)]*\).*/due to \1/' | sort | uniq -c + fi | tee -a $PROCID-summary.out +fi diff --git a/src/MapleFE/test/astdumpjava.sh b/src/MapleFE/test/astdumpjava.sh new file mode 100755 index 0000000000000000000000000000000000000000..a60c18ab412cbd7f81066032884f0c34efec56f3 --- /dev/null +++ b/src/MapleFE/test/astdumpjava.sh @@ -0,0 +1,164 @@ +#!/bin/bash +function usage { +cat << EOF + +Usage: astdump.sh [-d] [-f] [-p ] [-a] [-c] [-k] [-A] [-C] [-n] [-t|-T] [ ...] + +Short/long options: + -d | --dot Use Graphviz dot to generate the graph and view it with viewnior + -f | --fullscreen View the generated graph in fullscreen mode. It implies option -dot + -p | --pre Filter graphs with the specified , e.g. -p "CFG_" + -a | --ast Show AST graph. It is equivalent to options "-d -p AST" + -c | --cfg Show CFG graph. It is equivalent to options "-d -p CFG" + -s | --syntax Syntax highlighting the generated TypeScript code + -k | --keep Keep generated files *.java-[0-9]*.out.java which fail to compile with tsc + -A | --all Process all .java files in current directory excluding *.java-[0-9]*.out.java + -C | --clean Clean up generated files (*.java-[0-9]*.out.java) + -n | --name Keep original names by removing "__v[0-9]*" from generated code + -t | --treediff Compare the AST of generated TS code with the one of original TS code + -T | --Treediff Same as -t/--treediff except that it disables tsc for generated TS code + [ ...] Specify one or more TypeScript files to be processed +EOF +exit 1 +} +CMDLINE="$0 $*" +DOT= PRE= LIST= VIEWOP= HIGHLIGHT="cat" TSCERR= KEEP= CLEAN= NAME= TREEDIFF= TSC=yes +while [ $# -gt 0 ]; do + case $1 in + -d|--dot) DOT=dot;; + -f|--fullscreen) VIEWOP="--fullscreen"; DOT=fullscreen;; + -p|--pre) [ $# -ge 2 ] && { PRE="$2"; shift; } || { echo "$1 needs an argument"; exit 1; } ;; + -a|--ast) PRE="AST" ; DOT=ast ; TSCERR=">& /dev/null" ;; + -c|--cfg) PRE="CFG" ; DOT=cfg ; TSCERR=">& /dev/null" ;; + -s|--syntax) HIGHLIGHT="highlight -O xterm256 --syntax ts" ;; + -e|--tscerror) TSCERR= ;; + -k|--keep) KEEP=keep ;; + -C|--clean) CLEAN=clean ;; + -A|--all) LIST="$LIST $(find -maxdepth 1 -name '*.java')" ;; + -n|--name) NAME="original" ;; + -t|--treediff) TREEDIFF="--emit-ts-only"; NAME="original"; TSC=yes ;; + -T|--Treediff) TREEDIFF="--emit-ts-only"; NAME="original"; TSC= ;; + -*) echo "Unknown option $1"; usage;; + *) LIST="$LIST $1" + esac + shift +done +LIST=$(echo $LIST | xargs -n1 | grep -v '\.java-[0-9][0-9]*\.out.java' | grep -vF .java.tmp.java) +if [ -n "$CLEAN" ]; then + echo Cleaning up generated files... + find -maxdepth 1 -regex '.*\.java-[0-9]+\.out.[ctj][ps]p*\|.*\.java-[0-9]+\.[pd][no][gt]\|.*\.java.[ca][ps][pt]' -exec rm '{}' \; + rm -rf *.java.orig *.java.gen *.java.tmp.java *[0-9]-dump.out ts2cxx-lock-* + for xx in $LIST; do + rm -rf $xx.orig $xx.gen $xx.tmp.java $xx.*[0-9]-dump.out $xx-*[0-9].out.java + done + echo Done. +fi +[ -n "$LIST" ] || { echo Please specify one or more TypeScript files.; usage; } +[ -z "$DOT" ] || [ -x /usr/bin/dot -a -x /usr/bin/viewnior -a -x /usr/bin/highlight ] || sudo apt install graphviz viewnior highlight +JAVAOUT=$(cd $(dirname $(realpath $0))/../; pwd)/output/java +JAVA2AST=$JAVAOUT/bin/java2ast +AST2MPL=$JAVAOUT/bin/ast2mpl +[ -x "$JAVA2AST" ] || { echo Cannot execute $JAVA2AST; exit 1; } +[ -x "$AST2MPL" ] || { echo Cannot execute $AST2MPL; exit 1; } + +# Acquire/release a lock +typeset -i LockVar +LockVar=1 +function AcquireLock { + while [[ $LockVar -ne 0 ]] || sleep 0.3; do + ln -s Lock_$2 $1-lock-$((LockVar=(LockVar+1)%$3)) > /dev/null 2>&1 && break + done +} +function ReleaseLock { + rm -f $1-lock-$LockVar +} + +PROCID=$$ +#rm -rf *$PROCID-dump.out $PROCID-summary.out *$PROCID.out.java ts2cxx-lock-* +echo PROCID-dump.out=$PROCID-dump.out $PROCID-summary.out *$PROCID.out.java ts2cxx-lock-* +rm -f ~/tmp/* +cnt=0 +for tt in $LIST; do + echo $((++cnt)): $tt + set -x + echo --------- + echo "$JAVA2AST" "$tt" + out=$("$JAVA2AST" "$tt") + if [ $? -ne 0 ]; then + echo "MSG: Failed, test case (java2ast)$tt" + else + echo "$AST2MPL" "$tt".ast --trace=2 $TREEDIFF + out=$("$AST2MPL" "$tt".ast --trace=2 $TREEDIFF 2>&1) + [ $? -eq 0 ] || echo "MSG: Failed, test case (ast2mpl)$tt" + fi + echo "$out" + $JAVA2AST $tt.java + if [ $? -eq 0 ]; then + $AST2MPL $tt.java.ast $TREEDIFF | sed -n '/^AstDump:/,/^}/p' | sed 's/\(mStrIdx: unsigned int, \)[0-9]* =>/\1=>/' + fi > $tt.orig + $JAVA2AST $T + if [ $? -eq 0 ]; then + $AST2MPL $T.ast $TREEDIFF | sed -n '/^AstDump:/,/^}/p' | sed -e "s|$T|$tt.java|" \ + -e 's/\(mStrIdx: unsigned int, \)[0-9]* =>/\1=>/' + else + E="$E,java2ast" + fi > $tt.gen + diff $tt.orig $tt.gen + if [ $? -eq 0 -a -s $tt.orig -a -s $tt.gen ]; then + Passed="$Passed $tt" + echo "MSG: Passed, test case $tt" + else + diff -I '[0-9]\. const char\*, "' $tt.orig $tt.gen + if [ $? -eq 0 -a -s $tt.orig -a -s $tt.gen ]; then + Passed="$Passed $tt" + echo "MSG: Passed, test case (const-char*)$tt" + else + echo "MSG: Failed, test case (diff-ast$E)$tt" + fi + fi + echo === "$T"; cat "$T" + echo --- "$tt"; cat "$tt" + echo === + if [ -n "$DOT" ]; then + for tf in $tt.java $T; do + echo "=== $tf" + cat $tf + out="$out"$'\n'"$($JAVA2AST $tf --dump-dot)" + done + fi + [ -n "$KEEP" ] || rm -f "$T" $tt.orig $tt.gen $tt.java + if [ -n "$DOT" ]; then + echo --- "$tt"; cat "$tt" + idx=0 + grep -n -e "^digraph $PRE[^{]* {" -e "^}" <<< "$out" | grep -A1 "digraph [^{]* {" | + grep -v ^-- | sed 'N;s/\n/ /' | sed -e 's/:digraph [^{]* { */,/' -e 's/:.*/p/g' | + { while read cmd; do + idx=$((idx+1)) + sed -n $cmd <<< "$out" > "$tt"-$idx.dot + dot -Tpng -o "$tt"-$idx.png "$tt"-$idx.dot + # env LC_ALL=C viewnior $VIEWOP "$tt"-$idx.png & + done + wait + rm -f "$tt"-[0-9]*.png "$tt"-[0-9]*.dot; } + fi +done +wait +echo Done. +if [ -s $PROCID-summary.out ]; then + msg=$(grep -a "^MSG: [PF]a[si][sl]ed," $PROCID-summary.out) + echo "$CMDLINE" >> $PROCID-summary.out + if true; then + echo + echo "Test case(s) passed:" + grep -a "^MSG: Passed, test case " <<< "$msg" | sed 's/MSG: Passed, test case //' | env LC_ALL=C sort -r | nl + grep -aq -m1 "^MSG: Failed, test case " <<< "$msg" + if [ $? -eq 0 ]; then + echo + echo "Test case(s) failed:" + grep -a "^MSG: Failed," <<< "$msg" | sed 's/MSG: Failed, test case //' | env LC_ALL=C sort | nl + fi + echo + echo Total: $(wc -l <<< "$msg"), Passed: $(grep -ac "^MSG: Passed," <<< "$msg"), Failed: $(grep -ac "^MSG: Failed," <<< "$msg") + grep -a "^MSG: Failed," <<< "$msg" | sed 's/MSG: Failed, test case (\([^)]*\).*/due to \1/' | sort | uniq -c + fi | tee -a $PROCID-summary.out +fi diff --git a/src/MapleFE/test/gdbfile b/src/MapleFE/test/gdbfile deleted file mode 100644 index 31f4b07b22e30fb1524e1f07cb6c3286ba82c803..0000000000000000000000000000000000000000 --- a/src/MapleFE/test/gdbfile +++ /dev/null @@ -1,4 +0,0 @@ -file $BUILDDIR/java/java2mpl -set args t1.java -b main -r diff --git a/src/MapleFE/test/errtest/Point.class b/src/MapleFE/test/java/errtest/Point.class similarity index 100% rename from src/MapleFE/test/errtest/Point.class rename to src/MapleFE/test/java/errtest/Point.class diff --git a/src/MapleFE/test/errtest/class-field-dup-1.java b/src/MapleFE/test/java/errtest/class-field-dup-1.java similarity index 100% rename from src/MapleFE/test/errtest/class-field-dup-1.java rename to src/MapleFE/test/java/errtest/class-field-dup-1.java diff --git a/src/MapleFE/test/errtest/class-field-dup-1.java.result b/src/MapleFE/test/java/errtest/class-field-dup-1.java.result similarity index 100% rename from src/MapleFE/test/errtest/class-field-dup-1.java.result rename to src/MapleFE/test/java/errtest/class-field-dup-1.java.result diff --git a/src/MapleFE/test/errtest/class-field-dup-2.java b/src/MapleFE/test/java/errtest/class-field-dup-2.java similarity index 100% rename from src/MapleFE/test/errtest/class-field-dup-2.java rename to src/MapleFE/test/java/errtest/class-field-dup-2.java diff --git a/src/MapleFE/test/errtest/class-field-dup-2.java.result b/src/MapleFE/test/java/errtest/class-field-dup-2.java.result similarity index 100% rename from src/MapleFE/test/errtest/class-field-dup-2.java.result rename to src/MapleFE/test/java/errtest/class-field-dup-2.java.result diff --git a/src/MapleFE/test/errtest/definite-assignment-1.java b/src/MapleFE/test/java/errtest/definite-assignment-1.java similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-1.java rename to src/MapleFE/test/java/errtest/definite-assignment-1.java diff --git a/src/MapleFE/test/errtest/definite-assignment-1.java.result b/src/MapleFE/test/java/errtest/definite-assignment-1.java.result similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-1.java.result rename to src/MapleFE/test/java/errtest/definite-assignment-1.java.result diff --git a/src/MapleFE/test/errtest/definite-assignment-2.java b/src/MapleFE/test/java/errtest/definite-assignment-2.java similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-2.java rename to src/MapleFE/test/java/errtest/definite-assignment-2.java diff --git a/src/MapleFE/test/errtest/definite-assignment-2.java.result b/src/MapleFE/test/java/errtest/definite-assignment-2.java.result similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-2.java.result rename to src/MapleFE/test/java/errtest/definite-assignment-2.java.result diff --git a/src/MapleFE/test/errtest/definite-assignment-3.java b/src/MapleFE/test/java/errtest/definite-assignment-3.java similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-3.java rename to src/MapleFE/test/java/errtest/definite-assignment-3.java diff --git a/src/MapleFE/test/errtest/definite-assignment-3.java.result b/src/MapleFE/test/java/errtest/definite-assignment-3.java.result similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-3.java.result rename to src/MapleFE/test/java/errtest/definite-assignment-3.java.result diff --git a/src/MapleFE/test/errtest/definite-assignment-4.java b/src/MapleFE/test/java/errtest/definite-assignment-4.java similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-4.java rename to src/MapleFE/test/java/errtest/definite-assignment-4.java diff --git a/src/MapleFE/test/errtest/definite-assignment-4.java.result b/src/MapleFE/test/java/errtest/definite-assignment-4.java.result similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-4.java.result rename to src/MapleFE/test/java/errtest/definite-assignment-4.java.result diff --git a/src/MapleFE/test/errtest/definite-assignment-5.java b/src/MapleFE/test/java/errtest/definite-assignment-5.java similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-5.java rename to src/MapleFE/test/java/errtest/definite-assignment-5.java diff --git a/src/MapleFE/test/errtest/definite-assignment-5.java.result b/src/MapleFE/test/java/errtest/definite-assignment-5.java.result similarity index 96% rename from src/MapleFE/test/errtest/definite-assignment-5.java.result rename to src/MapleFE/test/java/errtest/definite-assignment-5.java.result index 46be40791da6d84464d090e3e90b9dbd84981392..122d471355a0aca9f620ab28c98ea3b1411821ac 100644 --- a/src/MapleFE/test/errtest/definite-assignment-5.java.result +++ b/src/MapleFE/test/java/errtest/definite-assignment-5.java.result @@ -9,7 +9,7 @@ class Point Constructors: Methods: func foo() throws: - var:pl + Decl: pl pl.z Assign 1 return pl.z LocalClasses: diff --git a/src/MapleFE/test/errtest/definite-assignment-6.java b/src/MapleFE/test/java/errtest/definite-assignment-6.java similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-6.java rename to src/MapleFE/test/java/errtest/definite-assignment-6.java diff --git a/src/MapleFE/test/errtest/definite-assignment-6.java.result b/src/MapleFE/test/java/errtest/definite-assignment-6.java.result similarity index 68% rename from src/MapleFE/test/errtest/definite-assignment-6.java.result rename to src/MapleFE/test/java/errtest/definite-assignment-6.java.result index dbd6f354215e3278573491d27b4da271d2dc8e5d..2e0cfcd43ee209ad7e789d05352ea6955746fc54 100644 --- a/src/MapleFE/test/errtest/definite-assignment-6.java.result +++ b/src/MapleFE/test/java/errtest/definite-assignment-6.java.result @@ -8,9 +8,14 @@ class Point Constructors: Methods: func foo() throws: - var:k + Decl: k while n LT 4 k Assign n + cond-branch cond:k GE 5 + true branch : + break: + false branch : + n Assign 6 System.out.println(k) LocalClasses: diff --git a/src/MapleFE/test/errtest/definite-assignment-7.java b/src/MapleFE/test/java/errtest/definite-assignment-7.java similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-7.java rename to src/MapleFE/test/java/errtest/definite-assignment-7.java diff --git a/src/MapleFE/test/errtest/definite-assignment-7.java.result b/src/MapleFE/test/java/errtest/definite-assignment-7.java.result similarity index 91% rename from src/MapleFE/test/errtest/definite-assignment-7.java.result rename to src/MapleFE/test/java/errtest/definite-assignment-7.java.result index c468a381e0c98c132717d67ad6926eb48685beed..7a0a5b310e26ed6cbc2981c2272d18fd696f3271 100644 --- a/src/MapleFE/test/errtest/definite-assignment-7.java.result +++ b/src/MapleFE/test/java/errtest/definite-assignment-7.java.result @@ -8,8 +8,8 @@ class Point Constructors: Methods: func foo() throws: - var:k - var:n=5 + Decl: k + Decl: n=5 cond-branch cond:n GT 2 true branch : k Assign 3 false branch : diff --git a/src/MapleFE/test/errtest/definite-assignment-8.java b/src/MapleFE/test/java/errtest/definite-assignment-8.java similarity index 100% rename from src/MapleFE/test/errtest/definite-assignment-8.java rename to src/MapleFE/test/java/errtest/definite-assignment-8.java diff --git a/src/MapleFE/test/errtest/definite-assignment-8.java.result b/src/MapleFE/test/java/errtest/definite-assignment-8.java.result similarity index 89% rename from src/MapleFE/test/errtest/definite-assignment-8.java.result rename to src/MapleFE/test/java/errtest/definite-assignment-8.java.result index 54716ecde467bb990ae0a8b0aa9483885785a734..e3f0e3c4409d900d538423bb4f9a6814e2fbc441 100644 --- a/src/MapleFE/test/errtest/definite-assignment-8.java.result +++ b/src/MapleFE/test/java/errtest/definite-assignment-8.java.result @@ -7,8 +7,8 @@ class Point Instance Initializer: Constructors: Methods: - func flow() throws: - var:k + func flow(flag) throws: + Decl: k cond-branch cond:flag true branch : k Assign 3 false branch : diff --git a/src/MapleFE/test/errtest/fun-param-1.java b/src/MapleFE/test/java/errtest/fun-param-1.java similarity index 100% rename from src/MapleFE/test/errtest/fun-param-1.java rename to src/MapleFE/test/java/errtest/fun-param-1.java diff --git a/src/MapleFE/test/errtest/fun-param-1.java.result b/src/MapleFE/test/java/errtest/fun-param-1.java.result similarity index 100% rename from src/MapleFE/test/errtest/fun-param-1.java.result rename to src/MapleFE/test/java/errtest/fun-param-1.java.result diff --git a/src/MapleFE/test/errtest/func-dup-1.java b/src/MapleFE/test/java/errtest/func-dup-1.java similarity index 100% rename from src/MapleFE/test/errtest/func-dup-1.java rename to src/MapleFE/test/java/errtest/func-dup-1.java diff --git a/src/MapleFE/test/errtest/func-dup-1.java.result b/src/MapleFE/test/java/errtest/func-dup-1.java.result similarity index 75% rename from src/MapleFE/test/errtest/func-dup-1.java.result rename to src/MapleFE/test/java/errtest/func-dup-1.java.result index 1a3b6b7077899782927dcb665f8ebf820640da8a..e15de87904fd0abaa09181c30a775871270733fd 100644 --- a/src/MapleFE/test/errtest/func-dup-1.java.result +++ b/src/MapleFE/test/java/errtest/func-dup-1.java.result @@ -7,8 +7,8 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: - func foo() throws: + func foo(c,b) throws: + func foo(i,b,c) throws: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/errtest/generate-result.sh b/src/MapleFE/test/java/errtest/generate-result.sh similarity index 92% rename from src/MapleFE/test/errtest/generate-result.sh rename to src/MapleFE/test/java/errtest/generate-result.sh index 9e1585b384c4e043acf8f6551a256a2ee41f7f20..08b3acc3b58dc1585fb15888064b004629e72007 100755 --- a/src/MapleFE/test/errtest/generate-result.sh +++ b/src/MapleFE/test/java/errtest/generate-result.sh @@ -17,5 +17,5 @@ FILES=$(pwd)/*.java for f in $FILES do echo "Generating result for $f ..." - $BUILDDIR/java/java2mpl $f > $f.result + ../../../output/java/java/java2mpl $f > $f.result done diff --git a/src/MapleFE/test/errtest/new-class-nodecl.java b/src/MapleFE/test/java/errtest/new-class-nodecl.java similarity index 100% rename from src/MapleFE/test/errtest/new-class-nodecl.java rename to src/MapleFE/test/java/errtest/new-class-nodecl.java diff --git a/src/MapleFE/test/errtest/new-class-nodecl.java.result b/src/MapleFE/test/java/errtest/new-class-nodecl.java.result similarity index 90% rename from src/MapleFE/test/errtest/new-class-nodecl.java.result rename to src/MapleFE/test/java/errtest/new-class-nodecl.java.result index dae33b0a3fddbf6052438231ef602b7c352b1e43..b54ce6497757b1fe6579b5dd024179151531b77d 100644 --- a/src/MapleFE/test/errtest/new-class-nodecl.java.result +++ b/src/MapleFE/test/java/errtest/new-class-nodecl.java.result @@ -8,7 +8,7 @@ class A Constructors: Methods: func foo() throws: - new Cyclic + new Cyclic() LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/errtest/new-param-nodecl.java b/src/MapleFE/test/java/errtest/new-param-nodecl.java similarity index 100% rename from src/MapleFE/test/errtest/new-param-nodecl.java rename to src/MapleFE/test/java/errtest/new-param-nodecl.java diff --git a/src/MapleFE/test/errtest/new-param-nodecl.java.result b/src/MapleFE/test/java/errtest/new-param-nodecl.java.result similarity index 94% rename from src/MapleFE/test/errtest/new-param-nodecl.java.result rename to src/MapleFE/test/java/errtest/new-param-nodecl.java.result index 4e496b1c10557801f985647afcedf740d99497f5..452a50a7237d54b7b5146f5c8240fa0f3850a030 100644 --- a/src/MapleFE/test/errtest/new-param-nodecl.java.result +++ b/src/MapleFE/test/java/errtest/new-param-nodecl.java.result @@ -9,7 +9,7 @@ class A Constructors: Methods: func foo() throws: - new Cyclic + new Cyclic(a,b) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/errtest/var-no-decl-1.java b/src/MapleFE/test/java/errtest/var-no-decl-1.java similarity index 100% rename from src/MapleFE/test/errtest/var-no-decl-1.java rename to src/MapleFE/test/java/errtest/var-no-decl-1.java diff --git a/src/MapleFE/test/errtest/var-no-decl-1.java.result b/src/MapleFE/test/java/errtest/var-no-decl-1.java.result similarity index 86% rename from src/MapleFE/test/errtest/var-no-decl-1.java.result rename to src/MapleFE/test/java/errtest/var-no-decl-1.java.result index 5b6375ed5b910025aa1b7ff760e9d76a3620dfb4..8e3b5b1a9dfa0a0239a58c4669943b189ff3a5fa 100644 --- a/src/MapleFE/test/errtest/var-no-decl-1.java.result +++ b/src/MapleFE/test/java/errtest/var-no-decl-1.java.result @@ -8,9 +8,10 @@ class A Constructors: Methods: func foo() throws: - var:a + Decl: a a Assign b LocalClasses: LocalInterfaces: +Identifier:a has no decl. Identifier:b has no decl. diff --git a/src/MapleFE/test/errtest/var-no-decl-2.java b/src/MapleFE/test/java/errtest/var-no-decl-2.java similarity index 100% rename from src/MapleFE/test/errtest/var-no-decl-2.java rename to src/MapleFE/test/java/errtest/var-no-decl-2.java diff --git a/src/MapleFE/test/errtest/var-no-decl-2.java.result b/src/MapleFE/test/java/errtest/var-no-decl-2.java.result similarity index 100% rename from src/MapleFE/test/errtest/var-no-decl-2.java.result rename to src/MapleFE/test/java/errtest/var-no-decl-2.java.result diff --git a/src/MapleFE/test/errtest/var-no-decl-3.java b/src/MapleFE/test/java/errtest/var-no-decl-3.java similarity index 100% rename from src/MapleFE/test/errtest/var-no-decl-3.java rename to src/MapleFE/test/java/errtest/var-no-decl-3.java diff --git a/src/MapleFE/test/errtest/var-no-decl-3.java.result b/src/MapleFE/test/java/errtest/var-no-decl-3.java.result similarity index 100% rename from src/MapleFE/test/errtest/var-no-decl-3.java.result rename to src/MapleFE/test/java/errtest/var-no-decl-3.java.result diff --git a/src/MapleFE/test/java2mpl/annotation-marker.java b/src/MapleFE/test/java/java2mpl/annotation-marker.java similarity index 100% rename from src/MapleFE/test/java2mpl/annotation-marker.java rename to src/MapleFE/test/java/java2mpl/annotation-marker.java diff --git a/src/MapleFE/test/java2mpl/annotation-marker.java.result b/src/MapleFE/test/java/java2mpl/annotation-marker.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/annotation-marker.java.result rename to src/MapleFE/test/java/java2mpl/annotation-marker.java.result diff --git a/src/MapleFE/test/java2mpl/annotation-single-elem.java b/src/MapleFE/test/java/java2mpl/annotation-single-elem.java similarity index 100% rename from src/MapleFE/test/java2mpl/annotation-single-elem.java rename to src/MapleFE/test/java/java2mpl/annotation-single-elem.java diff --git a/src/MapleFE/test/java2mpl/annotation-single-elem.java.result b/src/MapleFE/test/java/java2mpl/annotation-single-elem.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/annotation-single-elem.java.result rename to src/MapleFE/test/java/java2mpl/annotation-single-elem.java.result diff --git a/src/MapleFE/test/java2mpl/annotation-type-decl.java b/src/MapleFE/test/java/java2mpl/annotation-type-decl.java similarity index 100% rename from src/MapleFE/test/java2mpl/annotation-type-decl.java rename to src/MapleFE/test/java/java2mpl/annotation-type-decl.java diff --git a/src/MapleFE/test/java2mpl/annotation-type-decl.java.result b/src/MapleFE/test/java/java2mpl/annotation-type-decl.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/annotation-type-decl.java.result rename to src/MapleFE/test/java/java2mpl/annotation-type-decl.java.result diff --git a/src/MapleFE/test/java2mpl/annotation-useage.java b/src/MapleFE/test/java/java2mpl/annotation-useage.java similarity index 100% rename from src/MapleFE/test/java2mpl/annotation-useage.java rename to src/MapleFE/test/java/java2mpl/annotation-useage.java diff --git a/src/MapleFE/test/java2mpl/annotation-useage.java.result b/src/MapleFE/test/java/java2mpl/annotation-useage.java.result similarity index 77% rename from src/MapleFE/test/java2mpl/annotation-useage.java.result rename to src/MapleFE/test/java/java2mpl/annotation-useage.java.result index a3e660fd181da2ad43978b1fbd62843a66e4cdff..1f64c090b4f1460068047d9e116dc344b9478ca8 100644 --- a/src/MapleFE/test/java2mpl/annotation-useage.java.result +++ b/src/MapleFE/test/java/java2mpl/annotation-useage.java.result @@ -7,7 +7,7 @@ class A Instance Initializer: Constructors: Methods: - func travelThroughTime() throws: + func travelThroughTime(destination) throws: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/array-2d.java b/src/MapleFE/test/java/java2mpl/array-2d.java similarity index 100% rename from src/MapleFE/test/java2mpl/array-2d.java rename to src/MapleFE/test/java/java2mpl/array-2d.java diff --git a/src/MapleFE/test/java2mpl/array-2d.java.result b/src/MapleFE/test/java/java2mpl/array-2d.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/array-2d.java.result rename to src/MapleFE/test/java/java2mpl/array-2d.java.result diff --git a/src/MapleFE/test/java2mpl/array-access.java b/src/MapleFE/test/java/java2mpl/array-access.java similarity index 100% rename from src/MapleFE/test/java2mpl/array-access.java rename to src/MapleFE/test/java/java2mpl/array-access.java diff --git a/src/MapleFE/test/java2mpl/array-access.java.result b/src/MapleFE/test/java/java2mpl/array-access.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/array-access.java.result rename to src/MapleFE/test/java/java2mpl/array-access.java.result diff --git a/src/MapleFE/test/java2mpl/array-init.java b/src/MapleFE/test/java/java2mpl/array-init.java similarity index 100% rename from src/MapleFE/test/java2mpl/array-init.java rename to src/MapleFE/test/java/java2mpl/array-init.java diff --git a/src/MapleFE/test/java2mpl/array-init.java.result b/src/MapleFE/test/java/java2mpl/array-init.java.result similarity index 78% rename from src/MapleFE/test/java2mpl/array-init.java.result rename to src/MapleFE/test/java/java2mpl/array-init.java.result index 66f4a67617a83bcb17b0c27bcf586a77ed2f6a51..3ef43504c621e734813d2c79a03ab7040f8ac918 100644 --- a/src/MapleFE/test/java2mpl/array-init.java.result +++ b/src/MapleFE/test/java/java2mpl/array-init.java.result @@ -8,9 +8,9 @@ class A Constructors: Methods: func foo() throws: - var:ba= - var:array=[] - var:array=[] + Decl: ba= + Decl: array=[] + Decl: array=[] LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/array.java b/src/MapleFE/test/java/java2mpl/array.java similarity index 100% rename from src/MapleFE/test/java2mpl/array.java rename to src/MapleFE/test/java/java2mpl/array.java diff --git a/src/MapleFE/test/java2mpl/array.java.result b/src/MapleFE/test/java/java2mpl/array.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/array.java.result rename to src/MapleFE/test/java/java2mpl/array.java.result diff --git a/src/MapleFE/test/java2mpl/assert.java b/src/MapleFE/test/java/java2mpl/assert.java similarity index 100% rename from src/MapleFE/test/java2mpl/assert.java rename to src/MapleFE/test/java/java2mpl/assert.java diff --git a/src/MapleFE/test/java2mpl/assert.java.result b/src/MapleFE/test/java/java2mpl/assert.java.result similarity index 87% rename from src/MapleFE/test/java2mpl/assert.java.result rename to src/MapleFE/test/java/java2mpl/assert.java.result index 5e8b03621585d4050be1e101251f7004ddc0ffa9..16a94b50a7df4c987ace27e3a7c273f576c42806 100644 --- a/src/MapleFE/test/java2mpl/assert.java.result +++ b/src/MapleFE/test/java/java2mpl/assert.java.result @@ -7,7 +7,7 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: + func foo(a,b) throws: assert a LT b : LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/assignment.java b/src/MapleFE/test/java/java2mpl/assignment.java similarity index 100% rename from src/MapleFE/test/java2mpl/assignment.java rename to src/MapleFE/test/java/java2mpl/assignment.java diff --git a/src/MapleFE/test/java2mpl/assignment.java.result b/src/MapleFE/test/java/java2mpl/assignment.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/assignment.java.result rename to src/MapleFE/test/java/java2mpl/assignment.java.result diff --git a/src/MapleFE/test/java2mpl/binary-expr-1.java b/src/MapleFE/test/java/java2mpl/binary-expr-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/binary-expr-1.java rename to src/MapleFE/test/java/java2mpl/binary-expr-1.java diff --git a/src/MapleFE/test/java2mpl/binary-expr-1.java.result b/src/MapleFE/test/java/java2mpl/binary-expr-1.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/binary-expr-1.java.result rename to src/MapleFE/test/java/java2mpl/binary-expr-1.java.result diff --git a/src/MapleFE/test/java2mpl/binary-expr-2.java b/src/MapleFE/test/java/java2mpl/binary-expr-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/binary-expr-2.java rename to src/MapleFE/test/java/java2mpl/binary-expr-2.java diff --git a/src/MapleFE/test/java2mpl/binary-expr-2.java.result b/src/MapleFE/test/java/java2mpl/binary-expr-2.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/binary-expr-2.java.result rename to src/MapleFE/test/java/java2mpl/binary-expr-2.java.result diff --git a/src/MapleFE/test/java2mpl/binary-expr-3.java b/src/MapleFE/test/java/java2mpl/binary-expr-3.java similarity index 100% rename from src/MapleFE/test/java2mpl/binary-expr-3.java rename to src/MapleFE/test/java/java2mpl/binary-expr-3.java diff --git a/src/MapleFE/test/java2mpl/binary-expr-3.java.result b/src/MapleFE/test/java/java2mpl/binary-expr-3.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/binary-expr-3.java.result rename to src/MapleFE/test/java/java2mpl/binary-expr-3.java.result diff --git a/src/MapleFE/test/java2mpl/binary-expr-4.java b/src/MapleFE/test/java/java2mpl/binary-expr-4.java similarity index 100% rename from src/MapleFE/test/java2mpl/binary-expr-4.java rename to src/MapleFE/test/java/java2mpl/binary-expr-4.java diff --git a/src/MapleFE/test/java2mpl/binary-expr-4.java.result b/src/MapleFE/test/java/java2mpl/binary-expr-4.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/binary-expr-4.java.result rename to src/MapleFE/test/java/java2mpl/binary-expr-4.java.result diff --git a/src/MapleFE/test/java2mpl/binary-expr.java b/src/MapleFE/test/java/java2mpl/binary-expr.java similarity index 100% rename from src/MapleFE/test/java2mpl/binary-expr.java rename to src/MapleFE/test/java/java2mpl/binary-expr.java diff --git a/src/MapleFE/test/java2mpl/binary-expr.java.result b/src/MapleFE/test/java/java2mpl/binary-expr.java.result similarity index 36% rename from src/MapleFE/test/java2mpl/binary-expr.java.result rename to src/MapleFE/test/java/java2mpl/binary-expr.java.result index cdbfae457762078f979563e89710058d7f0507e8..c17eb9683da4b55f6b21b2ae0a5abc3504be38d1 100644 --- a/src/MapleFE/test/java2mpl/binary-expr.java.result +++ b/src/MapleFE/test/java/java2mpl/binary-expr.java.result @@ -8,7 +8,7 @@ class A Constructors: Methods: func foo() throws: - var:a,b,c + Decl: a,b,c a Assign b Add c a Assign b Sub c a Assign b GT c @@ -21,3 +21,30 @@ class A LocalClasses: LocalInterfaces: +Identifier:a has no decl. +Identifier:b has no decl. +Identifier:c has no decl. +Identifier:a has no decl. +Identifier:b has no decl. +Identifier:c has no decl. +Identifier:a has no decl. +Identifier:b has no decl. +Identifier:c has no decl. +Identifier:a has no decl. +Identifier:b has no decl. +Identifier:c has no decl. +Identifier:a has no decl. +Identifier:b has no decl. +Identifier:c has no decl. +Identifier:a has no decl. +Identifier:b has no decl. +Identifier:c has no decl. +Identifier:a has no decl. +Identifier:b has no decl. +Identifier:c has no decl. +Identifier:a has no decl. +Identifier:b has no decl. +Identifier:c has no decl. +Identifier:a has no decl. +Identifier:b has no decl. +Identifier:c has no decl. diff --git a/src/MapleFE/test/java2mpl/call-1.java b/src/MapleFE/test/java/java2mpl/call-1.java similarity index 94% rename from src/MapleFE/test/java2mpl/call-1.java rename to src/MapleFE/test/java/java2mpl/call-1.java index 1dab53c13ee39d0137e35fd78c56173feec84567..749296a93c6f1640b14620019a658782effd873e 100644 --- a/src/MapleFE/test/java2mpl/call-1.java +++ b/src/MapleFE/test/java/java2mpl/call-1.java @@ -13,7 +13,8 @@ //See the Mulan PSL v2 for more details. // class A { + void println() {} void foo() { - println(c); + println(); } } diff --git a/src/MapleFE/test/java2mpl/call-1.java.result b/src/MapleFE/test/java/java2mpl/call-1.java.result similarity index 74% rename from src/MapleFE/test/java2mpl/call-1.java.result rename to src/MapleFE/test/java/java2mpl/call-1.java.result index 7b1a54d690a1ddeda74cdc8d8a7ab52f58e98271..00599325f8be757af7b1762ef0a594cd1fa25d5f 100644 --- a/src/MapleFE/test/java2mpl/call-1.java.result +++ b/src/MapleFE/test/java/java2mpl/call-1.java.result @@ -1,4 +1,4 @@ -Matched 15 tokens. +Matched 20 tokens. ============= Module =========== == Sub Tree == class A @@ -7,8 +7,9 @@ class A Instance Initializer: Constructors: Methods: + func println() throws: func foo() throws: - println(c) + println() LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/call-2.java b/src/MapleFE/test/java/java2mpl/call-2.java similarity index 91% rename from src/MapleFE/test/java2mpl/call-2.java rename to src/MapleFE/test/java/java2mpl/call-2.java index 5ad3b36674bf4ff32ace41498c6cde0aae1c7567..315d053548472c2681db79f45d32fb7321c9022b 100644 --- a/src/MapleFE/test/java2mpl/call-2.java +++ b/src/MapleFE/test/java/java2mpl/call-2.java @@ -13,7 +13,8 @@ //See the Mulan PSL v2 for more details. // class A { + void println(char c, int a) {} void foo() { - println(c, a); + println('a', 1); } } diff --git a/src/MapleFE/test/java2mpl/call-2.java.result b/src/MapleFE/test/java/java2mpl/call-2.java.result similarity index 72% rename from src/MapleFE/test/java2mpl/call-2.java.result rename to src/MapleFE/test/java/java2mpl/call-2.java.result index 0f2a36102d38c5a7bff60fce9016ee322e6cfae1..d93d7abeeac17023bbe34f76127160e2ddd62abc 100644 --- a/src/MapleFE/test/java2mpl/call-2.java.result +++ b/src/MapleFE/test/java/java2mpl/call-2.java.result @@ -1,4 +1,4 @@ -Matched 17 tokens. +Matched 28 tokens. ============= Module =========== == Sub Tree == class A @@ -7,8 +7,9 @@ class A Instance Initializer: Constructors: Methods: + func println(c,a) throws: func foo() throws: - println(c,a) + println(a,1) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/call-3.java b/src/MapleFE/test/java/java2mpl/call-3.java similarity index 87% rename from src/MapleFE/test/java2mpl/call-3.java rename to src/MapleFE/test/java/java2mpl/call-3.java index f6578decf51503b17ff5d3ed4f414a0c113aeafc..2cbca58e90b3cb31eff2b3397e5868deaf32921d 100644 --- a/src/MapleFE/test/java2mpl/call-3.java +++ b/src/MapleFE/test/java/java2mpl/call-3.java @@ -13,7 +13,8 @@ //See the Mulan PSL v2 for more details. // class A { - void foo() { - println(c+1, a); + void println(char c, int a) {} + void foo(char c, int a) { + println(c, a); } } diff --git a/src/MapleFE/test/java/java2mpl/call-3.java.result b/src/MapleFE/test/java/java2mpl/call-3.java.result new file mode 100644 index 0000000000000000000000000000000000000000..e4cd31cb30e39ada338cb254b10c91ed6d41f425 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/call-3.java.result @@ -0,0 +1,15 @@ +Matched 33 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + + Instance Initializer: + Constructors: + Methods: + func println(c,a) throws: + func foo(c,a) throws: + println(c,a) + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java2mpl/call-4.java b/src/MapleFE/test/java/java2mpl/call-4.java similarity index 100% rename from src/MapleFE/test/java2mpl/call-4.java rename to src/MapleFE/test/java/java2mpl/call-4.java diff --git a/src/MapleFE/test/java2mpl/call-4.java.result b/src/MapleFE/test/java/java2mpl/call-4.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/call-4.java.result rename to src/MapleFE/test/java/java2mpl/call-4.java.result diff --git a/src/MapleFE/test/java2mpl/call-5.java b/src/MapleFE/test/java/java2mpl/call-5.java similarity index 100% rename from src/MapleFE/test/java2mpl/call-5.java rename to src/MapleFE/test/java/java2mpl/call-5.java diff --git a/src/MapleFE/test/java2mpl/call-5.java.result b/src/MapleFE/test/java/java2mpl/call-5.java.result similarity index 78% rename from src/MapleFE/test/java2mpl/call-5.java.result rename to src/MapleFE/test/java/java2mpl/call-5.java.result index 0addd443fa0633d217a13a0b62e5ed719636db3b..6f0495e478e15adaefe9afb3c1084606b10a5401 100644 --- a/src/MapleFE/test/java2mpl/call-5.java.result +++ b/src/MapleFE/test/java/java2mpl/call-5.java.result @@ -8,7 +8,7 @@ class A Constructors: Methods: func foo() throws: - var:socket=new Socket + Decl: socket=new Socket("localhost",listeningPort) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java/java2mpl/call-6.java b/src/MapleFE/test/java/java2mpl/call-6.java new file mode 100644 index 0000000000000000000000000000000000000000..c50c134fc5ed1a9d614a85c117819ba0008a6904 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/call-6.java @@ -0,0 +1,21 @@ +// +//Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +// +//OpenArkFE is licensed under the Mulan PSL v2. +//You can use this software according to the terms and conditions of the Mulan PSL v2. +//You may obtain a copy of Mulan PSL v2 at: +// +// http://license.coscl.org.cn/MulanPSL2 +// +//THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +//FIT FOR A PARTICULAR PURPOSE. +//See the Mulan PSL v2 for more details. +// +class A { + int bar(char c) { return 1; } + void foo(char c) { + int i; + i = bar(c); + } +} diff --git a/src/MapleFE/test/java/java2mpl/call-6.java.result b/src/MapleFE/test/java/java2mpl/call-6.java.result new file mode 100644 index 0000000000000000000000000000000000000000..9e07cabbf805525a53b101f2ff8cc6a850e31ee0 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/call-6.java.result @@ -0,0 +1,18 @@ +Matched 33 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + + Instance Initializer: + Constructors: + Methods: + func bar(c) throws: + return 1 + func foo(c) throws: + Decl: i + i Assign bar(c) + LocalClasses: + LocalInterfaces: + +Identifier:i has no decl. diff --git a/src/MapleFE/test/java/java2mpl/call-7.java b/src/MapleFE/test/java/java2mpl/call-7.java new file mode 100644 index 0000000000000000000000000000000000000000..9d89cb0d8c5bc486c4624e11b74fec8b0e69988d --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/call-7.java @@ -0,0 +1,26 @@ +// +//Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +// +//OpenArkFE is licensed under the Mulan PSL v2. +//You can use this software according to the terms and conditions of the Mulan PSL v2. +//You may obtain a copy of Mulan PSL v2 at: +// +// http://license.coscl.org.cn/MulanPSL2 +// +//THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +//FIT FOR A PARTICULAR PURPOSE. +//See the Mulan PSL v2 for more details. +// +class B { + int bar(int c, int a) { + c += a; + return c; + } +} + +class A { + int foo(B b) { + return b.bar(3, 4); + } +} diff --git a/src/MapleFE/test/java/java2mpl/call-7.java.result b/src/MapleFE/test/java/java2mpl/call-7.java.result new file mode 100644 index 0000000000000000000000000000000000000000..be32c9b7d483f8f204644fcd59cfd1ee6d2ed795 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/call-7.java.result @@ -0,0 +1,28 @@ +Matched 22 tokens. +Matched 44 tokens. +============= Module =========== +== Sub Tree == +class B + Fields: + + Instance Initializer: + Constructors: + Methods: + func bar(c,a) throws: + c AddAssign a + return c + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class A + Fields: + + Instance Initializer: + Constructors: + Methods: + func foo(b) throws: + return b.bar(3,4) + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/java2mpl/call-8.java b/src/MapleFE/test/java/java2mpl/call-8.java new file mode 100644 index 0000000000000000000000000000000000000000..68ca75463eab2d199bf7282930132016ee626871 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/call-8.java @@ -0,0 +1,29 @@ +// +//Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +// +//OpenArkFE is licensed under the Mulan PSL v2. +//You can use this software according to the terms and conditions of the Mulan PSL v2. +//You may obtain a copy of Mulan PSL v2 at: +// +// http://license.coscl.org.cn/MulanPSL2 +// +//THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +//FIT FOR A PARTICULAR PURPOSE. +//See the Mulan PSL v2 for more details. +// +class A { + int f; + int bar(int c, A a) { return c; } + int bar(int c, int a) { return a; } + int bar(A a) { return f; } + int foo(A b) { + int i = 0; + int j = 3; + int k = 4; + i = bar(i); + j = bar(j, k); + k = bar(j, this); + return i + j + k; + } +} diff --git a/src/MapleFE/test/java/java2mpl/call-8.java.result b/src/MapleFE/test/java/java2mpl/call-8.java.result new file mode 100644 index 0000000000000000000000000000000000000000..1ac416e49e35d2d8b79698376c5eab2d3977cbff --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/call-8.java.result @@ -0,0 +1,29 @@ +Matched 101 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + f + Instance Initializer: + Constructors: + Methods: + func bar(c,a) throws: + return c + func bar(c,a) throws: + return a + func bar(a) throws: + return f + func foo(b) throws: + Decl: i=0 + Decl: j=3 + Decl: k=4 + i Assign bar(i) + j Assign bar(j,k) + k Assign bar(j,this) + return i Add j Add k + LocalClasses: + LocalInterfaces: + +Identifier:i has no decl. +Identifier:j has no decl. +Identifier:k has no decl. diff --git a/src/MapleFE/test/sharedfe/add2.java b/src/MapleFE/test/java/java2mpl/call-param.java similarity index 90% rename from src/MapleFE/test/sharedfe/add2.java rename to src/MapleFE/test/java/java2mpl/call-param.java index 7f9c2a8f24dd8d66c4358eeab2251c8de35d71d1..eaed074e0fe533038ec2d7318ff163ed64e6b9b9 100644 --- a/src/MapleFE/test/sharedfe/add2.java +++ b/src/MapleFE/test/java/java2mpl/call-param.java @@ -12,10 +12,8 @@ //FIT FOR A PARTICULAR PURPOSE. //See the Mulan PSL v2 for more details. // - -int foo(int a, int b) { - int c; - - c = a + b; - return c; +class A { + void foo(int c) { + println(c); + } } diff --git a/src/MapleFE/test/java2mpl/call-3.java.result b/src/MapleFE/test/java/java2mpl/call-param.java.result similarity index 69% rename from src/MapleFE/test/java2mpl/call-3.java.result rename to src/MapleFE/test/java/java2mpl/call-param.java.result index 75eeeb5eba57813fd5c125aeb80afebf21dd84b5..058a3d0a1a765659f3b305ea8e88a7c2b4dd60b4 100644 --- a/src/MapleFE/test/java2mpl/call-3.java.result +++ b/src/MapleFE/test/java/java2mpl/call-param.java.result @@ -1,4 +1,4 @@ -Matched 19 tokens. +Matched 17 tokens. ============= Module =========== == Sub Tree == class A @@ -7,8 +7,8 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: - println(c Add 1,a) + func foo(c) throws: + println(c) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/cast-1.java b/src/MapleFE/test/java/java2mpl/cast-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/cast-1.java rename to src/MapleFE/test/java/java2mpl/cast-1.java diff --git a/src/MapleFE/test/java2mpl/cast-1.java.result b/src/MapleFE/test/java/java2mpl/cast-1.java.result similarity index 73% rename from src/MapleFE/test/java2mpl/cast-1.java.result rename to src/MapleFE/test/java/java2mpl/cast-1.java.result index 05d4989550b031a22b210e597570d9ba52e4368d..50dd6170c0555c65ec5dcda78983a90d7cc38fb4 100644 --- a/src/MapleFE/test/java2mpl/cast-1.java.result +++ b/src/MapleFE/test/java/java2mpl/cast-1.java.result @@ -19,7 +19,7 @@ interface Colorable Fields: Methods: - func setColor() throws: + func setColor(color) throws: == Sub Tree == class ColoredPoint @@ -28,7 +28,7 @@ class ColoredPoint Instance Initializer: Constructors: Methods: - func setColor() throws: + func setColor(color) throws: this.color Assign color LocalClasses: LocalInterfaces: @@ -50,15 +50,18 @@ class Test Instance Initializer: Constructors: Methods: - func main() throws: - var:p=new Point - var:cp=new ColoredPoint - var:c + func main(args) throws: + Decl: p=new Point() + Decl: cp=new ColoredPoint() + Decl: c cp Assign (ColoredPoint)p c Assign (Colorable)p - var:l=(Long)p - var:e=new EndPoint + Decl: l=(Long)p + Decl: e=new EndPoint() c Assign (Colorable)e LocalClasses: LocalInterfaces: +Identifier:cp has no decl. +Identifier:c has no decl. +Identifier:c has no decl. diff --git a/src/MapleFE/test/java2mpl/cast-2.java b/src/MapleFE/test/java/java2mpl/cast-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/cast-2.java rename to src/MapleFE/test/java/java2mpl/cast-2.java diff --git a/src/MapleFE/test/java2mpl/cast-2.java.result b/src/MapleFE/test/java/java2mpl/cast-2.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/cast-2.java.result rename to src/MapleFE/test/java/java2mpl/cast-2.java.result diff --git a/src/MapleFE/test/java2mpl/class-anonymous.java b/src/MapleFE/test/java/java2mpl/class-anonymous.java similarity index 100% rename from src/MapleFE/test/java2mpl/class-anonymous.java rename to src/MapleFE/test/java/java2mpl/class-anonymous.java diff --git a/src/MapleFE/test/java2mpl/class-anonymous.java.result b/src/MapleFE/test/java/java2mpl/class-anonymous.java.result similarity index 83% rename from src/MapleFE/test/java2mpl/class-anonymous.java.result rename to src/MapleFE/test/java/java2mpl/class-anonymous.java.result index 5dd2661dbf5ef9a1262d47cf44c7b3dfc8675c40..69dec033ca83d6d62bb51a8bf318dbe45cab967b 100644 --- a/src/MapleFE/test/java2mpl/class-anonymous.java.result +++ b/src/MapleFE/test/java/java2mpl/class-anonymous.java.result @@ -8,7 +8,7 @@ class ChatTest Constructors: Methods: func performDontReceiveMessageInNameState() throws: Exception - var:client2=new Thread + Decl: client2=new Thread(new ChatConnection()) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/class-constructor-explicit-2.java b/src/MapleFE/test/java/java2mpl/class-constructor-explicit-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/class-constructor-explicit-2.java rename to src/MapleFE/test/java/java2mpl/class-constructor-explicit-2.java diff --git a/src/MapleFE/test/java2mpl/class-constructor-explicit-2.java.result b/src/MapleFE/test/java/java2mpl/class-constructor-explicit-2.java.result similarity index 76% rename from src/MapleFE/test/java2mpl/class-constructor-explicit-2.java.result rename to src/MapleFE/test/java/java2mpl/class-constructor-explicit-2.java.result index a2e56860a7eb31a9e86e27dd1b9929d646eb9bc8..3130fa4e825f9fa930afb2a9b417b7288aa59d8d 100644 --- a/src/MapleFE/test/java2mpl/class-constructor-explicit-2.java.result +++ b/src/MapleFE/test/java/java2mpl/class-constructor-explicit-2.java.result @@ -7,7 +7,7 @@ class Point x y Instance Initializer: Constructors: - constructor Point() throws: + constructor Point(x,y) throws: this.x Assign x this.y Assign y Methods: @@ -20,8 +20,8 @@ class ColoredPoint WHITE=0 color Instance Initializer: Constructors: - constructor ColoredPoint() throws: - constructor ColoredPoint() throws: + constructor ColoredPoint(x,y) throws: + constructor ColoredPoint(x,y,color) throws: this.color Assign color Methods: LocalClasses: diff --git a/src/MapleFE/test/java2mpl/class-constructor-explicit.java b/src/MapleFE/test/java/java2mpl/class-constructor-explicit.java similarity index 100% rename from src/MapleFE/test/java2mpl/class-constructor-explicit.java rename to src/MapleFE/test/java/java2mpl/class-constructor-explicit.java diff --git a/src/MapleFE/test/java2mpl/class-constructor-explicit.java.result b/src/MapleFE/test/java/java2mpl/class-constructor-explicit.java.result similarity index 85% rename from src/MapleFE/test/java2mpl/class-constructor-explicit.java.result rename to src/MapleFE/test/java/java2mpl/class-constructor-explicit.java.result index 5194e250689f7824d8775eef28dcc95aea99c5dd..51e2d3636b85711fb1df3909b16776e020e146f6 100644 --- a/src/MapleFE/test/java2mpl/class-constructor-explicit.java.result +++ b/src/MapleFE/test/java/java2mpl/class-constructor-explicit.java.result @@ -6,7 +6,7 @@ class Point x y Instance Initializer: Constructors: - constructor Point() throws: + constructor Point(y) throws: this.y Assign y Methods: LocalClasses: diff --git a/src/MapleFE/test/java2mpl/class-constructor.java b/src/MapleFE/test/java/java2mpl/class-constructor.java similarity index 100% rename from src/MapleFE/test/java2mpl/class-constructor.java rename to src/MapleFE/test/java/java2mpl/class-constructor.java diff --git a/src/MapleFE/test/java2mpl/class-constructor.java.result b/src/MapleFE/test/java/java2mpl/class-constructor.java.result similarity index 86% rename from src/MapleFE/test/java2mpl/class-constructor.java.result rename to src/MapleFE/test/java/java2mpl/class-constructor.java.result index d9c4a0af8eb133761c6002521e117587358765bf..ef94fd9d7618926f879363fb37540882c065f77a 100644 --- a/src/MapleFE/test/java2mpl/class-constructor.java.result +++ b/src/MapleFE/test/java/java2mpl/class-constructor.java.result @@ -6,7 +6,7 @@ class Point x y Instance Initializer: Constructors: - constructor Point() throws: + constructor Point(x,y) throws: this.x Assign x this.y Assign y Methods: diff --git a/src/MapleFE/test/java2mpl/class-instance-initializer.java b/src/MapleFE/test/java/java2mpl/class-instance-initializer.java similarity index 100% rename from src/MapleFE/test/java2mpl/class-instance-initializer.java rename to src/MapleFE/test/java/java2mpl/class-instance-initializer.java diff --git a/src/MapleFE/test/java2mpl/class-instance-initializer.java.result b/src/MapleFE/test/java/java2mpl/class-instance-initializer.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/class-instance-initializer.java.result rename to src/MapleFE/test/java/java2mpl/class-instance-initializer.java.result diff --git a/src/MapleFE/test/java2mpl/class-method-1.java b/src/MapleFE/test/java/java2mpl/class-method-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/class-method-1.java rename to src/MapleFE/test/java/java2mpl/class-method-1.java diff --git a/src/MapleFE/test/java2mpl/class-method-1.java.result b/src/MapleFE/test/java/java2mpl/class-method-1.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/class-method-1.java.result rename to src/MapleFE/test/java/java2mpl/class-method-1.java.result diff --git a/src/MapleFE/test/java2mpl/class-method-2.java b/src/MapleFE/test/java/java2mpl/class-method-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/class-method-2.java rename to src/MapleFE/test/java/java2mpl/class-method-2.java diff --git a/src/MapleFE/test/java2mpl/class-method-2.java.result b/src/MapleFE/test/java/java2mpl/class-method-2.java.result similarity index 87% rename from src/MapleFE/test/java2mpl/class-method-2.java.result rename to src/MapleFE/test/java/java2mpl/class-method-2.java.result index 3a49cec4d0c63bb39c2f62116642b5004d2651a6..63a9e974acf1a29c1e8253c016c96d886cfef76b 100644 --- a/src/MapleFE/test/java2mpl/class-method-2.java.result +++ b/src/MapleFE/test/java/java2mpl/class-method-2.java.result @@ -7,7 +7,7 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: + func foo(c) throws: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/class-multi-decl.java b/src/MapleFE/test/java/java2mpl/class-multi-decl.java similarity index 100% rename from src/MapleFE/test/java2mpl/class-multi-decl.java rename to src/MapleFE/test/java/java2mpl/class-multi-decl.java diff --git a/src/MapleFE/test/java2mpl/class-multi-decl.java.result b/src/MapleFE/test/java/java2mpl/class-multi-decl.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/class-multi-decl.java.result rename to src/MapleFE/test/java/java2mpl/class-multi-decl.java.result diff --git a/src/MapleFE/test/java2mpl/class-multi-line.java b/src/MapleFE/test/java/java2mpl/class-multi-line.java similarity index 100% rename from src/MapleFE/test/java2mpl/class-multi-line.java rename to src/MapleFE/test/java/java2mpl/class-multi-line.java diff --git a/src/MapleFE/test/java2mpl/class-multi-line.java.result b/src/MapleFE/test/java/java2mpl/class-multi-line.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/class-multi-line.java.result rename to src/MapleFE/test/java/java2mpl/class-multi-line.java.result diff --git a/src/MapleFE/test/java2mpl/class-nested.java b/src/MapleFE/test/java/java2mpl/class-nested.java similarity index 100% rename from src/MapleFE/test/java2mpl/class-nested.java rename to src/MapleFE/test/java/java2mpl/class-nested.java diff --git a/src/MapleFE/test/java2mpl/class-nested.java.result b/src/MapleFE/test/java/java2mpl/class-nested.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/class-nested.java.result rename to src/MapleFE/test/java/java2mpl/class-nested.java.result diff --git a/src/MapleFE/test/java2mpl/class-static-initializer.java b/src/MapleFE/test/java/java2mpl/class-static-initializer.java similarity index 100% rename from src/MapleFE/test/java2mpl/class-static-initializer.java rename to src/MapleFE/test/java/java2mpl/class-static-initializer.java diff --git a/src/MapleFE/test/java2mpl/class-static-initializer.java.result b/src/MapleFE/test/java/java2mpl/class-static-initializer.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/class-static-initializer.java.result rename to src/MapleFE/test/java/java2mpl/class-static-initializer.java.result diff --git a/src/MapleFE/test/java2mpl/class.java b/src/MapleFE/test/java/java2mpl/class.java similarity index 100% rename from src/MapleFE/test/java2mpl/class.java rename to src/MapleFE/test/java/java2mpl/class.java diff --git a/src/MapleFE/test/java2mpl/class.java.result b/src/MapleFE/test/java/java2mpl/class.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/class.java.result rename to src/MapleFE/test/java/java2mpl/class.java.result diff --git a/src/MapleFE/test/java2mpl/comment-1.java b/src/MapleFE/test/java/java2mpl/comment-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/comment-1.java rename to src/MapleFE/test/java/java2mpl/comment-1.java diff --git a/src/MapleFE/test/java2mpl/comment-1.java.result b/src/MapleFE/test/java/java2mpl/comment-1.java.result similarity index 85% rename from src/MapleFE/test/java2mpl/comment-1.java.result rename to src/MapleFE/test/java/java2mpl/comment-1.java.result index 80a92a3a9b58bfc354c4a28fd18fe06c52931e64..d45e86e510ff9949e14b2fcf8a7510269aad3893 100644 --- a/src/MapleFE/test/java2mpl/comment-1.java.result +++ b/src/MapleFE/test/java/java2mpl/comment-1.java.result @@ -6,7 +6,7 @@ class Point Instance Initializer: Constructors: - constructor Point() throws: + constructor Point(x) throws: this.x Assign x Methods: LocalClasses: diff --git a/src/MapleFE/test/java2mpl/comment-2.java b/src/MapleFE/test/java/java2mpl/comment-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/comment-2.java rename to src/MapleFE/test/java/java2mpl/comment-2.java diff --git a/src/MapleFE/test/java2mpl/comment-2.java.result b/src/MapleFE/test/java/java2mpl/comment-2.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/comment-2.java.result rename to src/MapleFE/test/java/java2mpl/comment-2.java.result diff --git a/src/MapleFE/test/java2mpl/comment-3.java b/src/MapleFE/test/java/java2mpl/comment-3.java similarity index 100% rename from src/MapleFE/test/java2mpl/comment-3.java rename to src/MapleFE/test/java/java2mpl/comment-3.java diff --git a/src/MapleFE/test/java2mpl/comment-3.java.result b/src/MapleFE/test/java/java2mpl/comment-3.java.result similarity index 85% rename from src/MapleFE/test/java2mpl/comment-3.java.result rename to src/MapleFE/test/java/java2mpl/comment-3.java.result index 80a92a3a9b58bfc354c4a28fd18fe06c52931e64..d45e86e510ff9949e14b2fcf8a7510269aad3893 100644 --- a/src/MapleFE/test/java2mpl/comment-3.java.result +++ b/src/MapleFE/test/java/java2mpl/comment-3.java.result @@ -6,7 +6,7 @@ class Point Instance Initializer: Constructors: - constructor Point() throws: + constructor Point(x) throws: this.x Assign x Methods: LocalClasses: diff --git a/src/MapleFE/test/java2mpl/comment-4.java b/src/MapleFE/test/java/java2mpl/comment-4.java similarity index 100% rename from src/MapleFE/test/java2mpl/comment-4.java rename to src/MapleFE/test/java/java2mpl/comment-4.java diff --git a/src/MapleFE/test/java2mpl/comment-4.java.result b/src/MapleFE/test/java/java2mpl/comment-4.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/comment-4.java.result rename to src/MapleFE/test/java/java2mpl/comment-4.java.result diff --git a/src/MapleFE/test/java2mpl/conversion-1.java b/src/MapleFE/test/java/java2mpl/conversion-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/conversion-1.java rename to src/MapleFE/test/java/java2mpl/conversion-1.java diff --git a/src/MapleFE/test/java2mpl/conversion-1.java.result b/src/MapleFE/test/java/java2mpl/conversion-1.java.result similarity index 56% rename from src/MapleFE/test/java2mpl/conversion-1.java.result rename to src/MapleFE/test/java/java2mpl/conversion-1.java.result index 823c0b8ee4045035c60b7ad6696c76c986ddf44b..486eae7281893a5a605b3b0647b4e11745186e3b 100644 --- a/src/MapleFE/test/java2mpl/conversion-1.java.result +++ b/src/MapleFE/test/java/java2mpl/conversion-1.java.result @@ -7,13 +7,16 @@ class Test Instance Initializer: Constructors: Methods: - func main() throws: - var:i=(int)12.5 + func main(args) throws: + Decl: i=(int)12.5 System.out.println("(int)12.5f==" Add i) - var:f=i + Decl: f=i System.out.print(f) - f Assign - var:d=Math.sin(f) + f Assign f Mul i + Decl: d=Math.sin(f) LocalClasses: LocalInterfaces: +Identifier:f has no decl. +Identifier:f has no decl. +Identifier:i has no decl. diff --git a/src/MapleFE/test/java2mpl/definite-assignment-1.java b/src/MapleFE/test/java/java2mpl/definite-assignment-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/definite-assignment-1.java rename to src/MapleFE/test/java/java2mpl/definite-assignment-1.java diff --git a/src/MapleFE/test/java2mpl/definite-assignment-1.java.result b/src/MapleFE/test/java/java2mpl/definite-assignment-1.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/definite-assignment-1.java.result rename to src/MapleFE/test/java/java2mpl/definite-assignment-1.java.result diff --git a/src/MapleFE/test/java2mpl/definite-assignment-2.java b/src/MapleFE/test/java/java2mpl/definite-assignment-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/definite-assignment-2.java rename to src/MapleFE/test/java/java2mpl/definite-assignment-2.java diff --git a/src/MapleFE/test/java2mpl/definite-assignment-2.java.result b/src/MapleFE/test/java/java2mpl/definite-assignment-2.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/definite-assignment-2.java.result rename to src/MapleFE/test/java/java2mpl/definite-assignment-2.java.result diff --git a/src/MapleFE/test/java2mpl/definite-assignment-3.java b/src/MapleFE/test/java/java2mpl/definite-assignment-3.java similarity index 100% rename from src/MapleFE/test/java2mpl/definite-assignment-3.java rename to src/MapleFE/test/java/java2mpl/definite-assignment-3.java diff --git a/src/MapleFE/test/java2mpl/definite-assignment-3.java.result b/src/MapleFE/test/java/java2mpl/definite-assignment-3.java.result similarity index 82% rename from src/MapleFE/test/java2mpl/definite-assignment-3.java.result rename to src/MapleFE/test/java/java2mpl/definite-assignment-3.java.result index 5066bbbf6afc1dbe2efdd8ab7cc4436d3066f89f..dacb216c91756bdea4d421503c0e1427f6afa5b1 100644 --- a/src/MapleFE/test/java2mpl/definite-assignment-3.java.result +++ b/src/MapleFE/test/java/java2mpl/definite-assignment-3.java.result @@ -8,11 +8,10 @@ class A Constructors: Methods: func foo() throws: - var:k + Decl: k cond-branch cond:v GT 0 Land (k Assign System.in.read()) GE 0 true branch : - System.out.println(k) - false branch : + System.out.println(k) false branch : LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/definite-assignment-4.java b/src/MapleFE/test/java/java2mpl/definite-assignment-4.java similarity index 100% rename from src/MapleFE/test/java2mpl/definite-assignment-4.java rename to src/MapleFE/test/java/java2mpl/definite-assignment-4.java diff --git a/src/MapleFE/test/java2mpl/definite-assignment-4.java.result b/src/MapleFE/test/java/java2mpl/definite-assignment-4.java.result similarity index 68% rename from src/MapleFE/test/java2mpl/definite-assignment-4.java.result rename to src/MapleFE/test/java/java2mpl/definite-assignment-4.java.result index c9954779e6e336d17c4ab81a1fb7c283799057ac..b682ea540fff5f1c93296b7d850111b67ac0d24b 100644 --- a/src/MapleFE/test/java2mpl/definite-assignment-4.java.result +++ b/src/MapleFE/test/java/java2mpl/definite-assignment-4.java.result @@ -8,9 +8,14 @@ class A Constructors: Methods: func foo() throws: - var:k + Decl: k while true k Assign n + cond-branch cond:k GE 5 + true branch : + break: + false branch : + n Assign 6 System.out.println(k) LocalClasses: diff --git a/src/MapleFE/test/java2mpl/definite-assignment-5.java b/src/MapleFE/test/java/java2mpl/definite-assignment-5.java similarity index 100% rename from src/MapleFE/test/java2mpl/definite-assignment-5.java rename to src/MapleFE/test/java/java2mpl/definite-assignment-5.java diff --git a/src/MapleFE/test/java2mpl/definite-assignment-5.java.result b/src/MapleFE/test/java/java2mpl/definite-assignment-5.java.result similarity index 76% rename from src/MapleFE/test/java2mpl/definite-assignment-5.java.result rename to src/MapleFE/test/java/java2mpl/definite-assignment-5.java.result index 96fed950ed666c113bb89f747d84303bcbb74ed3..ab7ce94f419de62fe6d9ec11a847a51f6b682b47 100644 --- a/src/MapleFE/test/java2mpl/definite-assignment-5.java.result +++ b/src/MapleFE/test/java/java2mpl/definite-assignment-5.java.result @@ -7,14 +7,12 @@ class A Instance Initializer: Constructors: Methods: - func flow() throws: - var:k + func flow(flag) throws: + Decl: k cond-branch cond:flag true branch : - k Assign 3 - false branch : + k Assign 3 false branch : k Assign 4 - System.out.println(k) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/definite-assignment-6.java b/src/MapleFE/test/java/java2mpl/definite-assignment-6.java similarity index 100% rename from src/MapleFE/test/java2mpl/definite-assignment-6.java rename to src/MapleFE/test/java/java2mpl/definite-assignment-6.java diff --git a/src/MapleFE/test/java2mpl/definite-assignment-6.java.result b/src/MapleFE/test/java/java2mpl/definite-assignment-6.java.result similarity index 82% rename from src/MapleFE/test/java2mpl/definite-assignment-6.java.result rename to src/MapleFE/test/java/java2mpl/definite-assignment-6.java.result index de1ccd48d8c787674c090b95980c5f7666f87e5d..72b74d484c82e50dc48ef519aa881d158f966453 100644 --- a/src/MapleFE/test/java2mpl/definite-assignment-6.java.result +++ b/src/MapleFE/test/java/java2mpl/definite-assignment-6.java.result @@ -8,11 +8,10 @@ class A Constructors: Methods: func foo() throws: - var:k + Decl: k cond-branch cond:v GT 0 Land (k Assign System.read()) GE 0 true branch : - System.println(k) - false branch : + System.println(k) false branch : LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/doloop-1.java b/src/MapleFE/test/java/java2mpl/doloop-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/doloop-1.java rename to src/MapleFE/test/java/java2mpl/doloop-1.java diff --git a/src/MapleFE/test/java2mpl/doloop-1.java.result b/src/MapleFE/test/java/java2mpl/doloop-1.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/doloop-1.java.result rename to src/MapleFE/test/java/java2mpl/doloop-1.java.result diff --git a/src/MapleFE/test/java2mpl/enum-1.java b/src/MapleFE/test/java/java2mpl/enum-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/enum-1.java rename to src/MapleFE/test/java/java2mpl/enum-1.java diff --git a/src/MapleFE/test/java2mpl/enum-1.java.result b/src/MapleFE/test/java/java2mpl/enum-1.java.result similarity index 90% rename from src/MapleFE/test/java2mpl/enum-1.java.result rename to src/MapleFE/test/java/java2mpl/enum-1.java.result index 29ffe431e3bbc4d109adc343ba3963faf902856b..b1a3b3dc78218547f76750421ccb9dcc06c2931f 100644 --- a/src/MapleFE/test/java2mpl/enum-1.java.result +++ b/src/MapleFE/test/java/java2mpl/enum-1.java.result @@ -6,7 +6,7 @@ class[JavaEnum] Coin value Instance Initializer: Constructors: - constructor Coin() throws: + constructor Coin(value) throws: this.value Assign value Methods: func value() throws: diff --git a/src/MapleFE/test/java2mpl/escape-seq.java b/src/MapleFE/test/java/java2mpl/escape-seq.java similarity index 100% rename from src/MapleFE/test/java2mpl/escape-seq.java rename to src/MapleFE/test/java/java2mpl/escape-seq.java diff --git a/src/MapleFE/test/java2mpl/escape-seq.java.result b/src/MapleFE/test/java/java2mpl/escape-seq.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/escape-seq.java.result rename to src/MapleFE/test/java/java2mpl/escape-seq.java.result diff --git a/src/MapleFE/test/java/java2mpl/field-1.java b/src/MapleFE/test/java/java2mpl/field-1.java new file mode 100644 index 0000000000000000000000000000000000000000..7fa020083f8c42382ac826d28be6e066aa8d148e --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/field-1.java @@ -0,0 +1,5 @@ +class A { + public byte B() { + c = e.getValue().getBytes().length; + } +} diff --git a/src/MapleFE/test/java/java2mpl/field-1.java.result b/src/MapleFE/test/java/java2mpl/field-1.java.result new file mode 100644 index 0000000000000000000000000000000000000000..08b23df1739f889476828801001425adb619fe28 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/field-1.java.result @@ -0,0 +1,15 @@ +Matched 25 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + + Instance Initializer: + Constructors: + Methods: + func B() throws: + c Assign e.getValue().getBytes().length + LocalClasses: + LocalInterfaces: + +Identifier:c has no decl. diff --git a/src/MapleFE/test/java/java2mpl/field-2.java b/src/MapleFE/test/java/java2mpl/field-2.java new file mode 100644 index 0000000000000000000000000000000000000000..4f53850954577c44e65e20053be6878b3ff37f1d --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/field-2.java @@ -0,0 +1,5 @@ +public class Sizing { + void main() { + println(parseInstance(bitSet).toPrintable()); + } +} diff --git a/src/MapleFE/test/java/java2mpl/field-2.java.result b/src/MapleFE/test/java/java2mpl/field-2.java.result new file mode 100644 index 0000000000000000000000000000000000000000..ad276786674345046f80573238f0691223717a24 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/field-2.java.result @@ -0,0 +1,14 @@ +Matched 23 tokens. +============= Module =========== +== Sub Tree == +class Sizing + Fields: + + Instance Initializer: + Constructors: + Methods: + func main() throws: + println(parseInstance(bitSet).toPrintable()) + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/java2mpl/field-3.java b/src/MapleFE/test/java/java2mpl/field-3.java new file mode 100644 index 0000000000000000000000000000000000000000..3a2f73bd35a290803827ebbf1da9db79af766f1d --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/field-3.java @@ -0,0 +1,25 @@ +// +//Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +// +//OpenArkFE is licensed under the Mulan PSL v2. +//You can use this software according to the terms and conditions of the Mulan PSL v2. +//You may obtain a copy of Mulan PSL v2 at: +// +// http://license.coscl.org.cn/MulanPSL2 +// +//THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +//FIT FOR A PARTICULAR PURPOSE. +//See the Mulan PSL v2 for more details. +// + +class B { + Point p; +} + +class Point { + int x; + void foo(B q) { + q.p.x = 1; + } +} diff --git a/src/MapleFE/test/java/java2mpl/field-3.java.result b/src/MapleFE/test/java/java2mpl/field-3.java.result new file mode 100644 index 0000000000000000000000000000000000000000..5511e77c8fa6d76ebeefd6e1a0e499654fa25606 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/field-3.java.result @@ -0,0 +1,25 @@ +Matched 7 tokens. +Matched 30 tokens. +============= Module =========== +== Sub Tree == +class B + Fields: + p + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Point + Fields: + x + Instance Initializer: + Constructors: + Methods: + func foo(q) throws: + q.p.x Assign 1 + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java2mpl/forloop-1.java b/src/MapleFE/test/java/java2mpl/forloop-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/forloop-1.java rename to src/MapleFE/test/java/java2mpl/forloop-1.java diff --git a/src/MapleFE/test/java2mpl/forloop-1.java.result b/src/MapleFE/test/java/java2mpl/forloop-1.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/forloop-1.java.result rename to src/MapleFE/test/java/java2mpl/forloop-1.java.result diff --git a/src/MapleFE/test/java2mpl/forloop-2.java b/src/MapleFE/test/java/java2mpl/forloop-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/forloop-2.java rename to src/MapleFE/test/java/java2mpl/forloop-2.java diff --git a/src/MapleFE/test/java2mpl/forloop-2.java.result b/src/MapleFE/test/java/java2mpl/forloop-2.java.result similarity index 82% rename from src/MapleFE/test/java2mpl/forloop-2.java.result rename to src/MapleFE/test/java/java2mpl/forloop-2.java.result index 3fd419113288e4558e75e69c0adbe2bc6ae823c6..de6b83a2cec7e703feccd478dde30b3a0949d36d 100644 --- a/src/MapleFE/test/java2mpl/forloop-2.java.result +++ b/src/MapleFE/test/java/java2mpl/forloop-2.java.result @@ -9,9 +9,8 @@ class A Methods: func foo() throws: for ( ) - Inc - k - iInc + PreInc k + i Inc LocalClasses: diff --git a/src/MapleFE/test/java2mpl/forloop-3.java b/src/MapleFE/test/java/java2mpl/forloop-3.java similarity index 100% rename from src/MapleFE/test/java2mpl/forloop-3.java rename to src/MapleFE/test/java/java2mpl/forloop-3.java diff --git a/src/MapleFE/test/java2mpl/forloop-3.java.result b/src/MapleFE/test/java/java2mpl/forloop-3.java.result similarity index 82% rename from src/MapleFE/test/java2mpl/forloop-3.java.result rename to src/MapleFE/test/java/java2mpl/forloop-3.java.result index db96d08b6c2d35814e60db931f53007844d0077f..77669d056798d30837c930e2a698e66707ea8457 100644 --- a/src/MapleFE/test/java2mpl/forloop-3.java.result +++ b/src/MapleFE/test/java/java2mpl/forloop-3.java.result @@ -9,9 +9,8 @@ class A Methods: func foo() throws: for ( ) - Inc - k - iInc + PreInc k + i Inc LocalClasses: diff --git a/src/MapleFE/test/java2mpl/forloop-4.java b/src/MapleFE/test/java/java2mpl/forloop-4.java similarity index 100% rename from src/MapleFE/test/java2mpl/forloop-4.java rename to src/MapleFE/test/java/java2mpl/forloop-4.java diff --git a/src/MapleFE/test/java2mpl/forloop-4.java.result b/src/MapleFE/test/java/java2mpl/forloop-4.java.result similarity index 82% rename from src/MapleFE/test/java2mpl/forloop-4.java.result rename to src/MapleFE/test/java/java2mpl/forloop-4.java.result index 08c5830eb8cd2bec5ae7d1a3ac64acf5608c0ad1..54c4d8cd6fa532770b043c1bf7cc15562422a5b7 100644 --- a/src/MapleFE/test/java2mpl/forloop-4.java.result +++ b/src/MapleFE/test/java/java2mpl/forloop-4.java.result @@ -9,9 +9,9 @@ class A Methods: func foo() throws: for ( ) - kInc + k Inc - iInc + i Inc LocalClasses: diff --git a/src/MapleFE/test/java2mpl/func-body-2.java b/src/MapleFE/test/java/java2mpl/func-body-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/func-body-2.java rename to src/MapleFE/test/java/java2mpl/func-body-2.java diff --git a/src/MapleFE/test/java2mpl/func-body-2.java.result b/src/MapleFE/test/java/java2mpl/func-body-2.java.result similarity index 88% rename from src/MapleFE/test/java2mpl/func-body-2.java.result rename to src/MapleFE/test/java/java2mpl/func-body-2.java.result index b95b2f11e5ce3466ae72bc353880bfe79a634f18..95a46f76b202a9ae5af20a270bedc5bfff676897 100644 --- a/src/MapleFE/test/java2mpl/func-body-2.java.result +++ b/src/MapleFE/test/java/java2mpl/func-body-2.java.result @@ -7,7 +7,7 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: + func foo(c,b) throws: c Assign 3 return c Add b LocalClasses: diff --git a/src/MapleFE/test/java2mpl/func-body-3.java b/src/MapleFE/test/java/java2mpl/func-body-3.java similarity index 100% rename from src/MapleFE/test/java2mpl/func-body-3.java rename to src/MapleFE/test/java/java2mpl/func-body-3.java diff --git a/src/MapleFE/test/java2mpl/func-body-3.java.result b/src/MapleFE/test/java/java2mpl/func-body-3.java.result similarity index 77% rename from src/MapleFE/test/java2mpl/func-body-3.java.result rename to src/MapleFE/test/java/java2mpl/func-body-3.java.result index 71fa07343af0c07a17c35b1fb4250d979231c687..27174deac163f7d3d7c34f0df14ac9959b7847cd 100644 --- a/src/MapleFE/test/java2mpl/func-body-3.java.result +++ b/src/MapleFE/test/java/java2mpl/func-body-3.java.result @@ -8,9 +8,11 @@ class Test Constructors: Methods: func main() throws: - var:i=12 + Decl: i=12 i Assign 2 i Assign 1 LocalClasses: LocalInterfaces: +Identifier:i has no decl. +Identifier:i has no decl. diff --git a/src/MapleFE/test/java2mpl/func-body-4.java b/src/MapleFE/test/java/java2mpl/func-body-4.java similarity index 100% rename from src/MapleFE/test/java2mpl/func-body-4.java rename to src/MapleFE/test/java/java2mpl/func-body-4.java diff --git a/src/MapleFE/test/java2mpl/func-body-4.java.result b/src/MapleFE/test/java/java2mpl/func-body-4.java.result similarity index 79% rename from src/MapleFE/test/java2mpl/func-body-4.java.result rename to src/MapleFE/test/java/java2mpl/func-body-4.java.result index dbb7ad1bb598bc5fe78c85446c5d7691f7a1ce07..def16e9fea4c4af5b4a744e39884f78b2589f3ce 100644 --- a/src/MapleFE/test/java2mpl/func-body-4.java.result +++ b/src/MapleFE/test/java/java2mpl/func-body-4.java.result @@ -7,9 +7,9 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: + func foo(c,b) throws: return c Add b - func foo() throws: + func foo(c) throws: return c LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/func-body.java b/src/MapleFE/test/java/java2mpl/func-body.java similarity index 100% rename from src/MapleFE/test/java2mpl/func-body.java rename to src/MapleFE/test/java/java2mpl/func-body.java diff --git a/src/MapleFE/test/java2mpl/func-body.java.result b/src/MapleFE/test/java/java2mpl/func-body.java.result similarity index 87% rename from src/MapleFE/test/java2mpl/func-body.java.result rename to src/MapleFE/test/java/java2mpl/func-body.java.result index 94281ad6d4d6e363fef569580b34a2c2308e1709..8b87a7f5f3bf5d6f487c466bbf24c40afbe73e6a 100644 --- a/src/MapleFE/test/java2mpl/func-body.java.result +++ b/src/MapleFE/test/java/java2mpl/func-body.java.result @@ -7,7 +7,7 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: + func foo(c,b) throws: return c Add b LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/func-multi-param.java b/src/MapleFE/test/java/java2mpl/func-multi-param.java similarity index 100% rename from src/MapleFE/test/java2mpl/func-multi-param.java rename to src/MapleFE/test/java/java2mpl/func-multi-param.java diff --git a/src/MapleFE/test/java2mpl/func-multi-param.java.result b/src/MapleFE/test/java/java2mpl/func-multi-param.java.result similarity index 75% rename from src/MapleFE/test/java2mpl/func-multi-param.java.result rename to src/MapleFE/test/java/java2mpl/func-multi-param.java.result index 9a8abb5a85217e09b46adae374347eb7faf7a5e5..adc37165f90e4d0093bae09fcd9350c922e5c3bb 100644 --- a/src/MapleFE/test/java2mpl/func-multi-param.java.result +++ b/src/MapleFE/test/java/java2mpl/func-multi-param.java.result @@ -7,8 +7,8 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: - func bar() throws: + func foo(c,b) throws: + func bar(i,b,c) throws: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/others/generate-result.sh b/src/MapleFE/test/java/java2mpl/generate-result.sh similarity index 92% rename from src/MapleFE/test/others/generate-result.sh rename to src/MapleFE/test/java/java2mpl/generate-result.sh index bbd3acd878bd41d3a31fc5123972e954d7c9fcd0..08b3acc3b58dc1585fb15888064b004629e72007 100755 --- a/src/MapleFE/test/others/generate-result.sh +++ b/src/MapleFE/test/java/java2mpl/generate-result.sh @@ -17,5 +17,5 @@ FILES=$(pwd)/*.java for f in $FILES do echo "Generating result for $f ..." - ../../output/java/java2mpl $f > $f.result + ../../../output/java/java/java2mpl $f > $f.result done diff --git a/src/MapleFE/test/java2mpl/if-else-1.java b/src/MapleFE/test/java/java2mpl/if-else-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/if-else-1.java rename to src/MapleFE/test/java/java2mpl/if-else-1.java diff --git a/src/MapleFE/test/java2mpl/if-else-1.java.result b/src/MapleFE/test/java/java2mpl/if-else-1.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/if-else-1.java.result rename to src/MapleFE/test/java/java2mpl/if-else-1.java.result diff --git a/src/MapleFE/test/java2mpl/if-else-2.java b/src/MapleFE/test/java/java2mpl/if-else-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/if-else-2.java rename to src/MapleFE/test/java/java2mpl/if-else-2.java diff --git a/src/MapleFE/test/java2mpl/if-else-2.java.result b/src/MapleFE/test/java/java2mpl/if-else-2.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/if-else-2.java.result rename to src/MapleFE/test/java/java2mpl/if-else-2.java.result diff --git a/src/MapleFE/test/java2mpl/if-else-3.java b/src/MapleFE/test/java/java2mpl/if-else-3.java similarity index 100% rename from src/MapleFE/test/java2mpl/if-else-3.java rename to src/MapleFE/test/java/java2mpl/if-else-3.java diff --git a/src/MapleFE/test/java2mpl/if-else-3.java.result b/src/MapleFE/test/java/java2mpl/if-else-3.java.result similarity index 89% rename from src/MapleFE/test/java2mpl/if-else-3.java.result rename to src/MapleFE/test/java/java2mpl/if-else-3.java.result index e8f85eb80675776505131652c9c166686f5a35c7..02239e703020f1071f35269c604fef2fe80369af 100644 --- a/src/MapleFE/test/java2mpl/if-else-3.java.result +++ b/src/MapleFE/test/java/java2mpl/if-else-3.java.result @@ -14,8 +14,7 @@ class A false branch : cond-branch cond:b true branch : - return 3 - false branch : + return 3 false branch : return 1 diff --git a/src/MapleFE/test/java2mpl/illegal-expr-2.java b/src/MapleFE/test/java/java2mpl/illegal-expr-2.java.disabled similarity index 100% rename from src/MapleFE/test/java2mpl/illegal-expr-2.java rename to src/MapleFE/test/java/java2mpl/illegal-expr-2.java.disabled diff --git a/src/MapleFE/test/java2mpl/illegal-expr-2.java.result b/src/MapleFE/test/java/java2mpl/illegal-expr-2.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/illegal-expr-2.java.result rename to src/MapleFE/test/java/java2mpl/illegal-expr-2.java.result diff --git a/src/MapleFE/test/java2mpl/illegal-expr.java b/src/MapleFE/test/java/java2mpl/illegal-expr.java.disabled similarity index 100% rename from src/MapleFE/test/java2mpl/illegal-expr.java rename to src/MapleFE/test/java/java2mpl/illegal-expr.java.disabled diff --git a/src/MapleFE/test/java2mpl/illegal-expr.java.result b/src/MapleFE/test/java/java2mpl/illegal-expr.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/illegal-expr.java.result rename to src/MapleFE/test/java/java2mpl/illegal-expr.java.result diff --git a/src/MapleFE/test/java2mpl/interface-field.java b/src/MapleFE/test/java/java2mpl/interface-field.java similarity index 100% rename from src/MapleFE/test/java2mpl/interface-field.java rename to src/MapleFE/test/java/java2mpl/interface-field.java diff --git a/src/MapleFE/test/java2mpl/interface-field.java.result b/src/MapleFE/test/java/java2mpl/interface-field.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/interface-field.java.result rename to src/MapleFE/test/java/java2mpl/interface-field.java.result diff --git a/src/MapleFE/test/java2mpl/label-stmt.java b/src/MapleFE/test/java/java2mpl/label-stmt.java similarity index 100% rename from src/MapleFE/test/java2mpl/label-stmt.java rename to src/MapleFE/test/java/java2mpl/label-stmt.java diff --git a/src/MapleFE/test/java2mpl/label-stmt.java.result b/src/MapleFE/test/java/java2mpl/label-stmt.java.result similarity index 92% rename from src/MapleFE/test/java2mpl/label-stmt.java.result rename to src/MapleFE/test/java/java2mpl/label-stmt.java.result index bc0929a2817f385360eed4bc847c985e6f193ac3..524f7cd81391e216eaba2a56c6b8ecf37d8f14dd 100644 --- a/src/MapleFE/test/java2mpl/label-stmt.java.result +++ b/src/MapleFE/test/java/java2mpl/label-stmt.java.result @@ -9,7 +9,7 @@ class A Methods: func loseEdges() throws: search: - break search + break:search LocalClasses: diff --git a/src/MapleFE/test/java2mpl/lambda-1.java b/src/MapleFE/test/java/java2mpl/lambda-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/lambda-1.java rename to src/MapleFE/test/java/java2mpl/lambda-1.java diff --git a/src/MapleFE/test/java2mpl/lambda-1.java.result b/src/MapleFE/test/java/java2mpl/lambda-1.java.result similarity index 90% rename from src/MapleFE/test/java2mpl/lambda-1.java.result rename to src/MapleFE/test/java/java2mpl/lambda-1.java.result index 44e7e9238f5c5d76810ebb0837ccc2e4e20ac85d..16ea64b335bac5e1dfc3b385d142bd4aaf2d39ed 100644 --- a/src/MapleFE/test/java2mpl/lambda-1.java.result +++ b/src/MapleFE/test/java/java2mpl/lambda-1.java.result @@ -8,8 +8,7 @@ class Point Constructors: Methods: func foo() throws: - bar(() -> 42 -) + bar(() -> 42) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/lambda-2.java b/src/MapleFE/test/java/java2mpl/lambda-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/lambda-2.java rename to src/MapleFE/test/java/java2mpl/lambda-2.java diff --git a/src/MapleFE/test/java2mpl/lambda-2.java.result b/src/MapleFE/test/java/java2mpl/lambda-2.java.result similarity index 78% rename from src/MapleFE/test/java2mpl/lambda-2.java.result rename to src/MapleFE/test/java/java2mpl/lambda-2.java.result index b122cfbdb909338b687e18e76255885d36037005..5cc1b420788f5c4f7f1bc668b4227a7c2d25e22a 100644 --- a/src/MapleFE/test/java2mpl/lambda-2.java.result +++ b/src/MapleFE/test/java/java2mpl/lambda-2.java.result @@ -13,13 +13,13 @@ class Main Instance Initializer: Constructors: Methods: - func main() throws: - var:numbers=new ArrayList + func main(args) throws: + Decl: numbers=new ArrayList() numbers.add(5) numbers.add(9) numbers.add(8) numbers.add(1) - var:method=(n) -> System.out.println(n) + Decl: method=(n) -> System.out.println(n) numbers.forEach(method) LocalClasses: diff --git a/src/MapleFE/test/java2mpl/lambda-3.java b/src/MapleFE/test/java/java2mpl/lambda-3.java similarity index 100% rename from src/MapleFE/test/java2mpl/lambda-3.java rename to src/MapleFE/test/java/java2mpl/lambda-3.java diff --git a/src/MapleFE/test/java2mpl/lambda-3.java.result b/src/MapleFE/test/java/java2mpl/lambda-3.java.result similarity index 84% rename from src/MapleFE/test/java2mpl/lambda-3.java.result rename to src/MapleFE/test/java/java2mpl/lambda-3.java.result index 114e7b196e8479492d4f475732ea58d7509a1d47..0fb5dcb10fd362b5e55248f08f92321b6c1913f7 100644 --- a/src/MapleFE/test/java2mpl/lambda-3.java.result +++ b/src/MapleFE/test/java/java2mpl/lambda-3.java.result @@ -10,8 +10,8 @@ class Main Instance Initializer: Constructors: Methods: - func main() throws: - var:numbers=new ArrayList + func main(args) throws: + Decl: numbers=new ArrayList() numbers.add(5) numbers.add(9) numbers.add(8) diff --git a/src/MapleFE/test/java2mpl/lambda-4.java b/src/MapleFE/test/java/java2mpl/lambda-4.java similarity index 100% rename from src/MapleFE/test/java2mpl/lambda-4.java rename to src/MapleFE/test/java/java2mpl/lambda-4.java diff --git a/src/MapleFE/test/java2mpl/lambda-4.java.result b/src/MapleFE/test/java/java2mpl/lambda-4.java.result similarity index 63% rename from src/MapleFE/test/java2mpl/lambda-4.java.result rename to src/MapleFE/test/java/java2mpl/lambda-4.java.result index 7adeb147e3af0a80394bba7f21c7f4d21c7ad890..f7c61355a8bd9c2ce61c1027292f29e0a192e3b5 100644 --- a/src/MapleFE/test/java2mpl/lambda-4.java.result +++ b/src/MapleFE/test/java/java2mpl/lambda-4.java.result @@ -6,7 +6,7 @@ interface StringFunction Fields: Methods: - func run() throws: + func run(str) throws: == Sub Tree == class Main @@ -15,15 +15,13 @@ class Main Instance Initializer: Constructors: Methods: - func main() throws: - var:exclaim=(s) -> s Add "!" - - var:ask=(s) -> s Add "?" - + func main(args) throws: + Decl: exclaim=(s) -> s Add "!" + Decl: ask=(s) -> s Add "?" printFormatted("Hello",exclaim) printFormatted("Hello",ask) - func printFormatted() throws: - var:result=format.run(str) + func printFormatted(str,format) throws: + Decl: result=format.run(str) System.out.println(result) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/lambda-5.java b/src/MapleFE/test/java/java2mpl/lambda-5.java similarity index 100% rename from src/MapleFE/test/java2mpl/lambda-5.java rename to src/MapleFE/test/java/java2mpl/lambda-5.java diff --git a/src/MapleFE/test/java2mpl/lambda-5.java.result b/src/MapleFE/test/java/java2mpl/lambda-5.java.result similarity index 70% rename from src/MapleFE/test/java2mpl/lambda-5.java.result rename to src/MapleFE/test/java/java2mpl/lambda-5.java.result index 9f9aa2932015d632f7a10b0c950fe64332b145c6..e4892c90d2521fa5e2b1cc01315ec9fa5003e030 100644 --- a/src/MapleFE/test/java2mpl/lambda-5.java.result +++ b/src/MapleFE/test/java/java2mpl/lambda-5.java.result @@ -14,18 +14,21 @@ class Point Constructors: Methods: func foo() throws: - var:m + Decl: m m Assign () -> m Assign () -> 42 - m Assign () -> null - m Assign () -> return 42 m Assign () -> system.gc() - m Assign () -> x Add y - + m Assign (x,y) -> x Add y LocalClasses: LocalInterfaces: +Identifier:m has no decl. +Identifier:m has no decl. +Identifier:m has no decl. +Identifier:m has no decl. +Identifier:m has no decl. +Identifier:m has no decl. diff --git a/src/MapleFE/test/java2mpl/left-rec-1.java b/src/MapleFE/test/java/java2mpl/left-rec-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/left-rec-1.java rename to src/MapleFE/test/java/java2mpl/left-rec-1.java diff --git a/src/MapleFE/test/java2mpl/left-rec-1.java.result b/src/MapleFE/test/java/java2mpl/left-rec-1.java.result similarity index 84% rename from src/MapleFE/test/java2mpl/left-rec-1.java.result rename to src/MapleFE/test/java/java2mpl/left-rec-1.java.result index 6e55437b2ccd830ae8aba352a63855e46b0b326a..bc2788a9097ee1e454a8b4b79a6d1cbad7d168da 100644 --- a/src/MapleFE/test/java2mpl/left-rec-1.java.result +++ b/src/MapleFE/test/java/java2mpl/left-rec-1.java.result @@ -10,8 +10,7 @@ class A func foo() throws: cond-branch cond:(k Assign System.in.read()) GE 0 true branch : - System.out.println(k) - false branch : + System.out.println(k) false branch : LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/literal-float-double.java b/src/MapleFE/test/java/java2mpl/literal-float-double.java similarity index 100% rename from src/MapleFE/test/java2mpl/literal-float-double.java rename to src/MapleFE/test/java/java2mpl/literal-float-double.java diff --git a/src/MapleFE/test/java2mpl/literal-float-double.java.result b/src/MapleFE/test/java/java2mpl/literal-float-double.java.result similarity index 84% rename from src/MapleFE/test/java2mpl/literal-float-double.java.result rename to src/MapleFE/test/java/java2mpl/literal-float-double.java.result index 5f1bf6992b63ece0ed6f720b0efd526749804fe0..9d218a0b075eecae25ce5dc6e1f3d275ab359a2a 100644 --- a/src/MapleFE/test/java2mpl/literal-float-double.java.result +++ b/src/MapleFE/test/java/java2mpl/literal-float-double.java.result @@ -8,8 +8,8 @@ class A Constructors: Methods: func foo() throws: - var:a=11.1 - var:a=22.2 + Decl: a=11.1 + Decl: a=22.2 LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/literal-integer-2.java b/src/MapleFE/test/java/java2mpl/literal-integer-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/literal-integer-2.java rename to src/MapleFE/test/java/java2mpl/literal-integer-2.java diff --git a/src/MapleFE/test/java2mpl/literal-integer-2.java.result b/src/MapleFE/test/java/java2mpl/literal-integer-2.java.result similarity index 91% rename from src/MapleFE/test/java2mpl/literal-integer-2.java.result rename to src/MapleFE/test/java/java2mpl/literal-integer-2.java.result index abf79b059c13b8041cc6b659bf3ee076356d444e..1a5bb2d45d38ce0132e33e4eaabe9a42b0782b65 100644 --- a/src/MapleFE/test/java2mpl/literal-integer-2.java.result +++ b/src/MapleFE/test/java/java2mpl/literal-integer-2.java.result @@ -8,7 +8,7 @@ class A Constructors: Methods: func foo() throws: - var:a=273 + Decl: a=273 LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/literal-integer-3.java b/src/MapleFE/test/java/java2mpl/literal-integer-3.java similarity index 100% rename from src/MapleFE/test/java2mpl/literal-integer-3.java rename to src/MapleFE/test/java/java2mpl/literal-integer-3.java diff --git a/src/MapleFE/test/java2mpl/literal-integer-3.java.result b/src/MapleFE/test/java/java2mpl/literal-integer-3.java.result similarity index 78% rename from src/MapleFE/test/java2mpl/literal-integer-3.java.result rename to src/MapleFE/test/java/java2mpl/literal-integer-3.java.result index 27e73a24f4e60eceba4e6b702479ef334cc5aacc..82c1284467f4d864f07fde4f01a0cd96e4f8db3f 100644 --- a/src/MapleFE/test/java2mpl/literal-integer-3.java.result +++ b/src/MapleFE/test/java/java2mpl/literal-integer-3.java.result @@ -8,9 +8,11 @@ class A Constructors: Methods: func foo() throws: - var:a=273 + Decl: a=273 a Assign 268435455 a Assign -1 LocalClasses: LocalInterfaces: +Identifier:a has no decl. +Identifier:a has no decl. diff --git a/src/MapleFE/test/java2mpl/literal-integer.java b/src/MapleFE/test/java/java2mpl/literal-integer.java similarity index 100% rename from src/MapleFE/test/java2mpl/literal-integer.java rename to src/MapleFE/test/java/java2mpl/literal-integer.java diff --git a/src/MapleFE/test/java2mpl/literal-integer.java.result b/src/MapleFE/test/java/java2mpl/literal-integer.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/literal-integer.java.result rename to src/MapleFE/test/java/java2mpl/literal-integer.java.result diff --git a/src/MapleFE/test/java2mpl/literal-string-2.java b/src/MapleFE/test/java/java2mpl/literal-string-2.java similarity index 96% rename from src/MapleFE/test/java2mpl/literal-string-2.java rename to src/MapleFE/test/java/java2mpl/literal-string-2.java index ca47e9ef5dc4e5e1ede1446154728b82ef09bbc1..c0dfe8fc3d012602cfa29afc5d3926fa0eaa7557 100644 --- a/src/MapleFE/test/java2mpl/literal-string-2.java +++ b/src/MapleFE/test/java/java2mpl/literal-string-2.java @@ -13,6 +13,7 @@ //See the Mulan PSL v2 for more details. // class A { + void write(String s); void foo() { write("doesn't"); write("doesn\'t"); diff --git a/src/MapleFE/test/java2mpl/literal-string-2.java.result b/src/MapleFE/test/java/java2mpl/literal-string-2.java.result similarity index 74% rename from src/MapleFE/test/java2mpl/literal-string-2.java.result rename to src/MapleFE/test/java/java2mpl/literal-string-2.java.result index e08faab0e035bc782e0a08d15c571bf1ef0dc80e..7699fb51c96a52def125d2b29ff9cae1b195d9af 100644 --- a/src/MapleFE/test/java2mpl/literal-string-2.java.result +++ b/src/MapleFE/test/java/java2mpl/literal-string-2.java.result @@ -1,4 +1,4 @@ -Matched 20 tokens. +Matched 27 tokens. ============= Module =========== == Sub Tree == class A @@ -7,9 +7,10 @@ class A Instance Initializer: Constructors: Methods: + func write(s) throws: func foo() throws: write("doesn't") - write("doesn't") + write("doesn\'t") LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/literal-string.java b/src/MapleFE/test/java/java2mpl/literal-string.java similarity index 96% rename from src/MapleFE/test/java2mpl/literal-string.java rename to src/MapleFE/test/java/java2mpl/literal-string.java index c3aaa6176a67e590e888242ffc60c43d86afdebb..7eb79933aa51f92fd62c9d55f5b598b2d4fded85 100644 --- a/src/MapleFE/test/java2mpl/literal-string.java +++ b/src/MapleFE/test/java/java2mpl/literal-string.java @@ -13,6 +13,7 @@ //See the Mulan PSL v2 for more details. // class A { + void write(String s); void foo() { write("test\n"); } diff --git a/src/MapleFE/test/java2mpl/literal-string.java.result b/src/MapleFE/test/java/java2mpl/literal-string.java.result similarity index 72% rename from src/MapleFE/test/java2mpl/literal-string.java.result rename to src/MapleFE/test/java/java2mpl/literal-string.java.result index 1f3dd1f0ba06163f48ca36de7a2e7c4d0e50c67d..145e330401b210f7edb9cff65e3353f4a1d87a93 100644 --- a/src/MapleFE/test/java2mpl/literal-string.java.result +++ b/src/MapleFE/test/java/java2mpl/literal-string.java.result @@ -1,4 +1,4 @@ -Matched 15 tokens. +Matched 22 tokens. ============= Module =========== == Sub Tree == class A @@ -7,9 +7,9 @@ class A Instance Initializer: Constructors: Methods: + func write(s) throws: func foo() throws: - write("test -") + write("test\n") LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/literal-this-1.java b/src/MapleFE/test/java/java2mpl/literal-this-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/literal-this-1.java rename to src/MapleFE/test/java/java2mpl/literal-this-1.java diff --git a/src/MapleFE/test/java2mpl/literal-this-1.java.result b/src/MapleFE/test/java/java2mpl/literal-this-1.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/literal-this-1.java.result rename to src/MapleFE/test/java/java2mpl/literal-this-1.java.result diff --git a/src/MapleFE/test/java2mpl/literal-this-2.java b/src/MapleFE/test/java/java2mpl/literal-this-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/literal-this-2.java rename to src/MapleFE/test/java/java2mpl/literal-this-2.java diff --git a/src/MapleFE/test/java2mpl/literal-this-2.java.result b/src/MapleFE/test/java/java2mpl/literal-this-2.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/literal-this-2.java.result rename to src/MapleFE/test/java/java2mpl/literal-this-2.java.result diff --git a/src/MapleFE/test/java2mpl/literal-unicode.java b/src/MapleFE/test/java/java2mpl/literal-unicode.java similarity index 100% rename from src/MapleFE/test/java2mpl/literal-unicode.java rename to src/MapleFE/test/java/java2mpl/literal-unicode.java diff --git a/src/MapleFE/test/java2mpl/literal-unicode.java.result b/src/MapleFE/test/java/java2mpl/literal-unicode.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/literal-unicode.java.result rename to src/MapleFE/test/java/java2mpl/literal-unicode.java.result diff --git a/src/MapleFE/test/java2mpl/local-class.java b/src/MapleFE/test/java/java2mpl/local-class.java similarity index 100% rename from src/MapleFE/test/java2mpl/local-class.java rename to src/MapleFE/test/java/java2mpl/local-class.java diff --git a/src/MapleFE/test/java2mpl/local-class.java.result b/src/MapleFE/test/java/java2mpl/local-class.java.result similarity index 98% rename from src/MapleFE/test/java2mpl/local-class.java.result rename to src/MapleFE/test/java/java2mpl/local-class.java.result index 663f73158c2a3f2a351f96443fa90985342fc1ac..94a8dc2d57c2e3f92d87ded085b7bb6f95b9374e 100644 --- a/src/MapleFE/test/java2mpl/local-class.java.result +++ b/src/MapleFE/test/java/java2mpl/local-class.java.result @@ -8,7 +8,7 @@ class Global Constructors: Methods: func foo() throws: - new Cyclic + new Cyclic() class Cyclic Fields: diff --git a/src/MapleFE/test/java2mpl/new-stmt-1.java b/src/MapleFE/test/java/java2mpl/new-stmt-1.java similarity index 97% rename from src/MapleFE/test/java2mpl/new-stmt-1.java rename to src/MapleFE/test/java/java2mpl/new-stmt-1.java index 989e7968879e403c0c1d1f52b49232d501a3f61c..bdd4b5513fcf65d3fda6a20e7f27185f551cc19e 100644 --- a/src/MapleFE/test/java2mpl/new-stmt-1.java +++ b/src/MapleFE/test/java/java2mpl/new-stmt-1.java @@ -19,4 +19,5 @@ class A { } class Cyclic { + Cyclic() {} } diff --git a/src/MapleFE/test/java2mpl/new-stmt-1.java.result b/src/MapleFE/test/java/java2mpl/new-stmt-1.java.result similarity index 82% rename from src/MapleFE/test/java2mpl/new-stmt-1.java.result rename to src/MapleFE/test/java/java2mpl/new-stmt-1.java.result index 4785ac1f04b0f462d9cb8377472b482aceb337f8..38cc51684021ccf647c1be343aeff4babdfd0138 100644 --- a/src/MapleFE/test/java2mpl/new-stmt-1.java.result +++ b/src/MapleFE/test/java/java2mpl/new-stmt-1.java.result @@ -1,5 +1,5 @@ Matched 15 tokens. -Matched 19 tokens. +Matched 24 tokens. ============= Module =========== == Sub Tree == class A @@ -9,7 +9,7 @@ class A Constructors: Methods: func foo() throws: - new Cyclic + new Cyclic() LocalClasses: LocalInterfaces: @@ -19,6 +19,7 @@ class Cyclic Instance Initializer: Constructors: + constructor Cyclic() throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/new-stmt-2.java b/src/MapleFE/test/java/java2mpl/new-stmt-2.java similarity index 97% rename from src/MapleFE/test/java2mpl/new-stmt-2.java rename to src/MapleFE/test/java/java2mpl/new-stmt-2.java index a0156ccc386cc5be0dcdbe870ff686c82f05bda3..6ee5b41ae2c94a87fb25b4fddd9f7419c12e3e3d 100644 --- a/src/MapleFE/test/java2mpl/new-stmt-2.java +++ b/src/MapleFE/test/java/java2mpl/new-stmt-2.java @@ -19,4 +19,5 @@ class A { } class Cyclic { + Cyclic(int i) {} } diff --git a/src/MapleFE/test/java2mpl/new-stmt-2.java.result b/src/MapleFE/test/java/java2mpl/new-stmt-2.java.result similarity index 75% rename from src/MapleFE/test/java2mpl/new-stmt-2.java.result rename to src/MapleFE/test/java/java2mpl/new-stmt-2.java.result index 8706e6ffe58523083074c28d47d300efdfa1890d..7a792a923733e75bd9219d1c6c587ca8a68e919b 100644 --- a/src/MapleFE/test/java2mpl/new-stmt-2.java.result +++ b/src/MapleFE/test/java/java2mpl/new-stmt-2.java.result @@ -1,5 +1,5 @@ Matched 18 tokens. -Matched 22 tokens. +Matched 29 tokens. ============= Module =========== == Sub Tree == class A @@ -8,8 +8,8 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: - new Cyclic + func foo(a) throws: + new Cyclic(a) LocalClasses: LocalInterfaces: @@ -19,6 +19,7 @@ class Cyclic Instance Initializer: Constructors: + constructor Cyclic(i) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/new-stmt-3.java b/src/MapleFE/test/java/java2mpl/new-stmt-3.java similarity index 100% rename from src/MapleFE/test/java2mpl/new-stmt-3.java rename to src/MapleFE/test/java/java2mpl/new-stmt-3.java diff --git a/src/MapleFE/test/java2mpl/new-stmt-3.java.result b/src/MapleFE/test/java/java2mpl/new-stmt-3.java.result similarity index 90% rename from src/MapleFE/test/java2mpl/new-stmt-3.java.result rename to src/MapleFE/test/java/java2mpl/new-stmt-3.java.result index 195cc40edeb05f2eb020078f2093a3811bb36fa0..54d6721ee9ed140d8614f17dfc776f155ceaabf8 100644 --- a/src/MapleFE/test/java2mpl/new-stmt-3.java.result +++ b/src/MapleFE/test/java/java2mpl/new-stmt-3.java.result @@ -7,7 +7,7 @@ class Outer Instance Initializer: Constructors: constructor Outer() throws: - var:i=new Inner + Decl: i=new Inner() Methods: LocalClasses: class Inner @@ -17,7 +17,7 @@ class Outer Constructors: Methods: func foo() throws: - var:i= + Decl: i= LocalClasses: class Inner2 Fields: @@ -32,7 +32,7 @@ class Outer Instance Initializer: Constructors: constructor Inner3() throws: - var:i2=new Inner2 + Decl: i2=new Inner2() Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/sharedfe/add3.java b/src/MapleFE/test/java/java2mpl/new-stmt-4.java similarity index 88% rename from src/MapleFE/test/sharedfe/add3.java rename to src/MapleFE/test/java/java2mpl/new-stmt-4.java index 1c9b539ae78938be3d630dcaeb6e3924679dbac0..fe5428e599323109a4837de0c21d38894030b52c 100644 --- a/src/MapleFE/test/sharedfe/add3.java +++ b/src/MapleFE/test/java/java2mpl/new-stmt-4.java @@ -13,9 +13,10 @@ //See the Mulan PSL v2 for more details. // -int foo(int a, int b) { - int c; - - c = a + b + c; - return c; +class A { + A(int x) {} + void foo() { + A a; + a = new A(3); + } } diff --git a/src/MapleFE/test/java/java2mpl/new-stmt-4.java.result b/src/MapleFE/test/java/java2mpl/new-stmt-4.java.result new file mode 100644 index 0000000000000000000000000000000000000000..4836a70c96e244e9044b81e52801a680f1b3c411 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/new-stmt-4.java.result @@ -0,0 +1,17 @@ +Matched 28 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + + Instance Initializer: + Constructors: + constructor A(x) throws: + Methods: + func foo() throws: + Decl: a + a Assign new A(3) + LocalClasses: + LocalInterfaces: + +Identifier:a has no decl. diff --git a/src/MapleFE/test/java2mpl/point-list.java b/src/MapleFE/test/java/java2mpl/point-list.java similarity index 100% rename from src/MapleFE/test/java2mpl/point-list.java rename to src/MapleFE/test/java/java2mpl/point-list.java diff --git a/src/MapleFE/test/java2mpl/point-list.java.result b/src/MapleFE/test/java/java2mpl/point-list.java.result similarity index 92% rename from src/MapleFE/test/java2mpl/point-list.java.result rename to src/MapleFE/test/java/java2mpl/point-list.java.result index 7c9b31ffc1da5e7657ea28ff533f0b0dc5013672..b9155b43b38ab2271706493070e60f786a181a2d 100644 --- a/src/MapleFE/test/java2mpl/point-list.java.result +++ b/src/MapleFE/test/java/java2mpl/point-list.java.result @@ -9,7 +9,7 @@ class Point Constructors: Methods: func foo() throws: - var:pl=new PointList + Decl: pl=new PointList() pl.z Assign 1 return pl.z LocalClasses: diff --git a/src/MapleFE/test/java2mpl/switch-1.java b/src/MapleFE/test/java/java2mpl/switch-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/switch-1.java rename to src/MapleFE/test/java/java2mpl/switch-1.java diff --git a/src/MapleFE/test/java2mpl/switch-1.java.result b/src/MapleFE/test/java/java2mpl/switch-1.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/switch-1.java.result rename to src/MapleFE/test/java/java2mpl/switch-1.java.result diff --git a/src/MapleFE/test/java2mpl/switch-2.java b/src/MapleFE/test/java/java2mpl/switch-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/switch-2.java rename to src/MapleFE/test/java/java2mpl/switch-2.java diff --git a/src/MapleFE/test/java2mpl/switch-2.java.result b/src/MapleFE/test/java/java2mpl/switch-2.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/switch-2.java.result rename to src/MapleFE/test/java/java2mpl/switch-2.java.result diff --git a/src/MapleFE/test/java2mpl/t.java b/src/MapleFE/test/java/java2mpl/t.java similarity index 100% rename from src/MapleFE/test/java2mpl/t.java rename to src/MapleFE/test/java/java2mpl/t.java diff --git a/src/MapleFE/test/java2mpl/t.java.result b/src/MapleFE/test/java/java2mpl/t.java.result similarity index 85% rename from src/MapleFE/test/java2mpl/t.java.result rename to src/MapleFE/test/java/java2mpl/t.java.result index 80a92a3a9b58bfc354c4a28fd18fe06c52931e64..d45e86e510ff9949e14b2fcf8a7510269aad3893 100644 --- a/src/MapleFE/test/java2mpl/t.java.result +++ b/src/MapleFE/test/java/java2mpl/t.java.result @@ -6,7 +6,7 @@ class Point Instance Initializer: Constructors: - constructor Point() throws: + constructor Point(x) throws: this.x Assign x Methods: LocalClasses: diff --git a/src/MapleFE/test/java2mpl/t1.java b/src/MapleFE/test/java/java2mpl/t1.java similarity index 100% rename from src/MapleFE/test/java2mpl/t1.java rename to src/MapleFE/test/java/java2mpl/t1.java diff --git a/src/MapleFE/test/java2mpl/t1.java.result b/src/MapleFE/test/java/java2mpl/t1.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/t1.java.result rename to src/MapleFE/test/java/java2mpl/t1.java.result diff --git a/src/MapleFE/test/java2mpl/t2.java b/src/MapleFE/test/java/java2mpl/t2.java similarity index 100% rename from src/MapleFE/test/java2mpl/t2.java rename to src/MapleFE/test/java/java2mpl/t2.java diff --git a/src/MapleFE/test/java2mpl/t2.java.result b/src/MapleFE/test/java/java2mpl/t2.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/t2.java.result rename to src/MapleFE/test/java/java2mpl/t2.java.result diff --git a/src/MapleFE/test/java2mpl/t3.java b/src/MapleFE/test/java/java2mpl/t3.java similarity index 100% rename from src/MapleFE/test/java2mpl/t3.java rename to src/MapleFE/test/java/java2mpl/t3.java diff --git a/src/MapleFE/test/java2mpl/t3.java.result b/src/MapleFE/test/java/java2mpl/t3.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/t3.java.result rename to src/MapleFE/test/java/java2mpl/t3.java.result diff --git a/src/MapleFE/test/java2mpl/t4.java b/src/MapleFE/test/java/java2mpl/t4.java similarity index 100% rename from src/MapleFE/test/java2mpl/t4.java rename to src/MapleFE/test/java/java2mpl/t4.java diff --git a/src/MapleFE/test/java2mpl/t4.java.result b/src/MapleFE/test/java/java2mpl/t4.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/t4.java.result rename to src/MapleFE/test/java/java2mpl/t4.java.result diff --git a/src/MapleFE/test/java2mpl/t5.java b/src/MapleFE/test/java/java2mpl/t5.java similarity index 100% rename from src/MapleFE/test/java2mpl/t5.java rename to src/MapleFE/test/java/java2mpl/t5.java diff --git a/src/MapleFE/test/java2mpl/t5.java.result b/src/MapleFE/test/java/java2mpl/t5.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/t5.java.result rename to src/MapleFE/test/java/java2mpl/t5.java.result diff --git a/src/MapleFE/test/java/java2mpl/ternary-operator.java b/src/MapleFE/test/java/java2mpl/ternary-operator.java new file mode 100644 index 0000000000000000000000000000000000000000..0c4abf67536d37c48435740c1f62a56ccc72fa93 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/ternary-operator.java @@ -0,0 +1,23 @@ +// +//Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +// +//OpenArkFE is licensed under the Mulan PSL v2. +//You can use this software according to the terms and conditions of the Mulan PSL v2. +//You may obtain a copy of Mulan PSL v2 at: +// +// http://license.coscl.org.cn/MulanPSL2 +// +//THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +//FIT FOR A PARTICULAR PURPOSE. +//See the Mulan PSL v2 for more details. +// + +class A { + public static Boolean Is3(int s) { + Boolean b; + b = (s == 3 ? true : false); + return b; + } + +} diff --git a/src/MapleFE/test/java/java2mpl/ternary-operator.java.result b/src/MapleFE/test/java/java2mpl/ternary-operator.java.result new file mode 100644 index 0000000000000000000000000000000000000000..c1cc983aa0ee0b76fa407770126d462e8a11c470 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/ternary-operator.java.result @@ -0,0 +1,17 @@ +Matched 32 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + + Instance Initializer: + Constructors: + Methods: + func Is3(s) throws: + Decl: b + b Assign () + return b + LocalClasses: + LocalInterfaces: + +Identifier:b has no decl. diff --git a/src/MapleFE/test/java2mpl/throw-1.java b/src/MapleFE/test/java/java2mpl/throw-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/throw-1.java rename to src/MapleFE/test/java/java2mpl/throw-1.java diff --git a/src/MapleFE/test/java2mpl/throw-1.java.result b/src/MapleFE/test/java/java2mpl/throw-1.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/throw-1.java.result rename to src/MapleFE/test/java/java2mpl/throw-1.java.result diff --git a/src/MapleFE/test/java2mpl/throw-2.java b/src/MapleFE/test/java/java2mpl/throw-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/throw-2.java rename to src/MapleFE/test/java/java2mpl/throw-2.java diff --git a/src/MapleFE/test/java2mpl/throw-2.java.result b/src/MapleFE/test/java/java2mpl/throw-2.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/throw-2.java.result rename to src/MapleFE/test/java/java2mpl/throw-2.java.result diff --git a/src/MapleFE/test/java2mpl/type-argument-1.java b/src/MapleFE/test/java/java2mpl/type-argument-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/type-argument-1.java rename to src/MapleFE/test/java/java2mpl/type-argument-1.java diff --git a/src/MapleFE/test/java2mpl/type-argument-1.java.result b/src/MapleFE/test/java/java2mpl/type-argument-1.java.result similarity index 90% rename from src/MapleFE/test/java2mpl/type-argument-1.java.result rename to src/MapleFE/test/java/java2mpl/type-argument-1.java.result index 26072486913e9134b0cf558311ceb80140ee77b6..5031a406178674ab0966917f2af76f62ca7c61ea 100644 --- a/src/MapleFE/test/java2mpl/type-argument-1.java.result +++ b/src/MapleFE/test/java/java2mpl/type-argument-1.java.result @@ -3,7 +3,7 @@ Matched 14 tokens. == Sub Tree == class A Fields: - m=new HM + m=new HM(256) Instance Initializer: Constructors: Methods: diff --git a/src/MapleFE/test/java2mpl/type-argument-2.java b/src/MapleFE/test/java/java2mpl/type-argument-2.java similarity index 100% rename from src/MapleFE/test/java2mpl/type-argument-2.java rename to src/MapleFE/test/java/java2mpl/type-argument-2.java diff --git a/src/MapleFE/test/java2mpl/type-argument-2.java.result b/src/MapleFE/test/java/java2mpl/type-argument-2.java.result similarity index 91% rename from src/MapleFE/test/java2mpl/type-argument-2.java.result rename to src/MapleFE/test/java/java2mpl/type-argument-2.java.result index bfaa72f4a5a6423dd755381ddb9ef0ec2af9866d..3898da8e42cd8039913a076660fd43c24e5df300 100644 --- a/src/MapleFE/test/java2mpl/type-argument-2.java.result +++ b/src/MapleFE/test/java/java2mpl/type-argument-2.java.result @@ -3,7 +3,7 @@ Matched 23 tokens. == Sub Tree == class A Fields: - b=new B + b=new B(8) Instance Initializer: Constructors: Methods: diff --git a/src/MapleFE/test/java2mpl/type-argument-3.java b/src/MapleFE/test/java/java2mpl/type-argument-3.java similarity index 100% rename from src/MapleFE/test/java2mpl/type-argument-3.java rename to src/MapleFE/test/java/java2mpl/type-argument-3.java diff --git a/src/MapleFE/test/java2mpl/type-argument-3.java.result b/src/MapleFE/test/java/java2mpl/type-argument-3.java.result similarity index 78% rename from src/MapleFE/test/java2mpl/type-argument-3.java.result rename to src/MapleFE/test/java/java2mpl/type-argument-3.java.result index 05fbf45200db860a4b16d79f4922a52b86cd5c81..9bf1a3effa320225106fe83923691696a2c0ea7a 100644 --- a/src/MapleFE/test/java2mpl/type-argument-3.java.result +++ b/src/MapleFE/test/java/java2mpl/type-argument-3.java.result @@ -7,8 +7,8 @@ class C Instance Initializer: Constructors: Methods: - func getClasses() throws: - var:result=a + func getClasses(a) throws: + Decl: result=a return result LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/unary-operator-1.java b/src/MapleFE/test/java/java2mpl/unary-operator-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/unary-operator-1.java rename to src/MapleFE/test/java/java2mpl/unary-operator-1.java diff --git a/src/MapleFE/test/java2mpl/unary-operator-1.java.result b/src/MapleFE/test/java/java2mpl/unary-operator-1.java.result similarity index 78% rename from src/MapleFE/test/java2mpl/unary-operator-1.java.result rename to src/MapleFE/test/java/java2mpl/unary-operator-1.java.result index e493b2c3387e31f42111d2dfc125f8918c20f80f..931f5e09901bbc714327fc6fc656b6b01a04ba88 100644 --- a/src/MapleFE/test/java2mpl/unary-operator-1.java.result +++ b/src/MapleFE/test/java/java2mpl/unary-operator-1.java.result @@ -7,11 +7,10 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: + func foo(x) throws: cond-branch cond:x NE 0 true branch : - return 0 - false branch : + return 0 false branch : LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java2mpl/unary-operator.java b/src/MapleFE/test/java/java2mpl/unary-operator.java similarity index 100% rename from src/MapleFE/test/java2mpl/unary-operator.java rename to src/MapleFE/test/java/java2mpl/unary-operator.java diff --git a/src/MapleFE/test/java2mpl/unary-operator.java.result b/src/MapleFE/test/java/java2mpl/unary-operator.java.result similarity index 66% rename from src/MapleFE/test/java2mpl/unary-operator.java.result rename to src/MapleFE/test/java/java2mpl/unary-operator.java.result index fde76bdbe978473e1d5d2a435729d9ab8a2f68ac..2ed0a9a8e3cf5158bc710cd9148bcdaac9b5877b 100644 --- a/src/MapleFE/test/java2mpl/unary-operator.java.result +++ b/src/MapleFE/test/java/java2mpl/unary-operator.java.result @@ -7,12 +7,12 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: - var:y,z - xInc + func foo(x) throws: + Decl: y,z + x Inc y AddAssign (x Add a Add b) - aDec + a Dec b BxorAssign a z MulAssign y Add 4 @@ -20,3 +20,6 @@ class A LocalClasses: LocalInterfaces: +Identifier:y has no decl. +Identifier:z has no decl. +Identifier:y has no decl. diff --git a/src/MapleFE/test/java/java2mpl/var-scope-2.java b/src/MapleFE/test/java/java2mpl/var-scope-2.java new file mode 100644 index 0000000000000000000000000000000000000000..f5391c4be2185cfb52d8e8a25311711a1e3faf36 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/var-scope-2.java @@ -0,0 +1,36 @@ +// +//Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +// +//OpenArkFE is licensed under the Mulan PSL v2. +//You can use this software according to the terms and conditions of the Mulan PSL v2. +//You may obtain a copy of Mulan PSL v2 at: +// +// http://license.coscl.org.cn/MulanPSL2 +// +//THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +//FIT FOR A PARTICULAR PURPOSE. +//See the Mulan PSL v2 for more details. +// + +class A { + int a; + + int foo(int x) { + a = x; // field a + if (a == 1) { + int a = 2; // local variable a + a = x + this.a; + return a + 2; + } + + int a = 4; // local variable a|1 + a = x + this.a; + { + int a = 6; // local variable a|2 + x = a; + } + a += x; // local variable a|1 + return a + 4; + } +} diff --git a/src/MapleFE/test/java/java2mpl/var-scope-2.java.result b/src/MapleFE/test/java/java2mpl/var-scope-2.java.result new file mode 100644 index 0000000000000000000000000000000000000000..5a56845acdad661704058e92c9e99b6f4cdfb461 --- /dev/null +++ b/src/MapleFE/test/java/java2mpl/var-scope-2.java.result @@ -0,0 +1,28 @@ +Matched 78 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + a + Instance Initializer: + Constructors: + Methods: + func foo(x) throws: + a Assign x + cond-branch cond:a EQ 1 + true branch : + Decl: a=2 + a Assign x Add this.a + return a Add 2 + false branch : + + Decl: a=4 + a Assign x Add this.a + Decl: a=6 + x Assign a + + a AddAssign x + return a Add 4 + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java2mpl/var-scope.java b/src/MapleFE/test/java/java2mpl/var-scope.java similarity index 100% rename from src/MapleFE/test/java2mpl/var-scope.java rename to src/MapleFE/test/java/java2mpl/var-scope.java diff --git a/src/MapleFE/test/java2mpl/var-scope.java.result b/src/MapleFE/test/java/java2mpl/var-scope.java.result similarity index 73% rename from src/MapleFE/test/java2mpl/var-scope.java.result rename to src/MapleFE/test/java/java2mpl/var-scope.java.result index 253ac3d55f5aa2c5fd80c158f084987ebcf9bdb3..85df7146e43c6edfedc9749e43b16cd3901a7e5d 100644 --- a/src/MapleFE/test/java2mpl/var-scope.java.result +++ b/src/MapleFE/test/java/java2mpl/var-scope.java.result @@ -7,15 +7,16 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: + func foo(x) throws: a Assign x cond-branch cond:a EQ 1 true branch : - var:a=2 - + Decl: a=2 + a Assign x Add this.a + return a Add 2 false branch : - var:a=4 + Decl: a=4 a Assign x Add this.a return a Add 4 LocalClasses: diff --git a/src/MapleFE/test/java2mpl/whileloop-1.java b/src/MapleFE/test/java/java2mpl/whileloop-1.java similarity index 100% rename from src/MapleFE/test/java2mpl/whileloop-1.java rename to src/MapleFE/test/java/java2mpl/whileloop-1.java diff --git a/src/MapleFE/test/java2mpl/whileloop-1.java.result b/src/MapleFE/test/java/java2mpl/whileloop-1.java.result similarity index 100% rename from src/MapleFE/test/java2mpl/whileloop-1.java.result rename to src/MapleFE/test/java/java2mpl/whileloop-1.java.result diff --git a/src/MapleFE/test/openjdk/AbstractMethodError.java b/src/MapleFE/test/java/openjdk/AbstractMethodError.java similarity index 100% rename from src/MapleFE/test/openjdk/AbstractMethodError.java rename to src/MapleFE/test/java/openjdk/AbstractMethodError.java diff --git a/src/MapleFE/test/openjdk/AbstractMethodError.java.result b/src/MapleFE/test/java/openjdk/AbstractMethodError.java.result similarity index 72% rename from src/MapleFE/test/openjdk/AbstractMethodError.java.result rename to src/MapleFE/test/java/openjdk/AbstractMethodError.java.result index b316609ddc8ca5d33c2ebbdf41903a71a4cf14ed..ba598d38f2e8ca72c4baf23edd11262f99d7e37d 100644 --- a/src/MapleFE/test/openjdk/AbstractMethodError.java.result +++ b/src/MapleFE/test/java/openjdk/AbstractMethodError.java.result @@ -1,17 +1,16 @@ Matched 5 tokens. -Matched 44 tokens. +Matched 43 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class AbstractMethodError Fields: - serialVersionUID=Sub - -1256039074 + serialVersionUID=1256039074 Instance Initializer: Constructors: constructor AbstractMethodError() throws: - constructor AbstractMethodError() throws: + constructor AbstractMethodError(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/AbstractStringBuilder-simplified.java b/src/MapleFE/test/java/openjdk/AbstractStringBuilder-simplified.java similarity index 100% rename from src/MapleFE/test/openjdk/AbstractStringBuilder-simplified.java rename to src/MapleFE/test/java/openjdk/AbstractStringBuilder-simplified.java diff --git a/src/MapleFE/test/java/openjdk/AbstractStringBuilder-simplified.java.result b/src/MapleFE/test/java/openjdk/AbstractStringBuilder-simplified.java.result new file mode 100644 index 0000000000000000000000000000000000000000..4ca8eed4878e7a6857f1d703c8b24ab46b62a1de --- /dev/null +++ b/src/MapleFE/test/java/openjdk/AbstractStringBuilder-simplified.java.result @@ -0,0 +1,43 @@ +Matched 329 tokens. +============= Module =========== +== Sub Tree == +class AbstractStringBuilder + Fields: + value count MAX_ARRAY_SIZE=Integer.MAX_VALUE Sub 8 + Instance Initializer: + Constructors: + constructor AbstractStringBuilder() throws: + constructor AbstractStringBuilder(capacity) throws: + Methods: + func length() throws: + func capacity() throws: + func ensureCapacity(minimumCapacity) throws: + func ensureCapacityInternal(minimumCapacity) throws: + func newCapacity(minCapacity) throws: + func hugeCapacity(minCapacity) throws: + func trimToSize() throws: + func setLength(newLength) throws: + func charAt(index) throws: + func codePointAt(index) throws: + func codePointBefore(index) throws: + func codePointCount(beginIndex,endIndex) throws: + func offsetByCodePoints(index,codePointOffset) throws: + func getChars(srcBegin,srcEnd,dst,dstBegin) throws: + func setCharAt(index,ch) throws: + func append(obj) throws: + func append(str) throws: + func append(sb) throws: + func append(asb) throws: + func append(s) throws: + func appendNull() throws: + func append(s,start,end) throws: + func append(str) throws: + func append(str[],offset,len) throws: + func append(b) throws: + func append(c) throws: + func append(i) throws: + func append(l) throws: + func append(f) throws: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/openjdk/AbstractStringBuilder.java b/src/MapleFE/test/java/openjdk/AbstractStringBuilder.java similarity index 100% rename from src/MapleFE/test/openjdk/AbstractStringBuilder.java rename to src/MapleFE/test/java/openjdk/AbstractStringBuilder.java diff --git a/src/MapleFE/test/openjdk/AbstractStringBuilder.java.result b/src/MapleFE/test/java/openjdk/AbstractStringBuilder.java.result similarity index 57% rename from src/MapleFE/test/openjdk/AbstractStringBuilder.java.result rename to src/MapleFE/test/java/openjdk/AbstractStringBuilder.java.result index e2266a7cc41e75fd420a0e6afe758f2f10896cd7..9e9e2349c4b2ed8229f362673a4d7110a10e62ee 100644 Binary files a/src/MapleFE/test/openjdk/AbstractStringBuilder.java.result and b/src/MapleFE/test/java/openjdk/AbstractStringBuilder.java.result differ diff --git a/src/MapleFE/test/openjdk/Appendable.java b/src/MapleFE/test/java/openjdk/Appendable.java similarity index 100% rename from src/MapleFE/test/openjdk/Appendable.java rename to src/MapleFE/test/java/openjdk/Appendable.java diff --git a/src/MapleFE/test/openjdk/Appendable.java.result b/src/MapleFE/test/java/openjdk/Appendable.java.result similarity index 60% rename from src/MapleFE/test/openjdk/Appendable.java.result rename to src/MapleFE/test/java/openjdk/Appendable.java.result index 93789bd41e00d444dbea1751d57c1b97382d94ab..ee3a5ce7fa79c2591be93f9ab36dd50cc0a4ff15 100644 --- a/src/MapleFE/test/openjdk/Appendable.java.result +++ b/src/MapleFE/test/java/openjdk/Appendable.java.result @@ -11,7 +11,7 @@ interface Appendable Fields: Methods: - func append() throws: IOException - func append() throws: IOException - func append() throws: IOException + func append(csq) throws: IOException + func append(csq,start,end) throws: IOException + func append(c) throws: IOException diff --git a/src/MapleFE/test/openjdk/ArithmeticException.java b/src/MapleFE/test/java/openjdk/ArithmeticException.java similarity index 100% rename from src/MapleFE/test/openjdk/ArithmeticException.java rename to src/MapleFE/test/java/openjdk/ArithmeticException.java diff --git a/src/MapleFE/test/openjdk/ArithmeticException.java.result b/src/MapleFE/test/java/openjdk/ArithmeticException.java.result similarity index 86% rename from src/MapleFE/test/openjdk/ArithmeticException.java.result rename to src/MapleFE/test/java/openjdk/ArithmeticException.java.result index 9b4a3b76ead1bd4ae2341109ff7b11a765835a95..b858b7e57a8387ece48fb83667e0434f45e1f613 100644 --- a/src/MapleFE/test/openjdk/ArithmeticException.java.result +++ b/src/MapleFE/test/java/openjdk/ArithmeticException.java.result @@ -10,7 +10,7 @@ class ArithmeticException Instance Initializer: Constructors: constructor ArithmeticException() throws: - constructor ArithmeticException() throws: + constructor ArithmeticException(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/ArrayIndexOutOfBoundsException.java b/src/MapleFE/test/java/openjdk/ArrayIndexOutOfBoundsException.java similarity index 100% rename from src/MapleFE/test/openjdk/ArrayIndexOutOfBoundsException.java rename to src/MapleFE/test/java/openjdk/ArrayIndexOutOfBoundsException.java diff --git a/src/MapleFE/test/openjdk/ArrayIndexOutOfBoundsException.java.result b/src/MapleFE/test/java/openjdk/ArrayIndexOutOfBoundsException.java.result similarity index 46% rename from src/MapleFE/test/openjdk/ArrayIndexOutOfBoundsException.java.result rename to src/MapleFE/test/java/openjdk/ArrayIndexOutOfBoundsException.java.result index ddd36a4f3ca1e7977ba9191c26babd5f435be1a6..b80ef27091987537772f2e3601c2f636cabf1e82 100644 --- a/src/MapleFE/test/openjdk/ArrayIndexOutOfBoundsException.java.result +++ b/src/MapleFE/test/java/openjdk/ArrayIndexOutOfBoundsException.java.result @@ -1,20 +1,19 @@ Matched 5 tokens. -Matched 110 tokens. +Matched 109 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class ArrayIndexOutOfBoundsException Fields: - serialVersionUID=Sub - -1467917380 + serialVersionUID=1467917380 Instance Initializer: Constructors: constructor ArrayIndexOutOfBoundsException() throws: - constructor ArrayIndexOutOfBoundsException() throws: - constructor ArrayIndexOutOfBoundsException() throws: - constructor ArrayIndexOutOfBoundsException() throws: - constructor ArrayIndexOutOfBoundsException() throws: + constructor ArrayIndexOutOfBoundsException(index) throws: + constructor ArrayIndexOutOfBoundsException(s) throws: + constructor ArrayIndexOutOfBoundsException(sourceLength,index) throws: + constructor ArrayIndexOutOfBoundsException(sourceLength,offset,count) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/ArrayStoreException.java b/src/MapleFE/test/java/openjdk/ArrayStoreException.java similarity index 100% rename from src/MapleFE/test/openjdk/ArrayStoreException.java rename to src/MapleFE/test/java/openjdk/ArrayStoreException.java diff --git a/src/MapleFE/test/openjdk/ArrayStoreException.java.result b/src/MapleFE/test/java/openjdk/ArrayStoreException.java.result similarity index 72% rename from src/MapleFE/test/openjdk/ArrayStoreException.java.result rename to src/MapleFE/test/java/openjdk/ArrayStoreException.java.result index eedee8eec59aa257701e5ca55d339cda3c8e64e9..9ce786e95f8d5b34264ed8cba49b6b6710357764 100644 --- a/src/MapleFE/test/openjdk/ArrayStoreException.java.result +++ b/src/MapleFE/test/java/openjdk/ArrayStoreException.java.result @@ -1,17 +1,16 @@ Matched 5 tokens. -Matched 44 tokens. +Matched 43 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class ArrayStoreException Fields: - serialVersionUID=Sub - 1085227297 + serialVersionUID=-1085227297 Instance Initializer: Constructors: constructor ArrayStoreException() throws: - constructor ArrayStoreException() throws: + constructor ArrayStoreException(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/AutoCloseable.java b/src/MapleFE/test/java/openjdk/AutoCloseable.java similarity index 100% rename from src/MapleFE/test/openjdk/AutoCloseable.java rename to src/MapleFE/test/java/openjdk/AutoCloseable.java diff --git a/src/MapleFE/test/openjdk/AutoCloseable.java.result b/src/MapleFE/test/java/openjdk/AutoCloseable.java.result similarity index 100% rename from src/MapleFE/test/openjdk/AutoCloseable.java.result rename to src/MapleFE/test/java/openjdk/AutoCloseable.java.result diff --git a/src/MapleFE/test/openjdk/Boolean.java b/src/MapleFE/test/java/openjdk/Boolean.java similarity index 100% rename from src/MapleFE/test/openjdk/Boolean.java rename to src/MapleFE/test/java/openjdk/Boolean.java diff --git a/src/MapleFE/test/openjdk/Boolean.java.result b/src/MapleFE/test/java/openjdk/Boolean.java.result similarity index 44% rename from src/MapleFE/test/openjdk/Boolean.java.result rename to src/MapleFE/test/java/openjdk/Boolean.java.result index 8e54b2f8c83bb7e8394d669aed217fc728fdaed5..a780b2d8ad1a8801a0ff204e8763f0546d141c0b 100644 --- a/src/MapleFE/test/openjdk/Boolean.java.result +++ b/src/MapleFE/test/java/openjdk/Boolean.java.result @@ -1,58 +1,64 @@ Matched 5 tokens. -Matched 442 tokens. +Matched 440 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class Boolean Fields: - TRUE=new Boolean FALSE=new Boolean TYPE=() value serialVersionUID=Sub - 711132434 + TRUE=new Boolean(true) FALSE=new Boolean(false) TYPE=()boolean.getComponentType() value serialVersionUID=-711132434 Instance Initializer: Constructors: - constructor Boolean() throws: + constructor Boolean(value) throws: this.value Assign value - constructor Boolean() throws: + constructor Boolean(s) throws: Methods: - func parseBoolean() throws: + func parseBoolean(s) throws: return ((s NE null) Land s.equalsIgnoreCase("true")) func booleanValue() throws: return value - func valueOf() throws: + func valueOf(b) throws: return () - func valueOf() throws: + func valueOf(s) throws: return - func toString() throws: + func toString(b) throws: return func toString() throws: return func hashCode() throws: return Boolean.hashCode(value) - func hashCode() throws: + func hashCode(value) throws: return - func equals() throws: - cond-branch cond: + func equals(obj) throws: + cond-branch cond:obj instanceof Boolean true branch : - return value EQ ((Boolean)obj)booleanValue + return value EQ (Boolean)obj.booleanValue() false branch : return false - func getBoolean() throws: - var:result=false + func getBoolean(name) throws: + Decl: result=false result Assign parseBoolean(System.getProperty(name)) + IllegalArgumentException + NullPointerException + e return result - func compareTo() throws: + func compareTo(b) throws: return compare(this.value,b.value) - func compare() throws: + func compare(x,y) throws: return - func logicalAnd() throws: + func logicalAnd(a,b) throws: return a Land b - func logicalOr() throws: + func logicalOr(a,b) throws: return a Lor b - func logicalXor() throws: + func logicalXor(a,b) throws: return a Bxor b LocalClasses: LocalInterfaces: +Identifier:result has no decl. +Identifier:IllegalArgumentException has no decl. +Identifier:NullPointerException has no decl. +Identifier:e has no decl. diff --git a/src/MapleFE/test/openjdk/BootstrapMethodError.java b/src/MapleFE/test/java/openjdk/BootstrapMethodError.java similarity index 100% rename from src/MapleFE/test/openjdk/BootstrapMethodError.java rename to src/MapleFE/test/java/openjdk/BootstrapMethodError.java diff --git a/src/MapleFE/test/openjdk/BootstrapMethodError.java.result b/src/MapleFE/test/java/openjdk/BootstrapMethodError.java.result similarity index 68% rename from src/MapleFE/test/openjdk/BootstrapMethodError.java.result rename to src/MapleFE/test/java/openjdk/BootstrapMethodError.java.result index 144c70e68044fbb458be1deb47ae88174ad43e1a..d4d4b74a471b0aaaae526add731d196d79c6dfcd 100644 --- a/src/MapleFE/test/openjdk/BootstrapMethodError.java.result +++ b/src/MapleFE/test/java/openjdk/BootstrapMethodError.java.result @@ -10,9 +10,9 @@ class BootstrapMethodError Instance Initializer: Constructors: constructor BootstrapMethodError() throws: - constructor BootstrapMethodError() throws: - constructor BootstrapMethodError() throws: - constructor BootstrapMethodError() throws: + constructor BootstrapMethodError(s) throws: + constructor BootstrapMethodError(s,cause) throws: + constructor BootstrapMethodError(cause) throws: initCause(cause) Methods: LocalClasses: diff --git a/src/MapleFE/test/openjdk/Byte.java b/src/MapleFE/test/java/openjdk/Byte.java similarity index 100% rename from src/MapleFE/test/openjdk/Byte.java rename to src/MapleFE/test/java/openjdk/Byte.java diff --git a/src/MapleFE/test/openjdk/Byte.java.result b/src/MapleFE/test/java/openjdk/Byte.java.result similarity index 53% rename from src/MapleFE/test/openjdk/Byte.java.result rename to src/MapleFE/test/java/openjdk/Byte.java.result index 2c9e8a581342384a63e3bd9d4b345eaea6a1c9ed..37e80e137922edf8e27e5f557862acf629f2eb8d 100644 --- a/src/MapleFE/test/openjdk/Byte.java.result +++ b/src/MapleFE/test/java/openjdk/Byte.java.result @@ -1,46 +1,42 @@ Matched 5 tokens. -Matched 909 tokens. +Matched 906 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class Byte Fields: - MIN_VALUE=Sub - 128 MAX_VALUE=127 TYPE=() value SIZE=8 BYTES= serialVersionUID=Sub - 296684260 DIGITS= UPPER_CASE_DIGITS= + MIN_VALUE=-128 MAX_VALUE=127 TYPE=()byte.getComponentType() value SIZE=8 BYTES=SIZE Div Byte.SIZE serialVersionUID=-296684260 DIGITS= UPPER_CASE_DIGITS= Instance Initializer: Constructors: - constructor Byte() throws: + constructor Byte(value) throws: this.value Assign value - constructor Byte() throws: + constructor Byte(s) throws: this.value Assign parseByte(s,10) Methods: - func toString() throws: + func toString(b) throws: return Integer.toString((int)b,10) - func valueOf() throws: - var:offset=128 + func valueOf(b) throws: + Decl: offset=128 return - func parseByte() throws: NumberFormatException - var:i=Integer.parseInt(s,radix) + func parseByte(s,radix) throws: NumberFormatException + Decl: i=Integer.parseInt(s,radix) cond-branch cond:i LT MIN_VALUE Lor i GT MAX_VALUE true branch : - new NumberFormatException - false branch : + new NumberFormatException("Value out of range. Value:\"" Add s Add "\" Radix:" Add radix) false branch : return (byte)i - func parseByte() throws: NumberFormatException + func parseByte(s) throws: NumberFormatException return parseByte(s,10) - func valueOf() throws: NumberFormatException + func valueOf(s,radix) throws: NumberFormatException return valueOf(parseByte(s,radix)) - func valueOf() throws: NumberFormatException + func valueOf(s) throws: NumberFormatException return valueOf(s,10) - func decode() throws: NumberFormatException - var:i=Integer.decode(nm) + func decode(nm) throws: NumberFormatException + Decl: i=Integer.decode(nm) cond-branch cond:i LT MIN_VALUE Lor i GT MAX_VALUE true branch : - new NumberFormatException - false branch : + new NumberFormatException("Value " Add i Add " out of range from input " Add nm) false branch : return valueOf((byte)i) func byteValue() throws: @@ -59,29 +55,29 @@ class Byte return Integer.toString((int)value) func hashCode() throws: return Byte.hashCode(value) - func hashCode() throws: + func hashCode(value) throws: return (int)value - func equals() throws: - cond-branch cond: + func equals(obj) throws: + cond-branch cond:obj instanceof Byte true branch : - return value EQ ((Byte)obj)byteValue + return value EQ (Byte)obj.byteValue() false branch : return false - func compareTo() throws: + func compareTo(anotherByte) throws: return compare(this.value,anotherByte.value) - func compare() throws: + func compare(x,y) throws: return x Sub y - func toUnsignedInt() throws: + func toUnsignedInt(x) throws: return ((int)x) Band 255 - func toUnsignedLong() throws: + func toUnsignedLong(x) throws: return ((long)x) Band 4095 - func toHexString() throws: - var:digits= - var:buf= + func toHexString(b,upperCase) throws: + Decl: digits= + Decl: buf= Assign Assign - return new String + return new String(0,2,buf) LocalClasses: class ByteCache Fields: diff --git a/src/MapleFE/test/openjdk/CharSequence.java b/src/MapleFE/test/java/openjdk/CharSequence.java similarity index 100% rename from src/MapleFE/test/openjdk/CharSequence.java rename to src/MapleFE/test/java/openjdk/CharSequence.java diff --git a/src/MapleFE/test/openjdk/CharSequence.java.result b/src/MapleFE/test/java/openjdk/CharSequence.java.result similarity index 62% rename from src/MapleFE/test/openjdk/CharSequence.java.result rename to src/MapleFE/test/java/openjdk/CharSequence.java.result index 30f6b8b351ecccc27fe23d6dd4d5a06a1bba1703..be0ea994337d1959b2b85cf4253f0ef8d0608588 100644 --- a/src/MapleFE/test/openjdk/CharSequence.java.result +++ b/src/MapleFE/test/java/openjdk/CharSequence.java.result @@ -30,8 +30,8 @@ interface CharSequence Methods: func length() throws: - func charAt() throws: - func subSequence() throws: + func charAt(index) throws: + func subSequence(start,end) throws: func toString() throws: func chars() throws: class CharIterator @@ -45,20 +45,19 @@ interface CharSequence func nextInt() throws: cond-branch cond:hasNext() true branch : - return charAt( curInc + return charAt(cur Inc ) false branch : - new NoSuchElementException + new NoSuchElementException() - func forEachRemaining() throws: + func forEachRemaining(block) throws: for ( ) block.accept(charAt(cur)) LocalClasses: LocalInterfaces: - return StreamSupport.intStream(() -> Spliterators.spliterator(new CharIterator,length(),Spliterator.ORDERED) -,Spliterator.SUBSIZED Bor Spliterator.SIZED Bor Spliterator.ORDERED,false) + return StreamSupport.intStream(() -> Spliterators.spliterator(new CharIterator(),length(),Spliterator.ORDERED),Spliterator.SUBSIZED Bor Spliterator.SIZED Bor Spliterator.ORDERED,false) func codePoints() throws: class CodePointIterator Fields: @@ -66,27 +65,46 @@ interface CharSequence Instance Initializer: Constructors: Methods: - func forEachRemaining() throws: - var:length=length() - var:i=cur + func forEachRemaining(block) throws: + Decl: length=length() + Decl: i=cur + while i LT length Decl: c1=charAt(i Inc +) + cond-branch cond:Character.isHighSurrogate(c1) Lor i GE length + true branch : + block.accept(c1) + false branch : + Decl: c2=charAt(i) + cond-branch cond:Character.isLowSurrogate(c2) + true branch : + i Inc + + block.accept(Character.toCodePoint(c1,c2)) + false branch : + block.accept(c1) + + + + + cur Assign i func hasNext() throws: return cur LT length() func nextInt() throws: - var:length=length() + Decl: length=length() cond-branch cond:cur GE length true branch : - new NoSuchElementException + new NoSuchElementException() false branch : - var:c1=charAt( curInc + Decl: c1=charAt(cur Inc ) cond-branch cond:Character.isHighSurrogate(c1) Land cur LT length true branch : - var:c2=charAt(cur) + Decl: c2=charAt(cur) cond-branch cond:Character.isLowSurrogate(c2) true branch : - curInc + cur Inc return Character.toCodePoint(c1,c2) false branch : @@ -97,6 +115,5 @@ interface CharSequence LocalClasses: LocalInterfaces: - return StreamSupport.intStream(() -> Spliterators.spliteratorUnknownSize(new CodePointIterator,Spliterator.ORDERED) -,Spliterator.ORDERED,false) + return StreamSupport.intStream(() -> Spliterators.spliteratorUnknownSize(new CodePointIterator(),Spliterator.ORDERED),Spliterator.ORDERED,false) diff --git a/src/MapleFE/test/openjdk/Character-1.java b/src/MapleFE/test/java/openjdk/Character-1.java similarity index 100% rename from src/MapleFE/test/openjdk/Character-1.java rename to src/MapleFE/test/java/openjdk/Character-1.java diff --git a/src/MapleFE/test/java/openjdk/Character-1.java.result b/src/MapleFE/test/java/openjdk/Character-1.java.result new file mode 100644 index 0000000000000000000000000000000000000000..b145edf69e466f864e9534a862fa50f3b9feecd1 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Character-1.java.result @@ -0,0 +1,94 @@ +Matched 5 tokens. +Matched 14 tokens. +Matched 21 tokens. +Matched 28 tokens. +Matched 35 tokens. +Matched 42 tokens. +Matched 5258 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import dalvik.annotation.optimization.FastNative +== Sub Tree == +import java.util.Arrays +== Sub Tree == +import java.util.HashMap +== Sub Tree == +import java.util.Locale +== Sub Tree == +import java.util.Map +== Sub Tree == +class Character + Fields: + MIN_RADIX=2 MAX_RADIX=36 MIN_VALUE=0 MAX_VALUE=65535 TYPE=()char.getComponentType() UNASSIGNED=0 UPPERCASE_LETTER=1 LOWERCASE_LETTER=2 TITLECASE_LETTER=3 MODIFIER_LETTER=4 OTHER_LETTER=5 NON_SPACING_MARK=6 ENCLOSING_MARK=7 COMBINING_SPACING_MARK=8 DECIMAL_DIGIT_NUMBER=9 LETTER_NUMBER=10 OTHER_NUMBER=11 SPACE_SEPARATOR=12 LINE_SEPARATOR=13 PARAGRAPH_SEPARATOR=14 CONTROL=15 FORMAT=16 PRIVATE_USE=18 SURROGATE=19 DASH_PUNCTUATION=20 START_PUNCTUATION=21 END_PUNCTUATION=22 CONNECTOR_PUNCTUATION=23 OTHER_PUNCTUATION=24 MATH_SYMBOL=25 CURRENCY_SYMBOL=26 MODIFIER_SYMBOL=27 OTHER_SYMBOL=28 INITIAL_QUOTE_PUNCTUATION=29 FINAL_QUOTE_PUNCTUATION=30 ERROR=-1 DIRECTIONALITY_UNDEFINED=-1 DIRECTIONALITY_LEFT_TO_RIGHT=0 DIRECTIONALITY_RIGHT_TO_LEFT=1 DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC=2 DIRECTIONALITY_EUROPEAN_NUMBER=3 DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR=4 DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR=5 DIRECTIONALITY_ARABIC_NUMBER=6 DIRECTIONALITY_COMMON_NUMBER_SEPARATOR=7 DIRECTIONALITY_NONSPACING_MARK=8 DIRECTIONALITY_BOUNDARY_NEUTRAL=9 DIRECTIONALITY_PARAGRAPH_SEPARATOR=10 DIRECTIONALITY_SEGMENT_SEPARATOR=11 DIRECTIONALITY_WHITESPACE=12 DIRECTIONALITY_OTHER_NEUTRALS=13 DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING=14 DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE=15 DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING=16 DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE=17 DIRECTIONALITY_POP_DIRECTIONAL_FORMAT=18 MIN_HIGH_SURROGATE=55296 MAX_HIGH_SURROGATE=56319 MIN_LOW_SURROGATE=56320 MAX_LOW_SURROGATE=57343 MIN_SURROGATE=MIN_HIGH_SURROGATE MAX_SURROGATE=MAX_LOW_SURROGATE MIN_SUPPLEMENTARY_CODE_POINT=65536 MIN_CODE_POINT=0 MAX_CODE_POINT=1114111 DIRECTIONALITY= + Instance Initializer: + Constructors: + Methods: + LocalClasses: + class Subset + Fields: + name + Instance Initializer: + Constructors: + constructor Subset(name) throws: + cond-branch cond:name EQ null + true branch : + new NullPointerException("name") + false branch : + + this.name Assign name + Methods: + func equals(obj) throws: + return (this EQ obj) + func hashCode() throws: + return super.hashCode() + func toString() throws: + return name + LocalClasses: + LocalInterfaces: + class UnicodeBlock + Fields: + map=new HashMap(256) BASIC_LATIN=new UnicodeBlock("BASIC_LATIN","BASIC LATIN","BASICLATIN") LATIN_1_SUPPLEMENT=new UnicodeBlock("LATIN_1_SUPPLEMENT","LATIN-1 SUPPLEMENT","LATIN-1SUPPLEMENT") LATIN_EXTENDED_A=new UnicodeBlock("LATIN_EXTENDED_A","LATIN EXTENDED-A","LATINEXTENDED-A") LATIN_EXTENDED_B=new UnicodeBlock("LATIN_EXTENDED_B","LATIN EXTENDED-B","LATINEXTENDED-B") IPA_EXTENSIONS=new UnicodeBlock("IPA_EXTENSIONS","IPA EXTENSIONS","IPAEXTENSIONS") SPACING_MODIFIER_LETTERS=new UnicodeBlock("SPACING_MODIFIER_LETTERS","SPACING MODIFIER LETTERS","SPACINGMODIFIERLETTERS") COMBINING_DIACRITICAL_MARKS=new UnicodeBlock("COMBINING_DIACRITICAL_MARKS","COMBINING DIACRITICAL MARKS","COMBININGDIACRITICALMARKS") GREEK=new UnicodeBlock("GREEK","GREEK AND COPTIC","GREEKANDCOPTIC") CYRILLIC=new UnicodeBlock("CYRILLIC") ARMENIAN=new UnicodeBlock("ARMENIAN") HEBREW=new UnicodeBlock("HEBREW") ARABIC=new UnicodeBlock("ARABIC") DEVANAGARI=new UnicodeBlock("DEVANAGARI") BENGALI=new UnicodeBlock("BENGALI") GURMUKHI=new UnicodeBlock("GURMUKHI") GUJARATI=new UnicodeBlock("GUJARATI") ORIYA=new UnicodeBlock("ORIYA") TAMIL=new UnicodeBlock("TAMIL") TELUGU=new UnicodeBlock("TELUGU") KANNADA=new UnicodeBlock("KANNADA") MALAYALAM=new UnicodeBlock("MALAYALAM") THAI=new UnicodeBlock("THAI") LAO=new UnicodeBlock("LAO") TIBETAN=new UnicodeBlock("TIBETAN") GEORGIAN=new UnicodeBlock("GEORGIAN") HANGUL_JAMO=new UnicodeBlock("HANGUL_JAMO","HANGUL JAMO","HANGULJAMO") LATIN_EXTENDED_ADDITIONAL=new UnicodeBlock("LATIN_EXTENDED_ADDITIONAL","LATIN EXTENDED ADDITIONAL","LATINEXTENDEDADDITIONAL") GREEK_EXTENDED=new UnicodeBlock("GREEK_EXTENDED","GREEK EXTENDED","GREEKEXTENDED") GENERAL_PUNCTUATION=new UnicodeBlock("GENERAL_PUNCTUATION","GENERAL PUNCTUATION","GENERALPUNCTUATION") SUPERSCRIPTS_AND_SUBSCRIPTS=new UnicodeBlock("SUPERSCRIPTS_AND_SUBSCRIPTS","SUPERSCRIPTS AND SUBSCRIPTS","SUPERSCRIPTSANDSUBSCRIPTS") CURRENCY_SYMBOLS=new UnicodeBlock("CURRENCY_SYMBOLS","CURRENCY SYMBOLS","CURRENCYSYMBOLS") COMBINING_MARKS_FOR_SYMBOLS=new UnicodeBlock("COMBINING_MARKS_FOR_SYMBOLS","COMBINING DIACRITICAL MARKS FOR SYMBOLS","COMBININGDIACRITICALMARKSFORSYMBOLS","COMBINING MARKS FOR SYMBOLS","COMBININGMARKSFORSYMBOLS") LETTERLIKE_SYMBOLS=new UnicodeBlock("LETTERLIKE_SYMBOLS","LETTERLIKE SYMBOLS","LETTERLIKESYMBOLS") NUMBER_FORMS=new UnicodeBlock("NUMBER_FORMS","NUMBER FORMS","NUMBERFORMS") ARROWS=new UnicodeBlock("ARROWS") MATHEMATICAL_OPERATORS=new UnicodeBlock("MATHEMATICAL_OPERATORS","MATHEMATICAL OPERATORS","MATHEMATICALOPERATORS") MISCELLANEOUS_TECHNICAL=new UnicodeBlock("MISCELLANEOUS_TECHNICAL","MISCELLANEOUS TECHNICAL","MISCELLANEOUSTECHNICAL") CONTROL_PICTURES=new UnicodeBlock("CONTROL_PICTURES","CONTROL PICTURES","CONTROLPICTURES") OPTICAL_CHARACTER_RECOGNITION=new UnicodeBlock("OPTICAL_CHARACTER_RECOGNITION","OPTICAL CHARACTER RECOGNITION","OPTICALCHARACTERRECOGNITION") ENCLOSED_ALPHANUMERICS=new UnicodeBlock("ENCLOSED_ALPHANUMERICS","ENCLOSED ALPHANUMERICS","ENCLOSEDALPHANUMERICS") BOX_DRAWING=new UnicodeBlock("BOX_DRAWING","BOX DRAWING","BOXDRAWING") BLOCK_ELEMENTS=new UnicodeBlock("BLOCK_ELEMENTS","BLOCK ELEMENTS","BLOCKELEMENTS") GEOMETRIC_SHAPES=new UnicodeBlock("GEOMETRIC_SHAPES","GEOMETRIC SHAPES","GEOMETRICSHAPES") MISCELLANEOUS_SYMBOLS=new UnicodeBlock("MISCELLANEOUS_SYMBOLS","MISCELLANEOUS SYMBOLS","MISCELLANEOUSSYMBOLS") DINGBATS=new UnicodeBlock("DINGBATS") CJK_SYMBOLS_AND_PUNCTUATION=new UnicodeBlock("CJK_SYMBOLS_AND_PUNCTUATION","CJK SYMBOLS AND PUNCTUATION","CJKSYMBOLSANDPUNCTUATION") HIRAGANA=new UnicodeBlock("HIRAGANA") KATAKANA=new UnicodeBlock("KATAKANA") BOPOMOFO=new UnicodeBlock("BOPOMOFO") HANGUL_COMPATIBILITY_JAMO=new UnicodeBlock("HANGUL_COMPATIBILITY_JAMO","HANGUL COMPATIBILITY JAMO","HANGULCOMPATIBILITYJAMO") KANBUN=new UnicodeBlock("KANBUN") ENCLOSED_CJK_LETTERS_AND_MONTHS=new UnicodeBlock("ENCLOSED_CJK_LETTERS_AND_MONTHS","ENCLOSED CJK LETTERS AND MONTHS","ENCLOSEDCJKLETTERSANDMONTHS") CJK_COMPATIBILITY=new UnicodeBlock("CJK_COMPATIBILITY","CJK COMPATIBILITY","CJKCOMPATIBILITY") CJK_UNIFIED_IDEOGRAPHS=new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS","CJK UNIFIED IDEOGRAPHS","CJKUNIFIEDIDEOGRAPHS") HANGUL_SYLLABLES=new UnicodeBlock("HANGUL_SYLLABLES","HANGUL SYLLABLES","HANGULSYLLABLES") PRIVATE_USE_AREA=new UnicodeBlock("PRIVATE_USE_AREA","PRIVATE USE AREA","PRIVATEUSEAREA") CJK_COMPATIBILITY_IDEOGRAPHS=new UnicodeBlock("CJK_COMPATIBILITY_IDEOGRAPHS","CJK COMPATIBILITY IDEOGRAPHS","CJKCOMPATIBILITYIDEOGRAPHS") ALPHABETIC_PRESENTATION_FORMS=new UnicodeBlock("ALPHABETIC_PRESENTATION_FORMS","ALPHABETIC PRESENTATION FORMS","ALPHABETICPRESENTATIONFORMS") ARABIC_PRESENTATION_FORMS_A=new UnicodeBlock("ARABIC_PRESENTATION_FORMS_A","ARABIC PRESENTATION FORMS-A","ARABICPRESENTATIONFORMS-A") COMBINING_HALF_MARKS=new UnicodeBlock("COMBINING_HALF_MARKS","COMBINING HALF MARKS","COMBININGHALFMARKS") CJK_COMPATIBILITY_FORMS=new UnicodeBlock("CJK_COMPATIBILITY_FORMS","CJK COMPATIBILITY FORMS","CJKCOMPATIBILITYFORMS") SMALL_FORM_VARIANTS=new UnicodeBlock("SMALL_FORM_VARIANTS","SMALL FORM VARIANTS","SMALLFORMVARIANTS") ARABIC_PRESENTATION_FORMS_B=new UnicodeBlock("ARABIC_PRESENTATION_FORMS_B","ARABIC PRESENTATION FORMS-B","ARABICPRESENTATIONFORMS-B") HALFWIDTH_AND_FULLWIDTH_FORMS=new UnicodeBlock("HALFWIDTH_AND_FULLWIDTH_FORMS","HALFWIDTH AND FULLWIDTH FORMS","HALFWIDTHANDFULLWIDTHFORMS") SPECIALS=new UnicodeBlock("SPECIALS") SURROGATES_AREA=new UnicodeBlock("SURROGATES_AREA",false) SYRIAC=new UnicodeBlock("SYRIAC") THAANA=new UnicodeBlock("THAANA") SINHALA=new UnicodeBlock("SINHALA") MYANMAR=new UnicodeBlock("MYANMAR") ETHIOPIC=new UnicodeBlock("ETHIOPIC") CHEROKEE=new UnicodeBlock("CHEROKEE") UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS=new UnicodeBlock("UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS","UNIFIED CANADIAN ABORIGINAL SYLLABICS","UNIFIEDCANADIANABORIGINALSYLLABICS") OGHAM=new UnicodeBlock("OGHAM") RUNIC=new UnicodeBlock("RUNIC") KHMER=new UnicodeBlock("KHMER") MONGOLIAN=new UnicodeBlock("MONGOLIAN") BRAILLE_PATTERNS=new UnicodeBlock("BRAILLE_PATTERNS","BRAILLE PATTERNS","BRAILLEPATTERNS") CJK_RADICALS_SUPPLEMENT=new UnicodeBlock("CJK_RADICALS_SUPPLEMENT","CJK RADICALS SUPPLEMENT","CJKRADICALSSUPPLEMENT") KANGXI_RADICALS=new UnicodeBlock("KANGXI_RADICALS","KANGXI RADICALS","KANGXIRADICALS") IDEOGRAPHIC_DESCRIPTION_CHARACTERS=new UnicodeBlock("IDEOGRAPHIC_DESCRIPTION_CHARACTERS","IDEOGRAPHIC DESCRIPTION CHARACTERS","IDEOGRAPHICDESCRIPTIONCHARACTERS") BOPOMOFO_EXTENDED=new UnicodeBlock("BOPOMOFO_EXTENDED","BOPOMOFO EXTENDED","BOPOMOFOEXTENDED") CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A=new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A","CJK UNIFIED IDEOGRAPHS EXTENSION A","CJKUNIFIEDIDEOGRAPHSEXTENSIONA") YI_SYLLABLES=new UnicodeBlock("YI_SYLLABLES","YI SYLLABLES","YISYLLABLES") YI_RADICALS=new UnicodeBlock("YI_RADICALS","YI RADICALS","YIRADICALS") CYRILLIC_SUPPLEMENTARY=new UnicodeBlock("CYRILLIC_SUPPLEMENTARY","CYRILLIC SUPPLEMENTARY","CYRILLICSUPPLEMENTARY","CYRILLIC SUPPLEMENT","CYRILLICSUPPLEMENT") TAGALOG=new UnicodeBlock("TAGALOG") HANUNOO=new UnicodeBlock("HANUNOO") BUHID=new UnicodeBlock("BUHID") TAGBANWA=new UnicodeBlock("TAGBANWA") LIMBU=new UnicodeBlock("LIMBU") TAI_LE=new UnicodeBlock("TAI_LE","TAI LE","TAILE") KHMER_SYMBOLS=new UnicodeBlock("KHMER_SYMBOLS","KHMER SYMBOLS","KHMERSYMBOLS") PHONETIC_EXTENSIONS=new UnicodeBlock("PHONETIC_EXTENSIONS","PHONETIC EXTENSIONS","PHONETICEXTENSIONS") MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A=new UnicodeBlock("MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A","MISCELLANEOUS MATHEMATICAL SYMBOLS-A","MISCELLANEOUSMATHEMATICALSYMBOLS-A") SUPPLEMENTAL_ARROWS_A=new UnicodeBlock("SUPPLEMENTAL_ARROWS_A","SUPPLEMENTAL ARROWS-A","SUPPLEMENTALARROWS-A") SUPPLEMENTAL_ARROWS_B=new UnicodeBlock("SUPPLEMENTAL_ARROWS_B","SUPPLEMENTAL ARROWS-B","SUPPLEMENTALARROWS-B") MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B=new UnicodeBlock("MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B","MISCELLANEOUS MATHEMATICAL SYMBOLS-B","MISCELLANEOUSMATHEMATICALSYMBOLS-B") SUPPLEMENTAL_MATHEMATICAL_OPERATORS=new UnicodeBlock("SUPPLEMENTAL_MATHEMATICAL_OPERATORS","SUPPLEMENTAL MATHEMATICAL OPERATORS","SUPPLEMENTALMATHEMATICALOPERATORS") MISCELLANEOUS_SYMBOLS_AND_ARROWS=new UnicodeBlock("MISCELLANEOUS_SYMBOLS_AND_ARROWS","MISCELLANEOUS SYMBOLS AND ARROWS","MISCELLANEOUSSYMBOLSANDARROWS") KATAKANA_PHONETIC_EXTENSIONS=new UnicodeBlock("KATAKANA_PHONETIC_EXTENSIONS","KATAKANA PHONETIC EXTENSIONS","KATAKANAPHONETICEXTENSIONS") YIJING_HEXAGRAM_SYMBOLS=new UnicodeBlock("YIJING_HEXAGRAM_SYMBOLS","YIJING HEXAGRAM SYMBOLS","YIJINGHEXAGRAMSYMBOLS") VARIATION_SELECTORS=new UnicodeBlock("VARIATION_SELECTORS","VARIATION SELECTORS","VARIATIONSELECTORS") LINEAR_B_SYLLABARY=new UnicodeBlock("LINEAR_B_SYLLABARY","LINEAR B SYLLABARY","LINEARBSYLLABARY") LINEAR_B_IDEOGRAMS=new UnicodeBlock("LINEAR_B_IDEOGRAMS","LINEAR B IDEOGRAMS","LINEARBIDEOGRAMS") AEGEAN_NUMBERS=new UnicodeBlock("AEGEAN_NUMBERS","AEGEAN NUMBERS","AEGEANNUMBERS") OLD_ITALIC=new UnicodeBlock("OLD_ITALIC","OLD ITALIC","OLDITALIC") GOTHIC=new UnicodeBlock("GOTHIC") UGARITIC=new UnicodeBlock("UGARITIC") DESERET=new UnicodeBlock("DESERET") SHAVIAN=new UnicodeBlock("SHAVIAN") OSMANYA=new UnicodeBlock("OSMANYA") CYPRIOT_SYLLABARY=new UnicodeBlock("CYPRIOT_SYLLABARY","CYPRIOT SYLLABARY","CYPRIOTSYLLABARY") BYZANTINE_MUSICAL_SYMBOLS=new UnicodeBlock("BYZANTINE_MUSICAL_SYMBOLS","BYZANTINE MUSICAL SYMBOLS","BYZANTINEMUSICALSYMBOLS") MUSICAL_SYMBOLS=new UnicodeBlock("MUSICAL_SYMBOLS","MUSICAL SYMBOLS","MUSICALSYMBOLS") TAI_XUAN_JING_SYMBOLS=new UnicodeBlock("TAI_XUAN_JING_SYMBOLS","TAI XUAN JING SYMBOLS","TAIXUANJINGSYMBOLS") MATHEMATICAL_ALPHANUMERIC_SYMBOLS=new UnicodeBlock("MATHEMATICAL_ALPHANUMERIC_SYMBOLS","MATHEMATICAL ALPHANUMERIC SYMBOLS","MATHEMATICALALPHANUMERICSYMBOLS") CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B=new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B","CJK UNIFIED IDEOGRAPHS EXTENSION B","CJKUNIFIEDIDEOGRAPHSEXTENSIONB") CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT=new UnicodeBlock("CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT","CJK COMPATIBILITY IDEOGRAPHS SUPPLEMENT","CJKCOMPATIBILITYIDEOGRAPHSSUPPLEMENT") TAGS=new UnicodeBlock("TAGS") VARIATION_SELECTORS_SUPPLEMENT=new UnicodeBlock("VARIATION_SELECTORS_SUPPLEMENT","VARIATION SELECTORS SUPPLEMENT","VARIATIONSELECTORSSUPPLEMENT") SUPPLEMENTARY_PRIVATE_USE_AREA_A=new UnicodeBlock("SUPPLEMENTARY_PRIVATE_USE_AREA_A","SUPPLEMENTARY PRIVATE USE AREA-A","SUPPLEMENTARYPRIVATEUSEAREA-A") SUPPLEMENTARY_PRIVATE_USE_AREA_B=new UnicodeBlock("SUPPLEMENTARY_PRIVATE_USE_AREA_B","SUPPLEMENTARY PRIVATE USE AREA-B","SUPPLEMENTARYPRIVATEUSEAREA-B") HIGH_SURROGATES=new UnicodeBlock("HIGH_SURROGATES","HIGH SURROGATES","HIGHSURROGATES") HIGH_PRIVATE_USE_SURROGATES=new UnicodeBlock("HIGH_PRIVATE_USE_SURROGATES","HIGH PRIVATE USE SURROGATES","HIGHPRIVATEUSESURROGATES") LOW_SURROGATES=new UnicodeBlock("LOW_SURROGATES","LOW SURROGATES","LOWSURROGATES") ARABIC_SUPPLEMENT=new UnicodeBlock("ARABIC_SUPPLEMENT","ARABIC SUPPLEMENT","ARABICSUPPLEMENT") NKO=new UnicodeBlock("NKO") SAMARITAN=new UnicodeBlock("SAMARITAN") MANDAIC=new UnicodeBlock("MANDAIC") ETHIOPIC_SUPPLEMENT=new UnicodeBlock("ETHIOPIC_SUPPLEMENT","ETHIOPIC SUPPLEMENT","ETHIOPICSUPPLEMENT") UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED=new UnicodeBlock("UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED","UNIFIED CANADIAN ABORIGINAL SYLLABICS EXTENDED","UNIFIEDCANADIANABORIGINALSYLLABICSEXTENDED") NEW_TAI_LUE=new UnicodeBlock("NEW_TAI_LUE","NEW TAI LUE","NEWTAILUE") BUGINESE=new UnicodeBlock("BUGINESE") TAI_THAM=new UnicodeBlock("TAI_THAM","TAI THAM","TAITHAM") BALINESE=new UnicodeBlock("BALINESE") SUNDANESE=new UnicodeBlock("SUNDANESE") BATAK=new UnicodeBlock("BATAK") LEPCHA=new UnicodeBlock("LEPCHA") OL_CHIKI=new UnicodeBlock("OL_CHIKI","OL CHIKI","OLCHIKI") VEDIC_EXTENSIONS=new UnicodeBlock("VEDIC_EXTENSIONS","VEDIC EXTENSIONS","VEDICEXTENSIONS") PHONETIC_EXTENSIONS_SUPPLEMENT=new UnicodeBlock("PHONETIC_EXTENSIONS_SUPPLEMENT","PHONETIC EXTENSIONS SUPPLEMENT","PHONETICEXTENSIONSSUPPLEMENT") COMBINING_DIACRITICAL_MARKS_SUPPLEMENT=new UnicodeBlock("COMBINING_DIACRITICAL_MARKS_SUPPLEMENT","COMBINING DIACRITICAL MARKS SUPPLEMENT","COMBININGDIACRITICALMARKSSUPPLEMENT") GLAGOLITIC=new UnicodeBlock("GLAGOLITIC") LATIN_EXTENDED_C=new UnicodeBlock("LATIN_EXTENDED_C","LATIN EXTENDED-C","LATINEXTENDED-C") COPTIC=new UnicodeBlock("COPTIC") GEORGIAN_SUPPLEMENT=new UnicodeBlock("GEORGIAN_SUPPLEMENT","GEORGIAN SUPPLEMENT","GEORGIANSUPPLEMENT") TIFINAGH=new UnicodeBlock("TIFINAGH") ETHIOPIC_EXTENDED=new UnicodeBlock("ETHIOPIC_EXTENDED","ETHIOPIC EXTENDED","ETHIOPICEXTENDED") CYRILLIC_EXTENDED_A=new UnicodeBlock("CYRILLIC_EXTENDED_A","CYRILLIC EXTENDED-A","CYRILLICEXTENDED-A") SUPPLEMENTAL_PUNCTUATION=new UnicodeBlock("SUPPLEMENTAL_PUNCTUATION","SUPPLEMENTAL PUNCTUATION","SUPPLEMENTALPUNCTUATION") CJK_STROKES=new UnicodeBlock("CJK_STROKES","CJK STROKES","CJKSTROKES") LISU=new UnicodeBlock("LISU") VAI=new UnicodeBlock("VAI") CYRILLIC_EXTENDED_B=new UnicodeBlock("CYRILLIC_EXTENDED_B","CYRILLIC EXTENDED-B","CYRILLICEXTENDED-B") BAMUM=new UnicodeBlock("BAMUM") MODIFIER_TONE_LETTERS=new UnicodeBlock("MODIFIER_TONE_LETTERS","MODIFIER TONE LETTERS","MODIFIERTONELETTERS") LATIN_EXTENDED_D=new UnicodeBlock("LATIN_EXTENDED_D","LATIN EXTENDED-D","LATINEXTENDED-D") SYLOTI_NAGRI=new UnicodeBlock("SYLOTI_NAGRI","SYLOTI NAGRI","SYLOTINAGRI") COMMON_INDIC_NUMBER_FORMS=new UnicodeBlock("COMMON_INDIC_NUMBER_FORMS","COMMON INDIC NUMBER FORMS","COMMONINDICNUMBERFORMS") PHAGS_PA=new UnicodeBlock("PHAGS_PA","PHAGS-PA") SAURASHTRA=new UnicodeBlock("SAURASHTRA") DEVANAGARI_EXTENDED=new UnicodeBlock("DEVANAGARI_EXTENDED","DEVANAGARI EXTENDED","DEVANAGARIEXTENDED") KAYAH_LI=new UnicodeBlock("KAYAH_LI","KAYAH LI","KAYAHLI") REJANG=new UnicodeBlock("REJANG") HANGUL_JAMO_EXTENDED_A=new UnicodeBlock("HANGUL_JAMO_EXTENDED_A","HANGUL JAMO EXTENDED-A","HANGULJAMOEXTENDED-A") JAVANESE=new UnicodeBlock("JAVANESE") CHAM=new UnicodeBlock("CHAM") MYANMAR_EXTENDED_A=new UnicodeBlock("MYANMAR_EXTENDED_A","MYANMAR EXTENDED-A","MYANMAREXTENDED-A") TAI_VIET=new UnicodeBlock("TAI_VIET","TAI VIET","TAIVIET") ETHIOPIC_EXTENDED_A=new UnicodeBlock("ETHIOPIC_EXTENDED_A","ETHIOPIC EXTENDED-A","ETHIOPICEXTENDED-A") MEETEI_MAYEK=new UnicodeBlock("MEETEI_MAYEK","MEETEI MAYEK","MEETEIMAYEK") HANGUL_JAMO_EXTENDED_B=new UnicodeBlock("HANGUL_JAMO_EXTENDED_B","HANGUL JAMO EXTENDED-B","HANGULJAMOEXTENDED-B") VERTICAL_FORMS=new UnicodeBlock("VERTICAL_FORMS","VERTICAL FORMS","VERTICALFORMS") ANCIENT_GREEK_NUMBERS=new UnicodeBlock("ANCIENT_GREEK_NUMBERS","ANCIENT GREEK NUMBERS","ANCIENTGREEKNUMBERS") ANCIENT_SYMBOLS=new UnicodeBlock("ANCIENT_SYMBOLS","ANCIENT SYMBOLS","ANCIENTSYMBOLS") PHAISTOS_DISC=new UnicodeBlock("PHAISTOS_DISC","PHAISTOS DISC","PHAISTOSDISC") LYCIAN=new UnicodeBlock("LYCIAN") CARIAN=new UnicodeBlock("CARIAN") OLD_PERSIAN=new UnicodeBlock("OLD_PERSIAN","OLD PERSIAN","OLDPERSIAN") IMPERIAL_ARAMAIC=new UnicodeBlock("IMPERIAL_ARAMAIC","IMPERIAL ARAMAIC","IMPERIALARAMAIC") PHOENICIAN=new UnicodeBlock("PHOENICIAN") LYDIAN=new UnicodeBlock("LYDIAN") KHAROSHTHI=new UnicodeBlock("KHAROSHTHI") OLD_SOUTH_ARABIAN=new UnicodeBlock("OLD_SOUTH_ARABIAN","OLD SOUTH ARABIAN","OLDSOUTHARABIAN") AVESTAN=new UnicodeBlock("AVESTAN") INSCRIPTIONAL_PARTHIAN=new UnicodeBlock("INSCRIPTIONAL_PARTHIAN","INSCRIPTIONAL PARTHIAN","INSCRIPTIONALPARTHIAN") INSCRIPTIONAL_PAHLAVI=new UnicodeBlock("INSCRIPTIONAL_PAHLAVI","INSCRIPTIONAL PAHLAVI","INSCRIPTIONALPAHLAVI") OLD_TURKIC=new UnicodeBlock("OLD_TURKIC","OLD TURKIC","OLDTURKIC") RUMI_NUMERAL_SYMBOLS=new UnicodeBlock("RUMI_NUMERAL_SYMBOLS","RUMI NUMERAL SYMBOLS","RUMINUMERALSYMBOLS") BRAHMI=new UnicodeBlock("BRAHMI") KAITHI=new UnicodeBlock("KAITHI") CUNEIFORM=new UnicodeBlock("CUNEIFORM") CUNEIFORM_NUMBERS_AND_PUNCTUATION=new UnicodeBlock("CUNEIFORM_NUMBERS_AND_PUNCTUATION","CUNEIFORM NUMBERS AND PUNCTUATION","CUNEIFORMNUMBERSANDPUNCTUATION") EGYPTIAN_HIEROGLYPHS=new UnicodeBlock("EGYPTIAN_HIEROGLYPHS","EGYPTIAN HIEROGLYPHS","EGYPTIANHIEROGLYPHS") BAMUM_SUPPLEMENT=new UnicodeBlock("BAMUM_SUPPLEMENT","BAMUM SUPPLEMENT","BAMUMSUPPLEMENT") KANA_SUPPLEMENT=new UnicodeBlock("KANA_SUPPLEMENT","KANA SUPPLEMENT","KANASUPPLEMENT") ANCIENT_GREEK_MUSICAL_NOTATION=new UnicodeBlock("ANCIENT_GREEK_MUSICAL_NOTATION","ANCIENT GREEK MUSICAL NOTATION","ANCIENTGREEKMUSICALNOTATION") COUNTING_ROD_NUMERALS=new UnicodeBlock("COUNTING_ROD_NUMERALS","COUNTING ROD NUMERALS","COUNTINGRODNUMERALS") MAHJONG_TILES=new UnicodeBlock("MAHJONG_TILES","MAHJONG TILES","MAHJONGTILES") DOMINO_TILES=new UnicodeBlock("DOMINO_TILES","DOMINO TILES","DOMINOTILES") PLAYING_CARDS=new UnicodeBlock("PLAYING_CARDS","PLAYING CARDS","PLAYINGCARDS") ENCLOSED_ALPHANUMERIC_SUPPLEMENT=new UnicodeBlock("ENCLOSED_ALPHANUMERIC_SUPPLEMENT","ENCLOSED ALPHANUMERIC SUPPLEMENT","ENCLOSEDALPHANUMERICSUPPLEMENT") ENCLOSED_IDEOGRAPHIC_SUPPLEMENT=new UnicodeBlock("ENCLOSED_IDEOGRAPHIC_SUPPLEMENT","ENCLOSED IDEOGRAPHIC SUPPLEMENT","ENCLOSEDIDEOGRAPHICSUPPLEMENT") MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS=new UnicodeBlock("MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS","MISCELLANEOUS SYMBOLS AND PICTOGRAPHS","MISCELLANEOUSSYMBOLSANDPICTOGRAPHS") EMOTICONS=new UnicodeBlock("EMOTICONS") TRANSPORT_AND_MAP_SYMBOLS=new UnicodeBlock("TRANSPORT_AND_MAP_SYMBOLS","TRANSPORT AND MAP SYMBOLS","TRANSPORTANDMAPSYMBOLS") ALCHEMICAL_SYMBOLS=new UnicodeBlock("ALCHEMICAL_SYMBOLS","ALCHEMICAL SYMBOLS","ALCHEMICALSYMBOLS") CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C=new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C","CJK UNIFIED IDEOGRAPHS EXTENSION C","CJKUNIFIEDIDEOGRAPHSEXTENSIONC") CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D=new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D","CJK UNIFIED IDEOGRAPHS EXTENSION D","CJKUNIFIEDIDEOGRAPHSEXTENSIOND") ARABIC_EXTENDED_A=new UnicodeBlock("ARABIC_EXTENDED_A","ARABIC EXTENDED-A","ARABICEXTENDED-A") SUNDANESE_SUPPLEMENT=new UnicodeBlock("SUNDANESE_SUPPLEMENT","SUNDANESE SUPPLEMENT","SUNDANESESUPPLEMENT") MEETEI_MAYEK_EXTENSIONS=new UnicodeBlock("MEETEI_MAYEK_EXTENSIONS","MEETEI MAYEK EXTENSIONS","MEETEIMAYEKEXTENSIONS") MEROITIC_HIEROGLYPHS=new UnicodeBlock("MEROITIC_HIEROGLYPHS","MEROITIC HIEROGLYPHS","MEROITICHIEROGLYPHS") MEROITIC_CURSIVE=new UnicodeBlock("MEROITIC_CURSIVE","MEROITIC CURSIVE","MEROITICCURSIVE") SORA_SOMPENG=new UnicodeBlock("SORA_SOMPENG","SORA SOMPENG","SORASOMPENG") CHAKMA=new UnicodeBlock("CHAKMA") SHARADA=new UnicodeBlock("SHARADA") TAKRI=new UnicodeBlock("TAKRI") MIAO=new UnicodeBlock("MIAO") ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS=new UnicodeBlock("ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS","ARABIC MATHEMATICAL ALPHABETIC SYMBOLS","ARABICMATHEMATICALALPHABETICSYMBOLS") blockStarts=[] blocks= + Instance Initializer: + Constructors: + constructor UnicodeBlock(idName) throws: + constructor UnicodeBlock(idName,isMap) throws: + cond-branch cond:isMap + true branch : + map.put(idName,this) + false branch : + + constructor UnicodeBlock(idName,alias) throws: + map.put(alias,this) + constructor UnicodeBlock(idName,aliases) throws: + String + alias + aliases + map.put(alias,this) + Methods: + func of(c) throws: + return of((int)c) + func of(codePoint) throws: + cond-branch cond:isValidCodePoint(codePoint) + true branch : + new IllegalArgumentException() + false branch : + + Decl: top,bottom,current + bottom Assign 0 + top Assign blockStarts.length + current Assign top Div 2 + while top Sub bottom GT 1 cond-branch cond:codePoint GE + true branch : + bottom Assign current + false branch : + top Assign current + + current Assign (top Add bottom) Div 2 + + return + LocalClasses: + LocalInterfaces: + LocalInterfaces: + diff --git a/src/MapleFE/test/openjdk/Character-2.java b/src/MapleFE/test/java/openjdk/Character-2.java similarity index 100% rename from src/MapleFE/test/openjdk/Character-2.java rename to src/MapleFE/test/java/openjdk/Character-2.java diff --git a/src/MapleFE/test/openjdk/Character-2.java.result b/src/MapleFE/test/java/openjdk/Character-2.java.result similarity index 77% rename from src/MapleFE/test/openjdk/Character-2.java.result rename to src/MapleFE/test/java/openjdk/Character-2.java.result index 3dba7f116e0ccd4f8eac2e8ff074b1fc0010531c..57633d3b59ff2a36d79c9557e9d32cf09d0b6aff 100644 Binary files a/src/MapleFE/test/openjdk/Character-2.java.result and b/src/MapleFE/test/java/openjdk/Character-2.java.result differ diff --git a/src/MapleFE/test/openjdk/Character-3.java b/src/MapleFE/test/java/openjdk/Character-3.java similarity index 100% rename from src/MapleFE/test/openjdk/Character-3.java rename to src/MapleFE/test/java/openjdk/Character-3.java diff --git a/src/MapleFE/test/openjdk/Character-3.java.result b/src/MapleFE/test/java/openjdk/Character-3.java.result similarity index 96% rename from src/MapleFE/test/openjdk/Character-3.java.result rename to src/MapleFE/test/java/openjdk/Character-3.java.result index 5e7b55c8cfbffe30ecb9973faf6c0c2d1ff48e86..96e1415cc94ad9c912b3a7ff8d4185b15f7e08d1 100644 --- a/src/MapleFE/test/openjdk/Character-3.java.result +++ b/src/MapleFE/test/java/openjdk/Character-3.java.result @@ -7,7 +7,7 @@ class Character Instance Initializer: Constructors: Methods: - func isWhitespace() throws: + func isWhitespace(codePoint) throws: cond-branch cond:(codePoint GE 28 Land codePoint LE 32) Lor (codePoint GE 9 Land codePoint LE 13) true branch : return true diff --git a/src/MapleFE/test/openjdk/Character.java b/src/MapleFE/test/java/openjdk/Character.java similarity index 100% rename from src/MapleFE/test/openjdk/Character.java rename to src/MapleFE/test/java/openjdk/Character.java diff --git a/src/MapleFE/test/openjdk/Character.java.result b/src/MapleFE/test/java/openjdk/Character.java.result similarity index 30% rename from src/MapleFE/test/openjdk/Character.java.result rename to src/MapleFE/test/java/openjdk/Character.java.result index f074c02b6c61834e1a3f55ab5542329269e33d9a..3ab414e2dfa0b84f28a4e026a1d301519307fc0f 100644 --- a/src/MapleFE/test/openjdk/Character.java.result +++ b/src/MapleFE/test/java/openjdk/Character.java.result @@ -4,7 +4,7 @@ Matched 21 tokens. Matched 28 tokens. Matched 35 tokens. Matched 42 tokens. -Matched 11999 tokens. +Matched 11996 tokens. ============= Module =========== == Sub Tree == package java.lang @@ -21,63 +21,61 @@ import java.util.Map == Sub Tree == class Character Fields: - MIN_RADIX=2 MAX_RADIX=36 MIN_VALUE=0 MAX_VALUE=65535 TYPE=() UNASSIGNED=0 UPPERCASE_LETTER=1 LOWERCASE_LETTER=2 TITLECASE_LETTER=3 MODIFIER_LETTER=4 OTHER_LETTER=5 NON_SPACING_MARK=6 ENCLOSING_MARK=7 COMBINING_SPACING_MARK=8 DECIMAL_DIGIT_NUMBER=9 LETTER_NUMBER=10 OTHER_NUMBER=11 SPACE_SEPARATOR=12 LINE_SEPARATOR=13 PARAGRAPH_SEPARATOR=14 CONTROL=15 FORMAT=16 PRIVATE_USE=18 SURROGATE=19 DASH_PUNCTUATION=20 START_PUNCTUATION=21 END_PUNCTUATION=22 CONNECTOR_PUNCTUATION=23 OTHER_PUNCTUATION=24 MATH_SYMBOL=25 CURRENCY_SYMBOL=26 MODIFIER_SYMBOL=27 OTHER_SYMBOL=28 INITIAL_QUOTE_PUNCTUATION=29 FINAL_QUOTE_PUNCTUATION=30 ERROR=-1 DIRECTIONALITY_UNDEFINED=Sub - 1 DIRECTIONALITY_LEFT_TO_RIGHT=0 DIRECTIONALITY_RIGHT_TO_LEFT=1 DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC=2 DIRECTIONALITY_EUROPEAN_NUMBER=3 DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR=4 DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR=5 DIRECTIONALITY_ARABIC_NUMBER=6 DIRECTIONALITY_COMMON_NUMBER_SEPARATOR=7 DIRECTIONALITY_NONSPACING_MARK=8 DIRECTIONALITY_BOUNDARY_NEUTRAL=9 DIRECTIONALITY_PARAGRAPH_SEPARATOR=10 DIRECTIONALITY_SEGMENT_SEPARATOR=11 DIRECTIONALITY_WHITESPACE=12 DIRECTIONALITY_OTHER_NEUTRALS=13 DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING=14 DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE=15 DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING=16 DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE=17 DIRECTIONALITY_POP_DIRECTIONAL_FORMAT=18 MIN_HIGH_SURROGATE=55296 MAX_HIGH_SURROGATE=56319 MIN_LOW_SURROGATE=56320 MAX_LOW_SURROGATE=57343 MIN_SURROGATE=MIN_HIGH_SURROGATE MAX_SURROGATE=MAX_LOW_SURROGATE MIN_SUPPLEMENTARY_CODE_POINT=65536 MIN_CODE_POINT=0 MAX_CODE_POINT=1114111 DIRECTIONALITY= value serialVersionUID=1796875896 SIZE=16 BYTES= + MIN_RADIX=2 MAX_RADIX=36 MIN_VALUE=0 MAX_VALUE=65535 TYPE=()char.getComponentType() UNASSIGNED=0 UPPERCASE_LETTER=1 LOWERCASE_LETTER=2 TITLECASE_LETTER=3 MODIFIER_LETTER=4 OTHER_LETTER=5 NON_SPACING_MARK=6 ENCLOSING_MARK=7 COMBINING_SPACING_MARK=8 DECIMAL_DIGIT_NUMBER=9 LETTER_NUMBER=10 OTHER_NUMBER=11 SPACE_SEPARATOR=12 LINE_SEPARATOR=13 PARAGRAPH_SEPARATOR=14 CONTROL=15 FORMAT=16 PRIVATE_USE=18 SURROGATE=19 DASH_PUNCTUATION=20 START_PUNCTUATION=21 END_PUNCTUATION=22 CONNECTOR_PUNCTUATION=23 OTHER_PUNCTUATION=24 MATH_SYMBOL=25 CURRENCY_SYMBOL=26 MODIFIER_SYMBOL=27 OTHER_SYMBOL=28 INITIAL_QUOTE_PUNCTUATION=29 FINAL_QUOTE_PUNCTUATION=30 ERROR=-1 DIRECTIONALITY_UNDEFINED=-1 DIRECTIONALITY_LEFT_TO_RIGHT=0 DIRECTIONALITY_RIGHT_TO_LEFT=1 DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC=2 DIRECTIONALITY_EUROPEAN_NUMBER=3 DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR=4 DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR=5 DIRECTIONALITY_ARABIC_NUMBER=6 DIRECTIONALITY_COMMON_NUMBER_SEPARATOR=7 DIRECTIONALITY_NONSPACING_MARK=8 DIRECTIONALITY_BOUNDARY_NEUTRAL=9 DIRECTIONALITY_PARAGRAPH_SEPARATOR=10 DIRECTIONALITY_SEGMENT_SEPARATOR=11 DIRECTIONALITY_WHITESPACE=12 DIRECTIONALITY_OTHER_NEUTRALS=13 DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING=14 DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE=15 DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING=16 DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE=17 DIRECTIONALITY_POP_DIRECTIONAL_FORMAT=18 MIN_HIGH_SURROGATE=55296 MAX_HIGH_SURROGATE=56319 MIN_LOW_SURROGATE=56320 MAX_LOW_SURROGATE=57343 MIN_SURROGATE=MIN_HIGH_SURROGATE MAX_SURROGATE=MAX_LOW_SURROGATE MIN_SUPPLEMENTARY_CODE_POINT=65536 MIN_CODE_POINT=0 MAX_CODE_POINT=1114111 DIRECTIONALITY= value serialVersionUID=1796875896 SIZE=16 BYTES=SIZE Div Byte.SIZE Instance Initializer: Constructors: - constructor Character() throws: + constructor Character(value) throws: this.value Assign value Methods: - func valueOf() throws: + func valueOf(c) throws: cond-branch cond:c LE 127 true branch : return false branch : - return new Character + return new Character(c) func charValue() throws: return value func hashCode() throws: return Character.hashCode(value) - func hashCode() throws: + func hashCode(value) throws: return (int)value - func equals() throws: - cond-branch cond: + func equals(obj) throws: + cond-branch cond:obj instanceof Character true branch : - return value EQ ((Character)obj)charValue + return value EQ (Character)obj.charValue() false branch : return false func toString() throws: - var:buf=value[] + Decl: buf=value[] return String.valueOf(buf) - func toString() throws: + func toString(c) throws: return String.valueOf(c) - func isValidCodePoint() throws: - var:plane=codePoint Zext 16 + func isValidCodePoint(codePoint) throws: + Decl: plane=codePoint Zext 16 return plane LT ((MAX_CODE_POINT Add 1) Zext 16) - func isBmpCodePoint() throws: + func isBmpCodePoint(codePoint) throws: return codePoint Zext 16 EQ 0 - func isSupplementaryCodePoint() throws: + func isSupplementaryCodePoint(codePoint) throws: return codePoint GE MIN_SUPPLEMENTARY_CODE_POINT Land codePoint LT MAX_CODE_POINT Add 1 - func isHighSurrogate() throws: + func isHighSurrogate(ch) throws: return ch GE MIN_HIGH_SURROGATE Land ch LT (MAX_HIGH_SURROGATE Add 1) - func isLowSurrogate() throws: + func isLowSurrogate(ch) throws: return ch GE MIN_LOW_SURROGATE Land ch LT (MAX_LOW_SURROGATE Add 1) - func isSurrogate() throws: + func isSurrogate(ch) throws: return ch GE MIN_SURROGATE Land ch LT (MAX_SURROGATE Add 1) - func isSurrogatePair() throws: + func isSurrogatePair(high,low) throws: return isHighSurrogate(high) Land isLowSurrogate(low) - func charCount() throws: + func charCount(codePoint) throws: return - func toCodePoint() throws: + func toCodePoint(high,low) throws: return ((high Shl 10) Add low) Add (MIN_SUPPLEMENTARY_CODE_POINT Sub (MIN_HIGH_SURROGATE Shl 10) Sub MIN_LOW_SURROGATE) - func codePointAt() throws: - var:c1=seq.charAt(index) - cond-branch cond:isHighSurrogate(c1) Land Inc - index LT seq.length() + func codePointAt(seq,index) throws: + Decl: c1=seq.charAt(index) + cond-branch cond:isHighSurrogate(c1) Land PreInc index LT seq.length() true branch : - var:c2=seq.charAt(index) + Decl: c2=seq.charAt(index) cond-branch cond:isLowSurrogate(c2) true branch : return toCodePoint(c1,c2) @@ -86,21 +84,20 @@ class Character false branch : return c1 - func codePointAt() throws: + func codePointAt(a,index) throws: return codePointAtImpl(a,index,a.length) - func codePointAt() throws: + func codePointAt(a,index,limit) throws: cond-branch cond:index GE limit Lor limit LT 0 Lor limit GT a.length true branch : - new IndexOutOfBoundsException + new IndexOutOfBoundsException() false branch : return codePointAtImpl(a,index,limit) - func codePointAtImpl() throws: - var:c1= - cond-branch cond:isHighSurrogate(c1) Land Inc - index LT limit + func codePointAtImpl(a,index,limit) throws: + Decl: c1= + cond-branch cond:isHighSurrogate(c1) Land PreInc index LT limit true branch : - var:c2= + Decl: c2= cond-branch cond:isLowSurrogate(c2) true branch : return toCodePoint(c1,c2) @@ -109,13 +106,11 @@ class Character false branch : return c1 - func codePointBefore() throws: - var:c2=seq.charAt(Dec - index) + func codePointBefore(seq,index) throws: + Decl: c2=seq.charAt(PreDec index) cond-branch cond:isLowSurrogate(c2) Land index GT 0 true branch : - var:c1=seq.charAt(Dec - index) + Decl: c1=seq.charAt(PreDec index) cond-branch cond:isHighSurrogate(c1) true branch : return toCodePoint(c1,c2) @@ -124,20 +119,20 @@ class Character false branch : return c2 - func codePointBefore() throws: + func codePointBefore(a,index) throws: return codePointBeforeImpl(a,index,0) - func codePointBefore() throws: + func codePointBefore(a,index,start) throws: cond-branch cond:index LE start Lor start LT 0 Lor start GE a.length true branch : - new IndexOutOfBoundsException + new IndexOutOfBoundsException() false branch : return codePointBeforeImpl(a,index,start) - func codePointBeforeImpl() throws: - var:c2= + func codePointBeforeImpl(a,index,start) throws: + Decl: c2= cond-branch cond:isLowSurrogate(c2) Land index GT start true branch : - var:c1= + Decl: c1= cond-branch cond:isHighSurrogate(c1) true branch : return toCodePoint(c1,c2) @@ -146,11 +141,11 @@ class Character false branch : return c2 - func highSurrogate() throws: + func highSurrogate(codePoint) throws: return (char)((codePoint Zext 10) Add (MIN_HIGH_SURROGATE Sub (MIN_SUPPLEMENTARY_CODE_POINT Zext 10))) - func lowSurrogate() throws: + func lowSurrogate(codePoint) throws: return (char)((codePoint Band 1023) Add MIN_LOW_SURROGATE) - func toChars() throws: + func toChars(codePoint,dst,dstIndex) throws: cond-branch cond:isBmpCodePoint(codePoint) true branch : Assign (char)codePoint @@ -161,150 +156,200 @@ class Character toSurrogates(codePoint,dst,dstIndex) return 2 false branch : - new IllegalArgumentException + new IllegalArgumentException() - - func toChars() throws: + func toChars(codePoint) throws: cond-branch cond:isBmpCodePoint(codePoint) true branch : return false branch : cond-branch cond:isValidCodePoint(codePoint) true branch : - var:result= - + Decl: result= + toSurrogates(codePoint,result,0) + return result false branch : - new IllegalArgumentException + new IllegalArgumentException() - - func toSurrogates() throws: + func toSurrogates(codePoint,dst,index) throws: Assign lowSurrogate(codePoint) Assign highSurrogate(codePoint) - func codePointCount() throws: - var:length=seq.length() + func codePointCount(seq,beginIndex,endIndex) throws: + Decl: length=seq.length() cond-branch cond:beginIndex LT 0 Lor endIndex GT length Lor beginIndex GT endIndex true branch : - new IndexOutOfBoundsException + new IndexOutOfBoundsException() false branch : - var:n=endIndex Sub beginIndex + Decl: n=endIndex Sub beginIndex for ( ) - cond-branch cond:isHighSurrogate(seq.charAt( iInc + cond-branch cond:isHighSurrogate(seq.charAt(i Inc )) Land i LT endIndex Land isLowSurrogate(seq.charAt(i)) true branch : - nDec + n Dec - iInc + i Inc false branch : return n - func codePointCount() throws: + func codePointCount(a,offset,count) throws: cond-branch cond:count GT a.length Sub offset Lor offset LT 0 Lor count LT 0 true branch : - new IndexOutOfBoundsException + new IndexOutOfBoundsException() false branch : return codePointCountImpl(a,offset,count) - func codePointCountImpl() throws: - var:endIndex=offset Add count - var:n=count + func codePointCountImpl(a,offset,count) throws: + Decl: endIndex=offset Add count + Decl: n=count for ( ) - cond-branch cond:isHighSurrogate(a, iInc + cond-branch cond:isHighSurrogate(a,i Inc ) Land i LT endIndex Land isLowSurrogate(a,i) true branch : - nDec + n Dec - iInc + i Inc false branch : return n - func offsetByCodePoints() throws: - var:length=seq.length() + func offsetByCodePoints(seq,index,codePointOffset) throws: + Decl: length=seq.length() cond-branch cond:index LT 0 Lor index GT length true branch : - new IndexOutOfBoundsException + new IndexOutOfBoundsException() false branch : - var:x=index + Decl: x=index cond-branch cond:codePointOffset GE 0 true branch : - var:i + Decl: i + for ( ) + cond-branch cond:isHighSurrogate(seq.charAt(x Inc +)) Land x LT length Land isLowSurrogate(seq.charAt(x)) + true branch : + x Inc + + false branch : + + + cond-branch cond:i LT codePointOffset + true branch : + new IndexOutOfBoundsException() + false branch : false branch : - var:i + Decl: i + for ( ) + cond-branch cond:isLowSurrogate(seq.charAt(PreDec x)) Land x GT 0 Land isHighSurrogate(seq.charAt(x Sub 1)) + true branch : + x Dec + + false branch : + + + cond-branch cond:i LT 0 + true branch : + new IndexOutOfBoundsException() + false branch : return x - func offsetByCodePoints() throws: + func offsetByCodePoints(a,start,count,index,codePointOffset) throws: cond-branch cond:count GT a.length Sub start Lor start LT 0 Lor count LT 0 Lor index LT start Lor index GT start Add count true branch : - new IndexOutOfBoundsException + new IndexOutOfBoundsException() false branch : return offsetByCodePointsImpl(a,start,count,index,codePointOffset) - func offsetByCodePointsImpl() throws: - var:x=index + func offsetByCodePointsImpl(a,start,count,index,codePointOffset) throws: + Decl: x=index cond-branch cond:codePointOffset GE 0 true branch : - var:limit=start Add count + Decl: limit=start Add count + Decl: i + for ( ) + cond-branch cond:isHighSurrogate(a,x Inc +) Land x LT limit Land isLowSurrogate(a,x) + true branch : + x Inc + + false branch : + + + cond-branch cond:i LT codePointOffset + true branch : + new IndexOutOfBoundsException() + false branch : false branch : - var:i + Decl: i + for ( ) + cond-branch cond:isLowSurrogate(a,PreDec x) Land x GT start Land isHighSurrogate(a,x Sub 1) + true branch : + x Dec + + false branch : + + + cond-branch cond:i LT 0 + true branch : + new IndexOutOfBoundsException() + false branch : return x - func isLowerCase() throws: + func isLowerCase(ch) throws: return isLowerCase((int)ch) - func isLowerCase() throws: + func isLowerCase(codePoint) throws: return isLowerCaseImpl(codePoint) - func isLowerCaseImpl() throws: - func isUpperCase() throws: + func isLowerCaseImpl(codePoint) throws: + func isUpperCase(ch) throws: return isUpperCase((int)ch) - func isUpperCase() throws: + func isUpperCase(codePoint) throws: return isUpperCaseImpl(codePoint) - func isUpperCaseImpl() throws: - func isTitleCase() throws: + func isUpperCaseImpl(codePoint) throws: + func isTitleCase(ch) throws: return isTitleCase((int)ch) - func isTitleCase() throws: + func isTitleCase(codePoint) throws: return isTitleCaseImpl(codePoint) - func isTitleCaseImpl() throws: - func isDigit() throws: + func isTitleCaseImpl(codePoint) throws: + func isDigit(ch) throws: return isDigit((int)ch) - func isDigit() throws: + func isDigit(codePoint) throws: return isDigitImpl(codePoint) - func isDigitImpl() throws: - func isDefined() throws: + func isDigitImpl(codePoint) throws: + func isDefined(ch) throws: return isDefined((int)ch) - func isDefined() throws: + func isDefined(codePoint) throws: return isDefinedImpl(codePoint) - func isDefinedImpl() throws: - func isLetter() throws: + func isDefinedImpl(codePoint) throws: + func isLetter(ch) throws: return isLetter((int)ch) - func isLetter() throws: + func isLetter(codePoint) throws: return isLetterImpl(codePoint) - func isLetterImpl() throws: - func isLetterOrDigit() throws: + func isLetterImpl(codePoint) throws: + func isLetterOrDigit(ch) throws: return isLetterOrDigit((int)ch) - func isLetterOrDigit() throws: + func isLetterOrDigit(codePoint) throws: return isLetterOrDigitImpl(codePoint) - func isLetterOrDigitImpl() throws: - func isJavaLetter() throws: + func isLetterOrDigitImpl(codePoint) throws: + func isJavaLetter(ch) throws: return isJavaIdentifierStart(ch) - func isJavaLetterOrDigit() throws: + func isJavaLetterOrDigit(ch) throws: return isJavaIdentifierPart(ch) - func isAlphabetic() throws: + func isAlphabetic(codePoint) throws: return isAlphabeticImpl(codePoint) - func isAlphabeticImpl() throws: - func isIdeographic() throws: + func isAlphabeticImpl(codePoint) throws: + func isIdeographic(codePoint) throws: return isIdeographicImpl(codePoint) - func isIdeographicImpl() throws: - func isJavaIdentifierStart() throws: + func isIdeographicImpl(codePoint) throws: + func isJavaIdentifierStart(ch) throws: return isJavaIdentifierStart((int)ch) - func isJavaIdentifierStart() throws: + func isJavaIdentifierStart(codePoint) throws: cond-branch cond:codePoint LT 64 true branch : return (codePoint EQ $) @@ -314,11 +359,10 @@ class Character return (2147483630 Band (1 Shl (codePoint Sub 64))) NE 0 false branch : - return ((1 Shl getType(codePoint)) Band ((1 Shl UPPERCASE_LETTER) Bor (1 Shl LOWERCASE_LETTER) Bor (1 Shl TITLECASE_LETTER) Bor (1 Shl MODIFIER_LETTER) Bor (1 Shl OTHER_LETTER) Bor (1 Shl CURRENCY_SYMBOL) Bor (1 Shl CONNECTOR_PUNCTUATION) Bor (1 Shl LETTER_NUMBER))) NE 0 - func isJavaIdentifierPart() throws: + func isJavaIdentifierPart(ch) throws: return isJavaIdentifierPart((int)ch) - func isJavaIdentifierPart() throws: + func isJavaIdentifierPart(codePoint) throws: cond-branch cond:codePoint LT 64 true branch : return (-253953 Band (1 Shl codePoint)) NE 0 @@ -328,26 +372,25 @@ class Character return (2147483630 Band (1 Shl (codePoint Sub 64))) NE 0 false branch : - return ((1 Shl getType(codePoint)) Band ((1 Shl UPPERCASE_LETTER) Bor (1 Shl LOWERCASE_LETTER) Bor (1 Shl TITLECASE_LETTER) Bor (1 Shl MODIFIER_LETTER) Bor (1 Shl OTHER_LETTER) Bor (1 Shl CURRENCY_SYMBOL) Bor (1 Shl CONNECTOR_PUNCTUATION) Bor (1 Shl DECIMAL_DIGIT_NUMBER) Bor (1 Shl LETTER_NUMBER) Bor (1 Shl FORMAT) Bor (1 Shl COMBINING_SPACING_MARK) Bor (1 Shl NON_SPACING_MARK))) NE 0 Lor (codePoint GE 0 Land codePoint LE 8) Lor (codePoint GE 14 Land codePoint LE 27) Lor (codePoint GE 127 Land codePoint LE 159) - func isUnicodeIdentifierStart() throws: + func isUnicodeIdentifierStart(ch) throws: return isUnicodeIdentifierStart((int)ch) - func isUnicodeIdentifierStart() throws: + func isUnicodeIdentifierStart(codePoint) throws: return isUnicodeIdentifierStartImpl(codePoint) - func isUnicodeIdentifierStartImpl() throws: - func isUnicodeIdentifierPart() throws: + func isUnicodeIdentifierStartImpl(codePoint) throws: + func isUnicodeIdentifierPart(ch) throws: return isUnicodeIdentifierPart((int)ch) - func isUnicodeIdentifierPart() throws: + func isUnicodeIdentifierPart(codePoint) throws: return isUnicodeIdentifierPartImpl(codePoint) - func isUnicodeIdentifierPartImpl() throws: - func isIdentifierIgnorable() throws: + func isUnicodeIdentifierPartImpl(codePoint) throws: + func isIdentifierIgnorable(ch) throws: return isIdentifierIgnorable((int)ch) - func isIdentifierIgnorable() throws: + func isIdentifierIgnorable(codePoint) throws: return isIdentifierIgnorableImpl(codePoint) - func isIdentifierIgnorableImpl() throws: - func toLowerCase() throws: + func isIdentifierIgnorableImpl(codePoint) throws: + func toLowerCase(ch) throws: return (char)toLowerCase((int)ch) - func toLowerCase() throws: + func toLowerCase(codePoint) throws: cond-branch cond:codePoint GE A Land codePoint LE Z true branch : return codePoint Add (a Sub A) @@ -359,10 +402,10 @@ class Character false branch : return toLowerCaseImpl(codePoint) - func toLowerCaseImpl() throws: - func toUpperCase() throws: + func toLowerCaseImpl(codePoint) throws: + func toUpperCase(ch) throws: return (char)toUpperCase((int)ch) - func toUpperCase() throws: + func toUpperCase(codePoint) throws: cond-branch cond:codePoint GE a Land codePoint LE z true branch : return codePoint Sub (a Sub A) @@ -374,33 +417,44 @@ class Character false branch : return toUpperCaseImpl(codePoint) - func toUpperCaseImpl() throws: - func toTitleCase() throws: + func toUpperCaseImpl(codePoint) throws: + func toTitleCase(ch) throws: return (char)toTitleCase((int)ch) - func toTitleCase() throws: + func toTitleCase(codePoint) throws: return toTitleCaseImpl(codePoint) - func toTitleCaseImpl() throws: - func digit() throws: + func toTitleCaseImpl(codePoint) throws: + func digit(ch,radix) throws: return digit((int)ch,radix) - func digit() throws: + func digit(codePoint,radix) throws: cond-branch cond:radix LT MIN_RADIX Lor radix GT MAX_RADIX true branch : - return Sub - 1 + return -1 false branch : cond-branch cond:codePoint LT 128 true branch : - var:result=Sub - 1 + Decl: result=-1 + cond-branch cond:0 LE codePoint Land codePoint LE 9 + true branch : + result Assign codePoint Sub 0 + false branch : + cond-branch cond:a LE codePoint Land codePoint LE z + true branch : + result Assign 10 Add (codePoint Sub a) + false branch : + cond-branch cond:A LE codePoint Land codePoint LE Z + true branch : + result Assign 10 Add (codePoint Sub A) + false branch : + return false branch : return digitImpl(codePoint,radix) - func digitImpl() throws: - func getNumericValue() throws: + func digitImpl(codePoint,radix) throws: + func getNumericValue(ch) throws: return getNumericValue((int)ch) - func getNumericValue() throws: + func getNumericValue(codePoint) throws: cond-branch cond:codePoint LT 128 true branch : cond-branch cond:codePoint GE 0 Land codePoint LE 9 @@ -408,7 +462,17 @@ class Character return codePoint Sub 0 false branch : + cond-branch cond:codePoint GE a Land codePoint LE z + true branch : + return codePoint Sub (a Sub 10) + false branch : + cond-branch cond:codePoint GE A Land codePoint LE Z + true branch : + return codePoint Sub (A Sub 10) + false branch : + + return -1 false branch : cond-branch cond:codePoint GE 65313 Land codePoint LE 65338 @@ -422,12 +486,12 @@ class Character false branch : return getNumericValueImpl(codePoint) - func getNumericValueImpl() throws: - func isSpace() throws: + func getNumericValueImpl(codePoint) throws: + func isSpace(ch) throws: return (ch LE 32) Land (((((1 Shl 9) Bor (1 Shl 10) Bor (1 Shl 12) Bor (1 Shl 13) Bor (1 Shl 32)) Shr ch) Band 1) NE 0) - func isSpaceChar() throws: + func isSpaceChar(ch) throws: return isSpaceChar((int)ch) - func isSpaceChar() throws: + func isSpaceChar(codePoint) throws: cond-branch cond:codePoint EQ 32 Lor codePoint EQ 160 true branch : return true @@ -454,10 +518,10 @@ class Character false branch : return isSpaceCharImpl(codePoint) - func isSpaceCharImpl() throws: - func isWhitespace() throws: + func isSpaceCharImpl(codePoint) throws: + func isWhitespace(ch) throws: return isWhitespace((int)ch) - func isWhitespace() throws: + func isWhitespace(codePoint) throws: cond-branch cond:(codePoint GE 28 Land codePoint LE 32) Lor (codePoint GE 9 Land codePoint LE 13) true branch : return true @@ -489,23 +553,23 @@ class Character false branch : return isWhitespaceImpl(codePoint) - func isWhitespaceImpl() throws: - func isISOControl() throws: + func isWhitespaceImpl(codePoint) throws: + func isISOControl(ch) throws: return isISOControl((int)ch) - func isISOControl() throws: + func isISOControl(codePoint) throws: return codePoint LE 159 Land (codePoint GE 127 Lor (codePoint Zext 5 EQ 0)) - func getType() throws: + func getType(ch) throws: return getType((int)ch) - func getType() throws: - var:type=getTypeImpl(codePoint) + func getType(codePoint) throws: + Decl: type=getTypeImpl(codePoint) cond-branch cond:type LE Character.FORMAT true branch : return type false branch : return (type Add 1) - func getTypeImpl() throws: - func forDigit() throws: + func getTypeImpl(codePoint) throws: + func forDigit(digit,radix) throws: cond-branch cond:(digit GE radix) Lor (digit LT 0) true branch : return @@ -522,126 +586,123 @@ class Character false branch : return (char)(a Sub 10 Add digit) - func getDirectionality() throws: + func getDirectionality(ch) throws: return getDirectionality((int)ch) - func getDirectionality() throws: + func getDirectionality(codePoint) throws: cond-branch cond:getType(codePoint) EQ Character.UNASSIGNED true branch : return Character.DIRECTIONALITY_UNDEFINED false branch : - var:directionality=getDirectionalityImpl(codePoint) + Decl: directionality=getDirectionalityImpl(codePoint) cond-branch cond:directionality GE 0 Land directionality LT DIRECTIONALITY.length true branch : return false branch : return Character.DIRECTIONALITY_UNDEFINED - func getDirectionalityImpl() throws: - func isMirrored() throws: + func getDirectionalityImpl(codePoint) throws: + func isMirrored(ch) throws: return isMirrored((int)ch) - func isMirrored() throws: + func isMirrored(codePoint) throws: return isMirroredImpl(codePoint) - func isMirroredImpl() throws: - func compareTo() throws: + func isMirroredImpl(codePoint) throws: + func compareTo(anotherCharacter) throws: return compare(this.value,anotherCharacter.value) - func compare() throws: + func compare(x,y) throws: return x Sub y - func reverseBytes() throws: + func reverseBytes(ch) throws: return (char)(((ch Band 65280) Shr 8) Bor (ch Shl 8)) - func getName() throws: + func getName(codePoint) throws: cond-branch cond:isValidCodePoint(codePoint) true branch : - new IllegalArgumentException + new IllegalArgumentException() false branch : - var:name=getNameImpl(codePoint) + Decl: name=getNameImpl(codePoint) cond-branch cond:name NE null true branch : - return name - false branch : + return name false branch : cond-branch cond:getType(codePoint) EQ UNASSIGNED true branch : - return null - false branch : + return null false branch : - var:block=UnicodeBlock.of(codePoint) + Decl: block=UnicodeBlock.of(codePoint) cond-branch cond:block NE null true branch : - return Add " " Add - false branch : + return block.toString().replace(_, ) Add " " Add Integer.toHexString(codePoint).toUpperCase(Locale.ENGLISH) false branch : - return - func getNameImpl() throws: + return Integer.toHexString(codePoint).toUpperCase(Locale.ENGLISH) + func getNameImpl(codePoint) throws: LocalClasses: class Subset Fields: name Instance Initializer: Constructors: - constructor Subset() throws: + constructor Subset(name) throws: cond-branch cond:name EQ null true branch : - new NullPointerException + new NullPointerException("name") false branch : this.name Assign name Methods: - func equals() throws: + func equals(obj) throws: return (this EQ obj) func hashCode() throws: - return hashCode + return super.hashCode() func toString() throws: return name LocalClasses: LocalInterfaces: class UnicodeBlock Fields: - map=new HashMap BASIC_LATIN=new UnicodeBlock LATIN_1_SUPPLEMENT=new UnicodeBlock LATIN_EXTENDED_A=new UnicodeBlock LATIN_EXTENDED_B=new UnicodeBlock IPA_EXTENSIONS=new UnicodeBlock SPACING_MODIFIER_LETTERS=new UnicodeBlock COMBINING_DIACRITICAL_MARKS=new UnicodeBlock GREEK=new UnicodeBlock CYRILLIC=new UnicodeBlock ARMENIAN=new UnicodeBlock HEBREW=new UnicodeBlock ARABIC=new UnicodeBlock DEVANAGARI=new UnicodeBlock BENGALI=new UnicodeBlock GURMUKHI=new UnicodeBlock GUJARATI=new UnicodeBlock ORIYA=new UnicodeBlock TAMIL=new UnicodeBlock TELUGU=new UnicodeBlock KANNADA=new UnicodeBlock MALAYALAM=new UnicodeBlock THAI=new UnicodeBlock LAO=new UnicodeBlock TIBETAN=new UnicodeBlock GEORGIAN=new UnicodeBlock HANGUL_JAMO=new UnicodeBlock LATIN_EXTENDED_ADDITIONAL=new UnicodeBlock GREEK_EXTENDED=new UnicodeBlock GENERAL_PUNCTUATION=new UnicodeBlock SUPERSCRIPTS_AND_SUBSCRIPTS=new UnicodeBlock CURRENCY_SYMBOLS=new UnicodeBlock COMBINING_MARKS_FOR_SYMBOLS=new UnicodeBlock LETTERLIKE_SYMBOLS=new UnicodeBlock NUMBER_FORMS=new UnicodeBlock ARROWS=new UnicodeBlock MATHEMATICAL_OPERATORS=new UnicodeBlock MISCELLANEOUS_TECHNICAL=new UnicodeBlock CONTROL_PICTURES=new UnicodeBlock OPTICAL_CHARACTER_RECOGNITION=new UnicodeBlock ENCLOSED_ALPHANUMERICS=new UnicodeBlock BOX_DRAWING=new UnicodeBlock BLOCK_ELEMENTS=new UnicodeBlock GEOMETRIC_SHAPES=new UnicodeBlock MISCELLANEOUS_SYMBOLS=new UnicodeBlock DINGBATS=new UnicodeBlock CJK_SYMBOLS_AND_PUNCTUATION=new UnicodeBlock HIRAGANA=new UnicodeBlock KATAKANA=new UnicodeBlock BOPOMOFO=new UnicodeBlock HANGUL_COMPATIBILITY_JAMO=new UnicodeBlock KANBUN=new UnicodeBlock ENCLOSED_CJK_LETTERS_AND_MONTHS=new UnicodeBlock CJK_COMPATIBILITY=new UnicodeBlock CJK_UNIFIED_IDEOGRAPHS=new UnicodeBlock HANGUL_SYLLABLES=new UnicodeBlock PRIVATE_USE_AREA=new UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS=new UnicodeBlock ALPHABETIC_PRESENTATION_FORMS=new UnicodeBlock ARABIC_PRESENTATION_FORMS_A=new UnicodeBlock COMBINING_HALF_MARKS=new UnicodeBlock CJK_COMPATIBILITY_FORMS=new UnicodeBlock SMALL_FORM_VARIANTS=new UnicodeBlock ARABIC_PRESENTATION_FORMS_B=new UnicodeBlock HALFWIDTH_AND_FULLWIDTH_FORMS=new UnicodeBlock SPECIALS=new UnicodeBlock SURROGATES_AREA=new UnicodeBlock SYRIAC=new UnicodeBlock THAANA=new UnicodeBlock SINHALA=new UnicodeBlock MYANMAR=new UnicodeBlock ETHIOPIC=new UnicodeBlock CHEROKEE=new UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS=new UnicodeBlock OGHAM=new UnicodeBlock RUNIC=new UnicodeBlock KHMER=new UnicodeBlock MONGOLIAN=new UnicodeBlock BRAILLE_PATTERNS=new UnicodeBlock CJK_RADICALS_SUPPLEMENT=new UnicodeBlock KANGXI_RADICALS=new UnicodeBlock IDEOGRAPHIC_DESCRIPTION_CHARACTERS=new UnicodeBlock BOPOMOFO_EXTENDED=new UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A=new UnicodeBlock YI_SYLLABLES=new UnicodeBlock YI_RADICALS=new UnicodeBlock CYRILLIC_SUPPLEMENTARY=new UnicodeBlock TAGALOG=new UnicodeBlock HANUNOO=new UnicodeBlock BUHID=new UnicodeBlock TAGBANWA=new UnicodeBlock LIMBU=new UnicodeBlock TAI_LE=new UnicodeBlock KHMER_SYMBOLS=new UnicodeBlock PHONETIC_EXTENSIONS=new UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A=new UnicodeBlock SUPPLEMENTAL_ARROWS_A=new UnicodeBlock SUPPLEMENTAL_ARROWS_B=new UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B=new UnicodeBlock SUPPLEMENTAL_MATHEMATICAL_OPERATORS=new UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_ARROWS=new UnicodeBlock KATAKANA_PHONETIC_EXTENSIONS=new UnicodeBlock YIJING_HEXAGRAM_SYMBOLS=new UnicodeBlock VARIATION_SELECTORS=new UnicodeBlock LINEAR_B_SYLLABARY=new UnicodeBlock LINEAR_B_IDEOGRAMS=new UnicodeBlock AEGEAN_NUMBERS=new UnicodeBlock OLD_ITALIC=new UnicodeBlock GOTHIC=new UnicodeBlock UGARITIC=new UnicodeBlock DESERET=new UnicodeBlock SHAVIAN=new UnicodeBlock OSMANYA=new UnicodeBlock CYPRIOT_SYLLABARY=new UnicodeBlock BYZANTINE_MUSICAL_SYMBOLS=new UnicodeBlock MUSICAL_SYMBOLS=new UnicodeBlock TAI_XUAN_JING_SYMBOLS=new UnicodeBlock MATHEMATICAL_ALPHANUMERIC_SYMBOLS=new UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B=new UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT=new UnicodeBlock TAGS=new UnicodeBlock VARIATION_SELECTORS_SUPPLEMENT=new UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_A=new UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_B=new UnicodeBlock HIGH_SURROGATES=new UnicodeBlock HIGH_PRIVATE_USE_SURROGATES=new UnicodeBlock LOW_SURROGATES=new UnicodeBlock ARABIC_SUPPLEMENT=new UnicodeBlock NKO=new UnicodeBlock SAMARITAN=new UnicodeBlock MANDAIC=new UnicodeBlock ETHIOPIC_SUPPLEMENT=new UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED=new UnicodeBlock NEW_TAI_LUE=new UnicodeBlock BUGINESE=new UnicodeBlock TAI_THAM=new UnicodeBlock BALINESE=new UnicodeBlock SUNDANESE=new UnicodeBlock BATAK=new UnicodeBlock LEPCHA=new UnicodeBlock OL_CHIKI=new UnicodeBlock VEDIC_EXTENSIONS=new UnicodeBlock PHONETIC_EXTENSIONS_SUPPLEMENT=new UnicodeBlock COMBINING_DIACRITICAL_MARKS_SUPPLEMENT=new UnicodeBlock GLAGOLITIC=new UnicodeBlock LATIN_EXTENDED_C=new UnicodeBlock COPTIC=new UnicodeBlock GEORGIAN_SUPPLEMENT=new UnicodeBlock TIFINAGH=new UnicodeBlock ETHIOPIC_EXTENDED=new UnicodeBlock CYRILLIC_EXTENDED_A=new UnicodeBlock SUPPLEMENTAL_PUNCTUATION=new UnicodeBlock CJK_STROKES=new UnicodeBlock LISU=new UnicodeBlock VAI=new UnicodeBlock CYRILLIC_EXTENDED_B=new UnicodeBlock BAMUM=new UnicodeBlock MODIFIER_TONE_LETTERS=new UnicodeBlock LATIN_EXTENDED_D=new UnicodeBlock SYLOTI_NAGRI=new UnicodeBlock COMMON_INDIC_NUMBER_FORMS=new UnicodeBlock PHAGS_PA=new UnicodeBlock SAURASHTRA=new UnicodeBlock DEVANAGARI_EXTENDED=new UnicodeBlock KAYAH_LI=new UnicodeBlock REJANG=new UnicodeBlock HANGUL_JAMO_EXTENDED_A=new UnicodeBlock JAVANESE=new UnicodeBlock CHAM=new UnicodeBlock MYANMAR_EXTENDED_A=new UnicodeBlock TAI_VIET=new UnicodeBlock ETHIOPIC_EXTENDED_A=new UnicodeBlock MEETEI_MAYEK=new UnicodeBlock HANGUL_JAMO_EXTENDED_B=new UnicodeBlock VERTICAL_FORMS=new UnicodeBlock ANCIENT_GREEK_NUMBERS=new UnicodeBlock ANCIENT_SYMBOLS=new UnicodeBlock PHAISTOS_DISC=new UnicodeBlock LYCIAN=new UnicodeBlock CARIAN=new UnicodeBlock OLD_PERSIAN=new UnicodeBlock IMPERIAL_ARAMAIC=new UnicodeBlock PHOENICIAN=new UnicodeBlock LYDIAN=new UnicodeBlock KHAROSHTHI=new UnicodeBlock OLD_SOUTH_ARABIAN=new UnicodeBlock AVESTAN=new UnicodeBlock INSCRIPTIONAL_PARTHIAN=new UnicodeBlock INSCRIPTIONAL_PAHLAVI=new UnicodeBlock OLD_TURKIC=new UnicodeBlock RUMI_NUMERAL_SYMBOLS=new UnicodeBlock BRAHMI=new UnicodeBlock KAITHI=new UnicodeBlock CUNEIFORM=new UnicodeBlock CUNEIFORM_NUMBERS_AND_PUNCTUATION=new UnicodeBlock EGYPTIAN_HIEROGLYPHS=new UnicodeBlock BAMUM_SUPPLEMENT=new UnicodeBlock KANA_SUPPLEMENT=new UnicodeBlock ANCIENT_GREEK_MUSICAL_NOTATION=new UnicodeBlock COUNTING_ROD_NUMERALS=new UnicodeBlock MAHJONG_TILES=new UnicodeBlock DOMINO_TILES=new UnicodeBlock PLAYING_CARDS=new UnicodeBlock ENCLOSED_ALPHANUMERIC_SUPPLEMENT=new UnicodeBlock ENCLOSED_IDEOGRAPHIC_SUPPLEMENT=new UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS=new UnicodeBlock EMOTICONS=new UnicodeBlock TRANSPORT_AND_MAP_SYMBOLS=new UnicodeBlock ALCHEMICAL_SYMBOLS=new UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C=new UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D=new UnicodeBlock ARABIC_EXTENDED_A=new UnicodeBlock SUNDANESE_SUPPLEMENT=new UnicodeBlock MEETEI_MAYEK_EXTENSIONS=new UnicodeBlock MEROITIC_HIEROGLYPHS=new UnicodeBlock MEROITIC_CURSIVE=new UnicodeBlock SORA_SOMPENG=new UnicodeBlock CHAKMA=new UnicodeBlock SHARADA=new UnicodeBlock TAKRI=new UnicodeBlock MIAO=new UnicodeBlock ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS=new UnicodeBlock blockStarts=[] blocks= + map=new HashMap(256) BASIC_LATIN=new UnicodeBlock("BASIC_LATIN","BASIC LATIN","BASICLATIN") LATIN_1_SUPPLEMENT=new UnicodeBlock("LATIN_1_SUPPLEMENT","LATIN-1 SUPPLEMENT","LATIN-1SUPPLEMENT") LATIN_EXTENDED_A=new UnicodeBlock("LATIN_EXTENDED_A","LATIN EXTENDED-A","LATINEXTENDED-A") LATIN_EXTENDED_B=new UnicodeBlock("LATIN_EXTENDED_B","LATIN EXTENDED-B","LATINEXTENDED-B") IPA_EXTENSIONS=new UnicodeBlock("IPA_EXTENSIONS","IPA EXTENSIONS","IPAEXTENSIONS") SPACING_MODIFIER_LETTERS=new UnicodeBlock("SPACING_MODIFIER_LETTERS","SPACING MODIFIER LETTERS","SPACINGMODIFIERLETTERS") COMBINING_DIACRITICAL_MARKS=new UnicodeBlock("COMBINING_DIACRITICAL_MARKS","COMBINING DIACRITICAL MARKS","COMBININGDIACRITICALMARKS") GREEK=new UnicodeBlock("GREEK","GREEK AND COPTIC","GREEKANDCOPTIC") CYRILLIC=new UnicodeBlock("CYRILLIC") ARMENIAN=new UnicodeBlock("ARMENIAN") HEBREW=new UnicodeBlock("HEBREW") ARABIC=new UnicodeBlock("ARABIC") DEVANAGARI=new UnicodeBlock("DEVANAGARI") BENGALI=new UnicodeBlock("BENGALI") GURMUKHI=new UnicodeBlock("GURMUKHI") GUJARATI=new UnicodeBlock("GUJARATI") ORIYA=new UnicodeBlock("ORIYA") TAMIL=new UnicodeBlock("TAMIL") TELUGU=new UnicodeBlock("TELUGU") KANNADA=new UnicodeBlock("KANNADA") MALAYALAM=new UnicodeBlock("MALAYALAM") THAI=new UnicodeBlock("THAI") LAO=new UnicodeBlock("LAO") TIBETAN=new UnicodeBlock("TIBETAN") GEORGIAN=new UnicodeBlock("GEORGIAN") HANGUL_JAMO=new UnicodeBlock("HANGUL_JAMO","HANGUL JAMO","HANGULJAMO") LATIN_EXTENDED_ADDITIONAL=new UnicodeBlock("LATIN_EXTENDED_ADDITIONAL","LATIN EXTENDED ADDITIONAL","LATINEXTENDEDADDITIONAL") GREEK_EXTENDED=new UnicodeBlock("GREEK_EXTENDED","GREEK EXTENDED","GREEKEXTENDED") GENERAL_PUNCTUATION=new UnicodeBlock("GENERAL_PUNCTUATION","GENERAL PUNCTUATION","GENERALPUNCTUATION") SUPERSCRIPTS_AND_SUBSCRIPTS=new UnicodeBlock("SUPERSCRIPTS_AND_SUBSCRIPTS","SUPERSCRIPTS AND SUBSCRIPTS","SUPERSCRIPTSANDSUBSCRIPTS") CURRENCY_SYMBOLS=new UnicodeBlock("CURRENCY_SYMBOLS","CURRENCY SYMBOLS","CURRENCYSYMBOLS") COMBINING_MARKS_FOR_SYMBOLS=new UnicodeBlock("COMBINING_MARKS_FOR_SYMBOLS","COMBINING DIACRITICAL MARKS FOR SYMBOLS","COMBININGDIACRITICALMARKSFORSYMBOLS","COMBINING MARKS FOR SYMBOLS","COMBININGMARKSFORSYMBOLS") LETTERLIKE_SYMBOLS=new UnicodeBlock("LETTERLIKE_SYMBOLS","LETTERLIKE SYMBOLS","LETTERLIKESYMBOLS") NUMBER_FORMS=new UnicodeBlock("NUMBER_FORMS","NUMBER FORMS","NUMBERFORMS") ARROWS=new UnicodeBlock("ARROWS") MATHEMATICAL_OPERATORS=new UnicodeBlock("MATHEMATICAL_OPERATORS","MATHEMATICAL OPERATORS","MATHEMATICALOPERATORS") MISCELLANEOUS_TECHNICAL=new UnicodeBlock("MISCELLANEOUS_TECHNICAL","MISCELLANEOUS TECHNICAL","MISCELLANEOUSTECHNICAL") CONTROL_PICTURES=new UnicodeBlock("CONTROL_PICTURES","CONTROL PICTURES","CONTROLPICTURES") OPTICAL_CHARACTER_RECOGNITION=new UnicodeBlock("OPTICAL_CHARACTER_RECOGNITION","OPTICAL CHARACTER RECOGNITION","OPTICALCHARACTERRECOGNITION") ENCLOSED_ALPHANUMERICS=new UnicodeBlock("ENCLOSED_ALPHANUMERICS","ENCLOSED ALPHANUMERICS","ENCLOSEDALPHANUMERICS") BOX_DRAWING=new UnicodeBlock("BOX_DRAWING","BOX DRAWING","BOXDRAWING") BLOCK_ELEMENTS=new UnicodeBlock("BLOCK_ELEMENTS","BLOCK ELEMENTS","BLOCKELEMENTS") GEOMETRIC_SHAPES=new UnicodeBlock("GEOMETRIC_SHAPES","GEOMETRIC SHAPES","GEOMETRICSHAPES") MISCELLANEOUS_SYMBOLS=new UnicodeBlock("MISCELLANEOUS_SYMBOLS","MISCELLANEOUS SYMBOLS","MISCELLANEOUSSYMBOLS") DINGBATS=new UnicodeBlock("DINGBATS") CJK_SYMBOLS_AND_PUNCTUATION=new UnicodeBlock("CJK_SYMBOLS_AND_PUNCTUATION","CJK SYMBOLS AND PUNCTUATION","CJKSYMBOLSANDPUNCTUATION") HIRAGANA=new UnicodeBlock("HIRAGANA") KATAKANA=new UnicodeBlock("KATAKANA") BOPOMOFO=new UnicodeBlock("BOPOMOFO") HANGUL_COMPATIBILITY_JAMO=new UnicodeBlock("HANGUL_COMPATIBILITY_JAMO","HANGUL COMPATIBILITY JAMO","HANGULCOMPATIBILITYJAMO") KANBUN=new UnicodeBlock("KANBUN") ENCLOSED_CJK_LETTERS_AND_MONTHS=new UnicodeBlock("ENCLOSED_CJK_LETTERS_AND_MONTHS","ENCLOSED CJK LETTERS AND MONTHS","ENCLOSEDCJKLETTERSANDMONTHS") CJK_COMPATIBILITY=new UnicodeBlock("CJK_COMPATIBILITY","CJK COMPATIBILITY","CJKCOMPATIBILITY") CJK_UNIFIED_IDEOGRAPHS=new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS","CJK UNIFIED IDEOGRAPHS","CJKUNIFIEDIDEOGRAPHS") HANGUL_SYLLABLES=new UnicodeBlock("HANGUL_SYLLABLES","HANGUL SYLLABLES","HANGULSYLLABLES") PRIVATE_USE_AREA=new UnicodeBlock("PRIVATE_USE_AREA","PRIVATE USE AREA","PRIVATEUSEAREA") CJK_COMPATIBILITY_IDEOGRAPHS=new UnicodeBlock("CJK_COMPATIBILITY_IDEOGRAPHS","CJK COMPATIBILITY IDEOGRAPHS","CJKCOMPATIBILITYIDEOGRAPHS") ALPHABETIC_PRESENTATION_FORMS=new UnicodeBlock("ALPHABETIC_PRESENTATION_FORMS","ALPHABETIC PRESENTATION FORMS","ALPHABETICPRESENTATIONFORMS") ARABIC_PRESENTATION_FORMS_A=new UnicodeBlock("ARABIC_PRESENTATION_FORMS_A","ARABIC PRESENTATION FORMS-A","ARABICPRESENTATIONFORMS-A") COMBINING_HALF_MARKS=new UnicodeBlock("COMBINING_HALF_MARKS","COMBINING HALF MARKS","COMBININGHALFMARKS") CJK_COMPATIBILITY_FORMS=new UnicodeBlock("CJK_COMPATIBILITY_FORMS","CJK COMPATIBILITY FORMS","CJKCOMPATIBILITYFORMS") SMALL_FORM_VARIANTS=new UnicodeBlock("SMALL_FORM_VARIANTS","SMALL FORM VARIANTS","SMALLFORMVARIANTS") ARABIC_PRESENTATION_FORMS_B=new UnicodeBlock("ARABIC_PRESENTATION_FORMS_B","ARABIC PRESENTATION FORMS-B","ARABICPRESENTATIONFORMS-B") HALFWIDTH_AND_FULLWIDTH_FORMS=new UnicodeBlock("HALFWIDTH_AND_FULLWIDTH_FORMS","HALFWIDTH AND FULLWIDTH FORMS","HALFWIDTHANDFULLWIDTHFORMS") SPECIALS=new UnicodeBlock("SPECIALS") SURROGATES_AREA=new UnicodeBlock("SURROGATES_AREA",false) SYRIAC=new UnicodeBlock("SYRIAC") THAANA=new UnicodeBlock("THAANA") SINHALA=new UnicodeBlock("SINHALA") MYANMAR=new UnicodeBlock("MYANMAR") ETHIOPIC=new UnicodeBlock("ETHIOPIC") CHEROKEE=new UnicodeBlock("CHEROKEE") UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS=new UnicodeBlock("UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS","UNIFIED CANADIAN ABORIGINAL SYLLABICS","UNIFIEDCANADIANABORIGINALSYLLABICS") OGHAM=new UnicodeBlock("OGHAM") RUNIC=new UnicodeBlock("RUNIC") KHMER=new UnicodeBlock("KHMER") MONGOLIAN=new UnicodeBlock("MONGOLIAN") BRAILLE_PATTERNS=new UnicodeBlock("BRAILLE_PATTERNS","BRAILLE PATTERNS","BRAILLEPATTERNS") CJK_RADICALS_SUPPLEMENT=new UnicodeBlock("CJK_RADICALS_SUPPLEMENT","CJK RADICALS SUPPLEMENT","CJKRADICALSSUPPLEMENT") KANGXI_RADICALS=new UnicodeBlock("KANGXI_RADICALS","KANGXI RADICALS","KANGXIRADICALS") IDEOGRAPHIC_DESCRIPTION_CHARACTERS=new UnicodeBlock("IDEOGRAPHIC_DESCRIPTION_CHARACTERS","IDEOGRAPHIC DESCRIPTION CHARACTERS","IDEOGRAPHICDESCRIPTIONCHARACTERS") BOPOMOFO_EXTENDED=new UnicodeBlock("BOPOMOFO_EXTENDED","BOPOMOFO EXTENDED","BOPOMOFOEXTENDED") CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A=new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A","CJK UNIFIED IDEOGRAPHS EXTENSION A","CJKUNIFIEDIDEOGRAPHSEXTENSIONA") YI_SYLLABLES=new UnicodeBlock("YI_SYLLABLES","YI SYLLABLES","YISYLLABLES") YI_RADICALS=new UnicodeBlock("YI_RADICALS","YI RADICALS","YIRADICALS") CYRILLIC_SUPPLEMENTARY=new UnicodeBlock("CYRILLIC_SUPPLEMENTARY","CYRILLIC SUPPLEMENTARY","CYRILLICSUPPLEMENTARY","CYRILLIC SUPPLEMENT","CYRILLICSUPPLEMENT") TAGALOG=new UnicodeBlock("TAGALOG") HANUNOO=new UnicodeBlock("HANUNOO") BUHID=new UnicodeBlock("BUHID") TAGBANWA=new UnicodeBlock("TAGBANWA") LIMBU=new UnicodeBlock("LIMBU") TAI_LE=new UnicodeBlock("TAI_LE","TAI LE","TAILE") KHMER_SYMBOLS=new UnicodeBlock("KHMER_SYMBOLS","KHMER SYMBOLS","KHMERSYMBOLS") PHONETIC_EXTENSIONS=new UnicodeBlock("PHONETIC_EXTENSIONS","PHONETIC EXTENSIONS","PHONETICEXTENSIONS") MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A=new UnicodeBlock("MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A","MISCELLANEOUS MATHEMATICAL SYMBOLS-A","MISCELLANEOUSMATHEMATICALSYMBOLS-A") SUPPLEMENTAL_ARROWS_A=new UnicodeBlock("SUPPLEMENTAL_ARROWS_A","SUPPLEMENTAL ARROWS-A","SUPPLEMENTALARROWS-A") SUPPLEMENTAL_ARROWS_B=new UnicodeBlock("SUPPLEMENTAL_ARROWS_B","SUPPLEMENTAL ARROWS-B","SUPPLEMENTALARROWS-B") MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B=new UnicodeBlock("MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B","MISCELLANEOUS MATHEMATICAL SYMBOLS-B","MISCELLANEOUSMATHEMATICALSYMBOLS-B") SUPPLEMENTAL_MATHEMATICAL_OPERATORS=new UnicodeBlock("SUPPLEMENTAL_MATHEMATICAL_OPERATORS","SUPPLEMENTAL MATHEMATICAL OPERATORS","SUPPLEMENTALMATHEMATICALOPERATORS") MISCELLANEOUS_SYMBOLS_AND_ARROWS=new UnicodeBlock("MISCELLANEOUS_SYMBOLS_AND_ARROWS","MISCELLANEOUS SYMBOLS AND ARROWS","MISCELLANEOUSSYMBOLSANDARROWS") KATAKANA_PHONETIC_EXTENSIONS=new UnicodeBlock("KATAKANA_PHONETIC_EXTENSIONS","KATAKANA PHONETIC EXTENSIONS","KATAKANAPHONETICEXTENSIONS") YIJING_HEXAGRAM_SYMBOLS=new UnicodeBlock("YIJING_HEXAGRAM_SYMBOLS","YIJING HEXAGRAM SYMBOLS","YIJINGHEXAGRAMSYMBOLS") VARIATION_SELECTORS=new UnicodeBlock("VARIATION_SELECTORS","VARIATION SELECTORS","VARIATIONSELECTORS") LINEAR_B_SYLLABARY=new UnicodeBlock("LINEAR_B_SYLLABARY","LINEAR B SYLLABARY","LINEARBSYLLABARY") LINEAR_B_IDEOGRAMS=new UnicodeBlock("LINEAR_B_IDEOGRAMS","LINEAR B IDEOGRAMS","LINEARBIDEOGRAMS") AEGEAN_NUMBERS=new UnicodeBlock("AEGEAN_NUMBERS","AEGEAN NUMBERS","AEGEANNUMBERS") OLD_ITALIC=new UnicodeBlock("OLD_ITALIC","OLD ITALIC","OLDITALIC") GOTHIC=new UnicodeBlock("GOTHIC") UGARITIC=new UnicodeBlock("UGARITIC") DESERET=new UnicodeBlock("DESERET") SHAVIAN=new UnicodeBlock("SHAVIAN") OSMANYA=new UnicodeBlock("OSMANYA") CYPRIOT_SYLLABARY=new UnicodeBlock("CYPRIOT_SYLLABARY","CYPRIOT SYLLABARY","CYPRIOTSYLLABARY") BYZANTINE_MUSICAL_SYMBOLS=new UnicodeBlock("BYZANTINE_MUSICAL_SYMBOLS","BYZANTINE MUSICAL SYMBOLS","BYZANTINEMUSICALSYMBOLS") MUSICAL_SYMBOLS=new UnicodeBlock("MUSICAL_SYMBOLS","MUSICAL SYMBOLS","MUSICALSYMBOLS") TAI_XUAN_JING_SYMBOLS=new UnicodeBlock("TAI_XUAN_JING_SYMBOLS","TAI XUAN JING SYMBOLS","TAIXUANJINGSYMBOLS") MATHEMATICAL_ALPHANUMERIC_SYMBOLS=new UnicodeBlock("MATHEMATICAL_ALPHANUMERIC_SYMBOLS","MATHEMATICAL ALPHANUMERIC SYMBOLS","MATHEMATICALALPHANUMERICSYMBOLS") CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B=new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B","CJK UNIFIED IDEOGRAPHS EXTENSION B","CJKUNIFIEDIDEOGRAPHSEXTENSIONB") CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT=new UnicodeBlock("CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT","CJK COMPATIBILITY IDEOGRAPHS SUPPLEMENT","CJKCOMPATIBILITYIDEOGRAPHSSUPPLEMENT") TAGS=new UnicodeBlock("TAGS") VARIATION_SELECTORS_SUPPLEMENT=new UnicodeBlock("VARIATION_SELECTORS_SUPPLEMENT","VARIATION SELECTORS SUPPLEMENT","VARIATIONSELECTORSSUPPLEMENT") SUPPLEMENTARY_PRIVATE_USE_AREA_A=new UnicodeBlock("SUPPLEMENTARY_PRIVATE_USE_AREA_A","SUPPLEMENTARY PRIVATE USE AREA-A","SUPPLEMENTARYPRIVATEUSEAREA-A") SUPPLEMENTARY_PRIVATE_USE_AREA_B=new UnicodeBlock("SUPPLEMENTARY_PRIVATE_USE_AREA_B","SUPPLEMENTARY PRIVATE USE AREA-B","SUPPLEMENTARYPRIVATEUSEAREA-B") HIGH_SURROGATES=new UnicodeBlock("HIGH_SURROGATES","HIGH SURROGATES","HIGHSURROGATES") HIGH_PRIVATE_USE_SURROGATES=new UnicodeBlock("HIGH_PRIVATE_USE_SURROGATES","HIGH PRIVATE USE SURROGATES","HIGHPRIVATEUSESURROGATES") LOW_SURROGATES=new UnicodeBlock("LOW_SURROGATES","LOW SURROGATES","LOWSURROGATES") ARABIC_SUPPLEMENT=new UnicodeBlock("ARABIC_SUPPLEMENT","ARABIC SUPPLEMENT","ARABICSUPPLEMENT") NKO=new UnicodeBlock("NKO") SAMARITAN=new UnicodeBlock("SAMARITAN") MANDAIC=new UnicodeBlock("MANDAIC") ETHIOPIC_SUPPLEMENT=new UnicodeBlock("ETHIOPIC_SUPPLEMENT","ETHIOPIC SUPPLEMENT","ETHIOPICSUPPLEMENT") UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED=new UnicodeBlock("UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED","UNIFIED CANADIAN ABORIGINAL SYLLABICS EXTENDED","UNIFIEDCANADIANABORIGINALSYLLABICSEXTENDED") NEW_TAI_LUE=new UnicodeBlock("NEW_TAI_LUE","NEW TAI LUE","NEWTAILUE") BUGINESE=new UnicodeBlock("BUGINESE") TAI_THAM=new UnicodeBlock("TAI_THAM","TAI THAM","TAITHAM") BALINESE=new UnicodeBlock("BALINESE") SUNDANESE=new UnicodeBlock("SUNDANESE") BATAK=new UnicodeBlock("BATAK") LEPCHA=new UnicodeBlock("LEPCHA") OL_CHIKI=new UnicodeBlock("OL_CHIKI","OL CHIKI","OLCHIKI") VEDIC_EXTENSIONS=new UnicodeBlock("VEDIC_EXTENSIONS","VEDIC EXTENSIONS","VEDICEXTENSIONS") PHONETIC_EXTENSIONS_SUPPLEMENT=new UnicodeBlock("PHONETIC_EXTENSIONS_SUPPLEMENT","PHONETIC EXTENSIONS SUPPLEMENT","PHONETICEXTENSIONSSUPPLEMENT") COMBINING_DIACRITICAL_MARKS_SUPPLEMENT=new UnicodeBlock("COMBINING_DIACRITICAL_MARKS_SUPPLEMENT","COMBINING DIACRITICAL MARKS SUPPLEMENT","COMBININGDIACRITICALMARKSSUPPLEMENT") GLAGOLITIC=new UnicodeBlock("GLAGOLITIC") LATIN_EXTENDED_C=new UnicodeBlock("LATIN_EXTENDED_C","LATIN EXTENDED-C","LATINEXTENDED-C") COPTIC=new UnicodeBlock("COPTIC") GEORGIAN_SUPPLEMENT=new UnicodeBlock("GEORGIAN_SUPPLEMENT","GEORGIAN SUPPLEMENT","GEORGIANSUPPLEMENT") TIFINAGH=new UnicodeBlock("TIFINAGH") ETHIOPIC_EXTENDED=new UnicodeBlock("ETHIOPIC_EXTENDED","ETHIOPIC EXTENDED","ETHIOPICEXTENDED") CYRILLIC_EXTENDED_A=new UnicodeBlock("CYRILLIC_EXTENDED_A","CYRILLIC EXTENDED-A","CYRILLICEXTENDED-A") SUPPLEMENTAL_PUNCTUATION=new UnicodeBlock("SUPPLEMENTAL_PUNCTUATION","SUPPLEMENTAL PUNCTUATION","SUPPLEMENTALPUNCTUATION") CJK_STROKES=new UnicodeBlock("CJK_STROKES","CJK STROKES","CJKSTROKES") LISU=new UnicodeBlock("LISU") VAI=new UnicodeBlock("VAI") CYRILLIC_EXTENDED_B=new UnicodeBlock("CYRILLIC_EXTENDED_B","CYRILLIC EXTENDED-B","CYRILLICEXTENDED-B") BAMUM=new UnicodeBlock("BAMUM") MODIFIER_TONE_LETTERS=new UnicodeBlock("MODIFIER_TONE_LETTERS","MODIFIER TONE LETTERS","MODIFIERTONELETTERS") LATIN_EXTENDED_D=new UnicodeBlock("LATIN_EXTENDED_D","LATIN EXTENDED-D","LATINEXTENDED-D") SYLOTI_NAGRI=new UnicodeBlock("SYLOTI_NAGRI","SYLOTI NAGRI","SYLOTINAGRI") COMMON_INDIC_NUMBER_FORMS=new UnicodeBlock("COMMON_INDIC_NUMBER_FORMS","COMMON INDIC NUMBER FORMS","COMMONINDICNUMBERFORMS") PHAGS_PA=new UnicodeBlock("PHAGS_PA","PHAGS-PA") SAURASHTRA=new UnicodeBlock("SAURASHTRA") DEVANAGARI_EXTENDED=new UnicodeBlock("DEVANAGARI_EXTENDED","DEVANAGARI EXTENDED","DEVANAGARIEXTENDED") KAYAH_LI=new UnicodeBlock("KAYAH_LI","KAYAH LI","KAYAHLI") REJANG=new UnicodeBlock("REJANG") HANGUL_JAMO_EXTENDED_A=new UnicodeBlock("HANGUL_JAMO_EXTENDED_A","HANGUL JAMO EXTENDED-A","HANGULJAMOEXTENDED-A") JAVANESE=new UnicodeBlock("JAVANESE") CHAM=new UnicodeBlock("CHAM") MYANMAR_EXTENDED_A=new UnicodeBlock("MYANMAR_EXTENDED_A","MYANMAR EXTENDED-A","MYANMAREXTENDED-A") TAI_VIET=new UnicodeBlock("TAI_VIET","TAI VIET","TAIVIET") ETHIOPIC_EXTENDED_A=new UnicodeBlock("ETHIOPIC_EXTENDED_A","ETHIOPIC EXTENDED-A","ETHIOPICEXTENDED-A") MEETEI_MAYEK=new UnicodeBlock("MEETEI_MAYEK","MEETEI MAYEK","MEETEIMAYEK") HANGUL_JAMO_EXTENDED_B=new UnicodeBlock("HANGUL_JAMO_EXTENDED_B","HANGUL JAMO EXTENDED-B","HANGULJAMOEXTENDED-B") VERTICAL_FORMS=new UnicodeBlock("VERTICAL_FORMS","VERTICAL FORMS","VERTICALFORMS") ANCIENT_GREEK_NUMBERS=new UnicodeBlock("ANCIENT_GREEK_NUMBERS","ANCIENT GREEK NUMBERS","ANCIENTGREEKNUMBERS") ANCIENT_SYMBOLS=new UnicodeBlock("ANCIENT_SYMBOLS","ANCIENT SYMBOLS","ANCIENTSYMBOLS") PHAISTOS_DISC=new UnicodeBlock("PHAISTOS_DISC","PHAISTOS DISC","PHAISTOSDISC") LYCIAN=new UnicodeBlock("LYCIAN") CARIAN=new UnicodeBlock("CARIAN") OLD_PERSIAN=new UnicodeBlock("OLD_PERSIAN","OLD PERSIAN","OLDPERSIAN") IMPERIAL_ARAMAIC=new UnicodeBlock("IMPERIAL_ARAMAIC","IMPERIAL ARAMAIC","IMPERIALARAMAIC") PHOENICIAN=new UnicodeBlock("PHOENICIAN") LYDIAN=new UnicodeBlock("LYDIAN") KHAROSHTHI=new UnicodeBlock("KHAROSHTHI") OLD_SOUTH_ARABIAN=new UnicodeBlock("OLD_SOUTH_ARABIAN","OLD SOUTH ARABIAN","OLDSOUTHARABIAN") AVESTAN=new UnicodeBlock("AVESTAN") INSCRIPTIONAL_PARTHIAN=new UnicodeBlock("INSCRIPTIONAL_PARTHIAN","INSCRIPTIONAL PARTHIAN","INSCRIPTIONALPARTHIAN") INSCRIPTIONAL_PAHLAVI=new UnicodeBlock("INSCRIPTIONAL_PAHLAVI","INSCRIPTIONAL PAHLAVI","INSCRIPTIONALPAHLAVI") OLD_TURKIC=new UnicodeBlock("OLD_TURKIC","OLD TURKIC","OLDTURKIC") RUMI_NUMERAL_SYMBOLS=new UnicodeBlock("RUMI_NUMERAL_SYMBOLS","RUMI NUMERAL SYMBOLS","RUMINUMERALSYMBOLS") BRAHMI=new UnicodeBlock("BRAHMI") KAITHI=new UnicodeBlock("KAITHI") CUNEIFORM=new UnicodeBlock("CUNEIFORM") CUNEIFORM_NUMBERS_AND_PUNCTUATION=new UnicodeBlock("CUNEIFORM_NUMBERS_AND_PUNCTUATION","CUNEIFORM NUMBERS AND PUNCTUATION","CUNEIFORMNUMBERSANDPUNCTUATION") EGYPTIAN_HIEROGLYPHS=new UnicodeBlock("EGYPTIAN_HIEROGLYPHS","EGYPTIAN HIEROGLYPHS","EGYPTIANHIEROGLYPHS") BAMUM_SUPPLEMENT=new UnicodeBlock("BAMUM_SUPPLEMENT","BAMUM SUPPLEMENT","BAMUMSUPPLEMENT") KANA_SUPPLEMENT=new UnicodeBlock("KANA_SUPPLEMENT","KANA SUPPLEMENT","KANASUPPLEMENT") ANCIENT_GREEK_MUSICAL_NOTATION=new UnicodeBlock("ANCIENT_GREEK_MUSICAL_NOTATION","ANCIENT GREEK MUSICAL NOTATION","ANCIENTGREEKMUSICALNOTATION") COUNTING_ROD_NUMERALS=new UnicodeBlock("COUNTING_ROD_NUMERALS","COUNTING ROD NUMERALS","COUNTINGRODNUMERALS") MAHJONG_TILES=new UnicodeBlock("MAHJONG_TILES","MAHJONG TILES","MAHJONGTILES") DOMINO_TILES=new UnicodeBlock("DOMINO_TILES","DOMINO TILES","DOMINOTILES") PLAYING_CARDS=new UnicodeBlock("PLAYING_CARDS","PLAYING CARDS","PLAYINGCARDS") ENCLOSED_ALPHANUMERIC_SUPPLEMENT=new UnicodeBlock("ENCLOSED_ALPHANUMERIC_SUPPLEMENT","ENCLOSED ALPHANUMERIC SUPPLEMENT","ENCLOSEDALPHANUMERICSUPPLEMENT") ENCLOSED_IDEOGRAPHIC_SUPPLEMENT=new UnicodeBlock("ENCLOSED_IDEOGRAPHIC_SUPPLEMENT","ENCLOSED IDEOGRAPHIC SUPPLEMENT","ENCLOSEDIDEOGRAPHICSUPPLEMENT") MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS=new UnicodeBlock("MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS","MISCELLANEOUS SYMBOLS AND PICTOGRAPHS","MISCELLANEOUSSYMBOLSANDPICTOGRAPHS") EMOTICONS=new UnicodeBlock("EMOTICONS") TRANSPORT_AND_MAP_SYMBOLS=new UnicodeBlock("TRANSPORT_AND_MAP_SYMBOLS","TRANSPORT AND MAP SYMBOLS","TRANSPORTANDMAPSYMBOLS") ALCHEMICAL_SYMBOLS=new UnicodeBlock("ALCHEMICAL_SYMBOLS","ALCHEMICAL SYMBOLS","ALCHEMICALSYMBOLS") CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C=new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C","CJK UNIFIED IDEOGRAPHS EXTENSION C","CJKUNIFIEDIDEOGRAPHSEXTENSIONC") CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D=new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D","CJK UNIFIED IDEOGRAPHS EXTENSION D","CJKUNIFIEDIDEOGRAPHSEXTENSIOND") ARABIC_EXTENDED_A=new UnicodeBlock("ARABIC_EXTENDED_A","ARABIC EXTENDED-A","ARABICEXTENDED-A") SUNDANESE_SUPPLEMENT=new UnicodeBlock("SUNDANESE_SUPPLEMENT","SUNDANESE SUPPLEMENT","SUNDANESESUPPLEMENT") MEETEI_MAYEK_EXTENSIONS=new UnicodeBlock("MEETEI_MAYEK_EXTENSIONS","MEETEI MAYEK EXTENSIONS","MEETEIMAYEKEXTENSIONS") MEROITIC_HIEROGLYPHS=new UnicodeBlock("MEROITIC_HIEROGLYPHS","MEROITIC HIEROGLYPHS","MEROITICHIEROGLYPHS") MEROITIC_CURSIVE=new UnicodeBlock("MEROITIC_CURSIVE","MEROITIC CURSIVE","MEROITICCURSIVE") SORA_SOMPENG=new UnicodeBlock("SORA_SOMPENG","SORA SOMPENG","SORASOMPENG") CHAKMA=new UnicodeBlock("CHAKMA") SHARADA=new UnicodeBlock("SHARADA") TAKRI=new UnicodeBlock("TAKRI") MIAO=new UnicodeBlock("MIAO") ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS=new UnicodeBlock("ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS","ARABIC MATHEMATICAL ALPHABETIC SYMBOLS","ARABICMATHEMATICALALPHABETICSYMBOLS") blockStarts=[] blocks= Instance Initializer: Constructors: - constructor UnicodeBlock() throws: - constructor UnicodeBlock() throws: + constructor UnicodeBlock(idName) throws: + constructor UnicodeBlock(idName,isMap) throws: cond-branch cond:isMap true branch : map.put(idName,this) false branch : - constructor UnicodeBlock() throws: + constructor UnicodeBlock(idName,alias) throws: map.put(alias,this) - constructor UnicodeBlock() throws: + constructor UnicodeBlock(idName,aliases) throws: String alias aliases map.put(alias,this) Methods: - func of() throws: + func of(c) throws: return of((int)c) - func of() throws: + func of(codePoint) throws: cond-branch cond:isValidCodePoint(codePoint) true branch : - new IllegalArgumentException + new IllegalArgumentException() false branch : - var:top,bottom,current + Decl: top,bottom,current bottom Assign 0 top Assign blockStarts.length - current Assign + current Assign top Div 2 while top Sub bottom GT 1 cond-branch cond:codePoint GE true branch : bottom Assign current false branch : top Assign current - current Assign (top Add bottom)2 + current Assign (top Add bottom) Div 2 return - func forName() throws: - var:block=map.get(blockName.toUpperCase(Locale.US)) + func forName(blockName) throws: + Decl: block=map.get(blockName.toUpperCase(Locale.US)) cond-branch cond:block EQ null true branch : - new IllegalArgumentException + new IllegalArgumentException() false branch : return block @@ -649,38 +710,33 @@ class Character LocalInterfaces: class[JavaEnum] UnicodeScript Fields: - COMMON scriptStarts= scripts= aliases + scriptStarts= scripts= aliases Instance Initializer: InstInit- 0 Constructors: Methods: - func of() throws: + func of(codePoint) throws: cond-branch cond:isValidCodePoint(codePoint) true branch : - new IllegalArgumentException - false branch : + new IllegalArgumentException() false branch : - var:type=getType(codePoint) + Decl: type=getType(codePoint) cond-branch cond:type EQ UNASSIGNED true branch : - return UNKNOWN - false branch : + return UNKNOWN false branch : - var:index=Arrays.binarySearch(scriptStarts,codePoint) + Decl: index=Arrays.binarySearch(scriptStarts,codePoint) cond-branch cond:index LT 0 true branch : - index Assign Sub - index Sub 2 - false branch : + index Assign Minus index Sub 2 false branch : return - func forName() throws: + func forName(scriptName) throws: scriptName Assign scriptName.toUpperCase(Locale.ENGLISH) - var:sc=aliases.get(scriptName) + Decl: sc=aliases.get(scriptName) cond-branch cond:sc NE null true branch : - return sc - false branch : + return sc false branch : return valueOf(scriptName) LocalClasses: diff --git a/src/MapleFE/test/openjdk/Class-2.java b/src/MapleFE/test/java/openjdk/Class-2.java similarity index 100% rename from src/MapleFE/test/openjdk/Class-2.java rename to src/MapleFE/test/java/openjdk/Class-2.java diff --git a/src/MapleFE/test/openjdk/Class-2.java.result b/src/MapleFE/test/java/openjdk/Class-2.java.result similarity index 62% rename from src/MapleFE/test/openjdk/Class-2.java.result rename to src/MapleFE/test/java/openjdk/Class-2.java.result index a18295d54303b1ee1f0f4b9fb0638dcc2b954404..bbe92670f84638da3f5c4970793b40eb95f8b2ea 100644 --- a/src/MapleFE/test/openjdk/Class-2.java.result +++ b/src/MapleFE/test/java/openjdk/Class-2.java.result @@ -16,14 +16,13 @@ class Class return getEnclosingConstructorNative() func getEnclosingConstructorNative() throws: func classNameImpliesTopLevel() throws: - return + return getName().contains("$") func getDeclaringClass() throws: func getEnclosingClass() throws: func getSimpleName() throws: cond-branch cond:isArray() true branch : - return Add "[]" - false branch : + return getComponentType().getSimpleName() Add "[]" false branch : cond-branch cond:isAnonymousClass() true branch : @@ -35,8 +34,8 @@ class Class return getInnerClassName() false branch : - var:simpleName=getName() - var:dot=simpleName.lastIndexOf(".") + Decl: simpleName=getName() + Decl: dot=simpleName.lastIndexOf(".") cond-branch cond:dot GT 0 true branch : return simpleName.substring(simpleName.lastIndexOf(".") Add 1) @@ -46,9 +45,21 @@ class Class func getTypeName() throws: cond-branch cond:isArray() true branch : - var:cl=this + Decl: cl=this + Decl: dimensions=0 + while cl.isArray() dimensions Inc + + cl Assign cl.getComponentType() + + Decl: sb=new StringBuilder() + sb.append(cl.getName()) + for ( ) + sb.append("[]") + return sb.toString() + Throwable + e false branch : @@ -56,27 +67,28 @@ class Class func getCanonicalName() throws: cond-branch cond:isArray() true branch : - var:canonicalName= + Decl: canonicalName=getComponentType().getCanonicalName() cond-branch cond:canonicalName NE null true branch : - return canonicalName Add "[]" - false branch : + return canonicalName Add "[]" false branch : return null - false branch : cond-branch cond:isLocalOrAnonymousClass() true branch : - return null - false branch : + return null false branch : - var:enclosingClass=getEnclosingClass() + Decl: enclosingClass=getEnclosingClass() cond-branch cond:enclosingClass EQ null true branch : return getName() false branch : - var:enclosingName=enclosingClass.getCanonicalName() + Decl: enclosingName=enclosingClass.getCanonicalName() + cond-branch cond:enclosingName EQ null + true branch : + return null false branch : + return enclosingName Add "." Add getSimpleName() func isAnonymousClass() throws: func isLocalClass() throws: @@ -86,7 +98,7 @@ class Class func isLocalOrAnonymousClass() throws: return isLocalClass() Lor isAnonymousClass() func getClasses() throws: - var:result=new ArrayList + Decl: result=new ArrayList() for ( ) Class member @@ -100,27 +112,27 @@ class Class return result.toArray(Class,result.size()) func getFields() throws: SecurityException - var:fields=new ArrayList + Decl: fields=new ArrayList() getPublicFieldsRecursive(fields) return fields.toArray(Field,fields.size()) - func getPublicFieldsRecursive() throws: + func getPublicFieldsRecursive(result) throws: for ( ) Collections.addAll(result,c.getPublicDeclaredFields()) - var:iftable=ifTable + Decl: iftable=ifTable cond-branch cond:iftable NE null true branch : for ( ) - Collections.addAll(result,((Class))getPublicDeclaredFields) + Collections.addAll(result,(Class).getPublicDeclaredFields()) false branch : func getMethods() throws: SecurityException - var:methods=new ArrayList + Decl: methods=new ArrayList() getPublicMethodsInternal(methods) CollectionUtils.removeDuplicates(methods,Method.ORDER_BY_SIGNATURE) return methods.toArray(Method,methods.size()) - func getPublicMethodsInternal() throws: + func getPublicMethodsInternal(result) throws: Collections.addAll(result,getDeclaredMethodsUnchecked(true)) cond-branch cond:isInterface() true branch : @@ -129,40 +141,40 @@ class Class false branch : - var:iftable=ifTable + Decl: iftable=ifTable cond-branch cond:iftable NE null true branch : for ( ) - var:ifc=(Class) + Decl: ifc=(Class) Collections.addAll(result,ifc.getDeclaredMethodsUnchecked(true)) false branch : func getConstructors() throws: SecurityException return getDeclaredConstructorsInternal(true) - func getField() throws: NoSuchFieldException + func getField(name) throws: NoSuchFieldException cond-branch cond:name EQ null true branch : - new NullPointerException + new NullPointerException("name == null") false branch : - var:result=getPublicFieldRecursive(name) + Decl: result=getPublicFieldRecursive(name) cond-branch cond:result EQ null true branch : - new NoSuchFieldException + new NoSuchFieldException(name) false branch : return result - func getPublicFieldRecursive() throws: - func getMethod() throws: NoSuchMethodException SecurityException + func getPublicFieldRecursive(name) throws: + func getMethod(name,parameterTypes) throws: NoSuchMethodException SecurityException return getMethod(name,parameterTypes,true) - func getConstructor() throws: NoSuchMethodException SecurityException + func getConstructor(parameterTypes) throws: NoSuchMethodException SecurityException return getConstructor0(parameterTypes,Member.PUBLIC) func getDeclaredClasses() throws: func getDeclaredFields() throws: - func getDeclaredFieldsUnchecked() throws: + func getDeclaredFieldsUnchecked(publicOnly) throws: func getDeclaredMethods() throws: SecurityException - var:result=getDeclaredMethodsUnchecked(false) + Decl: result=getDeclaredMethodsUnchecked(false) Method m result @@ -170,18 +182,18 @@ class Class m.getParameterTypes() return result - func getDeclaredMethodsUnchecked() throws: + func getDeclaredMethodsUnchecked(publicOnly) throws: func getDeclaredConstructors() throws: SecurityException return getDeclaredConstructorsInternal(false) - func getDeclaredConstructorsInternal() throws: - func getDeclaredField() throws: NoSuchFieldException + func getDeclaredConstructorsInternal(publicOnly) throws: + func getDeclaredField(name) throws: NoSuchFieldException func getPublicDeclaredFields() throws: - func getDeclaredMethod() throws: NoSuchMethodException SecurityException + func getDeclaredMethod(name,parameterTypes) throws: NoSuchMethodException SecurityException return getMethod(name,parameterTypes,false) - func getMethod() throws: NoSuchMethodException + func getMethod(name,parameterTypes,recursivePublicMethods) throws: NoSuchMethodException cond-branch cond:name EQ null true branch : - new NullPointerException + new NullPointerException("name == null") false branch : cond-branch cond:parameterTypes EQ null @@ -189,17 +201,25 @@ class Class parameterTypes Assign EmptyArray.CLASS false branch : + Class + c + parameterTypes + cond-branch cond:c EQ null + true branch : + new NoSuchMethodException("parameter type is null") + false branch : + - var:result= + Decl: result= cond-branch cond:result EQ null Lor (recursivePublicMethods Land Modifier.isPublic(result.getAccessFlags())) true branch : - new NoSuchMethodException + new NoSuchMethodException(name Add " " Add Arrays.toString(parameterTypes)) false branch : return result - func getPublicMethodRecursive() throws: + func getPublicMethodRecursive(name,parameterTypes) throws: for ( ) - var:result=c.getDeclaredMethodInternal(name,parameterTypes) + Decl: result=c.getDeclaredMethodInternal(name,parameterTypes) cond-branch cond:result NE null Land Modifier.isPublic(result.getAccessFlags()) true branch : return result @@ -207,9 +227,9 @@ class Class return findInterfaceMethod(name,parameterTypes) - func getInstanceMethod() throws: NoSuchMethodException IllegalAccessException + func getInstanceMethod(name,parameterTypes) throws: NoSuchMethodException IllegalAccessException for ( ) - var:result=c.getDeclaredMethodInternal(name,parameterTypes) + Decl: result=c.getDeclaredMethodInternal(name,parameterTypes) cond-branch cond:result NE null Land Modifier.isStatic(result.getModifiers()) true branch : return result @@ -217,31 +237,36 @@ class Class return findInterfaceMethod(name,parameterTypes) - func findInterfaceMethod() throws: - var:iftable=ifTable + func findInterfaceMethod(name,parameterTypes) throws: + Decl: iftable=ifTable cond-branch cond:iftable NE null true branch : for ( ) - var:ifc=(Class) + Decl: ifc=(Class) + Decl: result=ifc.getPublicMethodRecursive(name,parameterTypes) + cond-branch cond:result NE null Land Modifier.isPublic(result.getAccessFlags()) + true branch : + return result + false branch : false branch : return null - func getDeclaredConstructor() throws: NoSuchMethodException SecurityException + func getDeclaredConstructor(parameterTypes) throws: NoSuchMethodException SecurityException return getConstructor0(parameterTypes,Member.DECLARED) - func getResourceAsStream() throws: + func getResourceAsStream(name) throws: name Assign resolveName(name) - var:cl=getClassLoader() + Decl: cl=getClassLoader() cond-branch cond:cl EQ null true branch : return ClassLoader.getSystemResourceAsStream(name) false branch : return cl.getResourceAsStream(name) - func getResource() throws: + func getResource(name) throws: name Assign resolveName(name) - var:cl=getClassLoader() + Decl: cl=getClassLoader() cond-branch cond:cl EQ null true branch : return ClassLoader.getSystemResource(name) @@ -250,7 +275,7 @@ class Class return cl.getResource(name) func getProtectionDomain() throws: return null - func resolveName() throws: + func resolveName(name) throws: cond-branch cond:name EQ null true branch : return name @@ -258,13 +283,21 @@ class Class cond-branch cond:name.startsWith("/") true branch : - var:c=this + Decl: c=this + while c.isArray() c Assign c.getComponentType() + + Decl: baseName=c.getName() + Decl: index=baseName.lastIndexOf(.) + cond-branch cond:index NE -1 + true branch : + name Assign baseName.substring(0,index).replace(.,/) Add "/" Add name + false branch : false branch : name Assign name.substring(1) return name - func getConstructor0() throws: NoSuchMethodException + func getConstructor0(parameterTypes,which) throws: NoSuchMethodException cond-branch cond:parameterTypes EQ null true branch : parameterTypes Assign EmptyArray.CLASS @@ -275,53 +308,49 @@ class Class parameterTypes cond-branch cond:c EQ null true branch : - new NoSuchMethodException + new NoSuchMethodException("parameter type is null") false branch : - var:result=getDeclaredConstructorInternal(parameterTypes) + Decl: result=getDeclaredConstructorInternal(parameterTypes) cond-branch cond:result EQ null Lor which EQ Member.PUBLIC Land Modifier.isPublic(result.getAccessFlags()) true branch : - new NoSuchMethodException + new NoSuchMethodException(" " Add Arrays.toString(parameterTypes)) false branch : return result - func getDeclaredConstructorInternal() throws: + func getDeclaredConstructorInternal(args) throws: func desiredAssertionStatus() throws: return false func getInnerClassName() throws: - func getInnerClassFlags() throws: + func getInnerClassFlags(defaultValue) throws: func isEnum() throws: - return ( Band ENUM) NE 0 Land EQ java.lang.Enum + return (this.getModifiers() Band ENUM) NE 0 Land this.getSuperclass() EQ java.lang.Enum func getEnumConstants() throws: - var:values=getEnumConstantsShared() + Decl: values=getEnumConstantsShared() return func getEnumConstantsShared() throws: cond-branch cond:isEnum() true branch : - return null - false branch : + return null false branch : return (T[])Enum.getSharedConstants((Class)this) - func cast() throws: + func cast(obj) throws: cond-branch cond:obj NE null Land isInstance(obj) true branch : - new ClassCastException - false branch : + new ClassCastException(cannotCastMsg(obj)) false branch : return (T)obj - func cannotCastMsg() throws: - return "Cannot cast " Add Add " to " Add getName() - func asSubclass() throws: + func cannotCastMsg(obj) throws: + return "Cannot cast " Add obj.getClass().getName() Add " to " Add getName() + func asSubclass(clazz) throws: cond-branch cond:clazz.isAssignableFrom(this) true branch : - return ()this - false branch : - new ClassCastException - - func getAnnotation() throws: + return ()this false branch : + new ClassCastException(this.toString() Add " cannot be cast to " Add clazz.getName()) + func getAnnotation(annotationClass) throws: Objects.requireNonNull(annotationClass) - var:annotation=getDeclaredAnnotation(annotationClass) + Decl: annotation=getDeclaredAnnotation(annotationClass) cond-branch cond:annotation NE null true branch : return annotation @@ -340,10 +369,10 @@ class Class false branch : return null - func isAnnotationPresent() throws: + func isAnnotationPresent(annotationClass) throws: cond-branch cond:annotationClass EQ null true branch : - new NullPointerException + new NullPointerException("annotationClass == null") false branch : cond-branch cond:isDeclaredAnnotationPresent(annotationClass) @@ -363,8 +392,8 @@ class Class false branch : return false - func getAnnotationsByType() throws: - var:annotations= + func getAnnotationsByType(annotationClass) throws: + Decl: annotations= cond-branch cond:annotations.length NE 0 true branch : return annotations @@ -372,7 +401,7 @@ class Class cond-branch cond:annotationClass.isDeclaredAnnotationPresent(Inherited) true branch : - var:superClass=getSuperclass() + Decl: superClass=getSuperclass() cond-branch cond:superClass NE null true branch : return superClass.getAnnotationsByType(annotationClass) @@ -382,7 +411,7 @@ class Class return (A[])Array.newInstance(annotationClass,0) func getAnnotations() throws: - var:map=new HashMap + Decl: map=new HashMap() Annotation declaredAnnotation getDeclaredAnnotations() @@ -392,7 +421,7 @@ class Class Annotation declaredAnnotation sup.getDeclaredAnnotations() - var:clazz=declaredAnnotation.annotationType() + Decl: clazz=declaredAnnotation.annotationType() cond-branch cond:map.containsKey(clazz) Land clazz.isDeclaredAnnotationPresent(Inherited) true branch : map.put(clazz,declaredAnnotation) @@ -400,19 +429,23 @@ class Class - var:coll=map.values() + Decl: coll=map.values() return coll.toArray(Annotation,coll.size()) - func getDeclaredAnnotation() throws: + func getDeclaredAnnotation(annotationClass) throws: func getDeclaredAnnotations() throws: - func isDeclaredAnnotationPresent() throws: + func isDeclaredAnnotationPresent(annotationClass) throws: func getSignatureAttribute() throws: - var:annotation=getSignatureAnnotation() + Decl: annotation=getSignatureAnnotation() cond-branch cond:annotation EQ null true branch : return null false branch : - var:result=new StringBuilder + Decl: result=new StringBuilder() + String + s + annotation + result.append(s) return result.toString() func getSignatureAnnotation() throws: @@ -420,11 +453,11 @@ class Class return (accessFlags Band 262144) NE 0 func getAccessFlags() throws: return accessFlags - func getDeclaredMethodInternal() throws: + func getDeclaredMethodInternal(name,args) throws: LocalClasses: class Caches Fields: - genericInterfaces=new BasicLruCache + genericInterfaces=new BasicLruCache(8) Instance Initializer: Constructors: Methods: @@ -434,7 +467,13 @@ class Class Identifier:Method has no decl. Identifier:m has no decl. +Identifier:result has no decl. +Identifier:Class has no decl. +Identifier:c has no decl. Identifier:Class has no decl. Identifier:c has no decl. Identifier:Annotation has no decl. Identifier:declaredAnnotation has no decl. +Identifier:String has no decl. +Identifier:s has no decl. +Identifier:annotation has no decl. diff --git a/src/MapleFE/test/openjdk/Class-3.java b/src/MapleFE/test/java/openjdk/Class-3.java similarity index 100% rename from src/MapleFE/test/openjdk/Class-3.java rename to src/MapleFE/test/java/openjdk/Class-3.java diff --git a/src/MapleFE/test/openjdk/Class-3.java.result b/src/MapleFE/test/java/openjdk/Class-3.java.result similarity index 81% rename from src/MapleFE/test/openjdk/Class-3.java.result rename to src/MapleFE/test/java/openjdk/Class-3.java.result index f9098f16aa989f15fb7789e7587fb0d2d603431b..2d303b495bbeb5dff8564b3783c1e40a45e94e90 100644 --- a/src/MapleFE/test/openjdk/Class-3.java.result +++ b/src/MapleFE/test/java/openjdk/Class-3.java.result @@ -8,7 +8,7 @@ class Class Constructors: Methods: func getDeclaredMethods() throws: - var:result=getDeclaredMethodsUnchecked(false) + Decl: result=getDeclaredMethodsUnchecked(false) Method m result @@ -20,3 +20,4 @@ class Class Identifier:Method has no decl. Identifier:m has no decl. +Identifier:result has no decl. diff --git a/src/MapleFE/test/openjdk/Class.java b/src/MapleFE/test/java/openjdk/Class.java similarity index 100% rename from src/MapleFE/test/openjdk/Class.java rename to src/MapleFE/test/java/openjdk/Class.java diff --git a/src/MapleFE/test/openjdk/Class.java.result b/src/MapleFE/test/java/openjdk/Class.java.result similarity index 62% rename from src/MapleFE/test/openjdk/Class.java.result rename to src/MapleFE/test/java/openjdk/Class.java.result index d955278969e86f51936a20429807dc3ecf5a320d..15d929fa9918f9b0f835856e0fdb4ab78a8040f6 100644 --- a/src/MapleFE/test/openjdk/Class.java.result +++ b/src/MapleFE/test/java/openjdk/Class.java.result @@ -111,30 +111,82 @@ class Class true branch : return toString() false branch : - var:sb=new StringBuilder + Decl: sb=new StringBuilder() + Decl: modifiers=getModifiers() Band Modifier.classModifiers() + cond-branch cond:modifiers NE 0 + true branch : + sb.append(Modifier.toString(modifiers)) + sb.append( ) + false branch : + cond-branch cond:isAnnotation() + true branch : + sb.append(@) + false branch : - func forName() throws: ClassNotFoundException + cond-branch cond:isInterface() + true branch : + sb.append("interface") + false branch : + cond-branch cond:isEnum() + true branch : + sb.append("enum") false branch : + sb.append("class") + + sb.append( ) + sb.append(getName()) + Decl: typeparms=getTypeParameters() + cond-branch cond:typeparms.length GT 0 + true branch : + Decl: first=true + sb.append(<) + TypeVariable + typeparm + typeparms + cond-branch cond:first + true branch : + sb.append(,) false branch : + + sb.append(typeparm.getTypeName()) + first Assign false + + sb.append(>) + false branch : + + return sb.toString() + + func forName(className) throws: ClassNotFoundException return forName(className,true,VMStack.getCallingClassLoader()) - func forName() throws: ClassNotFoundException + func forName(name,initialize,loader) throws: ClassNotFoundException cond-branch cond:loader EQ null true branch : loader Assign BootClassLoader.getInstance() false branch : - var:result + Decl: result + result Assign classForName(name,initialize,loader) + + ClassNotFoundException + e + Decl: cause=e.getCause() + cond-branch cond:cause instanceof LinkageError + true branch : + (LinkageError)cause + false branch : + + e return result - func classForName() throws: ClassNotFoundException + func classForName(className,shouldInitialize,classLoader) throws: ClassNotFoundException func newInstance() throws: InstantiationException IllegalAccessException - func isInstance() throws: + func isInstance(obj) throws: cond-branch cond:obj EQ null true branch : return false false branch : return isAssignableFrom(obj.getClass()) - func isAssignableFrom() throws: + func isAssignableFrom(cls) throws: cond-branch cond:this EQ cls true branch : return true @@ -149,8 +201,19 @@ class Class false branch : cond-branch cond:isInterface() true branch : - var:iftable=cls.ifTable + Decl: iftable=cls.ifTable + cond-branch cond:iftable NE null + true branch : + for ( ) + cond-branch cond: EQ this + true branch : + return true + false branch : + + false branch : + + return false false branch : cond-branch cond:cls.isInterface() true branch : @@ -165,9 +228,6 @@ class Class return false - - - func isInterface() throws: return (accessFlags Band Modifier.INTERFACE) NE 0 func isArray() throws: @@ -181,11 +241,10 @@ class Class func isSynthetic() throws: return (getModifiers() Band SYNTHETIC) NE 0 func getName() throws: - var:name=this.name + Decl: name=this.name cond-branch cond:name EQ null true branch : - this.name Assign name Assign getNameNative() - false branch : + this.name Assign name Assign getNameNative() false branch : return name func getNameNative() throws: @@ -197,13 +256,13 @@ class Class return func getTypeParameters() throws: - var:annotationSignature=getSignatureAttribute() + Decl: annotationSignature=getSignatureAttribute() cond-branch cond:annotationSignature EQ null true branch : return EmptyArray.TYPE_VARIABLE false branch : - var:parser=new GenericSignatureParser + Decl: parser=new GenericSignatureParser(getClassLoader()) parser.parseForClass(this,annotationSignature) return parser.formalTypeParameters func getSuperclass() throws: @@ -214,32 +273,33 @@ class Class return superClass func getGenericSuperclass() throws: - var:genericSuperclass=getSuperclass() + Decl: genericSuperclass=getSuperclass() cond-branch cond:genericSuperclass EQ null true branch : return null false branch : - var:annotationSignature=getSignatureAttribute() + Decl: annotationSignature=getSignatureAttribute() cond-branch cond:annotationSignature NE null true branch : - var:parser=new GenericSignatureParser - + Decl: parser=new GenericSignatureParser(getClassLoader()) + parser.parseForClass(this,annotationSignature) + genericSuperclass Assign parser.superclassType false branch : return Types.getType(genericSuperclass) func getPackage() throws: - var:loader=getClassLoader() + Decl: loader=getClassLoader() cond-branch cond:loader NE null true branch : - var:packageName=getPackageName$() + Decl: packageName=getPackageName$() return false branch : return null func getPackageName$() throws: - var:name=getName() - var:last=name.lastIndexOf(.) + Decl: name=getName() + Decl: last=name.lastIndexOf(.) return func getInterfaces() throws: cond-branch cond:isArray() @@ -247,7 +307,7 @@ class Class return false branch : - var:ifaces=getInterfacesInternal() + Decl: ifaces=getInterfacesInternal() cond-branch cond:ifaces EQ null true branch : return EmptyArray.CLASS @@ -256,13 +316,20 @@ class Class return ifaces func getInterfacesInternal() throws: func getGenericInterfaces() throws: - var:result - Caches.genericInterfaces + Decl: result result Assign Caches.genericInterfaces.get(this) cond-branch cond:result EQ null true branch : - var:annotationSignature=getSignatureAttribute() + Decl: annotationSignature=getSignatureAttribute() + cond-branch cond:annotationSignature EQ null + true branch : + result Assign getInterfaces() + false branch : + Decl: parser=new GenericSignatureParser(getClassLoader()) + parser.parseForClass(this,annotationSignature) + result Assign Types.getTypeArray(parser.interfaceTypes,false) + Caches.genericInterfaces.put(this,result) false branch : @@ -272,12 +339,17 @@ class Class func getModifiers() throws: cond-branch cond:isArray() true branch : - var:componentModifiers= + Decl: componentModifiers=getComponentType().getModifiers() + cond-branch cond:(componentModifiers Band Modifier.INTERFACE) NE 0 + true branch : + componentModifiers BandAssign (Modifier.INTERFACE Bor Modifier.STATIC) + false branch : + return Modifier.ABSTRACT Bor Modifier.FINAL Bor componentModifiers false branch : - var:JAVA_FLAGS_MASK=65535 - var:modifiers= + Decl: JAVA_FLAGS_MASK=65535 + Decl: modifiers=this.getInnerClassFlags(accessFlags Band JAVA_FLAGS_MASK) return modifiers Band JAVA_FLAGS_MASK func getSigners() throws: return null @@ -298,14 +370,13 @@ class Class return getEnclosingConstructorNative() func getEnclosingConstructorNative() throws: func classNameImpliesTopLevel() throws: - return + return getName().contains("$") func getDeclaringClass() throws: func getEnclosingClass() throws: func getSimpleName() throws: cond-branch cond:isArray() true branch : - return Add "[]" - false branch : + return getComponentType().getSimpleName() Add "[]" false branch : cond-branch cond:isAnonymousClass() true branch : @@ -317,8 +388,8 @@ class Class return getInnerClassName() false branch : - var:simpleName=getName() - var:dot=simpleName.lastIndexOf(".") + Decl: simpleName=getName() + Decl: dot=simpleName.lastIndexOf(".") cond-branch cond:dot GT 0 true branch : return simpleName.substring(simpleName.lastIndexOf(".") Add 1) @@ -328,9 +399,21 @@ class Class func getTypeName() throws: cond-branch cond:isArray() true branch : - var:cl=this + Decl: cl=this + Decl: dimensions=0 + while cl.isArray() dimensions Inc + + cl Assign cl.getComponentType() + + Decl: sb=new StringBuilder() + sb.append(cl.getName()) + for ( ) + sb.append("[]") + return sb.toString() + Throwable + e false branch : @@ -338,27 +421,28 @@ class Class func getCanonicalName() throws: cond-branch cond:isArray() true branch : - var:canonicalName= + Decl: canonicalName=getComponentType().getCanonicalName() cond-branch cond:canonicalName NE null true branch : - return canonicalName Add "[]" - false branch : + return canonicalName Add "[]" false branch : return null - false branch : cond-branch cond:isLocalOrAnonymousClass() true branch : - return null - false branch : + return null false branch : - var:enclosingClass=getEnclosingClass() + Decl: enclosingClass=getEnclosingClass() cond-branch cond:enclosingClass EQ null true branch : return getName() false branch : - var:enclosingName=enclosingClass.getCanonicalName() + Decl: enclosingName=enclosingClass.getCanonicalName() + cond-branch cond:enclosingName EQ null + true branch : + return null false branch : + return enclosingName Add "." Add getSimpleName() func isAnonymousClass() throws: func isLocalClass() throws: @@ -368,7 +452,7 @@ class Class func isLocalOrAnonymousClass() throws: return isLocalClass() Lor isAnonymousClass() func getClasses() throws: - var:result=new ArrayList + Decl: result=new ArrayList() for ( ) Class member @@ -382,27 +466,27 @@ class Class return result.toArray(Class,result.size()) func getFields() throws: SecurityException - var:fields=new ArrayList + Decl: fields=new ArrayList() getPublicFieldsRecursive(fields) return fields.toArray(Field,fields.size()) - func getPublicFieldsRecursive() throws: + func getPublicFieldsRecursive(result) throws: for ( ) Collections.addAll(result,c.getPublicDeclaredFields()) - var:iftable=ifTable + Decl: iftable=ifTable cond-branch cond:iftable NE null true branch : for ( ) - Collections.addAll(result,((Class))getPublicDeclaredFields) + Collections.addAll(result,(Class).getPublicDeclaredFields()) false branch : func getMethods() throws: SecurityException - var:methods=new ArrayList + Decl: methods=new ArrayList() getPublicMethodsInternal(methods) CollectionUtils.removeDuplicates(methods,Method.ORDER_BY_SIGNATURE) return methods.toArray(Method,methods.size()) - func getPublicMethodsInternal() throws: + func getPublicMethodsInternal(result) throws: Collections.addAll(result,getDeclaredMethodsUnchecked(true)) cond-branch cond:isInterface() true branch : @@ -411,40 +495,40 @@ class Class false branch : - var:iftable=ifTable + Decl: iftable=ifTable cond-branch cond:iftable NE null true branch : for ( ) - var:ifc=(Class) + Decl: ifc=(Class) Collections.addAll(result,ifc.getDeclaredMethodsUnchecked(true)) false branch : func getConstructors() throws: SecurityException return getDeclaredConstructorsInternal(true) - func getField() throws: NoSuchFieldException + func getField(name) throws: NoSuchFieldException cond-branch cond:name EQ null true branch : - new NullPointerException + new NullPointerException("name == null") false branch : - var:result=getPublicFieldRecursive(name) + Decl: result=getPublicFieldRecursive(name) cond-branch cond:result EQ null true branch : - new NoSuchFieldException + new NoSuchFieldException(name) false branch : return result - func getPublicFieldRecursive() throws: - func getMethod() throws: NoSuchMethodException SecurityException + func getPublicFieldRecursive(name) throws: + func getMethod(name,parameterTypes) throws: NoSuchMethodException SecurityException return getMethod(name,parameterTypes,true) - func getConstructor() throws: NoSuchMethodException SecurityException + func getConstructor(parameterTypes) throws: NoSuchMethodException SecurityException return getConstructor0(parameterTypes,Member.PUBLIC) func getDeclaredClasses() throws: func getDeclaredFields() throws: - func getDeclaredFieldsUnchecked() throws: + func getDeclaredFieldsUnchecked(publicOnly) throws: func getDeclaredMethods() throws: SecurityException - var:result=getDeclaredMethodsUnchecked(false) + Decl: result=getDeclaredMethodsUnchecked(false) Method m result @@ -452,18 +536,18 @@ class Class m.getParameterTypes() return result - func getDeclaredMethodsUnchecked() throws: + func getDeclaredMethodsUnchecked(publicOnly) throws: func getDeclaredConstructors() throws: SecurityException return getDeclaredConstructorsInternal(false) - func getDeclaredConstructorsInternal() throws: - func getDeclaredField() throws: NoSuchFieldException + func getDeclaredConstructorsInternal(publicOnly) throws: + func getDeclaredField(name) throws: NoSuchFieldException func getPublicDeclaredFields() throws: - func getDeclaredMethod() throws: NoSuchMethodException SecurityException + func getDeclaredMethod(name,parameterTypes) throws: NoSuchMethodException SecurityException return getMethod(name,parameterTypes,false) - func getMethod() throws: NoSuchMethodException + func getMethod(name,parameterTypes,recursivePublicMethods) throws: NoSuchMethodException cond-branch cond:name EQ null true branch : - new NullPointerException + new NullPointerException("name == null") false branch : cond-branch cond:parameterTypes EQ null @@ -471,17 +555,25 @@ class Class parameterTypes Assign EmptyArray.CLASS false branch : + Class + c + parameterTypes + cond-branch cond:c EQ null + true branch : + new NoSuchMethodException("parameter type is null") + false branch : + - var:result= + Decl: result= cond-branch cond:result EQ null Lor (recursivePublicMethods Land Modifier.isPublic(result.getAccessFlags())) true branch : - new NoSuchMethodException + new NoSuchMethodException(name Add " " Add Arrays.toString(parameterTypes)) false branch : return result - func getPublicMethodRecursive() throws: + func getPublicMethodRecursive(name,parameterTypes) throws: for ( ) - var:result=c.getDeclaredMethodInternal(name,parameterTypes) + Decl: result=c.getDeclaredMethodInternal(name,parameterTypes) cond-branch cond:result NE null Land Modifier.isPublic(result.getAccessFlags()) true branch : return result @@ -489,9 +581,9 @@ class Class return findInterfaceMethod(name,parameterTypes) - func getInstanceMethod() throws: NoSuchMethodException IllegalAccessException + func getInstanceMethod(name,parameterTypes) throws: NoSuchMethodException IllegalAccessException for ( ) - var:result=c.getDeclaredMethodInternal(name,parameterTypes) + Decl: result=c.getDeclaredMethodInternal(name,parameterTypes) cond-branch cond:result NE null Land Modifier.isStatic(result.getModifiers()) true branch : return result @@ -499,31 +591,36 @@ class Class return findInterfaceMethod(name,parameterTypes) - func findInterfaceMethod() throws: - var:iftable=ifTable + func findInterfaceMethod(name,parameterTypes) throws: + Decl: iftable=ifTable cond-branch cond:iftable NE null true branch : for ( ) - var:ifc=(Class) + Decl: ifc=(Class) + Decl: result=ifc.getPublicMethodRecursive(name,parameterTypes) + cond-branch cond:result NE null Land Modifier.isPublic(result.getAccessFlags()) + true branch : + return result + false branch : false branch : return null - func getDeclaredConstructor() throws: NoSuchMethodException SecurityException + func getDeclaredConstructor(parameterTypes) throws: NoSuchMethodException SecurityException return getConstructor0(parameterTypes,Member.DECLARED) - func getResourceAsStream() throws: + func getResourceAsStream(name) throws: name Assign resolveName(name) - var:cl=getClassLoader() + Decl: cl=getClassLoader() cond-branch cond:cl EQ null true branch : return ClassLoader.getSystemResourceAsStream(name) false branch : return cl.getResourceAsStream(name) - func getResource() throws: + func getResource(name) throws: name Assign resolveName(name) - var:cl=getClassLoader() + Decl: cl=getClassLoader() cond-branch cond:cl EQ null true branch : return ClassLoader.getSystemResource(name) @@ -532,7 +629,7 @@ class Class return cl.getResource(name) func getProtectionDomain() throws: return null - func resolveName() throws: + func resolveName(name) throws: cond-branch cond:name EQ null true branch : return name @@ -540,13 +637,21 @@ class Class cond-branch cond:name.startsWith("/") true branch : - var:c=this + Decl: c=this + while c.isArray() c Assign c.getComponentType() + + Decl: baseName=c.getName() + Decl: index=baseName.lastIndexOf(.) + cond-branch cond:index NE -1 + true branch : + name Assign baseName.substring(0,index).replace(.,/) Add "/" Add name + false branch : false branch : name Assign name.substring(1) return name - func getConstructor0() throws: NoSuchMethodException + func getConstructor0(parameterTypes,which) throws: NoSuchMethodException cond-branch cond:parameterTypes EQ null true branch : parameterTypes Assign EmptyArray.CLASS @@ -557,53 +662,49 @@ class Class parameterTypes cond-branch cond:c EQ null true branch : - new NoSuchMethodException + new NoSuchMethodException("parameter type is null") false branch : - var:result=getDeclaredConstructorInternal(parameterTypes) + Decl: result=getDeclaredConstructorInternal(parameterTypes) cond-branch cond:result EQ null Lor which EQ Member.PUBLIC Land Modifier.isPublic(result.getAccessFlags()) true branch : - new NoSuchMethodException + new NoSuchMethodException(" " Add Arrays.toString(parameterTypes)) false branch : return result - func getDeclaredConstructorInternal() throws: + func getDeclaredConstructorInternal(args) throws: func desiredAssertionStatus() throws: return false func getInnerClassName() throws: - func getInnerClassFlags() throws: + func getInnerClassFlags(defaultValue) throws: func isEnum() throws: - return ( Band ENUM) NE 0 Land EQ java.lang.Enum + return (this.getModifiers() Band ENUM) NE 0 Land this.getSuperclass() EQ java.lang.Enum func getEnumConstants() throws: - var:values=getEnumConstantsShared() + Decl: values=getEnumConstantsShared() return func getEnumConstantsShared() throws: cond-branch cond:isEnum() true branch : - return null - false branch : + return null false branch : return (T[])Enum.getSharedConstants((Class)this) - func cast() throws: + func cast(obj) throws: cond-branch cond:obj NE null Land isInstance(obj) true branch : - new ClassCastException - false branch : + new ClassCastException(cannotCastMsg(obj)) false branch : return (T)obj - func cannotCastMsg() throws: - return "Cannot cast " Add Add " to " Add getName() - func asSubclass() throws: + func cannotCastMsg(obj) throws: + return "Cannot cast " Add obj.getClass().getName() Add " to " Add getName() + func asSubclass(clazz) throws: cond-branch cond:clazz.isAssignableFrom(this) true branch : - return ()this - false branch : - new ClassCastException - - func getAnnotation() throws: + return ()this false branch : + new ClassCastException(this.toString() Add " cannot be cast to " Add clazz.getName()) + func getAnnotation(annotationClass) throws: Objects.requireNonNull(annotationClass) - var:annotation=getDeclaredAnnotation(annotationClass) + Decl: annotation=getDeclaredAnnotation(annotationClass) cond-branch cond:annotation NE null true branch : return annotation @@ -622,10 +723,10 @@ class Class false branch : return null - func isAnnotationPresent() throws: + func isAnnotationPresent(annotationClass) throws: cond-branch cond:annotationClass EQ null true branch : - new NullPointerException + new NullPointerException("annotationClass == null") false branch : cond-branch cond:isDeclaredAnnotationPresent(annotationClass) @@ -645,8 +746,8 @@ class Class false branch : return false - func getAnnotationsByType() throws: - var:annotations= + func getAnnotationsByType(annotationClass) throws: + Decl: annotations= cond-branch cond:annotations.length NE 0 true branch : return annotations @@ -654,7 +755,7 @@ class Class cond-branch cond:annotationClass.isDeclaredAnnotationPresent(Inherited) true branch : - var:superClass=getSuperclass() + Decl: superClass=getSuperclass() cond-branch cond:superClass NE null true branch : return superClass.getAnnotationsByType(annotationClass) @@ -664,7 +765,7 @@ class Class return (A[])Array.newInstance(annotationClass,0) func getAnnotations() throws: - var:map=new HashMap + Decl: map=new HashMap() Annotation declaredAnnotation getDeclaredAnnotations() @@ -674,7 +775,7 @@ class Class Annotation declaredAnnotation sup.getDeclaredAnnotations() - var:clazz=declaredAnnotation.annotationType() + Decl: clazz=declaredAnnotation.annotationType() cond-branch cond:map.containsKey(clazz) Land clazz.isDeclaredAnnotationPresent(Inherited) true branch : map.put(clazz,declaredAnnotation) @@ -682,19 +783,23 @@ class Class - var:coll=map.values() + Decl: coll=map.values() return coll.toArray(Annotation,coll.size()) - func getDeclaredAnnotation() throws: + func getDeclaredAnnotation(annotationClass) throws: func getDeclaredAnnotations() throws: - func isDeclaredAnnotationPresent() throws: + func isDeclaredAnnotationPresent(annotationClass) throws: func getSignatureAttribute() throws: - var:annotation=getSignatureAnnotation() + Decl: annotation=getSignatureAnnotation() cond-branch cond:annotation EQ null true branch : return null false branch : - var:result=new StringBuilder + Decl: result=new StringBuilder() + String + s + annotation + result.append(s) return result.toString() func getSignatureAnnotation() throws: @@ -702,11 +807,11 @@ class Class return (accessFlags Band 262144) NE 0 func getAccessFlags() throws: return accessFlags - func getDeclaredMethodInternal() throws: + func getDeclaredMethodInternal(name,args) throws: LocalClasses: class Caches Fields: - genericInterfaces=new BasicLruCache + genericInterfaces=new BasicLruCache(8) Instance Initializer: Constructors: Methods: @@ -714,9 +819,20 @@ class Class LocalInterfaces: LocalInterfaces: +Identifier:result has no decl. +Identifier:ClassNotFoundException has no decl. +Identifier:e has no decl. +Identifier:e has no decl. +Identifier:result has no decl. Identifier:Method has no decl. Identifier:m has no decl. +Identifier:result has no decl. +Identifier:Class has no decl. +Identifier:c has no decl. Identifier:Class has no decl. Identifier:c has no decl. Identifier:Annotation has no decl. Identifier:declaredAnnotation has no decl. +Identifier:String has no decl. +Identifier:s has no decl. +Identifier:annotation has no decl. diff --git a/src/MapleFE/test/openjdk/ClassCastException.java b/src/MapleFE/test/java/openjdk/ClassCastException.java similarity index 100% rename from src/MapleFE/test/openjdk/ClassCastException.java rename to src/MapleFE/test/java/openjdk/ClassCastException.java diff --git a/src/MapleFE/test/openjdk/ClassCastException.java.result b/src/MapleFE/test/java/openjdk/ClassCastException.java.result similarity index 72% rename from src/MapleFE/test/openjdk/ClassCastException.java.result rename to src/MapleFE/test/java/openjdk/ClassCastException.java.result index f6924ba6c8d0a3f64851ac35dda1cc1f8f7b0b45..51ba376909b673710ac93cfe8dd5b9797f8df885 100644 --- a/src/MapleFE/test/openjdk/ClassCastException.java.result +++ b/src/MapleFE/test/java/openjdk/ClassCastException.java.result @@ -1,17 +1,16 @@ Matched 5 tokens. -Matched 44 tokens. +Matched 43 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class ClassCastException Fields: - serialVersionUID=Sub - 832051876 + serialVersionUID=-832051876 Instance Initializer: Constructors: constructor ClassCastException() throws: - constructor ClassCastException() throws: + constructor ClassCastException(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/ClassCircularityError.java b/src/MapleFE/test/java/openjdk/ClassCircularityError.java similarity index 100% rename from src/MapleFE/test/openjdk/ClassCircularityError.java rename to src/MapleFE/test/java/openjdk/ClassCircularityError.java diff --git a/src/MapleFE/test/openjdk/ClassCircularityError.java.result b/src/MapleFE/test/java/openjdk/ClassCircularityError.java.result similarity index 86% rename from src/MapleFE/test/openjdk/ClassCircularityError.java.result rename to src/MapleFE/test/java/openjdk/ClassCircularityError.java.result index 83db87477c031158210b810f224ec4191755f058..7982bbd80765a5f334f08732eab60e5f54215fcf 100644 --- a/src/MapleFE/test/openjdk/ClassCircularityError.java.result +++ b/src/MapleFE/test/java/openjdk/ClassCircularityError.java.result @@ -10,7 +10,7 @@ class ClassCircularityError Instance Initializer: Constructors: constructor ClassCircularityError() throws: - constructor ClassCircularityError() throws: + constructor ClassCircularityError(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/ClassFormatError.java b/src/MapleFE/test/java/openjdk/ClassFormatError.java similarity index 100% rename from src/MapleFE/test/openjdk/ClassFormatError.java rename to src/MapleFE/test/java/openjdk/ClassFormatError.java diff --git a/src/MapleFE/test/openjdk/ClassFormatError.java.result b/src/MapleFE/test/java/openjdk/ClassFormatError.java.result similarity index 72% rename from src/MapleFE/test/openjdk/ClassFormatError.java.result rename to src/MapleFE/test/java/openjdk/ClassFormatError.java.result index 865999f63df951b27a8c2a422eb5b3a14179ec5a..2a347889ce0f2ca65e193a48128bcfd04f82f4fe 100644 --- a/src/MapleFE/test/openjdk/ClassFormatError.java.result +++ b/src/MapleFE/test/java/openjdk/ClassFormatError.java.result @@ -1,17 +1,16 @@ Matched 5 tokens. -Matched 44 tokens. +Matched 43 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class ClassFormatError Fields: - serialVersionUID=Sub - -344126837 + serialVersionUID=344126837 Instance Initializer: Constructors: constructor ClassFormatError() throws: - constructor ClassFormatError() throws: + constructor ClassFormatError(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/ClassLoader.java b/src/MapleFE/test/java/openjdk/ClassLoader.java similarity index 100% rename from src/MapleFE/test/openjdk/ClassLoader.java rename to src/MapleFE/test/java/openjdk/ClassLoader.java diff --git a/src/MapleFE/test/openjdk/ClassLoader.java.result b/src/MapleFE/test/java/openjdk/ClassLoader.java.result similarity index 57% rename from src/MapleFE/test/openjdk/ClassLoader.java.result rename to src/MapleFE/test/java/openjdk/ClassLoader.java.result index 70912ebe161e0b4b5972a9499fa7f9766efb01fe..185be8e8e980c216e0e7c7636d510e71897251bf 100644 --- a/src/MapleFE/test/openjdk/ClassLoader.java.result +++ b/src/MapleFE/test/java/openjdk/ClassLoader.java.result @@ -115,26 +115,35 @@ import sun.security.util.SecurityConstants == Sub Tree == class ClassLoader Fields: - proxyCache=new HashMap parent packages=new HashMap allocator classTable + proxyCache=new HashMap() parent packages=new HashMap() allocator classTable Instance Initializer: Constructors: - constructor ClassLoader() throws: + constructor ClassLoader(unused,parent) throws: this.parent Assign parent - constructor ClassLoader() throws: + constructor ClassLoader(parent) throws: constructor ClassLoader() throws: Methods: func createSystemClassLoader() throws: - var:classPath=System.getProperty("java.class.path",".") - var:librarySearchPath=System.getProperty("java.library.path","") - return new PathClassLoader + Decl: classPath=System.getProperty("java.class.path",".") + Decl: librarySearchPath=System.getProperty("java.library.path","") + return new PathClassLoader(classPath,librarySearchPath,BootClassLoader.getInstance()) func checkCreateClassLoader() throws: return null - func loadClass() throws: ClassNotFoundException + func loadClass(name) throws: ClassNotFoundException return loadClass(name,false) - func loadClass() throws: ClassNotFoundException - var:c=findLoadedClass(name) + func loadClass(name,resolve) throws: ClassNotFoundException + Decl: c=findLoadedClass(name) cond-branch cond:c EQ null true branch : + cond-branch cond:parent NE null + true branch : + c Assign parent.loadClass(name,false) + false branch : + c Assign findBootstrapClassOrNull(name) + + + ClassNotFoundException + e cond-branch cond:c EQ null true branch : @@ -144,33 +153,31 @@ class ClassLoader false branch : return c - func findClass() throws: ClassNotFoundException - new ClassNotFoundException - func defineClass() throws: ClassFormatError - new UnsupportedOperationException - func defineClass() throws: ClassFormatError - new UnsupportedOperationException - func defineClass() throws: ClassFormatError - new UnsupportedOperationException - func defineClass() throws: ClassFormatError - new UnsupportedOperationException - func resolveClass() throws: - func findSystemClass() throws: ClassNotFoundException + func findClass(name) throws: ClassNotFoundException + new ClassNotFoundException(name) + func defineClass(b,off,len) throws: ClassFormatError + new UnsupportedOperationException("can't load this type of class file") + func defineClass(name,b,off,len) throws: ClassFormatError + new UnsupportedOperationException("can't load this type of class file") + func defineClass(name,b,off,len,protectionDomain) throws: ClassFormatError + new UnsupportedOperationException("can't load this type of class file") + func defineClass(name,b,protectionDomain) throws: ClassFormatError + new UnsupportedOperationException("can't load this type of class file") + func resolveClass(c) throws: + func findSystemClass(name) throws: ClassNotFoundException return Class.forName(name,false,getSystemClassLoader()) - func findBootstrapClassOrNull() throws: + func findBootstrapClassOrNull(name) throws: return null - func findLoadedClass() throws: - var:loader + func findLoadedClass(name) throws: + Decl: loader cond-branch cond:this EQ BootClassLoader.getInstance() true branch : - loader Assign null - false branch : + loader Assign null false branch : loader Assign this - return VMClassLoader.findLoadedClass(loader,name) - func setSigners() throws: - func getResource() throws: - var:url + func setSigners(c,signers) throws: + func getResource(name) throws: + Decl: url cond-branch cond:parent NE null true branch : url Assign parent.getResource(name) @@ -183,8 +190,8 @@ class ClassLoader false branch : return url - func getResources() throws: IOException - var:tmp=() + func getResources(name) throws: IOException + Decl: tmp=() cond-branch cond:parent NE null true branch : Assign parent.getResources(name) @@ -192,70 +199,80 @@ class ClassLoader Assign getBootstrapResources(name) Assign findResources(name) - return new CompoundEnumeration - func findResource() throws: + return new CompoundEnumeration(tmp) + func findResource(name) throws: return null - func findResources() throws: IOException + func findResources(name) throws: IOException return java.util.Collections.emptyEnumeration() func registerAsParallelCapable() throws: return true - func getSystemResource() throws: - var:system=getSystemClassLoader() + func getSystemResource(name) throws: + Decl: system=getSystemClassLoader() cond-branch cond:system EQ null true branch : return getBootstrapResource(name) false branch : return system.getResource(name) - func getSystemResources() throws: IOException - var:system=getSystemClassLoader() + func getSystemResources(name) throws: IOException + Decl: system=getSystemClassLoader() cond-branch cond:system EQ null true branch : return getBootstrapResources(name) false branch : return system.getResources(name) - func getBootstrapResource() throws: + func getBootstrapResource(name) throws: return null - func getBootstrapResources() throws: IOException + func getBootstrapResources(name) throws: IOException return null - func getResourceAsStream() throws: - var:url=getResource(name) + func getResourceAsStream(name) throws: + Decl: url=getResource(name) return + IOException + e + return null - func getSystemResourceAsStream() throws: - var:url=getSystemResource(name) + func getSystemResourceAsStream(name) throws: + Decl: url=getSystemResource(name) return + IOException + e + return null func getParent() throws: return parent func getSystemClassLoader() throws: return SystemClassLoader.loader - func definePackage() throws: IllegalArgumentException - packages - var:pkg=packages.get(name) + func definePackage(name,specTitle,specVersion,specVendor,implTitle,implVersion,implVendor,sealBase) throws: IllegalArgumentException + Decl: pkg=packages.get(name) + cond-branch cond:pkg NE null + true branch : + new IllegalArgumentException(name) + false branch : + pkg Assign new Package(name,specTitle,specVersion,specVendor,implTitle,implVersion,implVendor,sealBase,this) + packages.put(name,pkg) + return pkg - func getPackage() throws: - var:pkg - packages + func getPackage(name) throws: + Decl: pkg pkg Assign packages.get(name) return pkg func getPackages() throws: - var:map - packages - map Assign new HashMap + Decl: map + map Assign new HashMap(packages) - var:pkgs - return - func findLibrary() throws: + Decl: pkgs + return map.values().toArray(Package,map.size()) + func findLibrary(libname) throws: return null - func setDefaultAssertionStatus() throws: - func setPackageAssertionStatus() throws: - func setClassAssertionStatus() throws: + func setDefaultAssertionStatus(enabled) throws: + func setPackageAssertionStatus(packageName,enabled) throws: + func setClassAssertionStatus(className,enabled) throws: func clearAssertionStatus() throws: LocalClasses: class SystemClassLoader @@ -279,37 +296,41 @@ class BootClassLoader func getInstance() throws: cond-branch cond:instance EQ null true branch : - instance Assign new BootClassLoader + instance Assign new BootClassLoader() false branch : return instance - func findClass() throws: ClassNotFoundException + func findClass(name) throws: ClassNotFoundException return Class.classForName(name,false,null) - func findResource() throws: + func findResource(name) throws: return VMClassLoader.getResource(name) - func findResources() throws: IOException + func findResources(resName) throws: IOException return Collections.enumeration(VMClassLoader.getResources(resName)) - func getPackage() throws: + func getPackage(name) throws: cond-branch cond:name NE null Land name.isEmpty() true branch : - this - var:pack= + Decl: pack=super.getPackage(name) + cond-branch cond:pack EQ null + true branch : + pack Assign definePackage(name,"Unknown","0.0","Unknown","Unknown","0.0","Unknown",null) + false branch : + return pack false branch : return null - func getResource() throws: + func getResource(resName) throws: return findResource(resName) - func loadClass() throws: ClassNotFoundException - var:clazz=findLoadedClass(className) + func loadClass(className,resolve) throws: ClassNotFoundException + Decl: clazz=findLoadedClass(className) cond-branch cond:clazz EQ null true branch : clazz Assign findClass(className) false branch : return clazz - func getResources() throws: IOException + func getResources(resName) throws: IOException return findResources(resName) LocalClasses: LocalInterfaces: @@ -319,4 +340,12 @@ UserType:UnsupportedOperationException has no decl. UserType:UnsupportedOperationException has no decl. UserType:UnsupportedOperationException has no decl. UserType:UnsupportedOperationException has no decl. +Identifier:IOException has no decl. +Identifier:e has no decl. +Identifier:IOException has no decl. +Identifier:e has no decl. +Identifier:pkg has no decl. +UserType:Package has no decl. +Identifier:pkg has no decl. +Identifier:map has no decl. UserType:HashMap has no decl. diff --git a/src/MapleFE/test/openjdk/ClassNotFoundException.java b/src/MapleFE/test/java/openjdk/ClassNotFoundException.java similarity index 100% rename from src/MapleFE/test/openjdk/ClassNotFoundException.java rename to src/MapleFE/test/java/openjdk/ClassNotFoundException.java diff --git a/src/MapleFE/test/openjdk/ClassNotFoundException.java.result b/src/MapleFE/test/java/openjdk/ClassNotFoundException.java.result similarity index 80% rename from src/MapleFE/test/openjdk/ClassNotFoundException.java.result rename to src/MapleFE/test/java/openjdk/ClassNotFoundException.java.result index 3fa59df1521e1bc42fd7830f9cb1fa2f40e2aad3..2fb746eda8dc24d8092ee275bdddd7d7cb8a4176 100644 --- a/src/MapleFE/test/openjdk/ClassNotFoundException.java.result +++ b/src/MapleFE/test/java/openjdk/ClassNotFoundException.java.result @@ -10,8 +10,8 @@ class ClassNotFoundException Instance Initializer: Constructors: constructor ClassNotFoundException() throws: - constructor ClassNotFoundException() throws: - constructor ClassNotFoundException() throws: + constructor ClassNotFoundException(s) throws: + constructor ClassNotFoundException(s,ex) throws: this.ex Assign ex Methods: func getException() throws: diff --git a/src/MapleFE/test/openjdk/CloneNotSupportedException.java b/src/MapleFE/test/java/openjdk/CloneNotSupportedException.java similarity index 100% rename from src/MapleFE/test/openjdk/CloneNotSupportedException.java rename to src/MapleFE/test/java/openjdk/CloneNotSupportedException.java diff --git a/src/MapleFE/test/openjdk/CloneNotSupportedException.java.result b/src/MapleFE/test/java/openjdk/CloneNotSupportedException.java.result similarity index 85% rename from src/MapleFE/test/openjdk/CloneNotSupportedException.java.result rename to src/MapleFE/test/java/openjdk/CloneNotSupportedException.java.result index e9dbfc2a87bc8c3893fa28cea8dd811e372d51c4..b63bfc1f9a54290068194a116ccfe561190c4612 100644 --- a/src/MapleFE/test/openjdk/CloneNotSupportedException.java.result +++ b/src/MapleFE/test/java/openjdk/CloneNotSupportedException.java.result @@ -10,7 +10,7 @@ class CloneNotSupportedException Instance Initializer: Constructors: constructor CloneNotSupportedException() throws: - constructor CloneNotSupportedException() throws: + constructor CloneNotSupportedException(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/Cloneable.java b/src/MapleFE/test/java/openjdk/Cloneable.java similarity index 100% rename from src/MapleFE/test/openjdk/Cloneable.java rename to src/MapleFE/test/java/openjdk/Cloneable.java diff --git a/src/MapleFE/test/openjdk/Cloneable.java.result b/src/MapleFE/test/java/openjdk/Cloneable.java.result similarity index 100% rename from src/MapleFE/test/openjdk/Cloneable.java.result rename to src/MapleFE/test/java/openjdk/Cloneable.java.result diff --git a/src/MapleFE/test/openjdk/Comparable.java b/src/MapleFE/test/java/openjdk/Comparable.java similarity index 100% rename from src/MapleFE/test/openjdk/Comparable.java rename to src/MapleFE/test/java/openjdk/Comparable.java diff --git a/src/MapleFE/test/openjdk/Comparable.java.result b/src/MapleFE/test/java/openjdk/Comparable.java.result similarity index 86% rename from src/MapleFE/test/openjdk/Comparable.java.result rename to src/MapleFE/test/java/openjdk/Comparable.java.result index 2d737cec543cbff17120c020edeaa87d83f005ef..1a4f72012690673b17f68a7e024fb72ffe4548e0 100644 --- a/src/MapleFE/test/openjdk/Comparable.java.result +++ b/src/MapleFE/test/java/openjdk/Comparable.java.result @@ -11,5 +11,5 @@ interface Comparable Fields: Methods: - func compareTo() throws: + func compareTo(o) throws: diff --git a/src/MapleFE/test/openjdk/Compiler.java b/src/MapleFE/test/java/openjdk/Compiler.java similarity index 100% rename from src/MapleFE/test/openjdk/Compiler.java rename to src/MapleFE/test/java/openjdk/Compiler.java diff --git a/src/MapleFE/test/openjdk/Compiler.java.result b/src/MapleFE/test/java/openjdk/Compiler.java.result similarity index 75% rename from src/MapleFE/test/openjdk/Compiler.java.result rename to src/MapleFE/test/java/openjdk/Compiler.java.result index d8c352271fda6a7d2612ae65351aaa16fe264269..a6b3bc5da59adcff29ccbede3941e1593d56b599 100644 --- a/src/MapleFE/test/openjdk/Compiler.java.result +++ b/src/MapleFE/test/java/openjdk/Compiler.java.result @@ -11,11 +11,11 @@ class Compiler Constructors: constructor Compiler() throws: Methods: - func compileClass() throws: + func compileClass(classToCompile) throws: return false - func compileClasses() throws: + func compileClasses(nameRoot) throws: return false - func command() throws: + func command(cmd) throws: return null func enable() throws: func disable() throws: diff --git a/src/MapleFE/test/openjdk/Deprecated.java b/src/MapleFE/test/java/openjdk/Deprecated.java similarity index 100% rename from src/MapleFE/test/openjdk/Deprecated.java rename to src/MapleFE/test/java/openjdk/Deprecated.java diff --git a/src/MapleFE/test/openjdk/Deprecated.java.result b/src/MapleFE/test/java/openjdk/Deprecated.java.result similarity index 100% rename from src/MapleFE/test/openjdk/Deprecated.java.result rename to src/MapleFE/test/java/openjdk/Deprecated.java.result diff --git a/src/MapleFE/test/openjdk/Double-2.java b/src/MapleFE/test/java/openjdk/Double-2.java similarity index 100% rename from src/MapleFE/test/openjdk/Double-2.java rename to src/MapleFE/test/java/openjdk/Double-2.java diff --git a/src/MapleFE/test/openjdk/Double-2.java.result b/src/MapleFE/test/java/openjdk/Double-2.java.result similarity index 89% rename from src/MapleFE/test/openjdk/Double-2.java.result rename to src/MapleFE/test/java/openjdk/Double-2.java.result index 8d239862b275dd1b9801953098cfd98e7a63dc9a..65efd20c0deac2928bdfa238f6a21a7b51b3f2f9 100644 --- a/src/MapleFE/test/openjdk/Double-2.java.result +++ b/src/MapleFE/test/java/openjdk/Double-2.java.result @@ -7,7 +7,7 @@ class Double Instance Initializer: Constructors: Methods: - func equals() throws: + func equals(obj) throws: return doubleToLongBits((Double)obj.value) EQ doubleToLongBits(value) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/Double.java b/src/MapleFE/test/java/openjdk/Double.java similarity index 100% rename from src/MapleFE/test/openjdk/Double.java rename to src/MapleFE/test/java/openjdk/Double.java diff --git a/src/MapleFE/test/openjdk/Double.java.result b/src/MapleFE/test/java/openjdk/Double.java.result similarity index 42% rename from src/MapleFE/test/openjdk/Double.java.result rename to src/MapleFE/test/java/openjdk/Double.java.result index fecc8cc42968c1c08b816502b7b3c098d5fc2fe9..7092f2aa51d3f61a8f59e3870d43aa2cdd0cc09c 100644 --- a/src/MapleFE/test/openjdk/Double.java.result +++ b/src/MapleFE/test/java/openjdk/Double.java.result @@ -2,7 +2,7 @@ Matched 5 tokens. Matched 12 tokens. Matched 19 tokens. Matched 26 tokens. -Matched 976 tokens. +Matched 972 tokens. ============= Module =========== == Sub Tree == package java.lang @@ -15,37 +15,52 @@ import sun.misc.DoubleConsts == Sub Tree == class Double Fields: - POSITIVE_INFINITY= NEGATIVE_INFINITY= NaN= MAX_VALUE=1.79769e+308 MIN_NORMAL=2.22507e-308 MIN_VALUE=4.94066e-324 MAX_EXPONENT=1023 MIN_EXPONENT=Sub - 1022 SIZE=64 BYTES= TYPE=() value serialVersionUID=Sub - -694942468 + POSITIVE_INFINITY=1 Div 0 NEGATIVE_INFINITY=-1 Div 0 NaN=0 Div 0 MAX_VALUE=1.79769e+308 MIN_NORMAL=2.22507e-308 MIN_VALUE=4.94066e-324 MAX_EXPONENT=1023 MIN_EXPONENT=-1022 SIZE=64 BYTES=SIZE Div Byte.SIZE TYPE=()double.getComponentType() value serialVersionUID=694942468 Instance Initializer: Constructors: - constructor Double() throws: + constructor Double(value) throws: this.value Assign value - constructor Double() throws: + constructor Double(s) throws: value Assign parseDouble(s) Methods: - func toString() throws: + func toString(d) throws: return FloatingDecimal.toJavaFormatString(d) - func toHexString() throws: + func toHexString(d) throws: cond-branch cond:isFinite(d) true branch : - return Double.toString(d) - false branch : - var:answer=new StringBuilder + return Double.toString(d) false branch : + Decl: answer=new StringBuilder(24) + cond-branch cond:Math.copySign(1,d) EQ -1 + true branch : + answer.append("-") false branch : + + answer.append("0x") + d Assign Math.abs(d) + cond-branch cond:d EQ 0 + true branch : + answer.append("0.0p0") + false branch : + Decl: subnormal=(d LT DoubleConsts.MIN_NORMAL) + Decl: signifBits=(Double.doubleToLongBits(d) Band DoubleConsts.SIGNIF_BIT_MASK) Bor 0 + answer.append(subnormal,"0.","1.") + Decl: signif=Long.toHexString(signifBits).substring(3,16) + answer.append(signif.equals("0000000000000"),"0",signif.replaceFirst("0{1,12}$","")) + answer.append(p) + answer.append(subnormal,DoubleConsts.MIN_EXPONENT,Math.getExponent(d)) + return answer.toString() - func valueOf() throws: NumberFormatException - return new Double - func valueOf() throws: - return new Double - func parseDouble() throws: NumberFormatException + func valueOf(s) throws: NumberFormatException + return new Double(parseDouble(s)) + func valueOf(d) throws: + return new Double(d) + func parseDouble(s) throws: NumberFormatException return FloatingDecimal.parseDouble(s) - func isNaN() throws: + func isNaN(v) throws: return (v NE v) - func isInfinite() throws: + func isInfinite(v) throws: return (v EQ POSITIVE_INFINITY) Lor (v EQ NEGATIVE_INFINITY) - func isFinite() throws: + func isFinite(d) throws: return Math.abs(d) LE DoubleConsts.MAX_VALUE func isNaN() throws: return isNaN(value) @@ -67,43 +82,39 @@ class Double return value func hashCode() throws: return Double.hashCode(value) - func hashCode() throws: - var:bits=doubleToLongBits(value) + func hashCode(value) throws: + Decl: bits=doubleToLongBits(value) return (int)(bits Bxor (bits Zext 32)) - func equals() throws: - return () Land (doubleToLongBits((Double)obj.value) EQ doubleToLongBits(value)) - func doubleToLongBits() throws: - var:result=doubleToRawLongBits(value) + func equals(obj) throws: + return (obj instanceof Double) Land (doubleToLongBits((Double)obj.value) EQ doubleToLongBits(value)) + func doubleToLongBits(value) throws: + Decl: result=doubleToRawLongBits(value) cond-branch cond:((result Band DoubleConsts.EXP_BIT_MASK) EQ DoubleConsts.EXP_BIT_MASK) Land (result Band DoubleConsts.SIGNIF_BIT_MASK) NE 0 true branch : - result Assign 0 - false branch : + result Assign 0 false branch : return result - func doubleToRawLongBits() throws: - func longBitsToDouble() throws: - func compareTo() throws: + func doubleToRawLongBits(value) throws: + func longBitsToDouble(bits) throws: + func compareTo(anotherDouble) throws: return Double.compare(value,anotherDouble.value) - func compare() throws: + func compare(d1,d2) throws: cond-branch cond:d1 LT d2 true branch : - return Sub - 1 - false branch : + return -1 false branch : cond-branch cond:d1 GT d2 true branch : - return 1 - false branch : + return 1 false branch : - var:thisBits=Double.doubleToLongBits(d1) - var:anotherBits=Double.doubleToLongBits(d2) + Decl: thisBits=Double.doubleToLongBits(d1) + Decl: anotherBits=Double.doubleToLongBits(d2) return () - func sum() throws: + func sum(a,b) throws: return a Add b - func max() throws: + func max(a,b) throws: return Math.max(a,b) - func min() throws: + func min(a,b) throws: return Math.min(a,b) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/Enum.java b/src/MapleFE/test/java/openjdk/Enum.java similarity index 100% rename from src/MapleFE/test/openjdk/Enum.java rename to src/MapleFE/test/java/openjdk/Enum.java diff --git a/src/MapleFE/test/openjdk/Enum.java.result b/src/MapleFE/test/java/openjdk/Enum.java.result similarity index 68% rename from src/MapleFE/test/openjdk/Enum.java.result rename to src/MapleFE/test/java/openjdk/Enum.java.result index c3a82a8bdf1800105532533ff0d0fb9bd97fdf10..fa6cb1d2de4c2b14419e990aa4cafbcc07f16cf7 100644 --- a/src/MapleFE/test/openjdk/Enum.java.result +++ b/src/MapleFE/test/java/openjdk/Enum.java.result @@ -33,10 +33,10 @@ import libcore.util.EmptyArray == Sub Tree == class Enum Fields: - name ordinal sharedConstantsCache=new BasicLruCache + name ordinal sharedConstantsCache=new BasicLruCache(64) Instance Initializer: Constructors: - constructor Enum() throws: + constructor Enum(name,ordinal) throws: this.name Assign name this.ordinal Assign ordinal Methods: @@ -46,58 +46,57 @@ class Enum return ordinal func toString() throws: return name - func equals() throws: + func equals(other) throws: return this EQ other func hashCode() throws: - return hashCode + return super.hashCode() func clone() throws: CloneNotSupportedException - new CloneNotSupportedException - func compareTo() throws: - var:other=(Enum)o - var:self=this + new CloneNotSupportedException() + func compareTo(o) throws: + Decl: other=(Enum)o + Decl: self=this cond-branch cond:self.getClass() NE other.getClass() Land self.getDeclaringClass() NE other.getDeclaringClass() true branch : - new ClassCastException - false branch : + new ClassCastException() false branch : return self.ordinal Sub other.ordinal func getDeclaringClass() throws: - var:clazz=getClass() - var:zuper=clazz.getSuperclass() + Decl: clazz=getClass() + Decl: zuper=clazz.getSuperclass() return - func valueOf() throws: + func valueOf(enumType,name) throws: cond-branch cond:enumType EQ null true branch : - new NullPointerException + new NullPointerException("enumType == null") false branch : cond-branch cond:name EQ null true branch : - new NullPointerException + new NullPointerException("name == null") false branch : - var:values=getSharedConstants(enumType) + Decl: values=getSharedConstants(enumType) cond-branch cond:values EQ null true branch : - new IllegalArgumentException + new IllegalArgumentException(enumType.toString() Add " is not an enum type.") false branch : for ( ) - var:value= + Decl: value= cond-branch cond:name.equals(value.name()) true branch : return value false branch : - new IllegalArgumentException - func getSharedConstants() throws: + new IllegalArgumentException("No enum constant " Add enumType.getCanonicalName() Add "." Add name) + func getSharedConstants(enumType) throws: return (T[])sharedConstantsCache.get(enumType) func finalize() throws: - func readObject() throws: IOException ClassNotFoundException - new InvalidObjectException + func readObject(in) throws: IOException ClassNotFoundException + new InvalidObjectException("can't deserialize enum") func readObjectNoData() throws: ObjectStreamException - new InvalidObjectException + new InvalidObjectException("can't deserialize enum") LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/EnumConstantNotPresentException.java b/src/MapleFE/test/java/openjdk/EnumConstantNotPresentException.java similarity index 100% rename from src/MapleFE/test/openjdk/EnumConstantNotPresentException.java rename to src/MapleFE/test/java/openjdk/EnumConstantNotPresentException.java diff --git a/src/MapleFE/test/openjdk/EnumConstantNotPresentException.java.result b/src/MapleFE/test/java/openjdk/EnumConstantNotPresentException.java.result similarity index 78% rename from src/MapleFE/test/openjdk/EnumConstantNotPresentException.java.result rename to src/MapleFE/test/java/openjdk/EnumConstantNotPresentException.java.result index e1e8b1230b1af6a155ea5a8c2f4f1b74a256be72..b4d1d6a141a842aef6d533c1087756cb49f5874f 100644 --- a/src/MapleFE/test/openjdk/EnumConstantNotPresentException.java.result +++ b/src/MapleFE/test/java/openjdk/EnumConstantNotPresentException.java.result @@ -1,16 +1,15 @@ Matched 5 tokens. -Matched 105 tokens. +Matched 104 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class EnumConstantNotPresentException Fields: - serialVersionUID=Sub - 180673940 enumType constantName + serialVersionUID=-180673940 enumType constantName Instance Initializer: Constructors: - constructor EnumConstantNotPresentException() throws: + constructor EnumConstantNotPresentException(enumType,constantName) throws: this.enumType Assign enumType this.constantName Assign constantName Methods: diff --git a/src/MapleFE/test/openjdk/Error.java b/src/MapleFE/test/java/openjdk/Error.java similarity index 100% rename from src/MapleFE/test/openjdk/Error.java rename to src/MapleFE/test/java/openjdk/Error.java diff --git a/src/MapleFE/test/openjdk/Error.java.result b/src/MapleFE/test/java/openjdk/Error.java.result similarity index 58% rename from src/MapleFE/test/openjdk/Error.java.result rename to src/MapleFE/test/java/openjdk/Error.java.result index 5dd4622ea7053655bf6e1c4dcc81bba7800f9fb3..51113c2cd922e448298aebd5378e04c5c9ec02d8 100644 --- a/src/MapleFE/test/openjdk/Error.java.result +++ b/src/MapleFE/test/java/openjdk/Error.java.result @@ -10,10 +10,10 @@ class Error Instance Initializer: Constructors: constructor Error() throws: - constructor Error() throws: - constructor Error() throws: - constructor Error() throws: - constructor Error() throws: + constructor Error(message) throws: + constructor Error(message,cause) throws: + constructor Error(cause) throws: + constructor Error(message,cause,enableSuppression,writableStackTrace) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/Exception.java b/src/MapleFE/test/java/openjdk/Exception.java similarity index 100% rename from src/MapleFE/test/openjdk/Exception.java rename to src/MapleFE/test/java/openjdk/Exception.java diff --git a/src/MapleFE/test/openjdk/Exception.java.result b/src/MapleFE/test/java/openjdk/Exception.java.result similarity index 47% rename from src/MapleFE/test/openjdk/Exception.java.result rename to src/MapleFE/test/java/openjdk/Exception.java.result index be76c0a91de7ca3202633ccc22099abc4729e97c..f47c721d29f22195f9da1f72a77ebe994d9999a6 100644 --- a/src/MapleFE/test/openjdk/Exception.java.result +++ b/src/MapleFE/test/java/openjdk/Exception.java.result @@ -1,20 +1,19 @@ Matched 5 tokens. -Matched 102 tokens. +Matched 101 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class Exception Fields: - serialVersionUID=Sub - -440081604 + serialVersionUID=440081604 Instance Initializer: Constructors: constructor Exception() throws: - constructor Exception() throws: - constructor Exception() throws: - constructor Exception() throws: - constructor Exception() throws: + constructor Exception(message) throws: + constructor Exception(message,cause) throws: + constructor Exception(cause) throws: + constructor Exception(message,cause,enableSuppression,writableStackTrace) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/ExceptionInInitializerError.java b/src/MapleFE/test/java/openjdk/ExceptionInInitializerError.java similarity index 100% rename from src/MapleFE/test/openjdk/ExceptionInInitializerError.java rename to src/MapleFE/test/java/openjdk/ExceptionInInitializerError.java diff --git a/src/MapleFE/test/openjdk/ExceptionInInitializerError.java.result b/src/MapleFE/test/java/openjdk/ExceptionInInitializerError.java.result similarity index 82% rename from src/MapleFE/test/openjdk/ExceptionInInitializerError.java.result rename to src/MapleFE/test/java/openjdk/ExceptionInInitializerError.java.result index cafc9f7c7352ee5c569011a0e8f5d1fa3b724cb6..23df8f7d4d6f1ebc4424ebe5708fe741390d7c04 100644 --- a/src/MapleFE/test/openjdk/ExceptionInInitializerError.java.result +++ b/src/MapleFE/test/java/openjdk/ExceptionInInitializerError.java.result @@ -11,10 +11,10 @@ class ExceptionInInitializerError Constructors: constructor ExceptionInInitializerError() throws: initCause(null) - constructor ExceptionInInitializerError() throws: + constructor ExceptionInInitializerError(thrown) throws: initCause(null) this.exception Assign thrown - constructor ExceptionInInitializerError() throws: + constructor ExceptionInInitializerError(s) throws: initCause(null) Methods: func getException() throws: diff --git a/src/MapleFE/test/openjdk/Float.java b/src/MapleFE/test/java/openjdk/Float.java similarity index 100% rename from src/MapleFE/test/openjdk/Float.java rename to src/MapleFE/test/java/openjdk/Float.java diff --git a/src/MapleFE/test/openjdk/Float.java.result b/src/MapleFE/test/java/openjdk/Float.java.result similarity index 54% rename from src/MapleFE/test/openjdk/Float.java.result rename to src/MapleFE/test/java/openjdk/Float.java.result index d1727db3e9bb575fcc88b0116c9f43d413c189b3..25f8d35f633b02d35b2f9e4cdabb6647e0e56b50 100644 --- a/src/MapleFE/test/openjdk/Float.java.result +++ b/src/MapleFE/test/java/openjdk/Float.java.result @@ -2,7 +2,7 @@ Matched 5 tokens. Matched 12 tokens. Matched 19 tokens. Matched 26 tokens. -Matched 848 tokens. +Matched 844 tokens. ============= Module =========== == Sub Tree == package java.lang @@ -15,39 +15,36 @@ import sun.misc.DoubleConsts == Sub Tree == class Float Fields: - POSITIVE_INFINITY= NEGATIVE_INFINITY= NaN= MAX_VALUE=3.40282e+38 MIN_NORMAL=1.17549e-38 MIN_VALUE=1.4013e-45 MAX_EXPONENT=127 MIN_EXPONENT=Sub - 126 SIZE=32 BYTES= TYPE=() value serialVersionUID=Sub - 616763156 + POSITIVE_INFINITY=1 Div 0 NEGATIVE_INFINITY=-1 Div 0 NaN=0 Div 0 MAX_VALUE=3.40282e+38 MIN_NORMAL=1.17549e-38 MIN_VALUE=1.4013e-45 MAX_EXPONENT=127 MIN_EXPONENT=-126 SIZE=32 BYTES=SIZE Div Byte.SIZE TYPE=()float.getComponentType() value serialVersionUID=-616763156 Instance Initializer: Constructors: - constructor Float() throws: + constructor Float(value) throws: this.value Assign value - constructor Float() throws: + constructor Float(value) throws: this.value Assign (float)value - constructor Float() throws: + constructor Float(s) throws: value Assign parseFloat(s) Methods: - func toString() throws: + func toString(f) throws: return FloatingDecimal.toJavaFormatString(f) - func toHexString() throws: + func toHexString(f) throws: cond-branch cond:Math.abs(f) LT FloatConsts.MIN_NORMAL Land f NE 0 true branch : - var:s=Double.toHexString(Math.scalb((double)f,DoubleConsts.MIN_EXPONENT Sub FloatConsts.MIN_EXPONENT)) + Decl: s=Double.toHexString(Math.scalb((double)f,DoubleConsts.MIN_EXPONENT Sub FloatConsts.MIN_EXPONENT)) return s.replaceFirst("p-1022$","p-126") false branch : return Double.toHexString(f) - - func valueOf() throws: NumberFormatException - return new Float - func valueOf() throws: - return new Float - func parseFloat() throws: NumberFormatException + func valueOf(s) throws: NumberFormatException + return new Float(parseFloat(s)) + func valueOf(f) throws: + return new Float(f) + func parseFloat(s) throws: NumberFormatException return FloatingDecimal.parseFloat(s) - func isNaN() throws: + func isNaN(v) throws: return (v NE v) - func isInfinite() throws: + func isInfinite(v) throws: return (v EQ POSITIVE_INFINITY) Lor (v EQ NEGATIVE_INFINITY) - func isFinite() throws: + func isFinite(f) throws: return Math.abs(f) LE FloatConsts.MAX_VALUE func isNaN() throws: return isNaN(value) @@ -69,42 +66,38 @@ class Float return (double)value func hashCode() throws: return Float.hashCode(value) - func hashCode() throws: + func hashCode(value) throws: return floatToIntBits(value) - func equals() throws: - return () Land (floatToIntBits((Float)obj.value) EQ floatToIntBits(value)) - func floatToIntBits() throws: - var:result=floatToRawIntBits(value) + func equals(obj) throws: + return (obj instanceof Float) Land (floatToIntBits((Float)obj.value) EQ floatToIntBits(value)) + func floatToIntBits(value) throws: + Decl: result=floatToRawIntBits(value) cond-branch cond:((result Band FloatConsts.EXP_BIT_MASK) EQ FloatConsts.EXP_BIT_MASK) Land (result Band FloatConsts.SIGNIF_BIT_MASK) NE 0 true branch : - result Assign 2143289344 - false branch : + result Assign 2143289344 false branch : return result - func floatToRawIntBits() throws: - func intBitsToFloat() throws: - func compareTo() throws: + func floatToRawIntBits(value) throws: + func intBitsToFloat(bits) throws: + func compareTo(anotherFloat) throws: return Float.compare(value,anotherFloat.value) - func compare() throws: + func compare(f1,f2) throws: cond-branch cond:f1 LT f2 true branch : - return Sub - 1 - false branch : + return -1 false branch : cond-branch cond:f1 GT f2 true branch : - return 1 - false branch : + return 1 false branch : - var:thisBits=Float.floatToIntBits(f1) - var:anotherBits=Float.floatToIntBits(f2) + Decl: thisBits=Float.floatToIntBits(f1) + Decl: anotherBits=Float.floatToIntBits(f2) return () - func sum() throws: + func sum(a,b) throws: return a Add b - func max() throws: + func max(a,b) throws: return Math.max(a,b) - func min() throws: + func min(a,b) throws: return Math.min(a,b) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/FunctionalInterface.java b/src/MapleFE/test/java/openjdk/FunctionalInterface.java similarity index 100% rename from src/MapleFE/test/openjdk/FunctionalInterface.java rename to src/MapleFE/test/java/openjdk/FunctionalInterface.java diff --git a/src/MapleFE/test/openjdk/FunctionalInterface.java.result b/src/MapleFE/test/java/openjdk/FunctionalInterface.java.result similarity index 100% rename from src/MapleFE/test/openjdk/FunctionalInterface.java.result rename to src/MapleFE/test/java/openjdk/FunctionalInterface.java.result diff --git a/src/MapleFE/test/openjdk/IllegalAccessError.java b/src/MapleFE/test/java/openjdk/IllegalAccessError.java similarity index 100% rename from src/MapleFE/test/openjdk/IllegalAccessError.java rename to src/MapleFE/test/java/openjdk/IllegalAccessError.java diff --git a/src/MapleFE/test/openjdk/IllegalAccessError.java.result b/src/MapleFE/test/java/openjdk/IllegalAccessError.java.result similarity index 72% rename from src/MapleFE/test/openjdk/IllegalAccessError.java.result rename to src/MapleFE/test/java/openjdk/IllegalAccessError.java.result index 901d3350b0a4bfbed762b29a13590ceb71be2bdc..ee810c6fa19c6471f03a7890f4fe6eb372772f8c 100644 --- a/src/MapleFE/test/openjdk/IllegalAccessError.java.result +++ b/src/MapleFE/test/java/openjdk/IllegalAccessError.java.result @@ -1,17 +1,16 @@ Matched 5 tokens. -Matched 44 tokens. +Matched 43 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class IllegalAccessError Fields: - serialVersionUID=Sub - -2047083421 + serialVersionUID=2047083421 Instance Initializer: Constructors: constructor IllegalAccessError() throws: - constructor IllegalAccessError() throws: + constructor IllegalAccessError(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/IllegalAccessException.java b/src/MapleFE/test/java/openjdk/IllegalAccessException.java similarity index 100% rename from src/MapleFE/test/openjdk/IllegalAccessException.java rename to src/MapleFE/test/java/openjdk/IllegalAccessException.java diff --git a/src/MapleFE/test/openjdk/IllegalAccessException.java.result b/src/MapleFE/test/java/openjdk/IllegalAccessException.java.result similarity index 86% rename from src/MapleFE/test/openjdk/IllegalAccessException.java.result rename to src/MapleFE/test/java/openjdk/IllegalAccessException.java.result index 77c6d9fc962f50bb6aa151c2d40484d8735d3355..0f015ed019a86553dfc8e3ba415a62f922910507 100644 --- a/src/MapleFE/test/openjdk/IllegalAccessException.java.result +++ b/src/MapleFE/test/java/openjdk/IllegalAccessException.java.result @@ -10,7 +10,7 @@ class IllegalAccessException Instance Initializer: Constructors: constructor IllegalAccessException() throws: - constructor IllegalAccessException() throws: + constructor IllegalAccessException(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/IllegalArgumentException.java b/src/MapleFE/test/java/openjdk/IllegalArgumentException.java similarity index 100% rename from src/MapleFE/test/openjdk/IllegalArgumentException.java rename to src/MapleFE/test/java/openjdk/IllegalArgumentException.java diff --git a/src/MapleFE/test/openjdk/IllegalArgumentException.java.result b/src/MapleFE/test/java/openjdk/IllegalArgumentException.java.result similarity index 55% rename from src/MapleFE/test/openjdk/IllegalArgumentException.java.result rename to src/MapleFE/test/java/openjdk/IllegalArgumentException.java.result index ab0c987eeb13c769b7c4f476ceefdba5a1adb147..4a49c834ef69e8256d44a33bc036570a35ac0077 100644 --- a/src/MapleFE/test/openjdk/IllegalArgumentException.java.result +++ b/src/MapleFE/test/java/openjdk/IllegalArgumentException.java.result @@ -1,19 +1,18 @@ Matched 5 tokens. -Matched 75 tokens. +Matched 74 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class IllegalArgumentException Fields: - serialVersionUID=Sub - -2103873468 + serialVersionUID=2103873468 Instance Initializer: Constructors: constructor IllegalArgumentException() throws: - constructor IllegalArgumentException() throws: - constructor IllegalArgumentException() throws: - constructor IllegalArgumentException() throws: + constructor IllegalArgumentException(s) throws: + constructor IllegalArgumentException(message,cause) throws: + constructor IllegalArgumentException(cause) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/IllegalMonitorStateException.java b/src/MapleFE/test/java/openjdk/IllegalMonitorStateException.java similarity index 100% rename from src/MapleFE/test/openjdk/IllegalMonitorStateException.java rename to src/MapleFE/test/java/openjdk/IllegalMonitorStateException.java diff --git a/src/MapleFE/test/openjdk/IllegalMonitorStateException.java.result b/src/MapleFE/test/java/openjdk/IllegalMonitorStateException.java.result similarity index 85% rename from src/MapleFE/test/openjdk/IllegalMonitorStateException.java.result rename to src/MapleFE/test/java/openjdk/IllegalMonitorStateException.java.result index 40ea298ea916adf631527d36b962e3c27db9b05e..95aafffda59dce3ef79436e4408a2b565d85e670 100644 --- a/src/MapleFE/test/openjdk/IllegalMonitorStateException.java.result +++ b/src/MapleFE/test/java/openjdk/IllegalMonitorStateException.java.result @@ -10,7 +10,7 @@ class IllegalMonitorStateException Instance Initializer: Constructors: constructor IllegalMonitorStateException() throws: - constructor IllegalMonitorStateException() throws: + constructor IllegalMonitorStateException(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/IllegalStateException.java b/src/MapleFE/test/java/openjdk/IllegalStateException.java similarity index 100% rename from src/MapleFE/test/openjdk/IllegalStateException.java rename to src/MapleFE/test/java/openjdk/IllegalStateException.java diff --git a/src/MapleFE/test/openjdk/IllegalStateException.java.result b/src/MapleFE/test/java/openjdk/IllegalStateException.java.result similarity index 55% rename from src/MapleFE/test/openjdk/IllegalStateException.java.result rename to src/MapleFE/test/java/openjdk/IllegalStateException.java.result index 2e476ee0c2acf14ed9bfa1399d5202d7cbc4e9fc..783d279016e888712683788de8a8642a415974ee 100644 --- a/src/MapleFE/test/openjdk/IllegalStateException.java.result +++ b/src/MapleFE/test/java/openjdk/IllegalStateException.java.result @@ -1,19 +1,18 @@ Matched 5 tokens. -Matched 74 tokens. +Matched 73 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class IllegalStateException Fields: - serialVersionUID=Sub - 1706626488 + serialVersionUID=-1706626488 Instance Initializer: Constructors: constructor IllegalStateException() throws: - constructor IllegalStateException() throws: - constructor IllegalStateException() throws: - constructor IllegalStateException() throws: + constructor IllegalStateException(s) throws: + constructor IllegalStateException(message,cause) throws: + constructor IllegalStateException(cause) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/IllegalThreadStateException.java b/src/MapleFE/test/java/openjdk/IllegalThreadStateException.java similarity index 100% rename from src/MapleFE/test/openjdk/IllegalThreadStateException.java rename to src/MapleFE/test/java/openjdk/IllegalThreadStateException.java diff --git a/src/MapleFE/test/openjdk/IllegalThreadStateException.java.result b/src/MapleFE/test/java/openjdk/IllegalThreadStateException.java.result similarity index 72% rename from src/MapleFE/test/openjdk/IllegalThreadStateException.java.result rename to src/MapleFE/test/java/openjdk/IllegalThreadStateException.java.result index e38f91928f4e02d5d561399a4f4146e84394e4c6..f6bb4fa7292cb4e106a708430caa3bd3d11b6fd6 100644 --- a/src/MapleFE/test/openjdk/IllegalThreadStateException.java.result +++ b/src/MapleFE/test/java/openjdk/IllegalThreadStateException.java.result @@ -1,17 +1,16 @@ Matched 5 tokens. -Matched 44 tokens. +Matched 43 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class IllegalThreadStateException Fields: - serialVersionUID=Sub - 944817870 + serialVersionUID=-944817870 Instance Initializer: Constructors: constructor IllegalThreadStateException() throws: - constructor IllegalThreadStateException() throws: + constructor IllegalThreadStateException(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/IncompatibleClassChangeError.java b/src/MapleFE/test/java/openjdk/IncompatibleClassChangeError.java similarity index 100% rename from src/MapleFE/test/openjdk/IncompatibleClassChangeError.java rename to src/MapleFE/test/java/openjdk/IncompatibleClassChangeError.java diff --git a/src/MapleFE/test/openjdk/IncompatibleClassChangeError.java.result b/src/MapleFE/test/java/openjdk/IncompatibleClassChangeError.java.result similarity index 72% rename from src/MapleFE/test/openjdk/IncompatibleClassChangeError.java.result rename to src/MapleFE/test/java/openjdk/IncompatibleClassChangeError.java.result index 25ca234a7efa329407ffe8986d32037f14a742c2..f60b99e0394340369de81923419ee8cf2b0be7d0 100644 --- a/src/MapleFE/test/openjdk/IncompatibleClassChangeError.java.result +++ b/src/MapleFE/test/java/openjdk/IncompatibleClassChangeError.java.result @@ -1,17 +1,16 @@ Matched 5 tokens. -Matched 44 tokens. +Matched 43 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class IncompatibleClassChangeError Fields: - serialVersionUID=Sub - 241186759 + serialVersionUID=-241186759 Instance Initializer: Constructors: constructor IncompatibleClassChangeError() throws: - constructor IncompatibleClassChangeError() throws: + constructor IncompatibleClassChangeError(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/IndexOutOfBoundsException.java b/src/MapleFE/test/java/openjdk/IndexOutOfBoundsException.java similarity index 100% rename from src/MapleFE/test/openjdk/IndexOutOfBoundsException.java rename to src/MapleFE/test/java/openjdk/IndexOutOfBoundsException.java diff --git a/src/MapleFE/test/openjdk/IndexOutOfBoundsException.java.result b/src/MapleFE/test/java/openjdk/IndexOutOfBoundsException.java.result similarity index 85% rename from src/MapleFE/test/openjdk/IndexOutOfBoundsException.java.result rename to src/MapleFE/test/java/openjdk/IndexOutOfBoundsException.java.result index a9a24df9ace72b094554679225d98135c255e81d..e6b7f17cecc4299420eacca954aea24cfafdde28 100644 --- a/src/MapleFE/test/openjdk/IndexOutOfBoundsException.java.result +++ b/src/MapleFE/test/java/openjdk/IndexOutOfBoundsException.java.result @@ -10,7 +10,7 @@ class IndexOutOfBoundsException Instance Initializer: Constructors: constructor IndexOutOfBoundsException() throws: - constructor IndexOutOfBoundsException() throws: + constructor IndexOutOfBoundsException(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/InheritableThreadLocal.java b/src/MapleFE/test/java/openjdk/InheritableThreadLocal.java similarity index 100% rename from src/MapleFE/test/openjdk/InheritableThreadLocal.java rename to src/MapleFE/test/java/openjdk/InheritableThreadLocal.java diff --git a/src/MapleFE/test/openjdk/InheritableThreadLocal.java.result b/src/MapleFE/test/java/openjdk/InheritableThreadLocal.java.result similarity index 67% rename from src/MapleFE/test/openjdk/InheritableThreadLocal.java.result rename to src/MapleFE/test/java/openjdk/InheritableThreadLocal.java.result index 0b33682f73eef1c10daa3f17b985c1ae414280df..bc6d651cb6cdcaf8b1e8026f564c4f67cb7a9bf4 100644 --- a/src/MapleFE/test/openjdk/InheritableThreadLocal.java.result +++ b/src/MapleFE/test/java/openjdk/InheritableThreadLocal.java.result @@ -13,12 +13,12 @@ class InheritableThreadLocal Instance Initializer: Constructors: Methods: - func childValue() throws: + func childValue(parentValue) throws: return parentValue - func getMap() throws: + func getMap(t) throws: return t.inheritableThreadLocals - func createMap() throws: - t.inheritableThreadLocals Assign new ThreadLocalMap + func createMap(t,firstValue) throws: + t.inheritableThreadLocals Assign new ThreadLocalMap(this,firstValue) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/InstantiationError.java b/src/MapleFE/test/java/openjdk/InstantiationError.java similarity index 100% rename from src/MapleFE/test/openjdk/InstantiationError.java rename to src/MapleFE/test/java/openjdk/InstantiationError.java diff --git a/src/MapleFE/test/openjdk/InstantiationError.java.result b/src/MapleFE/test/java/openjdk/InstantiationError.java.result similarity index 72% rename from src/MapleFE/test/openjdk/InstantiationError.java.result rename to src/MapleFE/test/java/openjdk/InstantiationError.java.result index f0d4db7ccc4b17645252db9359af8d444201ecf3..7964f147d622897c77e3113656d4a2a0d65d86be 100644 --- a/src/MapleFE/test/openjdk/InstantiationError.java.result +++ b/src/MapleFE/test/java/openjdk/InstantiationError.java.result @@ -1,17 +1,16 @@ Matched 5 tokens. -Matched 44 tokens. +Matched 43 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class InstantiationError Fields: - serialVersionUID=Sub - 522274964 + serialVersionUID=-522274964 Instance Initializer: Constructors: constructor InstantiationError() throws: - constructor InstantiationError() throws: + constructor InstantiationError(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/InstantiationException.java b/src/MapleFE/test/java/openjdk/InstantiationException.java similarity index 100% rename from src/MapleFE/test/openjdk/InstantiationException.java rename to src/MapleFE/test/java/openjdk/InstantiationException.java diff --git a/src/MapleFE/test/openjdk/InstantiationException.java.result b/src/MapleFE/test/java/openjdk/InstantiationException.java.result similarity index 72% rename from src/MapleFE/test/openjdk/InstantiationException.java.result rename to src/MapleFE/test/java/openjdk/InstantiationException.java.result index 318389f21526ffc3a14de3431ebfe07c80245d46..88f6bce0e263177027356f7d18a53bfcb6822430 100644 --- a/src/MapleFE/test/openjdk/InstantiationException.java.result +++ b/src/MapleFE/test/java/openjdk/InstantiationException.java.result @@ -1,17 +1,16 @@ Matched 5 tokens. -Matched 44 tokens. +Matched 43 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class InstantiationException Fields: - serialVersionUID=Sub - -1305838986 + serialVersionUID=1305838986 Instance Initializer: Constructors: constructor InstantiationException() throws: - constructor InstantiationException() throws: + constructor InstantiationException(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/Integer.java b/src/MapleFE/test/java/openjdk/Integer.java similarity index 100% rename from src/MapleFE/test/openjdk/Integer.java rename to src/MapleFE/test/java/openjdk/Integer.java diff --git a/src/MapleFE/test/openjdk/Integer.java.result b/src/MapleFE/test/java/openjdk/Integer.java.result similarity index 47% rename from src/MapleFE/test/openjdk/Integer.java.result rename to src/MapleFE/test/java/openjdk/Integer.java.result index 99b7f591bf6b48af36ed1562f11c662a67264f8b..a5effda89d9f5254c3e76dd7ecc9f00f776e0f64 100644 --- a/src/MapleFE/test/openjdk/Integer.java.result +++ b/src/MapleFE/test/java/openjdk/Integer.java.result @@ -1,8 +1,6 @@ Matched 5 tokens. Matched 14 tokens. -Matched 3758 tokens. -Convert unary --> binary -Convert unary --> binary +Matched 3756 tokens. ============= Module =========== == Sub Tree == package java.lang @@ -11,103 +9,123 @@ import java.lang.annotation.Native == Sub Tree == class Integer Fields: - MIN_VALUE=-2147483648 MAX_VALUE=2147483647 TYPE=() digits= SMALL_NEG_VALUES= SMALL_NONNEG_VALUES= DigitTens= DigitOnes= sizeTable= value SIZE=32 BYTES= serialVersionUID=-142506184 + MIN_VALUE=-2147483648 MAX_VALUE=2147483647 TYPE=()int.getComponentType() digits= SMALL_NEG_VALUES= SMALL_NONNEG_VALUES= DigitTens= DigitOnes= sizeTable= value SIZE=32 BYTES=SIZE Div Byte.SIZE serialVersionUID=-142506184 Instance Initializer: Constructors: - constructor Integer() throws: + constructor Integer(value) throws: this.value Assign value - constructor Integer() throws: + constructor Integer(s) throws: this.value Assign parseInt(s,10) Methods: - func toString() throws: + func toString(i,radix) throws: cond-branch cond:radix LT Character.MIN_RADIX Lor radix GT Character.MAX_RADIX true branch : - radix Assign 10 - false branch : + radix Assign 10 false branch : cond-branch cond:radix EQ 10 true branch : return toString(i) false branch : - var:buf=[] - var:negative=(i LT 0) - var:charPos=32 + Decl: buf=[] + Decl: negative=(i LT 0) + Decl: charPos=32 cond-branch cond:negative true branch : - i Assign Sub - i + i Assign Minus i false branch : - while i LE Sub - radix Assign digits Sub () - i Assign + while i LE Minus radix Assign + i Assign i Div radix - Assign digits Sub i + Assign cond-branch cond:negative true branch : Assign - false branch : - return new String - func toUnsignedString() throws: + return new String(buf,charPos,(33 Sub charPos)) + func toUnsignedString(i,radix) throws: return Long.toUnsignedString(toUnsignedLong(i),radix) - func toHexString() throws: + func toHexString(i) throws: return toUnsignedString0(i,4) - func toOctalString() throws: + func toOctalString(i) throws: return toUnsignedString0(i,3) - func toBinaryString() throws: + func toBinaryString(i) throws: return toUnsignedString0(i,1) - func toUnsignedString0() throws: - var:mag=Integer.SIZE Sub Integer.numberOfLeadingZeros(val) - var:chars=Math.max(((mag Add (shift Sub 1))shift)1) - var:buf= + func toUnsignedString0(val,shift) throws: + Decl: mag=Integer.SIZE Sub Integer.numberOfLeadingZeros(val) + Decl: chars=Math.max(((mag Add (shift Sub 1)) Div shift)1) + Decl: buf= formatUnsignedInt(val,shift,buf,0,chars) - return new String - func formatUnsignedInt() throws: - var:charPos=len - var:radix=1 Shl shift - var:mask=radix Sub 1 + return new String(buf) + func formatUnsignedInt(val,shift,buf,offset,len) throws: + Decl: charPos=len + Decl: radix=1 Shl shift + Decl: mask=radix Sub 1 do Assign val ZextAssign shift while val NE 0 Land charPos GT 0 return charPos - func toString() throws: + func toString(i) throws: cond-branch cond:i EQ Integer.MIN_VALUE true branch : - return "-2147483648" - false branch : + return "-2147483648" false branch : - var:negative=i LT 0 - var:small= + Decl: negative=i LT 0 + Decl: small= cond-branch cond:small true branch : - var:smallValues= + Decl: smallValues= + cond-branch cond:negative + true branch : + i Assign Minus i + cond-branch cond: EQ null + true branch : + Assign + false branch : + false branch : + cond-branch cond: EQ null + true branch : + Assign + false branch : + + + return false branch : - var:size= - var:buf= + Decl: size= + Decl: buf= getChars(i,size,buf) - return new String - func toUnsignedString() throws: + return new String(buf) + func toUnsignedString(i) throws: return Long.toString(toUnsignedLong(i)) - func getChars() throws: - var:q,r - var:charPos=index - var:sign=0 + func getChars(i,index,buf) throws: + Decl: q,r + Decl: charPos=index + Decl: sign=0 cond-branch cond:i LT 0 true branch : sign Assign - - i Assign Sub - i + i Assign Minus i false branch : - while i GE 65536 q Assign - + while i GE 65536 q Assign i Div 100 + r Assign i Sub ((q Shl 6) Add (q Shl 5) Add (q Shl 2)) + i Assign q + Assign + Assign for ( ) - q Assign () Zext (16 Add 3) + q Assign (i Mul 52429) Zext (16 Add 3) + r Assign i Sub ((q Shl 3) Add (q Shl 1)) + Assign + i Assign q + cond-branch cond:i EQ 0 + true branch : + break: + false branch : cond-branch cond:sign NE 0 @@ -115,90 +133,125 @@ while val NE 0 Land charPos GT 0 Assign sign false branch : - func stringSize() throws: + func stringSize(x) throws: for ( ) cond-branch cond:x LE true branch : - return i Add 1 - false branch : - + return i Add 1 false branch : - func parseInt() throws: NumberFormatException + func parseInt(s,radix) throws: NumberFormatException cond-branch cond:s EQ null true branch : - new NumberFormatException + new NumberFormatException("s == null") false branch : cond-branch cond:radix LT Character.MIN_RADIX true branch : - new NumberFormatException + new NumberFormatException("radix " Add radix Add " less than Character.MIN_RADIX") false branch : cond-branch cond:radix GT Character.MAX_RADIX true branch : - new NumberFormatException + new NumberFormatException("radix " Add radix Add " greater than Character.MAX_RADIX") false branch : - var:result=0 - var:negative=false - var:i=0,len=s.length() - var:limit=Sub - Integer.MAX_VALUE - var:multmin - var:digit + Decl: result=0 + Decl: negative=false + Decl: i=0,len=s.length() + Decl: limit=Minus Integer.MAX_VALUE + Decl: multmin + Decl: digit cond-branch cond:len GT 0 true branch : - var:firstChar=s.charAt(0) + Decl: firstChar=s.charAt(0) + cond-branch cond:firstChar LT 0 + true branch : + cond-branch cond:firstChar EQ - + true branch : + negative Assign true + limit Assign Integer.MIN_VALUE + false branch : + cond-branch cond:firstChar NE + + true branch : + NumberFormatException.forInputString(s) false branch : + + cond-branch cond:len EQ 1 + true branch : + NumberFormatException.forInputString(s) false branch : + + i Inc + + false branch : + + multmin Assign limit Div radix + while i LT len digit Assign Character.digit(s.charAt(i Inc +),radix) + cond-branch cond:digit LT 0 + true branch : + NumberFormatException.forInputString(s) + false branch : + + cond-branch cond:result LT multmin + true branch : + NumberFormatException.forInputString(s) + false branch : + + result MulAssign radix + cond-branch cond:result LT limit Add digit + true branch : + NumberFormatException.forInputString(s) + false branch : + + result SubAssign digit false branch : NumberFormatException.forInputString(s) return - func parseInt() throws: NumberFormatException + func parseInt(s) throws: NumberFormatException return parseInt(s,10) - func parseUnsignedInt() throws: NumberFormatException + func parseUnsignedInt(s,radix) throws: NumberFormatException cond-branch cond:s EQ null true branch : - new NumberFormatException + new NumberFormatException("null") false branch : - var:len=s.length() + Decl: len=s.length() cond-branch cond:len GT 0 true branch : - var:firstChar=s.charAt(0) + Decl: firstChar=s.charAt(0) cond-branch cond:firstChar EQ - true branch : - new NumberFormatException + new NumberFormatException(String.format("Illegal leading minus sign " Add "on unsigned string %s.",s)) false branch : cond-branch cond:len LE 5 Lor (radix EQ 10 Land len LE 9) true branch : return parseInt(s,radix) false branch : - var:ell=Long.parseLong(s,radix) + Decl: ell=Long.parseLong(s,radix) cond-branch cond:(ell Band 0) EQ 0 true branch : return (int)ell false branch : - new NumberFormatException + new NumberFormatException(String.format("String value %s exceeds " Add "range of unsigned int.",s)) false branch : NumberFormatException.forInputString(s) - func parseUnsignedInt() throws: NumberFormatException + func parseUnsignedInt(s) throws: NumberFormatException return parseUnsignedInt(s,10) - func valueOf() throws: NumberFormatException + func valueOf(s,radix) throws: NumberFormatException return Integer.valueOf(parseInt(s,radix)) - func valueOf() throws: NumberFormatException + func valueOf(s) throws: NumberFormatException return Integer.valueOf(parseInt(s,10)) - func valueOf() throws: + func valueOf(i) throws: cond-branch cond:i GE IntegerCache.low Land i LE IntegerCache.high true branch : - return - false branch : + return false branch : - return new Integer + return new Integer(i) func byteValue() throws: return (byte)value func shortValue() throws: @@ -215,57 +268,59 @@ while val NE 0 Land charPos GT 0 return toString(value) func hashCode() throws: return Integer.hashCode(value) - func hashCode() throws: + func hashCode(value) throws: return value - func equals() throws: - cond-branch cond: + func equals(obj) throws: + cond-branch cond:obj instanceof Integer true branch : - return value EQ ((Integer)obj)intValue + return value EQ (Integer)obj.intValue() false branch : return false - func getInteger() throws: + func getInteger(nm) throws: return getInteger(nm,null) - func getInteger() throws: - var:result=getInteger(nm,null) + func getInteger(nm,val) throws: + Decl: result=getInteger(nm,null) return - func getInteger() throws: - var:v=null + func getInteger(nm,val) throws: + Decl: v=null v Assign System.getProperty(nm) + IllegalArgumentException + NullPointerException + e cond-branch cond:v NE null true branch : return Integer.decode(v) + NumberFormatException + e false branch : return val - func decode() throws: NumberFormatException - var:radix=10 - var:index=0 - var:negative=false - var:result + func decode(nm) throws: NumberFormatException + Decl: radix=10 + Decl: index=0 + Decl: negative=false + Decl: result cond-branch cond:nm.length() EQ 0 true branch : - new NumberFormatException - false branch : + new NumberFormatException("Zero length string") false branch : - var:firstChar=nm.charAt(0) + Decl: firstChar=nm.charAt(0) cond-branch cond:firstChar EQ - true branch : negative Assign true - indexInc + index Inc false branch : cond-branch cond:firstChar EQ + true branch : - indexInc - + index Inc false branch : - cond-branch cond:nm.startsWith("0x",index) Lor nm.startsWith("0X",index) true branch : index AddAssign 2 @@ -273,55 +328,57 @@ while val NE 0 Land charPos GT 0 false branch : cond-branch cond:nm.startsWith("#",index) true branch : - indexInc + index Inc radix Assign 16 false branch : cond-branch cond:nm.startsWith("0",index) Land nm.length() GT 1 Add index true branch : - indexInc + index Inc radix Assign 8 false branch : - - cond-branch cond:nm.startsWith("-",index) Lor nm.startsWith("+",index) true branch : - new NumberFormatException - false branch : + new NumberFormatException("Sign character in wrong position") false branch : + result Assign Integer.valueOf(nm.substring(index),radix) + result Assign + + NumberFormatException + e + Decl: constant= + result Assign Integer.valueOf(constant,radix) return result - func compareTo() throws: + func compareTo(anotherInteger) throws: return compare(this.value,anotherInteger.value) - func compare() throws: + func compare(x,y) throws: return - func compareUnsigned() throws: + func compareUnsigned(x,y) throws: return compare(x Add MIN_VALUE,y Add MIN_VALUE) - func toUnsignedLong() throws: + func toUnsignedLong(x) throws: return ((long)x) Band -1 - func divideUnsigned() throws: - return (int)() - func remainderUnsigned() throws: - return (int)() - func highestOneBit() throws: + func divideUnsigned(dividend,divisor) throws: + return (int)(toUnsignedLong(dividend) Div toUnsignedLong(divisor)) + func remainderUnsigned(dividend,divisor) throws: + return (int)(toUnsignedLong(dividend) Mod toUnsignedLong(divisor)) + func highestOneBit(i) throws: i BorAssign (i Shr 1) i BorAssign (i Shr 2) i BorAssign (i Shr 4) i BorAssign (i Shr 8) i BorAssign (i Shr 16) return i Sub (i Zext 1) - func lowestOneBit() throws: - return i Band Sub - i - func numberOfLeadingZeros() throws: + func lowestOneBit(i) throws: + return i Band Minus i + func numberOfLeadingZeros(i) throws: cond-branch cond:i EQ 0 true branch : - return 32 - false branch : + return 32 false branch : - var:n=1 + Decl: n=1 cond-branch cond:i Zext 16 EQ 0 true branch : n AddAssign 16 @@ -348,14 +405,13 @@ while val NE 0 Land charPos GT 0 n SubAssign i Zext 31 return n - func numberOfTrailingZeros() throws: - var:y + func numberOfTrailingZeros(i) throws: + Decl: y cond-branch cond:i EQ 0 true branch : - return 32 - false branch : + return 32 false branch : - var:n=31 + Decl: n=31 y Assign i Shl 16 cond-branch cond:y NE 0 true branch : @@ -385,41 +441,37 @@ while val NE 0 Land charPos GT 0 false branch : return n Sub ((i Shl 1) Zext 31) - func bitCount() throws: + func bitCount(i) throws: i Assign i Sub ((i Zext 1) Band 1431655765) i Assign (i Band 858993459) Add ((i Zext 2) Band 858993459) i Assign (i Add (i Zext 4)) Band 252645135 i Assign i Add (i Zext 8) i Assign i Add (i Zext 16) return i Band 63 - func rotateLeft() throws: - return (i Shl distance) Bor (i Zext Sub - distance) - func rotateRight() throws: - return (i Zext distance) Bor (i Shl Sub - distance) - func reverse() throws: + func rotateLeft(i,distance) throws: + return (i Shl distance) Bor (i Zext Minus distance) + func rotateRight(i,distance) throws: + return (i Zext distance) Bor (i Shl Minus distance) + func reverse(i) throws: i Assign (i Band 1431655765) Shl 1 Bor (i Zext 1) Band 1431655765 i Assign (i Band 858993459) Shl 2 Bor (i Zext 2) Band 858993459 i Assign (i Band 252645135) Shl 4 Bor (i Zext 4) Band 252645135 i Assign (i Shl 24) Bor ((i Band 65280) Shl 8) Bor ((i Zext 8) Band 65280) Bor (i Zext 24) return i - func signum() throws: - return (i Shr 31) Bor (Sub - i Zext 31) - func reverseBytes() throws: + func signum(i) throws: + return (i Shr 31) Bor (Minus i Zext 31) + func reverseBytes(i) throws: return ((i Zext 24)) Bor ((i Shr 8) Band 65280) Bor ((i Shl 8) Band 16711680) Bor ((i Shl 24)) - func sum() throws: + func sum(a,b) throws: return a Add b - func max() throws: + func max(a,b) throws: return Math.max(a,b) - func min() throws: + func min(a,b) throws: return Math.min(a,b) LocalClasses: class IntegerCache Fields: - low=Sub - 128 high cache[] + low=-128 high cache[] Instance Initializer: InstInit- 0 Constructors: @@ -429,3 +481,17 @@ while val NE 0 Land charPos GT 0 LocalInterfaces: LocalInterfaces: +Identifier:v has no decl. +Identifier:IllegalArgumentException has no decl. +Identifier:NullPointerException has no decl. +Identifier:e has no decl. +Identifier:result has no decl. +Identifier:result has no decl. +Identifier:NumberFormatException has no decl. +Identifier:e has no decl. +Identifier:result has no decl. +Identifier:n has no decl. +Identifier:y has no decl. +Identifier:y has no decl. +Identifier:y has no decl. +Identifier:y has no decl. diff --git a/src/MapleFE/test/openjdk/InternalError.java b/src/MapleFE/test/java/openjdk/InternalError.java similarity index 100% rename from src/MapleFE/test/openjdk/InternalError.java rename to src/MapleFE/test/java/openjdk/InternalError.java diff --git a/src/MapleFE/test/openjdk/InternalError.java.result b/src/MapleFE/test/java/openjdk/InternalError.java.result similarity index 56% rename from src/MapleFE/test/openjdk/InternalError.java.result rename to src/MapleFE/test/java/openjdk/InternalError.java.result index aa5aa18b05260e49ae3bd60fbf7b7c82c21a1211..52e5fe44bddeaf366d900e102b77ce79752153bf 100644 --- a/src/MapleFE/test/openjdk/InternalError.java.result +++ b/src/MapleFE/test/java/openjdk/InternalError.java.result @@ -1,19 +1,18 @@ Matched 5 tokens. -Matched 75 tokens. +Matched 74 tokens. ============= Module =========== == Sub Tree == package java.lang == Sub Tree == class InternalError Fields: - serialVersionUID=Sub - 1073036797 + serialVersionUID=-1073036797 Instance Initializer: Constructors: constructor InternalError() throws: - constructor InternalError() throws: - constructor InternalError() throws: - constructor InternalError() throws: + constructor InternalError(message) throws: + constructor InternalError(message,cause) throws: + constructor InternalError(cause) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/InterruptedException.java b/src/MapleFE/test/java/openjdk/InterruptedException.java similarity index 100% rename from src/MapleFE/test/openjdk/InterruptedException.java rename to src/MapleFE/test/java/openjdk/InterruptedException.java diff --git a/src/MapleFE/test/openjdk/InterruptedException.java.result b/src/MapleFE/test/java/openjdk/InterruptedException.java.result similarity index 86% rename from src/MapleFE/test/openjdk/InterruptedException.java.result rename to src/MapleFE/test/java/openjdk/InterruptedException.java.result index bc6668075dd302f708c1d2663feb797dd1dae816..4b5a4410f404b13956d2eb630afa274728926e7a 100644 --- a/src/MapleFE/test/openjdk/InterruptedException.java.result +++ b/src/MapleFE/test/java/openjdk/InterruptedException.java.result @@ -10,7 +10,7 @@ class InterruptedException Instance Initializer: Constructors: constructor InterruptedException() throws: - constructor InterruptedException() throws: + constructor InterruptedException(s) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/Iterable.java b/src/MapleFE/test/java/openjdk/Iterable.java similarity index 100% rename from src/MapleFE/test/openjdk/Iterable.java rename to src/MapleFE/test/java/openjdk/Iterable.java diff --git a/src/MapleFE/test/openjdk/Iterable.java.result b/src/MapleFE/test/java/openjdk/Iterable.java.result similarity index 95% rename from src/MapleFE/test/openjdk/Iterable.java.result rename to src/MapleFE/test/java/openjdk/Iterable.java.result index 712993fa4593bdbc490a20d453e69e13494d2fe8..79077a8567f50708cb59801ee147234b37165d22 100644 --- a/src/MapleFE/test/openjdk/Iterable.java.result +++ b/src/MapleFE/test/java/openjdk/Iterable.java.result @@ -24,7 +24,7 @@ interface Iterable Methods: func iterator() throws: - func forEach() throws: + func forEach(action) throws: Objects.requireNonNull(action) T t diff --git a/src/MapleFE/test/openjdk/JavaLangAccess.java b/src/MapleFE/test/java/openjdk/JavaLangAccess.java similarity index 100% rename from src/MapleFE/test/openjdk/JavaLangAccess.java rename to src/MapleFE/test/java/openjdk/JavaLangAccess.java diff --git a/src/MapleFE/test/openjdk/JavaLangAccess.java.result b/src/MapleFE/test/java/openjdk/JavaLangAccess.java.result similarity index 86% rename from src/MapleFE/test/openjdk/JavaLangAccess.java.result rename to src/MapleFE/test/java/openjdk/JavaLangAccess.java.result index 48ac6364014e58a1577560ba18036244a7e84c6e..df7b84bd64b7f464a202153cc11ab302c5b79a28 100644 --- a/src/MapleFE/test/openjdk/JavaLangAccess.java.result +++ b/src/MapleFE/test/java/openjdk/JavaLangAccess.java.result @@ -11,7 +11,7 @@ class JavaLangAccess Constructors: constructor JavaLangAccess() throws: Methods: - func getEnumConstantsShared() throws: + func getEnumConstantsShared(klass) throws: return klass.getEnumConstantsShared() LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/LinkageError.java b/src/MapleFE/test/java/openjdk/LinkageError.java similarity index 100% rename from src/MapleFE/test/openjdk/LinkageError.java rename to src/MapleFE/test/java/openjdk/LinkageError.java diff --git a/src/MapleFE/test/openjdk/LinkageError.java.result b/src/MapleFE/test/java/openjdk/LinkageError.java.result similarity index 77% rename from src/MapleFE/test/openjdk/LinkageError.java.result rename to src/MapleFE/test/java/openjdk/LinkageError.java.result index b6b70d10cc091620ed09dba39f5ee9c613776f18..25e4a97982edf6748707966b4502f0e63b60f305 100644 --- a/src/MapleFE/test/openjdk/LinkageError.java.result +++ b/src/MapleFE/test/java/openjdk/LinkageError.java.result @@ -10,8 +10,8 @@ class LinkageError Instance Initializer: Constructors: constructor LinkageError() throws: - constructor LinkageError() throws: - constructor LinkageError() throws: + constructor LinkageError(s) throws: + constructor LinkageError(s,cause) throws: Methods: LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/openjdk/Long.java b/src/MapleFE/test/java/openjdk/Long.java similarity index 100% rename from src/MapleFE/test/openjdk/Long.java rename to src/MapleFE/test/java/openjdk/Long.java diff --git a/src/MapleFE/test/openjdk/Long.java.result b/src/MapleFE/test/java/openjdk/Long.java.result similarity index 47% rename from src/MapleFE/test/openjdk/Long.java.result rename to src/MapleFE/test/java/openjdk/Long.java.result index bfd8e31deed5cc374eed04142ec59f642f62aef4..883f0af4538bc7c6061d3d85e876a8a0d797c913 100644 --- a/src/MapleFE/test/openjdk/Long.java.result +++ b/src/MapleFE/test/java/openjdk/Long.java.result @@ -1,7 +1,7 @@ Matched 5 tokens. Matched 14 tokens. Matched 21 tokens. -Matched 3482 tokens. +Matched 3480 tokens. ============= Module =========== == Sub Tree == package java.lang @@ -12,37 +12,33 @@ import java.math == Sub Tree == class Long Fields: - MIN_VALUE=0 MAX_VALUE=-1 TYPE=() value SIZE=64 BYTES= serialVersionUID=-863034401 + MIN_VALUE=0 MAX_VALUE=-1 TYPE=()long.getComponentType() value SIZE=64 BYTES=SIZE Div Byte.SIZE serialVersionUID=-863034401 Instance Initializer: Constructors: - constructor Long() throws: + constructor Long(value) throws: this.value Assign value - constructor Long() throws: + constructor Long(s) throws: this.value Assign parseLong(s,10) Methods: - func toString() throws: + func toString(i,radix) throws: cond-branch cond:radix LT Character.MIN_RADIX Lor radix GT Character.MAX_RADIX true branch : - radix Assign 10 - false branch : + radix Assign 10 false branch : cond-branch cond:radix EQ 10 true branch : - return toString(i) - false branch : + return toString(i) false branch : - var:buf= - var:charPos=64 - var:negative=(i LT 0) + Decl: buf= + Decl: charPos=64 + Decl: negative=(i LT 0) cond-branch cond:negative true branch : - i Assign Sub - i + i Assign Minus i false branch : - while i LE Sub - radix Assign - i Assign + while i LE Minus radix Assign + i Assign i Div radix Assign cond-branch cond:negative @@ -50,77 +46,87 @@ class Long Assign - false branch : - return new String - func toUnsignedString() throws: + return new String(buf,charPos,(65 Sub charPos)) + func toUnsignedString(i,radix) throws: cond-branch cond:i GE 0 true branch : - return toString(i,radix) - false branch : + return toString(i,radix) false branch : A switch - func toUnsignedBigInteger() throws: + func toUnsignedBigInteger(i) throws: cond-branch cond:i GE 0 true branch : - return BigInteger.valueOf(i) - false branch : - var:upper=(int)(i Zext 32) - + return BigInteger.valueOf(i) false branch : + Decl: upper=(int)(i Zext 32) + Decl: lower=(int)i + return BigInteger.valueOf(Integer.toUnsignedLong(upper)).shiftLeft(32).add(BigInteger.valueOf(Integer.toUnsignedLong(lower))) - func toHexString() throws: + func toHexString(i) throws: return toUnsignedString0(i,4) - func toOctalString() throws: + func toOctalString(i) throws: return toUnsignedString0(i,3) - func toBinaryString() throws: + func toBinaryString(i) throws: return toUnsignedString0(i,1) - func toUnsignedString0() throws: - var:mag=Long.SIZE Sub Long.numberOfLeadingZeros(val) - var:chars=Math.max(((mag Add (shift Sub 1))shift)1) - var:buf= + func toUnsignedString0(val,shift) throws: + Decl: mag=Long.SIZE Sub Long.numberOfLeadingZeros(val) + Decl: chars=Math.max(((mag Add (shift Sub 1)) Div shift)1) + Decl: buf= formatUnsignedLong(val,shift,buf,0,chars) - return new String - func formatUnsignedLong() throws: - var:charPos=len - var:radix=1 Shl shift - var:mask=radix Sub 1 + return new String(buf) + func formatUnsignedLong(val,shift,buf,offset,len) throws: + Decl: charPos=len + Decl: radix=1 Shl shift + Decl: mask=radix Sub 1 do Assign val ZextAssign shift while val NE 0 Land charPos GT 0 return charPos - func toString() throws: + func toString(i) throws: cond-branch cond:i EQ Long.MIN_VALUE true branch : - return "-9223372036854775808" - false branch : + return "-9223372036854775808" false branch : - var:size= - var:buf= + Decl: size= + Decl: buf= getChars(i,size,buf) - return new String - func toUnsignedString() throws: + return new String(buf) + func toUnsignedString(i) throws: return toUnsignedString(i,10) - func getChars() throws: - var:q - var:r - var:charPos=index - var:sign=0 + func getChars(i,index,buf) throws: + Decl: q + Decl: r + Decl: charPos=index + Decl: sign=0 cond-branch cond:i LT 0 true branch : sign Assign - - i Assign Sub - i + i Assign Minus i false branch : - while i GT Integer.MAX_VALUE q Assign - - - var:q2 - var:i2=(int)i - while i2 GE 65536 q2 Assign + while i GT Integer.MAX_VALUE q Assign i Div 100 + r Assign (int)(i Sub ((q Shl 6) Add (q Shl 5) Add (q Shl 2))) + i Assign q + Assign + Assign + Decl: q2 + Decl: i2=(int)i + while i2 GE 65536 q2 Assign i2 Div 100 + r Assign i2 Sub ((q2 Shl 6) Add (q2 Shl 5) Add (q2 Shl 2)) + i2 Assign q2 + Assign + Assign for ( ) - q2 Assign () Zext (16 Add 3) + q2 Assign (i2 Mul 52429) Zext (16 Add 3) + r Assign i2 Sub ((q2 Shl 3) Add (q2 Shl 1)) + Assign + i2 Assign q2 + cond-branch cond:i2 EQ 0 + true branch : + break: + false branch : cond-branch cond:sign NE 0 @@ -128,113 +134,159 @@ while val NE 0 Land charPos GT 0 Assign sign false branch : - func stringSize() throws: - var:p=10 + func stringSize(x) throws: + Decl: p=10 for ( ) cond-branch cond:x LT p true branch : - return i - false branch : + return i false branch : - p Assign + p Assign 10 Mul p return 19 - func parseLong() throws: NumberFormatException + func parseLong(s,radix) throws: NumberFormatException cond-branch cond:s EQ null true branch : - new NumberFormatException + new NumberFormatException("null") false branch : cond-branch cond:radix LT Character.MIN_RADIX true branch : - new NumberFormatException + new NumberFormatException("radix " Add radix Add " less than Character.MIN_RADIX") false branch : cond-branch cond:radix GT Character.MAX_RADIX true branch : - new NumberFormatException + new NumberFormatException("radix " Add radix Add " greater than Character.MAX_RADIX") false branch : - var:result=0 - var:negative=false - var:i=0,len=s.length() - var:limit=Sub - Long.MAX_VALUE - var:multmin - var:digit + Decl: result=0 + Decl: negative=false + Decl: i=0,len=s.length() + Decl: limit=Minus Long.MAX_VALUE + Decl: multmin + Decl: digit cond-branch cond:len GT 0 true branch : - var:firstChar=s.charAt(0) + Decl: firstChar=s.charAt(0) + cond-branch cond:firstChar LT 0 + true branch : + cond-branch cond:firstChar EQ - + true branch : + negative Assign true + limit Assign Long.MIN_VALUE + false branch : + cond-branch cond:firstChar NE + + true branch : + NumberFormatException.forInputString(s) false branch : + + cond-branch cond:len EQ 1 + true branch : + NumberFormatException.forInputString(s) false branch : + + i Inc + + false branch : + + multmin Assign limit Div radix + while i LT len digit Assign Character.digit(s.charAt(i Inc +),radix) + cond-branch cond:digit LT 0 + true branch : + NumberFormatException.forInputString(s) + false branch : + + cond-branch cond:result LT multmin + true branch : + NumberFormatException.forInputString(s) + false branch : + + result MulAssign radix + cond-branch cond:result LT limit Add digit + true branch : + NumberFormatException.forInputString(s) + false branch : + + result SubAssign digit false branch : NumberFormatException.forInputString(s) return - func parseLong() throws: NumberFormatException + func parseLong(s) throws: NumberFormatException return parseLong(s,10) - func parseUnsignedLong() throws: NumberFormatException + func parseUnsignedLong(s,radix) throws: NumberFormatException cond-branch cond:s EQ null true branch : - new NumberFormatException + new NumberFormatException("null") false branch : - var:len=s.length() + Decl: len=s.length() cond-branch cond:len GT 0 true branch : - var:firstChar=s.charAt(0) + Decl: firstChar=s.charAt(0) cond-branch cond:firstChar EQ - true branch : - new NumberFormatException + new NumberFormatException(String.format("Illegal leading minus sign " Add "on unsigned string %s.",s)) false branch : cond-branch cond:len LE 12 Lor (radix EQ 10 Land len LE 18) true branch : return parseLong(s,radix) false branch : + Decl: first=parseLong(s.substring(0,len Sub 1),radix) + Decl: second=Character.digit(s.charAt(len Sub 1),radix) + cond-branch cond:second LT 0 + true branch : + new NumberFormatException("Bad digit at end of " Add s) + false branch : + Decl: result=first Mul radix Add second + cond-branch cond:compareUnsigned(result,first) LT 0 + true branch : + new NumberFormatException(String.format("String value %s exceeds " Add "range of unsigned long.",s)) + false branch : + + return result false branch : NumberFormatException.forInputString(s) - func parseUnsignedLong() throws: NumberFormatException + func parseUnsignedLong(s) throws: NumberFormatException return parseUnsignedLong(s,10) - func valueOf() throws: NumberFormatException + func valueOf(s,radix) throws: NumberFormatException return Long.valueOf(parseLong(s,radix)) - func valueOf() throws: NumberFormatException + func valueOf(s) throws: NumberFormatException return Long.valueOf(parseLong(s,10)) - func valueOf() throws: - var:offset=128 - cond-branch cond:l GE Sub - 128 Land l LE 127 + func valueOf(l) throws: + Decl: offset=128 + cond-branch cond:l GE -128 Land l LE 127 true branch : return false branch : - return new Long - func decode() throws: NumberFormatException - var:radix=10 - var:index=0 - var:negative=false - var:result + return new Long(l) + func decode(nm) throws: NumberFormatException + Decl: radix=10 + Decl: index=0 + Decl: negative=false + Decl: result cond-branch cond:nm.length() EQ 0 true branch : - new NumberFormatException - false branch : + new NumberFormatException("Zero length string") false branch : - var:firstChar=nm.charAt(0) + Decl: firstChar=nm.charAt(0) cond-branch cond:firstChar EQ - true branch : negative Assign true - indexInc + index Inc false branch : cond-branch cond:firstChar EQ + true branch : - indexInc - + index Inc false branch : - cond-branch cond:nm.startsWith("0x",index) Lor nm.startsWith("0X",index) true branch : index AddAssign 2 @@ -242,24 +294,28 @@ while val NE 0 Land charPos GT 0 false branch : cond-branch cond:nm.startsWith("#",index) true branch : - indexInc + index Inc radix Assign 16 false branch : cond-branch cond:nm.startsWith("0",index) Land nm.length() GT 1 Add index true branch : - indexInc + index Inc radix Assign 8 false branch : - - cond-branch cond:nm.startsWith("-",index) Lor nm.startsWith("+",index) true branch : - new NumberFormatException - false branch : + new NumberFormatException("Sign character in wrong position") false branch : + result Assign Long.valueOf(nm.substring(index),radix) + result Assign + + NumberFormatException + e + Decl: constant= + result Assign Long.valueOf(constant,radix) return result func byteValue() throws: @@ -278,40 +334,45 @@ while val NE 0 Land charPos GT 0 return toString(value) func hashCode() throws: return Long.hashCode(value) - func hashCode() throws: + func hashCode(value) throws: return (int)(value Bxor (value Zext 32)) - func equals() throws: - cond-branch cond: + func equals(obj) throws: + cond-branch cond:obj instanceof Long true branch : - return value EQ ((Long)obj)longValue + return value EQ (Long)obj.longValue() false branch : return false - func getLong() throws: + func getLong(nm) throws: return getLong(nm,null) - func getLong() throws: - var:result=Long.getLong(nm,null) + func getLong(nm,val) throws: + Decl: result=Long.getLong(nm,null) return - func getLong() throws: - var:v=null + func getLong(nm,val) throws: + Decl: v=null v Assign System.getProperty(nm) + IllegalArgumentException + NullPointerException + e cond-branch cond:v NE null true branch : return Long.decode(v) + NumberFormatException + e false branch : return val - func compareTo() throws: + func compareTo(anotherLong) throws: return compare(this.value,anotherLong.value) - func compare() throws: + func compare(x,y) throws: return - func compareUnsigned() throws: + func compareUnsigned(x,y) throws: return compare(x Add MIN_VALUE,y Add MIN_VALUE) - func divideUnsigned() throws: + func divideUnsigned(dividend,divisor) throws: cond-branch cond:divisor LT 0 true branch : return @@ -319,23 +380,20 @@ while val NE 0 Land charPos GT 0 cond-branch cond:dividend GT 0 true branch : - return - false branch : - return + return dividend Div divisor false branch : + return toUnsignedBigInteger(dividend).divide(toUnsignedBigInteger(divisor)).longValue() - func remainderUnsigned() throws: + func remainderUnsigned(dividend,divisor) throws: cond-branch cond:dividend GT 0 Land divisor GT 0 true branch : - return + return dividend Mod divisor false branch : cond-branch cond:compareUnsigned(dividend,divisor) LT 0 true branch : - return dividend - false branch : - return - + return dividend false branch : + return toUnsignedBigInteger(dividend).remainder(toUnsignedBigInteger(divisor)).longValue() - func highestOneBit() throws: + func highestOneBit(i) throws: i BorAssign (i Shr 1) i BorAssign (i Shr 2) i BorAssign (i Shr 4) @@ -343,17 +401,15 @@ while val NE 0 Land charPos GT 0 i BorAssign (i Shr 16) i BorAssign (i Shr 32) return i Sub (i Zext 1) - func lowestOneBit() throws: - return i Band Sub - i - func numberOfLeadingZeros() throws: + func lowestOneBit(i) throws: + return i Band Minus i + func numberOfLeadingZeros(i) throws: cond-branch cond:i EQ 0 true branch : - return 64 - false branch : + return 64 false branch : - var:n=1 - var:x=(int)(i Zext 32) + Decl: n=1 + Decl: x=(int)(i Zext 32) cond-branch cond:x EQ 0 true branch : n AddAssign 32 @@ -386,14 +442,13 @@ while val NE 0 Land charPos GT 0 n SubAssign x Zext 31 return n - func numberOfTrailingZeros() throws: - var:x,y + func numberOfTrailingZeros(i) throws: + Decl: x,y cond-branch cond:i EQ 0 true branch : - return 64 - false branch : + return 64 false branch : - var:n=63 + Decl: n=63 y Assign (int)i cond-branch cond:y NE 0 true branch : @@ -401,7 +456,6 @@ while val NE 0 Land charPos GT 0 x Assign y false branch : x Assign (int)(i Zext 32) - y Assign x Shl 16 cond-branch cond:y NE 0 true branch : @@ -431,7 +485,7 @@ while val NE 0 Land charPos GT 0 false branch : return n Sub ((x Shl 1) Zext 31) - func bitCount() throws: + func bitCount(i) throws: i Assign i Sub ((i Zext 1) Band 1431655765) i Assign (i Band 858993459) Add ((i Zext 2) Band 858993459) i Assign (i Add (i Zext 4)) Band -252645121 @@ -439,30 +493,27 @@ while val NE 0 Land charPos GT 0 i Assign i Add (i Zext 16) i Assign i Add (i Zext 32) return (int)i Band 127 - func rotateLeft() throws: - return (i Shl distance) Bor (i Zext Sub - distance) - func rotateRight() throws: - return (i Zext distance) Bor (i Shl Sub - distance) - func reverse() throws: + func rotateLeft(i,distance) throws: + return (i Shl distance) Bor (i Zext Minus distance) + func rotateRight(i,distance) throws: + return (i Zext distance) Bor (i Shl Minus distance) + func reverse(i) throws: i Assign (i Band 1431655765) Shl 1 Bor (i Zext 1) Band 1431655765 i Assign (i Band 858993459) Shl 2 Bor (i Zext 2) Band 858993459 i Assign (i Band -252645121) Shl 4 Bor (i Zext 4) Band -252645121 i Assign (i Band 267390975) Shl 8 Bor (i Zext 8) Band 267390975 i Assign (i Shl 48) Bor ((i Band -1048576) Shl 16) Bor ((i Zext 16) Band -1048576) Bor (i Zext 48) return i - func signum() throws: - return (int)((i Shr 63) Bor (Sub - i Zext 63)) - func reverseBytes() throws: + func signum(i) throws: + return (int)((i Shr 63) Bor (Minus i Zext 63)) + func reverseBytes(i) throws: i Assign (i Band 267390975) Shl 8 Bor (i Zext 8) Band 267390975 return (i Shl 48) Bor ((i Band -1048576) Shl 16) Bor ((i Zext 16) Band -1048576) Bor (i Zext 48) - func sum() throws: + func sum(a,b) throws: return a Add b - func max() throws: + func max(a,b) throws: return Math.max(a,b) - func min() throws: + func min(a,b) throws: return Math.min(a,b) LocalClasses: class LongCache @@ -477,3 +528,23 @@ while val NE 0 Land charPos GT 0 LocalInterfaces: LocalInterfaces: +Identifier:result has no decl. +Identifier:result has no decl. +Identifier:NumberFormatException has no decl. +Identifier:e has no decl. +Identifier:result has no decl. +Identifier:v has no decl. +Identifier:IllegalArgumentException has no decl. +Identifier:NullPointerException has no decl. +Identifier:e has no decl. +Identifier:n has no decl. +Identifier:x has no decl. +Identifier:y has no decl. +Identifier:y has no decl. +Identifier:x has no decl. +Identifier:y has no decl. +Identifier:x has no decl. +Identifier:y has no decl. +Identifier:x has no decl. +Identifier:y has no decl. +Identifier:x has no decl. diff --git a/src/MapleFE/test/openjdk/Math.java b/src/MapleFE/test/java/openjdk/Math.java similarity index 100% rename from src/MapleFE/test/openjdk/Math.java rename to src/MapleFE/test/java/openjdk/Math.java diff --git a/src/MapleFE/test/openjdk/Math.java.result b/src/MapleFE/test/java/openjdk/Math.java.result similarity index 48% rename from src/MapleFE/test/openjdk/Math.java.result rename to src/MapleFE/test/java/openjdk/Math.java.result index a18f75bee0181b780ab8522c42a24c036ac53fbf..47d7b98538b0be951dfc432801ba38c220114992 100644 --- a/src/MapleFE/test/openjdk/Math.java.result +++ b/src/MapleFE/test/java/openjdk/Math.java.result @@ -3,9 +3,7 @@ Matched 14 tokens. Matched 21 tokens. Matched 28 tokens. Matched 35 tokens. -Matched 3300 tokens. -Convert unary --> binary -Convert unary --> binary +Matched 3286 tokens. ============= Module =========== == Sub Tree == package java.lang @@ -20,213 +18,214 @@ import sun.misc.DoubleConsts == Sub Tree == class Math Fields: - E=2.71828 PI=3.14159 negativeZeroFloatBits=Float.floatToRawIntBits(Sub - 0) negativeZeroDoubleBits=Double.doubleToRawLongBits(Sub - 0) twoToTheDoubleScaleUp=powerOfTwoD(512) twoToTheDoubleScaleDown=powerOfTwoD(Sub - 512) + E=2.71828 PI=3.14159 negativeZeroFloatBits=Float.floatToRawIntBits(-0) negativeZeroDoubleBits=Double.doubleToRawLongBits(-0) twoToTheDoubleScaleUp=powerOfTwoD(512) twoToTheDoubleScaleDown=powerOfTwoD(-512) Instance Initializer: Constructors: constructor Math() throws: Methods: - func sin() throws: - func cos() throws: - func tan() throws: - func asin() throws: - func acos() throws: - func atan() throws: - func toRadians() throws: - return - func toDegrees() throws: - return - func exp() throws: - func log() throws: - func log10() throws: - func sqrt() throws: - func cbrt() throws: - func IEEEremainder() throws: - func ceil() throws: - func floor() throws: - func rint() throws: - func atan2() throws: - func pow() throws: - func round() throws: - var:intBits=Float.floatToRawIntBits(a) - var:biasedExp=(intBits Band FloatConsts.EXP_BIT_MASK) Shr (FloatConsts.SIGNIFICAND_WIDTH Sub 1) - var:shift=(FloatConsts.SIGNIFICAND_WIDTH Sub 2 Add FloatConsts.EXP_BIAS) Sub biasedExp - cond-branch cond:(shift Band Sub - 32) EQ 0 - true branch : - var:r=((intBits Band FloatConsts.SIGNIF_BIT_MASK) Bor (FloatConsts.SIGNIF_BIT_MASK Add 1)) + func sin(a) throws: + func cos(a) throws: + func tan(a) throws: + func asin(a) throws: + func acos(a) throws: + func atan(a) throws: + func toRadians(angdeg) throws: + return angdeg Div 180 Mul PI + func toDegrees(angrad) throws: + return angrad Mul 180 Div PI + func exp(a) throws: + func log(a) throws: + func log10(a) throws: + func sqrt(a) throws: + func cbrt(a) throws: + func IEEEremainder(f1,f2) throws: + func ceil(a) throws: + func floor(a) throws: + func rint(a) throws: + func atan2(y,x) throws: + func pow(a,b) throws: + func round(a) throws: + Decl: intBits=Float.floatToRawIntBits(a) + Decl: biasedExp=(intBits Band FloatConsts.EXP_BIT_MASK) Shr (FloatConsts.SIGNIFICAND_WIDTH Sub 1) + Decl: shift=(FloatConsts.SIGNIFICAND_WIDTH Sub 2 Add FloatConsts.EXP_BIAS) Sub biasedExp + cond-branch cond:(shift Band -32) EQ 0 + true branch : + Decl: r=((intBits Band FloatConsts.SIGNIF_BIT_MASK) Bor (FloatConsts.SIGNIF_BIT_MASK Add 1)) + cond-branch cond:intBits LT 0 + true branch : + r Assign Minus r + false branch : + return ((r Shr shift) Add 1) Shr 1 false branch : return (int)a - func round() throws: - var:longBits=Double.doubleToRawLongBits(a) - var:biasedExp=(longBits Band DoubleConsts.EXP_BIT_MASK) Shr (DoubleConsts.SIGNIFICAND_WIDTH Sub 1) - var:shift=(DoubleConsts.SIGNIFICAND_WIDTH Sub 2 Add DoubleConsts.EXP_BIAS) Sub biasedExp - cond-branch cond:(shift Band Sub - 64) EQ 0 + func round(a) throws: + Decl: longBits=Double.doubleToRawLongBits(a) + Decl: biasedExp=(longBits Band DoubleConsts.EXP_BIT_MASK) Shr (DoubleConsts.SIGNIFICAND_WIDTH Sub 1) + Decl: shift=(DoubleConsts.SIGNIFICAND_WIDTH Sub 2 Add DoubleConsts.EXP_BIAS) Sub biasedExp + cond-branch cond:(shift Band -64) EQ 0 true branch : - var:r=((longBits Band DoubleConsts.SIGNIF_BIT_MASK) Bor (DoubleConsts.SIGNIF_BIT_MASK Add 1)) + Decl: r=((longBits Band DoubleConsts.SIGNIF_BIT_MASK) Bor (DoubleConsts.SIGNIF_BIT_MASK Add 1)) + cond-branch cond:longBits LT 0 + true branch : + r Assign Minus r + false branch : + return ((r Shr shift) Add 1) Shr 1 false branch : return (long)a func random() throws: return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble() - func setRandomSeedInternal() throws: + func setRandomSeedInternal(seed) throws: RandomNumberGeneratorHolder.randomNumberGenerator.setSeed(seed) func randomIntInternal() throws: return RandomNumberGeneratorHolder.randomNumberGenerator.nextInt() func randomLongInternal() throws: return RandomNumberGeneratorHolder.randomNumberGenerator.nextLong() - func addExact() throws: - var:r=x Add y + func addExact(x,y) throws: + Decl: r=x Add y cond-branch cond:((x Bxor r) Band (y Bxor r)) LT 0 true branch : - new ArithmeticException + new ArithmeticException("integer overflow") false branch : return r - func addExact() throws: - var:r=x Add y + func addExact(x,y) throws: + Decl: r=x Add y cond-branch cond:((x Bxor r) Band (y Bxor r)) LT 0 true branch : - new ArithmeticException + new ArithmeticException("long overflow") false branch : return r - func subtractExact() throws: - var:r=x Sub y + func subtractExact(x,y) throws: + Decl: r=x Sub y cond-branch cond:((x Bxor y) Band (x Bxor r)) LT 0 true branch : - new ArithmeticException + new ArithmeticException("integer overflow") false branch : return r - func subtractExact() throws: - var:r=x Sub y + func subtractExact(x,y) throws: + Decl: r=x Sub y cond-branch cond:((x Bxor y) Band (x Bxor r)) LT 0 true branch : - new ArithmeticException + new ArithmeticException("long overflow") false branch : return r - func multiplyExact() throws: - var:r= + func multiplyExact(x,y) throws: + Decl: r=(long)x Mul (long)y cond-branch cond:(int)r NE r true branch : - new ArithmeticException + new ArithmeticException("integer overflow") false branch : return (int)r - func multiplyExact() throws: - var:r= - var:ax=Math.abs(x) - var:ay=Math.abs(y) + func multiplyExact(x,y) throws: + Decl: r=x Mul y + Decl: ax=Math.abs(x) + Decl: ay=Math.abs(y) cond-branch cond:((ax Bor ay) Zext 31 NE 0) true branch : - cond-branch cond:((y NE 0) Land ( NE x)) Lor (x EQ Long.MIN_VALUE Land y EQ Sub - 1) + cond-branch cond:((y NE 0) Land (r Div y NE x)) Lor (x EQ Long.MIN_VALUE Land y EQ -1) true branch : - new ArithmeticException + new ArithmeticException("long overflow") false branch : false branch : return r - func incrementExact() throws: + func incrementExact(a) throws: cond-branch cond:a EQ Integer.MAX_VALUE true branch : - new ArithmeticException + new ArithmeticException("integer overflow") false branch : return a Add 1 - func incrementExact() throws: + func incrementExact(a) throws: cond-branch cond:a EQ Long.MAX_VALUE true branch : - new ArithmeticException + new ArithmeticException("long overflow") false branch : return a Add 1 - func decrementExact() throws: + func decrementExact(a) throws: cond-branch cond:a EQ Integer.MIN_VALUE true branch : - new ArithmeticException + new ArithmeticException("integer overflow") false branch : return a Sub 1 - func decrementExact() throws: + func decrementExact(a) throws: cond-branch cond:a EQ Long.MIN_VALUE true branch : - new ArithmeticException + new ArithmeticException("long overflow") false branch : return a Sub 1 - func negateExact() throws: + func negateExact(a) throws: cond-branch cond:a EQ Integer.MIN_VALUE true branch : - new ArithmeticException + new ArithmeticException("integer overflow") false branch : - return Sub - a - func negateExact() throws: + return Minus a + func negateExact(a) throws: cond-branch cond:a EQ Long.MIN_VALUE true branch : - new ArithmeticException + new ArithmeticException("long overflow") false branch : - return Sub - a - func toIntExact() throws: + return Minus a + func toIntExact(value) throws: cond-branch cond:(int)value NE value true branch : - new ArithmeticException + new ArithmeticException("integer overflow") false branch : return (int)value - func floorDiv() throws: - var:r= - cond-branch cond:(x Bxor y) LT 0 Land ( NE x) + func floorDiv(x,y) throws: + Decl: r=x Div y + cond-branch cond:(x Bxor y) LT 0 Land (r Mul y NE x) true branch : - rDec + r Dec false branch : return r - func floorDiv() throws: - var:r= - cond-branch cond:(x Bxor y) LT 0 Land ( NE x) + func floorDiv(x,y) throws: + Decl: r=x Div y + cond-branch cond:(x Bxor y) LT 0 Land (r Mul y NE x) true branch : - rDec + r Dec false branch : return r - func floorMod() throws: - var:r=x Sub + func floorMod(x,y) throws: + Decl: r=x Sub floorDiv(x,y) Mul y return r - func floorMod() throws: - return x Sub - func abs() throws: + func floorMod(x,y) throws: + return x Sub floorDiv(x,y) Mul y + func abs(a) throws: return - func abs() throws: + func abs(a) throws: return - func abs() throws: + func abs(a) throws: return Float.intBitsToFloat(2147483647 Band Float.floatToRawIntBits(a)) - func abs() throws: + func abs(a) throws: return Double.longBitsToDouble(-1 Band Double.doubleToRawLongBits(a)) - func max() throws: + func max(a,b) throws: return - func max() throws: + func max(a,b) throws: return - func max() throws: + func max(a,b) throws: cond-branch cond:a NE a true branch : - return a - false branch : + return a false branch : cond-branch cond:(a EQ 0) Land (b EQ 0) Land (Float.floatToRawIntBits(a) EQ negativeZeroFloatBits) true branch : @@ -234,11 +233,10 @@ class Math false branch : return - func max() throws: + func max(a,b) throws: cond-branch cond:a NE a true branch : - return a - false branch : + return a false branch : cond-branch cond:(a EQ 0) Land (b EQ 0) Land (Double.doubleToRawLongBits(a) EQ negativeZeroDoubleBits) true branch : @@ -246,15 +244,14 @@ class Math false branch : return - func min() throws: + func min(a,b) throws: return - func min() throws: + func min(a,b) throws: return - func min() throws: + func min(a,b) throws: cond-branch cond:a NE a true branch : - return a - false branch : + return a false branch : cond-branch cond:(a EQ 0) Land (b EQ 0) Land (Float.floatToRawIntBits(b) EQ negativeZeroFloatBits) true branch : @@ -262,11 +259,10 @@ class Math false branch : return - func min() throws: + func min(a,b) throws: cond-branch cond:a NE a true branch : - return a - false branch : + return a false branch : cond-branch cond:(a EQ 0) Land (b EQ 0) Land (Double.doubleToRawLongBits(b) EQ negativeZeroDoubleBits) true branch : @@ -274,33 +270,33 @@ class Math false branch : return - func ulp() throws: - var:exp=getExponent(d) + func ulp(d) throws: + Decl: exp=getExponent(d) A switch - func ulp() throws: - var:exp=getExponent(f) + func ulp(f) throws: + Decl: exp=getExponent(f) A switch - func signum() throws: + func signum(d) throws: return - func signum() throws: + func signum(f) throws: return - func sinh() throws: - func cosh() throws: - func tanh() throws: - func hypot() throws: - func expm1() throws: - func log1p() throws: - func copySign() throws: + func sinh(x) throws: + func cosh(x) throws: + func tanh(x) throws: + func hypot(x,y) throws: + func expm1(x) throws: + func log1p(x) throws: + func copySign(magnitude,sign) throws: return Double.longBitsToDouble((Double.doubleToRawLongBits(sign) Band (DoubleConsts.SIGN_BIT_MASK)) Bor (Double.doubleToRawLongBits(magnitude) Band (DoubleConsts.EXP_BIT_MASK Bor DoubleConsts.SIGNIF_BIT_MASK))) - func copySign() throws: + func copySign(magnitude,sign) throws: return Float.intBitsToFloat((Float.floatToRawIntBits(sign) Band (FloatConsts.SIGN_BIT_MASK)) Bor (Float.floatToRawIntBits(magnitude) Band (FloatConsts.EXP_BIT_MASK Bor FloatConsts.SIGNIF_BIT_MASK))) - func getExponent() throws: + func getExponent(f) throws: return ((Float.floatToRawIntBits(f) Band FloatConsts.EXP_BIT_MASK) Shr (FloatConsts.SIGNIFICAND_WIDTH Sub 1)) Sub FloatConsts.EXP_BIAS - func getExponent() throws: + func getExponent(d) throws: return (int)(((Double.doubleToRawLongBits(d) Band DoubleConsts.EXP_BIT_MASK) Shr (DoubleConsts.SIGNIFICAND_WIDTH Sub 1)) Sub DoubleConsts.EXP_BIAS) - func nextAfter() throws: + func nextAfter(start,direction) throws: cond-branch cond:Double.isNaN(start) Lor Double.isNaN(direction) true branch : return start Add direction @@ -309,11 +305,23 @@ class Math true branch : return direction false branch : - var:transducer=Double.doubleToRawLongBits(start Add 0) - - - - func nextAfter() throws: + Decl: transducer=Double.doubleToRawLongBits(start Add 0) + cond-branch cond:direction GT start + true branch : + transducer Assign transducer Add () + false branch : + assert direction LT start : + cond-branch cond:transducer GT 0 + true branch : + PreDec transducer false branch : + cond-branch cond:transducer LT 0 + true branch : + PreInc transducer false branch : + transducer Assign DoubleConsts.SIGN_BIT_MASK Bor 1 + + return Double.longBitsToDouble(transducer) + + func nextAfter(start,direction) throws: cond-branch cond:Float.isNaN(start) Lor Double.isNaN(direction) true branch : return start Add (float)direction @@ -322,67 +330,70 @@ class Math true branch : return (float)direction false branch : - var:transducer=Float.floatToRawIntBits(start Add 0) - - - - func nextUp() throws: + Decl: transducer=Float.floatToRawIntBits(start Add 0) + cond-branch cond:direction GT start + true branch : + transducer Assign transducer Add () + false branch : + assert direction LT start : + cond-branch cond:transducer GT 0 + true branch : + PreDec transducer false branch : + cond-branch cond:transducer LT 0 + true branch : + PreInc transducer false branch : + transducer Assign FloatConsts.SIGN_BIT_MASK Bor 1 + + return Float.intBitsToFloat(transducer) + + func nextUp(d) throws: cond-branch cond:Double.isNaN(d) Lor d EQ Double.POSITIVE_INFINITY true branch : - return d - false branch : + return d false branch : d AddAssign 0 return Double.longBitsToDouble(Double.doubleToRawLongBits(d) Add ()) - func nextUp() throws: + func nextUp(f) throws: cond-branch cond:Float.isNaN(f) Lor f EQ FloatConsts.POSITIVE_INFINITY true branch : - return f - false branch : + return f false branch : f AddAssign 0 return Float.intBitsToFloat(Float.floatToRawIntBits(f) Add ()) - func nextDown() throws: + func nextDown(d) throws: cond-branch cond:Double.isNaN(d) Lor d EQ Double.NEGATIVE_INFINITY true branch : - return d - false branch : + return d false branch : cond-branch cond:d EQ 0 true branch : - return Sub - Double.MIN_VALUE - false branch : + return Minus Double.MIN_VALUE false branch : return Double.longBitsToDouble(Double.doubleToRawLongBits(d) Add ()) - - func nextDown() throws: + func nextDown(f) throws: cond-branch cond:Float.isNaN(f) Lor f EQ Float.NEGATIVE_INFINITY true branch : - return f - false branch : + return f false branch : cond-branch cond:f EQ 0 true branch : - return Sub - Float.MIN_VALUE - false branch : + return Minus Float.MIN_VALUE false branch : return Float.intBitsToFloat(Float.floatToRawIntBits(f) Add ()) - - func scalb() throws: - var:MAX_SCALE=DoubleConsts.MAX_EXPONENT Add Sub - DoubleConsts.MIN_EXPONENT Add DoubleConsts.SIGNIFICAND_WIDTH Add 1 - var:exp_adjust=0 - var:scale_increment=0 - var:exp_delta=Double.NaN + func scalb(d,scaleFactor) throws: + Decl: MAX_SCALE=DoubleConsts.MAX_EXPONENT Add Minus DoubleConsts.MIN_EXPONENT Add DoubleConsts.SIGNIFICAND_WIDTH Add 1 + Decl: exp_adjust=0 + Decl: scale_increment=0 + Decl: exp_delta=Double.NaN cond-branch cond:scaleFactor LT 0 true branch : - scaleFactor Assign Math.max(scaleFactor Sub MAX_SCALE) - + scaleFactor Assign Math.max(scaleFactor,Minus MAX_SCALE) + scale_increment Assign -512 + exp_delta Assign twoToTheDoubleScaleDown false branch : scaleFactor Assign Math.min(scaleFactor,MAX_SCALE) + scale_increment Assign 512 + exp_delta Assign twoToTheDoubleScaleUp - - var:t=(scaleFactor Shr 9 Sub 1) Zext 32 Sub 9 + Decl: t=(scaleFactor Shr 9 Sub 1) Zext 32 Sub 9 exp_adjust Assign ((scaleFactor Add t) Band (512 Sub 1)) Sub t d MulAssign powerOfTwoD(exp_adjust) scaleFactor SubAssign exp_adjust @@ -390,21 +401,20 @@ class Math scaleFactor SubAssign scale_increment return d - func scalb() throws: - var:MAX_SCALE=FloatConsts.MAX_EXPONENT Add Sub - FloatConsts.MIN_EXPONENT Add FloatConsts.SIGNIFICAND_WIDTH Add 1 - scaleFactor Assign Math.max(Math.min(scaleFactor,MAX_SCALE) Sub MAX_SCALE) - return (float)() - func powerOfTwoD() throws: + func scalb(f,scaleFactor) throws: + Decl: MAX_SCALE=FloatConsts.MAX_EXPONENT Add Minus FloatConsts.MIN_EXPONENT Add FloatConsts.SIGNIFICAND_WIDTH Add 1 + scaleFactor Assign Math.max(Math.min(scaleFactor,MAX_SCALE),Minus MAX_SCALE) + return (float)((double)f Mul powerOfTwoD(scaleFactor)) + func powerOfTwoD(n) throws: assert (n GE DoubleConsts.MIN_EXPONENT Land n LE DoubleConsts.MAX_EXPONENT) : return Double.longBitsToDouble((((long)n Add (long)DoubleConsts.EXP_BIAS) Shl (DoubleConsts.SIGNIFICAND_WIDTH Sub 1)) Band DoubleConsts.EXP_BIT_MASK) - func powerOfTwoF() throws: + func powerOfTwoF(n) throws: assert (n GE FloatConsts.MIN_EXPONENT Land n LE FloatConsts.MAX_EXPONENT) : return Float.intBitsToFloat(((n Add FloatConsts.EXP_BIAS) Shl (FloatConsts.SIGNIFICAND_WIDTH Sub 1)) Band FloatConsts.EXP_BIT_MASK) LocalClasses: class RandomNumberGeneratorHolder Fields: - randomNumberGenerator=new Random + randomNumberGenerator=new Random() Instance Initializer: Constructors: Methods: @@ -412,3 +422,6 @@ class Math LocalInterfaces: LocalInterfaces: +Identifier:exp_adjust has no decl. +Identifier:t has no decl. +Identifier:exp_adjust has no decl. diff --git a/src/MapleFE/test/java/openjdk/NegativeArraySizeException.java b/src/MapleFE/test/java/openjdk/NegativeArraySizeException.java new file mode 100644 index 0000000000000000000000000000000000000000..a90c8157e5ba879eebcc1498498ba1481f43fe6b --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NegativeArraySizeException.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown if an application tries to create an array with negative size. + * + * @author unascribed + * @since JDK1.0 + */ +public +class NegativeArraySizeException extends RuntimeException { + private static final long serialVersionUID = -8960118058596991861L; + + /** + * Constructs a NegativeArraySizeException with no + * detail message. + */ + public NegativeArraySizeException() { + super(); + } + + /** + * Constructs a NegativeArraySizeException with the + * specified detail message. + * + * @param s the detail message. + */ + public NegativeArraySizeException(String s) { + super(s); + } +} diff --git a/src/MapleFE/test/java/openjdk/NegativeArraySizeException.java.result b/src/MapleFE/test/java/openjdk/NegativeArraySizeException.java.result new file mode 100644 index 0000000000000000000000000000000000000000..c3722843d45de39a0e0df2186fe8e19593ab976d --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NegativeArraySizeException.java.result @@ -0,0 +1,17 @@ +Matched 5 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +class NegativeArraySizeException + Fields: + serialVersionUID=868449419 + Instance Initializer: + Constructors: + constructor NegativeArraySizeException() throws: + constructor NegativeArraySizeException(s) throws: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/NoClassDefFoundError.java b/src/MapleFE/test/java/openjdk/NoClassDefFoundError.java new file mode 100644 index 0000000000000000000000000000000000000000..869c8d9fb2ba8ab303b3211433fd37149e0f37e9 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NoClassDefFoundError.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown if the Java Virtual Machine or a ClassLoader instance + * tries to load in the definition of a class (as part of a normal method call + * or as part of creating a new instance using the new expression) + * and no definition of the class could be found. + *

+ * The searched-for class definition existed when the currently + * executing class was compiled, but the definition can no longer be + * found. + * + * @author unascribed + * @since JDK1.0 + */ +public +class NoClassDefFoundError extends LinkageError { + private static final long serialVersionUID = 9095859863287012458L; + + /** + * Constructs a NoClassDefFoundError with no detail message. + */ + public NoClassDefFoundError() { + super(); + } + + /** + * Constructs a NoClassDefFoundError with the specified + * detail message. + * + * @param s the detail message. + */ + public NoClassDefFoundError(String s) { + super(s); + } + + /** + * Constructs a new {@code NoClassDefFoundError} with the current stack + * trace, the specified detail message and the specified cause. Used + * internally by the Android runtime. + * + * @param detailMessage + * the detail message for this error. + * @param throwable + * the cause of this error. + */ + private NoClassDefFoundError(String detailMessage, Throwable throwable) { + super(detailMessage, throwable); + } +} diff --git a/src/MapleFE/test/java/openjdk/NoClassDefFoundError.java.result b/src/MapleFE/test/java/openjdk/NoClassDefFoundError.java.result new file mode 100644 index 0000000000000000000000000000000000000000..cc0491c55d3f01d700fcd1ec5edfb7530fee872e --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NoClassDefFoundError.java.result @@ -0,0 +1,18 @@ +Matched 5 tokens. +Matched 61 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +class NoClassDefFoundError + Fields: + serialVersionUID=-1913349014 + Instance Initializer: + Constructors: + constructor NoClassDefFoundError() throws: + constructor NoClassDefFoundError(s) throws: + constructor NoClassDefFoundError(detailMessage,throwable) throws: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/NoSuchFieldError.java b/src/MapleFE/test/java/openjdk/NoSuchFieldError.java new file mode 100644 index 0000000000000000000000000000000000000000..735adbbf0953a919fceb1bf37ccb340afbbb8ebc --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NoSuchFieldError.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown if an application tries to access or modify a specified + * field of an object, and that object no longer has that field. + *

+ * Normally, this error is caught by the compiler; this error can + * only occur at run time if the definition of a class has + * incompatibly changed. + * + * @author unascribed + * @since JDK1.0 + */ +public +class NoSuchFieldError extends IncompatibleClassChangeError { + private static final long serialVersionUID = -3456430195886129035L; + + /** + * Constructs a NoSuchFieldError with no detail message. + */ + public NoSuchFieldError() { + super(); + } + + /** + * Constructs a NoSuchFieldError with the specified + * detail message. + * + * @param s the detail message. + */ + public NoSuchFieldError(String s) { + super(s); + } +} diff --git a/src/MapleFE/test/java/openjdk/NoSuchFieldError.java.result b/src/MapleFE/test/java/openjdk/NoSuchFieldError.java.result new file mode 100644 index 0000000000000000000000000000000000000000..a0036f96ccd68048e728cac3d1f88141a434110a --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NoSuchFieldError.java.result @@ -0,0 +1,17 @@ +Matched 5 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +class NoSuchFieldError + Fields: + serialVersionUID=-1085931403 + Instance Initializer: + Constructors: + constructor NoSuchFieldError() throws: + constructor NoSuchFieldError(s) throws: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/NoSuchFieldException.java b/src/MapleFE/test/java/openjdk/NoSuchFieldException.java new file mode 100644 index 0000000000000000000000000000000000000000..0058264e5a719e205d66d91ae57170ae58370f78 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NoSuchFieldException.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Signals that the class doesn't have a field of a specified name. + * + * @author unascribed + * @since JDK1.1 + */ +public class NoSuchFieldException extends ReflectiveOperationException { + private static final long serialVersionUID = -6143714805279938260L; + + /** + * Constructor. + */ + public NoSuchFieldException() { + super(); + } + + /** + * Constructor with a detail message. + * + * @param s the detail message + */ + public NoSuchFieldException(String s) { + super(s); + } +} diff --git a/src/MapleFE/test/java/openjdk/NoSuchFieldException.java.result b/src/MapleFE/test/java/openjdk/NoSuchFieldException.java.result new file mode 100644 index 0000000000000000000000000000000000000000..6bb1d4f27cb61fefbd8af53f9f7d896cea44ce58 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NoSuchFieldException.java.result @@ -0,0 +1,17 @@ +Matched 5 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +class NoSuchFieldException + Fields: + serialVersionUID=1979394348 + Instance Initializer: + Constructors: + constructor NoSuchFieldException() throws: + constructor NoSuchFieldException(s) throws: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/NoSuchMethodError.java b/src/MapleFE/test/java/openjdk/NoSuchMethodError.java new file mode 100644 index 0000000000000000000000000000000000000000..248de62667c4915f189bbe7af2975559f1a92815 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NoSuchMethodError.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown if an application tries to call a specified method of a + * class (either static or instance), and that class no longer has a + * definition of that method. + *

+ * Normally, this error is caught by the compiler; this error can + * only occur at run time if the definition of a class has + * incompatibly changed. + * + * @author unascribed + * @since JDK1.0 + */ +public +class NoSuchMethodError extends IncompatibleClassChangeError { + private static final long serialVersionUID = -3765521442372831335L; + + /** + * Constructs a NoSuchMethodError with no detail message. + */ + public NoSuchMethodError() { + super(); + } + + /** + * Constructs a NoSuchMethodError with the + * specified detail message. + * + * @param s the detail message. + */ + public NoSuchMethodError(String s) { + super(s); + } +} diff --git a/src/MapleFE/test/java/openjdk/NoSuchMethodError.java.result b/src/MapleFE/test/java/openjdk/NoSuchMethodError.java.result new file mode 100644 index 0000000000000000000000000000000000000000..091ac4af475856ec5f928564149b33513bff24cf --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NoSuchMethodError.java.result @@ -0,0 +1,17 @@ +Matched 5 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +class NoSuchMethodError + Fields: + serialVersionUID=-515885159 + Instance Initializer: + Constructors: + constructor NoSuchMethodError() throws: + constructor NoSuchMethodError(s) throws: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/NoSuchMethodException.java b/src/MapleFE/test/java/openjdk/NoSuchMethodException.java new file mode 100644 index 0000000000000000000000000000000000000000..701437c9887b2f65f9a0c3887e912ea66ba5fd18 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NoSuchMethodException.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown when a particular method cannot be found. + * + * @author unascribed + * @since JDK1.0 + */ +public +class NoSuchMethodException extends ReflectiveOperationException { + private static final long serialVersionUID = 5034388446362600923L; + + /** + * Constructs a NoSuchMethodException without a detail message. + */ + public NoSuchMethodException() { + super(); + } + + /** + * Constructs a NoSuchMethodException with a detail message. + * + * @param s the detail message. + */ + public NoSuchMethodException(String s) { + super(s); + } +} diff --git a/src/MapleFE/test/java/openjdk/NoSuchMethodException.java.result b/src/MapleFE/test/java/openjdk/NoSuchMethodException.java.result new file mode 100644 index 0000000000000000000000000000000000000000..29371ab7362ed4e9940537e646b7ed999580ade4 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NoSuchMethodException.java.result @@ -0,0 +1,17 @@ +Matched 5 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +class NoSuchMethodException + Fields: + serialVersionUID=1590035931 + Instance Initializer: + Constructors: + constructor NoSuchMethodException() throws: + constructor NoSuchMethodException(s) throws: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/NullPointerException.java b/src/MapleFE/test/java/openjdk/NullPointerException.java new file mode 100644 index 0000000000000000000000000000000000000000..5b87ec4fd7c96bf2f7e70e68c8d40e9806c2ca75 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NullPointerException.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown when an application attempts to use {@code null} in a + * case where an object is required. These include: + *

    + *
  • Calling the instance method of a {@code null} object. + *
  • Accessing or modifying the field of a {@code null} object. + *
  • Taking the length of {@code null} as if it were an array. + *
  • Accessing or modifying the slots of {@code null} as if it + * were an array. + *
  • Throwing {@code null} as if it were a {@code Throwable} + * value. + *
+ *

+ * Applications should throw instances of this class to indicate + * other illegal uses of the {@code null} object. + * + * {@code NullPointerException} objects may be constructed by the + * virtual machine as if {@linkplain Throwable#Throwable(String, + * Throwable, boolean, boolean) suppression were disabled and/or the + * stack trace was not writable}. + * + * @author unascribed + * @since JDK1.0 + */ +public +class NullPointerException extends RuntimeException { + private static final long serialVersionUID = 5162710183389028792L; + + /** + * Constructs a {@code NullPointerException} with no detail message. + */ + public NullPointerException() { + super(); + } + + /** + * Constructs a {@code NullPointerException} with the specified + * detail message. + * + * @param s the detail message. + */ + public NullPointerException(String s) { + super(s); + } +} diff --git a/src/MapleFE/test/java/openjdk/NullPointerException.java.result b/src/MapleFE/test/java/openjdk/NullPointerException.java.result new file mode 100644 index 0000000000000000000000000000000000000000..7553e10f11f1111adae6258d9fc53e9e8a21db99 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NullPointerException.java.result @@ -0,0 +1,17 @@ +Matched 5 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +class NullPointerException + Fields: + serialVersionUID=-13508168 + Instance Initializer: + Constructors: + constructor NullPointerException() throws: + constructor NullPointerException(s) throws: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/Number.java b/src/MapleFE/test/java/openjdk/Number.java new file mode 100644 index 0000000000000000000000000000000000000000..d901609571b1ef1a6675bcb4caf096c858af3512 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Number.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * The abstract class {@code Number} is the superclass of platform + * classes representing numeric values that are convertible to the + * primitive types {@code byte}, {@code double}, {@code float}, {@code + * int}, {@code long}, and {@code short}. + * + * The specific semantics of the conversion from the numeric value of + * a particular {@code Number} implementation to a given primitive + * type is defined by the {@code Number} implementation in question. + * + * For platform classes, the conversion is often analogous to a + * narrowing primitive conversion or a widening primitive conversion + * as defining in The Java™ Language Specification + * for converting between primitive types. Therefore, conversions may + * lose information about the overall magnitude of a numeric value, may + * lose precision, and may even return a result of a different sign + * than the input. + * + * See the documentation of a given {@code Number} implementation for + * conversion details. + * + * @author Lee Boynton + * @author Arthur van Hoff + * @jls 5.1.2 Widening Primitive Conversions + * @jls 5.1.3 Narrowing Primitive Conversions + * @since JDK1.0 + */ +public abstract class Number implements java.io.Serializable { + /** + * Returns the value of the specified number as an {@code int}, + * which may involve rounding or truncation. + * + * @return the numeric value represented by this object after conversion + * to type {@code int}. + */ + public abstract int intValue(); + + /** + * Returns the value of the specified number as a {@code long}, + * which may involve rounding or truncation. + * + * @return the numeric value represented by this object after conversion + * to type {@code long}. + */ + public abstract long longValue(); + + /** + * Returns the value of the specified number as a {@code float}, + * which may involve rounding. + * + * @return the numeric value represented by this object after conversion + * to type {@code float}. + */ + public abstract float floatValue(); + + /** + * Returns the value of the specified number as a {@code double}, + * which may involve rounding. + * + * @return the numeric value represented by this object after conversion + * to type {@code double}. + */ + public abstract double doubleValue(); + + /** + * Returns the value of the specified number as a {@code byte}, + * which may involve rounding or truncation. + * + *

This implementation returns the result of {@link #intValue} cast + * to a {@code byte}. + * + * @return the numeric value represented by this object after conversion + * to type {@code byte}. + * @since JDK1.1 + */ + public byte byteValue() { + return (byte)intValue(); + } + + /** + * Returns the value of the specified number as a {@code short}, + * which may involve rounding or truncation. + * + *

This implementation returns the result of {@link #intValue} cast + * to a {@code short}. + * + * @return the numeric value represented by this object after conversion + * to type {@code short}. + * @since JDK1.1 + */ + public short shortValue() { + return (short)intValue(); + } + + /** use serialVersionUID from JDK 1.0.2 for interoperability */ + private static final long serialVersionUID = -8742448824652078965L; +} diff --git a/src/MapleFE/test/java/openjdk/Number.java.result b/src/MapleFE/test/java/openjdk/Number.java.result new file mode 100644 index 0000000000000000000000000000000000000000..1893622d300feeefb89605521d99af6279a948cb --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Number.java.result @@ -0,0 +1,23 @@ +Matched 5 tokens. +Matched 83 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +class Number + Fields: + serialVersionUID=194306187 + Instance Initializer: + Constructors: + Methods: + func intValue() throws: + func longValue() throws: + func floatValue() throws: + func doubleValue() throws: + func byteValue() throws: + return (byte)intValue() + func shortValue() throws: + return (short)intValue() + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/NumberFormatException.java b/src/MapleFE/test/java/openjdk/NumberFormatException.java new file mode 100644 index 0000000000000000000000000000000000000000..ea1ec9fd7714269e46a839c1810133afbbc8da6b --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NumberFormatException.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown to indicate that the application has attempted to convert + * a string to one of the numeric types, but that the string does not + * have the appropriate format. + * + * @author unascribed + * @see java.lang.Integer#parseInt(String) + * @since JDK1.0 + */ +public +class NumberFormatException extends IllegalArgumentException { + static final long serialVersionUID = -2848938806368998894L; + + /** + * Constructs a NumberFormatException with no detail message. + */ + public NumberFormatException () { + super(); + } + + /** + * Constructs a NumberFormatException with the + * specified detail message. + * + * @param s the detail message. + */ + public NumberFormatException (String s) { + super (s); + } + + /** + * Factory method for making a NumberFormatException + * given the specified input which caused the error. + * + * @param s the input causing the error + */ + static NumberFormatException forInputString(String s) { + return new NumberFormatException("For input string: \"" + s + "\""); + } +} diff --git a/src/MapleFE/test/java/openjdk/NumberFormatException.java.result b/src/MapleFE/test/java/openjdk/NumberFormatException.java.result new file mode 100644 index 0000000000000000000000000000000000000000..3641aa05de9998fffb8fd18a83d8408c5a14bd58 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/NumberFormatException.java.result @@ -0,0 +1,19 @@ +Matched 5 tokens. +Matched 62 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +class NumberFormatException + Fields: + serialVersionUID=-74651118 + Instance Initializer: + Constructors: + constructor NumberFormatException() throws: + constructor NumberFormatException(s) throws: + Methods: + func forInputString(s) throws: + return new NumberFormatException("For input string: \"" Add s Add "\"") + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/Object.java b/src/MapleFE/test/java/openjdk/Object.java new file mode 100644 index 0000000000000000000000000000000000000000..e9728e08224a92e160ed2b6fe3672a8a28973ff0 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Object.java @@ -0,0 +1,582 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import dalvik.annotation.optimization.FastNative; + +/** + * Class {@code Object} is the root of the class hierarchy. + * Every class has {@code Object} as a superclass. All objects, + * including arrays, implement the methods of this class. + * + * @author unascribed + * @see java.lang.Class + * @since JDK1.0 + */ +public class Object { + + private transient Class shadow$_klass_; + private transient int shadow$_monitor_; + + /** + * Returns the runtime class of this {@code Object}. The returned + * {@code Class} object is the object that is locked by {@code + * static synchronized} methods of the represented class. + * + *

The actual result type is {@code Class} + * where {@code |X|} is the erasure of the static type of the + * expression on which {@code getClass} is called. For + * example, no cast is required in this code fragment:

+ * + *

+ * {@code Number n = 0; }
+ * {@code Class c = n.getClass(); } + *

+ * + * @return The {@code Class} object that represents the runtime + * class of this object. + * @jls 15.8.2 Class Literals + */ + public final Class getClass() { + return shadow$_klass_; + } + + /** + * Returns a hash code value for the object. This method is + * supported for the benefit of hash tables such as those provided by + * {@link java.util.HashMap}. + *

+ * The general contract of {@code hashCode} is: + *

    + *
  • Whenever it is invoked on the same object more than once during + * an execution of a Java application, the {@code hashCode} method + * must consistently return the same integer, provided no information + * used in {@code equals} comparisons on the object is modified. + * This integer need not remain consistent from one execution of an + * application to another execution of the same application. + *
  • If two objects are equal according to the {@code equals(Object)} + * method, then calling the {@code hashCode} method on each of + * the two objects must produce the same integer result. + *
  • It is not required that if two objects are unequal + * according to the {@link java.lang.Object#equals(java.lang.Object)} + * method, then calling the {@code hashCode} method on each of the + * two objects must produce distinct integer results. However, the + * programmer should be aware that producing distinct integer results + * for unequal objects may improve the performance of hash tables. + *
+ *

+ * As much as is reasonably practical, the hashCode method defined by + * class {@code Object} does return distinct integers for distinct + * objects. (This is typically implemented by converting the internal + * address of the object into an integer, but this implementation + * technique is not required by the + * Java™ programming language.) + * + * @return a hash code value for this object. + * @see java.lang.Object#equals(java.lang.Object) + * @see java.lang.System#identityHashCode + */ + public int hashCode() { + return identityHashCode(this); + } + + // Android-changed: add a local helper for identityHashCode. + // Package-private to be used by j.l.System. We do the implementation here + // to avoid Object.hashCode doing a clinit check on j.l.System, and also + // to avoid leaking shadow$_monitor_ outside of this class. + /* package-private */ static int identityHashCode(Object obj) { + int lockWord = obj.shadow$_monitor_; + final int lockWordStateMask = 0xC0000000; // Top 2 bits. + final int lockWordStateHash = 0x80000000; // Top 2 bits are value 2 (kStateHash). + final int lockWordHashMask = 0x0FFFFFFF; // Low 28 bits. + if ((lockWord & lockWordStateMask) == lockWordStateHash) { + return lockWord & lockWordHashMask; + } + return identityHashCodeNative(obj); + } + + @FastNative + private static native int identityHashCodeNative(Object obj); + + /** + * Indicates whether some other object is "equal to" this one. + *

+ * The {@code equals} method implements an equivalence relation + * on non-null object references: + *

    + *
  • It is reflexive: for any non-null reference value + * {@code x}, {@code x.equals(x)} should return + * {@code true}. + *
  • It is symmetric: for any non-null reference values + * {@code x} and {@code y}, {@code x.equals(y)} + * should return {@code true} if and only if + * {@code y.equals(x)} returns {@code true}. + *
  • It is transitive: for any non-null reference values + * {@code x}, {@code y}, and {@code z}, if + * {@code x.equals(y)} returns {@code true} and + * {@code y.equals(z)} returns {@code true}, then + * {@code x.equals(z)} should return {@code true}. + *
  • It is consistent: for any non-null reference values + * {@code x} and {@code y}, multiple invocations of + * {@code x.equals(y)} consistently return {@code true} + * or consistently return {@code false}, provided no + * information used in {@code equals} comparisons on the + * objects is modified. + *
  • For any non-null reference value {@code x}, + * {@code x.equals(null)} should return {@code false}. + *
+ *

+ * The {@code equals} method for class {@code Object} implements + * the most discriminating possible equivalence relation on objects; + * that is, for any non-null reference values {@code x} and + * {@code y}, this method returns {@code true} if and only + * if {@code x} and {@code y} refer to the same object + * ({@code x == y} has the value {@code true}). + *

+ * Note that it is generally necessary to override the {@code hashCode} + * method whenever this method is overridden, so as to maintain the + * general contract for the {@code hashCode} method, which states + * that equal objects must have equal hash codes. + * + * @param obj the reference object with which to compare. + * @return {@code true} if this object is the same as the obj + * argument; {@code false} otherwise. + * @see #hashCode() + * @see java.util.HashMap + */ + public boolean equals(Object obj) { + return (this == obj); + } + + /** + * Creates and returns a copy of this object. The precise meaning + * of "copy" may depend on the class of the object. The general + * intent is that, for any object {@code x}, the expression: + *

+ *
+     * x.clone() != x
+ * will be true, and that the expression: + *
+ *
+     * x.clone().getClass() == x.getClass()
+ * will be {@code true}, but these are not absolute requirements. + * While it is typically the case that: + *
+ *
+     * x.clone().equals(x)
+ * will be {@code true}, this is not an absolute requirement. + *

+ * By convention, the returned object should be obtained by calling + * {@code super.clone}. If a class and all of its superclasses (except + * {@code Object}) obey this convention, it will be the case that + * {@code x.clone().getClass() == x.getClass()}. + *

+ * By convention, the object returned by this method should be independent + * of this object (which is being cloned). To achieve this independence, + * it may be necessary to modify one or more fields of the object returned + * by {@code super.clone} before returning it. Typically, this means + * copying any mutable objects that comprise the internal "deep structure" + * of the object being cloned and replacing the references to these + * objects with references to the copies. If a class contains only + * primitive fields or references to immutable objects, then it is usually + * the case that no fields in the object returned by {@code super.clone} + * need to be modified. + *

+ * The method {@code clone} for class {@code Object} performs a + * specific cloning operation. First, if the class of this object does + * not implement the interface {@code Cloneable}, then a + * {@code CloneNotSupportedException} is thrown. Note that all arrays + * are considered to implement the interface {@code Cloneable} and that + * the return type of the {@code clone} method of an array type {@code T[]} + * is {@code T[]} where T is any reference or primitive type. + * Otherwise, this method creates a new instance of the class of this + * object and initializes all its fields with exactly the contents of + * the corresponding fields of this object, as if by assignment; the + * contents of the fields are not themselves cloned. Thus, this method + * performs a "shallow copy" of this object, not a "deep copy" operation. + *

+ * The class {@code Object} does not itself implement the interface + * {@code Cloneable}, so calling the {@code clone} method on an object + * whose class is {@code Object} will result in throwing an + * exception at run time. + * + * @return a clone of this instance. + * @throws CloneNotSupportedException if the object's class does not + * support the {@code Cloneable} interface. Subclasses + * that override the {@code clone} method can also + * throw this exception to indicate that an instance cannot + * be cloned. + * @see java.lang.Cloneable + */ + protected Object clone() throws CloneNotSupportedException { + if (!(this instanceof Cloneable)) { + throw new CloneNotSupportedException("Class " + getClass().getName() + + " doesn't implement Cloneable"); + } + + return internalClone(); + } + + /* + * Native helper method for cloning. + */ + @FastNative + private native Object internalClone(); + + + /** + * Returns a string representation of the object. In general, the + * {@code toString} method returns a string that + * "textually represents" this object. The result should + * be a concise but informative representation that is easy for a + * person to read. + * It is recommended that all subclasses override this method. + *

+ * The {@code toString} method for class {@code Object} + * returns a string consisting of the name of the class of which the + * object is an instance, the at-sign character `{@code @}', and + * the unsigned hexadecimal representation of the hash code of the + * object. In other words, this method returns a string equal to the + * value of: + *

+ *
+     * getClass().getName() + '@' + Integer.toHexString(hashCode())
+     * 
+ * + * @return a string representation of the object. + */ + public String toString() { + return getClass().getName() + "@" + Integer.toHexString(hashCode()); + } + + /** + * Wakes up a single thread that is waiting on this object's + * monitor. If any threads are waiting on this object, one of them + * is chosen to be awakened. The choice is arbitrary and occurs at + * the discretion of the implementation. A thread waits on an object's + * monitor by calling one of the {@code wait} methods. + *

+ * The awakened thread will not be able to proceed until the current + * thread relinquishes the lock on this object. The awakened thread will + * compete in the usual manner with any other threads that might be + * actively competing to synchronize on this object; for example, the + * awakened thread enjoys no reliable privilege or disadvantage in being + * the next thread to lock this object. + *

+ * This method should only be called by a thread that is the owner + * of this object's monitor. A thread becomes the owner of the + * object's monitor in one of three ways: + *

    + *
  • By executing a synchronized instance method of that object. + *
  • By executing the body of a {@code synchronized} statement + * that synchronizes on the object. + *
  • For objects of type {@code Class,} by executing a + * synchronized static method of that class. + *
+ *

+ * Only one thread at a time can own an object's monitor. + * + * @throws IllegalMonitorStateException if the current thread is not + * the owner of this object's monitor. + * @see java.lang.Object#notifyAll() + * @see java.lang.Object#wait() + */ + @FastNative + public final native void notify(); + + /** + * Wakes up all threads that are waiting on this object's monitor. A + * thread waits on an object's monitor by calling one of the + * {@code wait} methods. + *

+ * The awakened threads will not be able to proceed until the current + * thread relinquishes the lock on this object. The awakened threads + * will compete in the usual manner with any other threads that might + * be actively competing to synchronize on this object; for example, + * the awakened threads enjoy no reliable privilege or disadvantage in + * being the next thread to lock this object. + *

+ * This method should only be called by a thread that is the owner + * of this object's monitor. See the {@code notify} method for a + * description of the ways in which a thread can become the owner of + * a monitor. + * + * @throws IllegalMonitorStateException if the current thread is not + * the owner of this object's monitor. + * @see java.lang.Object#notify() + * @see java.lang.Object#wait() + */ + @FastNative + public final native void notifyAll(); + + /** + * Causes the current thread to wait until either another thread invokes the + * {@link java.lang.Object#notify()} method or the + * {@link java.lang.Object#notifyAll()} method for this object, or a + * specified amount of time has elapsed. + *

+ * The current thread must own this object's monitor. + *

+ * This method causes the current thread (call it T) to + * place itself in the wait set for this object and then to relinquish + * any and all synchronization claims on this object. Thread T + * becomes disabled for thread scheduling purposes and lies dormant + * until one of four things happens: + *

    + *
  • Some other thread invokes the {@code notify} method for this + * object and thread T happens to be arbitrarily chosen as + * the thread to be awakened. + *
  • Some other thread invokes the {@code notifyAll} method for this + * object. + *
  • Some other thread {@linkplain Thread#interrupt() interrupts} + * thread T. + *
  • The specified amount of real time has elapsed, more or less. If + * {@code timeout} is zero, however, then real time is not taken into + * consideration and the thread simply waits until notified. + *
+ * The thread T is then removed from the wait set for this + * object and re-enabled for thread scheduling. It then competes in the + * usual manner with other threads for the right to synchronize on the + * object; once it has gained control of the object, all its + * synchronization claims on the object are restored to the status quo + * ante - that is, to the situation as of the time that the {@code wait} + * method was invoked. Thread T then returns from the + * invocation of the {@code wait} method. Thus, on return from the + * {@code wait} method, the synchronization state of the object and of + * thread {@code T} is exactly as it was when the {@code wait} method + * was invoked. + *

+ * A thread can also wake up without being notified, interrupted, or + * timing out, a so-called spurious wakeup. While this will rarely + * occur in practice, applications must guard against it by testing for + * the condition that should have caused the thread to be awakened, and + * continuing to wait if the condition is not satisfied. In other words, + * waits should always occur in loops, like this one: + *

+     *     synchronized (obj) {
+     *         while (<condition does not hold>)
+     *             obj.wait(timeout);
+     *         ... // Perform action appropriate to condition
+     *     }
+     * 
+ * (For more information on this topic, see Section 3.2.3 in Doug Lea's + * "Concurrent Programming in Java (Second Edition)" (Addison-Wesley, + * 2000), or Item 50 in Joshua Bloch's "Effective Java Programming + * Language Guide" (Addison-Wesley, 2001). + * + *

If the current thread is {@linkplain java.lang.Thread#interrupt() + * interrupted} by any thread before or while it is waiting, then an + * {@code InterruptedException} is thrown. This exception is not + * thrown until the lock status of this object has been restored as + * described above. + * + *

+ * Note that the {@code wait} method, as it places the current thread + * into the wait set for this object, unlocks only this object; any + * other objects on which the current thread may be synchronized remain + * locked while the thread waits. + *

+ * This method should only be called by a thread that is the owner + * of this object's monitor. See the {@code notify} method for a + * description of the ways in which a thread can become the owner of + * a monitor. + * + * @param millis the maximum time to wait in milliseconds. + * @throws IllegalArgumentException if the value of timeout is + * negative. + * @throws IllegalMonitorStateException if the current thread is not + * the owner of the object's monitor. + * @throws InterruptedException if any thread interrupted the + * current thread before or while the current thread + * was waiting for a notification. The interrupted + * status of the current thread is cleared when + * this exception is thrown. + * @see java.lang.Object#notify() + * @see java.lang.Object#notifyAll() + */ + public final void wait(long millis) throws InterruptedException { + wait(millis, 0); + } + + /** + * Causes the current thread to wait until another thread invokes the + * {@link java.lang.Object#notify()} method or the + * {@link java.lang.Object#notifyAll()} method for this object, or + * some other thread interrupts the current thread, or a certain + * amount of real time has elapsed. + *

+ * This method is similar to the {@code wait} method of one + * argument, but it allows finer control over the amount of time to + * wait for a notification before giving up. The amount of real time, + * measured in nanoseconds, is given by: + *

+ *
+     * 1000000*timeout+nanos
+ *

+ * In all other respects, this method does the same thing as the + * method {@link #wait(long)} of one argument. In particular, + * {@code wait(0, 0)} means the same thing as {@code wait(0)}. + *

+ * The current thread must own this object's monitor. The thread + * releases ownership of this monitor and waits until either of the + * following two conditions has occurred: + *

    + *
  • Another thread notifies threads waiting on this object's monitor + * to wake up either through a call to the {@code notify} method + * or the {@code notifyAll} method. + *
  • The timeout period, specified by {@code timeout} + * milliseconds plus {@code nanos} nanoseconds arguments, has + * elapsed. + *
+ *

+ * The thread then waits until it can re-obtain ownership of the + * monitor and resumes execution. + *

+ * As in the one argument version, interrupts and spurious wakeups are + * possible, and this method should always be used in a loop: + *

+     *     synchronized (obj) {
+     *         while (<condition does not hold>)
+     *             obj.wait(timeout, nanos);
+     *         ... // Perform action appropriate to condition
+     *     }
+     * 
+ * This method should only be called by a thread that is the owner + * of this object's monitor. See the {@code notify} method for a + * description of the ways in which a thread can become the owner of + * a monitor. + * + * @param millis the maximum time to wait in milliseconds. + * @param nanos additional time, in nanoseconds range + * 0-999999. + * @throws IllegalArgumentException if the value of timeout is + * negative or the value of nanos is + * not in the range 0-999999. + * @throws IllegalMonitorStateException if the current thread is not + * the owner of this object's monitor. + * @throws InterruptedException if any thread interrupted the + * current thread before or while the current thread + * was waiting for a notification. The interrupted + * status of the current thread is cleared when + * this exception is thrown. + */ + @FastNative + public final native void wait(long millis, int nanos) throws InterruptedException; + + /** + * Causes the current thread to wait until another thread invokes the + * {@link java.lang.Object#notify()} method or the + * {@link java.lang.Object#notifyAll()} method for this object. + * In other words, this method behaves exactly as if it simply + * performs the call {@code wait(0)}. + *

+ * The current thread must own this object's monitor. The thread + * releases ownership of this monitor and waits until another thread + * notifies threads waiting on this object's monitor to wake up + * either through a call to the {@code notify} method or the + * {@code notifyAll} method. The thread then waits until it can + * re-obtain ownership of the monitor and resumes execution. + *

+ * As in the one argument version, interrupts and spurious wakeups are + * possible, and this method should always be used in a loop: + *

+     *     synchronized (obj) {
+     *         while (<condition does not hold>)
+     *             obj.wait();
+     *         ... // Perform action appropriate to condition
+     *     }
+     * 
+ * This method should only be called by a thread that is the owner + * of this object's monitor. See the {@code notify} method for a + * description of the ways in which a thread can become the owner of + * a monitor. + * + * @throws IllegalMonitorStateException if the current thread is not + * the owner of the object's monitor. + * @throws InterruptedException if any thread interrupted the + * current thread before or while the current thread + * was waiting for a notification. The interrupted + * status of the current thread is cleared when + * this exception is thrown. + * @see java.lang.Object#notify() + * @see java.lang.Object#notifyAll() + */ + @FastNative + public final native void wait() throws InterruptedException; + + /** + * Called by the garbage collector on an object when garbage collection + * determines that there are no more references to the object. + * A subclass overrides the {@code finalize} method to dispose of + * system resources or to perform other cleanup. + *

+ * The general contract of {@code finalize} is that it is invoked + * if and when the Java™ virtual + * machine has determined that there is no longer any + * means by which this object can be accessed by any thread that has + * not yet died, except as a result of an action taken by the + * finalization of some other object or class which is ready to be + * finalized. The {@code finalize} method may take any action, including + * making this object available again to other threads; the usual purpose + * of {@code finalize}, however, is to perform cleanup actions before + * the object is irrevocably discarded. For example, the finalize method + * for an object that represents an input/output connection might perform + * explicit I/O transactions to break the connection before the object is + * permanently discarded. + *

+ * The {@code finalize} method of class {@code Object} performs no + * special action; it simply returns normally. Subclasses of + * {@code Object} may override this definition. + *

+ * The Java programming language does not guarantee which thread will + * invoke the {@code finalize} method for any given object. It is + * guaranteed, however, that the thread that invokes finalize will not + * be holding any user-visible synchronization locks when finalize is + * invoked. If an uncaught exception is thrown by the finalize method, + * the exception is ignored and finalization of that object terminates. + *

+ * After the {@code finalize} method has been invoked for an object, no + * further action is taken until the Java virtual machine has again + * determined that there is no longer any means by which this object can + * be accessed by any thread that has not yet died, including possible + * actions by other objects or classes which are ready to be finalized, + * at which point the object may be discarded. + *

+ * The {@code finalize} method is never invoked more than once by a Java + * virtual machine for any given object. + *

+ * Any exception thrown by the {@code finalize} method causes + * the finalization of this object to be halted, but is otherwise + * ignored. + * + * @throws Throwable the {@code Exception} raised by this method + * @see java.lang.ref.WeakReference + * @see java.lang.ref.PhantomReference + * @jls 12.6 Finalization of Class Instances + */ + protected void finalize() throws Throwable { } +} diff --git a/src/MapleFE/test/java/openjdk/Object.java.result b/src/MapleFE/test/java/openjdk/Object.java.result new file mode 100644 index 0000000000000000000000000000000000000000..d30bd56472a1e3a9411caeddeb4dbd5390e95311 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Object.java.result @@ -0,0 +1,53 @@ +Matched 5 tokens. +Matched 14 tokens. +Matched 299 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import dalvik.annotation.optimization.FastNative +== Sub Tree == +class Object + Fields: + shadow$_klass_ shadow$_monitor_ + Instance Initializer: + Constructors: + Methods: + func getClass() throws: + return shadow$_klass_ + func hashCode() throws: + return identityHashCode(this) + func identityHashCode(obj) throws: + Decl: lockWord=obj.shadow$_monitor_ + Decl: lockWordStateMask=-1073741824 + Decl: lockWordStateHash=-2147483648 + Decl: lockWordHashMask=268435455 + cond-branch cond:(lockWord Band lockWordStateMask) EQ lockWordStateHash + true branch : + return lockWord Band lockWordHashMask + false branch : + + return identityHashCodeNative(obj) + func identityHashCodeNative(obj) throws: + func equals(obj) throws: + return (this EQ obj) + func clone() throws: CloneNotSupportedException + cond-branch cond:(this instanceof Cloneable) + true branch : + new CloneNotSupportedException("Class " Add getClass().getName() Add " doesn't implement Cloneable") + false branch : + + return internalClone() + func internalClone() throws: + func toString() throws: + return getClass().getName() Add "@" Add Integer.toHexString(hashCode()) + func notify() throws: + func notifyAll() throws: + func wait(millis) throws: InterruptedException + wait(millis,0) + func wait(millis,nanos) throws: InterruptedException + func wait() throws: InterruptedException + func finalize() throws: Throwable + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/OutOfMemoryError.java b/src/MapleFE/test/java/openjdk/OutOfMemoryError.java new file mode 100644 index 0000000000000000000000000000000000000000..0f9df4e2f16519225e69515e7bd162d778346c76 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/OutOfMemoryError.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Thrown when the Java Virtual Machine cannot allocate an object + * because it is out of memory, and no more memory could be made + * available by the garbage collector. + * + * {@code OutOfMemoryError} objects may be constructed by the virtual + * machine as if {@linkplain Throwable#Throwable(String, Throwable, + * boolean, boolean) suppression were disabled and/or the stack trace was not + * writable}. + * + * @author unascribed + * @since JDK1.0 + */ +public class OutOfMemoryError extends VirtualMachineError { + private static final long serialVersionUID = 8228564086184010517L; + + /** + * Constructs an {@code OutOfMemoryError} with no detail message. + */ + public OutOfMemoryError() { + super(); + } + + /** + * Constructs an {@code OutOfMemoryError} with the specified + * detail message. + * + * @param s the detail message. + */ + public OutOfMemoryError(String s) { + super(s); + } +} diff --git a/src/MapleFE/test/java/openjdk/OutOfMemoryError.java.result b/src/MapleFE/test/java/openjdk/OutOfMemoryError.java.result new file mode 100644 index 0000000000000000000000000000000000000000..75397242fea0e8bb190ddc82dd91d2eb10e47c1f --- /dev/null +++ b/src/MapleFE/test/java/openjdk/OutOfMemoryError.java.result @@ -0,0 +1,17 @@ +Matched 5 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +class OutOfMemoryError + Fields: + serialVersionUID=-2004294891 + Instance Initializer: + Constructors: + constructor OutOfMemoryError() throws: + constructor OutOfMemoryError(s) throws: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/Override.java b/src/MapleFE/test/java/openjdk/Override.java new file mode 100644 index 0000000000000000000000000000000000000000..bf77344296cb6f07b940fc132e5a6a3963c4650a --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Override.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.lang.annotation.*; + +/** + * Indicates that a method declaration is intended to override a + * method declaration in a supertype. If a method is annotated with + * this annotation type compilers are required to generate an error + * message unless at least one of the following conditions hold: + * + *

  • + * The method does override or implement a method declared in a + * supertype. + *
  • + * The method has a signature that is override-equivalent to that of + * any public method declared in {@linkplain Object}. + *
+ * + * @author Peter von der Ahé + * @author Joshua Bloch + * @jls 9.6.1.4 @Override + * @since 1.5 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.SOURCE) +public @interface Override { +} diff --git a/src/MapleFE/test/java/openjdk/Override.java.result b/src/MapleFE/test/java/openjdk/Override.java.result new file mode 100644 index 0000000000000000000000000000000000000000..6f3311685210623aa18bcd56ecac4db5821da45d --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Override.java.result @@ -0,0 +1,10 @@ +Matched 5 tokens. +Matched 14 tokens. +Matched 34 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import java.lang.annotation +== Sub Tree == +annotation type : Override diff --git a/src/MapleFE/test/java/openjdk/Package.java b/src/MapleFE/test/java/openjdk/Package.java new file mode 100644 index 0000000000000000000000000000000000000000..55d2ba7df3299d9e49247e451ef828002efa2fbe --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Package.java @@ -0,0 +1,657 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.lang.reflect.AnnotatedElement; +import java.io.InputStream; +import java.util.Enumeration; + +import java.util.StringTokenizer; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.net.MalformedURLException; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; +import java.util.jar.Attributes; +import java.util.jar.Attributes.Name; +import java.util.jar.JarException; +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; + +import sun.net.www.ParseUtil; +import sun.reflect.CallerSensitive; +import dalvik.system.VMRuntime; +import dalvik.system.VMStack; + +import java.lang.annotation.Annotation; + +/** + * {@code Package} objects contain version information + * about the implementation and specification of a Java package. + * This versioning information is retrieved and made available + * by the {@link ClassLoader} instance that + * loaded the class(es). Typically, it is stored in the manifest that is + * distributed with the classes. + * + *

The set of classes that make up the package may implement a + * particular specification and if so the specification title, version number, + * and vendor strings identify that specification. + * An application can ask if the package is + * compatible with a particular version, see the {@link + * #isCompatibleWith isCompatibleWith} + * method for details. + * + *

Specification version numbers use a syntax that consists of nonnegative + * decimal integers separated by periods ".", for example "2.0" or + * "1.2.3.4.5.6.7". This allows an extensible number to be used to represent + * major, minor, micro, etc. versions. The version specification is described + * by the following formal grammar: + *

+ *
+ *
SpecificationVersion: + *
Digits RefinedVersionopt + + *
RefinedVersion: + *
{@code .} Digits + *
{@code .} Digits RefinedVersion + * + *
Digits: + *
Digit + *
Digits + * + *
Digit: + *
any character for which {@link Character#isDigit} returns {@code true}, + * e.g. 0, 1, 2, ... + *
+ *
+ * + *

The implementation title, version, and vendor strings identify an + * implementation and are made available conveniently to enable accurate + * reporting of the packages involved when a problem occurs. The contents + * all three implementation strings are vendor specific. The + * implementation version strings have no specified syntax and should + * only be compared for equality with desired version identifiers. + * + *

Within each {@code ClassLoader} instance all classes from the same + * java package have the same Package object. The static methods allow a package + * to be found by name or the set of all packages known to the current class + * loader to be found. + * + * @see ClassLoader#definePackage + */ +public class Package implements java.lang.reflect.AnnotatedElement { + /** + * Return the name of this package. + * + * @return The fully-qualified name of this package as defined in section 6.5.3 of + * The Java™ Language Specification, + * for example, {@code java.lang} + */ + public String getName() { + return pkgName; + } + + + /** + * Return the title of the specification that this package implements. + * @return the specification title, null is returned if it is not known. + */ + public String getSpecificationTitle() { + return specTitle; + } + + /** + * Returns the version number of the specification + * that this package implements. + * This version string must be a sequence of nonnegative decimal + * integers separated by "."'s and may have leading zeros. + * When version strings are compared the most significant + * numbers are compared. + * @return the specification version, null is returned if it is not known. + */ + public String getSpecificationVersion() { + return specVersion; + } + + /** + * Return the name of the organization, vendor, + * or company that owns and maintains the specification + * of the classes that implement this package. + * @return the specification vendor, null is returned if it is not known. + */ + public String getSpecificationVendor() { + return specVendor; + } + + /** + * Return the title of this package. + * @return the title of the implementation, null is returned if it is not known. + */ + public String getImplementationTitle() { + return implTitle; + } + + /** + * Return the version of this implementation. It consists of any string + * assigned by the vendor of this implementation and does + * not have any particular syntax specified or expected by the Java + * runtime. It may be compared for equality with other + * package version strings used for this implementation + * by this vendor for this package. + * @return the version of the implementation, null is returned if it is not known. + */ + public String getImplementationVersion() { + return implVersion; + } + + /** + * Returns the name of the organization, + * vendor or company that provided this implementation. + * @return the vendor that implemented this package.. + */ + public String getImplementationVendor() { + return implVendor; + } + + /** + * Returns true if this package is sealed. + * + * @return true if the package is sealed, false otherwise + */ + public boolean isSealed() { + return sealBase != null; + } + + /** + * Returns true if this package is sealed with respect to the specified + * code source url. + * + * @param url the code source url + * @return true if this package is sealed with respect to url + */ + public boolean isSealed(URL url) { + return url.equals(sealBase); + } + + /** + * Compare this package's specification version with a + * desired version. It returns true if + * this packages specification version number is greater than or equal + * to the desired version number.

+ * + * Version numbers are compared by sequentially comparing corresponding + * components of the desired and specification strings. + * Each component is converted as a decimal integer and the values + * compared. + * If the specification value is greater than the desired + * value true is returned. If the value is less false is returned. + * If the values are equal the period is skipped and the next pair of + * components is compared. + * + * @param desired the version string of the desired version. + * @return true if this package's version number is greater + * than or equal to the desired version number + * + * @exception NumberFormatException if the desired or current version + * is not of the correct dotted form. + */ + public boolean isCompatibleWith(String desired) + throws NumberFormatException + { + if (specVersion == null || specVersion.length() < 1) { + throw new NumberFormatException("Empty version string"); + } + + String [] sa = specVersion.split("\\.", -1); + int [] si = new int[sa.length]; + for (int i = 0; i < sa.length; i++) { + si[i] = Integer.parseInt(sa[i]); + if (si[i] < 0) + throw NumberFormatException.forInputString("" + si[i]); + } + + String [] da = desired.split("\\.", -1); + int [] di = new int[da.length]; + for (int i = 0; i < da.length; i++) { + di[i] = Integer.parseInt(da[i]); + if (di[i] < 0) + throw NumberFormatException.forInputString("" + di[i]); + } + + int len = Math.max(di.length, si.length); + for (int i = 0; i < len; i++) { + int d = (i < di.length ? di[i] : 0); + int s = (i < si.length ? si[i] : 0); + if (s < d) + return false; + if (s > d) + return true; + } + return true; + } + + /** + * Find a package by name in the callers {@code ClassLoader} instance. + * The callers {@code ClassLoader} instance is used to find the package + * instance corresponding to the named class. If the callers + * {@code ClassLoader} instance is null then the set of packages loaded + * by the system {@code ClassLoader} instance is searched to find the + * named package.

+ * + * Packages have attributes for versions and specifications only if the class + * loader created the package instance with the appropriate attributes. Typically, + * those attributes are defined in the manifests that accompany the classes. + * + * @param name a package name, for example, java.lang. + * @return the package of the requested name. It may be null if no package + * information is available from the archive or codebase. + */ + @CallerSensitive + public static Package getPackage(String name) { + ClassLoader l = VMStack.getCallingClassLoader(); + if (l != null) { + return l.getPackage(name); + } else { + return getSystemPackage(name); + } + } + + /** + * Get all the packages currently known for the caller's {@code ClassLoader} + * instance. Those packages correspond to classes loaded via or accessible by + * name to that {@code ClassLoader} instance. If the caller's + * {@code ClassLoader} instance is the bootstrap {@code ClassLoader} + * instance, which may be represented by {@code null} in some implementations, + * only packages corresponding to classes loaded by the bootstrap + * {@code ClassLoader} instance will be returned. + * + * @return a new array of packages known to the callers {@code ClassLoader} + * instance. An zero length array is returned if none are known. + */ + @CallerSensitive + public static Package[] getPackages() { + ClassLoader l = VMStack.getCallingClassLoader(); + if (l != null) { + return l.getPackages(); + } else { + return getSystemPackages(); + } + } + + /** + * Get the package for the specified class. + * The class's class loader is used to find the package instance + * corresponding to the specified class. If the class loader + * is the bootstrap class loader, which may be represented by + * {@code null} in some implementations, then the set of packages + * loaded by the bootstrap class loader is searched to find the package. + *

+ * Packages have attributes for versions and specifications only + * if the class loader created the package + * instance with the appropriate attributes. Typically those + * attributes are defined in the manifests that accompany + * the classes. + * + * @param c the class to get the package of. + * @return the package of the class. It may be null if no package + * information is available from the archive or codebase. */ + static Package getPackage(Class c) { + String name = c.getName(); + int i = name.lastIndexOf('.'); + if (i != -1) { + name = name.substring(0, i); + ClassLoader cl = c.getClassLoader(); + if (cl != null) { + return cl.getPackage(name); + } else { + return getSystemPackage(name); + } + } else { + return null; + } + } + + /** + * Return the hash code computed from the package name. + * @return the hash code computed from the package name. + */ + public int hashCode(){ + return pkgName.hashCode(); + } + + /** + * Returns the string representation of this Package. + * Its value is the string "package " and the package name. + * If the package title is defined it is appended. + * If the package version is defined it is appended. + * @return the string representation of the package. + */ + public String toString() { + // Android-changed start + // Several apps try to parse the output of toString(). This is a really + // bad idea - especially when there's a Package.getName() function as well as a + // Class.getName() function that can be used instead. + // Starting from the API level 25 the proper output is generated. + final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion(); + if (targetSdkVersion > 0 && targetSdkVersion <= 24) { + return "package " + pkgName; + } + // Android-changed end + + String spec = specTitle; + String ver = specVersion; + if (spec != null && spec.length() > 0) + spec = ", " + spec; + else + spec = ""; + if (ver != null && ver.length() > 0) + ver = ", version " + ver; + else + ver = ""; + return "package " + pkgName + spec + ver; + } + + private Class getPackageInfo() { + if (packageInfo == null) { + try { + packageInfo = Class.forName(pkgName + ".package-info", false, loader); + } catch (ClassNotFoundException ex) { + // store a proxy for the package info that has no annotations + class PackageInfoProxy {} + packageInfo = PackageInfoProxy.class; + } + } + return packageInfo; + } + + /** + * @throws NullPointerException {@inheritDoc} + * @since 1.5 + */ + public A getAnnotation(Class annotationClass) { + return getPackageInfo().getAnnotation(annotationClass); + } + + /** + * {@inheritDoc} + * @throws NullPointerException {@inheritDoc} + * @since 1.5 + */ + @Override + public boolean isAnnotationPresent(Class annotationClass) { + return AnnotatedElement.super.isAnnotationPresent(annotationClass); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @since 1.8 + */ + @Override + public A[] getAnnotationsByType(Class annotationClass) { + return getPackageInfo().getAnnotationsByType(annotationClass); + } + + /** + * @since 1.5 + */ + public Annotation[] getAnnotations() { + return getPackageInfo().getAnnotations(); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @since 1.8 + */ + @Override + public A getDeclaredAnnotation(Class annotationClass) { + return getPackageInfo().getDeclaredAnnotation(annotationClass); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @since 1.8 + */ + @Override + public A[] getDeclaredAnnotationsByType(Class annotationClass) { + return getPackageInfo().getDeclaredAnnotationsByType(annotationClass); + } + + /** + * @since 1.5 + */ + public Annotation[] getDeclaredAnnotations() { + return getPackageInfo().getDeclaredAnnotations(); + } + + /** + * Construct a package instance with the specified version + * information. + * @param name the name of the package + * @param spectitle the title of the specification + * @param specversion the version of the specification + * @param specvendor the organization that maintains the specification + * @param impltitle the title of the implementation + * @param implversion the version of the implementation + * @param implvendor the organization that maintains the implementation + */ + Package(String name, + String spectitle, String specversion, String specvendor, + String impltitle, String implversion, String implvendor, + URL sealbase, ClassLoader loader) + { + pkgName = name; + implTitle = impltitle; + implVersion = implversion; + implVendor = implvendor; + specTitle = spectitle; + specVersion = specversion; + specVendor = specvendor; + sealBase = sealbase; + this.loader = loader; + } + + /* + * Construct a package using the attributes from the specified manifest. + * + * @param name the package name + * @param man the optional manifest for the package + * @param url the optional code source url for the package + */ + private Package(String name, Manifest man, URL url, ClassLoader loader) { + String path = name.replace('.', '/').concat("/"); + String sealed = null; + String specTitle= null; + String specVersion= null; + String specVendor= null; + String implTitle= null; + String implVersion= null; + String implVendor= null; + URL sealBase= null; + Attributes attr = man.getAttributes(path); + if (attr != null) { + specTitle = attr.getValue(Name.SPECIFICATION_TITLE); + specVersion = attr.getValue(Name.SPECIFICATION_VERSION); + specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); + implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); + implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); + implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); + sealed = attr.getValue(Name.SEALED); + } + attr = man.getMainAttributes(); + if (attr != null) { + if (specTitle == null) { + specTitle = attr.getValue(Name.SPECIFICATION_TITLE); + } + if (specVersion == null) { + specVersion = attr.getValue(Name.SPECIFICATION_VERSION); + } + if (specVendor == null) { + specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); + } + if (implTitle == null) { + implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); + } + if (implVersion == null) { + implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); + } + if (implVendor == null) { + implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); + } + if (sealed == null) { + sealed = attr.getValue(Name.SEALED); + } + } + if ("true".equalsIgnoreCase(sealed)) { + sealBase = url; + } + pkgName = name; + this.specTitle = specTitle; + this.specVersion = specVersion; + this.specVendor = specVendor; + this.implTitle = implTitle; + this.implVersion = implVersion; + this.implVendor = implVendor; + this.sealBase = sealBase; + this.loader = loader; + } + + /* + * Returns the loaded system package for the specified name. + */ + static Package getSystemPackage(String name) { + synchronized (pkgs) { + Package pkg = pkgs.get(name); + if (pkg == null) { + name = name.replace('.', '/').concat("/"); + String fn = getSystemPackage0(name); + if (fn != null) { + pkg = defineSystemPackage(name, fn); + } + } + return pkg; + } + } + + /* + * Return an array of loaded system packages. + */ + static Package[] getSystemPackages() { + // First, update the system package map with new package names + String[] names = getSystemPackages0(); + synchronized (pkgs) { + for (int i = 0; i < names.length; i++) { + defineSystemPackage(names[i], getSystemPackage0(names[i])); + } + return pkgs.values().toArray(new Package[pkgs.size()]); + } + } + + private static Package defineSystemPackage(final String iname, + final String fn) + { + return AccessController.doPrivileged(new PrivilegedAction() { + public Package run() { + String name = iname; + // Get the cached code source url for the file name + URL url = urls.get(fn); + if (url == null) { + // URL not found, so create one + File file = new File(fn); + try { + url = ParseUtil.fileToEncodedURL(file); + } catch (MalformedURLException e) { + } + if (url != null) { + urls.put(fn, url); + // If loading a JAR file, then also cache the manifest + if (file.isFile()) { + mans.put(fn, loadManifest(fn)); + } + } + } + // Convert to "."-separated package name + name = name.substring(0, name.length() - 1).replace('/', '.'); + Package pkg; + Manifest man = mans.get(fn); + if (man != null) { + pkg = new Package(name, man, url, null); + } else { + pkg = new Package(name, null, null, null, + null, null, null, null, null); + } + pkgs.put(name, pkg); + return pkg; + } + }); + } + + /* + * Returns the Manifest for the specified JAR file name. + */ + private static Manifest loadManifest(String fn) { + try (FileInputStream fis = new FileInputStream(fn); + JarInputStream jis = new JarInputStream(fis, false)) + { + return jis.getManifest(); + } catch (IOException e) { + return null; + } + } + + // The map of loaded system packages + private static Map pkgs = new HashMap<>(31); + + // Maps each directory or zip file name to its corresponding url + private static Map urls = new HashMap<>(10); + + // Maps each code source url for a jar file to its manifest + private static Map mans = new HashMap<>(10); + + private static native String getSystemPackage0(String name); + private static native String[] getSystemPackages0(); + + /* + * Private storage for the package name and attributes. + */ + private final String pkgName; + private final String specTitle; + private final String specVersion; + private final String specVendor; + private final String implTitle; + private final String implVersion; + private final String implVendor; + private final URL sealBase; + private transient final ClassLoader loader; + private transient Class packageInfo; +} diff --git a/src/MapleFE/test/java/openjdk/Package.java.result b/src/MapleFE/test/java/openjdk/Package.java.result new file mode 100644 index 0000000000000000000000000000000000000000..018c563d1a7ccc902d87058ea27f9426d1b2a4c8 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Package.java.result @@ -0,0 +1,367 @@ +Matched 5 tokens. +Matched 14 tokens. +Matched 21 tokens. +Matched 28 tokens. +Matched 35 tokens. +Matched 42 tokens. +Matched 49 tokens. +Matched 56 tokens. +Matched 63 tokens. +Matched 70 tokens. +Matched 77 tokens. +Matched 84 tokens. +Matched 91 tokens. +Matched 100 tokens. +Matched 109 tokens. +Matched 118 tokens. +Matched 129 tokens. +Matched 138 tokens. +Matched 145 tokens. +Matched 152 tokens. +Matched 159 tokens. +Matched 168 tokens. +Matched 175 tokens. +Matched 182 tokens. +Matched 189 tokens. +Matched 198 tokens. +Matched 2146 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import java.lang.reflect.AnnotatedElement +== Sub Tree == +import java.io.InputStream +== Sub Tree == +import java.util.Enumeration +== Sub Tree == +import java.util.StringTokenizer +== Sub Tree == +import java.io.File +== Sub Tree == +import java.io.FileInputStream +== Sub Tree == +import java.io.FileNotFoundException +== Sub Tree == +import java.io.IOException +== Sub Tree == +import java.net.URL +== Sub Tree == +import java.net.MalformedURLException +== Sub Tree == +import java.security.AccessController +== Sub Tree == +import java.security.PrivilegedAction +== Sub Tree == +import java.util.jar.JarInputStream +== Sub Tree == +import java.util.jar.Manifest +== Sub Tree == +import java.util.jar.Attributes +== Sub Tree == +import java.util.jar.Attributes.Name +== Sub Tree == +import java.util.jar.JarException +== Sub Tree == +import java.util.Map +== Sub Tree == +import java.util.HashMap +== Sub Tree == +import java.util.Iterator +== Sub Tree == +import sun.net.www.ParseUtil +== Sub Tree == +import sun.reflect.CallerSensitive +== Sub Tree == +import dalvik.system.VMRuntime +== Sub Tree == +import dalvik.system.VMStack +== Sub Tree == +import java.lang.annotation.Annotation +== Sub Tree == +class Package + Fields: + pkgs=new HashMap(31) urls=new HashMap(10) mans=new HashMap(10) pkgName specTitle specVersion specVendor implTitle implVersion implVendor sealBase loader packageInfo + Instance Initializer: + Constructors: + constructor Package(name,spectitle,specversion,specvendor,impltitle,implversion,implvendor,sealbase,loader) throws: + pkgName Assign name + implTitle Assign impltitle + implVersion Assign implversion + implVendor Assign implvendor + specTitle Assign spectitle + specVersion Assign specversion + specVendor Assign specvendor + sealBase Assign sealbase + this.loader Assign loader + constructor Package(name,man,url,loader) throws: + Decl: path=name.replace(.,/).concat("/") + Decl: sealed=null + Decl: specTitle=null + Decl: specVersion=null + Decl: specVendor=null + Decl: implTitle=null + Decl: implVersion=null + Decl: implVendor=null + Decl: sealBase=null + Decl: attr=man.getAttributes(path) + cond-branch cond:attr NE null + true branch : + specTitle Assign attr.getValue(Name.SPECIFICATION_TITLE) + specVersion Assign attr.getValue(Name.SPECIFICATION_VERSION) + specVendor Assign attr.getValue(Name.SPECIFICATION_VENDOR) + implTitle Assign attr.getValue(Name.IMPLEMENTATION_TITLE) + implVersion Assign attr.getValue(Name.IMPLEMENTATION_VERSION) + implVendor Assign attr.getValue(Name.IMPLEMENTATION_VENDOR) + sealed Assign attr.getValue(Name.SEALED) + false branch : + + attr Assign man.getMainAttributes() + cond-branch cond:attr NE null + true branch : + cond-branch cond:specTitle EQ null + true branch : + specTitle Assign attr.getValue(Name.SPECIFICATION_TITLE) + false branch : + + cond-branch cond:specVersion EQ null + true branch : + specVersion Assign attr.getValue(Name.SPECIFICATION_VERSION) + false branch : + + cond-branch cond:specVendor EQ null + true branch : + specVendor Assign attr.getValue(Name.SPECIFICATION_VENDOR) + false branch : + + cond-branch cond:implTitle EQ null + true branch : + implTitle Assign attr.getValue(Name.IMPLEMENTATION_TITLE) + false branch : + + cond-branch cond:implVersion EQ null + true branch : + implVersion Assign attr.getValue(Name.IMPLEMENTATION_VERSION) + false branch : + + cond-branch cond:implVendor EQ null + true branch : + implVendor Assign attr.getValue(Name.IMPLEMENTATION_VENDOR) + false branch : + + cond-branch cond:sealed EQ null + true branch : + sealed Assign attr.getValue(Name.SEALED) + false branch : + + false branch : + + cond-branch cond:"true".equalsIgnoreCase(sealed) + true branch : + sealBase Assign url + false branch : + + pkgName Assign name + this.specTitle Assign specTitle + this.specVersion Assign specVersion + this.specVendor Assign specVendor + this.implTitle Assign implTitle + this.implVersion Assign implVersion + this.implVendor Assign implVendor + this.sealBase Assign sealBase + this.loader Assign loader + Methods: + func getName() throws: + return pkgName + func getSpecificationTitle() throws: + return specTitle + func getSpecificationVersion() throws: + return specVersion + func getSpecificationVendor() throws: + return specVendor + func getImplementationTitle() throws: + return implTitle + func getImplementationVersion() throws: + return implVersion + func getImplementationVendor() throws: + return implVendor + func isSealed() throws: + return sealBase NE null + func isSealed(url) throws: + return url.equals(sealBase) + func isCompatibleWith(desired) throws: NumberFormatException + cond-branch cond:specVersion EQ null Lor specVersion.length() LT 1 + true branch : + new NumberFormatException("Empty version string") + false branch : + + Decl: sa=specVersion.split("\\.",-1) + Decl: si= + for ( ) + Assign Integer.parseInt(sa,i) + cond-branch cond: LT 0 + true branch : + NumberFormatException.forInputString("" Add ) false branch : + + + Decl: da=desired.split("\\.",-1) + Decl: di= + for ( ) + Assign Integer.parseInt(da,i) + cond-branch cond: LT 0 + true branch : + NumberFormatException.forInputString("" Add ) false branch : + + + Decl: len=Math.max(di.length,si.length) + for ( ) + Decl: d=() + Decl: s=() + cond-branch cond:s LT d + true branch : + return false false branch : + + cond-branch cond:s GT d + true branch : + return true false branch : + + + return true + func getPackage(name) throws: + Decl: l=VMStack.getCallingClassLoader() + cond-branch cond:l NE null + true branch : + return l.getPackage(name) + false branch : + return getSystemPackage(name) + + func getPackages() throws: + Decl: l=VMStack.getCallingClassLoader() + cond-branch cond:l NE null + true branch : + return l.getPackages() + false branch : + return getSystemPackages() + + func getPackage(c) throws: + Decl: name=c.getName() + Decl: i=name.lastIndexOf(.) + cond-branch cond:i NE -1 + true branch : + name Assign name.substring(0,i) + Decl: cl=c.getClassLoader() + cond-branch cond:cl NE null + true branch : + return cl.getPackage(name) + false branch : + return getSystemPackage(name) + + false branch : + return null + + func hashCode() throws: + return pkgName.hashCode() + func toString() throws: + Decl: targetSdkVersion=VMRuntime.getRuntime().getTargetSdkVersion() + cond-branch cond:targetSdkVersion GT 0 Land targetSdkVersion LE 24 + true branch : + return "package " Add pkgName + false branch : + + Decl: spec=specTitle + Decl: ver=specVersion + cond-branch cond:spec NE null Land spec.length() GT 0 + true branch : + spec Assign ", " Add spec false branch : + spec Assign "" + cond-branch cond:ver NE null Land ver.length() GT 0 + true branch : + ver Assign ", version " Add ver false branch : + ver Assign "" + return "package " Add pkgName Add spec Add ver + func getPackageInfo() throws: + cond-branch cond:packageInfo EQ null + true branch : + packageInfo Assign Class.forName(pkgName Add ".package-info",false,loader) + + ClassNotFoundException + ex + class PackageInfoProxy + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + + packageInfo Assign PackageInfoProxy + + false branch : + + return packageInfo + func getAnnotation(annotationClass) throws: + return getPackageInfo().getAnnotation(annotationClass) + func isAnnotationPresent(annotationClass) throws: + return + func getAnnotationsByType(annotationClass) throws: + return getPackageInfo().getAnnotationsByType(annotationClass) + func getAnnotations() throws: + return getPackageInfo().getAnnotations() + func getDeclaredAnnotation(annotationClass) throws: + return getPackageInfo().getDeclaredAnnotation(annotationClass) + func getDeclaredAnnotationsByType(annotationClass) throws: + return getPackageInfo().getDeclaredAnnotationsByType(annotationClass) + func getDeclaredAnnotations() throws: + return getPackageInfo().getDeclaredAnnotations() + func getSystemPackage(name) throws: + Decl: pkg=pkgs.get(name) + cond-branch cond:pkg EQ null + true branch : + name Assign name.replace(.,/).concat("/") + Decl: fn=getSystemPackage0(name) + cond-branch cond:fn NE null + true branch : + pkg Assign defineSystemPackage(name,fn) + false branch : + + false branch : + + return pkg + + func getSystemPackages() throws: + Decl: names=getSystemPackages0() + for ( ) + defineSystemPackage(names,i,getSystemPackage0(names,i)) + + return pkgs.values().toArray(Package,pkgs.size()) + + func defineSystemPackage(iname,fn) throws: + return AccessController.doPrivileged(new PrivilegedAction()) + func loadManifest(fn) throws: + FileInputStream + fis + new FileInputStream(fn) + JarInputStream + jis + new JarInputStream(fis,false) + return jis.getManifest() + + IOException + e + return null + + func getSystemPackage0(name) throws: + func getSystemPackages0() throws: + LocalClasses: + LocalInterfaces: + +Identifier:FileInputStream has no decl. +Identifier:fis has no decl. +UserType:FileInputStream has no decl. +Identifier:JarInputStream has no decl. +Identifier:jis has no decl. +UserType:JarInputStream has no decl. +Identifier:fis has no decl. +Identifier:IOException has no decl. +Identifier:e has no decl. diff --git a/src/MapleFE/test/java/openjdk/Process.java b/src/MapleFE/test/java/openjdk/Process.java new file mode 100644 index 0000000000000000000000000000000000000000..4e94538246540920f91e8de412274c50a19b18ce --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Process.java @@ -0,0 +1,265 @@ +/* + * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.io.*; +import java.util.concurrent.TimeUnit; + +/** + * The {@link ProcessBuilder#start()} and + * {@link Runtime#exec(String[],String[],File) Runtime.exec} + * methods create a native process and return an instance of a + * subclass of {@code Process} that can be used to control the process + * and obtain information about it. The class {@code Process} + * provides methods for performing input from the process, performing + * output to the process, waiting for the process to complete, + * checking the exit status of the process, and destroying (killing) + * the process. + * + *

The methods that create processes may not work well for special + * processes on certain native platforms, such as native windowing + * processes, daemon processes, Win16/DOS processes on Microsoft + * Windows, or shell scripts. + * + *

By default, the created subprocess does not have its own terminal + * or console. All its standard I/O (i.e. stdin, stdout, stderr) + * operations will be redirected to the parent process, where they can + * be accessed via the streams obtained using the methods + * {@link #getOutputStream()}, + * {@link #getInputStream()}, and + * {@link #getErrorStream()}. + * The parent process uses these streams to feed input to and get output + * from the subprocess. Because some native platforms only provide + * limited buffer size for standard input and output streams, failure + * to promptly write the input stream or read the output stream of + * the subprocess may cause the subprocess to block, or even deadlock. + * + *

Where desired, + * subprocess I/O can also be redirected + * using methods of the {@link ProcessBuilder} class. + * + *

The subprocess is not killed when there are no more references to + * the {@code Process} object, but rather the subprocess + * continues executing asynchronously. + * + *

There is no requirement that a process represented by a {@code + * Process} object execute asynchronously or concurrently with respect + * to the Java process that owns the {@code Process} object. + * + *

As of 1.5, {@link ProcessBuilder#start()} is the preferred way + * to create a {@code Process}. + * + * @since JDK1.0 + */ +public abstract class Process { + /** + * Returns the output stream connected to the normal input of the + * subprocess. Output to the stream is piped into the standard + * input of the process represented by this {@code Process} object. + * + *

If the standard input of the subprocess has been redirected using + * {@link ProcessBuilder#redirectInput(Redirect) + * ProcessBuilder.redirectInput} + * then this method will return a + * null output stream. + * + *

Implementation note: It is a good idea for the returned + * output stream to be buffered. + * + * @return the output stream connected to the normal input of the + * subprocess + */ + public abstract OutputStream getOutputStream(); + + /** + * Returns the input stream connected to the normal output of the + * subprocess. The stream obtains data piped from the standard + * output of the process represented by this {@code Process} object. + * + *

If the standard output of the subprocess has been redirected using + * {@link ProcessBuilder#redirectOutput(Redirect) + * ProcessBuilder.redirectOutput} + * then this method will return a + * null input stream. + * + *

Otherwise, if the standard error of the subprocess has been + * redirected using + * {@link ProcessBuilder#redirectErrorStream(boolean) + * ProcessBuilder.redirectErrorStream} + * then the input stream returned by this method will receive the + * merged standard output and the standard error of the subprocess. + * + *

Implementation note: It is a good idea for the returned + * input stream to be buffered. + * + * @return the input stream connected to the normal output of the + * subprocess + */ + public abstract InputStream getInputStream(); + + /** + * Returns the input stream connected to the error output of the + * subprocess. The stream obtains data piped from the error output + * of the process represented by this {@code Process} object. + * + *

If the standard error of the subprocess has been redirected using + * {@link ProcessBuilder#redirectError(Redirect) + * ProcessBuilder.redirectError} or + * {@link ProcessBuilder#redirectErrorStream(boolean) + * ProcessBuilder.redirectErrorStream} + * then this method will return a + * null input stream. + * + *

Implementation note: It is a good idea for the returned + * input stream to be buffered. + * + * @return the input stream connected to the error output of + * the subprocess + */ + public abstract InputStream getErrorStream(); + + /** + * Causes the current thread to wait, if necessary, until the + * process represented by this {@code Process} object has + * terminated. This method returns immediately if the subprocess + * has already terminated. If the subprocess has not yet + * terminated, the calling thread will be blocked until the + * subprocess exits. + * + * @return the exit value of the subprocess represented by this + * {@code Process} object. By convention, the value + * {@code 0} indicates normal termination. + * @throws InterruptedException if the current thread is + * {@linkplain Thread#interrupt() interrupted} by another + * thread while it is waiting, then the wait is ended and + * an {@link InterruptedException} is thrown. + */ + public abstract int waitFor() throws InterruptedException; + + /** + * Causes the current thread to wait, if necessary, until the + * subprocess represented by this {@code Process} object has + * terminated, or the specified waiting time elapses. + * + *

If the subprocess has already terminated then this method returns + * immediately with the value {@code true}. If the process has not + * terminated and the timeout value is less than, or equal to, zero, then + * this method returns immediately with the value {@code false}. + * + *

The default implementation of this methods polls the {@code exitValue} + * to check if the process has terminated. Concrete implementations of this + * class are strongly encouraged to override this method with a more + * efficient implementation. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the {@code timeout} argument + * @return {@code true} if the subprocess has exited and {@code false} if + * the waiting time elapsed before the subprocess has exited. + * @throws InterruptedException if the current thread is interrupted + * while waiting. + * @throws NullPointerException if unit is null + * @since 1.8 + */ + public boolean waitFor(long timeout, TimeUnit unit) + throws InterruptedException + { + long startTime = System.nanoTime(); + long rem = unit.toNanos(timeout); + + do { + try { + exitValue(); + return true; + } catch(IllegalThreadStateException ex) { + if (rem > 0) + Thread.sleep( + Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100)); + } + rem = unit.toNanos(timeout) - (System.nanoTime() - startTime); + } while (rem > 0); + return false; + } + + /** + * Returns the exit value for the subprocess. + * + * @return the exit value of the subprocess represented by this + * {@code Process} object. By convention, the value + * {@code 0} indicates normal termination. + * @throws IllegalThreadStateException if the subprocess represented + * by this {@code Process} object has not yet terminated + */ + public abstract int exitValue(); + + /** + * Kills the subprocess. Whether the subprocess represented by this + * {@code Process} object is forcibly terminated or not is + * implementation dependent. + */ + public abstract void destroy(); + + /** + * Kills the subprocess. The subprocess represented by this + * {@code Process} object is forcibly terminated. + * + *

The default implementation of this method invokes {@link #destroy} + * and so may not forcibly terminate the process. Concrete implementations + * of this class are strongly encouraged to override this method with a + * compliant implementation. Invoking this method on {@code Process} + * objects returned by {@link ProcessBuilder#start} and + * {@link Runtime#exec} will forcibly terminate the process. + * + *

Note: The subprocess may not terminate immediately. + * i.e. {@code isAlive()} may return true for a brief period + * after {@code destroyForcibly()} is called. This method + * may be chained to {@code waitFor()} if needed. + * + * @return the {@code Process} object representing the + * subprocess to be forcibly destroyed. + * @since 1.8 + */ + public Process destroyForcibly() { + destroy(); + return this; + } + + /** + * Tests whether the subprocess represented by this {@code Process} is + * alive. + * + * @return {@code true} if the subprocess represented by this + * {@code Process} object has not yet terminated. + * @since 1.8 + */ + public boolean isAlive() { + try { + exitValue(); + return false; + } catch(IllegalThreadStateException e) { + return true; + } + } +} diff --git a/src/MapleFE/test/java/openjdk/Process.java.result b/src/MapleFE/test/java/openjdk/Process.java.result new file mode 100644 index 0000000000000000000000000000000000000000..e3747d710b6c90f237343ebdfc614d92287055b2 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Process.java.result @@ -0,0 +1,56 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 21 tokens. +Matched 223 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import java.io +== Sub Tree == +import java.util.concurrent.TimeUnit +== Sub Tree == +class Process + Fields: + + Instance Initializer: + Constructors: + Methods: + func getOutputStream() throws: + func getInputStream() throws: + func getErrorStream() throws: + func waitFor() throws: InterruptedException + func waitFor(timeout,unit) throws: InterruptedException + Decl: startTime=System.nanoTime() + Decl: rem=unit.toNanos(timeout) + do exitValue() + return true + + IllegalThreadStateException + ex + cond-branch cond:rem GT 0 + true branch : + Thread.sleep(Math.min(TimeUnit.NANOSECONDS.toMillis(rem) Add 1,100)) false branch : + + + rem Assign unit.toNanos(timeout) Sub (System.nanoTime() Sub startTime) +while rem GT 0 + return false + func exitValue() throws: + func destroy() throws: + func destroyForcibly() throws: + destroy() + return this + func isAlive() throws: + exitValue() + return false + + IllegalThreadStateException + e + return true + + LocalClasses: + LocalInterfaces: + +Identifier:IllegalThreadStateException has no decl. +Identifier:e has no decl. diff --git a/src/MapleFE/test/java/openjdk/ProcessBuilder.java b/src/MapleFE/test/java/openjdk/ProcessBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..0c892c2358d7474157290aa1e7e6f994987972a2 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/ProcessBuilder.java @@ -0,0 +1,1055 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * This class is used to create operating system processes. + * + *

Each {@code ProcessBuilder} instance manages a collection + * of process attributes. The {@link #start()} method creates a new + * {@link Process} instance with those attributes. The {@link + * #start()} method can be invoked repeatedly from the same instance + * to create new subprocesses with identical or related attributes. + * + *

Each process builder manages these process attributes: + * + *

+ * + *

Modifying a process builder's attributes will affect processes + * subsequently started by that object's {@link #start()} method, but + * will never affect previously started processes or the Java process + * itself. + * + *

Most error checking is performed by the {@link #start()} method. + * It is possible to modify the state of an object so that {@link + * #start()} will fail. For example, setting the command attribute to + * an empty list will not throw an exception unless {@link #start()} + * is invoked. + * + *

Note that this class is not synchronized. + * If multiple threads access a {@code ProcessBuilder} instance + * concurrently, and at least one of the threads modifies one of the + * attributes structurally, it must be synchronized externally. + * + *

Starting a new process which uses the default working directory + * and environment is easy: + * + *

 {@code
+ * Process p = new ProcessBuilder("myCommand", "myArg").start();
+ * }
+ * + *

Here is an example that starts a process with a modified working + * directory and environment, and redirects standard output and error + * to be appended to a log file: + * + *

 {@code
+ * ProcessBuilder pb =
+ *   new ProcessBuilder("myCommand", "myArg1", "myArg2");
+ * Map env = pb.environment();
+ * env.put("VAR1", "myValue");
+ * env.remove("OTHERVAR");
+ * env.put("VAR2", env.get("VAR1") + "suffix");
+ * pb.directory(new File("myDir"));
+ * File log = new File("log");
+ * pb.redirectErrorStream(true);
+ * pb.redirectOutput(Redirect.appendTo(log));
+ * Process p = pb.start();
+ * assert pb.redirectInput() == Redirect.PIPE;
+ * assert pb.redirectOutput().file() == log;
+ * assert p.getInputStream().read() == -1;
+ * }
+ * + *

To start a process with an explicit set of environment + * variables, first call {@link java.util.Map#clear() Map.clear()} + * before adding environment variables. + * + * @author Martin Buchholz + * @since 1.5 + */ + +public final class ProcessBuilder +{ + private List command; + private File directory; + private Map environment; + private boolean redirectErrorStream; + private Redirect[] redirects; + + /** + * Constructs a process builder with the specified operating + * system program and arguments. This constructor does not + * make a copy of the {@code command} list. Subsequent + * updates to the list will be reflected in the state of the + * process builder. It is not checked whether + * {@code command} corresponds to a valid operating system + * command. + * + * @param command the list containing the program and its arguments + * @throws NullPointerException if the argument is null + */ + public ProcessBuilder(List command) { + if (command == null) + throw new NullPointerException(); + this.command = command; + } + + /** + * Constructs a process builder with the specified operating + * system program and arguments. This is a convenience + * constructor that sets the process builder's command to a string + * list containing the same strings as the {@code command} + * array, in the same order. It is not checked whether + * {@code command} corresponds to a valid operating system + * command. + * + * @param command a string array containing the program and its arguments + */ + public ProcessBuilder(String... command) { + this.command = new ArrayList<>(command.length); + for (String arg : command) + this.command.add(arg); + } + + /** + * Sets this process builder's operating system program and + * arguments. This method does not make a copy of the + * {@code command} list. Subsequent updates to the list will + * be reflected in the state of the process builder. It is not + * checked whether {@code command} corresponds to a valid + * operating system command. + * + * @param command the list containing the program and its arguments + * @return this process builder + * + * @throws NullPointerException if the argument is null + */ + public ProcessBuilder command(List command) { + if (command == null) + throw new NullPointerException(); + this.command = command; + return this; + } + + /** + * Sets this process builder's operating system program and + * arguments. This is a convenience method that sets the command + * to a string list containing the same strings as the + * {@code command} array, in the same order. It is not + * checked whether {@code command} corresponds to a valid + * operating system command. + * + * @param command a string array containing the program and its arguments + * @return this process builder + */ + public ProcessBuilder command(String... command) { + this.command = new ArrayList<>(command.length); + for (String arg : command) + this.command.add(arg); + return this; + } + + /** + * Returns this process builder's operating system program and + * arguments. The returned list is not a copy. Subsequent + * updates to the list will be reflected in the state of this + * process builder. + * + * @return this process builder's program and its arguments + */ + public List command() { + return command; + } + + /** + * Returns a string map view of this process builder's environment. + * + * Whenever a process builder is created, the environment is + * initialized to a copy of the current process environment (see + * {@link System#getenv()}). Subprocesses subsequently started by + * this object's {@link #start()} method will use this map as + * their environment. + * + *

The returned object may be modified using ordinary {@link + * java.util.Map Map} operations. These modifications will be + * visible to subprocesses started via the {@link #start()} + * method. Two {@code ProcessBuilder} instances always + * contain independent process environments, so changes to the + * returned map will never be reflected in any other + * {@code ProcessBuilder} instance or the values returned by + * {@link System#getenv System.getenv}. + * + *

If the system does not support environment variables, an + * empty map is returned. + * + *

The returned map does not permit null keys or values. + * Attempting to insert or query the presence of a null key or + * value will throw a {@link NullPointerException}. + * Attempting to query the presence of a key or value which is not + * of type {@link String} will throw a {@link ClassCastException}. + * + *

The behavior of the returned map is system-dependent. A + * system may not allow modifications to environment variables or + * may forbid certain variable names or values. For this reason, + * attempts to modify the map may fail with + * {@link UnsupportedOperationException} or + * {@link IllegalArgumentException} + * if the modification is not permitted by the operating system. + * + *

Since the external format of environment variable names and + * values is system-dependent, there may not be a one-to-one + * mapping between them and Java's Unicode strings. Nevertheless, + * the map is implemented in such a way that environment variables + * which are not modified by Java code will have an unmodified + * native representation in the subprocess. + * + *

The returned map and its collection views may not obey the + * general contract of the {@link Object#equals} and + * {@link Object#hashCode} methods. + * + *

The returned map is typically case-sensitive on all platforms. + * + *

If a security manager exists, its + * {@link SecurityManager#checkPermission checkPermission} method + * is called with a + * {@link RuntimePermission}{@code ("getenv.*")} permission. + * This may result in a {@link SecurityException} being thrown. + * + *

When passing information to a Java subprocess, + * system properties + * are generally preferred over environment variables. + * + * @return this process builder's environment + * + * @throws SecurityException + * if a security manager exists and its + * {@link SecurityManager#checkPermission checkPermission} + * method doesn't allow access to the process environment + * + * @see Runtime#exec(String[],String[],java.io.File) + * @see System#getenv() + */ + public Map environment() { + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkPermission(new RuntimePermission("getenv.*")); + + if (environment == null) + environment = ProcessEnvironment.environment(); + + assert environment != null; + + return environment; + } + + // Only for use by Runtime.exec(...envp...) + ProcessBuilder environment(String[] envp) { + assert environment == null; + if (envp != null) { + environment = ProcessEnvironment.emptyEnvironment(envp.length); + assert environment != null; + + for (String envstring : envp) { + // Before 1.5, we blindly passed invalid envstrings + // to the child process. + // We would like to throw an exception, but do not, + // for compatibility with old broken code. + + // Silently discard any trailing junk. + if (envstring.indexOf((int) '\u0000') != -1) + envstring = envstring.replaceFirst("\u0000.*", ""); + + int eqlsign = + envstring.indexOf('=', ProcessEnvironment.MIN_NAME_LENGTH); + // Silently ignore envstrings lacking the required `='. + if (eqlsign != -1) + environment.put(envstring.substring(0,eqlsign), + envstring.substring(eqlsign+1)); + } + } + return this; + } + + /** + * Returns this process builder's working directory. + * + * Subprocesses subsequently started by this object's {@link + * #start()} method will use this as their working directory. + * The returned value may be {@code null} -- this means to use + * the working directory of the current Java process, usually the + * directory named by the system property {@code user.dir}, + * as the working directory of the child process. + * + * @return this process builder's working directory + */ + public File directory() { + return directory; + } + + /** + * Sets this process builder's working directory. + * + * Subprocesses subsequently started by this object's {@link + * #start()} method will use this as their working directory. + * The argument may be {@code null} -- this means to use the + * working directory of the current Java process, usually the + * directory named by the system property {@code user.dir}, + * as the working directory of the child process. + * + * @param directory the new working directory + * @return this process builder + */ + public ProcessBuilder directory(File directory) { + this.directory = directory; + return this; + } + + // ---------------- I/O Redirection ---------------- + + /** + * Implements a null input stream. + */ + static class NullInputStream extends InputStream { + static final NullInputStream INSTANCE = new NullInputStream(); + private NullInputStream() {} + public int read() { return -1; } + public int available() { return 0; } + } + + /** + * Implements a null output stream. + */ + static class NullOutputStream extends OutputStream { + static final NullOutputStream INSTANCE = new NullOutputStream(); + private NullOutputStream() {} + public void write(int b) throws IOException { + throw new IOException("Stream closed"); + } + } + + /** + * Represents a source of subprocess input or a destination of + * subprocess output. + * + * Each {@code Redirect} instance is one of the following: + * + *

    + *
  • the special value {@link #PIPE Redirect.PIPE} + *
  • the special value {@link #INHERIT Redirect.INHERIT} + *
  • a redirection to read from a file, created by an invocation of + * {@link Redirect#from Redirect.from(File)} + *
  • a redirection to write to a file, created by an invocation of + * {@link Redirect#to Redirect.to(File)} + *
  • a redirection to append to a file, created by an invocation of + * {@link Redirect#appendTo Redirect.appendTo(File)} + *
+ * + *

Each of the above categories has an associated unique + * {@link Type Type}. + * + * @since 1.7 + */ + public static abstract class Redirect { + /** + * The type of a {@link Redirect}. + */ + public enum Type { + /** + * The type of {@link Redirect#PIPE Redirect.PIPE}. + */ + PIPE, + + /** + * The type of {@link Redirect#INHERIT Redirect.INHERIT}. + */ + INHERIT, + + /** + * The type of redirects returned from + * {@link Redirect#from Redirect.from(File)}. + */ + READ, + + /** + * The type of redirects returned from + * {@link Redirect#to Redirect.to(File)}. + */ + WRITE, + + /** + * The type of redirects returned from + * {@link Redirect#appendTo Redirect.appendTo(File)}. + */ + APPEND + }; + + /** + * Returns the type of this {@code Redirect}. + * @return the type of this {@code Redirect} + */ + public abstract Type type(); + + /** + * Indicates that subprocess I/O will be connected to the + * current Java process over a pipe. + * + * This is the default handling of subprocess standard I/O. + * + *

It will always be true that + *

 {@code
+         * Redirect.PIPE.file() == null &&
+         * Redirect.PIPE.type() == Redirect.Type.PIPE
+         * }
+ */ + public static final Redirect PIPE = new Redirect() { + public Type type() { return Type.PIPE; } + public String toString() { return type().toString(); }}; + + /** + * Indicates that subprocess I/O source or destination will be the + * same as those of the current process. This is the normal + * behavior of most operating system command interpreters (shells). + * + *

It will always be true that + *

 {@code
+         * Redirect.INHERIT.file() == null &&
+         * Redirect.INHERIT.type() == Redirect.Type.INHERIT
+         * }
+ */ + public static final Redirect INHERIT = new Redirect() { + public Type type() { return Type.INHERIT; } + public String toString() { return type().toString(); }}; + + /** + * Returns the {@link File} source or destination associated + * with this redirect, or {@code null} if there is no such file. + * + * @return the file associated with this redirect, + * or {@code null} if there is no such file + */ + public File file() { return null; } + + /** + * When redirected to a destination file, indicates if the output + * is to be written to the end of the file. + */ + boolean append() { + throw new UnsupportedOperationException(); + } + + /** + * Returns a redirect to read from the specified file. + * + *

It will always be true that + *

 {@code
+         * Redirect.from(file).file() == file &&
+         * Redirect.from(file).type() == Redirect.Type.READ
+         * }
+ * + * @param file The {@code File} for the {@code Redirect}. + * @throws NullPointerException if the specified file is null + * @return a redirect to read from the specified file + */ + public static Redirect from(final File file) { + if (file == null) + throw new NullPointerException(); + return new Redirect() { + public Type type() { return Type.READ; } + public File file() { return file; } + public String toString() { + return "redirect to read from file \"" + file + "\""; + } + }; + } + + /** + * Returns a redirect to write to the specified file. + * If the specified file exists when the subprocess is started, + * its previous contents will be discarded. + * + *

It will always be true that + *

 {@code
+         * Redirect.to(file).file() == file &&
+         * Redirect.to(file).type() == Redirect.Type.WRITE
+         * }
+ * + * @param file The {@code File} for the {@code Redirect}. + * @throws NullPointerException if the specified file is null + * @return a redirect to write to the specified file + */ + public static Redirect to(final File file) { + if (file == null) + throw new NullPointerException(); + return new Redirect() { + public Type type() { return Type.WRITE; } + public File file() { return file; } + public String toString() { + return "redirect to write to file \"" + file + "\""; + } + boolean append() { return false; } + }; + } + + /** + * Returns a redirect to append to the specified file. + * Each write operation first advances the position to the + * end of the file and then writes the requested data. + * Whether the advancement of the position and the writing + * of the data are done in a single atomic operation is + * system-dependent and therefore unspecified. + * + *

It will always be true that + *

 {@code
+         * Redirect.appendTo(file).file() == file &&
+         * Redirect.appendTo(file).type() == Redirect.Type.APPEND
+         * }
+ * + * @param file The {@code File} for the {@code Redirect}. + * @throws NullPointerException if the specified file is null + * @return a redirect to append to the specified file + */ + public static Redirect appendTo(final File file) { + if (file == null) + throw new NullPointerException(); + return new Redirect() { + public Type type() { return Type.APPEND; } + public File file() { return file; } + public String toString() { + return "redirect to append to file \"" + file + "\""; + } + boolean append() { return true; } + }; + } + + /** + * Compares the specified object with this {@code Redirect} for + * equality. Returns {@code true} if and only if the two + * objects are identical or both objects are {@code Redirect} + * instances of the same type associated with non-null equal + * {@code File} instances. + */ + public boolean equals(Object obj) { + if (obj == this) + return true; + if (! (obj instanceof Redirect)) + return false; + Redirect r = (Redirect) obj; + if (r.type() != this.type()) + return false; + assert this.file() != null; + return this.file().equals(r.file()); + } + + /** + * Returns a hash code value for this {@code Redirect}. + * @return a hash code value for this {@code Redirect} + */ + public int hashCode() { + File file = file(); + if (file == null) + return super.hashCode(); + else + return file.hashCode(); + } + + /** + * No public constructors. Clients must use predefined + * static {@code Redirect} instances or factory methods. + */ + private Redirect() {} + } + + private Redirect[] redirects() { + if (redirects == null) + redirects = new Redirect[] { + Redirect.PIPE, Redirect.PIPE, Redirect.PIPE + }; + return redirects; + } + + /** + * Sets this process builder's standard input source. + * + * Subprocesses subsequently started by this object's {@link #start()} + * method obtain their standard input from this source. + * + *

If the source is {@link Redirect#PIPE Redirect.PIPE} + * (the initial value), then the standard input of a + * subprocess can be written to using the output stream + * returned by {@link Process#getOutputStream()}. + * If the source is set to any other value, then + * {@link Process#getOutputStream()} will return a + * null output stream. + * + * @param source the new standard input source + * @return this process builder + * @throws IllegalArgumentException + * if the redirect does not correspond to a valid source + * of data, that is, has type + * {@link Redirect.Type#WRITE WRITE} or + * {@link Redirect.Type#APPEND APPEND} + * @since 1.7 + */ + public ProcessBuilder redirectInput(Redirect source) { + if (source.type() == Redirect.Type.WRITE || + source.type() == Redirect.Type.APPEND) + throw new IllegalArgumentException( + "Redirect invalid for reading: " + source); + redirects()[0] = source; + return this; + } + + /** + * Sets this process builder's standard output destination. + * + * Subprocesses subsequently started by this object's {@link #start()} + * method send their standard output to this destination. + * + *

If the destination is {@link Redirect#PIPE Redirect.PIPE} + * (the initial value), then the standard output of a subprocess + * can be read using the input stream returned by {@link + * Process#getInputStream()}. + * If the destination is set to any other value, then + * {@link Process#getInputStream()} will return a + * null input stream. + * + * @param destination the new standard output destination + * @return this process builder + * @throws IllegalArgumentException + * if the redirect does not correspond to a valid + * destination of data, that is, has type + * {@link Redirect.Type#READ READ} + * @since 1.7 + */ + public ProcessBuilder redirectOutput(Redirect destination) { + if (destination.type() == Redirect.Type.READ) + throw new IllegalArgumentException( + "Redirect invalid for writing: " + destination); + redirects()[1] = destination; + return this; + } + + /** + * Sets this process builder's standard error destination. + * + * Subprocesses subsequently started by this object's {@link #start()} + * method send their standard error to this destination. + * + *

If the destination is {@link Redirect#PIPE Redirect.PIPE} + * (the initial value), then the error output of a subprocess + * can be read using the input stream returned by {@link + * Process#getErrorStream()}. + * If the destination is set to any other value, then + * {@link Process#getErrorStream()} will return a + * null input stream. + * + *

If the {@link #redirectErrorStream redirectErrorStream} + * attribute has been set {@code true}, then the redirection set + * by this method has no effect. + * + * @param destination the new standard error destination + * @return this process builder + * @throws IllegalArgumentException + * if the redirect does not correspond to a valid + * destination of data, that is, has type + * {@link Redirect.Type#READ READ} + * @since 1.7 + */ + public ProcessBuilder redirectError(Redirect destination) { + if (destination.type() == Redirect.Type.READ) + throw new IllegalArgumentException( + "Redirect invalid for writing: " + destination); + redirects()[2] = destination; + return this; + } + + /** + * Sets this process builder's standard input source to a file. + * + *

This is a convenience method. An invocation of the form + * {@code redirectInput(file)} + * behaves in exactly the same way as the invocation + * {@link #redirectInput(Redirect) redirectInput} + * {@code (Redirect.from(file))}. + * + * @param file the new standard input source + * @return this process builder + * @since 1.7 + */ + public ProcessBuilder redirectInput(File file) { + return redirectInput(Redirect.from(file)); + } + + /** + * Sets this process builder's standard output destination to a file. + * + *

This is a convenience method. An invocation of the form + * {@code redirectOutput(file)} + * behaves in exactly the same way as the invocation + * {@link #redirectOutput(Redirect) redirectOutput} + * {@code (Redirect.to(file))}. + * + * @param file the new standard output destination + * @return this process builder + * @since 1.7 + */ + public ProcessBuilder redirectOutput(File file) { + return redirectOutput(Redirect.to(file)); + } + + /** + * Sets this process builder's standard error destination to a file. + * + *

This is a convenience method. An invocation of the form + * {@code redirectError(file)} + * behaves in exactly the same way as the invocation + * {@link #redirectError(Redirect) redirectError} + * {@code (Redirect.to(file))}. + * + * @param file the new standard error destination + * @return this process builder + * @since 1.7 + */ + public ProcessBuilder redirectError(File file) { + return redirectError(Redirect.to(file)); + } + + /** + * Returns this process builder's standard input source. + * + * Subprocesses subsequently started by this object's {@link #start()} + * method obtain their standard input from this source. + * The initial value is {@link Redirect#PIPE Redirect.PIPE}. + * + * @return this process builder's standard input source + * @since 1.7 + */ + public Redirect redirectInput() { + return (redirects == null) ? Redirect.PIPE : redirects[0]; + } + + /** + * Returns this process builder's standard output destination. + * + * Subprocesses subsequently started by this object's {@link #start()} + * method redirect their standard output to this destination. + * The initial value is {@link Redirect#PIPE Redirect.PIPE}. + * + * @return this process builder's standard output destination + * @since 1.7 + */ + public Redirect redirectOutput() { + return (redirects == null) ? Redirect.PIPE : redirects[1]; + } + + /** + * Returns this process builder's standard error destination. + * + * Subprocesses subsequently started by this object's {@link #start()} + * method redirect their standard error to this destination. + * The initial value is {@link Redirect#PIPE Redirect.PIPE}. + * + * @return this process builder's standard error destination + * @since 1.7 + */ + public Redirect redirectError() { + return (redirects == null) ? Redirect.PIPE : redirects[2]; + } + + /** + * Sets the source and destination for subprocess standard I/O + * to be the same as those of the current Java process. + * + *

This is a convenience method. An invocation of the form + *

 {@code
+     * pb.inheritIO()
+     * }
+ * behaves in exactly the same way as the invocation + *
 {@code
+     * pb.redirectInput(Redirect.INHERIT)
+     *   .redirectOutput(Redirect.INHERIT)
+     *   .redirectError(Redirect.INHERIT)
+     * }
+ * + * This gives behavior equivalent to most operating system + * command interpreters, or the standard C library function + * {@code system()}. + * + * @return this process builder + * @since 1.7 + */ + public ProcessBuilder inheritIO() { + Arrays.fill(redirects(), Redirect.INHERIT); + return this; + } + + /** + * Tells whether this process builder merges standard error and + * standard output. + * + *

If this property is {@code true}, then any error output + * generated by subprocesses subsequently started by this object's + * {@link #start()} method will be merged with the standard + * output, so that both can be read using the + * {@link Process#getInputStream()} method. This makes it easier + * to correlate error messages with the corresponding output. + * The initial value is {@code false}. + * + * @return this process builder's {@code redirectErrorStream} property + */ + public boolean redirectErrorStream() { + return redirectErrorStream; + } + + /** + * Sets this process builder's {@code redirectErrorStream} property. + * + *

If this property is {@code true}, then any error output + * generated by subprocesses subsequently started by this object's + * {@link #start()} method will be merged with the standard + * output, so that both can be read using the + * {@link Process#getInputStream()} method. This makes it easier + * to correlate error messages with the corresponding output. + * The initial value is {@code false}. + * + * @param redirectErrorStream the new property value + * @return this process builder + */ + public ProcessBuilder redirectErrorStream(boolean redirectErrorStream) { + this.redirectErrorStream = redirectErrorStream; + return this; + } + + /** + * Starts a new process using the attributes of this process builder. + * + *

The new process will + * invoke the command and arguments given by {@link #command()}, + * in a working directory as given by {@link #directory()}, + * with a process environment as given by {@link #environment()}. + * + *

This method checks that the command is a valid operating + * system command. Which commands are valid is system-dependent, + * but at the very least the command must be a non-empty list of + * non-null strings. + * + *

A minimal set of system dependent environment variables may + * be required to start a process on some operating systems. + * As a result, the subprocess may inherit additional environment variable + * settings beyond those in the process builder's {@link #environment()}. + * + *

If there is a security manager, its + * {@link SecurityManager#checkExec checkExec} + * method is called with the first component of this object's + * {@code command} array as its argument. This may result in + * a {@link SecurityException} being thrown. + * + *

Starting an operating system process is highly system-dependent. + * Among the many things that can go wrong are: + *

    + *
  • The operating system program file was not found. + *
  • Access to the program file was denied. + *
  • The working directory does not exist. + *
+ * + *

In such cases an exception will be thrown. The exact nature + * of the exception is system-dependent, but it will always be a + * subclass of {@link IOException}. + * + *

Subsequent modifications to this process builder will not + * affect the returned {@link Process}. + * + * @return a new {@link Process} object for managing the subprocess + * + * @throws NullPointerException + * if an element of the command list is null + * + * @throws IndexOutOfBoundsException + * if the command is an empty list (has size {@code 0}) + * + * @throws SecurityException + * if a security manager exists and + *

    + * + *
  • its + * {@link SecurityManager#checkExec checkExec} + * method doesn't allow creation of the subprocess, or + * + *
  • the standard input to the subprocess was + * {@linkplain #redirectInput redirected from a file} + * and the security manager's + * {@link SecurityManager#checkRead checkRead} method + * denies read access to the file, or + * + *
  • the standard output or standard error of the + * subprocess was + * {@linkplain #redirectOutput redirected to a file} + * and the security manager's + * {@link SecurityManager#checkWrite checkWrite} method + * denies write access to the file + * + *
+ * + * @throws IOException if an I/O error occurs + * + * @see Runtime#exec(String[], String[], java.io.File) + */ + public Process start() throws IOException { + // Must convert to array first -- a malicious user-supplied + // list might try to circumvent the security check. + String[] cmdarray = command.toArray(new String[command.size()]); + cmdarray = cmdarray.clone(); + + for (String arg : cmdarray) + if (arg == null) + throw new NullPointerException(); + // Throws IndexOutOfBoundsException if command is empty + String prog = cmdarray[0]; + + SecurityManager security = System.getSecurityManager(); + if (security != null) + security.checkExec(prog); + + String dir = directory == null ? null : directory.toString(); + + for (int i = 1; i < cmdarray.length; i++) { + if (cmdarray[i].indexOf('\u0000') >= 0) { + throw new IOException("invalid null character in command"); + } + } + + try { + return ProcessImpl.start(cmdarray, + environment, + dir, + redirects, + redirectErrorStream); + } catch (IOException | IllegalArgumentException e) { + String exceptionInfo = ": " + e.getMessage(); + Throwable cause = e; + if ((e instanceof IOException) && security != null) { + // Can not disclose the fail reason for read-protected files. + try { + security.checkRead(prog); + } catch (SecurityException se) { + exceptionInfo = ""; + cause = se; + } + } + // It's much easier for us to create a high-quality error + // message than the low-level C code which found the problem. + throw new IOException( + "Cannot run program \"" + prog + "\"" + + (dir == null ? "" : " (in directory \"" + dir + "\")") + + exceptionInfo, + cause); + } + } +} diff --git a/src/MapleFE/test/java/openjdk/ProcessBuilder.java.result b/src/MapleFE/test/java/openjdk/ProcessBuilder.java.result new file mode 100644 index 0000000000000000000000000000000000000000..b94bef0597edd4df522c431578f4fbc3d2436a9f --- /dev/null +++ b/src/MapleFE/test/java/openjdk/ProcessBuilder.java.result @@ -0,0 +1,305 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 19 tokens. +Matched 26 tokens. +Matched 33 tokens. +Matched 40 tokens. +Matched 47 tokens. +Matched 54 tokens. +Matched 61 tokens. +Matched 1635 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import java.io.File +== Sub Tree == +import java.io.IOException +== Sub Tree == +import java.io.InputStream +== Sub Tree == +import java.io.OutputStream +== Sub Tree == +import java.util.Arrays +== Sub Tree == +import java.util.ArrayList +== Sub Tree == +import java.util.List +== Sub Tree == +import java.util.Map +== Sub Tree == +class ProcessBuilder + Fields: + command directory environment redirectErrorStream redirects + Instance Initializer: + Constructors: + constructor ProcessBuilder(command) throws: + cond-branch cond:command EQ null + true branch : + new NullPointerException() false branch : + + this.command Assign command + constructor ProcessBuilder(command) throws: + this.command Assign new ArrayList(command.length) + String + arg + command + this.command.add(arg) + Methods: + func command(command) throws: + cond-branch cond:command EQ null + true branch : + new NullPointerException() false branch : + + this.command Assign command + return this + func command(command) throws: + this.command Assign new ArrayList(command.length) + String + arg + command + this.command.add(arg) + return this + func command() throws: + return command + func environment() throws: + Decl: security=System.getSecurityManager() + cond-branch cond:security NE null + true branch : + security.checkPermission(new RuntimePermission("getenv.*")) false branch : + + cond-branch cond:environment EQ null + true branch : + environment Assign ProcessEnvironment.environment() false branch : + + assert environment NE null : + return environment + func environment(envp) throws: + assert environment EQ null : + cond-branch cond:envp NE null + true branch : + environment Assign ProcessEnvironment.emptyEnvironment(envp.length) + assert environment NE null : + String + envstring + envp + cond-branch cond:envstring.indexOf((int)0) NE -1 + true branch : + envstring Assign envstring.replaceFirst("\u0000.*","") false branch : + + Decl: eqlsign=envstring.indexOf(=,ProcessEnvironment.MIN_NAME_LENGTH) + cond-branch cond:eqlsign NE -1 + true branch : + environment.put(envstring.substring(0,eqlsign),envstring.substring(eqlsign Add 1)) false branch : + + + false branch : + + return this + func directory() throws: + return directory + func directory(directory) throws: + this.directory Assign directory + return this + func redirects() throws: + cond-branch cond:redirects EQ null + true branch : + redirects Assign false branch : + + return redirects + func redirectInput(source) throws: + cond-branch cond:source.type() EQ Redirect.Type.WRITE Lor source.type() EQ Redirect.Type.APPEND + true branch : + new IllegalArgumentException("Redirect invalid for reading: " Add source) false branch : + + Assign source + return this + func redirectOutput(destination) throws: + cond-branch cond:destination.type() EQ Redirect.Type.READ + true branch : + new IllegalArgumentException("Redirect invalid for writing: " Add destination) false branch : + + Assign destination + return this + func redirectError(destination) throws: + cond-branch cond:destination.type() EQ Redirect.Type.READ + true branch : + new IllegalArgumentException("Redirect invalid for writing: " Add destination) false branch : + + Assign destination + return this + func redirectInput(file) throws: + return redirectInput(Redirect.from(file)) + func redirectOutput(file) throws: + return redirectOutput(Redirect.to(file)) + func redirectError(file) throws: + return redirectError(Redirect.to(file)) + func redirectInput() throws: + return + func redirectOutput() throws: + return + func redirectError() throws: + return + func inheritIO() throws: + Arrays.fill(redirects(),Redirect.INHERIT) + return this + func redirectErrorStream() throws: + return redirectErrorStream + func redirectErrorStream(redirectErrorStream) throws: + this.redirectErrorStream Assign redirectErrorStream + return this + func start() throws: IOException + Decl: cmdarray=command.toArray(String,command.size()) + cmdarray Assign cmdarray.clone() + String + arg + cmdarray + cond-branch cond:arg EQ null + true branch : + new NullPointerException() false branch : + + Decl: prog= + Decl: security=System.getSecurityManager() + cond-branch cond:security NE null + true branch : + security.checkExec(prog) false branch : + + Decl: dir= + for ( ) + cond-branch cond:.indexOf(0) GE 0 + true branch : + new IOException("invalid null character in command") + false branch : + + + return ProcessImpl.start(cmdarray,environment,dir,redirects,redirectErrorStream) + + IOException + IllegalArgumentException + e + Decl: exceptionInfo=": " Add e.getMessage() + Decl: cause=e + cond-branch cond:(e instanceof IOException) Land security NE null + true branch : + security.checkRead(prog) + + SecurityException + se + exceptionInfo Assign "" + cause Assign se + + false branch : + + new IOException("Cannot run program \"" Add prog Add "\"" Add () Add exceptionInfo,cause) + + LocalClasses: + class NullInputStream + Fields: + INSTANCE=new NullInputStream() + Instance Initializer: + Constructors: + constructor NullInputStream() throws: + Methods: + func read() throws: + return -1 + func available() throws: + return 0 + LocalClasses: + LocalInterfaces: + class NullOutputStream + Fields: + INSTANCE=new NullOutputStream() + Instance Initializer: + Constructors: + constructor NullOutputStream() throws: + Methods: + func write(b) throws: IOException + new IOException("Stream closed") + LocalClasses: + LocalInterfaces: + class Redirect + Fields: + PIPE=new Redirect() INHERIT=new Redirect() + Instance Initializer: + Constructors: + constructor Redirect() throws: + Methods: + func type() throws: + func file() throws: + return null + func append() throws: + new UnsupportedOperationException() + func from(file) throws: + cond-branch cond:file EQ null + true branch : + new NullPointerException() false branch : + + return new Redirect() + func to(file) throws: + cond-branch cond:file EQ null + true branch : + new NullPointerException() false branch : + + return new Redirect() + func appendTo(file) throws: + cond-branch cond:file EQ null + true branch : + new NullPointerException() false branch : + + return new Redirect() + func equals(obj) throws: + cond-branch cond:obj EQ this + true branch : + return true false branch : + + cond-branch cond:(obj instanceof Redirect) + true branch : + return false false branch : + + Decl: r=(Redirect)obj + cond-branch cond:r.type() NE this.type() + true branch : + return false false branch : + + assert this.file() NE null : + return this.file().equals(r.file()) + func hashCode() throws: + Decl: file=file() + cond-branch cond:file EQ null + true branch : + return super.hashCode() false branch : + return file.hashCode() + LocalClasses: + class[JavaEnum] Type + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + LocalInterfaces: + LocalInterfaces: + +Field Decl Duplication! Identifier:command is duplicated with Function:command +Field Decl Duplication! Identifier:command is duplicated with Function:command +Field Decl Duplication! Identifier:command is duplicated with Function:command +Field Decl Duplication! Identifier:directory is duplicated with Function:directory +Field Decl Duplication! Identifier:directory is duplicated with Function:directory +Field Decl Duplication! Identifier:environment is duplicated with Function:environment +Field Decl Duplication! Identifier:environment is duplicated with Function:environment +Field Decl Duplication! Identifier:redirectErrorStream is duplicated with Function:redirectErrorStream +Field Decl Duplication! Identifier:redirectErrorStream is duplicated with Function:redirectErrorStream +Field Decl Duplication! Identifier:redirects is duplicated with Function:redirects +UserType:ArrayList has no decl. +Identifier:String has no decl. +Identifier:arg has no decl. +Identifier:cmdarray has no decl. +Identifier:String has no decl. +Identifier:arg has no decl. +Identifier:cmdarray has no decl. +Identifier:IOException has no decl. +Identifier:IllegalArgumentException has no decl. +Identifier:e has no decl. +UserType:IOException has no decl. +Identifier:cause has no decl. diff --git a/src/MapleFE/test/java/openjdk/ProcessEnvironment.java b/src/MapleFE/test/java/openjdk/ProcessEnvironment.java new file mode 100644 index 0000000000000000000000000000000000000000..08d260cf4a3cd3a66a11d435d99ae404b68e9d8e --- /dev/null +++ b/src/MapleFE/test/java/openjdk/ProcessEnvironment.java @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* We use APIs that access the standard Unix environ array, which + * is defined by UNIX98 to look like: + * + * char **environ; + * + * These are unsorted, case-sensitive, null-terminated arrays of bytes + * of the form FOO=BAR\000 which are usually encoded in the user's + * default encoding (file.encoding is an excellent choice for + * encoding/decoding these). However, even though the user cannot + * directly access the underlying byte representation, we take pains + * to pass on the child the exact byte representation we inherit from + * the parent process for any environment name or value not created by + * Javaland. So we keep track of all the byte representations. + * + * Internally, we define the types Variable and Value that exhibit + * String/byteArray duality. The internal representation of the + * environment then looks like a Map. But we don't + * expose this to the user -- we only provide a Map + * view, although we could also provide a Map view. + * + * The non-private methods in this class are not for general use even + * within this package. Instead, they are the system-dependent parts + * of the system-independent method of the same name. Don't even + * think of using this class unless your method's name appears below. + * + * @author Martin Buchholz + * @since 1.5 + */ + +package java.lang; + +import java.io.*; +import java.util.*; + + +final class ProcessEnvironment +{ + private static final HashMap theEnvironment; + private static final Map theUnmodifiableEnvironment; + static final int MIN_NAME_LENGTH = 0; + + static { + // We cache the C environment. This means that subsequent calls + // to putenv/setenv from C will not be visible from Java code. + byte[][] environ = environ(); + theEnvironment = new HashMap<>(environ.length/2 + 3); + // Read environment variables back to front, + // so that earlier variables override later ones. + for (int i = environ.length-1; i > 0; i-=2) + theEnvironment.put(Variable.valueOf(environ[i-1]), + Value.valueOf(environ[i])); + + theUnmodifiableEnvironment + = Collections.unmodifiableMap + (new StringEnvironment(theEnvironment)); + } + + /* Only for use by System.getenv(String) */ + static String getenv(String name) { + return theUnmodifiableEnvironment.get(name); + } + + /* Only for use by System.getenv() */ + static Map getenv() { + return theUnmodifiableEnvironment; + } + + /* Only for use by ProcessBuilder.environment() */ + @SuppressWarnings("unchecked") + static Map environment() { + return new StringEnvironment + ((Map)(theEnvironment.clone())); + } + + /* Only for use by Runtime.exec(...String[]envp...) */ + static Map emptyEnvironment(int capacity) { + return new StringEnvironment(new HashMap(capacity)); + } + + private static native byte[][] environ(); + + // This class is not instantiable. + private ProcessEnvironment() {} + + // Check that name is suitable for insertion into Environment map + private static void validateVariable(String name) { + if (name.indexOf('=') != -1 || + name.indexOf('\u0000') != -1) + throw new IllegalArgumentException + ("Invalid environment variable name: \"" + name + "\""); + } + + // Check that value is suitable for insertion into Environment map + private static void validateValue(String value) { + if (value.indexOf('\u0000') != -1) + throw new IllegalArgumentException + ("Invalid environment variable value: \"" + value + "\""); + } + + // A class hiding the byteArray-String duality of + // text data on Unixoid operating systems. + private static abstract class ExternalData { + protected final String str; + protected final byte[] bytes; + + protected ExternalData(String str, byte[] bytes) { + this.str = str; + this.bytes = bytes; + } + + public byte[] getBytes() { + return bytes; + } + + public String toString() { + return str; + } + + public boolean equals(Object o) { + return o instanceof ExternalData + && arrayEquals(getBytes(), ((ExternalData) o).getBytes()); + } + + public int hashCode() { + return arrayHash(getBytes()); + } + } + + private static class Variable + extends ExternalData implements Comparable + { + protected Variable(String str, byte[] bytes) { + super(str, bytes); + } + + public static Variable valueOfQueryOnly(Object str) { + return valueOfQueryOnly((String) str); + } + + public static Variable valueOfQueryOnly(String str) { + return new Variable(str, str.getBytes()); + } + + public static Variable valueOf(String str) { + validateVariable(str); + return valueOfQueryOnly(str); + } + + public static Variable valueOf(byte[] bytes) { + return new Variable(new String(bytes), bytes); + } + + public int compareTo(Variable variable) { + return arrayCompare(getBytes(), variable.getBytes()); + } + + public boolean equals(Object o) { + return o instanceof Variable && super.equals(o); + } + } + + private static class Value + extends ExternalData implements Comparable + { + protected Value(String str, byte[] bytes) { + super(str, bytes); + } + + public static Value valueOfQueryOnly(Object str) { + return valueOfQueryOnly((String) str); + } + + public static Value valueOfQueryOnly(String str) { + return new Value(str, str.getBytes()); + } + + public static Value valueOf(String str) { + validateValue(str); + return valueOfQueryOnly(str); + } + + public static Value valueOf(byte[] bytes) { + return new Value(new String(bytes), bytes); + } + + public int compareTo(Value value) { + return arrayCompare(getBytes(), value.getBytes()); + } + + public boolean equals(Object o) { + return o instanceof Value && super.equals(o); + } + } + + // This implements the String map view the user sees. + private static class StringEnvironment + extends AbstractMap + { + private Map m; + private static String toString(Value v) { + return v == null ? null : v.toString(); + } + public StringEnvironment(Map m) {this.m = m;} + public int size() {return m.size();} + public boolean isEmpty() {return m.isEmpty();} + public void clear() { m.clear();} + public boolean containsKey(Object key) { + return m.containsKey(Variable.valueOfQueryOnly(key)); + } + public boolean containsValue(Object value) { + return m.containsValue(Value.valueOfQueryOnly(value)); + } + public String get(Object key) { + return toString(m.get(Variable.valueOfQueryOnly(key))); + } + public String put(String key, String value) { + return toString(m.put(Variable.valueOf(key), + Value.valueOf(value))); + } + public String remove(Object key) { + return toString(m.remove(Variable.valueOfQueryOnly(key))); + } + public Set keySet() { + return new StringKeySet(m.keySet()); + } + public Set> entrySet() { + return new StringEntrySet(m.entrySet()); + } + public Collection values() { + return new StringValues(m.values()); + } + + // It is technically feasible to provide a byte-oriented view + // as follows: + // public Map asByteArrayMap() { + // return new ByteArrayEnvironment(m); + // } + + + // Convert to Unix style environ as a monolithic byte array + // inspired by the Windows Environment Block, except we work + // exclusively with bytes instead of chars, and we need only + // one trailing NUL on Unix. + // This keeps the JNI as simple and efficient as possible. + public byte[] toEnvironmentBlock(int[]envc) { + int count = m.size() * 2; // For added '=' and NUL + for (Map.Entry entry : m.entrySet()) { + count += entry.getKey().getBytes().length; + count += entry.getValue().getBytes().length; + } + + byte[] block = new byte[count]; + + int i = 0; + for (Map.Entry entry : m.entrySet()) { + byte[] key = entry.getKey ().getBytes(); + byte[] value = entry.getValue().getBytes(); + System.arraycopy(key, 0, block, i, key.length); + i+=key.length; + block[i++] = (byte) '='; + System.arraycopy(value, 0, block, i, value.length); + i+=value.length + 1; + // No need to write NUL byte explicitly + //block[i++] = (byte) '\u0000'; + } + envc[0] = m.size(); + return block; + } + } + + static byte[] toEnvironmentBlock(Map map, int[]envc) { + return map == null ? null : + ((StringEnvironment)map).toEnvironmentBlock(envc); + } + + + private static class StringEntry + implements Map.Entry + { + private final Map.Entry e; + public StringEntry(Map.Entry e) {this.e = e;} + public String getKey() {return e.getKey().toString();} + public String getValue() {return e.getValue().toString();} + public String setValue(String newValue) { + return e.setValue(Value.valueOf(newValue)).toString(); + } + public String toString() {return getKey() + "=" + getValue();} + public boolean equals(Object o) { + return o instanceof StringEntry + && e.equals(((StringEntry)o).e); + } + public int hashCode() {return e.hashCode();} + } + + private static class StringEntrySet + extends AbstractSet> + { + private final Set> s; + public StringEntrySet(Set> s) {this.s = s;} + public int size() {return s.size();} + public boolean isEmpty() {return s.isEmpty();} + public void clear() { s.clear();} + public Iterator> iterator() { + return new Iterator>() { + Iterator> i = s.iterator(); + public boolean hasNext() {return i.hasNext();} + public Map.Entry next() { + return new StringEntry(i.next()); + } + public void remove() {i.remove();} + }; + } + private static Map.Entry vvEntry(final Object o) { + if (o instanceof StringEntry) + return ((StringEntry)o).e; + return new Map.Entry() { + public Variable getKey() { + return Variable.valueOfQueryOnly(((Map.Entry)o).getKey()); + } + public Value getValue() { + return Value.valueOfQueryOnly(((Map.Entry)o).getValue()); + } + public Value setValue(Value value) { + throw new UnsupportedOperationException(); + } + }; + } + public boolean contains(Object o) { return s.contains(vvEntry(o)); } + public boolean remove(Object o) { return s.remove(vvEntry(o)); } + public boolean equals(Object o) { + return o instanceof StringEntrySet + && s.equals(((StringEntrySet) o).s); + } + public int hashCode() {return s.hashCode();} + } + + private static class StringValues + extends AbstractCollection + { + private final Collection c; + public StringValues(Collection c) {this.c = c;} + public int size() {return c.size();} + public boolean isEmpty() {return c.isEmpty();} + public void clear() { c.clear();} + public Iterator iterator() { + return new Iterator() { + Iterator i = c.iterator(); + public boolean hasNext() {return i.hasNext();} + public String next() {return i.next().toString();} + public void remove() {i.remove();} + }; + } + public boolean contains(Object o) { + return c.contains(Value.valueOfQueryOnly(o)); + } + public boolean remove(Object o) { + return c.remove(Value.valueOfQueryOnly(o)); + } + public boolean equals(Object o) { + return o instanceof StringValues + && c.equals(((StringValues)o).c); + } + public int hashCode() {return c.hashCode();} + } + + private static class StringKeySet extends AbstractSet { + private final Set s; + public StringKeySet(Set s) {this.s = s;} + public int size() {return s.size();} + public boolean isEmpty() {return s.isEmpty();} + public void clear() { s.clear();} + public Iterator iterator() { + return new Iterator() { + Iterator i = s.iterator(); + public boolean hasNext() {return i.hasNext();} + public String next() {return i.next().toString();} + public void remove() { i.remove();} + }; + } + public boolean contains(Object o) { + return s.contains(Variable.valueOfQueryOnly(o)); + } + public boolean remove(Object o) { + return s.remove(Variable.valueOfQueryOnly(o)); + } + } + + // Replace with general purpose method someday + private static int arrayCompare(byte[]x, byte[] y) { + int min = x.length < y.length ? x.length : y.length; + for (int i = 0; i < min; i++) + if (x[i] != y[i]) + return x[i] - y[i]; + return x.length - y.length; + } + + // Replace with general purpose method someday + private static boolean arrayEquals(byte[] x, byte[] y) { + if (x.length != y.length) + return false; + for (int i = 0; i < x.length; i++) + if (x[i] != y[i]) + return false; + return true; + } + + // Replace with general purpose method someday + private static int arrayHash(byte[] x) { + int hash = 0; + for (int i = 0; i < x.length; i++) + hash = 31 * hash + x[i]; + return hash; + } + +} diff --git a/src/MapleFE/test/java/openjdk/ProcessEnvironment.java.result b/src/MapleFE/test/java/openjdk/ProcessEnvironment.java.result new file mode 100644 index 0000000000000000000000000000000000000000..10edbc49196cff4198a5bfaacd3f0319fd209597 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/ProcessEnvironment.java.result @@ -0,0 +1,296 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 19 tokens. +Matched 2531 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import java.io +== Sub Tree == +import java.util +== Sub Tree == +class ProcessEnvironment + Fields: + theEnvironment theUnmodifiableEnvironment MIN_NAME_LENGTH=0 + Instance Initializer: + InstInit- 0 + Constructors: + constructor ProcessEnvironment() throws: + Methods: + func getenv(name) throws: + return theUnmodifiableEnvironment.get(name) + func getenv() throws: + return theUnmodifiableEnvironment + func environment() throws: + return new StringEnvironment(()(theEnvironment.clone())) + func emptyEnvironment(capacity) throws: + return new StringEnvironment(new HashMap(capacity)) + func environ() throws: + func validateVariable(name) throws: + cond-branch cond:name.indexOf(=) NE -1 Lor name.indexOf(0) NE -1 + true branch : + new IllegalArgumentException("Invalid environment variable name: \"" Add name Add "\"") false branch : + + func validateValue(value) throws: + cond-branch cond:value.indexOf(0) NE -1 + true branch : + new IllegalArgumentException("Invalid environment variable value: \"" Add value Add "\"") false branch : + + func toEnvironmentBlock(map,envc) throws: + return + func arrayCompare(x,y) throws: + Decl: min= + for ( ) + cond-branch cond: NE + true branch : + return Sub false branch : + + return x.length Sub y.length + func arrayEquals(x,y) throws: + cond-branch cond:x.length NE y.length + true branch : + return false false branch : + + for ( ) + cond-branch cond: NE + true branch : + return false false branch : + + return true + func arrayHash(x) throws: + Decl: hash=0 + for ( ) + hash Assign 31 Mul hash Add + return hash + LocalClasses: + class ExternalData + Fields: + str bytes + Instance Initializer: + Constructors: + constructor ExternalData(str,bytes) throws: + this.str Assign str + this.bytes Assign bytes + Methods: + func getBytes() throws: + return bytes + func toString() throws: + return str + func equals(o) throws: + return o instanceof ExternalData Land arrayEquals(getBytes(),(ExternalData)o.getBytes()) + func hashCode() throws: + return arrayHash(getBytes()) + LocalClasses: + LocalInterfaces: + class Variable + Fields: + + Instance Initializer: + Constructors: + constructor Variable(str,bytes) throws: + Methods: + func valueOfQueryOnly(str) throws: + return valueOfQueryOnly((String)str) + func valueOfQueryOnly(str) throws: + return new Variable(str,str.getBytes()) + func valueOf(str) throws: + validateVariable(str) + return valueOfQueryOnly(str) + func valueOf(bytes) throws: + return new Variable(new String(bytes),bytes) + func compareTo(variable) throws: + return arrayCompare(getBytes(),variable.getBytes()) + func equals(o) throws: + return o instanceof Variable Land super.equals(o) + LocalClasses: + LocalInterfaces: + class Value + Fields: + + Instance Initializer: + Constructors: + constructor Value(str,bytes) throws: + Methods: + func valueOfQueryOnly(str) throws: + return valueOfQueryOnly((String)str) + func valueOfQueryOnly(str) throws: + return new Value(str,str.getBytes()) + func valueOf(str) throws: + validateValue(str) + return valueOfQueryOnly(str) + func valueOf(bytes) throws: + return new Value(new String(bytes),bytes) + func compareTo(value) throws: + return arrayCompare(getBytes(),value.getBytes()) + func equals(o) throws: + return o instanceof Value Land super.equals(o) + LocalClasses: + LocalInterfaces: + class StringEnvironment + Fields: + m + Instance Initializer: + Constructors: + constructor StringEnvironment(m) throws: + this.m Assign m + Methods: + func toString(v) throws: + return + func size() throws: + return m.size() + func isEmpty() throws: + return m.isEmpty() + func clear() throws: + m.clear() + func containsKey(key) throws: + return m.containsKey(Variable.valueOfQueryOnly(key)) + func containsValue(value) throws: + return m.containsValue(Value.valueOfQueryOnly(value)) + func get(key) throws: + return toString(m.get(Variable.valueOfQueryOnly(key))) + func put(key,value) throws: + return toString(m.put(Variable.valueOf(key),Value.valueOf(value))) + func remove(key) throws: + return toString(m.remove(Variable.valueOfQueryOnly(key))) + func keySet() throws: + return new StringKeySet(m.keySet()) + func entrySet() throws: + return new StringEntrySet(m.entrySet()) + func values() throws: + return new StringValues(m.values()) + func toEnvironmentBlock(envc) throws: + Decl: count=m.size() Mul 2 + Map + Entry + Variable + Value + entry + m.entrySet() + count AddAssign entry.getKey().getBytes().length + count AddAssign entry.getValue().getBytes().length + + Decl: block= + Decl: i=0 + Map + Entry + Variable + Value + entry + m.entrySet() + Decl: key=entry.getKey().getBytes() + Decl: value=entry.getValue().getBytes() + System.arraycopy(key,0,block,i,key.length) + i AddAssign key.length + Assign (byte)= + System.arraycopy(value,0,block,i,value.length) + i AddAssign value.length Add 1 + + Assign m.size() + return block + LocalClasses: + LocalInterfaces: + class StringEntry + Fields: + e + Instance Initializer: + Constructors: + constructor StringEntry(e) throws: + this.e Assign e + Methods: + func getKey() throws: + return e.getKey().toString() + func getValue() throws: + return e.getValue().toString() + func setValue(newValue) throws: + return e.setValue(Value.valueOf(newValue)).toString() + func toString() throws: + return getKey() Add "=" Add getValue() + func equals(o) throws: + return o instanceof StringEntry Land e.equals((StringEntry)o.e) + func hashCode() throws: + return e.hashCode() + LocalClasses: + LocalInterfaces: + class StringEntrySet + Fields: + s + Instance Initializer: + Constructors: + constructor StringEntrySet(s) throws: + this.s Assign s + Methods: + func size() throws: + return s.size() + func isEmpty() throws: + return s.isEmpty() + func clear() throws: + s.clear() + func iterator() throws: + return new Iterator() + func vvEntry(o) throws: + cond-branch cond:o instanceof StringEntry + true branch : + return (StringEntry)o.e false branch : + + return new Map() + func contains(o) throws: + return s.contains(vvEntry(o)) + func remove(o) throws: + return s.remove(vvEntry(o)) + func equals(o) throws: + return o instanceof StringEntrySet Land s.equals((StringEntrySet)o.s) + func hashCode() throws: + return s.hashCode() + LocalClasses: + LocalInterfaces: + class StringValues + Fields: + c + Instance Initializer: + Constructors: + constructor StringValues(c) throws: + this.c Assign c + Methods: + func size() throws: + return c.size() + func isEmpty() throws: + return c.isEmpty() + func clear() throws: + c.clear() + func iterator() throws: + return new Iterator() + func contains(o) throws: + return c.contains(Value.valueOfQueryOnly(o)) + func remove(o) throws: + return c.remove(Value.valueOfQueryOnly(o)) + func equals(o) throws: + return o instanceof StringValues Land c.equals((StringValues)o.c) + func hashCode() throws: + return c.hashCode() + LocalClasses: + LocalInterfaces: + class StringKeySet + Fields: + s + Instance Initializer: + Constructors: + constructor StringKeySet(s) throws: + this.s Assign s + Methods: + func size() throws: + return s.size() + func isEmpty() throws: + return s.isEmpty() + func clear() throws: + s.clear() + func iterator() throws: + return new Iterator() + func contains(o) throws: + return s.contains(Variable.valueOfQueryOnly(o)) + func remove(o) throws: + return s.remove(Variable.valueOfQueryOnly(o)) + LocalClasses: + LocalInterfaces: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/Runtime.java b/src/MapleFE/test/java/openjdk/Runtime.java new file mode 100644 index 0000000000000000000000000000000000000000..3d5281479e13c4825896dc4fe34a0ee19dc6f3b1 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Runtime.java @@ -0,0 +1,1161 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import dalvik.annotation.optimization.FastNative; +import java.io.*; +import java.util.StringTokenizer; +import sun.reflect.CallerSensitive; +import java.lang.ref.FinalizerReference; +import java.util.ArrayList; +import java.util.List; +import dalvik.system.BaseDexClassLoader; +import dalvik.system.VMDebug; +import dalvik.system.VMStack; +import dalvik.system.VMRuntime; +import libcore.io.IoUtils; +import libcore.io.Libcore; +import libcore.util.EmptyArray; +import static android.system.OsConstants._SC_NPROCESSORS_CONF; + +/** + * Every Java application has a single instance of class + * Runtime that allows the application to interface with + * the environment in which the application is running. The current + * runtime can be obtained from the getRuntime method. + *

+ * An application cannot create its own instance of this class. + * + * @author unascribed + * @see java.lang.Runtime#getRuntime() + * @since JDK1.0 + */ + +public class Runtime { + private static Runtime currentRuntime = new Runtime(); + + /** + * Holds the list of threads to run when the VM terminates + */ + private List shutdownHooks = new ArrayList(); + + /** + * Reflects whether finalization should be run for all objects + * when the VM terminates. + */ + private static boolean finalizeOnExit; + + /** + * Reflects whether we are already shutting down the VM. + */ + private boolean shuttingDown; + + /** + * Reflects whether we are tracing method calls. + */ + private boolean tracingMethods; + + private static native void nativeExit(int code); + + /** + * Returns the runtime object associated with the current Java application. + * Most of the methods of class Runtime are instance + * methods and must be invoked with respect to the current runtime object. + * + * @return the Runtime object associated with the current + * Java application. + */ + public static Runtime getRuntime() { + return currentRuntime; + } + + /** Don't let anyone else instantiate this class */ + private Runtime() {} + + /** + * Terminates the currently running Java virtual machine by initiating its + * shutdown sequence. This method never returns normally. The argument + * serves as a status code; by convention, a nonzero status code indicates + * abnormal termination. + * + *

The virtual machine's shutdown sequence consists of two phases. In + * the first phase all registered {@link #addShutdownHook shutdown hooks}, + * if any, are started in some unspecified order and allowed to run + * concurrently until they finish. In the second phase all uninvoked + * finalizers are run if {@link #runFinalizersOnExit finalization-on-exit} + * has been enabled. Once this is done the virtual machine {@link #halt + * halts}. + * + *

If this method is invoked after the virtual machine has begun its + * shutdown sequence then if shutdown hooks are being run this method will + * block indefinitely. If shutdown hooks have already been run and on-exit + * finalization has been enabled then this method halts the virtual machine + * with the given status code if the status is nonzero; otherwise, it + * blocks indefinitely. + * + *

The {@link System#exit(int) System.exit} method is the + * conventional and convenient means of invoking this method.

+ * + * @param status + * Termination status. By convention, a nonzero status code + * indicates abnormal termination. + * + * @throws SecurityException + * If a security manager is present and its {@link + * SecurityManager#checkExit checkExit} method does not permit + * exiting with the specified status + * + * @see java.lang.SecurityException + * @see java.lang.SecurityManager#checkExit(int) + * @see #addShutdownHook + * @see #removeShutdownHook + * @see #runFinalizersOnExit + * @see #halt(int) + */ + public void exit(int status) { + // Make sure we don't try this several times + synchronized(this) { + if (!shuttingDown) { + shuttingDown = true; + + Thread[] hooks; + synchronized (shutdownHooks) { + // create a copy of the hooks + hooks = new Thread[shutdownHooks.size()]; + shutdownHooks.toArray(hooks); + } + + // Start all shutdown hooks concurrently + for (Thread hook : hooks) { + hook.start(); + } + + // Wait for all shutdown hooks to finish + for (Thread hook : hooks) { + try { + hook.join(); + } catch (InterruptedException ex) { + // Ignore, since we are at VM shutdown. + } + } + + // Ensure finalization on exit, if requested + if (finalizeOnExit) { + runFinalization(); + } + + // Get out of here finally... + nativeExit(status); + } + } + } + + /** + * Registers a new virtual-machine shutdown hook. + * + *

The Java virtual machine shuts down in response to two kinds + * of events: + * + *

    + * + *
  • The program exits normally, when the last non-daemon + * thread exits or when the {@link #exit exit} (equivalently, + * {@link System#exit(int) System.exit}) method is invoked, or + * + *
  • The virtual machine is terminated in response to a + * user interrupt, such as typing ^C, or a system-wide event, + * such as user logoff or system shutdown. + * + *
+ * + *

A shutdown hook is simply an initialized but unstarted + * thread. When the virtual machine begins its shutdown sequence it will + * start all registered shutdown hooks in some unspecified order and let + * them run concurrently. When all the hooks have finished it will then + * run all uninvoked finalizers if finalization-on-exit has been enabled. + * Finally, the virtual machine will halt. Note that daemon threads will + * continue to run during the shutdown sequence, as will non-daemon threads + * if shutdown was initiated by invoking the {@link #exit exit} + * method. + * + *

Once the shutdown sequence has begun it can be stopped only by + * invoking the {@link #halt halt} method, which forcibly + * terminates the virtual machine. + * + *

Once the shutdown sequence has begun it is impossible to register a + * new shutdown hook or de-register a previously-registered hook. + * Attempting either of these operations will cause an + * {@link IllegalStateException} to be thrown. + * + *

Shutdown hooks run at a delicate time in the life cycle of a virtual + * machine and should therefore be coded defensively. They should, in + * particular, be written to be thread-safe and to avoid deadlocks insofar + * as possible. They should also not rely blindly upon services that may + * have registered their own shutdown hooks and therefore may themselves in + * the process of shutting down. Attempts to use other thread-based + * services such as the AWT event-dispatch thread, for example, may lead to + * deadlocks. + * + *

Shutdown hooks should also finish their work quickly. When a + * program invokes {@link #exit exit} the expectation is + * that the virtual machine will promptly shut down and exit. When the + * virtual machine is terminated due to user logoff or system shutdown the + * underlying operating system may only allow a fixed amount of time in + * which to shut down and exit. It is therefore inadvisable to attempt any + * user interaction or to perform a long-running computation in a shutdown + * hook. + * + *

Uncaught exceptions are handled in shutdown hooks just as in any + * other thread, by invoking the {@link ThreadGroup#uncaughtException + * uncaughtException} method of the thread's {@link + * ThreadGroup} object. The default implementation of this method + * prints the exception's stack trace to {@link System#err} and + * terminates the thread; it does not cause the virtual machine to exit or + * halt. + * + *

In rare circumstances the virtual machine may abort, that is, + * stop running without shutting down cleanly. This occurs when the + * virtual machine is terminated externally, for example with the + * SIGKILL signal on Unix or the TerminateProcess call on + * Microsoft Windows. The virtual machine may also abort if a native + * method goes awry by, for example, corrupting internal data structures or + * attempting to access nonexistent memory. If the virtual machine aborts + * then no guarantee can be made about whether or not any shutdown hooks + * will be run.

+ * + * @param hook + * An initialized but unstarted {@link Thread} object + * + * @throws IllegalArgumentException + * If the specified hook has already been registered, + * or if it can be determined that the hook is already running or + * has already been run + * + * @throws IllegalStateException + * If the virtual machine is already in the process + * of shutting down + * + * @throws SecurityException + * If a security manager is present and it denies + * {@link RuntimePermission}("shutdownHooks") + * + * @see #removeShutdownHook + * @see #halt(int) + * @see #exit(int) + * @since 1.3 + */ + public void addShutdownHook(Thread hook) { + // Sanity checks + if (hook == null) { + throw new NullPointerException("hook == null"); + } + + if (shuttingDown) { + throw new IllegalStateException("VM already shutting down"); + } + + if (hook.started) { + throw new IllegalArgumentException("Hook has already been started"); + } + + synchronized (shutdownHooks) { + if (shutdownHooks.contains(hook)) { + throw new IllegalArgumentException("Hook already registered."); + } + + shutdownHooks.add(hook); + } + } + + /** + * De-registers a previously-registered virtual-machine shutdown hook.

+ * + * @param hook the hook to remove + * @return true if the specified hook had previously been + * registered and was successfully de-registered, false + * otherwise. + * + * @throws IllegalStateException + * If the virtual machine is already in the process of shutting + * down + * + * @throws SecurityException + * If a security manager is present and it denies + * {@link RuntimePermission}("shutdownHooks") + * + * @see #addShutdownHook + * @see #exit(int) + * @since 1.3 + */ + public boolean removeShutdownHook(Thread hook) { + // Sanity checks + if (hook == null) { + throw new NullPointerException("hook == null"); + } + + if (shuttingDown) { + throw new IllegalStateException("VM already shutting down"); + } + + synchronized (shutdownHooks) { + return shutdownHooks.remove(hook); + } + } + + /** + * Forcibly terminates the currently running Java virtual machine. This + * method never returns normally. + * + *

This method should be used with extreme caution. Unlike the + * {@link #exit exit} method, this method does not cause shutdown + * hooks to be started and does not run uninvoked finalizers if + * finalization-on-exit has been enabled. If the shutdown sequence has + * already been initiated then this method does not wait for any running + * shutdown hooks or finalizers to finish their work.

+ * + * @param status + * Termination status. By convention, a nonzero status code + * indicates abnormal termination. If the {@link Runtime#exit + * exit} (equivalently, {@link System#exit(int) + * System.exit}) method has already been invoked then this + * status code will override the status code passed to that method. + * + * @throws SecurityException + * If a security manager is present and its {@link + * SecurityManager#checkExit checkExit} method does not permit + * an exit with the specified status + * + * @see #exit + * @see #addShutdownHook + * @see #removeShutdownHook + * @since 1.3 + */ + public void halt(int status) { + nativeExit(status); + } + + /** + * Enable or disable finalization on exit; doing so specifies that the + * finalizers of all objects that have finalizers that have not yet been + * automatically invoked are to be run before the Java runtime exits. + * By default, finalization on exit is disabled. + * + *

If there is a security manager, + * its checkExit method is first called + * with 0 as its argument to ensure the exit is allowed. + * This could result in a SecurityException. + * + * @param value true to enable finalization on exit, false to disable + * @deprecated This method is inherently unsafe. It may result in + * finalizers being called on live objects while other threads are + * concurrently manipulating those objects, resulting in erratic + * behavior or deadlock. + * + * @throws SecurityException + * if a security manager exists and its checkExit + * method doesn't allow the exit. + * + * @see java.lang.Runtime#exit(int) + * @see java.lang.Runtime#gc() + * @see java.lang.SecurityManager#checkExit(int) + * @since JDK1.1 + */ + @Deprecated + public static void runFinalizersOnExit(boolean value) { + finalizeOnExit = value; + } + + /** + * Executes the specified string command in a separate process. + * + *

This is a convenience method. An invocation of the form + * exec(command) + * behaves in exactly the same way as the invocation + * {@link #exec(String, String[], File) exec}(command, null, null). + * + * @param command a specified system command. + * + * @return A new {@link Process} object for managing the subprocess + * + * @throws SecurityException + * If a security manager exists and its + * {@link SecurityManager#checkExec checkExec} + * method doesn't allow creation of the subprocess + * + * @throws IOException + * If an I/O error occurs + * + * @throws NullPointerException + * If command is null + * + * @throws IllegalArgumentException + * If command is empty + * + * @see #exec(String[], String[], File) + * @see ProcessBuilder + */ + public Process exec(String command) throws IOException { + return exec(command, null, null); + } + + /** + * Executes the specified string command in a separate process with the + * specified environment. + * + *

This is a convenience method. An invocation of the form + * exec(command, envp) + * behaves in exactly the same way as the invocation + * {@link #exec(String, String[], File) exec}(command, envp, null). + * + * @param command a specified system command. + * + * @param envp array of strings, each element of which + * has environment variable settings in the format + * name=value, or + * null if the subprocess should inherit + * the environment of the current process. + * + * @return A new {@link Process} object for managing the subprocess + * + * @throws SecurityException + * If a security manager exists and its + * {@link SecurityManager#checkExec checkExec} + * method doesn't allow creation of the subprocess + * + * @throws IOException + * If an I/O error occurs + * + * @throws NullPointerException + * If command is null, + * or one of the elements of envp is null + * + * @throws IllegalArgumentException + * If command is empty + * + * @see #exec(String[], String[], File) + * @see ProcessBuilder + */ + public Process exec(String command, String[] envp) throws IOException { + return exec(command, envp, null); + } + + /** + * Executes the specified string command in a separate process with the + * specified environment and working directory. + * + *

This is a convenience method. An invocation of the form + * exec(command, envp, dir) + * behaves in exactly the same way as the invocation + * {@link #exec(String[], String[], File) exec}(cmdarray, envp, dir), + * where cmdarray is an array of all the tokens in + * command. + * + *

More precisely, the command string is broken + * into tokens using a {@link StringTokenizer} created by the call + * new {@link StringTokenizer}(command) with no + * further modification of the character categories. The tokens + * produced by the tokenizer are then placed in the new string + * array cmdarray, in the same order. + * + * @param command a specified system command. + * + * @param envp array of strings, each element of which + * has environment variable settings in the format + * name=value, or + * null if the subprocess should inherit + * the environment of the current process. + * + * @param dir the working directory of the subprocess, or + * null if the subprocess should inherit + * the working directory of the current process. + * + * @return A new {@link Process} object for managing the subprocess + * + * @throws SecurityException + * If a security manager exists and its + * {@link SecurityManager#checkExec checkExec} + * method doesn't allow creation of the subprocess + * + * @throws IOException + * If an I/O error occurs + * + * @throws NullPointerException + * If command is null, + * or one of the elements of envp is null + * + * @throws IllegalArgumentException + * If command is empty + * + * @see ProcessBuilder + * @since 1.3 + */ + public Process exec(String command, String[] envp, File dir) + throws IOException { + if (command.length() == 0) + throw new IllegalArgumentException("Empty command"); + + StringTokenizer st = new StringTokenizer(command); + String[] cmdarray = new String[st.countTokens()]; + for (int i = 0; st.hasMoreTokens(); i++) + cmdarray[i] = st.nextToken(); + return exec(cmdarray, envp, dir); + } + + /** + * Executes the specified command and arguments in a separate process. + * + *

This is a convenience method. An invocation of the form + * exec(cmdarray) + * behaves in exactly the same way as the invocation + * {@link #exec(String[], String[], File) exec}(cmdarray, null, null). + * + * @param cmdarray array containing the command to call and + * its arguments. + * + * @return A new {@link Process} object for managing the subprocess + * + * @throws SecurityException + * If a security manager exists and its + * {@link SecurityManager#checkExec checkExec} + * method doesn't allow creation of the subprocess + * + * @throws IOException + * If an I/O error occurs + * + * @throws NullPointerException + * If cmdarray is null, + * or one of the elements of cmdarray is null + * + * @throws IndexOutOfBoundsException + * If cmdarray is an empty array + * (has length 0) + * + * @see ProcessBuilder + */ + public Process exec(String cmdarray[]) throws IOException { + return exec(cmdarray, null, null); + } + + /** + * Executes the specified command and arguments in a separate process + * with the specified environment. + * + *

This is a convenience method. An invocation of the form + * exec(cmdarray, envp) + * behaves in exactly the same way as the invocation + * {@link #exec(String[], String[], File) exec}(cmdarray, envp, null). + * + * @param cmdarray array containing the command to call and + * its arguments. + * + * @param envp array of strings, each element of which + * has environment variable settings in the format + * name=value, or + * null if the subprocess should inherit + * the environment of the current process. + * + * @return A new {@link Process} object for managing the subprocess + * + * @throws SecurityException + * If a security manager exists and its + * {@link SecurityManager#checkExec checkExec} + * method doesn't allow creation of the subprocess + * + * @throws IOException + * If an I/O error occurs + * + * @throws NullPointerException + * If cmdarray is null, + * or one of the elements of cmdarray is null, + * or one of the elements of envp is null + * + * @throws IndexOutOfBoundsException + * If cmdarray is an empty array + * (has length 0) + * + * @see ProcessBuilder + */ + public Process exec(String[] cmdarray, String[] envp) throws IOException { + return exec(cmdarray, envp, null); + } + + + /** + * Executes the specified command and arguments in a separate process with + * the specified environment and working directory. + * + *

Given an array of strings cmdarray, representing the + * tokens of a command line, and an array of strings envp, + * representing "environment" variable settings, this method creates + * a new process in which to execute the specified command. + * + *

This method checks that cmdarray is a valid operating + * system command. Which commands are valid is system-dependent, + * but at the very least the command must be a non-empty list of + * non-null strings. + * + *

If envp is null, the subprocess inherits the + * environment settings of the current process. + * + *

A minimal set of system dependent environment variables may + * be required to start a process on some operating systems. + * As a result, the subprocess may inherit additional environment variable + * settings beyond those in the specified environment. + * + *

{@link ProcessBuilder#start()} is now the preferred way to + * start a process with a modified environment. + * + *

The working directory of the new subprocess is specified by dir. + * If dir is null, the subprocess inherits the + * current working directory of the current process. + * + *

If a security manager exists, its + * {@link SecurityManager#checkExec checkExec} + * method is invoked with the first component of the array + * cmdarray as its argument. This may result in a + * {@link SecurityException} being thrown. + * + *

Starting an operating system process is highly system-dependent. + * Among the many things that can go wrong are: + *

    + *
  • The operating system program file was not found. + *
  • Access to the program file was denied. + *
  • The working directory does not exist. + *
+ * + *

In such cases an exception will be thrown. The exact nature + * of the exception is system-dependent, but it will always be a + * subclass of {@link IOException}. + * + * + * @param cmdarray array containing the command to call and + * its arguments. + * + * @param envp array of strings, each element of which + * has environment variable settings in the format + * name=value, or + * null if the subprocess should inherit + * the environment of the current process. + * + * @param dir the working directory of the subprocess, or + * null if the subprocess should inherit + * the working directory of the current process. + * + * @return A new {@link Process} object for managing the subprocess + * + * @throws SecurityException + * If a security manager exists and its + * {@link SecurityManager#checkExec checkExec} + * method doesn't allow creation of the subprocess + * + * @throws IOException + * If an I/O error occurs + * + * @throws NullPointerException + * If cmdarray is null, + * or one of the elements of cmdarray is null, + * or one of the elements of envp is null + * + * @throws IndexOutOfBoundsException + * If cmdarray is an empty array + * (has length 0) + * + * @see ProcessBuilder + * @since 1.3 + */ + public Process exec(String[] cmdarray, String[] envp, File dir) + throws IOException { + return new ProcessBuilder(cmdarray) + .environment(envp) + .directory(dir) + .start(); + } + + /** + * Returns the number of processors available to the Java virtual machine. + * + *

This value may change during a particular invocation of the virtual + * machine. Applications that are sensitive to the number of available + * processors should therefore occasionally poll this property and adjust + * their resource usage appropriately.

+ * + * @return the maximum number of processors available to the virtual + * machine; never smaller than one + * @since 1.4 + */ + public int availableProcessors() { + return (int) Libcore.os.sysconf(_SC_NPROCESSORS_CONF); + } + + /** + * Returns the amount of free memory in the Java Virtual Machine. + * Calling the + * gc method may result in increasing the value returned + * by freeMemory. + * + * @return an approximation to the total amount of memory currently + * available for future allocated objects, measured in bytes. + */ + @FastNative + public native long freeMemory(); + + /** + * Returns the total amount of memory in the Java virtual machine. + * The value returned by this method may vary over time, depending on + * the host environment. + *

+ * Note that the amount of memory required to hold an object of any + * given type may be implementation-dependent. + * + * @return the total amount of memory currently available for current + * and future objects, measured in bytes. + */ + @FastNative + public native long totalMemory(); + + /** + * Returns the maximum amount of memory that the Java virtual machine will + * attempt to use. If there is no inherent limit then the value {@link + * java.lang.Long#MAX_VALUE} will be returned. + * + * @return the maximum amount of memory that the virtual machine will + * attempt to use, measured in bytes + * @since 1.4 + */ + @FastNative + public native long maxMemory(); + + /** + * Runs the garbage collector. + * Calling this method suggests that the Java virtual machine expend + * effort toward recycling unused objects in order to make the memory + * they currently occupy available for quick reuse. When control + * returns from the method call, the virtual machine has made + * its best effort to recycle all discarded objects. + *

+ * The name gc stands for "garbage + * collector". The virtual machine performs this recycling + * process automatically as needed, in a separate thread, even if the + * gc method is not invoked explicitly. + *

+ * The method {@link System#gc()} is the conventional and convenient + * means of invoking this method. + */ + public native void gc(); + + /* Wormhole for calling java.lang.ref.Finalizer.runFinalization */ + private static native void runFinalization0(); + + /** + * Runs the finalization methods of any objects pending finalization. + * Calling this method suggests that the Java virtual machine expend + * effort toward running the finalize methods of objects + * that have been found to be discarded but whose finalize + * methods have not yet been run. When control returns from the + * method call, the virtual machine has made a best effort to + * complete all outstanding finalizations. + *

+ * The virtual machine performs the finalization process + * automatically as needed, in a separate thread, if the + * runFinalization method is not invoked explicitly. + *

+ * The method {@link System#runFinalization()} is the conventional + * and convenient means of invoking this method. + * + * @see java.lang.Object#finalize() + */ + public void runFinalization() { + VMRuntime.runFinalization(0); + } + + /** + * Enables/Disables tracing of instructions. + * If the boolean argument is true, this + * method suggests that the Java virtual machine emit debugging + * information for each instruction in the virtual machine as it + * is executed. The format of this information, and the file or other + * output stream to which it is emitted, depends on the host environment. + * The virtual machine may ignore this request if it does not support + * this feature. The destination of the trace output is system + * dependent. + *

+ * If the boolean argument is false, this + * method causes the virtual machine to stop performing the + * detailed instruction trace it is performing. + * + * @param on true to enable instruction tracing; + * false to disable this feature. + */ + public void traceInstructions(boolean on) { + } + + /** + * Enables/Disables tracing of method calls. + * If the boolean argument is true, this + * method suggests that the Java virtual machine emit debugging + * information for each method in the virtual machine as it is + * called. The format of this information, and the file or other output + * stream to which it is emitted, depends on the host environment. The + * virtual machine may ignore this request if it does not support + * this feature. + *

+ * Calling this method with argument false suggests that the + * virtual machine cease emitting per-call debugging information. + *

+ * Calling this method on Android Lollipop or later (API level >= 21) + * with {@code true} argument will cause it to throw an + * {@code UnsupportedOperationException}. + * + * @param on true to enable instruction tracing; + * false to disable this feature. + */ + public void traceMethodCalls(boolean on) { + if (on != tracingMethods) { + if (on) { + VMDebug.startMethodTracing(); + } else { + VMDebug.stopMethodTracing(); + } + tracingMethods = on; + } + } + + /** + * Loads the native library specified by the filename argument. The filename + * argument must be an absolute path name. + * (for example + * Runtime.getRuntime().load("/home/avh/lib/libX11.so");). + * + * If the filename argument, when stripped of any platform-specific library + * prefix, path, and file extension, indicates a library whose name is, + * for example, L, and a native library called L is statically linked + * with the VM, then the JNI_OnLoad_L function exported by the library + * is invoked rather than attempting to load a dynamic library. + * A filename matching the argument does not have to exist in the file + * system. See the JNI Specification for more details. + * + * Otherwise, the filename argument is mapped to a native library image in + * an implementation-dependent manner. + *

+ * First, if there is a security manager, its checkLink + * method is called with the filename as its argument. + * This may result in a security exception. + *

+ * This is similar to the method {@link #loadLibrary(String)}, but it + * accepts a general file name as an argument rather than just a library + * name, allowing any file of native code to be loaded. + *

+ * The method {@link System#load(String)} is the conventional and + * convenient means of invoking this method. + * + * @param filename the file to load. + * @exception SecurityException if a security manager exists and its + * checkLink method doesn't allow + * loading of the specified dynamic library + * @exception UnsatisfiedLinkError if either the filename is not an + * absolute path name, the native library is not statically + * linked with the VM, or the library cannot be mapped to + * a native library image by the host system. + * @exception NullPointerException if filename is + * null + * @see java.lang.Runtime#getRuntime() + * @see java.lang.SecurityException + * @see java.lang.SecurityManager#checkLink(java.lang.String) + */ + @CallerSensitive + public void load(String filename) { + load0(VMStack.getStackClass1(), filename); + } + + /** Check target sdk, if it's higher than N, we throw an UnsupportedOperationException */ + private void checkTargetSdkVersionForLoad(String methodName) { + final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion(); + if (targetSdkVersion > 24) { + throw new UnsupportedOperationException(methodName + " is not supported on SDK " + + targetSdkVersion); + } + } + + // Fixes b/25859957 regression. Depending on private methods is bad, mkay. + void load(String absolutePath, ClassLoader loader) { + checkTargetSdkVersionForLoad("java.lang.Runtime#load(String, ClassLoader)"); + + java.lang.System.logE("java.lang.Runtime#load(String, ClassLoader)" + + " is private and will be removed in a future Android release"); + if (absolutePath == null) { + throw new NullPointerException("absolutePath == null"); + } + String error = doLoad(absolutePath, loader); + if (error != null) { + throw new UnsatisfiedLinkError(error); + } + } + + synchronized void load0(Class fromClass, String filename) { + if (!(new File(filename).isAbsolute())) { + throw new UnsatisfiedLinkError( + "Expecting an absolute path of the library: " + filename); + } + if (filename == null) { + throw new NullPointerException("filename == null"); + } + String error = doLoad(filename, fromClass.getClassLoader()); + if (error != null) { + throw new UnsatisfiedLinkError(error); + } + } + + /** + * Loads the native library specified by the libname + * argument. The libname argument must not contain any platform + * specific prefix, file extension or path. If a native library + * called libname is statically linked with the VM, then the + * JNI_OnLoad_libname function exported by the library is invoked. + * See the JNI Specification for more details. + * + * Otherwise, the libname argument is loaded from a system library + * location and mapped to a native library image in an implementation- + * dependent manner. + *

+ * First, if there is a security manager, its checkLink + * method is called with the libname as its argument. + * This may result in a security exception. + *

+ * The method {@link System#loadLibrary(String)} is the conventional + * and convenient means of invoking this method. If native + * methods are to be used in the implementation of a class, a standard + * strategy is to put the native code in a library file (call it + * LibFile) and then to put a static initializer: + *

+     * static { System.loadLibrary("LibFile"); }
+     * 
+ * within the class declaration. When the class is loaded and + * initialized, the necessary native code implementation for the native + * methods will then be loaded as well. + *

+ * If this method is called more than once with the same library + * name, the second and subsequent calls are ignored. + * + * @param libname the name of the library. + * @exception SecurityException if a security manager exists and its + * checkLink method doesn't allow + * loading of the specified dynamic library + * @exception UnsatisfiedLinkError if either the libname argument + * contains a file path, the native library is not statically + * linked with the VM, or the library cannot be mapped to a + * native library image by the host system. + * @exception NullPointerException if libname is + * null + * @see java.lang.SecurityException + * @see java.lang.SecurityManager#checkLink(java.lang.String) + */ + @CallerSensitive + public void loadLibrary(String libname) { + loadLibrary0(VMStack.getCallingClassLoader(), libname); + } + + /** + * Temporarily preserved for backward compatibility. Applications call this + * method using reflection. + * + * **** THIS METHOD WILL BE REMOVED IN A FUTURE ANDROID VERSION **** + * + * http://b/26217329 + * + * @hide + */ + public void loadLibrary(String libname, ClassLoader classLoader) { + checkTargetSdkVersionForLoad("java.lang.Runtime#loadLibrary(String, ClassLoader)"); + java.lang.System.logE("java.lang.Runtime#loadLibrary(String, ClassLoader)" + + " is private and will be removed in a future Android release"); + loadLibrary0(classLoader, libname); + } + + synchronized void loadLibrary0(ClassLoader loader, String libname) { + if (libname.indexOf((int)File.separatorChar) != -1) { + throw new UnsatisfiedLinkError( + "Directory separator should not appear in library name: " + libname); + } + String libraryName = libname; + if (loader != null) { + String filename = loader.findLibrary(libraryName); + if (filename == null) { + // It's not necessarily true that the ClassLoader used + // System.mapLibraryName, but the default setup does, and it's + // misleading to say we didn't find "libMyLibrary.so" when we + // actually searched for "liblibMyLibrary.so.so". + throw new UnsatisfiedLinkError(loader + " couldn't find \"" + + System.mapLibraryName(libraryName) + "\""); + } + String error = doLoad(filename, loader); + if (error != null) { + throw new UnsatisfiedLinkError(error); + } + return; + } + + String filename = System.mapLibraryName(libraryName); + List candidates = new ArrayList(); + String lastError = null; + for (String directory : getLibPaths()) { + String candidate = directory + filename; + candidates.add(candidate); + + if (IoUtils.canOpenReadOnly(candidate)) { + String error = doLoad(candidate, loader); + if (error == null) { + return; // We successfully loaded the library. Job done. + } + lastError = error; + } + } + + if (lastError != null) { + throw new UnsatisfiedLinkError(lastError); + } + throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates); + } + + private volatile String[] mLibPaths = null; + + private String[] getLibPaths() { + if (mLibPaths == null) { + synchronized(this) { + if (mLibPaths == null) { + mLibPaths = initLibPaths(); + } + } + } + return mLibPaths; + } + + private static String[] initLibPaths() { + String javaLibraryPath = System.getProperty("java.library.path"); + if (javaLibraryPath == null) { + return EmptyArray.STRING; + } + String[] paths = javaLibraryPath.split(":"); + // Add a '/' to the end of each directory so we don't have to do it every time. + for (int i = 0; i < paths.length; ++i) { + if (!paths[i].endsWith("/")) { + paths[i] += "/"; + } + } + return paths; + } + private String doLoad(String name, ClassLoader loader) { + // Android apps are forked from the zygote, so they can't have a custom LD_LIBRARY_PATH, + // which means that by default an app's shared library directory isn't on LD_LIBRARY_PATH. + + // The PathClassLoader set up by frameworks/base knows the appropriate path, so we can load + // libraries with no dependencies just fine, but an app that has multiple libraries that + // depend on each other needed to load them in most-dependent-first order. + + // We added API to Android's dynamic linker so we can update the library path used for + // the currently-running process. We pull the desired path out of the ClassLoader here + // and pass it to nativeLoad so that it can call the private dynamic linker API. + + // We didn't just change frameworks/base to update the LD_LIBRARY_PATH once at the + // beginning because multiple apks can run in the same process and third party code can + // use its own BaseDexClassLoader. + + // We didn't just add a dlopen_with_custom_LD_LIBRARY_PATH call because we wanted any + // dlopen(3) calls made from a .so's JNI_OnLoad to work too. + + // So, find out what the native library search path is for the ClassLoader in question... + String librarySearchPath = null; + if (loader != null && loader instanceof BaseDexClassLoader) { + BaseDexClassLoader dexClassLoader = (BaseDexClassLoader) loader; + librarySearchPath = dexClassLoader.getLdLibraryPath(); + } + // nativeLoad should be synchronized so there's only one LD_LIBRARY_PATH in use regardless + // of how many ClassLoaders are in the system, but dalvik doesn't support synchronized + // internal natives. + synchronized (this) { + return nativeLoad(name, loader, librarySearchPath); + } + } + + // TODO: should be synchronized, but dalvik doesn't support synchronized internal natives. + private static native String nativeLoad(String filename, ClassLoader loader, + String librarySearchPath); + + /** + * Creates a localized version of an input stream. This method takes + * an InputStream and returns an InputStream + * equivalent to the argument in all respects except that it is + * localized: as characters in the local character set are read from + * the stream, they are automatically converted from the local + * character set to Unicode. + *

+ * If the argument is already a localized stream, it may be returned + * as the result. + * + * @param in InputStream to localize + * @return a localized input stream + * @see java.io.InputStream + * @see java.io.BufferedReader#BufferedReader(java.io.Reader) + * @see java.io.InputStreamReader#InputStreamReader(java.io.InputStream) + * @deprecated As of JDK 1.1, the preferred way to translate a byte + * stream in the local encoding into a character stream in Unicode is via + * the InputStreamReader and BufferedReader + * classes. + */ + @Deprecated + public InputStream getLocalizedInputStream(InputStream in) { + return in; + } + + /** + * Creates a localized version of an output stream. This method + * takes an OutputStream and returns an + * OutputStream equivalent to the argument in all respects + * except that it is localized: as Unicode characters are written to + * the stream, they are automatically converted to the local + * character set. + *

+ * If the argument is already a localized stream, it may be returned + * as the result. + * + * @deprecated As of JDK 1.1, the preferred way to translate a + * Unicode character stream into a byte stream in the local encoding is via + * the OutputStreamWriter, BufferedWriter, and + * PrintWriter classes. + * + * @param out OutputStream to localize + * @return a localized output stream + * @see java.io.OutputStream + * @see java.io.BufferedWriter#BufferedWriter(java.io.Writer) + * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream) + * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream) + */ + @Deprecated + public OutputStream getLocalizedOutputStream(OutputStream out) { + return out; + } + +} diff --git a/src/MapleFE/test/java/openjdk/Runtime.java.result b/src/MapleFE/test/java/openjdk/Runtime.java.result new file mode 100644 index 0000000000000000000000000000000000000000..7e96553a7a5b9943a44f7411a2714915bfad15db --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Runtime.java.result @@ -0,0 +1,319 @@ +Matched 5 tokens. +Matched 14 tokens. +Matched 21 tokens. +Matched 28 tokens. +Matched 35 tokens. +Matched 44 tokens. +Matched 51 tokens. +Matched 58 tokens. +Matched 65 tokens. +Matched 72 tokens. +Matched 79 tokens. +Matched 86 tokens. +Matched 93 tokens. +Matched 100 tokens. +Matched 107 tokens. +Matched 117 tokens. +Matched 1578 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import dalvik.annotation.optimization.FastNative +== Sub Tree == +import java.io +== Sub Tree == +import java.util.StringTokenizer +== Sub Tree == +import sun.reflect.CallerSensitive +== Sub Tree == +import java.lang.ref.FinalizerReference +== Sub Tree == +import java.util.ArrayList +== Sub Tree == +import java.util.List +== Sub Tree == +import dalvik.system.BaseDexClassLoader +== Sub Tree == +import dalvik.system.VMDebug +== Sub Tree == +import dalvik.system.VMStack +== Sub Tree == +import dalvik.system.VMRuntime +== Sub Tree == +import libcore.io.IoUtils +== Sub Tree == +import libcore.io.Libcore +== Sub Tree == +import libcore.util.EmptyArray +== Sub Tree == +import static android.system.OsConstants._SC_NPROCESSORS_CONF +== Sub Tree == +class Runtime + Fields: + currentRuntime=new Runtime() shutdownHooks=new ArrayList() finalizeOnExit shuttingDown tracingMethods mLibPaths=null + Instance Initializer: + Constructors: + constructor Runtime() throws: + Methods: + func nativeExit(code) throws: + func getRuntime() throws: + return currentRuntime + func exit(status) throws: + cond-branch cond:shuttingDown + true branch : + shuttingDown Assign true + Decl: hooks + hooks Assign + shutdownHooks.toArray(hooks) + + Thread + hook + hooks + hook.start() + + Thread + hook + hooks + hook.join() + + InterruptedException + ex + + + cond-branch cond:finalizeOnExit + true branch : + runFinalization() + false branch : + + nativeExit(status) + false branch : + + + func addShutdownHook(hook) throws: + cond-branch cond:hook EQ null + true branch : + new NullPointerException("hook == null") + false branch : + + cond-branch cond:shuttingDown + true branch : + new IllegalStateException("VM already shutting down") + false branch : + + cond-branch cond:hook.started + true branch : + new IllegalArgumentException("Hook has already been started") + false branch : + + cond-branch cond:shutdownHooks.contains(hook) + true branch : + new IllegalArgumentException("Hook already registered.") + false branch : + + shutdownHooks.add(hook) + + func removeShutdownHook(hook) throws: + cond-branch cond:hook EQ null + true branch : + new NullPointerException("hook == null") + false branch : + + cond-branch cond:shuttingDown + true branch : + new IllegalStateException("VM already shutting down") + false branch : + + return shutdownHooks.remove(hook) + + func halt(status) throws: + nativeExit(status) + func runFinalizersOnExit(value) throws: + finalizeOnExit Assign value + func exec(command) throws: IOException + return exec(command,null,null) + func exec(command,envp) throws: IOException + return exec(command,envp,null) + func exec(command,envp,dir) throws: IOException + cond-branch cond:command.length() EQ 0 + true branch : + new IllegalArgumentException("Empty command") false branch : + + Decl: st=new StringTokenizer(command) + Decl: cmdarray= + for ( ) + Assign st.nextToken() + return exec(cmdarray,envp,dir) + func exec(cmdarray[]) throws: IOException + return exec(cmdarray,null,null) + func exec(cmdarray,envp) throws: IOException + return exec(cmdarray,envp,null) + func exec(cmdarray,envp,dir) throws: IOException + return new ProcessBuilder(cmdarray).environment(envp).directory(dir).start() + func availableProcessors() throws: + return (int)Libcore.os.sysconf(_SC_NPROCESSORS_CONF) + func freeMemory() throws: + func totalMemory() throws: + func maxMemory() throws: + func gc() throws: + func runFinalization0() throws: + func runFinalization() throws: + VMRuntime.runFinalization(0) + func traceInstructions(on) throws: + func traceMethodCalls(on) throws: + cond-branch cond:on NE tracingMethods + true branch : + cond-branch cond:on + true branch : + VMDebug.startMethodTracing() + false branch : + VMDebug.stopMethodTracing() + + tracingMethods Assign on + false branch : + + func load(filename) throws: + load0(VMStack.getStackClass1(),filename) + func checkTargetSdkVersionForLoad(methodName) throws: + Decl: targetSdkVersion=VMRuntime.getRuntime().getTargetSdkVersion() + cond-branch cond:targetSdkVersion GT 24 + true branch : + new UnsupportedOperationException(methodName Add " is not supported on SDK " Add targetSdkVersion) + false branch : + + func load(absolutePath,loader) throws: + checkTargetSdkVersionForLoad("java.lang.Runtime#load(String, ClassLoader)") + java.lang.System.logE("java.lang.Runtime#load(String, ClassLoader)" Add " is private and will be removed in a future Android release") + cond-branch cond:absolutePath EQ null + true branch : + new NullPointerException("absolutePath == null") + false branch : + + Decl: error=doLoad(absolutePath,loader) + cond-branch cond:error NE null + true branch : + new UnsatisfiedLinkError(error) + false branch : + + func load0(fromClass,filename) throws: + cond-branch cond:(new File(filename).isAbsolute()) + true branch : + new UnsatisfiedLinkError("Expecting an absolute path of the library: " Add filename) + false branch : + + cond-branch cond:filename EQ null + true branch : + new NullPointerException("filename == null") + false branch : + + Decl: error=doLoad(filename,fromClass.getClassLoader()) + cond-branch cond:error NE null + true branch : + new UnsatisfiedLinkError(error) + false branch : + + func loadLibrary(libname) throws: + loadLibrary0(VMStack.getCallingClassLoader(),libname) + func loadLibrary(libname,classLoader) throws: + checkTargetSdkVersionForLoad("java.lang.Runtime#loadLibrary(String, ClassLoader)") + java.lang.System.logE("java.lang.Runtime#loadLibrary(String, ClassLoader)" Add " is private and will be removed in a future Android release") + loadLibrary0(classLoader,libname) + func loadLibrary0(loader,libname) throws: + cond-branch cond:libname.indexOf((int)File.separatorChar) NE -1 + true branch : + new UnsatisfiedLinkError("Directory separator should not appear in library name: " Add libname) + false branch : + + Decl: libraryName=libname + cond-branch cond:loader NE null + true branch : + Decl: filename=loader.findLibrary(libraryName) + cond-branch cond:filename EQ null + true branch : + new UnsatisfiedLinkError(loader Add " couldn't find \"" Add System.mapLibraryName(libraryName) Add "\"") + false branch : + + Decl: error=doLoad(filename,loader) + cond-branch cond:error NE null + true branch : + new UnsatisfiedLinkError(error) + false branch : + + return + false branch : + + Decl: filename=System.mapLibraryName(libraryName) + Decl: candidates=new ArrayList() + Decl: lastError=null + String + directory + getLibPaths() + Decl: candidate=directory Add filename + candidates.add(candidate) + cond-branch cond:IoUtils.canOpenReadOnly(candidate) + true branch : + Decl: error=doLoad(candidate,loader) + cond-branch cond:error EQ null + true branch : + return + false branch : + + lastError Assign error + false branch : + + + cond-branch cond:lastError NE null + true branch : + new UnsatisfiedLinkError(lastError) + false branch : + + new UnsatisfiedLinkError("Library " Add libraryName Add " not found; tried " Add candidates) + func getLibPaths() throws: + cond-branch cond:mLibPaths EQ null + true branch : + cond-branch cond:mLibPaths EQ null + true branch : + mLibPaths Assign initLibPaths() + false branch : + + + false branch : + + return mLibPaths + func initLibPaths() throws: + Decl: javaLibraryPath=System.getProperty("java.library.path") + cond-branch cond:javaLibraryPath EQ null + true branch : + return EmptyArray.STRING + false branch : + + Decl: paths=javaLibraryPath.split(":") + for ( ) + cond-branch cond:.endsWith("/") + true branch : + AddAssign "/" + false branch : + + + return paths + func doLoad(name,loader) throws: + Decl: librarySearchPath=null + cond-branch cond:loader NE null Land loader instanceof BaseDexClassLoader + true branch : + Decl: dexClassLoader=(BaseDexClassLoader)loader + librarySearchPath Assign dexClassLoader.getLdLibraryPath() + false branch : + + return nativeLoad(name,loader,librarySearchPath) + + func nativeLoad(filename,loader,librarySearchPath) throws: + func getLocalizedInputStream(in) throws: + return in + func getLocalizedOutputStream(out) throws: + return out + LocalClasses: + LocalInterfaces: + +Identifier:String has no decl. +Identifier:directory has no decl. +UserType:UnsatisfiedLinkError has no decl. diff --git a/src/MapleFE/test/java/openjdk/SafeVarargs.java b/src/MapleFE/test/java/openjdk/SafeVarargs.java new file mode 100644 index 0000000000000000000000000000000000000000..243b9f1fc95c746a69ab290aeab6b377ac12f73e --- /dev/null +++ b/src/MapleFE/test/java/openjdk/SafeVarargs.java @@ -0,0 +1,33 @@ + +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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. + */ +package java.lang; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +/** + * Claims to the compiler that the annotation target does nothing potentially unsafe + * to its varargs argument. + * + * @since 1.7 + */ +@Documented +@Retention(value=RetentionPolicy.RUNTIME) +@Target(value={ElementType.CONSTRUCTOR, ElementType.METHOD}) +public @interface SafeVarargs { +} diff --git a/src/MapleFE/test/java/openjdk/SafeVarargs.java.result b/src/MapleFE/test/java/openjdk/SafeVarargs.java.result new file mode 100644 index 0000000000000000000000000000000000000000..1d1ab5064a0f9d34c5e0e8c17c9a389ff739eeb6 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/SafeVarargs.java.result @@ -0,0 +1,22 @@ +Matched 5 tokens. +Matched 14 tokens. +Matched 23 tokens. +Matched 32 tokens. +Matched 41 tokens. +Matched 50 tokens. +Matched 82 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import java.lang.annotation.Documented +== Sub Tree == +import java.lang.annotation.ElementType +== Sub Tree == +import java.lang.annotation.Retention +== Sub Tree == +import java.lang.annotation.RetentionPolicy +== Sub Tree == +import java.lang.annotation.Target +== Sub Tree == +annotation type : SafeVarargs diff --git a/src/MapleFE/test/java/openjdk/SecurityManager.java b/src/MapleFE/test/java/openjdk/SecurityManager.java new file mode 100644 index 0000000000000000000000000000000000000000..2182ca6e22322ce1beb9638cc301e29014d7cc8e --- /dev/null +++ b/src/MapleFE/test/java/openjdk/SecurityManager.java @@ -0,0 +1,108 @@ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package java.lang; +import java.io.FileDescriptor; +import java.net.InetAddress; +import java.security.Permission; +/** + * Legacy security code; do not use. + * + *

Security managers do not provide a + * secure environment for executing untrusted code. Untrusted code cannot be + * safely isolated within the Dalvik VM. + */ +public class SecurityManager { + /** + * @deprecated Use {@link #checkPermission} + */ + @Deprecated + protected boolean inCheck; + public SecurityManager() { } + public void checkAccept(String host, int port) { } + public void checkAccess(Thread thread) { } + public void checkAccess(ThreadGroup group) { } + public void checkConnect(String host, int port) { } + public void checkConnect(String host, int port, Object context) { } + public void checkCreateClassLoader() { } + public void checkDelete(String file) { } + public void checkExec(String cmd) { } + public void checkExit(int status) { } + public void checkLink(String libName) { } + public void checkListen(int port) { } + public void checkMemberAccess(Class cls, int type) { } + public void checkMulticast(InetAddress maddr) { } + /** + * @deprecated use {@link #checkMulticast(java.net.InetAddress)} + */ + @Deprecated public void checkMulticast(InetAddress maddr, byte ttl) { } + public void checkPackageAccess(String packageName) { } + public void checkPackageDefinition(String packageName) { } + public void checkPropertiesAccess() { } + public void checkPropertyAccess(String key) { } + public void checkRead(FileDescriptor fd) { } + public void checkRead(String file) { } + public void checkRead(String file, Object context) { } + public void checkSecurityAccess(String target) { } + public void checkSetFactory() { } + public boolean checkTopLevelWindow(Object window) { return true; } + public void checkSystemClipboardAccess() { } + public void checkAwtEventQueueAccess() { } + public void checkPrintJobAccess() { } + public void checkWrite(FileDescriptor fd) { } + public void checkWrite(String file) { } + /** + * @deprecated Use {@link #checkPermission}. + */ + @Deprecated public boolean getInCheck() { return inCheck; } + protected Class[] getClassContext() { return null; } + /** + * @deprecated Use {@link #checkPermission}. + */ + @Deprecated protected ClassLoader currentClassLoader() { return null; } + /** + * @deprecated Use {@link #checkPermission}. + */ + @Deprecated protected int classLoaderDepth() { + return -1; + } + /** + * @deprecated Use {@link #checkPermission}. + */ + @Deprecated protected Class currentLoadedClass() { return null; } + /** + * @deprecated Use {@link #checkPermission}. + */ + @Deprecated protected int classDepth(String name) { return -1; } + /** + * @deprecated Use {@link #checkPermission}. + */ + @Deprecated protected boolean inClass(String name) { return false; } + /** + * @deprecated Use {@link #checkPermission} + */ + @Deprecated protected boolean inClassLoader() { return false; } + /** + * Returns the current thread's thread group. + */ + public ThreadGroup getThreadGroup() { + return Thread.currentThread().getThreadGroup(); + } + public Object getSecurityContext() { return null; } + public void checkPermission(Permission permission) { } + public void checkPermission(Permission permission, Object context) { } +} diff --git a/src/MapleFE/test/java/openjdk/SecurityManager.java.result b/src/MapleFE/test/java/openjdk/SecurityManager.java.result new file mode 100644 index 0000000000000000000000000000000000000000..fad7670e870adc19712c7ccac717013294dc6a74 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/SecurityManager.java.result @@ -0,0 +1,77 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 19 tokens. +Matched 26 tokens. +Matched 475 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import java.io.FileDescriptor +== Sub Tree == +import java.net.InetAddress +== Sub Tree == +import java.security.Permission +== Sub Tree == +class SecurityManager + Fields: + inCheck + Instance Initializer: + Constructors: + constructor SecurityManager() throws: + Methods: + func checkAccept(host,port) throws: + func checkAccess(thread) throws: + func checkAccess(group) throws: + func checkConnect(host,port) throws: + func checkConnect(host,port,context) throws: + func checkCreateClassLoader() throws: + func checkDelete(file) throws: + func checkExec(cmd) throws: + func checkExit(status) throws: + func checkLink(libName) throws: + func checkListen(port) throws: + func checkMemberAccess(cls,type) throws: + func checkMulticast(maddr) throws: + func checkMulticast(maddr,ttl) throws: + func checkPackageAccess(packageName) throws: + func checkPackageDefinition(packageName) throws: + func checkPropertiesAccess() throws: + func checkPropertyAccess(key) throws: + func checkRead(fd) throws: + func checkRead(file) throws: + func checkRead(file,context) throws: + func checkSecurityAccess(target) throws: + func checkSetFactory() throws: + func checkTopLevelWindow(window) throws: + return true + func checkSystemClipboardAccess() throws: + func checkAwtEventQueueAccess() throws: + func checkPrintJobAccess() throws: + func checkWrite(fd) throws: + func checkWrite(file) throws: + func getInCheck() throws: + return inCheck + func getClassContext() throws: + return null + func currentClassLoader() throws: + return null + func classLoaderDepth() throws: + return -1 + func currentLoadedClass() throws: + return null + func classDepth(name) throws: + return -1 + func inClass(name) throws: + return false + func inClassLoader() throws: + return false + func getThreadGroup() throws: + return Thread.currentThread().getThreadGroup() + func getSecurityContext() throws: + return null + func checkPermission(permission) throws: + func checkPermission(permission,context) throws: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/java/openjdk/Short.java b/src/MapleFE/test/java/openjdk/Short.java new file mode 100644 index 0000000000000000000000000000000000000000..17324fb296bcf3ca873934de606ca7da3b3b85e6 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Short.java @@ -0,0 +1,290 @@ + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package java.lang; +/** + * The wrapper for the primitive type {@code short}. + * + * @see java.lang.Number + * @since 1.1 + */ +@FindBugsSuppressWarnings("DM_NUMBER_CTOR") +public final class Short extends Number implements Comparable { + private static final long serialVersionUID = 7515723908773894738L; + /** + * The value which the receiver represents. + */ + private final short value; + /** + * Constant for the maximum {@code short} value, 215-1. + */ + public static final short MAX_VALUE = (short) 0x7FFF; + /** + * Constant for the minimum {@code short} value, -215. + */ + public static final short MIN_VALUE = (short) 0x8000; + /** + * Constant for the number of bits needed to represent a {@code short} in + * two's complement form. + * + * @since 1.5 + */ + public static final int SIZE = 16; + /** + * The {@link Class} object that represents the primitive type {@code + * short}. + */ + @SuppressWarnings("unchecked") + public static final Class TYPE + = (Class) short[].class.getComponentType(); + // Note: Short.TYPE can't be set to "short.class", since *that* is + // defined to be "java.lang.Short.TYPE"; + /** + * Constructs a new {@code Short} from the specified string. + * + * @param string + * the string representation of a short value. + * @throws NumberFormatException + * if {@code string} cannot be parsed as a short value. + * @see #parseShort(String) + */ + public Short(String string) throws NumberFormatException { + this(parseShort(string)); + } + /** + * Constructs a new {@code Short} with the specified primitive short value. + * + * @param value + * the primitive short value to store in the new instance. + */ + public Short(short value) { + this.value = value; + } + @Override + public byte byteValue() { + return (byte) value; + } + /** + * Compares this object to the specified short object to determine their + * relative order. + * + * @param object + * the short object to compare this object to. + * @return a negative value if the value of this short is less than the + * value of {@code object}; 0 if the value of this short and the + * value of {@code object} are equal; a positive value if the value + * of this short is greater than the value of {@code object}. + * @throws NullPointerException + * if {@code object} is null. + * @see java.lang.Comparable + * @since 1.2 + */ + public int compareTo(Short object) { + return compare(value, object.value); + } + /** + * Compares two {@code short} values. + * @return 0 if lhs = rhs, less than 0 if lhs < rhs, and greater than 0 if lhs > rhs. + * @since 1.7 + */ + public static int compare(short lhs, short rhs) { + return lhs > rhs ? 1 : (lhs < rhs ? -1 : 0); + } + /** + * Parses the specified string and returns a {@code Short} instance if the + * string can be decoded into a short value. The string may be an optional + * minus sign "-" followed by a hexadecimal ("0x..." or "#..."), octal + * ("0..."), or decimal ("...") representation of a short. + * + * @param string + * a string representation of a short value. + * @return a {@code Short} containing the value represented by + * {@code string}. + * @throws NumberFormatException + * if {@code string} cannot be parsed as a short value. + */ + public static Short decode(String string) throws NumberFormatException { + int intValue = Integer.decode(string).intValue(); + short result = (short) intValue; + if (result == intValue) { + return valueOf(result); + } + throw new NumberFormatException("Value out of range for short: \"" + string + "\""); + } + @Override + public double doubleValue() { + return value; + } + /** + * Compares this instance with the specified object and indicates if they + * are equal. In order to be equal, {@code object} must be an instance of + * {@code Short} and have the same short value as this object. + * + * @param object + * the object to compare this short with. + * @return {@code true} if the specified object is equal to this + * {@code Short}; {@code false} otherwise. + */ + @Override + public boolean equals(Object object) { + return (object instanceof Short) && (((Short) object).value == value); + } + @Override + public float floatValue() { + return value; + } + @Override + public int hashCode() { + return value; + } + @Override + public int intValue() { + return value; + } + @Override + public long longValue() { + return value; + } + /** + * Parses the specified string as a signed decimal short value. The ASCII + * character \u002d ('-') is recognized as the minus sign. + * + * @param string + * the string representation of a short value. + * @return the primitive short value represented by {@code string}. + * @throws NumberFormatException + * if {@code string} cannot be parsed as a short value. + */ + public static short parseShort(String string) throws NumberFormatException { + return parseShort(string, 10); + } + /** + * Parses the specified string as a signed short value using the specified + * radix. The ASCII character \u002d ('-') is recognized as the minus sign. + * + * @param string + * the string representation of a short value. + * @param radix + * the radix to use when parsing. + * @return the primitive short value represented by {@code string} using + * {@code radix}. + * @throws NumberFormatException + * if {@code string} cannot be parsed as a short value, or + * {@code radix < Character.MIN_RADIX || + * radix > Character.MAX_RADIX}. + */ + public static short parseShort(String string, int radix) throws NumberFormatException { + int intValue = Integer.parseInt(string, radix); + short result = (short) intValue; + if (result == intValue) { + return result; + } + throw new NumberFormatException("Value out of range for short: \"" + string + "\""); + } + /** + * Gets the primitive value of this short. + * + * @return this object's primitive value. + */ + @Override + public short shortValue() { + return value; + } + @Override + public String toString() { + return Integer.toString(value); + } + /** + * Returns a string containing a concise, human-readable description of the + * specified short value with radix 10. + * + * @param value + * the short to convert to a string. + * @return a printable representation of {@code value}. + */ + public static String toString(short value) { + return Integer.toString(value); + } + /** + * Parses the specified string as a signed decimal short value. + * + * @param string + * the string representation of a short value. + * @return a {@code Short} instance containing the short value represented + * by {@code string}. + * @throws NumberFormatException + * if {@code string} cannot be parsed as a short value. + * @see #parseShort(String) + */ + public static Short valueOf(String string) throws NumberFormatException { + return valueOf(parseShort(string)); + } + /** + * Parses the specified string as a signed short value using the specified + * radix. + * + * @param string + * the string representation of a short value. + * @param radix + * the radix to use when parsing. + * @return a {@code Short} instance containing the short value represented + * by {@code string} using {@code radix}. + * @throws NumberFormatException + * if {@code string} cannot be parsed as a short value, or + * {@code radix < Character.MIN_RADIX || + * radix > Character.MAX_RADIX}. + * @see #parseShort(String, int) + */ + public static Short valueOf(String string, int radix) throws NumberFormatException { + return valueOf(parseShort(string, radix)); + } + /** + * Reverses the bytes of the specified short. + * + * @param s + * the short value for which to reverse bytes. + * @return the reversed value. + * @since 1.5 + */ + public static short reverseBytes(short s) { + return (short) ((s << 8) | ((s >>> 8) & 0xFF)); + } + /** + * Returns a {@code Short} instance for the specified short value. + *

+ * If it is not necessary to get a new {@code Short} instance, it is + * recommended to use this method instead of the constructor, since it + * maintains a cache of instances which may result in better performance. + * + * @param s + * the short value to store in the instance. + * @return a {@code Short} instance containing {@code s}. + * @since 1.5 + */ + public static Short valueOf(short s) { + return s < -128 || s >= 128 ? new Short(s) : SMALL_VALUES[s + 128]; + } + /** + * A cache of instances used by {@link Short#valueOf(short)} and auto-boxing. + */ + private static final Short[] SMALL_VALUES = new Short[256]; + static { + for (int i = -128; i < 128; i++) { + SMALL_VALUES[i + 128] = new Short((short) i); + } + } +} diff --git a/src/MapleFE/test/java/openjdk/Short.java.result b/src/MapleFE/test/java/openjdk/Short.java.result new file mode 100644 index 0000000000000000000000000000000000000000..f2e1a293dd41b0f80a45ed23d2c3a9570974d0ad --- /dev/null +++ b/src/MapleFE/test/java/openjdk/Short.java.result @@ -0,0 +1,73 @@ +Matched 5 tokens. +Matched 627 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +class Short + Fields: + serialVersionUID=878762578 value MAX_VALUE=(short)32767 MIN_VALUE=(short)32768 SIZE=16 TYPE=()short.getComponentType() SMALL_VALUES= + Instance Initializer: + InstInit- 0 + Constructors: + constructor Short(string) throws: + constructor Short(value) throws: + this.value Assign value + Methods: + func byteValue() throws: + return (byte)value + func compareTo(object) throws: + return compare(value,object.value) + func compare(lhs,rhs) throws: + return + func decode(string) throws: NumberFormatException + Decl: intValue=Integer.decode(string).intValue() + Decl: result=(short)intValue + cond-branch cond:result EQ intValue + true branch : + return valueOf(result) + false branch : + + new NumberFormatException("Value out of range for short: \"" Add string Add "\"") + func doubleValue() throws: + return value + func equals(object) throws: + return (object instanceof Short) Land ((Short)object.value EQ value) + func floatValue() throws: + return value + func hashCode() throws: + return value + func intValue() throws: + return value + func longValue() throws: + return value + func parseShort(string) throws: NumberFormatException + return parseShort(string,10) + func parseShort(string,radix) throws: NumberFormatException + Decl: intValue=Integer.parseInt(string,radix) + Decl: result=(short)intValue + cond-branch cond:result EQ intValue + true branch : + return result + false branch : + + new NumberFormatException("Value out of range for short: \"" Add string Add "\"") + func shortValue() throws: + return value + func toString() throws: + return Integer.toString(value) + func toString(value) throws: + return Integer.toString(value) + func valueOf(string) throws: NumberFormatException + return valueOf(parseShort(string)) + func valueOf(string,radix) throws: NumberFormatException + return valueOf(parseShort(string,radix)) + func reverseBytes(s) throws: + return (short)((s Shl 8) Bor ((s Zext 8) Band 255)) + func valueOf(s) throws: + return + LocalClasses: + LocalInterfaces: + +UserType:NumberFormatException has no decl. +UserType:NumberFormatException has no decl. diff --git a/src/MapleFE/test/java/openjdk/StackTraceElement.java b/src/MapleFE/test/java/openjdk/StackTraceElement.java new file mode 100644 index 0000000000000000000000000000000000000000..e519fea26af9e97cba4e99e6981c10b60dd13446 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/StackTraceElement.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.util.Objects; + +/** + * An element in a stack trace, as returned by {@link + * Throwable#getStackTrace()}. Each element represents a single stack frame. + * All stack frames except for the one at the top of the stack represent + * a method invocation. The frame at the top of the stack represents the + * execution point at which the stack trace was generated. Typically, + * this is the point at which the throwable corresponding to the stack trace + * was created. + * + * @since 1.4 + * @author Josh Bloch + */ +public final class StackTraceElement implements java.io.Serializable { + // Normally initialized by VM (public constructor added in 1.5) + private String declaringClass; + private String methodName; + private String fileName; + private int lineNumber; + + /** + * Creates a stack trace element representing the specified execution + * point. + * + * @param declaringClass the fully qualified name of the class containing + * the execution point represented by the stack trace element + * @param methodName the name of the method containing the execution point + * represented by the stack trace element + * @param fileName the name of the file containing the execution point + * represented by the stack trace element, or {@code null} if + * this information is unavailable + * @param lineNumber the line number of the source line containing the + * execution point represented by this stack trace element, or + * a negative number if this information is unavailable. A value + * of -2 indicates that the method containing the execution point + * is a native method + * @throws NullPointerException if {@code declaringClass} or + * {@code methodName} is null + * @since 1.5 + */ + public StackTraceElement(String declaringClass, String methodName, + String fileName, int lineNumber) { + this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null"); + this.methodName = Objects.requireNonNull(methodName, "Method name is null"); + this.fileName = fileName; + this.lineNumber = lineNumber; + } + + /** + * Returns the name of the source file containing the execution point + * represented by this stack trace element. Generally, this corresponds + * to the {@code SourceFile} attribute of the relevant {@code class} + * file (as per The Java Virtual Machine Specification, Section + * 4.7.7). In some systems, the name may refer to some source code unit + * other than a file, such as an entry in source repository. + * + * @return the name of the file containing the execution point + * represented by this stack trace element, or {@code null} if + * this information is unavailable. + */ + public String getFileName() { + return fileName; + } + + /** + * Returns the line number of the source line containing the execution + * point represented by this stack trace element. Generally, this is + * derived from the {@code LineNumberTable} attribute of the relevant + * {@code class} file (as per The Java Virtual Machine + * Specification, Section 4.7.8). + * + * @return the line number of the source line containing the execution + * point represented by this stack trace element, or a negative + * number if this information is unavailable. + */ + public int getLineNumber() { + return lineNumber; + } + + /** + * Returns the fully qualified name of the class containing the + * execution point represented by this stack trace element. + * + * @return the fully qualified name of the {@code Class} containing + * the execution point represented by this stack trace element. + */ + public String getClassName() { + return declaringClass; + } + + /** + * Returns the name of the method containing the execution point + * represented by this stack trace element. If the execution point is + * contained in an instance or class initializer, this method will return + * the appropriate special method name, {@code } or + * {@code }, as per Section 3.9 of The Java Virtual + * Machine Specification. + * + * @return the name of the method containing the execution point + * represented by this stack trace element. + */ + public String getMethodName() { + return methodName; + } + + /** + * Returns true if the method containing the execution point + * represented by this stack trace element is a native method. + * + * @return {@code true} if the method containing the execution point + * represented by this stack trace element is a native method. + */ + public boolean isNativeMethod() { + return lineNumber == -2; + } + + /** + * Returns a string representation of this stack trace element. The + * format of this string depends on the implementation, but the following + * examples may be regarded as typical: + *

    + *
  • + * {@code "MyClass.mash(MyClass.java:9)"} - Here, {@code "MyClass"} + * is the fully-qualified name of the class containing the + * execution point represented by this stack trace element, + * {@code "mash"} is the name of the method containing the execution + * point, {@code "MyClass.java"} is the source file containing the + * execution point, and {@code "9"} is the line number of the source + * line containing the execution point. + *
  • + * {@code "MyClass.mash(MyClass.java)"} - As above, but the line + * number is unavailable. + *
  • + * {@code "MyClass.mash(Unknown Source)"} - As above, but neither + * the file name nor the line number are available. + *
  • + * {@code "MyClass.mash(Native Method)"} - As above, but neither + * the file name nor the line number are available, and the method + * containing the execution point is known to be a native method. + *
+ * @see Throwable#printStackTrace() + */ + public String toString() { + // Android-changed: When ART cannot find a line number, the lineNumber field is set + // to the dex_pc and the fileName field is set to null. + StringBuilder result = new StringBuilder(); + result.append(getClassName()).append(".").append(methodName); + if (isNativeMethod()) { + result.append("(Native Method)"); + } else if (fileName != null) { + if (lineNumber >= 0) { + result.append("(").append(fileName).append(":").append(lineNumber).append(")"); + } else { + result.append("(").append(fileName).append(")"); + } + } else { + if (lineNumber >= 0) { + // The line number is actually the dex pc. + result.append("(Unknown Source:").append(lineNumber).append(")"); + } else { + result.append("(Unknown Source)"); + } + } + return result.toString(); + } + + /** + * Returns true if the specified object is another + * {@code StackTraceElement} instance representing the same execution + * point as this instance. Two stack trace elements {@code a} and + * {@code b} are equal if and only if: + *
{@code
+     *     equals(a.getFileName(), b.getFileName()) &&
+     *     a.getLineNumber() == b.getLineNumber()) &&
+     *     equals(a.getClassName(), b.getClassName()) &&
+     *     equals(a.getMethodName(), b.getMethodName())
+     * }
+ * where {@code equals} has the semantics of {@link + * java.util.Objects#equals(Object, Object) Objects.equals}. + * + * @param obj the object to be compared with this stack trace element. + * @return true if the specified object is another + * {@code StackTraceElement} instance representing the same + * execution point as this instance. + */ + public boolean equals(Object obj) { + if (obj==this) + return true; + if (!(obj instanceof StackTraceElement)) + return false; + StackTraceElement e = (StackTraceElement)obj; + return e.declaringClass.equals(declaringClass) && + e.lineNumber == lineNumber && + Objects.equals(methodName, e.methodName) && + Objects.equals(fileName, e.fileName); + } + + /** + * Returns a hash code value for this stack trace element. + */ + public int hashCode() { + int result = 31*declaringClass.hashCode() + methodName.hashCode(); + result = 31*result + Objects.hashCode(fileName); + result = 31*result + lineNumber; + return result; + } + + private static final long serialVersionUID = 6992337162326171013L; +} diff --git a/src/MapleFE/test/java/openjdk/StackTraceElement.java.result b/src/MapleFE/test/java/openjdk/StackTraceElement.java.result new file mode 100644 index 0000000000000000000000000000000000000000..610f5efb0019c2a9debe1daa437eab8762710876 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/StackTraceElement.java.result @@ -0,0 +1,77 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 438 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import java.util.Objects +== Sub Tree == +class StackTraceElement + Fields: + declaringClass methodName fileName lineNumber serialVersionUID=641129861 + Instance Initializer: + Constructors: + constructor StackTraceElement(declaringClass,methodName,fileName,lineNumber) throws: + this.declaringClass Assign Objects.requireNonNull(declaringClass,"Declaring class is null") + this.methodName Assign Objects.requireNonNull(methodName,"Method name is null") + this.fileName Assign fileName + this.lineNumber Assign lineNumber + Methods: + func getFileName() throws: + return fileName + func getLineNumber() throws: + return lineNumber + func getClassName() throws: + return declaringClass + func getMethodName() throws: + return methodName + func isNativeMethod() throws: + return lineNumber EQ -2 + func toString() throws: + Decl: result=new StringBuilder() + result.append(getClassName()).append(".").append(methodName) + cond-branch cond:isNativeMethod() + true branch : + result.append("(Native Method)") + false branch : + cond-branch cond:fileName NE null + true branch : + cond-branch cond:lineNumber GE 0 + true branch : + result.append("(").append(fileName).append(":").append(lineNumber).append(")") + false branch : + result.append("(").append(fileName).append(")") + + false branch : + cond-branch cond:lineNumber GE 0 + true branch : + result.append("(Unknown Source:").append(lineNumber).append(")") + false branch : + result.append("(Unknown Source)") + + + return result.toString() + func equals(obj) throws: + cond-branch cond:obj EQ this + true branch : + return true false branch : + + cond-branch cond:(obj instanceof StackTraceElement) + true branch : + return false false branch : + + Decl: e=(StackTraceElement)obj + return e.declaringClass.equals(declaringClass) Land e.lineNumber EQ lineNumber Land Objects.equals(methodName,e.methodName) Land Objects.equals(fileName,e.fileName) + func hashCode() throws: + Decl: result=31 Mul declaringClass.hashCode() Add methodName.hashCode() + result Assign 31 Mul result Add Objects.hashCode(fileName) + result Assign 31 Mul result Add lineNumber + return result + LocalClasses: + LocalInterfaces: + +Identifier:result has no decl. +Identifier:result has no decl. +Identifier:result has no decl. +Identifier:result has no decl. diff --git a/src/MapleFE/test/java/openjdk/StrictMath.java b/src/MapleFE/test/java/openjdk/StrictMath.java new file mode 100644 index 0000000000000000000000000000000000000000..ae4af2bcac896b7a804e2d7cef1ab3ac7cef6c38 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/StrictMath.java @@ -0,0 +1,1710 @@ +/* + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; +import java.util.Random; +import sun.misc.DoubleConsts; + +/** + * The class {@code StrictMath} contains methods for performing basic + * numeric operations such as the elementary exponential, logarithm, + * square root, and trigonometric functions. + * + *

To help ensure portability of Java programs, the definitions of + * some of the numeric functions in this package require that they + * produce the same results as certain published algorithms. These + * algorithms are available from the well-known network library + * {@code netlib} as the package "Freely Distributable Math + * Library," {@code fdlibm}. These + * algorithms, which are written in the C programming language, are + * then to be understood as executed with all floating-point + * operations following the rules of Java floating-point arithmetic. + * + *

The Java math library is defined with respect to + * {@code fdlibm} version 5.3. Where {@code fdlibm} provides + * more than one definition for a function (such as + * {@code acos}), use the "IEEE 754 core function" version + * (residing in a file whose name begins with the letter + * {@code e}). The methods which require {@code fdlibm} + * semantics are {@code sin}, {@code cos}, {@code tan}, + * {@code asin}, {@code acos}, {@code atan}, + * {@code exp}, {@code log}, {@code log10}, + * {@code cbrt}, {@code atan2}, {@code pow}, + * {@code sinh}, {@code cosh}, {@code tanh}, + * {@code hypot}, {@code expm1}, and {@code log1p}. + * + *

+ * The platform uses signed two's complement integer arithmetic with + * int and long primitive types. The developer should choose + * the primitive type to ensure that arithmetic operations consistently + * produce correct results, which in some cases means the operations + * will not overflow the range of values of the computation. + * The best practice is to choose the primitive type and algorithm to avoid + * overflow. In cases where the size is {@code int} or {@code long} and + * overflow errors need to be detected, the methods {@code addExact}, + * {@code subtractExact}, {@code multiplyExact}, and {@code toIntExact} + * throw an {@code ArithmeticException} when the results overflow. + * For other arithmetic operations such as divide, absolute value, + * increment, decrement, and negation overflow occurs only with + * a specific minimum or maximum value and should be checked against + * the minimum or maximum as appropriate. + * + * @author unascribed + * @author Joseph D. Darcy + * @since 1.3 + */ + +public final class StrictMath { + + /** + * Don't let anyone instantiate this class. + */ + private StrictMath() {} + + /** + * The {@code double} value that is closer than any other to + * e, the base of the natural logarithms. + */ + public static final double E = 2.7182818284590452354; + + /** + * The {@code double} value that is closer than any other to + * pi, the ratio of the circumference of a circle to its + * diameter. + */ + public static final double PI = 3.14159265358979323846; + + /** + * Returns the trigonometric sine of an angle. Special cases: + *

  • If the argument is NaN or an infinity, then the + * result is NaN. + *
  • If the argument is zero, then the result is a zero with the + * same sign as the argument.
+ * + * @param a an angle, in radians. + * @return the sine of the argument. + */ + public static native double sin(double a); + + /** + * Returns the trigonometric cosine of an angle. Special cases: + *
  • If the argument is NaN or an infinity, then the + * result is NaN.
+ * + * @param a an angle, in radians. + * @return the cosine of the argument. + */ + public static native double cos(double a); + + /** + * Returns the trigonometric tangent of an angle. Special cases: + *
  • If the argument is NaN or an infinity, then the result + * is NaN. + *
  • If the argument is zero, then the result is a zero with the + * same sign as the argument.
+ * + * @param a an angle, in radians. + * @return the tangent of the argument. + */ + public static native double tan(double a); + + /** + * Returns the arc sine of a value; the returned angle is in the + * range -pi/2 through pi/2. Special cases: + *
  • If the argument is NaN or its absolute value is greater + * than 1, then the result is NaN. + *
  • If the argument is zero, then the result is a zero with the + * same sign as the argument.
+ * + * @param a the value whose arc sine is to be returned. + * @return the arc sine of the argument. + */ + public static native double asin(double a); + + /** + * Returns the arc cosine of a value; the returned angle is in the + * range 0.0 through pi. Special case: + *
  • If the argument is NaN or its absolute value is greater + * than 1, then the result is NaN.
+ * + * @param a the value whose arc cosine is to be returned. + * @return the arc cosine of the argument. + */ + public static native double acos(double a); + + /** + * Returns the arc tangent of a value; the returned angle is in the + * range -pi/2 through pi/2. Special cases: + *
  • If the argument is NaN, then the result is NaN. + *
  • If the argument is zero, then the result is a zero with the + * same sign as the argument.
+ * + * @param a the value whose arc tangent is to be returned. + * @return the arc tangent of the argument. + */ + public static native double atan(double a); + + /** + * Converts an angle measured in degrees to an approximately + * equivalent angle measured in radians. The conversion from + * degrees to radians is generally inexact. + * + * @param angdeg an angle, in degrees + * @return the measurement of the angle {@code angdeg} + * in radians. + */ + public static strictfp double toRadians(double angdeg) { + // Do not delegate to Math.toRadians(angdeg) because + // this method has the strictfp modifier. + return angdeg / 180.0 * PI; + } + + /** + * Converts an angle measured in radians to an approximately + * equivalent angle measured in degrees. The conversion from + * radians to degrees is generally inexact; users should + * not expect {@code cos(toRadians(90.0))} to exactly + * equal {@code 0.0}. + * + * @param angrad an angle, in radians + * @return the measurement of the angle {@code angrad} + * in degrees. + */ + public static strictfp double toDegrees(double angrad) { + // Do not delegate to Math.toDegrees(angrad) because + // this method has the strictfp modifier. + return angrad * 180.0 / PI; + } + + /** + * Returns Euler's number e raised to the power of a + * {@code double} value. Special cases: + *
  • If the argument is NaN, the result is NaN. + *
  • If the argument is positive infinity, then the result is + * positive infinity. + *
  • If the argument is negative infinity, then the result is + * positive zero.
+ * + * @param a the exponent to raise e to. + * @return the value e{@code a}, + * where e is the base of the natural logarithms. + */ + public static native double exp(double a); + + /** + * Returns the natural logarithm (base e) of a {@code double} + * value. Special cases: + *
  • If the argument is NaN or less than zero, then the result + * is NaN. + *
  • If the argument is positive infinity, then the result is + * positive infinity. + *
  • If the argument is positive zero or negative zero, then the + * result is negative infinity.
+ * + * @param a a value + * @return the value ln {@code a}, the natural logarithm of + * {@code a}. + */ + public static native double log(double a); + + + /** + * Returns the base 10 logarithm of a {@code double} value. + * Special cases: + * + *
  • If the argument is NaN or less than zero, then the result + * is NaN. + *
  • If the argument is positive infinity, then the result is + * positive infinity. + *
  • If the argument is positive zero or negative zero, then the + * result is negative infinity. + *
  • If the argument is equal to 10n for + * integer n, then the result is n. + *
+ * + * @param a a value + * @return the base 10 logarithm of {@code a}. + * @since 1.5 + */ + public static native double log10(double a); + + /** + * Returns the correctly rounded positive square root of a + * {@code double} value. + * Special cases: + *
  • If the argument is NaN or less than zero, then the result + * is NaN. + *
  • If the argument is positive infinity, then the result is positive + * infinity. + *
  • If the argument is positive zero or negative zero, then the + * result is the same as the argument.
+ * Otherwise, the result is the {@code double} value closest to + * the true mathematical square root of the argument value. + * + * @param a a value. + * @return the positive square root of {@code a}. + */ + public static native double sqrt(double a); + + /** + * Returns the cube root of a {@code double} value. For + * positive finite {@code x}, {@code cbrt(-x) == + * -cbrt(x)}; that is, the cube root of a negative value is + * the negative of the cube root of that value's magnitude. + * Special cases: + * + *
    + * + *
  • If the argument is NaN, then the result is NaN. + * + *
  • If the argument is infinite, then the result is an infinity + * with the same sign as the argument. + * + *
  • If the argument is zero, then the result is a zero with the + * same sign as the argument. + * + *
+ * + * @param a a value. + * @return the cube root of {@code a}. + * @since 1.5 + */ + public static native double cbrt(double a); + + /** + * Computes the remainder operation on two arguments as prescribed + * by the IEEE 754 standard. + * The remainder value is mathematically equal to + * f1 - f2 × n, + * where n is the mathematical integer closest to the exact + * mathematical value of the quotient {@code f1/f2}, and if two + * mathematical integers are equally close to {@code f1/f2}, + * then n is the integer that is even. If the remainder is + * zero, its sign is the same as the sign of the first argument. + * Special cases: + *
  • If either argument is NaN, or the first argument is infinite, + * or the second argument is positive zero or negative zero, then the + * result is NaN. + *
  • If the first argument is finite and the second argument is + * infinite, then the result is the same as the first argument.
+ * + * @param f1 the dividend. + * @param f2 the divisor. + * @return the remainder when {@code f1} is divided by + * {@code f2}. + */ + public static native double IEEEremainder(double f1, double f2); + + /** + * Returns the smallest (closest to negative infinity) + * {@code double} value that is greater than or equal to the + * argument and is equal to a mathematical integer. Special cases: + *
  • If the argument value is already equal to a + * mathematical integer, then the result is the same as the + * argument.
  • If the argument is NaN or an infinity or + * positive zero or negative zero, then the result is the same as + * the argument.
  • If the argument value is less than zero but + * greater than -1.0, then the result is negative zero.
Note + * that the value of {@code StrictMath.ceil(x)} is exactly the + * value of {@code -StrictMath.floor(-x)}. + * + * @param a a value. + * @return the smallest (closest to negative infinity) + * floating-point value that is greater than or equal to + * the argument and is equal to a mathematical integer. + */ + public static double ceil(double a) { + return floorOrCeil(a, -0.0, 1.0, 1.0); + } + + /** + * Returns the largest (closest to positive infinity) + * {@code double} value that is less than or equal to the + * argument and is equal to a mathematical integer. Special cases: + *
  • If the argument value is already equal to a + * mathematical integer, then the result is the same as the + * argument.
  • If the argument is NaN or an infinity or + * positive zero or negative zero, then the result is the same as + * the argument.
+ * + * @param a a value. + * @return the largest (closest to positive infinity) + * floating-point value that less than or equal to the argument + * and is equal to a mathematical integer. + */ + public static double floor(double a) { + return floorOrCeil(a, -1.0, 0.0, -1.0); + } + + /** + * Internal method to share logic between floor and ceil. + * + * @param a the value to be floored or ceiled + * @param negativeBoundary result for values in (-1, 0) + * @param positiveBoundary result for values in (0, 1) + * @param increment value to add when the argument is non-integral + */ + private static double floorOrCeil(double a, + double negativeBoundary, + double positiveBoundary, + double sign) { + int exponent = Math.getExponent(a); + + if (exponent < 0) { + /* + * Absolute value of argument is less than 1. + * floorOrceil(-0.0) => -0.0 + * floorOrceil(+0.0) => +0.0 + */ + return ((a == 0.0) ? a : + ( (a < 0.0) ? negativeBoundary : positiveBoundary) ); + } else if (exponent >= 52) { + /* + * Infinity, NaN, or a value so large it must be integral. + */ + return a; + } + // Else the argument is either an integral value already XOR it + // has to be rounded to one. + assert exponent >= 0 && exponent <= 51; + + long doppel = Double.doubleToRawLongBits(a); + long mask = DoubleConsts.SIGNIF_BIT_MASK >> exponent; + + if ( (mask & doppel) == 0L ) + return a; // integral value + else { + double result = Double.longBitsToDouble(doppel & (~mask)); + if (sign*a > 0.0) + result = result + sign; + return result; + } + } + + /** + * Returns the {@code double} value that is closest in value + * to the argument and is equal to a mathematical integer. If two + * {@code double} values that are mathematical integers are + * equally close to the value of the argument, the result is the + * integer value that is even. Special cases: + *
  • If the argument value is already equal to a mathematical + * integer, then the result is the same as the argument. + *
  • If the argument is NaN or an infinity or positive zero or negative + * zero, then the result is the same as the argument.
+ * + * @param a a value. + * @return the closest floating-point value to {@code a} that is + * equal to a mathematical integer. + * @author Joseph D. Darcy + */ + public static double rint(double a) { + /* + * If the absolute value of a is not less than 2^52, it + * is either a finite integer (the double format does not have + * enough significand bits for a number that large to have any + * fractional portion), an infinity, or a NaN. In any of + * these cases, rint of the argument is the argument. + * + * Otherwise, the sum (twoToThe52 + a ) will properly round + * away any fractional portion of a since ulp(twoToThe52) == + * 1.0; subtracting out twoToThe52 from this sum will then be + * exact and leave the rounded integer portion of a. + * + * This method does *not* need to be declared strictfp to get + * fully reproducible results. Whether or not a method is + * declared strictfp can only make a difference in the + * returned result if some operation would overflow or + * underflow with strictfp semantics. The operation + * (twoToThe52 + a ) cannot overflow since large values of a + * are screened out; the add cannot underflow since twoToThe52 + * is too large. The subtraction ((twoToThe52 + a ) - + * twoToThe52) will be exact as discussed above and thus + * cannot overflow or meaningfully underflow. Finally, the + * last multiply in the return statement is by plus or minus + * 1.0, which is exact too. + */ + double twoToThe52 = (double)(1L << 52); // 2^52 + double sign = Math.copySign(1.0, a); // preserve sign info + a = Math.abs(a); + + if (a < twoToThe52) { // E_min <= ilogb(a) <= 51 + a = ((twoToThe52 + a ) - twoToThe52); + } + + return sign * a; // restore original sign + } + + /** + * Returns the angle theta from the conversion of rectangular + * coordinates ({@code x}, {@code y}) to polar + * coordinates (r, theta). + * This method computes the phase theta by computing an arc tangent + * of {@code y/x} in the range of -pi to pi. Special + * cases: + *
  • If either argument is NaN, then the result is NaN. + *
  • If the first argument is positive zero and the second argument + * is positive, or the first argument is positive and finite and the + * second argument is positive infinity, then the result is positive + * zero. + *
  • If the first argument is negative zero and the second argument + * is positive, or the first argument is negative and finite and the + * second argument is positive infinity, then the result is negative zero. + *
  • If the first argument is positive zero and the second argument + * is negative, or the first argument is positive and finite and the + * second argument is negative infinity, then the result is the + * {@code double} value closest to pi. + *
  • If the first argument is negative zero and the second argument + * is negative, or the first argument is negative and finite and the + * second argument is negative infinity, then the result is the + * {@code double} value closest to -pi. + *
  • If the first argument is positive and the second argument is + * positive zero or negative zero, or the first argument is positive + * infinity and the second argument is finite, then the result is the + * {@code double} value closest to pi/2. + *
  • If the first argument is negative and the second argument is + * positive zero or negative zero, or the first argument is negative + * infinity and the second argument is finite, then the result is the + * {@code double} value closest to -pi/2. + *
  • If both arguments are positive infinity, then the result is the + * {@code double} value closest to pi/4. + *
  • If the first argument is positive infinity and the second argument + * is negative infinity, then the result is the {@code double} + * value closest to 3*pi/4. + *
  • If the first argument is negative infinity and the second argument + * is positive infinity, then the result is the {@code double} value + * closest to -pi/4. + *
  • If both arguments are negative infinity, then the result is the + * {@code double} value closest to -3*pi/4.
+ * + * @param y the ordinate coordinate + * @param x the abscissa coordinate + * @return the theta component of the point + * (rtheta) + * in polar coordinates that corresponds to the point + * (xy) in Cartesian coordinates. + */ + public static native double atan2(double y, double x); + + + /** + * Returns the value of the first argument raised to the power of the + * second argument. Special cases: + * + *
  • If the second argument is positive or negative zero, then the + * result is 1.0. + *
  • If the second argument is 1.0, then the result is the same as the + * first argument. + *
  • If the second argument is NaN, then the result is NaN. + *
  • If the first argument is NaN and the second argument is nonzero, + * then the result is NaN. + * + *
  • If + *
      + *
    • the absolute value of the first argument is greater than 1 + * and the second argument is positive infinity, or + *
    • the absolute value of the first argument is less than 1 and + * the second argument is negative infinity, + *
    + * then the result is positive infinity. + * + *
  • If + *
      + *
    • the absolute value of the first argument is greater than 1 and + * the second argument is negative infinity, or + *
    • the absolute value of the + * first argument is less than 1 and the second argument is positive + * infinity, + *
    + * then the result is positive zero. + * + *
  • If the absolute value of the first argument equals 1 and the + * second argument is infinite, then the result is NaN. + * + *
  • If + *
      + *
    • the first argument is positive zero and the second argument + * is greater than zero, or + *
    • the first argument is positive infinity and the second + * argument is less than zero, + *
    + * then the result is positive zero. + * + *
  • If + *
      + *
    • the first argument is positive zero and the second argument + * is less than zero, or + *
    • the first argument is positive infinity and the second + * argument is greater than zero, + *
    + * then the result is positive infinity. + * + *
  • If + *
      + *
    • the first argument is negative zero and the second argument + * is greater than zero but not a finite odd integer, or + *
    • the first argument is negative infinity and the second + * argument is less than zero but not a finite odd integer, + *
    + * then the result is positive zero. + * + *
  • If + *
      + *
    • the first argument is negative zero and the second argument + * is a positive finite odd integer, or + *
    • the first argument is negative infinity and the second + * argument is a negative finite odd integer, + *
    + * then the result is negative zero. + * + *
  • If + *
      + *
    • the first argument is negative zero and the second argument + * is less than zero but not a finite odd integer, or + *
    • the first argument is negative infinity and the second + * argument is greater than zero but not a finite odd integer, + *
    + * then the result is positive infinity. + * + *
  • If + *
      + *
    • the first argument is negative zero and the second argument + * is a negative finite odd integer, or + *
    • the first argument is negative infinity and the second + * argument is a positive finite odd integer, + *
    + * then the result is negative infinity. + * + *
  • If the first argument is finite and less than zero + *
      + *
    • if the second argument is a finite even integer, the + * result is equal to the result of raising the absolute value of + * the first argument to the power of the second argument + * + *
    • if the second argument is a finite odd integer, the result + * is equal to the negative of the result of raising the absolute + * value of the first argument to the power of the second + * argument + * + *
    • if the second argument is finite and not an integer, then + * the result is NaN. + *
    + * + *
  • If both arguments are integers, then the result is exactly equal + * to the mathematical result of raising the first argument to the power + * of the second argument if that result can in fact be represented + * exactly as a {@code double} value.
+ * + *

(In the foregoing descriptions, a floating-point value is + * considered to be an integer if and only if it is finite and a + * fixed point of the method {@link #ceil ceil} or, + * equivalently, a fixed point of the method {@link #floor + * floor}. A value is a fixed point of a one-argument + * method if and only if the result of applying the method to the + * value is equal to the value.) + * + * @param a base. + * @param b the exponent. + * @return the value {@code a}{@code b}. + */ + public static native double pow(double a, double b); + + /** + * Returns the closest {@code int} to the argument, with ties + * rounding to positive infinity. + * + *

Special cases: + *

  • If the argument is NaN, the result is 0. + *
  • If the argument is negative infinity or any value less than or + * equal to the value of {@code Integer.MIN_VALUE}, the result is + * equal to the value of {@code Integer.MIN_VALUE}. + *
  • If the argument is positive infinity or any value greater than or + * equal to the value of {@code Integer.MAX_VALUE}, the result is + * equal to the value of {@code Integer.MAX_VALUE}.
+ * + * @param a a floating-point value to be rounded to an integer. + * @return the value of the argument rounded to the nearest + * {@code int} value. + * @see java.lang.Integer#MAX_VALUE + * @see java.lang.Integer#MIN_VALUE + */ + public static int round(float a) { + return Math.round(a); + } + + /** + * Returns the closest {@code long} to the argument, with ties + * rounding to positive infinity. + * + *

Special cases: + *

  • If the argument is NaN, the result is 0. + *
  • If the argument is negative infinity or any value less than or + * equal to the value of {@code Long.MIN_VALUE}, the result is + * equal to the value of {@code Long.MIN_VALUE}. + *
  • If the argument is positive infinity or any value greater than or + * equal to the value of {@code Long.MAX_VALUE}, the result is + * equal to the value of {@code Long.MAX_VALUE}.
+ * + * @param a a floating-point value to be rounded to a + * {@code long}. + * @return the value of the argument rounded to the nearest + * {@code long} value. + * @see java.lang.Long#MAX_VALUE + * @see java.lang.Long#MIN_VALUE + */ + public static long round(double a) { + return Math.round(a); + } + + private static final class RandomNumberGeneratorHolder { + static final Random randomNumberGenerator = new Random(); + } + + /** + * Returns a {@code double} value with a positive sign, greater + * than or equal to {@code 0.0} and less than {@code 1.0}. + * Returned values are chosen pseudorandomly with (approximately) + * uniform distribution from that range. + * + *

When this method is first called, it creates a single new + * pseudorandom-number generator, exactly as if by the expression + * + *

{@code new java.util.Random()}
+ * + * This new pseudorandom-number generator is used thereafter for + * all calls to this method and is used nowhere else. + * + *

This method is properly synchronized to allow correct use by + * more than one thread. However, if many threads need to generate + * pseudorandom numbers at a great rate, it may reduce contention + * for each thread to have its own pseudorandom-number generator. + * + * @return a pseudorandom {@code double} greater than or equal + * to {@code 0.0} and less than {@code 1.0}. + * @see Random#nextDouble() + */ + public static double random() { + return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble(); + } + + /** + * Returns the sum of its arguments, + * throwing an exception if the result overflows an {@code int}. + * + * @param x the first value + * @param y the second value + * @return the result + * @throws ArithmeticException if the result overflows an int + * @see Math#addExact(int,int) + * @since 1.8 + */ + public static int addExact(int x, int y) { + return Math.addExact(x, y); + } + + /** + * Returns the sum of its arguments, + * throwing an exception if the result overflows a {@code long}. + * + * @param x the first value + * @param y the second value + * @return the result + * @throws ArithmeticException if the result overflows a long + * @see Math#addExact(long,long) + * @since 1.8 + */ + public static long addExact(long x, long y) { + return Math.addExact(x, y); + } + + /** + * Returns the difference of the arguments, + * throwing an exception if the result overflows an {@code int}. + * + * @param x the first value + * @param y the second value to subtract from the first + * @return the result + * @throws ArithmeticException if the result overflows an int + * @see Math#subtractExact(int,int) + * @since 1.8 + */ + public static int subtractExact(int x, int y) { + return Math.subtractExact(x, y); + } + + /** + * Returns the difference of the arguments, + * throwing an exception if the result overflows a {@code long}. + * + * @param x the first value + * @param y the second value to subtract from the first + * @return the result + * @throws ArithmeticException if the result overflows a long + * @see Math#subtractExact(long,long) + * @since 1.8 + */ + public static long subtractExact(long x, long y) { + return Math.subtractExact(x, y); + } + + /** + * Returns the product of the arguments, + * throwing an exception if the result overflows an {@code int}. + * + * @param x the first value + * @param y the second value + * @return the result + * @throws ArithmeticException if the result overflows an int + * @see Math#multiplyExact(int,int) + * @since 1.8 + */ + public static int multiplyExact(int x, int y) { + return Math.multiplyExact(x, y); + } + + /** + * Returns the product of the arguments, + * throwing an exception if the result overflows a {@code long}. + * + * @param x the first value + * @param y the second value + * @return the result + * @throws ArithmeticException if the result overflows a long + * @see Math#multiplyExact(long,long) + * @since 1.8 + */ + public static long multiplyExact(long x, long y) { + return Math.multiplyExact(x, y); + } + + /** + * Returns the value of the {@code long} argument; + * throwing an exception if the value overflows an {@code int}. + * + * @param value the long value + * @return the argument as an int + * @throws ArithmeticException if the {@code argument} overflows an int + * @see Math#toIntExact(long) + * @since 1.8 + */ + public static int toIntExact(long value) { + return Math.toIntExact(value); + } + + /** + * Returns the largest (closest to positive infinity) + * {@code int} value that is less than or equal to the algebraic quotient. + * There is one special case, if the dividend is the + * {@linkplain Integer#MIN_VALUE Integer.MIN_VALUE} and the divisor is {@code -1}, + * then integer overflow occurs and + * the result is equal to the {@code Integer.MIN_VALUE}. + *

+ * See {@link Math#floorDiv(int, int) Math.floorDiv} for examples and + * a comparison to the integer division {@code /} operator. + * + * @param x the dividend + * @param y the divisor + * @return the largest (closest to positive infinity) + * {@code int} value that is less than or equal to the algebraic quotient. + * @throws ArithmeticException if the divisor {@code y} is zero + * @see Math#floorDiv(int, int) + * @see Math#floor(double) + * @since 1.8 + */ + public static int floorDiv(int x, int y) { + return Math.floorDiv(x, y); + } + + /** + * Returns the largest (closest to positive infinity) + * {@code long} value that is less than or equal to the algebraic quotient. + * There is one special case, if the dividend is the + * {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the divisor is {@code -1}, + * then integer overflow occurs and + * the result is equal to the {@code Long.MIN_VALUE}. + *

+ * See {@link Math#floorDiv(int, int) Math.floorDiv} for examples and + * a comparison to the integer division {@code /} operator. + * + * @param x the dividend + * @param y the divisor + * @return the largest (closest to positive infinity) + * {@code long} value that is less than or equal to the algebraic quotient. + * @throws ArithmeticException if the divisor {@code y} is zero + * @see Math#floorDiv(long, long) + * @see Math#floor(double) + * @since 1.8 + */ + public static long floorDiv(long x, long y) { + return Math.floorDiv(x, y); + } + + /** + * Returns the floor modulus of the {@code int} arguments. + *

+ * The floor modulus is {@code x - (floorDiv(x, y) * y)}, + * has the same sign as the divisor {@code y}, and + * is in the range of {@code -abs(y) < r < +abs(y)}. + *

+ * The relationship between {@code floorDiv} and {@code floorMod} is such that: + *

    + *
  • {@code floorDiv(x, y) * y + floorMod(x, y) == x} + *
+ *

+ * See {@link Math#floorMod(int, int) Math.floorMod} for examples and + * a comparison to the {@code %} operator. + * + * @param x the dividend + * @param y the divisor + * @return the floor modulus {@code x - (floorDiv(x, y) * y)} + * @throws ArithmeticException if the divisor {@code y} is zero + * @see Math#floorMod(int, int) + * @see StrictMath#floorDiv(int, int) + * @since 1.8 + */ + public static int floorMod(int x, int y) { + return Math.floorMod(x , y); + } + /** + * Returns the floor modulus of the {@code long} arguments. + *

+ * The floor modulus is {@code x - (floorDiv(x, y) * y)}, + * has the same sign as the divisor {@code y}, and + * is in the range of {@code -abs(y) < r < +abs(y)}. + *

+ * The relationship between {@code floorDiv} and {@code floorMod} is such that: + *

    + *
  • {@code floorDiv(x, y) * y + floorMod(x, y) == x} + *
+ *

+ * See {@link Math#floorMod(int, int) Math.floorMod} for examples and + * a comparison to the {@code %} operator. + * + * @param x the dividend + * @param y the divisor + * @return the floor modulus {@code x - (floorDiv(x, y) * y)} + * @throws ArithmeticException if the divisor {@code y} is zero + * @see Math#floorMod(long, long) + * @see StrictMath#floorDiv(long, long) + * @since 1.8 + */ + public static long floorMod(long x, long y) { + return Math.floorMod(x, y); + } + + /** + * Returns the absolute value of an {@code int} value. + * If the argument is not negative, the argument is returned. + * If the argument is negative, the negation of the argument is returned. + * + *

Note that if the argument is equal to the value of + * {@link Integer#MIN_VALUE}, the most negative representable + * {@code int} value, the result is that same value, which is + * negative. + * + * @param a the argument whose absolute value is to be determined. + * @return the absolute value of the argument. + */ + public static int abs(int a) { + return Math.abs(a); + } + + /** + * Returns the absolute value of a {@code long} value. + * If the argument is not negative, the argument is returned. + * If the argument is negative, the negation of the argument is returned. + * + *

Note that if the argument is equal to the value of + * {@link Long#MIN_VALUE}, the most negative representable + * {@code long} value, the result is that same value, which + * is negative. + * + * @param a the argument whose absolute value is to be determined. + * @return the absolute value of the argument. + */ + public static long abs(long a) { + return Math.abs(a); + } + + /** + * Returns the absolute value of a {@code float} value. + * If the argument is not negative, the argument is returned. + * If the argument is negative, the negation of the argument is returned. + * Special cases: + *

  • If the argument is positive zero or negative zero, the + * result is positive zero. + *
  • If the argument is infinite, the result is positive infinity. + *
  • If the argument is NaN, the result is NaN.
+ * In other words, the result is the same as the value of the expression: + *

{@code Float.intBitsToFloat(0x7fffffff & Float.floatToIntBits(a))} + * + * @param a the argument whose absolute value is to be determined + * @return the absolute value of the argument. + */ + public static float abs(float a) { + return Math.abs(a); + } + + /** + * Returns the absolute value of a {@code double} value. + * If the argument is not negative, the argument is returned. + * If the argument is negative, the negation of the argument is returned. + * Special cases: + *

  • If the argument is positive zero or negative zero, the result + * is positive zero. + *
  • If the argument is infinite, the result is positive infinity. + *
  • If the argument is NaN, the result is NaN.
+ * In other words, the result is the same as the value of the expression: + *

{@code Double.longBitsToDouble((Double.doubleToLongBits(a)<<1)>>>1)} + * + * @param a the argument whose absolute value is to be determined + * @return the absolute value of the argument. + */ + public static double abs(double a) { + return Math.abs(a); + } + + /** + * Returns the greater of two {@code int} values. That is, the + * result is the argument closer to the value of + * {@link Integer#MAX_VALUE}. If the arguments have the same value, + * the result is that same value. + * + * @param a an argument. + * @param b another argument. + * @return the larger of {@code a} and {@code b}. + */ + public static int max(int a, int b) { + return Math.max(a, b); + } + + /** + * Returns the greater of two {@code long} values. That is, the + * result is the argument closer to the value of + * {@link Long#MAX_VALUE}. If the arguments have the same value, + * the result is that same value. + * + * @param a an argument. + * @param b another argument. + * @return the larger of {@code a} and {@code b}. + */ + public static long max(long a, long b) { + return Math.max(a, b); + } + + /** + * Returns the greater of two {@code float} values. That is, + * the result is the argument closer to positive infinity. If the + * arguments have the same value, the result is that same + * value. If either value is NaN, then the result is NaN. Unlike + * the numerical comparison operators, this method considers + * negative zero to be strictly smaller than positive zero. If one + * argument is positive zero and the other negative zero, the + * result is positive zero. + * + * @param a an argument. + * @param b another argument. + * @return the larger of {@code a} and {@code b}. + */ + public static float max(float a, float b) { + return Math.max(a, b); + } + + /** + * Returns the greater of two {@code double} values. That + * is, the result is the argument closer to positive infinity. If + * the arguments have the same value, the result is that same + * value. If either value is NaN, then the result is NaN. Unlike + * the numerical comparison operators, this method considers + * negative zero to be strictly smaller than positive zero. If one + * argument is positive zero and the other negative zero, the + * result is positive zero. + * + * @param a an argument. + * @param b another argument. + * @return the larger of {@code a} and {@code b}. + */ + public static double max(double a, double b) { + return Math.max(a, b); + } + + /** + * Returns the smaller of two {@code int} values. That is, + * the result the argument closer to the value of + * {@link Integer#MIN_VALUE}. If the arguments have the same + * value, the result is that same value. + * + * @param a an argument. + * @param b another argument. + * @return the smaller of {@code a} and {@code b}. + */ + public static int min(int a, int b) { + return Math.min(a, b); + } + + /** + * Returns the smaller of two {@code long} values. That is, + * the result is the argument closer to the value of + * {@link Long#MIN_VALUE}. If the arguments have the same + * value, the result is that same value. + * + * @param a an argument. + * @param b another argument. + * @return the smaller of {@code a} and {@code b}. + */ + public static long min(long a, long b) { + return Math.min(a, b); + } + + /** + * Returns the smaller of two {@code float} values. That is, + * the result is the value closer to negative infinity. If the + * arguments have the same value, the result is that same + * value. If either value is NaN, then the result is NaN. Unlike + * the numerical comparison operators, this method considers + * negative zero to be strictly smaller than positive zero. If + * one argument is positive zero and the other is negative zero, + * the result is negative zero. + * + * @param a an argument. + * @param b another argument. + * @return the smaller of {@code a} and {@code b.} + */ + public static float min(float a, float b) { + return Math.min(a, b); + } + + /** + * Returns the smaller of two {@code double} values. That + * is, the result is the value closer to negative infinity. If the + * arguments have the same value, the result is that same + * value. If either value is NaN, then the result is NaN. Unlike + * the numerical comparison operators, this method considers + * negative zero to be strictly smaller than positive zero. If one + * argument is positive zero and the other is negative zero, the + * result is negative zero. + * + * @param a an argument. + * @param b another argument. + * @return the smaller of {@code a} and {@code b}. + */ + public static double min(double a, double b) { + return Math.min(a, b); + } + + /** + * Returns the size of an ulp of the argument. An ulp, unit in + * the last place, of a {@code double} value is the positive + * distance between this floating-point value and the {@code + * double} value next larger in magnitude. Note that for non-NaN + * x, ulp(-x) == ulp(x). + * + *

Special Cases: + *

    + *
  • If the argument is NaN, then the result is NaN. + *
  • If the argument is positive or negative infinity, then the + * result is positive infinity. + *
  • If the argument is positive or negative zero, then the result is + * {@code Double.MIN_VALUE}. + *
  • If the argument is ±{@code Double.MAX_VALUE}, then + * the result is equal to 2971. + *
+ * + * @param d the floating-point value whose ulp is to be returned + * @return the size of an ulp of the argument + * @author Joseph D. Darcy + * @since 1.5 + */ + public static double ulp(double d) { + return Math.ulp(d); + } + + /** + * Returns the size of an ulp of the argument. An ulp, unit in + * the last place, of a {@code float} value is the positive + * distance between this floating-point value and the {@code + * float} value next larger in magnitude. Note that for non-NaN + * x, ulp(-x) == ulp(x). + * + *

Special Cases: + *

    + *
  • If the argument is NaN, then the result is NaN. + *
  • If the argument is positive or negative infinity, then the + * result is positive infinity. + *
  • If the argument is positive or negative zero, then the result is + * {@code Float.MIN_VALUE}. + *
  • If the argument is ±{@code Float.MAX_VALUE}, then + * the result is equal to 2104. + *
+ * + * @param f the floating-point value whose ulp is to be returned + * @return the size of an ulp of the argument + * @author Joseph D. Darcy + * @since 1.5 + */ + public static float ulp(float f) { + return Math.ulp(f); + } + + /** + * Returns the signum function of the argument; zero if the argument + * is zero, 1.0 if the argument is greater than zero, -1.0 if the + * argument is less than zero. + * + *

Special Cases: + *

    + *
  • If the argument is NaN, then the result is NaN. + *
  • If the argument is positive zero or negative zero, then the + * result is the same as the argument. + *
+ * + * @param d the floating-point value whose signum is to be returned + * @return the signum function of the argument + * @author Joseph D. Darcy + * @since 1.5 + */ + public static double signum(double d) { + return Math.signum(d); + } + + /** + * Returns the signum function of the argument; zero if the argument + * is zero, 1.0f if the argument is greater than zero, -1.0f if the + * argument is less than zero. + * + *

Special Cases: + *

    + *
  • If the argument is NaN, then the result is NaN. + *
  • If the argument is positive zero or negative zero, then the + * result is the same as the argument. + *
+ * + * @param f the floating-point value whose signum is to be returned + * @return the signum function of the argument + * @author Joseph D. Darcy + * @since 1.5 + */ + public static float signum(float f) { + return Math.signum(f); + } + + /** + * Returns the hyperbolic sine of a {@code double} value. + * The hyperbolic sine of x is defined to be + * (ex - e-x)/2 + * where e is {@linkplain Math#E Euler's number}. + * + *

Special cases: + *

    + * + *
  • If the argument is NaN, then the result is NaN. + * + *
  • If the argument is infinite, then the result is an infinity + * with the same sign as the argument. + * + *
  • If the argument is zero, then the result is a zero with the + * same sign as the argument. + * + *
+ * + * @param x The number whose hyperbolic sine is to be returned. + * @return The hyperbolic sine of {@code x}. + * @since 1.5 + */ + public static native double sinh(double x); + + /** + * Returns the hyperbolic cosine of a {@code double} value. + * The hyperbolic cosine of x is defined to be + * (ex + e-x)/2 + * where e is {@linkplain Math#E Euler's number}. + * + *

Special cases: + *

    + * + *
  • If the argument is NaN, then the result is NaN. + * + *
  • If the argument is infinite, then the result is positive + * infinity. + * + *
  • If the argument is zero, then the result is {@code 1.0}. + * + *
+ * + * @param x The number whose hyperbolic cosine is to be returned. + * @return The hyperbolic cosine of {@code x}. + * @since 1.5 + */ + public static native double cosh(double x); + + /** + * Returns the hyperbolic tangent of a {@code double} value. + * The hyperbolic tangent of x is defined to be + * (ex - e-x)/(ex + e-x), + * in other words, {@linkplain Math#sinh + * sinh(x)}/{@linkplain Math#cosh cosh(x)}. Note + * that the absolute value of the exact tanh is always less than + * 1. + * + *

Special cases: + *

    + * + *
  • If the argument is NaN, then the result is NaN. + * + *
  • If the argument is zero, then the result is a zero with the + * same sign as the argument. + * + *
  • If the argument is positive infinity, then the result is + * {@code +1.0}. + * + *
  • If the argument is negative infinity, then the result is + * {@code -1.0}. + * + *
+ * + * @param x The number whose hyperbolic tangent is to be returned. + * @return The hyperbolic tangent of {@code x}. + * @since 1.5 + */ + public static native double tanh(double x); + + /** + * Returns sqrt(x2 +y2) + * without intermediate overflow or underflow. + * + *

Special cases: + *

    + * + *
  • If either argument is infinite, then the result + * is positive infinity. + * + *
  • If either argument is NaN and neither argument is infinite, + * then the result is NaN. + * + *
+ * + * @param x a value + * @param y a value + * @return sqrt(x2 +y2) + * without intermediate overflow or underflow + * @since 1.5 + */ + public static native double hypot(double x, double y); + + /** + * Returns ex -1. Note that for values of + * x near 0, the exact sum of + * {@code expm1(x)} + 1 is much closer to the true + * result of ex than {@code exp(x)}. + * + *

Special cases: + *

    + *
  • If the argument is NaN, the result is NaN. + * + *
  • If the argument is positive infinity, then the result is + * positive infinity. + * + *
  • If the argument is negative infinity, then the result is + * -1.0. + * + *
  • If the argument is zero, then the result is a zero with the + * same sign as the argument. + * + *
+ * + * @param x the exponent to raise e to in the computation of + * e{@code x} -1. + * @return the value e{@code x} - 1. + * @since 1.5 + */ + public static native double expm1(double x); + + /** + * Returns the natural logarithm of the sum of the argument and 1. + * Note that for small values {@code x}, the result of + * {@code log1p(x)} is much closer to the true result of ln(1 + * + {@code x}) than the floating-point evaluation of + * {@code log(1.0+x)}. + * + *

Special cases: + *

    + * + *
  • If the argument is NaN or less than -1, then the result is + * NaN. + * + *
  • If the argument is positive infinity, then the result is + * positive infinity. + * + *
  • If the argument is negative one, then the result is + * negative infinity. + * + *
  • If the argument is zero, then the result is a zero with the + * same sign as the argument. + * + *
+ * + * @param x a value + * @return the value ln({@code x} + 1), the natural + * log of {@code x} + 1 + * @since 1.5 + */ + public static native double log1p(double x); + + /** + * Returns the first floating-point argument with the sign of the + * second floating-point argument. For this method, a NaN + * {@code sign} argument is always treated as if it were + * positive. + * + * @param magnitude the parameter providing the magnitude of the result + * @param sign the parameter providing the sign of the result + * @return a value with the magnitude of {@code magnitude} + * and the sign of {@code sign}. + * @since 1.6 + */ + public static double copySign(double magnitude, double sign) { + return Math.copySign(magnitude, (Double.isNaN(sign)?1.0d:sign)); + } + + /** + * Returns the first floating-point argument with the sign of the + * second floating-point argument. For this method, a NaN + * {@code sign} argument is always treated as if it were + * positive. + * + * @param magnitude the parameter providing the magnitude of the result + * @param sign the parameter providing the sign of the result + * @return a value with the magnitude of {@code magnitude} + * and the sign of {@code sign}. + * @since 1.6 + */ + public static float copySign(float magnitude, float sign) { + return Math.copySign(magnitude, (Float.isNaN(sign)?1.0f:sign)); + } + /** + * Returns the unbiased exponent used in the representation of a + * {@code float}. Special cases: + * + *
    + *
  • If the argument is NaN or infinite, then the result is + * {@link Float#MAX_EXPONENT} + 1. + *
  • If the argument is zero or subnormal, then the result is + * {@link Float#MIN_EXPONENT} -1. + *
+ * @param f a {@code float} value + * @return the unbiased exponent of the argument + * @since 1.6 + */ + public static int getExponent(float f) { + return Math.getExponent(f); + } + + /** + * Returns the unbiased exponent used in the representation of a + * {@code double}. Special cases: + * + *
    + *
  • If the argument is NaN or infinite, then the result is + * {@link Double#MAX_EXPONENT} + 1. + *
  • If the argument is zero or subnormal, then the result is + * {@link Double#MIN_EXPONENT} -1. + *
+ * @param d a {@code double} value + * @return the unbiased exponent of the argument + * @since 1.6 + */ + public static int getExponent(double d) { + return Math.getExponent(d); + } + + /** + * Returns the floating-point number adjacent to the first + * argument in the direction of the second argument. If both + * arguments compare as equal the second argument is returned. + * + *

Special cases: + *

    + *
  • If either argument is a NaN, then NaN is returned. + * + *
  • If both arguments are signed zeros, {@code direction} + * is returned unchanged (as implied by the requirement of + * returning the second argument if the arguments compare as + * equal). + * + *
  • If {@code start} is + * ±{@link Double#MIN_VALUE} and {@code direction} + * has a value such that the result should have a smaller + * magnitude, then a zero with the same sign as {@code start} + * is returned. + * + *
  • If {@code start} is infinite and + * {@code direction} has a value such that the result should + * have a smaller magnitude, {@link Double#MAX_VALUE} with the + * same sign as {@code start} is returned. + * + *
  • If {@code start} is equal to ± + * {@link Double#MAX_VALUE} and {@code direction} has a + * value such that the result should have a larger magnitude, an + * infinity with same sign as {@code start} is returned. + *
+ * + * @param start starting floating-point value + * @param direction value indicating which of + * {@code start}'s neighbors or {@code start} should + * be returned + * @return The floating-point number adjacent to {@code start} in the + * direction of {@code direction}. + * @since 1.6 + */ + public static double nextAfter(double start, double direction) { + return Math.nextAfter(start, direction); + } + + /** + * Returns the floating-point number adjacent to the first + * argument in the direction of the second argument. If both + * arguments compare as equal a value equivalent to the second argument + * is returned. + * + *

Special cases: + *

    + *
  • If either argument is a NaN, then NaN is returned. + * + *
  • If both arguments are signed zeros, a value equivalent + * to {@code direction} is returned. + * + *
  • If {@code start} is + * ±{@link Float#MIN_VALUE} and {@code direction} + * has a value such that the result should have a smaller + * magnitude, then a zero with the same sign as {@code start} + * is returned. + * + *
  • If {@code start} is infinite and + * {@code direction} has a value such that the result should + * have a smaller magnitude, {@link Float#MAX_VALUE} with the + * same sign as {@code start} is returned. + * + *
  • If {@code start} is equal to ± + * {@link Float#MAX_VALUE} and {@code direction} has a + * value such that the result should have a larger magnitude, an + * infinity with same sign as {@code start} is returned. + *
+ * + * @param start starting floating-point value + * @param direction value indicating which of + * {@code start}'s neighbors or {@code start} should + * be returned + * @return The floating-point number adjacent to {@code start} in the + * direction of {@code direction}. + * @since 1.6 + */ + public static float nextAfter(float start, double direction) { + return Math.nextAfter(start, direction); + } + + /** + * Returns the floating-point value adjacent to {@code d} in + * the direction of positive infinity. This method is + * semantically equivalent to {@code nextAfter(d, + * Double.POSITIVE_INFINITY)}; however, a {@code nextUp} + * implementation may run faster than its equivalent + * {@code nextAfter} call. + * + *

Special Cases: + *

    + *
  • If the argument is NaN, the result is NaN. + * + *
  • If the argument is positive infinity, the result is + * positive infinity. + * + *
  • If the argument is zero, the result is + * {@link Double#MIN_VALUE} + * + *
+ * + * @param d starting floating-point value + * @return The adjacent floating-point value closer to positive + * infinity. + * @since 1.6 + */ + public static double nextUp(double d) { + return Math.nextUp(d); + } + + /** + * Returns the floating-point value adjacent to {@code f} in + * the direction of positive infinity. This method is + * semantically equivalent to {@code nextAfter(f, + * Float.POSITIVE_INFINITY)}; however, a {@code nextUp} + * implementation may run faster than its equivalent + * {@code nextAfter} call. + * + *

Special Cases: + *

    + *
  • If the argument is NaN, the result is NaN. + * + *
  • If the argument is positive infinity, the result is + * positive infinity. + * + *
  • If the argument is zero, the result is + * {@link Float#MIN_VALUE} + * + *
+ * + * @param f starting floating-point value + * @return The adjacent floating-point value closer to positive + * infinity. + * @since 1.6 + */ + public static float nextUp(float f) { + return Math.nextUp(f); + } + + /** + * Returns the floating-point value adjacent to {@code d} in + * the direction of negative infinity. This method is + * semantically equivalent to {@code nextAfter(d, + * Double.NEGATIVE_INFINITY)}; however, a + * {@code nextDown} implementation may run faster than its + * equivalent {@code nextAfter} call. + * + *

Special Cases: + *

    + *
  • If the argument is NaN, the result is NaN. + * + *
  • If the argument is negative infinity, the result is + * negative infinity. + * + *
  • If the argument is zero, the result is + * {@code -Double.MIN_VALUE} + * + *
+ * + * @param d starting floating-point value + * @return The adjacent floating-point value closer to negative + * infinity. + * @since 1.8 + */ + public static double nextDown(double d) { + return Math.nextDown(d); + } + + /** + * Returns the floating-point value adjacent to {@code f} in + * the direction of negative infinity. This method is + * semantically equivalent to {@code nextAfter(f, + * Float.NEGATIVE_INFINITY)}; however, a + * {@code nextDown} implementation may run faster than its + * equivalent {@code nextAfter} call. + * + *

Special Cases: + *

    + *
  • If the argument is NaN, the result is NaN. + * + *
  • If the argument is negative infinity, the result is + * negative infinity. + * + *
  • If the argument is zero, the result is + * {@code -Float.MIN_VALUE} + * + *
+ * + * @param f starting floating-point value + * @return The adjacent floating-point value closer to negative + * infinity. + * @since 1.8 + */ + public static float nextDown(float f) { + return Math.nextDown(f); + } + + /** + * Returns {@code d} × + * 2{@code scaleFactor} rounded as if performed + * by a single correctly rounded floating-point multiply to a + * member of the double value set. See the Java + * Language Specification for a discussion of floating-point + * value sets. If the exponent of the result is between {@link + * Double#MIN_EXPONENT} and {@link Double#MAX_EXPONENT}, the + * answer is calculated exactly. If the exponent of the result + * would be larger than {@code Double.MAX_EXPONENT}, an + * infinity is returned. Note that if the result is subnormal, + * precision may be lost; that is, when {@code scalb(x, n)} + * is subnormal, {@code scalb(scalb(x, n), -n)} may not equal + * x. When the result is non-NaN, the result has the same + * sign as {@code d}. + * + *

Special cases: + *

    + *
  • If the first argument is NaN, NaN is returned. + *
  • If the first argument is infinite, then an infinity of the + * same sign is returned. + *
  • If the first argument is zero, then a zero of the same + * sign is returned. + *
+ * + * @param d number to be scaled by a power of two. + * @param scaleFactor power of 2 used to scale {@code d} + * @return {@code d} × 2{@code scaleFactor} + * @since 1.6 + */ + public static double scalb(double d, int scaleFactor) { + return Math.scalb(d, scaleFactor); + } + + /** + * Returns {@code f} × + * 2{@code scaleFactor} rounded as if performed + * by a single correctly rounded floating-point multiply to a + * member of the float value set. See the Java + * Language Specification for a discussion of floating-point + * value sets. If the exponent of the result is between {@link + * Float#MIN_EXPONENT} and {@link Float#MAX_EXPONENT}, the + * answer is calculated exactly. If the exponent of the result + * would be larger than {@code Float.MAX_EXPONENT}, an + * infinity is returned. Note that if the result is subnormal, + * precision may be lost; that is, when {@code scalb(x, n)} + * is subnormal, {@code scalb(scalb(x, n), -n)} may not equal + * x. When the result is non-NaN, the result has the same + * sign as {@code f}. + * + *

Special cases: + *

    + *
  • If the first argument is NaN, NaN is returned. + *
  • If the first argument is infinite, then an infinity of the + * same sign is returned. + *
  • If the first argument is zero, then a zero of the same + * sign is returned. + *
+ * + * @param f number to be scaled by a power of two. + * @param scaleFactor power of 2 used to scale {@code f} + * @return {@code f} × 2{@code scaleFactor} + * @since 1.6 + */ + public static float scalb(float f, int scaleFactor) { + return Math.scalb(f, scaleFactor); + } +} diff --git a/src/MapleFE/test/java/openjdk/StrictMath.java.result b/src/MapleFE/test/java/openjdk/StrictMath.java.result new file mode 100644 index 0000000000000000000000000000000000000000..43c673cea33cbea5851d6c80142ce66fa203db18 --- /dev/null +++ b/src/MapleFE/test/java/openjdk/StrictMath.java.result @@ -0,0 +1,176 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 19 tokens. +Matched 1469 tokens. +============= Module =========== +== Sub Tree == +package java.lang +== Sub Tree == +import java.util.Random +== Sub Tree == +import sun.misc.DoubleConsts +== Sub Tree == +class StrictMath + Fields: + E=2.71828 PI=3.14159 + Instance Initializer: + Constructors: + constructor StrictMath() throws: + Methods: + func sin(a) throws: + func cos(a) throws: + func tan(a) throws: + func asin(a) throws: + func acos(a) throws: + func atan(a) throws: + func toRadians(angdeg) throws: + return angdeg Div 180 Mul PI + func toDegrees(angrad) throws: + return angrad Mul 180 Div PI + func exp(a) throws: + func log(a) throws: + func log10(a) throws: + func sqrt(a) throws: + func cbrt(a) throws: + func IEEEremainder(f1,f2) throws: + func ceil(a) throws: + return floorOrCeil(a,-0,1,1) + func floor(a) throws: + return floorOrCeil(a,-1,0,-1) + func floorOrCeil(a,negativeBoundary,positiveBoundary,sign) throws: + Decl: exponent=Math.getExponent(a) + cond-branch cond:exponent LT 0 + true branch : + return () + false branch : + cond-branch cond:exponent GE 52 + true branch : + return a + false branch : + + assert exponent GE 0 Land exponent LE 51 : + Decl: doppel=Double.doubleToRawLongBits(a) + Decl: mask=DoubleConsts.SIGNIF_BIT_MASK Shr exponent + cond-branch cond:(mask Band doppel) EQ 0 + true branch : + return a false branch : + Decl: result=Double.longBitsToDouble(doppel Band (mask)) + cond-branch cond:sign Mul a GT 0 + true branch : + result Assign result Add sign false branch : + + return result + + func rint(a) throws: + Decl: twoToThe52=(double)(1 Shl 52) + Decl: sign=Math.copySign(1,a) + a Assign Math.abs(a) + cond-branch cond:a LT twoToThe52 + true branch : + a Assign ((twoToThe52 Add a) Sub twoToThe52) + false branch : + + return sign Mul a + func atan2(y,x) throws: + func pow(a,b) throws: + func round(a) throws: + return Math.round(a) + func round(a) throws: + return Math.round(a) + func random() throws: + return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble() + func addExact(x,y) throws: + return Math.addExact(x,y) + func addExact(x,y) throws: + return Math.addExact(x,y) + func subtractExact(x,y) throws: + return Math.subtractExact(x,y) + func subtractExact(x,y) throws: + return Math.subtractExact(x,y) + func multiplyExact(x,y) throws: + return Math.multiplyExact(x,y) + func multiplyExact(x,y) throws: + return Math.multiplyExact(x,y) + func toIntExact(value) throws: + return Math.toIntExact(value) + func floorDiv(x,y) throws: + return Math.floorDiv(x,y) + func floorDiv(x,y) throws: + return Math.floorDiv(x,y) + func floorMod(x,y) throws: + return Math.floorMod(x,y) + func floorMod(x,y) throws: + return Math.floorMod(x,y) + func abs(a) throws: + return Math.abs(a) + func abs(a) throws: + return Math.abs(a) + func abs(a) throws: + return Math.abs(a) + func abs(a) throws: + return Math.abs(a) + func max(a,b) throws: + return Math.max(a,b) + func max(a,b) throws: + return Math.max(a,b) + func max(a,b) throws: + return Math.max(a,b) + func max(a,b) throws: + return Math.max(a,b) + func min(a,b) throws: + return Math.min(a,b) + func min(a,b) throws: + return Math.min(a,b) + func min(a,b) throws: + return Math.min(a,b) + func min(a,b) throws: + return Math.min(a,b) + func ulp(d) throws: + return Math.ulp(d) + func ulp(f) throws: + return Math.ulp(f) + func signum(d) throws: + return Math.signum(d) + func signum(f) throws: + return Math.signum(f) + func sinh(x) throws: + func cosh(x) throws: + func tanh(x) throws: + func hypot(x,y) throws: + func expm1(x) throws: + func log1p(x) throws: + func copySign(magnitude,sign) throws: + return Math.copySign(magnitude,()) + func copySign(magnitude,sign) throws: + return Math.copySign(magnitude,()) + func getExponent(f) throws: + return Math.getExponent(f) + func getExponent(d) throws: + return Math.getExponent(d) + func nextAfter(start,direction) throws: + return Math.nextAfter(start,direction) + func nextAfter(start,direction) throws: + return Math.nextAfter(start,direction) + func nextUp(d) throws: + return Math.nextUp(d) + func nextUp(f) throws: + return Math.nextUp(f) + func nextDown(d) throws: + return Math.nextDown(d) + func nextDown(f) throws: + return Math.nextDown(f) + func scalb(d,scaleFactor) throws: + return Math.scalb(d,scaleFactor) + func scalb(f,scaleFactor) throws: + return Math.scalb(f,scaleFactor) + LocalClasses: + class RandomNumberGeneratorHolder + Fields: + randomNumberGenerator=new Random() + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + LocalInterfaces: + diff --git a/src/MapleFE/test/openjdk/generate-result.sh b/src/MapleFE/test/java/openjdk/generate-result.sh similarity index 92% rename from src/MapleFE/test/openjdk/generate-result.sh rename to src/MapleFE/test/java/openjdk/generate-result.sh index bbd3acd878bd41d3a31fc5123972e954d7c9fcd0..08b3acc3b58dc1585fb15888064b004629e72007 100755 --- a/src/MapleFE/test/openjdk/generate-result.sh +++ b/src/MapleFE/test/java/openjdk/generate-result.sh @@ -17,5 +17,5 @@ FILES=$(pwd)/*.java for f in $FILES do echo "Generating result for $f ..." - ../../output/java/java2mpl $f > $f.result + ../../../output/java/java/java2mpl $f > $f.result done diff --git a/src/MapleFE/test/others/ChatTest-1.java b/src/MapleFE/test/java/others/ChatTest-1.java similarity index 100% rename from src/MapleFE/test/others/ChatTest-1.java rename to src/MapleFE/test/java/others/ChatTest-1.java diff --git a/src/MapleFE/test/others/ChatTest-1.java.result b/src/MapleFE/test/java/others/ChatTest-1.java.result similarity index 57% rename from src/MapleFE/test/others/ChatTest-1.java.result rename to src/MapleFE/test/java/others/ChatTest-1.java.result index d55049c9bf1d5050a278afd07f004dded5f5b1e1..199b485acd4c4704be2e0e6aed2e3025a514e691 100644 --- a/src/MapleFE/test/others/ChatTest-1.java.result +++ b/src/MapleFE/test/java/others/ChatTest-1.java.result @@ -28,7 +28,7 @@ class ChatTest Instance Initializer: Constructors: Methods: - func main() throws: Throwable + func main(args) throws: Throwable testStartStop() testPortOpen() testAsksForName() @@ -37,57 +37,63 @@ class ChatTest testUsernameAndMessage() testDontReceiveMessageInNameState() func startServer() throws: IOException - var:server=new ChatServer - var:address=(InetSocketAddress)server.getSocketAddress() + Decl: server=new ChatServer(0) + Decl: address=(InetSocketAddress)server.getSocketAddress() listeningPort Assign address.getPort() server.run() return server func testStartStop() throws: Exception - var:server=startServer() + Decl: server=startServer() server.shutdown() func testPortOpen() throws: Exception - var:server=startServer() - var:socket=new Socket + Decl: server=startServer() + Decl: socket=new Socket("localhost",listeningPort) cond-branch cond:socket.isConnected() true branch : - new RuntimeException + new RuntimeException("Failed to connect to server: port not open") false branch : server.shutdown() func testAsksForName() throws: Exception - var:server=startServer() - var:socket=new Socket + Decl: server=startServer() + Decl: socket=new Socket("localhost",listeningPort) + Decl: reader=new BufferedReader(new InputStreamReader(socket.getInputStream())) + Decl: string=readAvailableString(reader) + cond-branch cond:string.equals("Name: ") + true branch : + new RuntimeException("Server doesn't send Name: ") + false branch : server.shutdown() func testUseName() throws: Throwable - var:server=startServer() + Decl: server=startServer() performTestUseName() server.shutdown() func testConnectDisconnectConnect() throws: Exception - var:server=startServer() + Decl: server=startServer() performTestConnectDisconnectConnect() server.shutdown() func testUsernameAndMessage() throws: Exception - var:server=startServer() + Decl: server=startServer() performTestUsernameAndMessage() server.shutdown() func testDontReceiveMessageInNameState() throws: Exception - var:server=startServer() + Decl: server=startServer() performDontReceiveMessageInNameState() server.shutdown() - func assertEqual() throws: + func assertEqual(exception,value,expected) throws: cond-branch cond:expected EQ value true branch : return @@ -95,23 +101,23 @@ class ChatTest cond-branch cond:expected EQ null true branch : - exception.add(new RuntimeException) + exception.add(new RuntimeException("Expected null, but was: " Add value)) return false branch : cond-branch cond:expected.equals(value) true branch : - exception.add(new RuntimeException) + exception.add(new RuntimeException("Expected: " Add expected Add " but was: " Add value)) return false branch : func performDontReceiveMessageInNameState() throws: Exception - var:barrier1=new CyclicBarrier - var:barrier2=new CyclicBarrier - var:barrier3=new CyclicBarrier - var:exceptions=Collections.synchronizedList(new ArrayList) - var:chatConnection=new ChatConnection - var:client2=new Thread + Decl: barrier1=new CyclicBarrier(2) + Decl: barrier2=new CyclicBarrier(2) + Decl: barrier3=new CyclicBarrier(2) + Decl: exceptions=Collections.synchronizedList(new ArrayList()) + Decl: chatConnection=new ChatConnection() + Decl: client2=new Thread(new ChatConnection()) client2.start() chatConnection.run() cond-branch cond:exceptions.isEmpty() @@ -119,17 +125,17 @@ class ChatTest exceptions.get(0) false branch : - func waitForJoin() throws: IOException - var:joined + func waitForJoin(reader,s) throws: IOException + Decl: joined do joined Assign readAvailableString(reader) while (joined NE null Land joined.contains("Welcome " Add s)) func performTestUsernameAndMessage() throws: Exception - var:barrier1=new CyclicBarrier - var:barrier2=new CyclicBarrier - var:barrier3=new CyclicBarrier - var:exceptions=Collections.synchronizedList(new ArrayList) - var:chatConnection=new ChatConnection - var:client2=new Thread + Decl: barrier1=new CyclicBarrier(2) + Decl: barrier2=new CyclicBarrier(2) + Decl: barrier3=new CyclicBarrier(2) + Decl: exceptions=Collections.synchronizedList(new ArrayList()) + Decl: chatConnection=new ChatConnection() + Decl: client2=new Thread(new ChatConnection()) client2.start() chatConnection.run() cond-branch cond:exceptions.isEmpty() @@ -137,18 +143,19 @@ while (joined NE null Land joined.contains("Welcome " Add s)) exceptions.get(0) false branch : - func readAvailableString() throws: IOException + func readAvailableString(reader) throws: IOException return readAvailableString(reader,false) - func readAvailableString() throws: IOException - var:builder=new StringBuilder - var:bytes + func readAvailableString(reader,now) throws: IOException + Decl: builder=new StringBuilder() + Decl: bytes cond-branch cond:now Land reader.ready() true branch : return null false branch : - do var:buf= - + do Decl: buf= + bytes Assign reader.read(buf) + builder.append(buf,0,bytes) while bytes EQ 256 return builder.toString() LocalClasses: @@ -161,13 +168,21 @@ while bytes EQ 256 func run() throws: Socket socket - new Socket - + new Socket("localhost",listeningPort) + BufferedReader + reader + new BufferedReader(new InputStreamReader(socket.getInputStream())) + Writer + writer + new FlushingWriter(new OutputStreamWriter(socket.getOutputStream())) socket.setTcpNoDelay(true) run(socket,reader,writer) + Exception + e + exception Assign e - func run() throws: Exception + func run(socket,reader,writer) throws: Exception LocalClasses: LocalInterfaces: class FlushingWriter @@ -175,18 +190,17 @@ while bytes EQ 256 delegate Instance Initializer: Constructors: - constructor FlushingWriter() throws: + constructor FlushingWriter(delegate) throws: this.delegate Assign delegate Methods: - func write() throws: IOException + func write(cbuf,off,len) throws: IOException delegate.write(cbuf,off,len) func flush() throws: IOException delegate.flush() func close() throws: IOException delegate.close() - func write() throws: IOException - write - str + func write(str) throws: IOException + super.write(str) flush() LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/others/ChatTest-2.java b/src/MapleFE/test/java/others/ChatTest-2.java similarity index 100% rename from src/MapleFE/test/others/ChatTest-2.java rename to src/MapleFE/test/java/others/ChatTest-2.java diff --git a/src/MapleFE/test/others/ChatTest-2.java.result b/src/MapleFE/test/java/others/ChatTest-2.java.result similarity index 84% rename from src/MapleFE/test/others/ChatTest-2.java.result rename to src/MapleFE/test/java/others/ChatTest-2.java.result index c0aa2ba566e42a8972817cc2e3032afd719d2436..18139019faa869c267dead7f165103cf6f5280af 100644 --- a/src/MapleFE/test/others/ChatTest-2.java.result +++ b/src/MapleFE/test/java/others/ChatTest-2.java.result @@ -8,7 +8,7 @@ class ChatTest Constructors: Methods: func performDontReceiveMessageInNameState() throws: - var:exceptions=new ArrayList + Decl: exceptions=new ArrayList() LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/others/ChatTest-full.java b/src/MapleFE/test/java/others/ChatTest-full.java similarity index 100% rename from src/MapleFE/test/others/ChatTest-full.java rename to src/MapleFE/test/java/others/ChatTest-full.java diff --git a/src/MapleFE/test/others/ChatTest-full.java.result b/src/MapleFE/test/java/others/ChatTest-full.java.result similarity index 56% rename from src/MapleFE/test/others/ChatTest-full.java.result rename to src/MapleFE/test/java/others/ChatTest-full.java.result index 7117d4628595fdbaf3125491e34a7678146b49da..c8e02b22089dab33690a75a5a774d208074d1823 100644 --- a/src/MapleFE/test/others/ChatTest-full.java.result +++ b/src/MapleFE/test/java/others/ChatTest-full.java.result @@ -29,11 +29,11 @@ class ChatTest Constructors: Methods: func performTestConnectDisconnectConnect() throws: Exception - var:barrier1=new CyclicBarrier - var:barrier2=new CyclicBarrier - var:barrier3=new CyclicBarrier - var:exceptions=new ArrayList - func main() throws: Throwable + Decl: barrier1=new CyclicBarrier(2) + Decl: barrier2=new CyclicBarrier(2) + Decl: barrier3=new CyclicBarrier(2) + Decl: exceptions=new ArrayList() + func main(args) throws: Throwable testStartStop() testPortOpen() testAsksForName() @@ -42,57 +42,63 @@ class ChatTest testUsernameAndMessage() testDontReceiveMessageInNameState() func startServer() throws: IOException - var:server=new ChatServer - var:address=(InetSocketAddress)server.getSocketAddress() + Decl: server=new ChatServer(0) + Decl: address=(InetSocketAddress)server.getSocketAddress() listeningPort Assign address.getPort() server.run() return server func testStartStop() throws: Exception - var:server=startServer() + Decl: server=startServer() server.shutdown() func testPortOpen() throws: Exception - var:server=startServer() - var:socket=new Socket + Decl: server=startServer() + Decl: socket=new Socket("localhost",listeningPort) cond-branch cond:socket.isConnected() true branch : - new RuntimeException + new RuntimeException("Failed to connect to server: port not open") false branch : server.shutdown() func testAsksForName() throws: Exception - var:server=startServer() - var:socket=new Socket + Decl: server=startServer() + Decl: socket=new Socket("localhost",listeningPort) + Decl: reader=new BufferedReader(new InputStreamReader(socket.getInputStream())) + Decl: string=readAvailableString(reader) + cond-branch cond:string.equals("Name: ") + true branch : + new RuntimeException("Server doesn't send Name: ") + false branch : server.shutdown() func testUseName() throws: Throwable - var:server=startServer() + Decl: server=startServer() performTestUseName() server.shutdown() func testConnectDisconnectConnect() throws: Exception - var:server=startServer() + Decl: server=startServer() performTestConnectDisconnectConnect() server.shutdown() func testUsernameAndMessage() throws: Exception - var:server=startServer() + Decl: server=startServer() performTestUsernameAndMessage() server.shutdown() func testDontReceiveMessageInNameState() throws: Exception - var:server=startServer() + Decl: server=startServer() performDontReceiveMessageInNameState() server.shutdown() - func assertEqual() throws: + func assertEqual(exception,value,expected) throws: cond-branch cond:expected EQ value true branch : return @@ -100,23 +106,23 @@ class ChatTest cond-branch cond:expected EQ null true branch : - exception.add(new RuntimeException) + exception.add(new RuntimeException("Expected null, but was: " Add value)) return false branch : cond-branch cond:expected.equals(value) true branch : - exception.add(new RuntimeException) + exception.add(new RuntimeException("Expected: " Add expected Add " but was: " Add value)) return false branch : func performDontReceiveMessageInNameState() throws: Exception - var:barrier1=new CyclicBarrier - var:barrier2=new CyclicBarrier - var:barrier3=new CyclicBarrier - var:exceptions=Collections.synchronizedList(new ArrayList) - var:chatConnection=new ChatConnection - var:client2=new Thread + Decl: barrier1=new CyclicBarrier(2) + Decl: barrier2=new CyclicBarrier(2) + Decl: barrier3=new CyclicBarrier(2) + Decl: exceptions=Collections.synchronizedList(new ArrayList()) + Decl: chatConnection=new ChatConnection() + Decl: client2=new Thread(new ChatConnection()) client2.start() chatConnection.run() cond-branch cond:exceptions.isEmpty() @@ -124,17 +130,17 @@ class ChatTest exceptions.get(0) false branch : - func waitForJoin() throws: IOException - var:joined + func waitForJoin(reader,s) throws: IOException + Decl: joined do joined Assign readAvailableString(reader) while (joined NE null Land joined.contains("Welcome " Add s)) func performTestUsernameAndMessage() throws: Exception - var:barrier1=new CyclicBarrier - var:barrier2=new CyclicBarrier - var:barrier3=new CyclicBarrier - var:exceptions=Collections.synchronizedList(new ArrayList) - var:chatConnection=new ChatConnection - var:client2=new Thread + Decl: barrier1=new CyclicBarrier(2) + Decl: barrier2=new CyclicBarrier(2) + Decl: barrier3=new CyclicBarrier(2) + Decl: exceptions=Collections.synchronizedList(new ArrayList()) + Decl: chatConnection=new ChatConnection() + Decl: client2=new Thread(new ChatConnection()) client2.start() chatConnection.run() cond-branch cond:exceptions.isEmpty() @@ -143,13 +149,13 @@ while (joined NE null Land joined.contains("Welcome " Add s)) false branch : func performTestConnectDisconnectConnect() throws: Exception - var:barrier1=new CyclicBarrier - var:barrier2=new CyclicBarrier - var:barrier3=new CyclicBarrier - var:exceptions=new ArrayList - var:chatConnection=new ChatConnection - var:chatConnection2=new ChatConnection - var:client2=new Thread + Decl: barrier1=new CyclicBarrier(2) + Decl: barrier2=new CyclicBarrier(2) + Decl: barrier3=new CyclicBarrier(2) + Decl: exceptions=new ArrayList() + Decl: chatConnection=new ChatConnection() + Decl: chatConnection2=new ChatConnection() + Decl: client2=new Thread(new ChatConnection()) client2.start() chatConnection.run() chatConnection2.run() @@ -159,12 +165,12 @@ while (joined NE null Land joined.contains("Welcome " Add s)) false branch : func performTestUseName() throws: Exception - var:barrier1=new CyclicBarrier - var:barrier2=new CyclicBarrier - var:barrier3=new CyclicBarrier - var:exceptions=new ArrayList - var:chatConnection=new ChatConnection - var:client2=new Thread + Decl: barrier1=new CyclicBarrier(2) + Decl: barrier2=new CyclicBarrier(2) + Decl: barrier3=new CyclicBarrier(2) + Decl: exceptions=new ArrayList() + Decl: chatConnection=new ChatConnection() + Decl: client2=new Thread(new ChatConnection()) client2.start() chatConnection.run() cond-branch cond:exceptions.isEmpty() @@ -172,18 +178,19 @@ while (joined NE null Land joined.contains("Welcome " Add s)) exceptions.get(0) false branch : - func readAvailableString() throws: IOException + func readAvailableString(reader) throws: IOException return readAvailableString(reader,false) - func readAvailableString() throws: IOException - var:builder=new StringBuilder - var:bytes + func readAvailableString(reader,now) throws: IOException + Decl: builder=new StringBuilder() + Decl: bytes cond-branch cond:now Land reader.ready() true branch : return null false branch : - do var:buf= - + do Decl: buf= + bytes Assign reader.read(buf) + builder.append(buf,0,bytes) while bytes EQ 256 return builder.toString() LocalClasses: @@ -196,13 +203,21 @@ while bytes EQ 256 func run() throws: Socket socket - new Socket - + new Socket("localhost",listeningPort) + BufferedReader + reader + new BufferedReader(new InputStreamReader(socket.getInputStream())) + Writer + writer + new FlushingWriter(new OutputStreamWriter(socket.getOutputStream())) socket.setTcpNoDelay(true) run(socket,reader,writer) + Exception + e + exception Assign e - func run() throws: Exception + func run(socket,reader,writer) throws: Exception LocalClasses: LocalInterfaces: class FlushingWriter @@ -210,18 +225,17 @@ while bytes EQ 256 delegate Instance Initializer: Constructors: - constructor FlushingWriter() throws: + constructor FlushingWriter(delegate) throws: this.delegate Assign delegate Methods: - func write() throws: IOException + func write(cbuf,off,len) throws: IOException delegate.write(cbuf,off,len) func flush() throws: IOException delegate.flush() func close() throws: IOException delegate.close() - func write() throws: IOException - write - str + func write(str) throws: IOException + super.write(str) flush() LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/others/ChatTest.java b/src/MapleFE/test/java/others/ChatTest.java similarity index 100% rename from src/MapleFE/test/others/ChatTest.java rename to src/MapleFE/test/java/others/ChatTest.java diff --git a/src/MapleFE/test/others/ChatTest.java.result b/src/MapleFE/test/java/others/ChatTest.java.result similarity index 55% rename from src/MapleFE/test/others/ChatTest.java.result rename to src/MapleFE/test/java/others/ChatTest.java.result index c1c0ddabe2350f16c28c717327eb8783de0da2d9..d1ced6a9bec630e4c5b309f54e27d0f8e28e9d8b 100644 --- a/src/MapleFE/test/others/ChatTest.java.result +++ b/src/MapleFE/test/java/others/ChatTest.java.result @@ -7,7 +7,7 @@ class ChatTest Instance Initializer: Constructors: Methods: - func main() throws: Throwable + func main(args) throws: Throwable testStartStop() testPortOpen() testAsksForName() @@ -16,57 +16,63 @@ class ChatTest testUsernameAndMessage() testDontReceiveMessageInNameState() func startServer() throws: IOException - var:server=new ChatServer - var:address=(InetSocketAddress)server.getSocketAddress() + Decl: server=new ChatServer(0) + Decl: address=(InetSocketAddress)server.getSocketAddress() listeningPort Assign address.getPort() server.run() return server func testStartStop() throws: Exception - var:server=startServer() + Decl: server=startServer() server.shutdown() func testPortOpen() throws: Exception - var:server=startServer() - var:socket=new Socket + Decl: server=startServer() + Decl: socket=new Socket("localhost",listeningPort) cond-branch cond:socket.isConnected() true branch : - new RuntimeException + new RuntimeException("Failed to connect to server: port not open") false branch : server.shutdown() func testAsksForName() throws: Exception - var:server=startServer() - var:socket=new Socket + Decl: server=startServer() + Decl: socket=new Socket("localhost",listeningPort) + Decl: reader=new BufferedReader(new InputStreamReader(socket.getInputStream())) + Decl: string=readAvailableString(reader) + cond-branch cond:string.equals("Name: ") + true branch : + new RuntimeException("Server doesn't send Name: ") + false branch : server.shutdown() func testUseName() throws: Throwable - var:server=startServer() + Decl: server=startServer() performTestUseName() server.shutdown() func testConnectDisconnectConnect() throws: Exception - var:server=startServer() + Decl: server=startServer() performTestConnectDisconnectConnect() server.shutdown() func testUsernameAndMessage() throws: Exception - var:server=startServer() + Decl: server=startServer() performTestUsernameAndMessage() server.shutdown() func testDontReceiveMessageInNameState() throws: Exception - var:server=startServer() + Decl: server=startServer() performDontReceiveMessageInNameState() server.shutdown() - func assertEqual() throws: + func assertEqual(exception,value,expected) throws: cond-branch cond:expected EQ value true branch : return @@ -74,23 +80,23 @@ class ChatTest cond-branch cond:expected EQ null true branch : - exception.add(new RuntimeException) + exception.add(new RuntimeException("Expected null, but was: " Add value)) return false branch : cond-branch cond:expected.equals(value) true branch : - exception.add(new RuntimeException) + exception.add(new RuntimeException("Expected: " Add expected Add " but was: " Add value)) return false branch : func performDontReceiveMessageInNameState() throws: Exception - var:barrier1=new CyclicBarrier - var:barrier2=new CyclicBarrier - var:barrier3=new CyclicBarrier - var:exceptions=Collections.synchronizedList(new ArrayList) - var:chatConnection=new ChatConnection - var:client2=new Thread + Decl: barrier1=new CyclicBarrier(2) + Decl: barrier2=new CyclicBarrier(2) + Decl: barrier3=new CyclicBarrier(2) + Decl: exceptions=Collections.synchronizedList(new ArrayList()) + Decl: chatConnection=new ChatConnection() + Decl: client2=new Thread(new ChatConnection()) client2.start() chatConnection.run() cond-branch cond:exceptions.isEmpty() @@ -98,17 +104,17 @@ class ChatTest exceptions.get(0) false branch : - func waitForJoin() throws: IOException - var:joined + func waitForJoin(reader,s) throws: IOException + Decl: joined do joined Assign readAvailableString(reader) while (joined NE null Land joined.contains("Welcome " Add s)) func performTestUsernameAndMessage() throws: Exception - var:barrier1=new CyclicBarrier - var:barrier2=new CyclicBarrier - var:barrier3=new CyclicBarrier - var:exceptions=Collections.synchronizedList(new ArrayList) - var:chatConnection=new ChatConnection - var:client2=new Thread + Decl: barrier1=new CyclicBarrier(2) + Decl: barrier2=new CyclicBarrier(2) + Decl: barrier3=new CyclicBarrier(2) + Decl: exceptions=Collections.synchronizedList(new ArrayList()) + Decl: chatConnection=new ChatConnection() + Decl: client2=new Thread(new ChatConnection()) client2.start() chatConnection.run() cond-branch cond:exceptions.isEmpty() diff --git a/src/MapleFE/test/java2mpl/generate-result.sh b/src/MapleFE/test/java/others/generate-result.sh similarity index 92% rename from src/MapleFE/test/java2mpl/generate-result.sh rename to src/MapleFE/test/java/others/generate-result.sh index bbd3acd878bd41d3a31fc5123972e954d7c9fcd0..08b3acc3b58dc1585fb15888064b004629e72007 100755 --- a/src/MapleFE/test/java2mpl/generate-result.sh +++ b/src/MapleFE/test/java/others/generate-result.sh @@ -17,5 +17,5 @@ FILES=$(pwd)/*.java for f in $FILES do echo "Generating result for $f ..." - ../../output/java/java2mpl $f > $f.result + ../../../output/java/java/java2mpl $f > $f.result done diff --git a/src/MapleFE/test/others/plotter.java b/src/MapleFE/test/java/others/plotter.java similarity index 100% rename from src/MapleFE/test/others/plotter.java rename to src/MapleFE/test/java/others/plotter.java diff --git a/src/MapleFE/test/others/plotter.java.result b/src/MapleFE/test/java/others/plotter.java.result similarity index 67% rename from src/MapleFE/test/others/plotter.java.result rename to src/MapleFE/test/java/others/plotter.java.result index 78be976165d420319bc69a4617fcea334bcd11cf..c266a3188f1edb757c066e00dfa72b56d962494a 100644 --- a/src/MapleFE/test/others/plotter.java.result +++ b/src/MapleFE/test/java/others/plotter.java.result @@ -37,15 +37,23 @@ class Plotter Instance Initializer: Constructors: Methods: - func main() throws: IOException - var:path=Paths.get("footprint.csv") + func main(args) throws: IOException + Decl: path=Paths.get("footprint.csv") BufferedWriter stream Files.newBufferedWriter(path,StandardOpenOption.CREATE) - stream.write("bits,bool,bitset -") + stream.write("bits,bool,bitset\n") for ( ) System.out.println("Number of bits => " Add i) + Decl: ba= + Decl: bitSet=new BitSet(i) + Decl: baSize=ClassLayout.parseInstance(ba).instanceSize() + Decl: bitSetSize=GraphLayout.parseInstance(bitSet).totalSize() + stream.write((i Add "," Add baSize Add "," Add bitSetSize Add "\n")) + cond-branch cond:i Mod 10000 EQ 0 + true branch : + stream.flush() + false branch : diff --git a/src/MapleFE/test/others/receiver.java b/src/MapleFE/test/java/others/receiver.java similarity index 84% rename from src/MapleFE/test/others/receiver.java rename to src/MapleFE/test/java/others/receiver.java index 7bd8f8a09b64773ccf5d519d6532b88a320d74ab..280035847267b28da7e4d6ebe8c84d629ff79504 100644 --- a/src/MapleFE/test/others/receiver.java +++ b/src/MapleFE/test/java/others/receiver.java @@ -19,11 +19,13 @@ class Outer { Outer() {} void m(Outer this) {} class Inner { - Inner(Outer Outer.this) {} + //Inner(Outer Outer.this) {} + Inner(Outer Outer) {} void m(Inner this) {} class B { - B(Outer.Inner Inner.this) {} - void m(Outer.Inner.B this) {} + //B(Outer.Inner Inner.this) {} + B(Inner Inner) {} + void m(Outer this) {} } } } diff --git a/src/MapleFE/test/others/receiver.java.result b/src/MapleFE/test/java/others/receiver.java.result similarity index 71% rename from src/MapleFE/test/others/receiver.java.result rename to src/MapleFE/test/java/others/receiver.java.result index e3f63c08a412c4f8164eeb5573606acca0063cce..adb36777b5f0d0f38dddcd088e3376e437b01c49 100644 --- a/src/MapleFE/test/others/receiver.java.result +++ b/src/MapleFE/test/java/others/receiver.java.result @@ -1,4 +1,4 @@ -Matched 65 tokens. +Matched 55 tokens. ============= Module =========== == Sub Tree == class Outer @@ -8,25 +8,25 @@ class Outer Constructors: constructor Outer() throws: Methods: - func m() throws: + func m(Outer) throws: LocalClasses: class Inner Fields: Instance Initializer: Constructors: - constructor Inner() throws: + constructor Inner(Outer) throws: Methods: - func m() throws: + func m(Inner) throws: LocalClasses: class B Fields: Instance Initializer: Constructors: - constructor B() throws: + constructor B(Inner) throws: Methods: - func m() throws: + func m(Outer) throws: LocalClasses: LocalInterfaces: LocalInterfaces: diff --git a/src/MapleFE/test/others/sizing.java b/src/MapleFE/test/java/others/sizing.java similarity index 100% rename from src/MapleFE/test/others/sizing.java rename to src/MapleFE/test/java/others/sizing.java diff --git a/src/MapleFE/test/others/sizing.java.result b/src/MapleFE/test/java/others/sizing.java.result similarity index 66% rename from src/MapleFE/test/others/sizing.java.result rename to src/MapleFE/test/java/others/sizing.java.result index 5a9bf938c5873e9237d34bb5e7a59e0ba0d8121f..950e89f28d0fc42010b2bf592287eb68dab6f054 100644 --- a/src/MapleFE/test/others/sizing.java.result +++ b/src/MapleFE/test/java/others/sizing.java.result @@ -19,11 +19,11 @@ class Sizing Instance Initializer: Constructors: Methods: - func main() throws: - var:ba= - System.out.println(ClassLayout.parseInstance(ba),toPrintable) - var:bitSet=new BitSet - System.out.println(GraphLayout.parseInstance(bitSet),toPrintable) + func main(args) throws: + Decl: ba= + System.out.println(ClassLayout.parseInstance(ba).toPrintable()) + Decl: bitSet=new BitSet(10000) + System.out.println(GraphLayout.parseInstance(bitSet).toPrintable()) LocalClasses: LocalInterfaces: diff --git a/src/MapleFE/test/java/syntaxonly/generate-result.sh b/src/MapleFE/test/java/syntaxonly/generate-result.sh new file mode 100755 index 0000000000000000000000000000000000000000..08b3acc3b58dc1585fb15888064b004629e72007 --- /dev/null +++ b/src/MapleFE/test/java/syntaxonly/generate-result.sh @@ -0,0 +1,21 @@ +# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +#!/bin/bash +FILES=$(pwd)/*.java +for f in $FILES +do + echo "Generating result for $f ..." + ../../../output/java/java/java2mpl $f > $f.result +done diff --git a/src/MapleFE/test/syntaxonly/var-scope-1.java b/src/MapleFE/test/java/syntaxonly/var-scope-1.java similarity index 100% rename from src/MapleFE/test/syntaxonly/var-scope-1.java rename to src/MapleFE/test/java/syntaxonly/var-scope-1.java diff --git a/src/MapleFE/test/syntaxonly/var-scope-1.java.result b/src/MapleFE/test/java/syntaxonly/var-scope-1.java.result similarity index 55% rename from src/MapleFE/test/syntaxonly/var-scope-1.java.result rename to src/MapleFE/test/java/syntaxonly/var-scope-1.java.result index e2618617a5bfc8b1f83178266e81bd1a8bd3a168..5ca73a8308698c869f6edb6f3cd94e27b28a511b 100644 --- a/src/MapleFE/test/syntaxonly/var-scope-1.java.result +++ b/src/MapleFE/test/java/syntaxonly/var-scope-1.java.result @@ -7,12 +7,20 @@ class A Instance Initializer: Constructors: Methods: - func foo() throws: + func foo(x) throws: a Assign x cond-branch cond:a EQ 2 true branch : - var:a=2 + Decl: a=2 + x Assign a Add this.a Add 2 + a Assign x Add 2 + cond-branch cond:a EQ 4 + true branch : + Decl: a=4 + x Assign a Add this.a Add 4 + false branch : + x Assign a Add 5 false branch : a Assign x Add this.a Add a diff --git a/src/MapleFE/test/java2mpl_runtests.pl b/src/MapleFE/test/java2mpl_runtests.pl deleted file mode 100755 index 6a7b7af8b263d6ebd8d8df21b8bc0d015b1faa0e..0000000000000000000000000000000000000000 --- a/src/MapleFE/test/java2mpl_runtests.pl +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/perl -w -use Cwd; -use warnings; - -my $pwd = getcwd; - -#print "here1 current pwd $pwd\n"; - -if ((!(defined $ARGV[0])) || ($ARGV[0] ne "java2mpl")) { - print "------------------------------------------------\n"; - print "usage: java2mpl_runtests.pl java2mpl\n"; - print "------------------------------------------------\n"; - exit; -} - -$dirname = "./$ARGV[0]"; - -my $outdir = "$pwd/java2mpl_output"; -my $diffdir = "$pwd/java2mpl_diff"; -my $notexistsdir = "$pwd/java2mpl_notexists"; -if(!(-e "$outdir")) { - system("mkdir -p $outdir"); -} - -my @failed_java2mpl_file; -my @successed_file; - -my $count = 0; -my $countJAVA2MPL = 0; - - -chdir $dirname; -$dirname = "./"; -opendir (DIR, $dirname ) || die "Error in opening dir $dirname\n"; - -#print "here2 dirname $dirname\n"; - -print("\n====================== run tests: $ARGV[0] =====================\n"); - -while( ($srcdir = readdir(DIR))){ - if(-d $srcdir and $srcdir ne ".." and $srcdir ne "output" and $srcdir ne "temp") { - my $predir = getcwd; - chdir $srcdir; - my @javafiles; - @javafiles = <*.java>; - -#print "here3 source directory $srcdir\n"; -#print "here4 predir $predir\n"; - - my @allfiles = (@javafiles); - foreach $fullname (@allfiles) { - $count ++; - (my $file = $fullname) =~ s/\.[^.]+$//; - if(defined $ARGV[1]) { - print "\n$file"; - } else { - print "."; - } - if ($count % 50 == 0) { - print " $count\n"; - } - my $flag = 0; - my $src_file = $fullname; - my $java2mpl_oresult_file = $file.'.java.result'; - my $java2mpl_log_file = $file.'.java2mpl.log'; - my $java2mpl_result_file = $file.'.java.java2mpl.result'; - my $java2mpl_err_file = $file.'.err'; - my $java2mpl_diff_file = $file.'.java.diff'; - - if(!(-e "$outdir")) { - system("mkdir -p $outdir"); - } - -#print "here5 outdir $outdir\n"; -#print "here6 src_file $src_file\n"; - - system("cp $src_file $outdir/$src_file"); - $res = system("cd $pwd/..; $BUILDDIR/java/java2mpl $outdir/$src_file > $outdir/$java2mpl_result_file"); - if ($res > 0) { - print "\ngdb --args $BUILDDIR/java/java2mpl $outdir/$src_file\n"; - print " ==java2mpl===> $file\n\n"; - $countJAVA2MPL ++; - push(@failed_java2mpl_file, $file); - $flag ++; - next; - } - -#print "here7 diff src_file $pwd/java2mpl/$java2mpl_oresult_file\n"; -#print "here8 diff java2mpl_result_file $java2mpl_result_file\n"; - - if (!(-e $java2mpl_oresult_file)) { - if(!(-e "$notexistsdir")) { - system("mkdir -p $notexistsdir"); - } - -#print "here9 $java2mpl_oresult_file NOT exists\n"; - print "Original file $java2mpl_oresult_file does NOT exists!\n"; - system("touch $notexistsdir/$java2mpl_oresult_file"); - $countJAVA2MPL ++; - push(@failed_java2mpl_file, $file); - } - else { -#print "here10 java2mpl_result_file $outdir/$java2mpl_result_file\n"; - if ((!(-e "$outdir/$java2mpl_result_file")) || (-z "$outdir/$java2mpl_result_file")) { - if(!(-e "$notexistsdir")) { - system("mkdir -p $notexistsdir"); - } - -#print "here11 $outdir/$java2mpl_result_file NOT exists\n"; - print "$java2mpl_result_file either empty or not exists!\n"; - system("touch $notexistsdir/$java2mpl_result_file"); - $countJAVA2MPL ++; - push(@failed_java2mpl_file, $file); - } else { - $res2 = system("diff $pwd/java2mpl/$java2mpl_oresult_file $outdir/$java2mpl_result_file"); - if ($res2 > 0) { - if(!(-e "$diffdir")) { - system("mkdir -p $diffdir"); - } - -#print "here12 $java2mpl_diff_file Different!!!\n"; - print "$java2mpl_oresult_file $java2mpl_result_file are different!!!\n"; - system("touch $diffdir/$java2mpl_diff_file"); - $countJAVA2MPL ++; - push(@failed_java2mpl_file, $file); - } else { - push(@successed_file, $file); - } - - } - } - -# if($flag eq 0){ -# push(@successed_file, $file); -# } - next; - - if ($flag eq -1) { - push(@successed_file, $file); - system("rm -f $outdir/$src_file"); - system("rm -f $outdir/$java2mpl_log_file"); - system("rm -f $outdir/$java2mpl_oresult_file"); - system("rm -f $outdir/$java2mpl_result_file"); - system("rm -f $outdir/$java2mpl_err_file"); - system("rm -f $diffdir/$java2mpl_diff_file"); - system("rm -f $notexists/$java2mpl_oresult_file"); - system("rm -f $notexists/$java2mpl_result_file"); - next; - } - } - chdir $predir; - } -} - -print " $count\n"; -closedir(DIR); -chdir $pwd; - -my $countFailed = $countJAVA2MPL ; -my $countPassed = $count - $countFailed; - -my $reportFile = 'java2mpl_report.txt'; -open(my $fh, '>', $reportFile) or die "Could not open file '$reportFile' $!"; -print $fh "$ARGV[0] report: \n"; - -if ($countFailed eq 0) { - print("\n all $count tests passed\n"); - print("======================================================\n"); - print $fh "all $count tests passed\n"; - close $fh; -} else { - print "\n\n=====Scan Result=====\n\n"; - print "Total Test Cases: $count\n"; - if(scalar(@successed_file) > 0) { - print "\n=========================\npassed $countPassed tests:\n\n"; - foreach $passed (@successed_file) { - print $passed."\n"; - } - print $fh "$countPassed testcases passed\n"; - } - print "\n=========================\nfailed $countFailed tests:\n\n"; - if(scalar(@failed_java2mpl_file) > 0){ - print("=== failed java2mpl: $countJAVA2MPL tests\n"); - print $fh "$countJAVA2MPL testcases failed\n"; - - foreach $failed (@failed_java2mpl_file) { - print $failed."\n"; - } - print "\n"; - } - print "=========================\n"; - close $fh; -} diff --git a/src/MapleFE/test/msts_test.sh b/src/MapleFE/test/msts_test.sh new file mode 100755 index 0000000000000000000000000000000000000000..b502845fdc33c1ba5df9e3d406fbdec49c2b0686 --- /dev/null +++ b/src/MapleFE/test/msts_test.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +[ -n "$MAPLEFE_ROOT" ] || { echo MAPLE_ROOT not set. Please source envsetup.sh.; exit 1; } +cd ${MAPLEFE_ROOT}/test + +if [ ! -d ${MAPLEFE_ROOT}/test/TypeScript ]; then + git clone -b release-1.8 https://github.com/microsoft/TypeScript.git +fi + +if [ -f ${MAPLEFE_ROOT}/test/msts_testlist ]; then + cat msts_testlist | xargs -n1 -I % sh -c '{ rm -f typescript/ms_tests/%; cp -f TypeScript/tests/cases/compiler/% typescript/ms_tests/; cp -f TypeScript/LICENSE.txt typescript/ms_tests/; }' +fi + +# setup files only. do not run test +if [ "x$1" = "xsetup" ]; then + exit 0 +fi + +# export is for sh -c in xargs +export TS2AST=$MAPLEFE_ROOT/output/typescript/bin/ts2ast +export PASS_LIST=msts_passed.txt +FAIL_LIST=msts_failed.txt +MSTEST_DIR=$MAPLEFE_ROOT/test/TypeScript/tests/cases/compiler +N_JOBS=16 + +[ -n "$MAPLE_ROOT" ] || { echo MAPLE_ROOT not set. Please source envsetup.sh.; exit 1; } +if [ ! -d $MSTEST_DIR ]; then + echo "$MSTEST_DIR" does not exist. Please git clone https://github.com/microsoft/TypeScript.git under "$MAPLEFE_ROOT/test" + exit 1 +fi + +cd $MAPLEFE_ROOT/test +rm -f $PASS_LIST +find $MSTEST_DIR -name "*.ts" | xargs -n1 -P$N_JOBS -I % sh -c '{ $TS2AST %; exitcode=$?; if [ $exitcode -eq 0 ]; then basename % >> $PASS_LIST; fi }' +cd $MSTEST_DIR +ls *.ts | grep -v -x -f $MAPLEFE_ROOT/test/$PASS_LIST /dev/stdin > $MAPLEFE_ROOT/test/$FAIL_LIST +cd - +sort -o $PASS_LIST $PASS_LIST +echo +echo "Microsoft Typescript compiler testcases: Passed: " `wc -l < $PASS_LIST` " Failed: " `wc -l < $FAIL_LIST` +echo "List of passed and failed cases are in $PASS_LIST and $FAIL_LIST" +echo +echo "Note: Add testcase name from above lists into mstest_testlist if" +echo " you want it included in make test" +echo +cd - > /dev/null diff --git a/src/MapleFE/test/msts_testlist b/src/MapleFE/test/msts_testlist new file mode 100644 index 0000000000000000000000000000000000000000..5444b5c452e1b8e2c7a778b0cda3c34ff9efeb49 --- /dev/null +++ b/src/MapleFE/test/msts_testlist @@ -0,0 +1,5 @@ +checkInterfaceBases.ts +getsetReturnTypes.ts +reExportGlobalDeclaration3.ts +library_ObjectPrototypeProperties.ts + diff --git a/src/MapleFE/test/new_runtests.pl b/src/MapleFE/test/new_runtests.pl new file mode 100755 index 0000000000000000000000000000000000000000..06479ff92804476597d5731effb295d0039554d3 --- /dev/null +++ b/src/MapleFE/test/new_runtests.pl @@ -0,0 +1,228 @@ +#!/usr/bin/perl + +use Cwd; +use warnings; +use experimental 'smartmatch'; +use File::Find; +use File::Basename; + +use File::Find qw(find); + +if(!(defined $ARGV[0])) { + print "------------------------------------------------\n"; + print "usage: runtests.pl [ java | java/subdirectory | typescript | typescript/subdirectory ]\n"; + print "------------------------------------------------\n"; + exit; +} + +my $lang = $ARGV[0]; +my $pwd = getcwd; +my $currdir = "$pwd"; + +my @failed_file; +my @failed_file1; +my @failed_file2; +my @successed_file; + +my $count = 0; +my $counttotal = 0; +my $countfailedcases = 0; +my $countfailedcases1 = 0; +my $countfailedcases2 = 0; +my $countsub = 0; + +my $pinput = ''; +my $cmnd = ''; +my $outroot = ''; +print "Running $lang\n"; +if ($lang =~ /\Qjava\E/) { + $pinput = "java"; + $cmnd = "../output/java/bin/java2ast"; + $cmnd1 = "../output/java/bin/ast2mpl"; + $flag = ""; + $outroot = "$currdir/../output/$pinput/test"; +} elsif ($lang =~ /\Qtypescript\E/) { + $pinput = "ts"; + $cmnd = "../output/typescript/bin/ts2ast"; + $cmnd1 = "../output/typescript/bin/ast2cpp"; + $flag = "--no-imported"; + $outroot = "$currdir/../output/typescript/test"; +} else { + print "$lang is an invalid option\n"; + exit; +} + +my $testdir = $lang; +# get specified directory to test if other than $lang +if(defined $ARGV[1]) { + $testdir = $ARGV[1]; +} + +system("rm -Rf $outroot/report.txt $outroot/diff $outroot/notexists"); + +if(!(-e "$outroot")) { + system("mkdir -p $outroot"); +} + +opendir (my $DIR, $testdir) || die "Error in opening $testdir directory\n"; + +sub listdirs { + my @dirs = @_; + my @files; + + if ( $pinput ~~ [qw( java ts )] ) { + find({ wanted => sub { push @files, glob "\"$_/{*.$pinput,*.$pinput.result}\"" } , no_chdir => 1 }, @dirs); + } else { + find({ wanted => sub { push @files, $_ } , no_chdir => 1 }, @dirs); + } + + return @files; +} + +my @paths = listdirs($testdir) ; + +foreach my $file (@paths) { + my ($filename) = ( $file =~ /([^\\\/]+)$/s ) ; + my ($pathname) = dirname($file); + + if ( $pinput ~~ [qw( java ts )] ) { + system("rm -rf $outroot/$file; cp -rp --parents $file $outroot/"); + + if ( ($filename =~ (/(.+)[.]java$/)) || ($filename =~ (/(.+)[.]ts$/)) ) { + + my $origresult = "$pwd/$file.result"; + my $outresult = $file.'.result.'.$pinput; + my $diff_file = $file.'.result.diff'; + my $notexistsdir = "$outroot/notexists"; + my $diffdir = "$outroot/diff"; + + $count ++; + print "."; + if ($count % 50 == 0) { + print " $count\n"; + } + + #my $res = system("$pwd/$cmnd $outroot/$file > $outroot/$outresult"); + #my $res = system('$pwd/$cmnd $outroot/$file; $pwd/$cmnd1 $outroot/$file.ast > $outroot/$outresult'); + my $res = system("$pwd/$cmnd $outroot/$file > $outroot/$outresult"); + #print "$pwd/$cmnd $outroot/$file > $outroot/$outresult"; + + if ($res > 0) { + print " ==$pinput===> $file\n"; + print "$pwd/$cmnd $outroot/$file\n"; + $countfailedcases ++; + push(@failed_file, $pinput.": ".$file); + #print "---------------------------\n"; + next; + } else { + my $res1 = system("$cmnd1 $outroot/$file.ast $flag > $outroot/$outresult.1"); + #print "$cmnd1 $outroot/$file.ast $flag > $outroot/$outresult.1"; + + if ($res1 > 0) { + print " ==$pinput===> $file\n"; + print "$cmnd1 $outroot/$file.ast\n"; + $countfailedcases1 ++; + push(@failed_file1, $pinput.": ".$file); + #print "---------------------------\n"; + next; + } + } + + if (!(-e $origresult) ) { + if(!(-e "$notexistsdir")) { + system("mkdir -p $notexistsdir"); + } + print "\nOriginal file $origresult does NOT exists!\n"; + system("mkdir -p $notexistsdir/$file && touch $notexistsdir/$file"); + $countfailedcases2 ++; + push(@failed_file2, $pinput.": result file not exists: ".$origresult); + } else { + if ((!(-e "$outroot/$outresult")) || (-z "$outroot/$outresult")) { + if(!(-e "$notexistsdir")) { + system("mkdir -p $notexistsdir"); + } + + print "\n$outroot/$outresult either empty or not exists!\n"; + system("mkdir -p $notexistsdir/$file && touch $notexistsdir/$file"); + $countfailedcases2 ++; + push(@failed_file2, $pinput.": file empty or not exists: ".$file); + } else { + my $res2 = system("diff $origresult $outroot/$outresult"); + if ($res2 > 0) { + if(!(-e "$diffdir")) { + system("mkdir -p $diffdir"); + } + + print "\n$origresult $outroot/$outresult are different!!!\n"; + print "\ncp $outroot/$outresult $origresult\n"; + system("mkdir -p $diffdir/$diff_file && touch $diffdir/$diff_file"); + $countfailedcases2 ++; + push(@failed_file2, $pinput.": result files diff: ".$origresult); + } else { + push(@successed_file, $file." ".$pinput); + } + } + } + } # if #2 + + } # if #1 + +} + +my $countFailed = $countfailedcases + $countfailedcases1 + $countfailedcases2; +my $countPassed = $count - $countFailed; + +my $reportFile = "$outroot/report.txt"; +open(my $fh, '>', $reportFile) or die "Could not open file '$reportFile' $!"; + +if ($countFailed eq 0) { + print "\n\n=====Scan Result=====\n\n"; + print("\n all $count tests passed\n"); + print("======================================================\n"); + print $fh "all $count tests passed\n"; + close $fh; +} else { + print "\n\n=====Scan Result=====\n\n"; + print "Total Test Cases: $count\n"; + if(scalar(@successed_file) > 0) { + print "\n=========================\npassed $countPassed tests:\n\n"; + #foreach $passed (@successed_file) { + # print $passed."\n"; + #} + #print $fh "$countPassed testcases passed\n"; + } + print "\n=========================\nfailed $countFailed tests:\n\n"; + if(scalar(@failed_file) > 0){ + print("=== failed : $countfailedcases tests - $cmnd\n"); + print $fh "$countfailedcases testcases failed\n"; + + foreach $failed (@failed_file) { + print $failed."\n"; + print $fh $failed."\n"; + } + print "\n"; + } + if(scalar(@failed_file1) > 0){ + print("=== failed : $countfailedcases1 tests - $cmnd1\n"); + print $fh "$countfailedcases1 testcases failed\n"; + + foreach $failed (@failed_file1) { + print $failed."\n"; + print $fh $failed."\n"; + } + print "\n"; + } + if(scalar(@failed_file2) > 0){ + print("=== failed : $countfailedcases2 tests - result\n"); + print $fh "$countfailedcases2 testcases failed\n"; + + foreach $failed (@failed_file2) { + print $failed."\n"; + print $fh $failed."\n"; + } + print "\n"; + } + print "=========================\n"; + close $fh; +} + diff --git a/src/MapleFE/test/openjdk/AbstractStringBuilder-simplified.java.result b/src/MapleFE/test/openjdk/AbstractStringBuilder-simplified.java.result deleted file mode 100644 index e91770236ddee7cd6da5c826ea9abf44bc7271ac..0000000000000000000000000000000000000000 --- a/src/MapleFE/test/openjdk/AbstractStringBuilder-simplified.java.result +++ /dev/null @@ -1,43 +0,0 @@ -Matched 329 tokens. -============= Module =========== -== Sub Tree == -class AbstractStringBuilder - Fields: - value count MAX_ARRAY_SIZE=Integer.MAX_VALUE Sub 8 - Instance Initializer: - Constructors: - constructor AbstractStringBuilder() throws: - constructor AbstractStringBuilder() throws: - Methods: - func length() throws: - func capacity() throws: - func ensureCapacity() throws: - func ensureCapacityInternal() throws: - func newCapacity() throws: - func hugeCapacity() throws: - func trimToSize() throws: - func setLength() throws: - func charAt() throws: - func codePointAt() throws: - func codePointBefore() throws: - func codePointCount() throws: - func offsetByCodePoints() throws: - func getChars() throws: - func setCharAt() throws: - func append() throws: - func append() throws: - func append() throws: - func append() throws: - func append() throws: - func appendNull() throws: - func append() throws: - func append() throws: - func append() throws: - func append() throws: - func append() throws: - func append() throws: - func append() throws: - func append() throws: - LocalClasses: - LocalInterfaces: - diff --git a/src/MapleFE/test/openjdk/Character-1.java.result b/src/MapleFE/test/openjdk/Character-1.java.result deleted file mode 100644 index f13200748e4839d4e7b77a073301d734d18c6f81..0000000000000000000000000000000000000000 --- a/src/MapleFE/test/openjdk/Character-1.java.result +++ /dev/null @@ -1,95 +0,0 @@ -Matched 5 tokens. -Matched 14 tokens. -Matched 21 tokens. -Matched 28 tokens. -Matched 35 tokens. -Matched 42 tokens. -Matched 5259 tokens. -============= Module =========== -== Sub Tree == -package java.lang -== Sub Tree == -import dalvik.annotation.optimization.FastNative -== Sub Tree == -import java.util.Arrays -== Sub Tree == -import java.util.HashMap -== Sub Tree == -import java.util.Locale -== Sub Tree == -import java.util.Map -== Sub Tree == -class Character - Fields: - MIN_RADIX=2 MAX_RADIX=36 MIN_VALUE=0 MAX_VALUE=65535 TYPE=() UNASSIGNED=0 UPPERCASE_LETTER=1 LOWERCASE_LETTER=2 TITLECASE_LETTER=3 MODIFIER_LETTER=4 OTHER_LETTER=5 NON_SPACING_MARK=6 ENCLOSING_MARK=7 COMBINING_SPACING_MARK=8 DECIMAL_DIGIT_NUMBER=9 LETTER_NUMBER=10 OTHER_NUMBER=11 SPACE_SEPARATOR=12 LINE_SEPARATOR=13 PARAGRAPH_SEPARATOR=14 CONTROL=15 FORMAT=16 PRIVATE_USE=18 SURROGATE=19 DASH_PUNCTUATION=20 START_PUNCTUATION=21 END_PUNCTUATION=22 CONNECTOR_PUNCTUATION=23 OTHER_PUNCTUATION=24 MATH_SYMBOL=25 CURRENCY_SYMBOL=26 MODIFIER_SYMBOL=27 OTHER_SYMBOL=28 INITIAL_QUOTE_PUNCTUATION=29 FINAL_QUOTE_PUNCTUATION=30 ERROR=-1 DIRECTIONALITY_UNDEFINED=Sub - 1 DIRECTIONALITY_LEFT_TO_RIGHT=0 DIRECTIONALITY_RIGHT_TO_LEFT=1 DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC=2 DIRECTIONALITY_EUROPEAN_NUMBER=3 DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR=4 DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR=5 DIRECTIONALITY_ARABIC_NUMBER=6 DIRECTIONALITY_COMMON_NUMBER_SEPARATOR=7 DIRECTIONALITY_NONSPACING_MARK=8 DIRECTIONALITY_BOUNDARY_NEUTRAL=9 DIRECTIONALITY_PARAGRAPH_SEPARATOR=10 DIRECTIONALITY_SEGMENT_SEPARATOR=11 DIRECTIONALITY_WHITESPACE=12 DIRECTIONALITY_OTHER_NEUTRALS=13 DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING=14 DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE=15 DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING=16 DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE=17 DIRECTIONALITY_POP_DIRECTIONAL_FORMAT=18 MIN_HIGH_SURROGATE=55296 MAX_HIGH_SURROGATE=56319 MIN_LOW_SURROGATE=56320 MAX_LOW_SURROGATE=57343 MIN_SURROGATE=MIN_HIGH_SURROGATE MAX_SURROGATE=MAX_LOW_SURROGATE MIN_SUPPLEMENTARY_CODE_POINT=65536 MIN_CODE_POINT=0 MAX_CODE_POINT=1114111 DIRECTIONALITY= - Instance Initializer: - Constructors: - Methods: - LocalClasses: - class Subset - Fields: - name - Instance Initializer: - Constructors: - constructor Subset() throws: - cond-branch cond:name EQ null - true branch : - new NullPointerException - false branch : - - this.name Assign name - Methods: - func equals() throws: - return (this EQ obj) - func hashCode() throws: - return hashCode - func toString() throws: - return name - LocalClasses: - LocalInterfaces: - class UnicodeBlock - Fields: - map=new HashMap BASIC_LATIN=new UnicodeBlock LATIN_1_SUPPLEMENT=new UnicodeBlock LATIN_EXTENDED_A=new UnicodeBlock LATIN_EXTENDED_B=new UnicodeBlock IPA_EXTENSIONS=new UnicodeBlock SPACING_MODIFIER_LETTERS=new UnicodeBlock COMBINING_DIACRITICAL_MARKS=new UnicodeBlock GREEK=new UnicodeBlock CYRILLIC=new UnicodeBlock ARMENIAN=new UnicodeBlock HEBREW=new UnicodeBlock ARABIC=new UnicodeBlock DEVANAGARI=new UnicodeBlock BENGALI=new UnicodeBlock GURMUKHI=new UnicodeBlock GUJARATI=new UnicodeBlock ORIYA=new UnicodeBlock TAMIL=new UnicodeBlock TELUGU=new UnicodeBlock KANNADA=new UnicodeBlock MALAYALAM=new UnicodeBlock THAI=new UnicodeBlock LAO=new UnicodeBlock TIBETAN=new UnicodeBlock GEORGIAN=new UnicodeBlock HANGUL_JAMO=new UnicodeBlock LATIN_EXTENDED_ADDITIONAL=new UnicodeBlock GREEK_EXTENDED=new UnicodeBlock GENERAL_PUNCTUATION=new UnicodeBlock SUPERSCRIPTS_AND_SUBSCRIPTS=new UnicodeBlock CURRENCY_SYMBOLS=new UnicodeBlock COMBINING_MARKS_FOR_SYMBOLS=new UnicodeBlock LETTERLIKE_SYMBOLS=new UnicodeBlock NUMBER_FORMS=new UnicodeBlock ARROWS=new UnicodeBlock MATHEMATICAL_OPERATORS=new UnicodeBlock MISCELLANEOUS_TECHNICAL=new UnicodeBlock CONTROL_PICTURES=new UnicodeBlock OPTICAL_CHARACTER_RECOGNITION=new UnicodeBlock ENCLOSED_ALPHANUMERICS=new UnicodeBlock BOX_DRAWING=new UnicodeBlock BLOCK_ELEMENTS=new UnicodeBlock GEOMETRIC_SHAPES=new UnicodeBlock MISCELLANEOUS_SYMBOLS=new UnicodeBlock DINGBATS=new UnicodeBlock CJK_SYMBOLS_AND_PUNCTUATION=new UnicodeBlock HIRAGANA=new UnicodeBlock KATAKANA=new UnicodeBlock BOPOMOFO=new UnicodeBlock HANGUL_COMPATIBILITY_JAMO=new UnicodeBlock KANBUN=new UnicodeBlock ENCLOSED_CJK_LETTERS_AND_MONTHS=new UnicodeBlock CJK_COMPATIBILITY=new UnicodeBlock CJK_UNIFIED_IDEOGRAPHS=new UnicodeBlock HANGUL_SYLLABLES=new UnicodeBlock PRIVATE_USE_AREA=new UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS=new UnicodeBlock ALPHABETIC_PRESENTATION_FORMS=new UnicodeBlock ARABIC_PRESENTATION_FORMS_A=new UnicodeBlock COMBINING_HALF_MARKS=new UnicodeBlock CJK_COMPATIBILITY_FORMS=new UnicodeBlock SMALL_FORM_VARIANTS=new UnicodeBlock ARABIC_PRESENTATION_FORMS_B=new UnicodeBlock HALFWIDTH_AND_FULLWIDTH_FORMS=new UnicodeBlock SPECIALS=new UnicodeBlock SURROGATES_AREA=new UnicodeBlock SYRIAC=new UnicodeBlock THAANA=new UnicodeBlock SINHALA=new UnicodeBlock MYANMAR=new UnicodeBlock ETHIOPIC=new UnicodeBlock CHEROKEE=new UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS=new UnicodeBlock OGHAM=new UnicodeBlock RUNIC=new UnicodeBlock KHMER=new UnicodeBlock MONGOLIAN=new UnicodeBlock BRAILLE_PATTERNS=new UnicodeBlock CJK_RADICALS_SUPPLEMENT=new UnicodeBlock KANGXI_RADICALS=new UnicodeBlock IDEOGRAPHIC_DESCRIPTION_CHARACTERS=new UnicodeBlock BOPOMOFO_EXTENDED=new UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A=new UnicodeBlock YI_SYLLABLES=new UnicodeBlock YI_RADICALS=new UnicodeBlock CYRILLIC_SUPPLEMENTARY=new UnicodeBlock TAGALOG=new UnicodeBlock HANUNOO=new UnicodeBlock BUHID=new UnicodeBlock TAGBANWA=new UnicodeBlock LIMBU=new UnicodeBlock TAI_LE=new UnicodeBlock KHMER_SYMBOLS=new UnicodeBlock PHONETIC_EXTENSIONS=new UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A=new UnicodeBlock SUPPLEMENTAL_ARROWS_A=new UnicodeBlock SUPPLEMENTAL_ARROWS_B=new UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B=new UnicodeBlock SUPPLEMENTAL_MATHEMATICAL_OPERATORS=new UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_ARROWS=new UnicodeBlock KATAKANA_PHONETIC_EXTENSIONS=new UnicodeBlock YIJING_HEXAGRAM_SYMBOLS=new UnicodeBlock VARIATION_SELECTORS=new UnicodeBlock LINEAR_B_SYLLABARY=new UnicodeBlock LINEAR_B_IDEOGRAMS=new UnicodeBlock AEGEAN_NUMBERS=new UnicodeBlock OLD_ITALIC=new UnicodeBlock GOTHIC=new UnicodeBlock UGARITIC=new UnicodeBlock DESERET=new UnicodeBlock SHAVIAN=new UnicodeBlock OSMANYA=new UnicodeBlock CYPRIOT_SYLLABARY=new UnicodeBlock BYZANTINE_MUSICAL_SYMBOLS=new UnicodeBlock MUSICAL_SYMBOLS=new UnicodeBlock TAI_XUAN_JING_SYMBOLS=new UnicodeBlock MATHEMATICAL_ALPHANUMERIC_SYMBOLS=new UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B=new UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT=new UnicodeBlock TAGS=new UnicodeBlock VARIATION_SELECTORS_SUPPLEMENT=new UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_A=new UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_B=new UnicodeBlock HIGH_SURROGATES=new UnicodeBlock HIGH_PRIVATE_USE_SURROGATES=new UnicodeBlock LOW_SURROGATES=new UnicodeBlock ARABIC_SUPPLEMENT=new UnicodeBlock NKO=new UnicodeBlock SAMARITAN=new UnicodeBlock MANDAIC=new UnicodeBlock ETHIOPIC_SUPPLEMENT=new UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED=new UnicodeBlock NEW_TAI_LUE=new UnicodeBlock BUGINESE=new UnicodeBlock TAI_THAM=new UnicodeBlock BALINESE=new UnicodeBlock SUNDANESE=new UnicodeBlock BATAK=new UnicodeBlock LEPCHA=new UnicodeBlock OL_CHIKI=new UnicodeBlock VEDIC_EXTENSIONS=new UnicodeBlock PHONETIC_EXTENSIONS_SUPPLEMENT=new UnicodeBlock COMBINING_DIACRITICAL_MARKS_SUPPLEMENT=new UnicodeBlock GLAGOLITIC=new UnicodeBlock LATIN_EXTENDED_C=new UnicodeBlock COPTIC=new UnicodeBlock GEORGIAN_SUPPLEMENT=new UnicodeBlock TIFINAGH=new UnicodeBlock ETHIOPIC_EXTENDED=new UnicodeBlock CYRILLIC_EXTENDED_A=new UnicodeBlock SUPPLEMENTAL_PUNCTUATION=new UnicodeBlock CJK_STROKES=new UnicodeBlock LISU=new UnicodeBlock VAI=new UnicodeBlock CYRILLIC_EXTENDED_B=new UnicodeBlock BAMUM=new UnicodeBlock MODIFIER_TONE_LETTERS=new UnicodeBlock LATIN_EXTENDED_D=new UnicodeBlock SYLOTI_NAGRI=new UnicodeBlock COMMON_INDIC_NUMBER_FORMS=new UnicodeBlock PHAGS_PA=new UnicodeBlock SAURASHTRA=new UnicodeBlock DEVANAGARI_EXTENDED=new UnicodeBlock KAYAH_LI=new UnicodeBlock REJANG=new UnicodeBlock HANGUL_JAMO_EXTENDED_A=new UnicodeBlock JAVANESE=new UnicodeBlock CHAM=new UnicodeBlock MYANMAR_EXTENDED_A=new UnicodeBlock TAI_VIET=new UnicodeBlock ETHIOPIC_EXTENDED_A=new UnicodeBlock MEETEI_MAYEK=new UnicodeBlock HANGUL_JAMO_EXTENDED_B=new UnicodeBlock VERTICAL_FORMS=new UnicodeBlock ANCIENT_GREEK_NUMBERS=new UnicodeBlock ANCIENT_SYMBOLS=new UnicodeBlock PHAISTOS_DISC=new UnicodeBlock LYCIAN=new UnicodeBlock CARIAN=new UnicodeBlock OLD_PERSIAN=new UnicodeBlock IMPERIAL_ARAMAIC=new UnicodeBlock PHOENICIAN=new UnicodeBlock LYDIAN=new UnicodeBlock KHAROSHTHI=new UnicodeBlock OLD_SOUTH_ARABIAN=new UnicodeBlock AVESTAN=new UnicodeBlock INSCRIPTIONAL_PARTHIAN=new UnicodeBlock INSCRIPTIONAL_PAHLAVI=new UnicodeBlock OLD_TURKIC=new UnicodeBlock RUMI_NUMERAL_SYMBOLS=new UnicodeBlock BRAHMI=new UnicodeBlock KAITHI=new UnicodeBlock CUNEIFORM=new UnicodeBlock CUNEIFORM_NUMBERS_AND_PUNCTUATION=new UnicodeBlock EGYPTIAN_HIEROGLYPHS=new UnicodeBlock BAMUM_SUPPLEMENT=new UnicodeBlock KANA_SUPPLEMENT=new UnicodeBlock ANCIENT_GREEK_MUSICAL_NOTATION=new UnicodeBlock COUNTING_ROD_NUMERALS=new UnicodeBlock MAHJONG_TILES=new UnicodeBlock DOMINO_TILES=new UnicodeBlock PLAYING_CARDS=new UnicodeBlock ENCLOSED_ALPHANUMERIC_SUPPLEMENT=new UnicodeBlock ENCLOSED_IDEOGRAPHIC_SUPPLEMENT=new UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS=new UnicodeBlock EMOTICONS=new UnicodeBlock TRANSPORT_AND_MAP_SYMBOLS=new UnicodeBlock ALCHEMICAL_SYMBOLS=new UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C=new UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D=new UnicodeBlock ARABIC_EXTENDED_A=new UnicodeBlock SUNDANESE_SUPPLEMENT=new UnicodeBlock MEETEI_MAYEK_EXTENSIONS=new UnicodeBlock MEROITIC_HIEROGLYPHS=new UnicodeBlock MEROITIC_CURSIVE=new UnicodeBlock SORA_SOMPENG=new UnicodeBlock CHAKMA=new UnicodeBlock SHARADA=new UnicodeBlock TAKRI=new UnicodeBlock MIAO=new UnicodeBlock ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS=new UnicodeBlock blockStarts=[] blocks= - Instance Initializer: - Constructors: - constructor UnicodeBlock() throws: - constructor UnicodeBlock() throws: - cond-branch cond:isMap - true branch : - map.put(idName,this) - false branch : - - constructor UnicodeBlock() throws: - map.put(alias,this) - constructor UnicodeBlock() throws: - String - alias - aliases - map.put(alias,this) - Methods: - func of() throws: - return of((int)c) - func of() throws: - cond-branch cond:isValidCodePoint(codePoint) - true branch : - new IllegalArgumentException - false branch : - - var:top,bottom,current - bottom Assign 0 - top Assign blockStarts.length - current Assign - while top Sub bottom GT 1 cond-branch cond:codePoint GE - true branch : - bottom Assign current - false branch : - top Assign current - - current Assign (top Add bottom)2 - - return - LocalClasses: - LocalInterfaces: - LocalInterfaces: - diff --git a/src/MapleFE/test/runtests.pl b/src/MapleFE/test/runtests.pl index 7824d713863e65f3ece5fcc3b3d0d2df7e038db4..f1bd481822ca842ced060d3e79754e7b0f63ccf7 100755 --- a/src/MapleFE/test/runtests.pl +++ b/src/MapleFE/test/runtests.pl @@ -52,7 +52,7 @@ my $countsub = 0; system("rm -Rf report.txt $pwd/output $pwd/diff $pwd/notexists"); my $currdir = "$pwd"; -my $outroot = "$currdir/../output/test"; +my $outroot = "$currdir/../output/java/test"; if(!(-e "$outroot")) { system("mkdir -p $outroot"); } @@ -106,37 +106,37 @@ foreach my $dir (@dirname) { #print "here15 dir $dir\n"; #print "here16 src_file $src_file\n"; if ($dir eq "java2mpl") { - $res = system("$pwd/../output/java/java2mpl $outdir/$src_file > $outdir/$result_file"); + $res = system("$pwd/../output/java/java/java2mpl $outdir/$src_file > $outdir/$result_file"); } if ($dir eq "errtest") { - $res = system("$pwd/../output/java/java2mpl $outdir/$src_file > $outdir/$result_file"); + $res = system("$pwd/../output/java/java/java2mpl $outdir/$src_file > $outdir/$result_file"); } if ($dir eq "others") { - $res = system("$pwd/../output/java/java2mpl $outdir/$src_file > $outdir/$result_file"); + $res = system("$pwd/../output/java/java/java2mpl $outdir/$src_file > $outdir/$result_file"); } if ($dir eq "openjdk") { - $res = system("$pwd/../output/java/java2mpl $outdir/$src_file > $outdir/$result_file"); + $res = system("$pwd/../output/java/java/java2mpl $outdir/$src_file > $outdir/$result_file"); } if ($dir eq "syntaxonly") { - $res = system("$pwd/../output/java/java2mpl $outdir/$src_file > $outdir/$result_file"); + $res = system("$pwd/../output/java/java/java2mpl $outdir/$src_file > $outdir/$result_file"); } if ($res > 0) { #print "over here1...\n"; if ($dir eq "java2mpl") { - print "$pwd/../output/java/java2mpl $outdir/$src_file\n"; + print "$pwd/../output/java/java/java2mpl $outdir/$src_file\n"; } if ($dir eq "errtest") { - print "$pwd/../output/java/java2mpl $outdir/$src_file\n"; + print "$pwd/../output/java/java/java2mpl $outdir/$src_file\n"; } if ($dir eq "others") { - print "$pwd/../output/java/java2mpl $outdir/$src_file\n"; + print "$pwd/../output/java/java/java2mpl $outdir/$src_file\n"; } if ($dir eq "openjdk") { - print "$pwd/../output/java/java2mpl $outdir/$src_file\n"; + print "$pwd/../output/java/java/java2mpl $outdir/$src_file\n"; } if ($dir eq "syntaxonly") { - print "$pwd/../output/java/java2mpl $outdir/$src_file\n"; + print "$pwd/../output/java/java/java2mpl $outdir/$src_file\n"; } print " ==$dir===> $file\n"; $countfailedjava ++; diff --git a/src/MapleFE/test/sharedfe/add2.java.result b/src/MapleFE/test/sharedfe/add2.java.result deleted file mode 100644 index 651c3b881b2baed1eb034ff2218c979c64aeba1e..0000000000000000000000000000000000000000 --- a/src/MapleFE/test/sharedfe/add2.java.result +++ /dev/null @@ -1,35 +0,0 @@ -!!! Stack match result: 1 -!!! Stack match result: 1 -!!! Stack match result: 1 - - -============================== function ============================== -func foo (int a, int b) { - LocalVariableDeclarationStatement - "int" - Identifier - "c" - Assignment - LeftHandSide + AssignmentOperator + Expression - Identifier - "c" - '=' - Expression - BinaryExpression - AdditiveExpression - AdditiveExpression + '+' + MultiplicativeExpression - Identifier - "a" - '+' - Identifier - "b" - StatementWithoutTrailingSubstatement - ReturnStatement - "return" + ZEROORONE(Expression) + ';' - "return" - Identifier - "c" -} -====================================================================== - - diff --git a/src/MapleFE/test/sharedfe/add3.java.result b/src/MapleFE/test/sharedfe/add3.java.result deleted file mode 100644 index 7512d871815b308b5b203154fbec1c8109d90954..0000000000000000000000000000000000000000 --- a/src/MapleFE/test/sharedfe/add3.java.result +++ /dev/null @@ -1,40 +0,0 @@ -!!! Stack match result: 1 -!!! Stack match result: 1 -!!! Stack match result: 1 - - -============================== function ============================== -func foo (int a, int b) { - LocalVariableDeclarationStatement - "int" - Identifier - "c" - Assignment - LeftHandSide + AssignmentOperator + Expression - Identifier - "c" - '=' - Expression - BinaryExpression - AdditiveExpression - AdditiveExpression + '+' + MultiplicativeExpression - AdditiveExpression - AdditiveExpression + '+' + MultiplicativeExpression - Identifier - "a" - '+' - Identifier - "b" - '+' - Identifier - "c" - StatementWithoutTrailingSubstatement - ReturnStatement - "return" + ZEROORONE(Expression) + ';' - "return" - Identifier - "c" -} -====================================================================== - - diff --git a/src/MapleFE/test/sharedfe/run b/src/MapleFE/test/sharedfe/run deleted file mode 100755 index 1a06476d61d839c098c166018c83898a812c2939..0000000000000000000000000000000000000000 --- a/src/MapleFE/test/sharedfe/run +++ /dev/null @@ -1,8 +0,0 @@ -#! /bin/bash -DIR=`pwd | sed "s/MapleFE.*/MapleFE/"` -echo DIR=${DIR} -cd $BUILDDIR/autogen - -#test t.java -echo testing ... t.java -./sharedfe ../../test/sharedfe/t.java diff --git a/src/MapleFE/test/sharedfe_runtests.pl b/src/MapleFE/test/sharedfe_runtests.pl deleted file mode 100755 index 9e9a0d8c1c9da801ba72d4e0d5a8a8121736dfa2..0000000000000000000000000000000000000000 --- a/src/MapleFE/test/sharedfe_runtests.pl +++ /dev/null @@ -1,193 +0,0 @@ -#!/usr/bin/perl -w -use Cwd; -use warnings; - -my $pwd = getcwd; - -#print "here1 current pwd $pwd\n"; - -if ((!(defined $ARGV[0])) || ($ARGV[0] ne "sharedfe")) { - print "------------------------------------------------\n"; - print "usage: sharedfe_runtests.pl sharedfe \n"; - print "------------------------------------------------\n"; - exit; -} - -$dirname = "./$ARGV[0]"; - -my $outdir = "$pwd/sharedfe_output"; -my $diffdir = "$pwd/sharedfe_diff"; -my $notexistsdir = "$pwd/sharedfe_notexists"; -if(!(-e "$outdir")) { - system("mkdir -p $outdir"); -} - -my @failed_sharedfe_file; -my @successed_file; - -my $count = 0; -my $countsharedfe = 0; - - -chdir $dirname; -$dirname = "./"; -opendir (DIR, $dirname ) || die "Error in opening dir $dirname\n"; - -#print "here2 dirname $dirname\n"; - -print("\n====================== run tests: $ARGV[0] =====================\n"); - -while( ($srcdir = readdir(DIR))){ - if(-d $srcdir and $srcdir ne ".." and $srcdir ne "output" and $srcdir ne "temp") { - my $predir = getcwd; - chdir $srcdir; - my @javafiles; - @javafiles = <*.java>; - -#print "here3 source directory $srcdir\n"; -#print "here4 predir $predir\n"; - - my @allfiles = (@javafiles); - foreach $fullname (@allfiles) { - $count ++; - (my $file = $fullname) =~ s/\.[^.]+$//; - if(defined $ARGV[1]) { - print "\n$file"; - } else { - print "."; - } - if ($count % 50 == 0) { - print " $count\n"; - } - my $flag = 0; - my $src_file = $fullname; - my $sharedfe_oresult_file = $file.'.java.result'; - my $sharedfe_log_file = $file.'.sharedfe.log'; - my $sharedfe_result_file = $file.'.java.sharedfe.result'; - my $sharedfe_err_file = $file.'.err'; - my $sharedfe_diff_file = $file.'.java.diff'; - - if(!(-e "$outdir")) { - system("mkdir -p $outdir"); - } - -#print "here5 outdir $outdir\n"; -#print "here6 src_file $src_file\n"; - - system("cp $src_file $outdir/$src_file"); - $res = system("cd $BUILDDIR/autogen; ./sharedfe $outdir/$src_file > $outdir/$sharedfe_result_file"); - if ($res > 0) { - print "\n(cd $BUILDDIR/autogen; gdb --args ./sharedfe $outdir/$src_file)\n"; - print " ==sharedfe===> $file\n"; -# $countsharedfe ++; -# push(@failed_sharedfe_file, $file); - $flag ++; - next; - } - -#print "here7 diff src_file $pwd/sharedfe/$sharedfe_oresult_file\n"; -#print "here8 diff sharedfe_result_file $sharedfe_result_file\n"; - - if (!(-e $sharedfe_oresult_file)) { - if(!(-e "$notexistsdir")) { - system("mkdir -p $notexistsdir"); - } - -#print "here9 $sharedfe_oresult_file NOT exists\n"; - print "Original file $sharedfe_oresult_file does NOT exists!\n"; - system("touch $notexistsdir/$sharedfe_oresult_file"); - $countsharedfe ++; - push(@failed_sharedfe_file, $file); - } - else { -#print "here10 sharedfe_result_file $outdir/$sharedfe_result_file\n"; - if ((!(-e "$outdir/$sharedfe_result_file")) || (-z "$outdir/$sharedfe_result_file")) { - if(!(-e "$notexistsdir")) { - system("mkdir -p $notexistsdir"); - } - -#print "here11 $outdir/$sharedfe_result_file NOT exists\n"; - print "$sharedfe_result_file either empty or not exists!\n"; - system("touch $notexistsdir/$sharedfe_result_file"); - $countsharedfe ++; - push(@failed_sharedfe_file, $file); - } else { - $res2 = system("diff $pwd/sharedfe/$sharedfe_oresult_file $outdir/$sharedfe_result_file"); - if ($res2 > 0) { - if(!(-e "$diffdir")) { - system("mkdir -p $diffdir"); - } - -#print "here12 $sharedfe_diff_file Different!!!\n"; - print "$sharedfe_oresult_file $sharedfe_result_file are different!!!\n"; - system("touch $diffdir/$sharedfe_diff_file"); - $countsharedfe ++; - push(@failed_sharedfe_file, $file); - } else { - push(@successed_file, $file); - } - - } - } - -# if($flag eq 0){ -# push(@successed_file, $file); -# } - next; - - if ($flag eq -1) { - push(@successed_file, $file); - system("rm -f $outdir/$src_file"); - system("rm -f $outdir/$sharedfe_log_file"); - system("rm -f $outdir/$sharedfe_oresult_file"); - system("rm -f $outdir/$sharedfe_result_file"); - system("rm -f $outdir/$sharedfe_err_file"); - system("rm -f $diffdir/$sharedfe_diff_file"); - system("rm -f $notexists/$sharedfe_oresult_file"); - system("rm -f $notexists/$sharedfe_result_file"); - next; - } - } - chdir $predir; - } -} - -print " $count\n"; -closedir(DIR); -chdir $pwd; - -my $countFailed = $countsharedfe ; -my $countPassed = $count - $countFailed; - -my $reportFile = 'sharedfe_report.txt'; -open(my $fh, '>', $reportFile) or die "Could not open file '$reportFile' $!"; -print $fh "$ARGV[0] report: \n"; - -if ($countFailed eq 0) { - print("\n all $count tests passed\n"); - print("======================================================\n"); - print $fh "all $count tests passed\n"; - close $fh; -} else { - print "\n\n=====Scan Result=====\n\n"; - print "Total Test Cases: $count\n"; - if(scalar(@successed_file) > 0) { - print "\n=========================\npassed $countPassed tests:\n\n"; - foreach $passed (@successed_file) { - print $passed."\n"; - } - print $fh "$countPassed testcases passed\n"; - } - print "\n=========================\nfailed $countFailed tests:\n\n"; - if(scalar(@failed_sharedfe_file) > 0){ - print("=== failed sharedfe: $countsharedfe tests\n"); - print $fh "$countsharedfe testcases failed\n"; - - foreach $failed (@failed_sharedfe_file) { - print $failed."\n"; - } - print "\n"; - } - print "=========================\n"; - close $fh; -} diff --git a/src/MapleFE/test/typescript/generate-result.sh b/src/MapleFE/test/typescript/generate-result.sh new file mode 100755 index 0000000000000000000000000000000000000000..5e3e9c5354afa6bc5edbf0428348ba74db0f96c9 --- /dev/null +++ b/src/MapleFE/test/typescript/generate-result.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +FILES=`find . -name "*.ts"` +for f in $FILES +do + echo "Generating result for $f ..." + $MAPLEFE_ROOT/output/typescript/bin/ts2ast $f > $f.result +done diff --git a/src/MapleFE/test/typescript/ms_tests/README b/src/MapleFE/test/typescript/ms_tests/README new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/MapleFE/test/typescript/ms_tests/checkInterfaceBases.ts.result b/src/MapleFE/test/typescript/ms_tests/checkInterfaceBases.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..06e1681196983bfca57f375df768dced69a0d430 --- /dev/null +++ b/src/MapleFE/test/typescript/ms_tests/checkInterfaceBases.ts.result @@ -0,0 +1,13 @@ +Matched 16 tokens. +Matched 24 tokens. +Matched 32 tokens. +Matched 40 tokens. +============= Module =========== +== Sub Tree == +ts_interface: JQueryEventObjectTest {data;which;metaKey } +== Sub Tree == +trip-slash reference path = "jquery.d.ts" +== Sub Tree == +ts_interface: SecondEvent {data } +== Sub Tree == +ts_interface: Third { } diff --git a/src/MapleFE/test/typescript/ms_tests/getsetReturnTypes.ts.result b/src/MapleFE/test/typescript/ms_tests/getsetReturnTypes.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e0ca09b6180bf1a841fd45c57c16dc3775ae03e1 --- /dev/null +++ b/src/MapleFE/test/typescript/ms_tests/getsetReturnTypes.ts.result @@ -0,0 +1,14 @@ +Matched 22 tokens. +Matched 32 tokens. +Matched 44 tokens. +============= Module =========== +== Sub Tree == +func makePoint(x) throws: + return {x:get x() throws: + return x +} + +== Sub Tree == +js_var Decl: x=makePoint(2).x +== Sub Tree == +js_var Decl: y=makePoint(2).x diff --git a/src/MapleFE/test/typescript/ms_tests/library_ObjectPrototypeProperties.ts.result b/src/MapleFE/test/typescript/ms_tests/library_ObjectPrototypeProperties.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1cf0e482cb7d522e06cb8c2022e407bc2f85119f --- /dev/null +++ b/src/MapleFE/test/typescript/ms_tests/library_ObjectPrototypeProperties.ts.result @@ -0,0 +1,22 @@ +Matched 6 tokens. +Matched 14 tokens. +Matched 22 tokens. +Matched 30 tokens. +Matched 39 tokens. +Matched 48 tokens. +Matched 57 tokens. +============= Module =========== +== Sub Tree == +Object.prototype.constructor +== Sub Tree == +Object.prototype.toString() +== Sub Tree == +Object.prototype.toLocaleString() +== Sub Tree == +Object.prototype.valueOf() +== Sub Tree == +Object.prototype.hasOwnProperty("string") +== Sub Tree == +Object.prototype.isPrototypeOf(Object) +== Sub Tree == +Object.prototype.propertyIsEnumerable("string") diff --git a/src/MapleFE/test/typescript/ms_tests/reExportGlobalDeclaration3.ts.result b/src/MapleFE/test/typescript/ms_tests/reExportGlobalDeclaration3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c0e6053f15e6add6d4b1949ee1355d75bbe1c288 --- /dev/null +++ b/src/MapleFE/test/typescript/ms_tests/reExportGlobalDeclaration3.ts.result @@ -0,0 +1,23 @@ +Matched 11 tokens. +Matched 22 tokens. +Matched 31 tokens. +Matched 40 tokens. +Matched 47 tokens. +Matched 54 tokens. +============= Module =========== +== Sub Tree == +declare namespace NS1 + export {js_var Decl: foo} + +== Sub Tree == +declare namespace NS2 + export {js_var Decl: foo} + +== Sub Tree == +export {NS1,NS1 as NNS1} +== Sub Tree == +export {NS2,NS2 as NNS2} +== Sub Tree == +export {NS1 as NNNS1} +== Sub Tree == +export {NS2 as NNNS2} diff --git a/src/MapleFE/test/typescript/ts2cxx-test.sh b/src/MapleFE/test/typescript/ts2cxx-test.sh new file mode 100755 index 0000000000000000000000000000000000000000..33897fa18fd607b8c978d4a89637679d88b8f66d --- /dev/null +++ b/src/MapleFE/test/typescript/ts2cxx-test.sh @@ -0,0 +1,115 @@ +#!/bin/bash +# Usage: cd MapleFE/test/typescript/unit_tests; ../ts2cpp-test.sh *.ts +[ $# -lt 1 ] && exec $0 $(git ls-files "*.ts") +SUCC= +MPLFEPATH=$(cd $(dirname $0)/../../; pwd) +TSOUT=$MPLFEPATH/output/typescript +RTSRC=$MPLFEPATH/ast2cpp/runtime/src +RTINC=$MPLFEPATH/ast2cpp/runtime/include +ASTINC=$MPLFEPATH/astopt/include +TS2AST=$TSOUT/bin/ts2ast +AST2CPP=$TSOUT/bin/ast2cpp +TSCSH=$(dirname $0)/tsc.sh + +# Acquire/release a lock +typeset -i LockVar +LockVar=1 +function AcquireLock { + while [[ $LockVar -ne 0 ]] || sleep 0.1; do + ln -s Lock_$2 $1-lock-$((LockVar=(LockVar+1)%$3)) > /dev/null 2>&1 && break + done +} +function ReleaseLock { + rm -f $1-lock-$LockVar +} +trap "{ pstree -p $$ | tr ')' '\n' | sed 's/.*(//' | xargs kill -9 2> /dev/null; rm -f ts2cpp-lock-*; }" SIGINT SIGQUIT SIGKILL SIGTERM +rm -rf ts2cpp-lock-* *-ts2cpp.out ts2cpp.summary.out ts2cpp.failures*.out +cnt=0 +if [ $# -gt 1 ]; then + list1=$(grep -L -e "^ *import " -e "^ *export .* from " "$@") + list2=$(grep -l -e "^ *import " -e "^ *export .* from " "$@") +else + list1="$@" list2= +fi +single="no" +for list in "$list1" "$list2"; do +for f in $list; do + echo $((++cnt)): $f + t=$(basename $f .ts) + [ -f $t.ts ] && f=$t.ts + AcquireLock ts2cpp for_$t $(nproc) + (set -x + while true; do + $TS2AST $f || { echo "(ts2ast)$f" >> ts2cpp.failures.out; break; } + dep=$(sed 's/[ ,:|]\(import(\)/\n\1/g' "$f" | grep -E "^ *[ei][xm]port.*( from |require|\( *['\"])" | \ + sed -r "s/^ *[ei][xm]port.*( from |require *\(|\() *['\"]([^'\"]*).*/\2.cpp/" | sort -u) + for cpp in $dep; do + ts=$(sed 's/\.cpp/.ts/' <<< "$cpp") + $TS2AST $ts + dep="$dep "$(sed 's/[ ,:|]\(import(\)/\n\1/g' "$ts" | grep -E "^ *[ei][xm]port.*( from |require|\( *['\"])" | \ + sed -r "s/^ *[ei][xm]port.*( from |require *\(|\() *['\"]([^'\"]*).*/\2.cpp/" | sort -u) + done + dep=$(echo $dep | xargs -n1 | sort -u) + $AST2CPP $f.ast || { echo "(ast2cpp)$f" >> ts2cpp.failures.out; break; } + g++ -std=c++17 -g -I$RTINC -I$ASTINC $t.cpp $RTSRC/*.cpp $dep -o $t.out || { echo "(g++)$f" >> ts2cpp.failures2.out; break; } + ./$t.out 2>&1 > $f-run.out || { echo "(run)$f" >> ts2cpp.failures2.out; break; } + $TSCSH $f + diff $f-run.out $f-nodejs.out + if [ $? -ne 0 ]; then + sed -e 's/^[A-Za-z]* {/{/' $f-run.out | diff - $f-nodejs.out + if [ $? -ne 0 ]; then + sed -e 's/^[A-Za-z]* {/{/' -e 's/} [A-Za-z]* {/} {/' $f-run.out | diff - $f-nodejs.out + if [ $? -ne 0 ]; then + echo "(result)$f" >> ts2cpp.failures3.out + break + fi + fi + fi + echo $t >> ts2cpp.summary.out + break + done + ReleaseLock ts2cpp + ) >& $f-ts2cpp.out & + if [ $single = "yes" ]; then + wait + fi +done 2>&1 +wait +single="yes" +done +num=$(echo $list1 $list2 | wc -w) +total=$(git ls-files "*.ts" | wc -w) +log=cxx-tmp.log +[ $num -eq $total ] && log=cxx.log +if [ -f ts2cpp.summary.out ]; then + echo -e "\nDate: $(date)\nTest cases passed:" | tee -a $log + sort ts2cpp.summary.out | xargs -n1 | nl | tee -a $log +fi +if [ -f ts2cpp.failures3.out ]; then + echo -e "\nTest cases failed due to unexpected results:" | tee -a $log + sort ts2cpp.failures3.out | xargs -n1 | nl | tee -a $log + if [ $num -eq 1 ]; then + echo -e "\ndiff $t.ts-nodejs.out $t.ts-run.out" + diff $t.ts-nodejs.out $t.ts-run.out + fi +fi +if [ -f ts2cpp.failures2.out ]; then + echo -e "\nTest cases failed due to g++ or run:" | tee -a $log + sort ts2cpp.failures2.out | xargs -n1 | nl | tee -a $log + if [ $num -eq 1 ]; then + echo -e "\nCommand line to compile $t.cpp:" + grep -- "-std=c++17" $t.ts-ts2cpp.out | sed 's/^+/ /' + fi +fi +if [ -f ts2cpp.failures.out ]; then + echo -e "\nTest cases failed due to ts2ast or ast2cpp:" | tee -a $log + sort ts2cpp.failures.out | xargs -n1 | nl | tee -a $log +fi +if [ $num -eq $total ]; then + grep -c ": error:" *.ts-ts2cpp.out | sort -nrt: -k2 | grep -v :0 | sed 's/-ts2cpp.out//' > cxx-error.log + lines=$(grep -n -e "Test cases passed:" -e "Test cases failed due to g++ or run:" $log | \ + grep -A1 ":Test cases passed:" | tail -2 | cut -d: -f1) + sed -n $(echo $lines | sed 's/[^0-9]/,/')p $log | grep "[0-9]" | expand | cut -c9- > cxx-succ.log +else + echo Saved testing results to file $log +fi diff --git a/src/MapleFE/test/typescript/tsc.sh b/src/MapleFE/test/typescript/tsc.sh new file mode 100755 index 0000000000000000000000000000000000000000..1b2579cc6aa8169abb928c804af71e7c6cd88ce3 --- /dev/null +++ b/src/MapleFE/test/typescript/tsc.sh @@ -0,0 +1,63 @@ +#!/bin/bash +# Acquire/release a lock +typeset -i LockVar +LockVar=1 +function AcquireLock { + while [[ $LockVar -ne 0 ]] || sleep 0.1; do + ln -s Lock_$2 $1-lock-$((LockVar=(LockVar+1)%$3)) > /dev/null 2>&1 && break + done +} +function ReleaseLock { + rm -f $1-lock-$LockVar +} +rm -rf -- tsc-lock-* *-tsc.out tsc.summary.out tsc.failures*.out + +OPT="--target es2017 \ + --lib es2015,es2017,dom \ + --module commonjs \ + --downlevelIteration \ + --esModuleInterop \ + --experimentalDecorators" +# --sourceMap \ +# --isolatedModules \ +while [ "x${1:0:1}" = "x-" ]; do + OPT="$OPT $1" + shift +done +i=0 +for f; do + echo $((++i)). $f + js=$(dirname $f)/$(basename $f .ts).js + rm -f $js + AcquireLock tsc for_$t $(nproc) + (bash -x -c "tsc --strict $OPT $f" + if [ $? -ne 0 ]; then + echo "(--strict)"$f >> tsc.failures.out + bash -x -c "tsc $OPT $f" || echo "(non-strict)"$f >> tsc.failures.out + fi + if [ -f "$js" ]; then + bash -x -c "node $js" + [ $? -ne 0 ] && echo "(nodejs)"$f >> tsc.failures.out + fi 2>&1 > $f-nodejs.out + ReleaseLock tsc + ) >& $f-tsc.out & +done +wait +rc=0 +if [ -f tsc.failures.out ]; then + echo -e "\nTest cases failed with tsc strict mode enabled:" + sort tsc.failures.out | grep "(--strict)" | xargs -n1 | nl + grep -q -e "(non-strict)" -e "(nodejs)" tsc.failures.out + if [ $? -eq 0 ]; then + echo -e "\nTest cases failed with non-strict mode or nodejs:" + sort tsc.failures.out | grep -e "(non-strict)" -e "(nodejs)" | xargs -n1 | nl + rc=2 + else + echo -e "\nAll passed with tsc non-strict mode." + rc=1 + fi +elif [ $# -gt 0 ]; then + echo All passed +fi +[ $i -eq 1 -a -f $f-tsc.out ] && cat $f-tsc.out $f-nodejs.out +exit $rc diff --git a/src/MapleFE/test/typescript/unit_tests/App-copy.ts b/src/MapleFE/test/typescript/unit_tests/App-copy.ts new file mode 100644 index 0000000000000000000000000000000000000000..da2bce06f59f6ae0d2be5ec42666819bf150768d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App-copy.ts @@ -0,0 +1,4 @@ +import myX, * as M from "./M-copy"; +console.log(myX, M.getx()); +M.setx(3); +console.log(myX, M.getx()); diff --git a/src/MapleFE/test/typescript/unit_tests/App-copy.ts.result b/src/MapleFE/test/typescript/unit_tests/App-copy.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..29130fe6ddec7df47adeb50b2666ef352d4ba485 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App-copy.ts.result @@ -0,0 +1,13 @@ +Matched 9 tokens. +Matched 22 tokens. +Matched 29 tokens. +Matched 42 tokens. +============= Module =========== +== Sub Tree == +import { default as myX, * as M} "./M-copy" +== Sub Tree == +console.log(myX,M.getx()) +== Sub Tree == +M.setx(3) +== Sub Tree == +console.log(myX,M.getx()) diff --git a/src/MapleFE/test/typescript/unit_tests/App-import.ts b/src/MapleFE/test/typescript/unit_tests/App-import.ts new file mode 100644 index 0000000000000000000000000000000000000000..f00203e409f8a420d35178f31005ed05f2c63119 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App-import.ts @@ -0,0 +1,5 @@ +import myX, * as M from "./M"; +import getx = M.getx; +console.log(myX, getx()); +M.setx(3); +console.log(myX, getx()); diff --git a/src/MapleFE/test/typescript/unit_tests/App-import.ts.result b/src/MapleFE/test/typescript/unit_tests/App-import.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..da9ea239e3f9c3568bec0a928d882cc1ba3f292a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App-import.ts.result @@ -0,0 +1,16 @@ +Matched 9 tokens. +Matched 16 tokens. +Matched 27 tokens. +Matched 34 tokens. +Matched 45 tokens. +============= Module =========== +== Sub Tree == +import { default as myX, * as M} "./M" +== Sub Tree == +import {M.getx as getx} +== Sub Tree == +console.log(myX,getx()) +== Sub Tree == +M.setx(3) +== Sub Tree == +console.log(myX,getx()) diff --git a/src/MapleFE/test/typescript/unit_tests/App-re-export.ts b/src/MapleFE/test/typescript/unit_tests/App-re-export.ts new file mode 100644 index 0000000000000000000000000000000000000000..666b1b1a9253d51e8a1dc0c014afecc1159e701a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App-re-export.ts @@ -0,0 +1,4 @@ +import myX, * as M from "./re-export"; +console.log(myX, M.getx()); +M.setx(3); +console.log(myX, M.getx()); diff --git a/src/MapleFE/test/typescript/unit_tests/App-re-export.ts.result b/src/MapleFE/test/typescript/unit_tests/App-re-export.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5c98f56a103bf8886bc56404fa09eada9d8eba5c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App-re-export.ts.result @@ -0,0 +1,13 @@ +Matched 9 tokens. +Matched 22 tokens. +Matched 29 tokens. +Matched 42 tokens. +============= Module =========== +== Sub Tree == +import { default as myX, * as M} "./re-export" +== Sub Tree == +console.log(myX,M.getx()) +== Sub Tree == +M.setx(3) +== Sub Tree == +console.log(myX,M.getx()) diff --git a/src/MapleFE/test/typescript/unit_tests/App-re-export2.ts b/src/MapleFE/test/typescript/unit_tests/App-re-export2.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6dbb897f9b7df1aa5acf345eea33c946ebdc796 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App-re-export2.ts @@ -0,0 +1,7 @@ +import myX, * as M from "./re-export2"; +import {Y as y} from "./re-export2"; +console.log(y); +console.log(myX, M.getx()); +M.setx(3); +console.log(myX, M.getx()); +console.log(y); diff --git a/src/MapleFE/test/typescript/unit_tests/App-re-export2.ts.result b/src/MapleFE/test/typescript/unit_tests/App-re-export2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..fd84b06b35dafc531d8f2f20cb9f4ff01840c9ff --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App-re-export2.ts.result @@ -0,0 +1,22 @@ +Matched 9 tokens. +Matched 18 tokens. +Matched 25 tokens. +Matched 38 tokens. +Matched 45 tokens. +Matched 58 tokens. +Matched 65 tokens. +============= Module =========== +== Sub Tree == +import { default as myX, * as M} "./re-export2" +== Sub Tree == +import {Y as y} "./re-export2" +== Sub Tree == +console.log(y) +== Sub Tree == +console.log(myX,M.getx()) +== Sub Tree == +M.setx(3) +== Sub Tree == +console.log(myX,M.getx()) +== Sub Tree == +console.log(y) diff --git a/src/MapleFE/test/typescript/unit_tests/App.ts b/src/MapleFE/test/typescript/unit_tests/App.ts new file mode 100644 index 0000000000000000000000000000000000000000..cc80a709ec968705cc976b4fd1cbd89c006638ab --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App.ts @@ -0,0 +1,4 @@ +import myX, * as M from "./M"; +console.log(myX, M.getx()); +M.setx(3); +console.log(myX, M.getx()); diff --git a/src/MapleFE/test/typescript/unit_tests/App.ts.result b/src/MapleFE/test/typescript/unit_tests/App.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..dd6dc8f514ff7e2f7a5196cc3325fbfa8cb8ad52 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App.ts.result @@ -0,0 +1,13 @@ +Matched 9 tokens. +Matched 22 tokens. +Matched 29 tokens. +Matched 42 tokens. +============= Module =========== +== Sub Tree == +import { default as myX, * as M} "./M" +== Sub Tree == +console.log(myX,M.getx()) +== Sub Tree == +M.setx(3) +== Sub Tree == +console.log(myX,M.getx()) diff --git a/src/MapleFE/test/typescript/unit_tests/App2.ts b/src/MapleFE/test/typescript/unit_tests/App2.ts new file mode 100644 index 0000000000000000000000000000000000000000..217529e23913ed6c6a6009119b7d42e8f2412584 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App2.ts @@ -0,0 +1,6 @@ +import myX from "./M"; +import * as M from "./M"; +import { X } from "./export-default-as"; +console.log(myX, M.getx(), X); +M.setx(3); +console.log(myX, M.getx(), X); diff --git a/src/MapleFE/test/typescript/unit_tests/App2.ts.result b/src/MapleFE/test/typescript/unit_tests/App2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..249a408c8184c473415bb95033b63cd89e62eb49 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App2.ts.result @@ -0,0 +1,19 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 19 tokens. +Matched 34 tokens. +Matched 41 tokens. +Matched 56 tokens. +============= Module =========== +== Sub Tree == +import { default as myX} "./M" +== Sub Tree == +import { * as M} "./M" +== Sub Tree == +import {X} "./export-default-as" +== Sub Tree == +console.log(myX,M.getx(),X) +== Sub Tree == +M.setx(3) +== Sub Tree == +console.log(myX,M.getx(),X) diff --git a/src/MapleFE/test/typescript/unit_tests/App3.ts b/src/MapleFE/test/typescript/unit_tests/App3.ts new file mode 100644 index 0000000000000000000000000000000000000000..48559a7bebd0451f08d473e81e46fefed7759d34 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App3.ts @@ -0,0 +1,6 @@ +import myX from "./export-default-as2"; +import * as M from "./M"; +import { X } from "./export-default-as"; +console.log(myX, M.getx(), X); +M.setx(3); +console.log(myX, M.getx(), X); diff --git a/src/MapleFE/test/typescript/unit_tests/App3.ts.result b/src/MapleFE/test/typescript/unit_tests/App3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..34009cc2f9199603cd7e9429abc9032f194971e9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App3.ts.result @@ -0,0 +1,19 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 19 tokens. +Matched 34 tokens. +Matched 41 tokens. +Matched 56 tokens. +============= Module =========== +== Sub Tree == +import { default as myX} "./export-default-as2" +== Sub Tree == +import { * as M} "./M" +== Sub Tree == +import {X} "./export-default-as" +== Sub Tree == +console.log(myX,M.getx(),X) +== Sub Tree == +M.setx(3) +== Sub Tree == +console.log(myX,M.getx(),X) diff --git a/src/MapleFE/test/typescript/unit_tests/App4.ts b/src/MapleFE/test/typescript/unit_tests/App4.ts new file mode 100644 index 0000000000000000000000000000000000000000..6de0137d3fede63ed01fd51f5dc0b6e318c66b7c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App4.ts @@ -0,0 +1,4 @@ +import myX, { MM as M } from "./re-export4"; +console.log(myX, M.getx()); +M.setx(3); +console.log(myX, M.getx()); diff --git a/src/MapleFE/test/typescript/unit_tests/App4.ts.result b/src/MapleFE/test/typescript/unit_tests/App4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0de69f258027c851b846ec14eaea36156dfc37fd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App4.ts.result @@ -0,0 +1,13 @@ +Matched 11 tokens. +Matched 24 tokens. +Matched 31 tokens. +Matched 44 tokens. +============= Module =========== +== Sub Tree == +import { default as myX,MM as M} "./re-export4" +== Sub Tree == +console.log(myX,M.getx()) +== Sub Tree == +M.setx(3) +== Sub Tree == +console.log(myX,M.getx()) diff --git a/src/MapleFE/test/typescript/unit_tests/App5.ts b/src/MapleFE/test/typescript/unit_tests/App5.ts new file mode 100644 index 0000000000000000000000000000000000000000..9dacf6d73f2d8479e0ef0b6a01a48ce08e7d2b92 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App5.ts @@ -0,0 +1,2 @@ +import { getx } from "./export-import2"; +console.log(getx()); diff --git a/src/MapleFE/test/typescript/unit_tests/App5.ts.result b/src/MapleFE/test/typescript/unit_tests/App5.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6fbc351181248dd3fa552c65e36ad67a2c53d059 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/App5.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 16 tokens. +============= Module =========== +== Sub Tree == +import {getx} "./export-import2" +== Sub Tree == +console.log(getx()) diff --git a/src/MapleFE/test/typescript/unit_tests/M-copy.ts b/src/MapleFE/test/typescript/unit_tests/M-copy.ts new file mode 100644 index 0000000000000000000000000000000000000000..252e1655aa8a80a9e04449a87bbb4b55b67b83f2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/M-copy.ts @@ -0,0 +1,10 @@ +var x: number = 2; +//export { x as default }; // ref +export default x; // copy +x = 12; +export function getx(): number { + return x; +} +export function setx(v: number): void { + x = v; +} diff --git a/src/MapleFE/test/typescript/unit_tests/M-copy.ts.result b/src/MapleFE/test/typescript/unit_tests/M-copy.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..73f2fb1c3534788e3ecc2c278ec0a14a184ea86b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/M-copy.ts.result @@ -0,0 +1,20 @@ +Matched 7 tokens. +Matched 11 tokens. +Matched 15 tokens. +Matched 27 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=2 +== Sub Tree == +export { default as x} +== Sub Tree == +x Assign 12 +== Sub Tree == +export {func getx() throws: + return x +} +== Sub Tree == +export {func setx(v) throws: + x Assign v +} diff --git a/src/MapleFE/test/typescript/unit_tests/M.ts b/src/MapleFE/test/typescript/unit_tests/M.ts new file mode 100644 index 0000000000000000000000000000000000000000..f49b68cf52af8d098313ad690b3cc54097ce1892 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/M.ts @@ -0,0 +1,9 @@ +var x: number = 2; +export { x as default }; // ref +//export default x; // copy +export function getx(): number { + return x; +} +export function setx(v: number): void { + x = v; +} diff --git a/src/MapleFE/test/typescript/unit_tests/M.ts.result b/src/MapleFE/test/typescript/unit_tests/M.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..84952de63aa56f4a000dbe0fa74eb6d3a75dab10 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/M.ts.result @@ -0,0 +1,17 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 26 tokens. +Matched 42 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=2 +== Sub Tree == +export {x as default} +== Sub Tree == +export {func getx() throws: + return x +} +== Sub Tree == +export {func setx(v) throws: + x Assign v +} diff --git a/src/MapleFE/test/typescript/unit_tests/Promise-catch.ts b/src/MapleFE/test/typescript/unit_tests/Promise-catch.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2edeed401c7e645fe6ce65e583c98fa143eed49 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/Promise-catch.ts @@ -0,0 +1,11 @@ +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch +// cocos: director.ts, root.ts +// tsc --lib es2015,dom Promise-catch.ts +const promise1 = new Promise((resolve, reject) => { + throw "something happened"; +}); + +promise1.catch((error) => { + console.log(error); +}); diff --git a/src/MapleFE/test/typescript/unit_tests/Promise-catch.ts.result b/src/MapleFE/test/typescript/unit_tests/Promise-catch.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..d82e45128883669847aed9b2698cc4e230e710a0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/Promise-catch.ts.result @@ -0,0 +1,10 @@ +Matched 19 tokens. +Matched 38 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: promise1=new Promise((resolve,reject) -> throw "something happened" + +) +== Sub Tree == +promise1.catch((error) -> console.log(error) +) diff --git a/src/MapleFE/test/typescript/unit_tests/abstract-class.ts b/src/MapleFE/test/typescript/unit_tests/abstract-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..90eb9824872b87bbcfcf3c315081b644267b9bc7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/abstract-class.ts @@ -0,0 +1,8 @@ +abstract class Foo { + public f1: number = 0; + private f2: number = 0; + constructor(a: number, b: number) { + this.f1 = a; + this.f2 = b; + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/abstract-class.ts.result b/src/MapleFE/test/typescript/unit_tests/abstract-class.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..888597a8042fcead4b747ddfda25adef9c8c8a3f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/abstract-class.ts.result @@ -0,0 +1,15 @@ +Matched 43 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + f1=0 f2=0 + Instance Initializer: + Constructors: + constructor (a,b) throws: + this.f1 Assign a + this.f2 Assign b + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/abstract-class2.ts b/src/MapleFE/test/typescript/unit_tests/abstract-class2.ts new file mode 100644 index 0000000000000000000000000000000000000000..993d6e5eaa91ec5c86b8bdc383caeaee0eb5ec53 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/abstract-class2.ts @@ -0,0 +1,3 @@ +abstract class Klass { + public abstract func(): void; +} diff --git a/src/MapleFE/test/typescript/unit_tests/abstract-class2.ts.result b/src/MapleFE/test/typescript/unit_tests/abstract-class2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c2dbc106515111dc84188ca97656c49f6e4b91bd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/abstract-class2.ts.result @@ -0,0 +1,13 @@ +Matched 13 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + func func() throws: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/abstract-new.ts b/src/MapleFE/test/typescript/unit_tests/abstract-new.ts new file mode 100644 index 0000000000000000000000000000000000000000..bd1ffeb4a8e0f587f8db27ec313ff848b2651539 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/abstract-new.ts @@ -0,0 +1,2 @@ +type Type any> = T extends abstract new (...args: infer P) => any ? P : never; + diff --git a/src/MapleFE/test/typescript/unit_tests/abstract-new.ts.result b/src/MapleFE/test/typescript/unit_tests/abstract-new.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e3e36bcc0bd887c67b0e743e6f9b6cdae543ea9c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/abstract-new.ts.result @@ -0,0 +1,4 @@ +Matched 35 tokens. +============= Module =========== +== Sub Tree == + type Type = T extends new (args) -> ? P : never diff --git a/src/MapleFE/test/typescript/unit_tests/add.ts b/src/MapleFE/test/typescript/unit_tests/add.ts new file mode 100644 index 0000000000000000000000000000000000000000..583789b9c703e11801e5e96f32be11aa57f887cc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/add.ts @@ -0,0 +1,4 @@ +var a: number = 1; +var b: number = 1; +var c: number; +c = a + b; diff --git a/src/MapleFE/test/typescript/unit_tests/add.ts.result b/src/MapleFE/test/typescript/unit_tests/add.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..028434f5242c519543c3021c12c790eaa8ea4cce --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/add.ts.result @@ -0,0 +1,13 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 19 tokens. +Matched 25 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: a=1 +== Sub Tree == +js_var Decl: b=1 +== Sub Tree == +js_var Decl: c +== Sub Tree == +c Assign a Add b diff --git a/src/MapleFE/test/typescript/unit_tests/array-default.ts b/src/MapleFE/test/typescript/unit_tests/array-default.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0b75ed259ae31964b932df4d5acc402ac21bdf5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-default.ts @@ -0,0 +1,5 @@ +// the type of arr element is never by default +const arr: [] = []; +(arr as any[]).push([]); +arr.push.apply(arr, {} as any); +console.log(arr); diff --git a/src/MapleFE/test/typescript/unit_tests/array-default.ts.result b/src/MapleFE/test/typescript/unit_tests/array-default.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0b7026b4dd2e7ebaf64824e9cab98a44bcfbc052 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-default.ts.result @@ -0,0 +1,13 @@ +Matched 9 tokens. +Matched 23 tokens. +Matched 37 tokens. +Matched 44 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: arr=[] +== Sub Tree == +arr.push([]) +== Sub Tree == +arr.push.apply(arr, {}) +== Sub Tree == +console.log(arr) diff --git a/src/MapleFE/test/typescript/unit_tests/array-elem-as-type.ts b/src/MapleFE/test/typescript/unit_tests/array-elem-as-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..f73d2cbfcec10db79c64055237a4099cf9931e71 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-elem-as-type.ts @@ -0,0 +1,10 @@ +var arr: number[] = [7, 4, 5, 9, 2, 8, 1, 6, 3]; +var sum: number = 0; +var i; +var len; +(i = 0), (len = arr.length); +for (; i < len; ++i) { + var x = arr[i] as number; + sum += x; +} +console.log(sum); diff --git a/src/MapleFE/test/typescript/unit_tests/array-elem-as-type.ts.result b/src/MapleFE/test/typescript/unit_tests/array-elem-as-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f173498338d57b001c80dd07f7ad73761857096d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-elem-as-type.ts.result @@ -0,0 +1,27 @@ +Matched 27 tokens. +Matched 34 tokens. +Matched 37 tokens. +Matched 40 tokens. +Matched 54 tokens. +Matched 80 tokens. +Matched 87 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[7,4,5,9,2,8,1,6,3] +== Sub Tree == +js_var Decl: sum=0 +== Sub Tree == +js_var Decl: i +== Sub Tree == +js_var Decl: len +== Sub Tree == +i Assign 0 +== Sub Tree == +len Assign arr.length +== Sub Tree == +for ( ) + js_var Decl: x=arr[i] + sum AddAssign x + +== Sub Tree == +console.log(sum) diff --git a/src/MapleFE/test/typescript/unit_tests/array-elem-casting.ts b/src/MapleFE/test/typescript/unit_tests/array-elem-casting.ts new file mode 100644 index 0000000000000000000000000000000000000000..4b31f0e78b75023a77b181744e1f62ba023e066a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-elem-casting.ts @@ -0,0 +1,21 @@ +class Base { + str: string; + constructor(s: string) { this.str = s; } +} + +class Derived extends Base { + num: number; + constructor(s: string, n: number) { super(s); this.num = n; } +} + +function func(...args: Base[]): Derived { + if (args.length === 1 && args[0] instanceof Derived) { + return args[0]; + } + return { str: "Unkown", num: 0 }; +} + +var b: Base = new Base("Base"); +console.log(func(b)); +var d: Derived = new Derived("Derived", 123); +console.log(func(d)); diff --git a/src/MapleFE/test/typescript/unit_tests/array-elem-casting.ts.result b/src/MapleFE/test/typescript/unit_tests/array-elem-casting.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..59337de3cda4b0b4191755eb8c7aaba2e86ea13e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-elem-casting.ts.result @@ -0,0 +1,50 @@ +Matched 22 tokens. +Matched 55 tokens. +Matched 106 tokens. +Matched 117 tokens. +Matched 127 tokens. +Matched 140 tokens. +Matched 150 tokens. +============= Module =========== +== Sub Tree == +class Base + Fields: + str + Instance Initializer: + Constructors: + constructor (s) throws: + this.str Assign s + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Derived + Fields: + num + Instance Initializer: + Constructors: + constructor (s,n) throws: + super(s) + this.num Assign n + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func func(...args) throws: + cond-branch cond:args.length StEq 1 Land args[0] instanceof Derived + true branch : + return (Derived)args[0] + false branch : + + return {str:"Unkown", num:0} + +== Sub Tree == +js_var Decl: b=new Base("Base") +== Sub Tree == +console.log(func(b)) +== Sub Tree == +js_var Decl: d=new Derived("Derived",123) +== Sub Tree == +console.log(func(d)) diff --git a/src/MapleFE/test/typescript/unit_tests/array-in-ctor.ts b/src/MapleFE/test/typescript/unit_tests/array-in-ctor.ts new file mode 100644 index 0000000000000000000000000000000000000000..b07b07525bb2d8d56c392da58000ff3701fcc84b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-in-ctor.ts @@ -0,0 +1,19 @@ +class Klass { + data: any; + constructor() { + { + this.data = [ + new Array(123, 456) + ]; + } + } + public dump (value: number) { + switch (value) { + case 1: + console.log(value, this.data); + } + } +} + +let obj: Klass = new Klass(); +obj.dump(1); diff --git a/src/MapleFE/test/typescript/unit_tests/array-in-ctor.ts.result b/src/MapleFE/test/typescript/unit_tests/array-in-ctor.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c8d8cb19b4ad241057695b6f79d93fe33c3625ad --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-in-ctor.ts.result @@ -0,0 +1,24 @@ +Matched 58 tokens. +Matched 68 tokens. +Matched 75 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + data + Instance Initializer: + Constructors: + constructor () throws: + this.data Assign [new Array(123,456)] + + Methods: + func dump(value) throws: + A switch + + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: obj=new Klass() +== Sub Tree == +obj.dump(1) diff --git a/src/MapleFE/test/typescript/unit_tests/array-keyof.ts b/src/MapleFE/test/typescript/unit_tests/array-keyof.ts new file mode 100644 index 0000000000000000000000000000000000000000..73934390e2193181394511892587acaeeb1d0425 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-keyof.ts @@ -0,0 +1 @@ +export declare type Type = { t: Array; }; diff --git a/src/MapleFE/test/typescript/unit_tests/array-keyof.ts.result b/src/MapleFE/test/typescript/unit_tests/array-keyof.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ba0b4104c0a161528b642857ea94a2561245f387 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-keyof.ts.result @@ -0,0 +1,4 @@ +Matched 26 tokens. +============= Module =========== +== Sub Tree == +export {declare type Type = {t }} diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal.ts b/src/MapleFE/test/typescript/unit_tests/array-literal.ts new file mode 100644 index 0000000000000000000000000000000000000000..a2b8c3d09d56a2057504ee21541a7e3d414cca2a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal.ts @@ -0,0 +1,2 @@ +var arr: number[] = [Math.ceil(5 / 3)]; +console.log(arr); diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal.ts.result b/src/MapleFE/test/typescript/unit_tests/array-literal.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..bc92f1cb5f4257ee738e4d02aa35e34deb011554 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal.ts.result @@ -0,0 +1,7 @@ +Matched 18 tokens. +Matched 25 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[Math.ceil(5 Div 3)] +== Sub Tree == +console.log(arr) diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal10.ts b/src/MapleFE/test/typescript/unit_tests/array-literal10.ts new file mode 100644 index 0000000000000000000000000000000000000000..03553ff2a936d7103bab8a77bae243fc6f70900a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal10.ts @@ -0,0 +1,23 @@ +class Foo { + [key: string]: number; + public f1: number = 0; + private f2: number = 0; + constructor(a: number, b: number) { + this.f1 = a; + this.f2 = b; + } +} +var funcs = [ + function func(): Foo { + console.log("Returning a new object"); + return new Foo(789, 0); + }, +]; +var obj: Foo | undefined = undefined; +var i: number = 1; +var res: number = (obj || funcs[0]())[`f${i}`]; +console.log(res); +obj = new Foo(123, 456); +++i; +res = (obj || funcs[0]())[`f${i}`]; +console.log(res); diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal10.ts.result b/src/MapleFE/test/typescript/unit_tests/array-literal10.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..759ae8eefbf133e6fd24499b4449484476c3c410 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal10.ts.result @@ -0,0 +1,47 @@ +Matched 50 tokens. +Matched 81 tokens. +Matched 90 tokens. +Matched 97 tokens. +Matched 116 tokens. +Matched 123 tokens. +Matched 133 tokens. +Matched 136 tokens. +Matched 152 tokens. +Matched 159 tokens. +Matched 160 tokens. +Matched 161 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + number f1=0 f2=0 + Instance Initializer: + Constructors: + constructor (a,b) throws: + this.f1 Assign a + this.f2 Assign b + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: funcs=[func func() throws: + console.log("Returning a new object") + return new Foo(789,0) +] +== Sub Tree == +js_var Decl: obj=undefined +== Sub Tree == +js_var Decl: i=1 +== Sub Tree == +js_var Decl: res=obj Lor funcs[0]()[ template-literal: "f",i] +== Sub Tree == +console.log(res) +== Sub Tree == +obj Assign new Foo(123,456) +== Sub Tree == +PreInc i +== Sub Tree == +res Assign obj Lor funcs[0]()[ template-literal: "f",i] +== Sub Tree == +console.log(res) diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal11.ts b/src/MapleFE/test/typescript/unit_tests/array-literal11.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6381be5e07c99952d7fb382738ea71b72d29f4c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal11.ts @@ -0,0 +1,7 @@ +enum Direction { + LEFT, + RIGHT, +} + +const rec = [true ? Direction.LEFT : Direction.RIGHT]; +console.log(rec); diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal11.ts.result b/src/MapleFE/test/typescript/unit_tests/array-literal11.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a863b9610058f07b873ae3f4e747ccaccd0cc05c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal11.ts.result @@ -0,0 +1,10 @@ +Matched 8 tokens. +Matched 23 tokens. +Matched 30 tokens. +============= Module =========== +== Sub Tree == +ts_enum: Direction {LEFT;RIGHT } +== Sub Tree == +js_const Decl: rec=[true ? Direction.LEFT : Direction.RIGHT] +== Sub Tree == +console.log(rec) diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal2.ts b/src/MapleFE/test/typescript/unit_tests/array-literal2.ts new file mode 100644 index 0000000000000000000000000000000000000000..76f552860cd11ba7e0aa23d919045491b7c1b1f8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal2.ts @@ -0,0 +1,3 @@ +var arr: number[] = [1, 2, 3]; +arr = [9, arr[2], arr[1]]; +console.log(arr); diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal2.ts.result b/src/MapleFE/test/typescript/unit_tests/array-literal2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..bca281e730440eca5ee46297f21f163cb920a0d7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal2.ts.result @@ -0,0 +1,10 @@ +Matched 15 tokens. +Matched 31 tokens. +Matched 38 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[1,2,3] +== Sub Tree == +arr Assign [9,arr[2],arr[1]] +== Sub Tree == +console.log(arr) diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal3.ts b/src/MapleFE/test/typescript/unit_tests/array-literal3.ts new file mode 100644 index 0000000000000000000000000000000000000000..4322acdc44cb19d6289d1fc5ab9ef574f7ce4c46 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal3.ts @@ -0,0 +1,3 @@ +var _2 = 0; +this["_2"] = 22; +console.log(this["_2"]); diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal3.ts.result b/src/MapleFE/test/typescript/unit_tests/array-literal3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..38a609320e0d7402555c34ffc5ee0df7b0d6999a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal3.ts.result @@ -0,0 +1,10 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 22 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: _2=0 +== Sub Tree == +this["_2"] Assign 22 +== Sub Tree == +console.log(this["_2"]) diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal4.ts b/src/MapleFE/test/typescript/unit_tests/array-literal4.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ea00dcf819bf765a527e7eaed054eda0f623933 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal4.ts @@ -0,0 +1,7 @@ +enum E { + LEFT = "left", + RIGHT = "right", +} + +var arr: E[] = [E.LEFT, E.RIGHT]; +console.log(arr); diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal4.ts.result b/src/MapleFE/test/typescript/unit_tests/array-literal4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ff97cb533540cb4a98ea44cff7951289d5f8506e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal4.ts.result @@ -0,0 +1,10 @@ +Matched 12 tokens. +Matched 29 tokens. +Matched 36 tokens. +============= Module =========== +== Sub Tree == +ts_enum: E {LEFT="left";RIGHT="right" } +== Sub Tree == +js_var Decl: arr=[E.LEFT,E.RIGHT] +== Sub Tree == +console.log(arr) diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal5.ts b/src/MapleFE/test/typescript/unit_tests/array-literal5.ts new file mode 100644 index 0000000000000000000000000000000000000000..c92f992fd391cc6347b5376be7f2f14e11ac02e0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal5.ts @@ -0,0 +1,7 @@ +enum Direction { + LEFT, + RIGHT, +} + +const rec = [Direction.LEFT, Direction.RIGHT]; +console.log(rec); diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal5.ts.result b/src/MapleFE/test/typescript/unit_tests/array-literal5.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..fcba11dd60be145c61ad30095c8b87323b16e6c0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal5.ts.result @@ -0,0 +1,10 @@ +Matched 8 tokens. +Matched 21 tokens. +Matched 28 tokens. +============= Module =========== +== Sub Tree == +ts_enum: Direction {LEFT;RIGHT } +== Sub Tree == +js_const Decl: rec=[Direction.LEFT,Direction.RIGHT] +== Sub Tree == +console.log(rec) diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal6.ts b/src/MapleFE/test/typescript/unit_tests/array-literal6.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c221537c71678f56557feda48bf07e667b1cdc4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal6.ts @@ -0,0 +1,3 @@ +var i = 10; +var face = [0, i + 1, i + 2]; +console.log(face); diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal6.ts.result b/src/MapleFE/test/typescript/unit_tests/array-literal6.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..92c4549e714868a092af165169005f6c4fc85f63 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal6.ts.result @@ -0,0 +1,10 @@ +Matched 5 tokens. +Matched 20 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: i=10 +== Sub Tree == +js_var Decl: face=[0,i Add 1,i Add 2] +== Sub Tree == +console.log(face) diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal7.ts b/src/MapleFE/test/typescript/unit_tests/array-literal7.ts new file mode 100644 index 0000000000000000000000000000000000000000..42358e48c70aadc11d7bf9f5d786dcb1ea65f0ef --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal7.ts @@ -0,0 +1,11 @@ +const arr: (() => void)[] = [ + () => { + console.log("Lambda0"); + }, + () => { + console.log("Lambda1"); + }, +]; +console.log(arr); +arr[0](); +arr[1](); diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal7.ts.result b/src/MapleFE/test/typescript/unit_tests/array-literal7.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..4cf433c3c169d9e2ec8f63929edd281582bf5651 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal7.ts.result @@ -0,0 +1,15 @@ +Matched 41 tokens. +Matched 48 tokens. +Matched 55 tokens. +Matched 62 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: arr=[() -> console.log("Lambda0") +,() -> console.log("Lambda1") +] +== Sub Tree == +console.log(arr) +== Sub Tree == +arr[0]() +== Sub Tree == +arr[1]() diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal8.ts b/src/MapleFE/test/typescript/unit_tests/array-literal8.ts new file mode 100644 index 0000000000000000000000000000000000000000..d64691ed229ff2b4d7cd5bdc4c2526cb251c9fea --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal8.ts @@ -0,0 +1,3 @@ +var i = 10; +var face = [0, i - 2, -i]; +console.log(face); diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal8.ts.result b/src/MapleFE/test/typescript/unit_tests/array-literal8.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3f249815bd52fe43ab00d43a493ce98c4ee89601 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal8.ts.result @@ -0,0 +1,10 @@ +Matched 5 tokens. +Matched 19 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: i=10 +== Sub Tree == +js_var Decl: face=[0,i Sub 2,Minus i] +== Sub Tree == +console.log(face) diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal9.ts b/src/MapleFE/test/typescript/unit_tests/array-literal9.ts new file mode 100644 index 0000000000000000000000000000000000000000..2837536a26a0ae85f63a05ca0c96b2582e867dc4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal9.ts @@ -0,0 +1,21 @@ +class Foo { + [key: string]: number; + public f1: number = 0; + private f2: number = 0; + constructor(a: number, b: number) { + this.f1 = a; + this.f2 = b; + } +} +function func(): Foo { + console.log("Returning a new object"); + return new Foo(789, 0); +} +var obj: Foo | undefined = undefined; +var i: number = 1; +var res: number = (obj || func())[`f${i}`]; +console.log(res); +obj = new Foo(123, 456); +++i; +res = (obj || func())[`f${i}`]; +console.log(res); diff --git a/src/MapleFE/test/typescript/unit_tests/array-literal9.ts.result b/src/MapleFE/test/typescript/unit_tests/array-literal9.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a0665e2795510928f1805094a2424ac4bd05ecb0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-literal9.ts.result @@ -0,0 +1,47 @@ +Matched 50 tokens. +Matched 74 tokens. +Matched 83 tokens. +Matched 90 tokens. +Matched 106 tokens. +Matched 113 tokens. +Matched 123 tokens. +Matched 126 tokens. +Matched 139 tokens. +Matched 146 tokens. +Matched 147 tokens. +Matched 148 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + number f1=0 f2=0 + Instance Initializer: + Constructors: + constructor (a,b) throws: + this.f1 Assign a + this.f2 Assign b + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func func() throws: + console.log("Returning a new object") + return new Foo(789,0) + +== Sub Tree == +js_var Decl: obj=undefined +== Sub Tree == +js_var Decl: i=1 +== Sub Tree == +js_var Decl: res=obj Lor func()[ template-literal: "f",i] +== Sub Tree == +console.log(res) +== Sub Tree == +obj Assign new Foo(123,456) +== Sub Tree == +PreInc i +== Sub Tree == +res Assign obj Lor func()[ template-literal: "f",i] +== Sub Tree == +console.log(res) diff --git a/src/MapleFE/test/typescript/unit_tests/array-multi-dims.ts b/src/MapleFE/test/typescript/unit_tests/array-multi-dims.ts new file mode 100644 index 0000000000000000000000000000000000000000..cc36afe28914bc6577aba29b1498360c045fdff1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-multi-dims.ts @@ -0,0 +1,7 @@ +const arr = [ + [4, 9, 2], + [3, 5, 7], + [8, 1, 6], +]; +console.log(arr[0][0] + arr[1][1] + arr[2][2]); +console.log(arr[0][2] + arr[1][1] + arr[2][0]); diff --git a/src/MapleFE/test/typescript/unit_tests/array-multi-dims.ts.result b/src/MapleFE/test/typescript/unit_tests/array-multi-dims.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2fba0af866e109ed8ee7e50a7715ae0442c2eb1f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-multi-dims.ts.result @@ -0,0 +1,10 @@ +Matched 30 tokens. +Matched 59 tokens. +Matched 88 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: arr=[[4,9,2],[3,5,7],[8,1,6]] +== Sub Tree == +console.log(arr[0][0] Add arr[1][1] Add arr[2][2]) +== Sub Tree == +console.log(arr[0][2] Add arr[1][1] Add arr[2][0]) diff --git a/src/MapleFE/test/typescript/unit_tests/array-multi-dims2.ts b/src/MapleFE/test/typescript/unit_tests/array-multi-dims2.ts new file mode 100644 index 0000000000000000000000000000000000000000..4b2f295fd5204dd0c1672a8f9c40d052207b4692 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-multi-dims2.ts @@ -0,0 +1,6 @@ +const arr = [ + [4, 9, 2], + [3, 5, 7], + [8, 1, 6], +]; +console.log(arr[0][0] + 1); diff --git a/src/MapleFE/test/typescript/unit_tests/array-multi-dims2.ts.result b/src/MapleFE/test/typescript/unit_tests/array-multi-dims2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..28342ba99577fba4f8fef191c59f343d1da9f9bf --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-multi-dims2.ts.result @@ -0,0 +1,7 @@ +Matched 30 tokens. +Matched 45 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: arr=[[4,9,2],[3,5,7],[8,1,6]] +== Sub Tree == +console.log(arr[0][0] Add 1) diff --git a/src/MapleFE/test/typescript/unit_tests/array-new-elem.ts b/src/MapleFE/test/typescript/unit_tests/array-new-elem.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab299a77f92d3d6c3e4141044a00470ab297e051 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-new-elem.ts @@ -0,0 +1,2 @@ +var arr: Object[] = [new Object(), new Object()]; +console.log(arr); diff --git a/src/MapleFE/test/typescript/unit_tests/array-new-elem.ts.result b/src/MapleFE/test/typescript/unit_tests/array-new-elem.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..39fdc1a6f79b334c411d27613f4cc237bb4e62fb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-new-elem.ts.result @@ -0,0 +1,7 @@ +Matched 19 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[new Object(),new Object()] +== Sub Tree == +console.log(arr) diff --git a/src/MapleFE/test/typescript/unit_tests/array-object.ts b/src/MapleFE/test/typescript/unit_tests/array-object.ts new file mode 100644 index 0000000000000000000000000000000000000000..f77faff98b2a8f58e9ef3ce91447da273ec2b552 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-object.ts @@ -0,0 +1,6 @@ +function func(arg: any) { + console.log(arg); +} +func([ [`Number`, { type: Number, count: 1, }], + [`String`, { type: String, count: 2, }], + ] as Array<[ name: string, value: any, ]>); diff --git a/src/MapleFE/test/typescript/unit_tests/array-object.ts.result b/src/MapleFE/test/typescript/unit_tests/array-object.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..93c56af98019afa2b9f3410874718c9c9b1f9dfb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-object.ts.result @@ -0,0 +1,9 @@ +Matched 16 tokens. +Matched 66 tokens. +============= Module =========== +== Sub Tree == +func func(arg) throws: + console.log(arg) + +== Sub Tree == +func([[ template-literal: "Number",NULL, {type:Number, count:1}],[ template-literal: "String",NULL, {type:String, count:2}]]) diff --git a/src/MapleFE/test/typescript/unit_tests/array-typeof.ts b/src/MapleFE/test/typescript/unit_tests/array-typeof.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a0bf0f58983e8d4ddf5ea627f39aad87a1100c3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-typeof.ts @@ -0,0 +1,5 @@ +class VType {} +class V2 extends VType {s: string = "abc"} +class V3 extends VType {n: number = 123} + +const BuiltinVTypes: typeof VType[] = [V2, V3]; diff --git a/src/MapleFE/test/typescript/unit_tests/array-typeof.ts.result b/src/MapleFE/test/typescript/unit_tests/array-typeof.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2619a263e550753b67d5adfd0a498975b6f8cff9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-typeof.ts.result @@ -0,0 +1,37 @@ +Matched 4 tokens. +Matched 15 tokens. +Matched 26 tokens. +Matched 40 tokens. +============= Module =========== +== Sub Tree == +class VType + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class V2 + Fields: + s="abc" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class V3 + Fields: + n=123 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_const Decl: BuiltinVTypes=[V2,V3] diff --git a/src/MapleFE/test/typescript/unit_tests/array-with-any.ts b/src/MapleFE/test/typescript/unit_tests/array-with-any.ts new file mode 100644 index 0000000000000000000000000000000000000000..978def01bdb8a14df648564e58a162029c58ffe1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-with-any.ts @@ -0,0 +1,6 @@ +class Klass { + protected n: Map void> = new Map(); +} + +var obj: Klass = new Klass(); +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/array-with-any.ts.result b/src/MapleFE/test/typescript/unit_tests/array-with-any.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..68721240385785d491d4a00636796bcb8492764a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-with-any.ts.result @@ -0,0 +1,18 @@ +Matched 29 tokens. +Matched 39 tokens. +Matched 46 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + n=new Map() + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/array-with-template-literal.ts b/src/MapleFE/test/typescript/unit_tests/array-with-template-literal.ts new file mode 100644 index 0000000000000000000000000000000000000000..34c66adddf4f8080f2ae08229dc6fb2870fd5fe5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-with-template-literal.ts @@ -0,0 +1,2 @@ +var arr = [null, [`template literal`, null] as unknown as (Array | null)[]]; +console.log(arr); diff --git a/src/MapleFE/test/typescript/unit_tests/array-with-template-literal.ts.result b/src/MapleFE/test/typescript/unit_tests/array-with-template-literal.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..95703f0d9280e671aec08b05ca33a88c33696189 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/array-with-template-literal.ts.result @@ -0,0 +1,7 @@ +Matched 26 tokens. +Matched 33 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[null,[ template-literal: "template literal",NULL,null]] +== Sub Tree == +console.log(arr) diff --git a/src/MapleFE/test/typescript/unit_tests/arrow-func.ts b/src/MapleFE/test/typescript/unit_tests/arrow-func.ts new file mode 100644 index 0000000000000000000000000000000000000000..187f525abab4d92014240b72687e3d5692db660d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/arrow-func.ts @@ -0,0 +1,5 @@ +let f1 = (x: number): number => { + return x / 3; +}; +let f2 = (x: number): number => x / 3; +console.log(f1(6), f2(9)); diff --git a/src/MapleFE/test/typescript/unit_tests/arrow-func.ts.result b/src/MapleFE/test/typescript/unit_tests/arrow-func.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..414e71ab055ea3bcb572cfab1e8f4836ced30d42 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/arrow-func.ts.result @@ -0,0 +1,11 @@ +Matched 19 tokens. +Matched 34 tokens. +Matched 49 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: f1=(x) -> return x Div 3 + +== Sub Tree == +js_let Decl: f2=(x) -> x Div 3 +== Sub Tree == +console.log(f1(6),f2(9)) diff --git a/src/MapleFE/test/typescript/unit_tests/as-any.ts b/src/MapleFE/test/typescript/unit_tests/as-any.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8a7913ef1fa1febe692064759b7bce4a10f34c8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-any.ts @@ -0,0 +1,5 @@ +function func() { + return { list: [1, 2, 3] }; +} +let s = func().list as any; +console.log(s); diff --git a/src/MapleFE/test/typescript/unit_tests/as-any.ts.result b/src/MapleFE/test/typescript/unit_tests/as-any.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..55b43f4ae642cdb62f7e204b6b6de20327205967 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-any.ts.result @@ -0,0 +1,12 @@ +Matched 19 tokens. +Matched 30 tokens. +Matched 37 tokens. +============= Module =========== +== Sub Tree == +func func() throws: + return {list:[1,2,3]} + +== Sub Tree == +js_let Decl: s=func().list +== Sub Tree == +console.log(s) diff --git a/src/MapleFE/test/typescript/unit_tests/as-const.ts b/src/MapleFE/test/typescript/unit_tests/as-const.ts new file mode 100644 index 0000000000000000000000000000000000000000..a2929ff44bf7ee07757023c317692bcb32f387c0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-const.ts @@ -0,0 +1,2 @@ +let s = "abc" as const; +console.log(s); diff --git a/src/MapleFE/test/typescript/unit_tests/as-const.ts.result b/src/MapleFE/test/typescript/unit_tests/as-const.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..99ca9082fab295b78836515677a59c2b1cd77aae --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-const.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 14 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: s="abc" +== Sub Tree == +console.log(s) diff --git a/src/MapleFE/test/typescript/unit_tests/as-const2.ts b/src/MapleFE/test/typescript/unit_tests/as-const2.ts new file mode 100644 index 0000000000000000000000000000000000000000..a434946630930b4a7f4c856a45b7ba576b4354e7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-const2.ts @@ -0,0 +1,5 @@ +enum Color { + Blue = "blue", +} +let s = Color.Blue as const; +console.log(s); diff --git a/src/MapleFE/test/typescript/unit_tests/as-const2.ts.result b/src/MapleFE/test/typescript/unit_tests/as-const2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5dd5949f6656a05ee1df9f073e4949398ac96472 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-const2.ts.result @@ -0,0 +1,10 @@ +Matched 8 tokens. +Matched 17 tokens. +Matched 24 tokens. +============= Module =========== +== Sub Tree == +ts_enum: Color {Blue="blue" } +== Sub Tree == +js_let Decl: s=Color.Blue +== Sub Tree == +console.log(s) diff --git a/src/MapleFE/test/typescript/unit_tests/as-const3.ts b/src/MapleFE/test/typescript/unit_tests/as-const3.ts new file mode 100644 index 0000000000000000000000000000000000000000..49781c19f481bdeb0b76af2dbb190320ef45e8e2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-const3.ts @@ -0,0 +1,5 @@ +enum Color { + Blue = "blue", +} +const s = (Color.Blue) as const; +console.log(s); diff --git a/src/MapleFE/test/typescript/unit_tests/as-const3.ts.result b/src/MapleFE/test/typescript/unit_tests/as-const3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c6224047ba7ca9528a6274e8f06df7188ff37917 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-const3.ts.result @@ -0,0 +1,10 @@ +Matched 8 tokens. +Matched 19 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +ts_enum: Color {Blue="blue" } +== Sub Tree == +js_const Decl: s=Color.Blue +== Sub Tree == +console.log(s) diff --git a/src/MapleFE/test/typescript/unit_tests/as-function-type.ts b/src/MapleFE/test/typescript/unit_tests/as-function-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..31ec2a2235020ea85ff759517ff7c5bb31e958bd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-function-type.ts @@ -0,0 +1,12 @@ +function func(cb: (s: string) => number): string { + console.log(cb("abc")); + return "OK"; +} + +var fn = function (s: string): number { + console.log(s); + return 123; +}; + +const f = func(fn as (s: string) => number); +console.log(f); diff --git a/src/MapleFE/test/typescript/unit_tests/as-function-type.ts.result b/src/MapleFE/test/typescript/unit_tests/as-function-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..45dce72dc6432c23a4d5673651c5c6bf964b315a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-function-type.ts.result @@ -0,0 +1,19 @@ +Matched 30 tokens. +Matched 54 tokens. +Matched 70 tokens. +Matched 77 tokens. +============= Module =========== +== Sub Tree == +func func(cb) throws: + console.log(cb("abc")) + return "OK" + +== Sub Tree == +js_var Decl: fn=func (s) throws: + console.log(s) + return 123 + +== Sub Tree == +js_const Decl: f=func(fn) +== Sub Tree == +console.log(f) diff --git a/src/MapleFE/test/typescript/unit_tests/as-namespace.d.ts b/src/MapleFE/test/typescript/unit_tests/as-namespace.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..0a893306950046bc266722e31af034a505fda3b4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-namespace.d.ts @@ -0,0 +1,6 @@ +// Proposal: export as namespace for UMD module output +// https://github.com/microsoft/TypeScript/issues/26532 + +// https://www.typescriptlang.org/docs/handbook/modules.html#umd-modules +export var x: number; +export as namespace NS; diff --git a/src/MapleFE/test/typescript/unit_tests/as-namespace.d.ts.result b/src/MapleFE/test/typescript/unit_tests/as-namespace.d.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..819b72b7c97e7689470604c34869967973d67359 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/as-namespace.d.ts.result @@ -0,0 +1,7 @@ +Matched 6 tokens. +Matched 11 tokens. +============= Module =========== +== Sub Tree == +export {js_var Decl: x} +== Sub Tree == +export {NS} diff --git a/src/MapleFE/test/typescript/unit_tests/ascii_escape.ts b/src/MapleFE/test/typescript/unit_tests/ascii_escape.ts new file mode 100644 index 0000000000000000000000000000000000000000..4976e247f6f5b188ed972d25e592b9fb486e055e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ascii_escape.ts @@ -0,0 +1 @@ +var x = "\\\n\"'\b\f\r"; diff --git a/src/MapleFE/test/typescript/unit_tests/ascii_escape.ts.result b/src/MapleFE/test/typescript/unit_tests/ascii_escape.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a031f7282aff0e7c32eed9ee8194e37174775a2f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ascii_escape.ts.result @@ -0,0 +1,4 @@ +Matched 5 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x="\\\n\"'\b\f\r" diff --git a/src/MapleFE/test/typescript/unit_tests/asserts-condition.ts b/src/MapleFE/test/typescript/unit_tests/asserts-condition.ts new file mode 100644 index 0000000000000000000000000000000000000000..a382744e5bf8716d4bf4cf64b06015e2015ec6fc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/asserts-condition.ts @@ -0,0 +1,8 @@ +function nonNullable(e: T): asserts e is NonNullable { + if (e === null || e === undefined) throw new Error("Assertion failure"); + console.log("nonNullable", e); +} + +class Klass {} +var obj: Klass = new Klass(); +nonNullable(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/asserts-condition.ts.result b/src/MapleFE/test/typescript/unit_tests/asserts-condition.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..09373fda959de25aab57ea0b472794c7dad8d8f5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/asserts-condition.ts.result @@ -0,0 +1,28 @@ +Matched 46 tokens. +Matched 50 tokens. +Matched 60 tokens. +Matched 68 tokens. +============= Module =========== +== Sub Tree == +func nonNullable(e) : assert e is NonNullable : throws: + cond-branch cond:e StEq null Lor e StEq undefined + true branch : + throw new Error("Assertion failure") + false branch : + + console.log("nonNullable",e) + +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +nonNullable(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/assign-quotes.ts b/src/MapleFE/test/typescript/unit_tests/assign-quotes.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e8bd5285e81cd8f2b2a6ef418b2c89a56dd93b2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/assign-quotes.ts @@ -0,0 +1,4 @@ +var foo; +if (foo === "") { + foo = '""'; +} diff --git a/src/MapleFE/test/typescript/unit_tests/assign-quotes.ts.result b/src/MapleFE/test/typescript/unit_tests/assign-quotes.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a9c2370b68c52f084740b2416a1e806a9582c386 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/assign-quotes.ts.result @@ -0,0 +1,11 @@ +Matched 3 tokens. +Matched 15 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: foo +== Sub Tree == +cond-branch cond:foo StEq "" +true branch : + foo Assign """" +false branch : + diff --git a/src/MapleFE/test/typescript/unit_tests/async-function.ts b/src/MapleFE/test/typescript/unit_tests/async-function.ts new file mode 100644 index 0000000000000000000000000000000000000000..09efbe49be53e3795f87c17e3cd3314dd711d65f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/async-function.ts @@ -0,0 +1,8 @@ +async function func() { + return "done"; +} + +(async () => { + const val = await func(); + console.log(val); +})(); diff --git a/src/MapleFE/test/typescript/unit_tests/async-function.ts.result b/src/MapleFE/test/typescript/unit_tests/async-function.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..942cc2667a90d02078203623716deec0f37a0833 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/async-function.ts.result @@ -0,0 +1,11 @@ +Matched 10 tokens. +Matched 36 tokens. +============= Module =========== +== Sub Tree == +func func() throws: + return "done" + +== Sub Tree == +() -> js_const Decl: val= await func() +console.log(val) +() diff --git a/src/MapleFE/test/typescript/unit_tests/async-in-literal.ts b/src/MapleFE/test/typescript/unit_tests/async-in-literal.ts new file mode 100644 index 0000000000000000000000000000000000000000..18c4e2fd48a8fd2629aade8ffda24995ff018043 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/async-in-literal.ts @@ -0,0 +1,9 @@ +function func() { + return { + async message() { + return "done"; + }, + }; +} + +console.log(func().message()); diff --git a/src/MapleFE/test/typescript/unit_tests/async-in-literal.ts.result b/src/MapleFE/test/typescript/unit_tests/async-in-literal.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e514d99fc30f5e9e56102068be896253d426bfe7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/async-in-literal.ts.result @@ -0,0 +1,11 @@ +Matched 20 tokens. +Matched 33 tokens. +============= Module =========== +== Sub Tree == +func func() throws: + return {message:func message() throws: + return "done" +} + +== Sub Tree == +console.log(func().message()) diff --git a/src/MapleFE/test/typescript/unit_tests/await-import.ts b/src/MapleFE/test/typescript/unit_tests/await-import.ts new file mode 100644 index 0000000000000000000000000000000000000000..47ea73929177b224e463a6d08a1566e23bc489da --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/await-import.ts @@ -0,0 +1,6 @@ +(async () => { + const { default: myX, getx, setx } = await import("./M"); + console.log(myX, getx()); + setx(3); + console.log(myX, getx()); +})(); diff --git a/src/MapleFE/test/typescript/unit_tests/await-import.ts.result b/src/MapleFE/test/typescript/unit_tests/await-import.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3fa7f89a3b3ae1d4bc56d6399820055735a04bb0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/await-import.ts.result @@ -0,0 +1,8 @@ +Matched 55 tokens. +============= Module =========== +== Sub Tree == +() -> js_const Decl: {default:myX, :getx, :setx} +console.log(myX,getx()) +setx(3) +console.log(myX,getx()) +() diff --git a/src/MapleFE/test/typescript/unit_tests/bin-op-scoped.ts b/src/MapleFE/test/typescript/unit_tests/bin-op-scoped.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f3f85714803e399e2fd2a8810a5dd1698cda9bb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/bin-op-scoped.ts @@ -0,0 +1,35 @@ +var a: number = 1; + +var b: number = 1; + +var c: number; + +c = a + b; + +c = a - b; + +c = a * b; + +c = a / b; + +c = a % b; + +{ + // Should generate a BlockNode here + + let a: number = 2; + + let b: number = 2; + + let c: number; + + c = a + b; + + c = a - b; + + c = a * b; + + c = a / b; + + c = a % b; +} diff --git a/src/MapleFE/test/typescript/unit_tests/bin-op-scoped.ts.result b/src/MapleFE/test/typescript/unit_tests/bin-op-scoped.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5a9d4b024703c0e882b626088bc56d6a8c700ed7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/bin-op-scoped.ts.result @@ -0,0 +1,36 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 19 tokens. +Matched 25 tokens. +Matched 31 tokens. +Matched 37 tokens. +Matched 43 tokens. +Matched 49 tokens. +Matched 100 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: a=1 +== Sub Tree == +js_var Decl: b=1 +== Sub Tree == +js_var Decl: c +== Sub Tree == +c Assign a Add b +== Sub Tree == +c Assign a Sub b +== Sub Tree == +c Assign a Mul b +== Sub Tree == +c Assign a Div b +== Sub Tree == +c Assign a Mod b +== Sub Tree == +js_let Decl: a=2 +js_let Decl: b=2 +js_let Decl: c +c Assign a Add b +c Assign a Sub b +c Assign a Mul b +c Assign a Div b +c Assign a Mod b + diff --git a/src/MapleFE/test/typescript/unit_tests/bin_op.ts b/src/MapleFE/test/typescript/unit_tests/bin_op.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab73727295fca09696bf5b480045c8a00b55f182 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/bin_op.ts @@ -0,0 +1,14 @@ +var a: number = 1; +var b: number = 1; +var c: number; +c = a + b; +c = a - b; +c = a * b; +c = a / b; +c = a % b; +c = a >> b; +c = a << b; +c = a >>> b; +var d: boolean; +d = a < b; +d = a <= b; diff --git a/src/MapleFE/test/typescript/unit_tests/bin_op.ts.result b/src/MapleFE/test/typescript/unit_tests/bin_op.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..226184c6a19aab5d26cb953227cb9d0a8f8e8412 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/bin_op.ts.result @@ -0,0 +1,43 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 19 tokens. +Matched 25 tokens. +Matched 31 tokens. +Matched 37 tokens. +Matched 43 tokens. +Matched 49 tokens. +Matched 55 tokens. +Matched 61 tokens. +Matched 67 tokens. +Matched 72 tokens. +Matched 78 tokens. +Matched 84 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: a=1 +== Sub Tree == +js_var Decl: b=1 +== Sub Tree == +js_var Decl: c +== Sub Tree == +c Assign a Add b +== Sub Tree == +c Assign a Sub b +== Sub Tree == +c Assign a Mul b +== Sub Tree == +c Assign a Div b +== Sub Tree == +c Assign a Mod b +== Sub Tree == +c Assign a Shr b +== Sub Tree == +c Assign a Shl b +== Sub Tree == +c Assign a Zext b +== Sub Tree == +js_var Decl: d +== Sub Tree == +d Assign a LT b +== Sub Tree == +d Assign a LE b diff --git a/src/MapleFE/test/typescript/unit_tests/binary-search.ts b/src/MapleFE/test/typescript/unit_tests/binary-search.ts new file mode 100644 index 0000000000000000000000000000000000000000..9aaa1bcdf814d86e74c691eb2509c42c7a641244 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/binary-search.ts @@ -0,0 +1,19 @@ +function binarySearch(array: number[], value: number): number { + var low: number = 0; + var high: number = array.length - 1; + var mid: number = high >>> 1; + for (; low <= high; mid = (low + high) >>> 1) { + const test = array[mid]; + if (test > value) { + high = mid - 1; + } else if (test < value) { + low = mid + 1; + } else { + return mid; + } + } + return ~low; +} + +var sequence: number[] = [13, 21, 34, 55, 89, 144]; +console.log(binarySearch(sequence, 144)); diff --git a/src/MapleFE/test/typescript/unit_tests/binary-search.ts.result b/src/MapleFE/test/typescript/unit_tests/binary-search.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6303a4639f9eb62830475cb37afca3416c35ef61 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/binary-search.ts.result @@ -0,0 +1,28 @@ +Matched 110 tokens. +Matched 131 tokens. +Matched 143 tokens. +============= Module =========== +== Sub Tree == +func binarySearch(array,value) throws: + js_var Decl: low=0 + js_var Decl: high=array.length Sub 1 + js_var Decl: mid=high Zext 1 + for ( ) + js_const Decl: test=array[mid] + cond-branch cond:test GT value + true branch : + high Assign mid Sub 1 + false branch : + cond-branch cond:test LT value + true branch : + low Assign mid Add 1 + false branch : + return mid + + + return Bcomp low + +== Sub Tree == +js_var Decl: sequence=[13,21,34,55,89,144] +== Sub Tree == +console.log(binarySearch(sequence,144)) diff --git a/src/MapleFE/test/typescript/unit_tests/binding-pattern.ts b/src/MapleFE/test/typescript/unit_tests/binding-pattern.ts new file mode 100644 index 0000000000000000000000000000000000000000..4abf0710d4ed9f6e32463c43667e6749a0c12439 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/binding-pattern.ts @@ -0,0 +1,7 @@ +interface IFace { + Num: number; + Str: string; +} + +declare const func: ({ Num: num, Str: str }?: IFace) => boolean; +export { IFace, func }; diff --git a/src/MapleFE/test/typescript/unit_tests/binding-pattern.ts.result b/src/MapleFE/test/typescript/unit_tests/binding-pattern.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7e28023e40ee9f1e1371f29d4cf9afe4ba4e96b4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/binding-pattern.ts.result @@ -0,0 +1,10 @@ +Matched 12 tokens. +Matched 33 tokens. +Matched 40 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {Num;Str } +== Sub Tree == +declare js_const Decl: func +== Sub Tree == +export {IFace,func} diff --git a/src/MapleFE/test/typescript/unit_tests/bracket-notation.ts b/src/MapleFE/test/typescript/unit_tests/bracket-notation.ts new file mode 100644 index 0000000000000000000000000000000000000000..3da12ff7cd3217233b81605cacc55312b0c49dfd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/bracket-notation.ts @@ -0,0 +1,7 @@ +interface Foo { + [key: string]: number; +} + +let bar: Foo = {}; +bar["key1"] = 1; +console.log(bar["key1"]); diff --git a/src/MapleFE/test/typescript/unit_tests/bracket-notation.ts.result b/src/MapleFE/test/typescript/unit_tests/bracket-notation.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..cf441e4309529b1a2ec0cf8efc52ca2ebe835eed --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/bracket-notation.ts.result @@ -0,0 +1,13 @@ +Matched 12 tokens. +Matched 20 tokens. +Matched 27 tokens. +Matched 37 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Foo {string index type: number } +== Sub Tree == +js_let Decl: bar= {} +== Sub Tree == +bar["key1"] Assign 1 +== Sub Tree == +console.log(bar["key1"]) diff --git a/src/MapleFE/test/typescript/unit_tests/call-array-ctor.ts b/src/MapleFE/test/typescript/unit_tests/call-array-ctor.ts new file mode 100644 index 0000000000000000000000000000000000000000..c4524f59b731e58903b4a953e86d37606959f8a2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/call-array-ctor.ts @@ -0,0 +1,3 @@ +var obj1: string[] = Array("first", "second", "third"); +var obj2: string[] = new Array("1", "2", "3"); +console.log(obj1, obj2); diff --git a/src/MapleFE/test/typescript/unit_tests/call-array-ctor.ts.result b/src/MapleFE/test/typescript/unit_tests/call-array-ctor.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..285f106fa9963fafb9cfe99e55064ea2ba56f600 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/call-array-ctor.ts.result @@ -0,0 +1,10 @@ +Matched 16 tokens. +Matched 33 tokens. +Matched 42 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: obj1=Array("first","second","third") +== Sub Tree == +js_var Decl: obj2=new Array("1","2","3") +== Sub Tree == +console.log(obj1,obj2) diff --git a/src/MapleFE/test/typescript/unit_tests/call-func.ts b/src/MapleFE/test/typescript/unit_tests/call-func.ts new file mode 100644 index 0000000000000000000000000000000000000000..d18e988373d9cb1bd9207a5cb4470d09e7c15178 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/call-func.ts @@ -0,0 +1,12 @@ +function func(o: Object): Object { + return o; +} + +class Klass { + [key: string]: number; + x: number = 123; +} + +var obj: Klass = { x: 1 }; +(func(obj) as Klass)["x"] = 2; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/call-func.ts.result b/src/MapleFE/test/typescript/unit_tests/call-func.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..4d0e7c34ab048b4fc85ac6d6364d8de83f674076 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/call-func.ts.result @@ -0,0 +1,26 @@ +Matched 14 tokens. +Matched 32 tokens. +Matched 43 tokens. +Matched 57 tokens. +Matched 64 tokens. +============= Module =========== +== Sub Tree == +func func(o) throws: + return o + +== Sub Tree == +class Klass + Fields: + number x=123 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj= {x:1} +== Sub Tree == +func(obj)["x"] Assign 2 +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/car.ts b/src/MapleFE/test/typescript/unit_tests/car.ts new file mode 100644 index 0000000000000000000000000000000000000000..26410d7987d970e5b10bd076e335deac66c1cdc7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/car.ts @@ -0,0 +1,13 @@ +class Vehicle { + name: string; + constructor(name: string) { + this.name = name; + } +} +class Car extends Vehicle { + constructor(name: string) { + super(name); + } +} +let car: Car = new Car("A car"); +console.log(car.name); diff --git a/src/MapleFE/test/typescript/unit_tests/car.ts.result b/src/MapleFE/test/typescript/unit_tests/car.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..79f120f5d1e290e03d2c08da60bf10d809446024 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/car.ts.result @@ -0,0 +1,33 @@ +Matched 22 tokens. +Matched 41 tokens. +Matched 52 tokens. +Matched 61 tokens. +============= Module =========== +== Sub Tree == +class Vehicle + Fields: + name + Instance Initializer: + Constructors: + constructor (name) throws: + this.name Assign name + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Car + Fields: + + Instance Initializer: + Constructors: + constructor (name) throws: + super(name) + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: car=new Car("A car") +== Sub Tree == +console.log(car.name) diff --git a/src/MapleFE/test/typescript/unit_tests/casting-with-generic-type.ts b/src/MapleFE/test/typescript/unit_tests/casting-with-generic-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..c9652eaecfce913e0a55bd1599962ba08cdd069c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/casting-with-generic-type.ts @@ -0,0 +1,3 @@ +function func(f: Function) { + return <() => Array>f; +} diff --git a/src/MapleFE/test/typescript/unit_tests/casting-with-generic-type.ts.result b/src/MapleFE/test/typescript/unit_tests/casting-with-generic-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..26122598b2a01c577e7f6caf04b546b75110b997 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/casting-with-generic-type.ts.result @@ -0,0 +1,6 @@ +Matched 23 tokens. +============= Module =========== +== Sub Tree == +func func(f) throws: + return (() -> )f + diff --git a/src/MapleFE/test/typescript/unit_tests/class-deco.ts b/src/MapleFE/test/typescript/unit_tests/class-deco.ts new file mode 100644 index 0000000000000000000000000000000000000000..93c2869d1ebe1ddc870ccccab38b3f25f4beeafc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-deco.ts @@ -0,0 +1,6 @@ +function class_deco(ctor: Function): void { + console.log("Class constructor is :", ctor); +} +@class_deco +class Klass {} +var o = new Klass(); diff --git a/src/MapleFE/test/typescript/unit_tests/class-deco.ts.result b/src/MapleFE/test/typescript/unit_tests/class-deco.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ed9f8b106b87edfb0c302c2bd35a5213fdb7d672 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-deco.ts.result @@ -0,0 +1,20 @@ +Matched 20 tokens. +Matched 26 tokens. +Matched 34 tokens. +============= Module =========== +== Sub Tree == +func class_deco(ctor) throws: + console.log("Class constructor is :",ctor) + +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: o=new Klass() diff --git a/src/MapleFE/test/typescript/unit_tests/class-deco2.ts b/src/MapleFE/test/typescript/unit_tests/class-deco2.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe783cc93145707009fbc1536d5c6080df34efdb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-deco2.ts @@ -0,0 +1,9 @@ +function class_deco(name: string): Function { + function deco(ctor: Function): void { + console.log("Class constructor is :", ctor, ", Name is: ", name); + } + return deco; +} +@class_deco("Deco") +class Klass {} +var o = new Klass(); diff --git a/src/MapleFE/test/typescript/unit_tests/class-deco2.ts.result b/src/MapleFE/test/typescript/unit_tests/class-deco2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..626101c9d23cbb6d5100f514d28e81e4966f7709 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-deco2.ts.result @@ -0,0 +1,23 @@ +Matched 38 tokens. +Matched 47 tokens. +Matched 55 tokens. +============= Module =========== +== Sub Tree == +func class_deco(name) throws: + func deco(ctor) throws: + console.log("Class constructor is :",ctor,", Name is: ",name) + + return deco + +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: o=new Klass() diff --git a/src/MapleFE/test/typescript/unit_tests/class-deco3.ts b/src/MapleFE/test/typescript/unit_tests/class-deco3.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e599b2155c6c1712aafee180d57f2582731cba9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-deco3.ts @@ -0,0 +1,29 @@ +function class_deco(name: string): Function { + function deco(ctor: Function): void { + console.log("Class constructor is :", ctor, ", Name is: ", name); + } + return deco; +} + +@class_deco('Klass') +class Klass { + data: any = null; + public setData(value: any) { + this.data= [ + { + n: value, + }, + ]; + } + + public dump (value: number) { + switch (value) { + case 1: + console.log(value, this.data); + } + } +} + +let obj: Klass = new Klass(); +obj.setData(123); +obj.dump(1); diff --git a/src/MapleFE/test/typescript/unit_tests/class-deco3.ts.result b/src/MapleFE/test/typescript/unit_tests/class-deco3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..d150e86876fa5ca48788a0859c9f42299389c81c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-deco3.ts.result @@ -0,0 +1,34 @@ +Matched 38 tokens. +Matched 105 tokens. +Matched 115 tokens. +Matched 122 tokens. +Matched 129 tokens. +============= Module =========== +== Sub Tree == +func class_deco(name) throws: + func deco(ctor) throws: + console.log("Class constructor is :",ctor,", Name is: ",name) + + return deco + +== Sub Tree == +class Klass + Fields: + data=null + Instance Initializer: + Constructors: + Methods: + func setData(value) throws: + this.data Assign [ {n:value}] + func dump(value) throws: + A switch + + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: obj=new Klass() +== Sub Tree == +obj.setData(123) +== Sub Tree == +obj.dump(1) diff --git a/src/MapleFE/test/typescript/unit_tests/class-deco4.ts b/src/MapleFE/test/typescript/unit_tests/class-deco4.ts new file mode 100644 index 0000000000000000000000000000000000000000..9174fb8079897328c8aaf3a4c02bbcb31e156753 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-deco4.ts @@ -0,0 +1,22 @@ +function class_deco(name: string): Function { + function deco(ctor: Function): void { + console.log("Class constructor is :", ctor, ", Name is: ", name); + } + return deco; +} + +@class_deco('Klass') +class Klass { + data: + {n: number} = {n : 123}; + + public dump (value: number) { + switch (value) { + case 1: + console.log(value, this.data); + } + } +} + +let obj: Klass = new Klass(); +obj.dump(1); diff --git a/src/MapleFE/test/typescript/unit_tests/class-deco4.ts.result b/src/MapleFE/test/typescript/unit_tests/class-deco4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b52fdf7351455c144a4bf82ff4623a2dd1db1b91 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-deco4.ts.result @@ -0,0 +1,29 @@ +Matched 38 tokens. +Matched 90 tokens. +Matched 100 tokens. +Matched 107 tokens. +============= Module =========== +== Sub Tree == +func class_deco(name) throws: + func deco(ctor) throws: + console.log("Class constructor is :",ctor,", Name is: ",name) + + return deco + +== Sub Tree == +class Klass + Fields: + data= {n:123} + Instance Initializer: + Constructors: + Methods: + func dump(value) throws: + A switch + + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: obj=new Klass() +== Sub Tree == +obj.dump(1) diff --git a/src/MapleFE/test/typescript/unit_tests/class-direct-fd.ts b/src/MapleFE/test/typescript/unit_tests/class-direct-fd.ts new file mode 100644 index 0000000000000000000000000000000000000000..f68d085fd6f21b6d5d2cd41575ffc5c00a39dedc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-direct-fd.ts @@ -0,0 +1,32 @@ +class Foo { + public f1: number = 0; + public f2: number = 0; + constructor(a: number, b: number) { + this.f1 = a; + this.f2 = b; + } +} + +var bar : Foo = {f1:1, f2:2}; +bar.f1 = 3; // direct dot +bar["f1"] = 4; // direct prop +bar["p1"] = 10; // prop + +bar.f2 = bar.f1; // direct dot = direct dot +bar.f2 = bar["f1"]; // direct dot = direct prop +bar["f1"] = bar["f2"]; // direct prop = direct prop +bar["f1"] = bar["p1"]; // direct prop = prop + +bar["p2"] = bar["f2"]; // prop = direct prop +bar["p2"] = bar["p1"]; // prop = prop +bar["p2"] = bar["p2"] >> bar["p1"]; // (int32_t)(xxx) = yyy >> zzz +bar["p2"] = bar["p2"] >>> bar["p1"]; // (uint32_t)(xxx) = yyy >> zzz + + +console.log(bar.f1); +console.log(bar.f2); +console.log(bar["f1"]); +console.log(bar["f2"]); +console.log(bar["p1"]); +console.log(bar["p2"]); + diff --git a/src/MapleFE/test/typescript/unit_tests/class-direct-fd.ts.result b/src/MapleFE/test/typescript/unit_tests/class-direct-fd.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1863507c9b01e410acbaafa80ad19103ce446590 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-direct-fd.ts.result @@ -0,0 +1,69 @@ +Matched 42 tokens. +Matched 57 tokens. +Matched 63 tokens. +Matched 70 tokens. +Matched 77 tokens. +Matched 85 tokens. +Matched 94 tokens. +Matched 104 tokens. +Matched 114 tokens. +Matched 124 tokens. +Matched 134 tokens. +Matched 149 tokens. +Matched 164 tokens. +Matched 173 tokens. +Matched 182 tokens. +Matched 192 tokens. +Matched 202 tokens. +Matched 212 tokens. +Matched 222 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + f1=0 f2=0 + Instance Initializer: + Constructors: + constructor (a,b) throws: + this.f1 Assign a + this.f2 Assign b + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: bar= {f1:1, f2:2} +== Sub Tree == +bar.f1 Assign 3 +== Sub Tree == +bar["f1"] Assign 4 +== Sub Tree == +bar["p1"] Assign 10 +== Sub Tree == +bar.f2 Assign bar.f1 +== Sub Tree == +bar.f2 Assign bar["f1"] +== Sub Tree == +bar["f1"] Assign bar["f2"] +== Sub Tree == +bar["f1"] Assign bar["p1"] +== Sub Tree == +bar["p2"] Assign bar["f2"] +== Sub Tree == +bar["p2"] Assign bar["p1"] +== Sub Tree == +bar["p2"] Assign bar["p2"] Shr bar["p1"] +== Sub Tree == +bar["p2"] Assign bar["p2"] Zext bar["p1"] +== Sub Tree == +console.log(bar.f1) +== Sub Tree == +console.log(bar.f2) +== Sub Tree == +console.log(bar["f1"]) +== Sub Tree == +console.log(bar["f2"]) +== Sub Tree == +console.log(bar["p1"]) +== Sub Tree == +console.log(bar["p2"]) diff --git a/src/MapleFE/test/typescript/unit_tests/class-extends.ts b/src/MapleFE/test/typescript/unit_tests/class-extends.ts new file mode 100644 index 0000000000000000000000000000000000000000..176d1555e8b04bf5a36576c675ed0b9dc541cfa5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-extends.ts @@ -0,0 +1,23 @@ +class Car { + private _make: string; + constructor(make: string) { + this._make = make; + } + public getMake(): string { + return this._make; + } +} + +class Model extends Car { + private _model: string; + constructor(make: string, model: string) { + super(make); + this._model = model; + } + public getModel(): string { + return this._model; + } +} + +let passat: Model = new Model("VW", "Passat"); +console.log(passat.getMake(), passat.getModel()); diff --git a/src/MapleFE/test/typescript/unit_tests/class-extends.ts.result b/src/MapleFE/test/typescript/unit_tests/class-extends.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..194818d19c823c5616d1de1765403897d2f8f277 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-extends.ts.result @@ -0,0 +1,38 @@ +Matched 36 tokens. +Matched 83 tokens. +Matched 96 tokens. +Matched 113 tokens. +============= Module =========== +== Sub Tree == +class Car + Fields: + _make + Instance Initializer: + Constructors: + constructor (make) throws: + this._make Assign make + Methods: + func getMake() throws: + return this._make + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Model + Fields: + _model + Instance Initializer: + Constructors: + constructor (make,model) throws: + super(make) + this._model Assign model + Methods: + func getModel() throws: + return this._model + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: passat=new Model("VW","Passat") +== Sub Tree == +console.log(passat.getMake(),passat.getModel()) diff --git a/src/MapleFE/test/typescript/unit_tests/class-extends2.ts b/src/MapleFE/test/typescript/unit_tests/class-extends2.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae538bf8cfdfab1c4fc94e3500908224f81b982f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-extends2.ts @@ -0,0 +1,23 @@ +class Car { + private _make: string; + constructor(make: string) { + this._make = make; + } + public getMake(): string { + return this._make; + } +} + +class Model extends Car { + private _model: string; + constructor(make: string, model: string) { + super(make); + this._model = super.getMake() + model; + } + public getModel(): string { + return this._model; + } +} + +let passat: Model = new Model("VW", "Passat"); +console.log(passat.getMake(), passat.getModel()); diff --git a/src/MapleFE/test/typescript/unit_tests/class-extends2.ts.result b/src/MapleFE/test/typescript/unit_tests/class-extends2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2ad27f7c11b90658965008e57e37cefcd85e8d61 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-extends2.ts.result @@ -0,0 +1,38 @@ +Matched 36 tokens. +Matched 89 tokens. +Matched 102 tokens. +Matched 119 tokens. +============= Module =========== +== Sub Tree == +class Car + Fields: + _make + Instance Initializer: + Constructors: + constructor (make) throws: + this._make Assign make + Methods: + func getMake() throws: + return this._make + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Model + Fields: + _model + Instance Initializer: + Constructors: + constructor (make,model) throws: + super(make) + this._model Assign super.getMake() Add model + Methods: + func getModel() throws: + return this._model + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: passat=new Model("VW","Passat") +== Sub Tree == +console.log(passat.getMake(),passat.getModel()) diff --git a/src/MapleFE/test/typescript/unit_tests/class-extends3.ts b/src/MapleFE/test/typescript/unit_tests/class-extends3.ts new file mode 100644 index 0000000000000000000000000000000000000000..356bf07792ee304fab0458f781062929096a0044 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-extends3.ts @@ -0,0 +1,22 @@ +class Car { + private _make: string; + constructor(make: string) { + this._make = make; + } + public getMake(): string { + return this._make; + } +} + +class Model extends Car { + private _model: string; + constructor(make: string, model: string) { + super(make) this._model = super.getMake() + model; + } + public getModel(): string { + return this._model; + } +} + +let passat: Model = new Model("VW", "Passat"); +console.log(passat.getMake(), passat.getModel()); diff --git a/src/MapleFE/test/typescript/unit_tests/class-extends3.ts.result b/src/MapleFE/test/typescript/unit_tests/class-extends3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5368fc30da365058f5d1934d73ee3dfecd5b2e61 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-extends3.ts.result @@ -0,0 +1,38 @@ +Matched 36 tokens. +Matched 88 tokens. +Matched 101 tokens. +Matched 118 tokens. +============= Module =========== +== Sub Tree == +class Car + Fields: + _make + Instance Initializer: + Constructors: + constructor (make) throws: + this._make Assign make + Methods: + func getMake() throws: + return this._make + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Model + Fields: + _model + Instance Initializer: + Constructors: + constructor (make,model) throws: + super(make) + this._model Assign super.getMake() Add model + Methods: + func getModel() throws: + return this._model + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: passat=new Model("VW","Passat") +== Sub Tree == +console.log(passat.getMake(),passat.getModel()) diff --git a/src/MapleFE/test/typescript/unit_tests/class-generics-arrowfunc.ts b/src/MapleFE/test/typescript/unit_tests/class-generics-arrowfunc.ts new file mode 100644 index 0000000000000000000000000000000000000000..28f611a4e94a9086fa416f9e52208c49078a3b3e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-generics-arrowfunc.ts @@ -0,0 +1,25 @@ +// Class with generics and arrow function. +// - Class constructor takes a function as parameter and saves it. +// - The saved function allocates and return an object with generics type. +// - Class method alloc() calls the saved function to allocate and return an obj. +class Foo { + private _ctor: () => T; + + constructor(ctor: () => T) { + this._ctor = ctor; + } + + public alloc(): T { + return this._ctor(); + } +} + +// Create class object with String type +// - Create class object with type String +// - Pass an arrow function (that returns a new String object) to the class constructor +const FooString: Foo = new Foo(() => new String("foo")); + +// Optional check. +// - Call alloc() of new class object to get a new object and +// - call the object's builtin toString() method to display it. +console.log(FooString.alloc().toString()); diff --git a/src/MapleFE/test/typescript/unit_tests/class-generics-arrowfunc.ts.result b/src/MapleFE/test/typescript/unit_tests/class-generics-arrowfunc.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a83ce45d57efe59786174ed01db3b6b11892246d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-generics-arrowfunc.ts.result @@ -0,0 +1,22 @@ +Matched 47 tokens. +Matched 71 tokens. +Matched 86 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + _ctor + Instance Initializer: + Constructors: + constructor (ctor) throws: + this._ctor Assign ctor + Methods: + func alloc() throws: + return this._ctor() + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_const Decl: FooString=new Foo(() -> new String("foo")) +== Sub Tree == +console.log(FooString.alloc().toString()) diff --git a/src/MapleFE/test/typescript/unit_tests/class-implements-interface.ts b/src/MapleFE/test/typescript/unit_tests/class-implements-interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4bf9e97f3cdf069f9b9f72a96eb4731d4ff5dec --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-implements-interface.ts @@ -0,0 +1,5 @@ +interface Intf1 {} +class C1 implements Intf1 {} + +interface Intf2 {} +class C2 implements Intf2 {} diff --git a/src/MapleFE/test/typescript/unit_tests/class-implements-interface.ts.result b/src/MapleFE/test/typescript/unit_tests/class-implements-interface.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..89303989da48c640f2cfedff34ca4d1addec4ac6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-implements-interface.ts.result @@ -0,0 +1,29 @@ +Matched 4 tokens. +Matched 10 tokens. +Matched 17 tokens. +Matched 29 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Intf1 { } +== Sub Tree == +class C1 + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +ts_interface: Intf2 { } +== Sub Tree == +class C2 + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/class-in-func.ts b/src/MapleFE/test/typescript/unit_tests/class-in-func.ts new file mode 100644 index 0000000000000000000000000000000000000000..42a5e9634d166e994c1f1cf10812e8ca70dd2ff5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-in-func.ts @@ -0,0 +1,6 @@ +function func(): Function { + class Car {} + return Car; +} +console.log(func()); + diff --git a/src/MapleFE/test/typescript/unit_tests/class-in-func.ts.result b/src/MapleFE/test/typescript/unit_tests/class-in-func.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..382cdd5a0ba7c0731a823653f9643b9f4658cfce --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-in-func.ts.result @@ -0,0 +1,18 @@ +Matched 15 tokens. +Matched 24 tokens. +============= Module =========== +== Sub Tree == +func func() throws: + class Car + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + + return Car + +== Sub Tree == +console.log(func()) diff --git a/src/MapleFE/test/typescript/unit_tests/class-type.ts b/src/MapleFE/test/typescript/unit_tests/class-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..af4104977e7dbab267736e405600e69122dd892f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-type.ts @@ -0,0 +1,2 @@ +console.log(typeof new (class {})); +console.log(new (class {f: number = 123;})); diff --git a/src/MapleFE/test/typescript/unit_tests/class-type.ts.result b/src/MapleFE/test/typescript/unit_tests/class-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..51e6940208ca513dab8d0f3517c1f9dc23440aee --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class-type.ts.result @@ -0,0 +1,7 @@ +Matched 13 tokens. +Matched 31 tokens. +============= Module =========== +== Sub Tree == +console.log( typeof new ()) +== Sub Tree == +console.log(new ()) diff --git a/src/MapleFE/test/typescript/unit_tests/class.ts b/src/MapleFE/test/typescript/unit_tests/class.ts new file mode 100644 index 0000000000000000000000000000000000000000..6103ec8a6fe6a680ec46e13c950211da090f45bf --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class.ts @@ -0,0 +1,8 @@ +class Foo { + public f1: number = 0; + private f2: number = 0; + constructor(a: number, b: number) { + this.f1 = a; + this.f2 = b; + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/class.ts.result b/src/MapleFE/test/typescript/unit_tests/class.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..01b7a8b13f627aae8015a633428937e4d1bb71cd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class.ts.result @@ -0,0 +1,15 @@ +Matched 42 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + f1=0 f2=0 + Instance Initializer: + Constructors: + constructor (a,b) throws: + this.f1 Assign a + this.f2 Assign b + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/class1.ts b/src/MapleFE/test/typescript/unit_tests/class1.ts new file mode 100644 index 0000000000000000000000000000000000000000..721b9a69277d69ef5bed73071021c144876645ca --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class1.ts @@ -0,0 +1,30 @@ +class Bar { + public b1: number = 5; + public b2: number = 6; +} + +class Foo { + public f1: number = 0; + public f2: number = 0; + public bar: Bar; + constructor(a: number, b: number) { + this.f1 = a; + this.f2 = b; + this.bar= new Bar(); + } +} + +class App { + public foo: Foo; + constructor(a: number, b: number) { + this.foo = new Foo(a, b); + } +} + +var foo: Foo = new Foo(1, 2); +console.log(foo); + +var app: App = new App(3, 4); +console.log(app); + + diff --git a/src/MapleFE/test/typescript/unit_tests/class1.ts.result b/src/MapleFE/test/typescript/unit_tests/class1.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..42cfac29ee3fbb55d509d9712f3490e3438b7e71 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class1.ts.result @@ -0,0 +1,52 @@ +Matched 18 tokens. +Matched 74 tokens. +Matched 107 tokens. +Matched 120 tokens. +Matched 127 tokens. +Matched 140 tokens. +Matched 147 tokens. +============= Module =========== +== Sub Tree == +class Bar + Fields: + b1=5 b2=6 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Foo + Fields: + f1=0 f2=0 bar + Instance Initializer: + Constructors: + constructor (a,b) throws: + this.f1 Assign a + this.f2 Assign b + this.bar Assign new Bar() + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class App + Fields: + foo + Instance Initializer: + Constructors: + constructor (a,b) throws: + this.foo Assign new Foo(a,b) + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: foo=new Foo(1,2) +== Sub Tree == +console.log(foo) +== Sub Tree == +js_var Decl: app=new App(3,4) +== Sub Tree == +console.log(app) diff --git a/src/MapleFE/test/typescript/unit_tests/class2.ts b/src/MapleFE/test/typescript/unit_tests/class2.ts new file mode 100644 index 0000000000000000000000000000000000000000..cef2e430e977d30ec47fa8da745e5329873b0f71 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class2.ts @@ -0,0 +1,15 @@ +class Klass {} +class Foo { + public f1: number = 0; + private f2: number = 0; + constructor(a: number, b: number) { + this.f1 = a; + this.f2 = b; + } + public static test(obj: unknown): obj is Klass { + return obj instanceof Klass; + } +} + +var obj: Klass = new Klass(); +console.log(Foo.test(obj)); diff --git a/src/MapleFE/test/typescript/unit_tests/class2.ts.result b/src/MapleFE/test/typescript/unit_tests/class2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..cc2dbc1ecfa7502adae0f99f43a7a19c8d2944da --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class2.ts.result @@ -0,0 +1,34 @@ +Matched 4 tokens. +Matched 65 tokens. +Matched 75 tokens. +Matched 87 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Foo + Fields: + f1=0 f2=0 + Instance Initializer: + Constructors: + constructor (a,b) throws: + this.f1 Assign a + this.f2 Assign b + Methods: + func test(obj) throws: + return obj instanceof Klass + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +console.log(Foo.test(obj)) diff --git a/src/MapleFE/test/typescript/unit_tests/class3.ts b/src/MapleFE/test/typescript/unit_tests/class3.ts new file mode 100644 index 0000000000000000000000000000000000000000..9b2b79c39f13cdb9b6c9dca8454420dccb7a4052 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class3.ts @@ -0,0 +1,11 @@ +class Foo { + public out: number = 0; + public in: number = 0; + constructor(a: number, b: number) { + this.out = a; + this.in = b; + } +} + +var obj: Foo = new Foo(12, 34); +console.log(obj.in); diff --git a/src/MapleFE/test/typescript/unit_tests/class3.ts.result b/src/MapleFE/test/typescript/unit_tests/class3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a659f6a71e5e584e1a54c9b0e6b15f07b065d60d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class3.ts.result @@ -0,0 +1,21 @@ +Matched 42 tokens. +Matched 55 tokens. +Matched 64 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + out=0 in=0 + Instance Initializer: + Constructors: + constructor (a,b) throws: + this.out Assign a + this.in Assign b + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Foo(12,34) +== Sub Tree == +console.log(obj.in) diff --git a/src/MapleFE/test/typescript/unit_tests/class4.ts b/src/MapleFE/test/typescript/unit_tests/class4.ts new file mode 100644 index 0000000000000000000000000000000000000000..f9aea57360141cf48427de02147514af1aaff5ec --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class4.ts @@ -0,0 +1,12 @@ +class Foo { + public s: string; + constructor(f: (args?: [d: string, i: string], obj?: string) => string) { + this.s = f(); + } +} + +function func(args?: [d: string, i: string], obj?: string): string { + return "abc"; +} +var obj: Foo = new Foo(func); +console.log(obj.s); diff --git a/src/MapleFE/test/typescript/unit_tests/class4.ts.result b/src/MapleFE/test/typescript/unit_tests/class4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0c805813345d538628820d057ab095d144a32c03 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class4.ts.result @@ -0,0 +1,25 @@ +Matched 45 tokens. +Matched 73 tokens. +Matched 84 tokens. +Matched 93 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + s + Instance Initializer: + Constructors: + constructor (f) throws: + this.s Assign f() + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func func(args?,obj?) throws: + return "abc" + +== Sub Tree == +js_var Decl: obj=new Foo(func) +== Sub Tree == +console.log(obj.s) diff --git a/src/MapleFE/test/typescript/unit_tests/class5.ts b/src/MapleFE/test/typescript/unit_tests/class5.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e6a4413d95e9586a6973e8328f0b1823eedc63b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class5.ts @@ -0,0 +1,6 @@ +class Klass { + public switch: number = 0; +} + +var obj: Klass = new Klass(); +console.log(obj, obj.switch); diff --git a/src/MapleFE/test/typescript/unit_tests/class5.ts.result b/src/MapleFE/test/typescript/unit_tests/class5.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1c10c42ffd7ecc28a2d1728c35432b3c9ebdd502 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class5.ts.result @@ -0,0 +1,18 @@ +Matched 11 tokens. +Matched 21 tokens. +Matched 32 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + switch=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +console.log(obj,obj.switch) diff --git a/src/MapleFE/test/typescript/unit_tests/class6.ts b/src/MapleFE/test/typescript/unit_tests/class6.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad924fc06795ae44aa9fc447ddf7a8480482c9f2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class6.ts @@ -0,0 +1,20 @@ +class Klass { + public num: number = 1; + + if(n: number): boolean { + return this.num == n; + } + + try(n: number): void { + if(n == this.num) + console.log("EQ"); + else + console.log("NE"); + } +} + +var obj: Klass = new Klass(); +console.log(obj.if(0)); +console.log(obj.if(1)); +obj.try(0); +obj.try(1); diff --git a/src/MapleFE/test/typescript/unit_tests/class6.ts.result b/src/MapleFE/test/typescript/unit_tests/class6.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..08a20f91d9cb7bde8eba40afc7635cd73adeb7ca --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/class6.ts.result @@ -0,0 +1,34 @@ +Matched 61 tokens. +Matched 71 tokens. +Matched 83 tokens. +Matched 95 tokens. +Matched 102 tokens. +Matched 109 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + num=1 + Instance Initializer: + Constructors: + Methods: + func if(n) throws: + return this.num EQ n + func try(n) throws: + cond-branch cond:n EQ this.num + true branch : + console.log("EQ") false branch : + console.log("NE") + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +console.log(obj.if(0)) +== Sub Tree == +console.log(obj.if(1)) +== Sub Tree == +obj.try(0) +== Sub Tree == +obj.try(1) diff --git a/src/MapleFE/test/typescript/unit_tests/classFactory.ts b/src/MapleFE/test/typescript/unit_tests/classFactory.ts new file mode 100644 index 0000000000000000000000000000000000000000..08904c0b24442466500662faebd735fff8e1b422 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/classFactory.ts @@ -0,0 +1,24 @@ +/* 1. class factory */ + +// Generic constructor interface +type Constructor = new (...args: any[]) => T; + +// A standard interface to be incorporated into all generated classes +interface someStandardInterface {} + +// Class factory that takes a base class and generates a new class with a standard interface +function ClassFactory( + base: Constructor +): Constructor { + class GeneratedClass extends (base as unknown as any) {} + + return GeneratedClass as unknown as any; +} + +/* 2. Usage of the class factory */ + +// A class to be use as base for generating one with some standard interface +class someBaseClass {} + +// A class that uses ClassFactory to generate a new class with standard inteface +class newClassWithStandardInterface extends ClassFactory(someBaseClass) {} diff --git a/src/MapleFE/test/typescript/unit_tests/classFactory.ts.result b/src/MapleFE/test/typescript/unit_tests/classFactory.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..cce1551435250ee21f4aa440a66ef697e6288c8f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/classFactory.ts.result @@ -0,0 +1,43 @@ +Matched 21 tokens. +Matched 25 tokens. +Matched 66 tokens. +Matched 70 tokens. +Matched 79 tokens. +============= Module =========== +== Sub Tree == + type Constructor = new (args) -> +== Sub Tree == +ts_interface: someStandardInterface { } +== Sub Tree == +func ClassFactory(base) throws: + class GeneratedClass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + + return GeneratedClass + +== Sub Tree == +class someBaseClass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class newClassWithStandardInterface + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/classFactory2.ts b/src/MapleFE/test/typescript/unit_tests/classFactory2.ts new file mode 100644 index 0000000000000000000000000000000000000000..dc4f599ee9ce6c0c27a975d9799aead1a34c61d5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/classFactory2.ts @@ -0,0 +1,10 @@ +type Constructor = new (...args: any[]) => T; +interface someStandardInterface {} +function ClassFactory( + base: Constructor +): Constructor { + class GeneratedClass extends (base as unknown as any) {} + return GeneratedClass as unknown as any; +} +class someBaseClass {} +class newClassWithStandardInterface extends ClassFactory(someBaseClass) {} diff --git a/src/MapleFE/test/typescript/unit_tests/classFactory2.ts.result b/src/MapleFE/test/typescript/unit_tests/classFactory2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..cce1551435250ee21f4aa440a66ef697e6288c8f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/classFactory2.ts.result @@ -0,0 +1,43 @@ +Matched 21 tokens. +Matched 25 tokens. +Matched 66 tokens. +Matched 70 tokens. +Matched 79 tokens. +============= Module =========== +== Sub Tree == + type Constructor = new (args) -> +== Sub Tree == +ts_interface: someStandardInterface { } +== Sub Tree == +func ClassFactory(base) throws: + class GeneratedClass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + + return GeneratedClass + +== Sub Tree == +class someBaseClass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class newClassWithStandardInterface + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/closure-let.ts b/src/MapleFE/test/typescript/unit_tests/closure-let.ts new file mode 100644 index 0000000000000000000000000000000000000000..50f508b22cac66fa3033165004779f505361ece5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/closure-let.ts @@ -0,0 +1,12 @@ +let funcs: (() => void)[] = []; +function initialize() { + var msgs: [string, string] = ["Hello", "World"]; + for (var i = 0; i < msgs.length; i++) { + let msg: string = msgs[i]; + funcs[i] = () => console.log(msg); + } +} +initialize(); +for (var i = 0; i < funcs.length; i++) { + funcs[i](); +} diff --git a/src/MapleFE/test/typescript/unit_tests/closure-let.ts.result b/src/MapleFE/test/typescript/unit_tests/closure-let.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..fa793762dcd6d0452eca806758d0436aa4a7cdb3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/closure-let.ts.result @@ -0,0 +1,21 @@ +Matched 15 tokens. +Matched 79 tokens. +Matched 83 tokens. +Matched 108 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: funcs=[] +== Sub Tree == +func initialize() throws: + js_var Decl: msgs=["Hello","World"] + for ( ) + js_let Decl: msg=msgs[i] + funcs[i] Assign () -> console.log(msg) + + +== Sub Tree == +initialize() +== Sub Tree == +for ( ) + funcs[i]() + diff --git a/src/MapleFE/test/typescript/unit_tests/closure.ts b/src/MapleFE/test/typescript/unit_tests/closure.ts new file mode 100644 index 0000000000000000000000000000000000000000..880b66a5a31e55ab49992d5bb280290469a6b3e4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/closure.ts @@ -0,0 +1,17 @@ +var base: number = 10; + +function counter(private_count: number): () => number { + function increment(): number { + private_count += 1; + return base + private_count; + } + + return increment; +} + +var count: () => number = counter(0); +console.log(count()); // output: 11 +console.log(count()); // output: 12 +var count2: () => number = counter(100); +console.log(count2()); // output: 111 +console.log(count2()); // output: 112 diff --git a/src/MapleFE/test/typescript/unit_tests/closure.ts.result b/src/MapleFE/test/typescript/unit_tests/closure.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..9672af69ac71c39bf99703d626b268cd38c671f6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/closure.ts.result @@ -0,0 +1,31 @@ +Matched 7 tokens. +Matched 41 tokens. +Matched 54 tokens. +Matched 63 tokens. +Matched 72 tokens. +Matched 85 tokens. +Matched 94 tokens. +Matched 103 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: base=10 +== Sub Tree == +func counter(private_count) throws: + func increment() throws: + private_count AddAssign 1 + return base Add private_count + + return increment + +== Sub Tree == +js_var Decl: count=counter(0) +== Sub Tree == +console.log(count()) +== Sub Tree == +console.log(count()) +== Sub Tree == +js_var Decl: count2=counter(100) +== Sub Tree == +console.log(count2()) +== Sub Tree == +console.log(count2()) diff --git a/src/MapleFE/test/typescript/unit_tests/comma.ts b/src/MapleFE/test/typescript/unit_tests/comma.ts new file mode 100644 index 0000000000000000000000000000000000000000..e2da02e7bce092263500ab2019fe72e2aa446074 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/comma.ts @@ -0,0 +1,9 @@ +var arr: number[] = [7, 4, 5, 9, 2, 8, 1, 6, 3]; +var sum: number = 0; +var i; +var len; +(i = 0), (len = arr.length); +for (; i < len; ++i) { + sum += arr[i]; +} +console.log(sum); diff --git a/src/MapleFE/test/typescript/unit_tests/comma.ts.result b/src/MapleFE/test/typescript/unit_tests/comma.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..228d2770b375c7a582b8f79b54951b5234a6b64d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/comma.ts.result @@ -0,0 +1,26 @@ +Matched 27 tokens. +Matched 34 tokens. +Matched 37 tokens. +Matched 40 tokens. +Matched 54 tokens. +Matched 73 tokens. +Matched 80 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[7,4,5,9,2,8,1,6,3] +== Sub Tree == +js_var Decl: sum=0 +== Sub Tree == +js_var Decl: i +== Sub Tree == +js_var Decl: len +== Sub Tree == +i Assign 0 +== Sub Tree == +len Assign arr.length +== Sub Tree == +for ( ) + sum AddAssign arr[i] + +== Sub Tree == +console.log(sum) diff --git a/src/MapleFE/test/typescript/unit_tests/comma2.ts b/src/MapleFE/test/typescript/unit_tests/comma2.ts new file mode 100644 index 0000000000000000000000000000000000000000..4aec7822ab8bd4b4c1739d29fbaa0a362929bdc0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/comma2.ts @@ -0,0 +1,9 @@ +var arr: number[] = [-1, +4, 5, 9, 2, 8, 1, 6, 3]; +var sum: number = 0; +var i; +var len; +(i = 0), (len = arr.length); +for (; i < len; ++i) { + sum += arr[i]; +} +console.log(sum); diff --git a/src/MapleFE/test/typescript/unit_tests/comma2.ts.result b/src/MapleFE/test/typescript/unit_tests/comma2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6448754f63ebf97c9d608070aaf46a8fcdc8fa15 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/comma2.ts.result @@ -0,0 +1,26 @@ +Matched 27 tokens. +Matched 34 tokens. +Matched 37 tokens. +Matched 40 tokens. +Matched 54 tokens. +Matched 73 tokens. +Matched 80 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[-1,4,5,9,2,8,1,6,3] +== Sub Tree == +js_var Decl: sum=0 +== Sub Tree == +js_var Decl: i +== Sub Tree == +js_var Decl: len +== Sub Tree == +i Assign 0 +== Sub Tree == +len Assign arr.length +== Sub Tree == +for ( ) + sum AddAssign arr[i] + +== Sub Tree == +console.log(sum) diff --git a/src/MapleFE/test/typescript/unit_tests/computed-func-name.ts b/src/MapleFE/test/typescript/unit_tests/computed-func-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..56d7ac01ea9c030c8514c9b7511a2cfe3b78c565 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/computed-func-name.ts @@ -0,0 +1,11 @@ +let prop: string = "foo"; + +class Klass { + [key: string]: () => void; + public [prop]() { + console.log(prop); + } +} + +var obj: Klass = new Klass(); +obj[prop](); diff --git a/src/MapleFE/test/typescript/unit_tests/computed-func-name.ts.result b/src/MapleFE/test/typescript/unit_tests/computed-func-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..820936de5bffb8298c0271c93bf259163fc7ed80 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/computed-func-name.ts.result @@ -0,0 +1,23 @@ +Matched 7 tokens. +Matched 37 tokens. +Matched 47 tokens. +Matched 54 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: prop="foo" +== Sub Tree == +class Klass + Fields: + () -> + Instance Initializer: + Constructors: + Methods: + func () throws: + console.log(prop) + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj[prop]() diff --git a/src/MapleFE/test/typescript/unit_tests/computed-func-name2.js.result b/src/MapleFE/test/typescript/unit_tests/computed-func-name2.js.result new file mode 100644 index 0000000000000000000000000000000000000000..f20041335dcc2d91f460d5dcddf3a16b4830dc12 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/computed-func-name2.js.result @@ -0,0 +1,38 @@ +Matched 5 tokens. +Matched 68 tokens. +Matched 76 tokens. +Matched 83 tokens. +Matched 90 tokens. +Matched 94 tokens. +Matched 102 tokens. +Matched 109 tokens. +Matched 116 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: prop="foo" +== Sub Tree == +js_var Decl: Klass=func () throws: + func Klass() throws: + + Klass.prototype[prop] Assign func () throws: + console.log("prop =",prop) + + Klass.prototype.bar Assign func () throws: + console.log("Function bar()") + + return Klass +() +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj[prop]() +== Sub Tree == +obj["foo"]() +== Sub Tree == +prop Assign "bar" +== Sub Tree == +js_var Decl: obj2=new Klass() +== Sub Tree == +obj2[prop]() +== Sub Tree == +obj2["foo"]() diff --git a/src/MapleFE/test/typescript/unit_tests/computed-func-name2.ts b/src/MapleFE/test/typescript/unit_tests/computed-func-name2.ts new file mode 100644 index 0000000000000000000000000000000000000000..65c6ee4e70f34935d330cc3f9e4cffba10721511 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/computed-func-name2.ts @@ -0,0 +1,20 @@ +let prop: string = "foo"; + +class Klass { + [key: string]: () => void; + public [prop]() { + console.log("prop =", prop); + } + public bar() { + console.log("Function bar()"); + } +} + +var obj: Klass = new Klass(); +obj[prop](); // prop = foo +obj["foo"](); // prop = foo + +prop = "bar"; +var obj2: Klass = new Klass(); +obj2[prop](); // Function bar() +obj2["foo"](); // prop = bar diff --git a/src/MapleFE/test/typescript/unit_tests/computed-func-name2.ts.result b/src/MapleFE/test/typescript/unit_tests/computed-func-name2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..59e2da842e36c91ce29d0aca4700b0de56d05c85 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/computed-func-name2.ts.result @@ -0,0 +1,40 @@ +Matched 7 tokens. +Matched 52 tokens. +Matched 62 tokens. +Matched 69 tokens. +Matched 76 tokens. +Matched 80 tokens. +Matched 90 tokens. +Matched 97 tokens. +Matched 104 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: prop="foo" +== Sub Tree == +class Klass + Fields: + () -> + Instance Initializer: + Constructors: + Methods: + func () throws: + console.log("prop =",prop) + func bar() throws: + console.log("Function bar()") + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj[prop]() +== Sub Tree == +obj["foo"]() +== Sub Tree == +prop Assign "bar" +== Sub Tree == +js_var Decl: obj2=new Klass() +== Sub Tree == +obj2[prop]() +== Sub Tree == +obj2["foo"]() diff --git a/src/MapleFE/test/typescript/unit_tests/computed-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/computed-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..404decc67c4709da9921e7ad00db4c0df0614a50 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/computed-prop-name.ts @@ -0,0 +1,8 @@ +const prop = "flag"; + +class Klass { + public [prop]?: string = "example"; +} + +var obj: Klass = new Klass(); +console.log(obj[prop]); diff --git a/src/MapleFE/test/typescript/unit_tests/computed-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/computed-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..80ebc2aad4aa944c9902c7df182d0d9181efce22 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/computed-prop-name.ts.result @@ -0,0 +1,21 @@ +Matched 5 tokens. +Matched 19 tokens. +Matched 29 tokens. +Matched 39 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: prop="flag" +== Sub Tree == +class Klass + Fields: + [prop] : string + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +console.log(obj[prop]) diff --git a/src/MapleFE/test/typescript/unit_tests/computed-prop-name2.ts b/src/MapleFE/test/typescript/unit_tests/computed-prop-name2.ts new file mode 100644 index 0000000000000000000000000000000000000000..2c9d4f65e21c5494f015a247023c3b6cb6e13709 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/computed-prop-name2.ts @@ -0,0 +1,9 @@ +function func() { + return {[prop] : "abc" }; +} + +var prop: string | number = "my key"; +console.log(func()); +prop = -12.3; +console.log(func()); + diff --git a/src/MapleFE/test/typescript/unit_tests/computed-prop-name2.ts.result b/src/MapleFE/test/typescript/unit_tests/computed-prop-name2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..90b354456c6c4b3fa99e322159ab0f783c088cdc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/computed-prop-name2.ts.result @@ -0,0 +1,18 @@ +Matched 15 tokens. +Matched 24 tokens. +Matched 33 tokens. +Matched 37 tokens. +Matched 46 tokens. +============= Module =========== +== Sub Tree == +func func() throws: + return {[prop] : :"abc"} + +== Sub Tree == +js_var Decl: prop="my key" +== Sub Tree == +console.log(func()) +== Sub Tree == +prop Assign -12.3 +== Sub Tree == +console.log(func()) diff --git a/src/MapleFE/test/typescript/unit_tests/conditional-type.ts b/src/MapleFE/test/typescript/unit_tests/conditional-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..34aeef2a1635e481bd8ac2a3e85c35e65bcba5bf --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/conditional-type.ts @@ -0,0 +1,5 @@ +export type X = A extends true ? any[] : string; + +var x: X = [1, 2, 3]; +var y: X = "abc"; +console.log(x, y); diff --git a/src/MapleFE/test/typescript/unit_tests/conditional-type.ts.result b/src/MapleFE/test/typescript/unit_tests/conditional-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..cc85ca05590b18ccc7942827ca9700dcaecf897e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/conditional-type.ts.result @@ -0,0 +1,13 @@ +Matched 21 tokens. +Matched 37 tokens. +Matched 44 tokens. +Matched 53 tokens. +============= Module =========== +== Sub Tree == +export { type X = A extends true ? prim array-TBD : string} +== Sub Tree == +js_var Decl: x=[1,2,3] +== Sub Tree == +js_var Decl: y="abc" +== Sub Tree == +console.log(x,y) diff --git a/src/MapleFE/test/typescript/unit_tests/conditional-type2.ts b/src/MapleFE/test/typescript/unit_tests/conditional-type2.ts new file mode 100644 index 0000000000000000000000000000000000000000..d0e37de5d617f885f8f06d78b54ef1e3db109b30 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/conditional-type2.ts @@ -0,0 +1 @@ +type Type = { [K in keyof B]: B[K] extends T ? never : K }; diff --git a/src/MapleFE/test/typescript/unit_tests/conditional-type2.ts.result b/src/MapleFE/test/typescript/unit_tests/conditional-type2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..486f6911c9ab3a89fc244803614bfbc34bed6212 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/conditional-type2.ts.result @@ -0,0 +1,4 @@ +Matched 28 tokens. +============= Module =========== +== Sub Tree == + type Type = {[K in keyof B] : B[K] extends T ? never : K } diff --git a/src/MapleFE/test/typescript/unit_tests/conditional-type3.ts b/src/MapleFE/test/typescript/unit_tests/conditional-type3.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ee4d803b9334354adba4c0e0b0182b124bbe60d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/conditional-type3.ts @@ -0,0 +1,2 @@ +type Names = { [K in keyof T]: T[K] extends (...args: Array) => any ? K : never; }[keyof T] & string; +type MyType>> = Required[M] extends (...args: any[]) => any ? string : number; diff --git a/src/MapleFE/test/typescript/unit_tests/conditional-type3.ts.result b/src/MapleFE/test/typescript/unit_tests/conditional-type3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..916713c050178409e45d488605ab3d378df5f608 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/conditional-type3.ts.result @@ -0,0 +1,7 @@ +Matched 43 tokens. +Matched 83 tokens. +============= Module =========== +== Sub Tree == + type Names = intersect = {[K in keyof T] : T[K] extends (args) -> ? K : never }[ keyof T] & string +== Sub Tree == + type MyType = Required[M] extends (args) -> ? string : number diff --git a/src/MapleFE/test/typescript/unit_tests/const-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/const-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..aae109523dd5f3dfa52d66712606f8607a4e2e9f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/const-as-prop-name.ts @@ -0,0 +1,3 @@ +interface IFace { + const: boolean | null; +} diff --git a/src/MapleFE/test/typescript/unit_tests/const-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/const-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..fc72ca5a897a23ab14653ae1e49983a10df33626 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/const-as-prop-name.ts.result @@ -0,0 +1,4 @@ +Matched 10 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {const } diff --git a/src/MapleFE/test/typescript/unit_tests/construct-signature.ts b/src/MapleFE/test/typescript/unit_tests/construct-signature.ts new file mode 100644 index 0000000000000000000000000000000000000000..d74e3ed3bba353b2f62117087add916faa578bda --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/construct-signature.ts @@ -0,0 +1,13 @@ +// https://www.typescriptlang.org/docs/handbook/2/classes.html#abstract-construct-signatures +// used in cocos creator deserialize.ts + +// construct signature using generics +// This creates a type alias for constructors that takes no arguments +type T_Ctor = new () => T; + +interface I_Class extends T_Ctor { + __vals__: string[]; +} + +type AnyCtor = T_Ctor; +type AnyClass = I_Class; diff --git a/src/MapleFE/test/typescript/unit_tests/construct-signature.ts.result b/src/MapleFE/test/typescript/unit_tests/construct-signature.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..716378336f60110d57d3a1d8c2568dd93c4985c4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/construct-signature.ts.result @@ -0,0 +1,13 @@ +Matched 12 tokens. +Matched 30 tokens. +Matched 38 tokens. +Matched 46 tokens. +============= Module =========== +== Sub Tree == + type T_Ctor = new () -> +== Sub Tree == +ts_interface: I_Class {__vals__ } +== Sub Tree == + type AnyCtor = T_Ctor +== Sub Tree == + type AnyClass = I_Class diff --git a/src/MapleFE/test/typescript/unit_tests/constructor-1.ts b/src/MapleFE/test/typescript/unit_tests/constructor-1.ts new file mode 100644 index 0000000000000000000000000000000000000000..637dcf847794cb2d0913102a555b0cc23590715e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/constructor-1.ts @@ -0,0 +1,11 @@ +// Constructor function for Person objects +function Person(first, last, age, eye) { + this.firstName = first; + this.lastName = last; + this.age = age; + this.eyeColor = eye; +} + +//// Create a Person object +var myFather = new Person("John", "Doe", 50, "blue"); +console.log(myFather.age); diff --git a/src/MapleFE/test/typescript/unit_tests/constructor-1.ts.result b/src/MapleFE/test/typescript/unit_tests/constructor-1.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c89f8c461daa73f532e12811afc55542b9cfe116 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/constructor-1.ts.result @@ -0,0 +1,15 @@ +Matched 37 tokens. +Matched 52 tokens. +Matched 61 tokens. +============= Module =========== +== Sub Tree == +func Person(first,last,age,eye) throws: + this.firstName Assign first + this.lastName Assign last + this.age Assign age + this.eyeColor Assign eye + +== Sub Tree == +js_var Decl: myFather=new Person("John","Doe",50,"blue") +== Sub Tree == +console.log(myFather.age) diff --git a/src/MapleFE/test/typescript/unit_tests/constructor-prop.ts b/src/MapleFE/test/typescript/unit_tests/constructor-prop.ts new file mode 100644 index 0000000000000000000000000000000000000000..7bb638b9992913d33a374532397cd45f59711c9b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/constructor-prop.ts @@ -0,0 +1,11 @@ +// object constructor property used in cocos-creator class.ts +function func() {} +let f = new func(); +console.log(f.constructor); +f.constructor.prop1 = 1; +Object.defineProperty(f.constructor, "prop2", { + value: 2, + writable: true, + enumerable: true, +}); +console.log(f.constructor); diff --git a/src/MapleFE/test/typescript/unit_tests/constructor-prop.ts.result b/src/MapleFE/test/typescript/unit_tests/constructor-prop.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..56d9cde7d9d948cc2890f1c64d0dc0c4233a8059 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/constructor-prop.ts.result @@ -0,0 +1,20 @@ +Matched 6 tokens. +Matched 14 tokens. +Matched 23 tokens. +Matched 31 tokens. +Matched 57 tokens. +Matched 66 tokens. +============= Module =========== +== Sub Tree == +func func() throws: + +== Sub Tree == +js_let Decl: f=new func() +== Sub Tree == +console.log(f.constructor) +== Sub Tree == +f.constructor.prop1 Assign 1 +== Sub Tree == +Object.defineProperty(f.constructor,"prop2", {value:2, writable:true, enumerable:true}) +== Sub Tree == +console.log(f.constructor) diff --git a/src/MapleFE/test/typescript/unit_tests/continue-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/continue-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..871a70a35a3315bab7e1c0c06eb8035f6403a3b0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/continue-as-prop-name.ts @@ -0,0 +1,3 @@ +interface IFace { + continue: string; +} diff --git a/src/MapleFE/test/typescript/unit_tests/continue-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/continue-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..fd863b8f4c7b5e3441bc5eb7169e8eeb8eecc51f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/continue-as-prop-name.ts.result @@ -0,0 +1,4 @@ +Matched 8 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {continue } diff --git a/src/MapleFE/test/typescript/unit_tests/continue-stmt.ts b/src/MapleFE/test/typescript/unit_tests/continue-stmt.ts new file mode 100644 index 0000000000000000000000000000000000000000..244d1a8e6ee42a3c7d8038075ab9546a989630f0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/continue-stmt.ts @@ -0,0 +1,8 @@ +for (var i: number = 1; i < 10; ++i) { + if (i < 5) { + console.log(i, " is less than 5"); + continue; + } + if (i == 8) break; + console.log(i, " is greater than 4"); +} diff --git a/src/MapleFE/test/typescript/unit_tests/continue-stmt.ts.result b/src/MapleFE/test/typescript/unit_tests/continue-stmt.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1bd275e2d03beac414c6c52a7ef469cb4814dbe1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/continue-stmt.ts.result @@ -0,0 +1,18 @@ +Matched 54 tokens. +============= Module =========== +== Sub Tree == +for ( ) + cond-branch cond:i LT 5 + true branch : + console.log(i," is less than 5") + continue: + + false branch : + + cond-branch cond:i EQ 8 + true branch : + break: + false branch : + + console.log(i," is greater than 4") + diff --git a/src/MapleFE/test/typescript/unit_tests/ctor-interface.ts b/src/MapleFE/test/typescript/unit_tests/ctor-interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..5a164709fcdbc19a1d481ef07b3de1e13ac54cba --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ctor-interface.ts @@ -0,0 +1,6 @@ +class Klass { + f: number = 123; +} +interface KlassConstructor { + new (): Klass; +} diff --git a/src/MapleFE/test/typescript/unit_tests/ctor-interface.ts.result b/src/MapleFE/test/typescript/unit_tests/ctor-interface.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8bd1120216f391c703ae39114e638d66d319d89d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ctor-interface.ts.result @@ -0,0 +1,16 @@ +Matched 10 tokens. +Matched 20 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + f=123 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +ts_interface: KlassConstructor {func () throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/ctor-signature.ts b/src/MapleFE/test/typescript/unit_tests/ctor-signature.ts new file mode 100644 index 0000000000000000000000000000000000000000..90c39ba9443c1bee72e1699e6143f40853ca36b0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ctor-signature.ts @@ -0,0 +1,21 @@ +interface IFace { + name: string; +} + +interface ICtor { + new(name: string): IFace; +} + +class Car implements IFace { + name: string; + constructor(n: string) { + this.name = n; + } +} + +function carFactory(myClass: ICtor, name: string) { + return new myClass(name); +} + +let car = carFactory(Car, "myCar"); +console.log(car); diff --git a/src/MapleFE/test/typescript/unit_tests/ctor-signature.ts.result b/src/MapleFE/test/typescript/unit_tests/ctor-signature.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..931c9a50452fa3eeeff76328cbc63b4a65cbec00 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ctor-signature.ts.result @@ -0,0 +1,32 @@ +Matched 8 tokens. +Matched 21 tokens. +Matched 45 tokens. +Matched 65 tokens. +Matched 75 tokens. +Matched 82 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {name } +== Sub Tree == +ts_interface: ICtor {func (name) throws: + } +== Sub Tree == +class Car + Fields: + name + Instance Initializer: + Constructors: + constructor (n) throws: + this.name Assign n + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func carFactory(myClass,name) throws: + return new myClass(name) + +== Sub Tree == +js_let Decl: car=carFactory(Car,"myCar") +== Sub Tree == +console.log(car) diff --git a/src/MapleFE/test/typescript/unit_tests/ctor-with-function.ts b/src/MapleFE/test/typescript/unit_tests/ctor-with-function.ts new file mode 100644 index 0000000000000000000000000000000000000000..62f6a90078fb43af2a843e2a91f3380fd0bc23c8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ctor-with-function.ts @@ -0,0 +1,11 @@ +//const obj = new Pool(() => ({ subModel: null!, passIdx: -1, dynamicOffsets: [], lights: [] }), 16); +class Klass { + func: () => any; + num: number; + constructor(f: () => any, n: number) { + this.func = f; + this.num = n; + } +} +const obj = new Klass(() => ({ n: 1 }), 16); +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/ctor-with-function.ts.result b/src/MapleFE/test/typescript/unit_tests/ctor-with-function.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3a5f7caf3a3e905858b6f3eb3cf55d534f295c90 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ctor-with-function.ts.result @@ -0,0 +1,21 @@ +Matched 42 tokens. +Matched 62 tokens. +Matched 69 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + func num + Instance Initializer: + Constructors: + constructor (f,n) throws: + this.func Assign f + this.num Assign n + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_const Decl: obj=new Klass(() -> {n:1},16) +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/ctor-with-function2.ts b/src/MapleFE/test/typescript/unit_tests/ctor-with-function2.ts new file mode 100644 index 0000000000000000000000000000000000000000..d05c98b56d6a49618409cd6042c58978fea10ea3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ctor-with-function2.ts @@ -0,0 +1,10 @@ +class Klass { + func: () => any; + num: number; + constructor(f: () => any, n: number) { + this.func = f; + this.num = n; + } +} +const obj = new Klass(() => { n: 1 }, 16); +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/ctor-with-function2.ts.result b/src/MapleFE/test/typescript/unit_tests/ctor-with-function2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ec43f0446f217e607308eaf652d9b396185b269e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ctor-with-function2.ts.result @@ -0,0 +1,21 @@ +Matched 42 tokens. +Matched 60 tokens. +Matched 67 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + func num + Instance Initializer: + Constructors: + constructor (f,n) throws: + this.func Assign f + this.num Assign n + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_const Decl: obj=new Klass(() -> {n:1},16) +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/debugger.ts b/src/MapleFE/test/typescript/unit_tests/debugger.ts new file mode 100644 index 0000000000000000000000000000000000000000..6131fe0b02277946b4b75a16da0e37a498da8959 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/debugger.ts @@ -0,0 +1,3 @@ +if (true) { + debugger; +} diff --git a/src/MapleFE/test/typescript/unit_tests/debugger.ts.result b/src/MapleFE/test/typescript/unit_tests/debugger.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8aedf7ee087ab5ddb5ef28cf23a4ff28b5d089a5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/debugger.ts.result @@ -0,0 +1,8 @@ +Matched 8 tokens. +============= Module =========== +== Sub Tree == +cond-branch cond:true +true branch : + debugger +false branch : + diff --git a/src/MapleFE/test/typescript/unit_tests/declare-class-with-ctor.ts b/src/MapleFE/test/typescript/unit_tests/declare-class-with-ctor.ts new file mode 100644 index 0000000000000000000000000000000000000000..72198abe66005438467d2f1bc5353b2aeeb465a1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-class-with-ctor.ts @@ -0,0 +1,8 @@ +declare class Klass { + constructor (name: string) + name: string; +} +declare class Klass2 { + constructor (name: string); + name: string; +} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-class-with-ctor.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-class-with-ctor.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..36dd5d810502e717caa8e6933edbd9b29e67faa2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-class-with-ctor.ts.result @@ -0,0 +1,25 @@ +Matched 15 tokens. +Matched 31 tokens. +============= Module =========== +== Sub Tree == +declare class Klass + Fields: + name + Instance Initializer: + Constructors: + constructor (name) throws: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +declare class Klass2 + Fields: + name + Instance Initializer: + Constructors: + constructor (name) throws: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/declare-class.ts b/src/MapleFE/test/typescript/unit_tests/declare-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..27a8f6bbd9af48aee64a160e71944ab2155b04a6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-class.ts @@ -0,0 +1,3 @@ +export declare class Klass { + obj: Object; +} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-class.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-class.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c76ea7abe40e06fe503f4fd97f89177e328b861d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-class.ts.result @@ -0,0 +1,12 @@ +Matched 10 tokens. +============= Module =========== +== Sub Tree == +export {declare class Klass + Fields: + obj + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: +} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-const.ts b/src/MapleFE/test/typescript/unit_tests/declare-const.ts new file mode 100644 index 0000000000000000000000000000000000000000..7e6a6408d6e237f09d26567cc0a6353e0fcd734f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-const.ts @@ -0,0 +1 @@ +declare const x: any; diff --git a/src/MapleFE/test/typescript/unit_tests/declare-const.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-const.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..66fb19511fe51abeb85b400a83ec8720eb9efd82 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-const.ts.result @@ -0,0 +1,4 @@ +Matched 6 tokens. +============= Module =========== +== Sub Tree == +declare js_const Decl: x diff --git a/src/MapleFE/test/typescript/unit_tests/declare-global.ts b/src/MapleFE/test/typescript/unit_tests/declare-global.ts new file mode 100644 index 0000000000000000000000000000000000000000..7aaeaa55cd472a2f79fbc1b88a9af9415926a914 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-global.ts @@ -0,0 +1,5 @@ +// declare an interface in the global scope +declare global { + interface IFace { name: string; } +} +export var obj: IFace = { name: "abc" }; diff --git a/src/MapleFE/test/typescript/unit_tests/declare-global.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-global.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..83c9e73a4321b788057672bccc87565eacbd3e68 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-global.ts.result @@ -0,0 +1,7 @@ +Matched 12 tokens. +Matched 24 tokens. +============= Module =========== +== Sub Tree == +declare ts_interface: IFace {name } +== Sub Tree == +export {js_var Decl: obj= {name:"abc"}} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-global2.ts b/src/MapleFE/test/typescript/unit_tests/declare-global2.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae33b890770a09d1deeb7d5980b37794a9cb074a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-global2.ts @@ -0,0 +1,6 @@ +export interface IFace { } + +declare global { + const flag1: boolean; + const flag2: boolean; +} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-global2.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-global2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..28811e1ed540364440cad01e257bf91dedc0ac8a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-global2.ts.result @@ -0,0 +1,7 @@ +Matched 5 tokens. +Matched 19 tokens. +============= Module =========== +== Sub Tree == +export {ts_interface: IFace { }} +== Sub Tree == +declare js_const Decl: flag1js_const Decl: flag2 diff --git a/src/MapleFE/test/typescript/unit_tests/declare-interface.ts b/src/MapleFE/test/typescript/unit_tests/declare-interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..060b2debb46a0a15920a4e5f29a9dcd5f1f28d5c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-interface.ts @@ -0,0 +1,4 @@ +declare interface IFace { + readonly n: number; + [index: number]: T; +} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-interface.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-interface.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a8cc988e84ff89312aaa153d057346772352ffbe --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-interface.ts.result @@ -0,0 +1,4 @@ +Matched 21 tokens. +============= Module =========== +== Sub Tree == +declare ts_interface: IFace {numeric index type: Tn } diff --git a/src/MapleFE/test/typescript/unit_tests/declare-module.ts b/src/MapleFE/test/typescript/unit_tests/declare-module.ts new file mode 100644 index 0000000000000000000000000000000000000000..85bf919ac9bb5130c82f5e667f7b08351e746162 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-module.ts @@ -0,0 +1,3 @@ +declare module Module { + function func(s: string): string; +} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-module.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-module.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..91105793f7e036902b7a378d583bcc2b551d6b02 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-module.ts.result @@ -0,0 +1,8 @@ +Matched 15 tokens. +============= Module =========== +== Sub Tree == +declare ============= Module =========== +== Sub Tree == +func func(s) throws: + + diff --git a/src/MapleFE/test/typescript/unit_tests/declare-module2.ts b/src/MapleFE/test/typescript/unit_tests/declare-module2.ts new file mode 100644 index 0000000000000000000000000000000000000000..be0850e00dc80128aecea7f16248ddf395db0da6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-module2.ts @@ -0,0 +1,4 @@ +declare module "FuncModule" { + const func: () => boolean; + export = func; +} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-module2.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-module2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f033bda5aa548b7d452da14a315493b66c978793 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-module2.ts.result @@ -0,0 +1,9 @@ +Matched 17 tokens. +============= Module =========== +== Sub Tree == +declare ============= Module =========== +== Sub Tree == +js_const Decl: func +== Sub Tree == +export { SINGLE func} + diff --git a/src/MapleFE/test/typescript/unit_tests/declare-module3.ts b/src/MapleFE/test/typescript/unit_tests/declare-module3.ts new file mode 100644 index 0000000000000000000000000000000000000000..c637d62d2f948ec9afe5a190f08889e38ec31158 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-module3.ts @@ -0,0 +1 @@ +declare module "mod/runtime" {} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-module3.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-module3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..de33fd5c99bb131cbcd4bf76152e63a0b73c3e80 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-module3.ts.result @@ -0,0 +1,5 @@ +Matched 5 tokens. +============= Module =========== +== Sub Tree == +declare ============= Module =========== + diff --git a/src/MapleFE/test/typescript/unit_tests/declare-module4.ts b/src/MapleFE/test/typescript/unit_tests/declare-module4.ts new file mode 100644 index 0000000000000000000000000000000000000000..931c5ee5519199619f90912bc78c8154bca0b814 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-module4.ts @@ -0,0 +1,8 @@ +export var x: number; +declare global { + module Module { + interface IFace { + expect: string; + } + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-module4.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-module4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5a444572ab6cbf9a1af96a66f9729b7f5440adc9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-module4.ts.result @@ -0,0 +1,10 @@ +Matched 6 tokens. +Matched 22 tokens. +============= Module =========== +== Sub Tree == +export {js_var Decl: x} +== Sub Tree == +declare ============= Module =========== +== Sub Tree == +ts_interface: IFace {expect } + diff --git a/src/MapleFE/test/typescript/unit_tests/declare-namespace.ts b/src/MapleFE/test/typescript/unit_tests/declare-namespace.ts new file mode 100644 index 0000000000000000000000000000000000000000..d5204a4e29c0928d15c36a7ded51a62d8264609d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-namespace.ts @@ -0,0 +1,9 @@ +export function func(opt?: func.Opts) { + opt = opt || {}; +} + +export declare namespace func { + export interface Opts { + debug?: boolean; + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-namespace.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-namespace.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..eeca548ef01d5c27ef2dda4be85fb6397e5024c7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-namespace.ts.result @@ -0,0 +1,11 @@ +Matched 20 tokens. +Matched 36 tokens. +============= Module =========== +== Sub Tree == +export {func func(opt?) throws: + opt Assign opt Lor {} +} +== Sub Tree == +export {declare namespace func + export {ts_interface: Opts {debug? }} +} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-namespace2.ts b/src/MapleFE/test/typescript/unit_tests/declare-namespace2.ts new file mode 100644 index 0000000000000000000000000000000000000000..d8d87c5b390936a736cd477c1794dff509f3d231 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-namespace2.ts @@ -0,0 +1 @@ +declare namespace NS {} diff --git a/src/MapleFE/test/typescript/unit_tests/declare-namespace2.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-namespace2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..681699f524d5d233a2feff9d5af1adbd54a40427 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-namespace2.ts.result @@ -0,0 +1,5 @@ +Matched 5 tokens. +============= Module =========== +== Sub Tree == +declare namespace NS + diff --git a/src/MapleFE/test/typescript/unit_tests/declare-var.ts b/src/MapleFE/test/typescript/unit_tests/declare-var.ts new file mode 100644 index 0000000000000000000000000000000000000000..bcf2fa2a5ee28208c9c68fb04950c4003b82fcb0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-var.ts @@ -0,0 +1 @@ +declare var x: number; diff --git a/src/MapleFE/test/typescript/unit_tests/declare-var.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-var.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..707d1adb0c6a26a07d99595f40cb86d5bd00d667 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-var.ts.result @@ -0,0 +1,4 @@ +Matched 6 tokens. +============= Module =========== +== Sub Tree == +declare js_var Decl: x diff --git a/src/MapleFE/test/typescript/unit_tests/declare-var2.ts b/src/MapleFE/test/typescript/unit_tests/declare-var2.ts new file mode 100644 index 0000000000000000000000000000000000000000..7814fc2d7009074f76edbbcda8d1485b4dda6b21 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-var2.ts @@ -0,0 +1 @@ +declare var v: JSON; diff --git a/src/MapleFE/test/typescript/unit_tests/declare-var2.ts.result b/src/MapleFE/test/typescript/unit_tests/declare-var2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..87a5be12d2f9c654e9e232e54d6e857b716f706d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/declare-var2.ts.result @@ -0,0 +1,4 @@ +Matched 6 tokens. +============= Module =========== +== Sub Tree == +declare js_var Decl: v diff --git a/src/MapleFE/test/typescript/unit_tests/deco-module.ts b/src/MapleFE/test/typescript/unit_tests/deco-module.ts new file mode 100644 index 0000000000000000000000000000000000000000..299de200d618a6e79b5f819d838ac09d006ee326 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/deco-module.ts @@ -0,0 +1,5 @@ +export function prop_deco(msg: string) { + return function (target: any, name: string) { + console.log("Accessed", name, msg, target); + }; +} diff --git a/src/MapleFE/test/typescript/unit_tests/deco-module.ts.result b/src/MapleFE/test/typescript/unit_tests/deco-module.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..726b8d368545a27168f9496a7f13290e26d0a749 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/deco-module.ts.result @@ -0,0 +1,8 @@ +Matched 37 tokens. +============= Module =========== +== Sub Tree == +export {func prop_deco(msg) throws: + return func (target,name) throws: + console.log("Accessed",name,msg,target) + +} diff --git a/src/MapleFE/test/typescript/unit_tests/default-prop.ts b/src/MapleFE/test/typescript/unit_tests/default-prop.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f78feb3c49a972a8426ecac3a2f41a050c1cabb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/default-prop.ts @@ -0,0 +1,4 @@ +const obj = { + default: {}, +}; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/default-prop.ts.result b/src/MapleFE/test/typescript/unit_tests/default-prop.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3a075fd8c45ec326c8d8352eccd399c55a7d1745 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/default-prop.ts.result @@ -0,0 +1,7 @@ +Matched 11 tokens. +Matched 18 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {default: {}} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/define-prop-get-set.ts b/src/MapleFE/test/typescript/unit_tests/define-prop-get-set.ts new file mode 100644 index 0000000000000000000000000000000000000000..a99c1546b9bbfb138839726cc96a27d95a89382f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/define-prop-get-set.ts @@ -0,0 +1,16 @@ +var obj = { x: "abc", name: "" }; + +Object.defineProperty(obj, "name", { + get(this) { + console.log("Return obj.x"); + return this["x"]; + }, + set(this, val: any) { + console.log(`Set obj.x to '${val}'`); + this["x"] = val; + }, + enumerable: false, +}); + +obj.name = "def"; +console.log(obj, obj.name); diff --git a/src/MapleFE/test/typescript/unit_tests/define-prop-get-set.ts.result b/src/MapleFE/test/typescript/unit_tests/define-prop-get-set.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..180a0342af27f281ec3ae9cad50d23c2a111b34b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/define-prop-get-set.ts.result @@ -0,0 +1,20 @@ +Matched 13 tokens. +Matched 74 tokens. +Matched 80 tokens. +Matched 91 tokens. +Matched 92 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: obj= {x:"abc", name:""} +== Sub Tree == +Object.defineProperty(obj,"name", {get:func get(this) throws: + console.log("Return obj.x") + return this["x"] +, set:func set(this,val) throws: + console.log( template-literal: "Set obj.x to '",val,"'",NULL) + this["x"] Assign val +, enumerable:false}) +== Sub Tree == +obj.name Assign "def" +== Sub Tree == +console.log(obj,obj.name) diff --git a/src/MapleFE/test/typescript/unit_tests/delete-func.ts b/src/MapleFE/test/typescript/unit_tests/delete-func.ts new file mode 100644 index 0000000000000000000000000000000000000000..a5e6cf1014b2bfb358fb561639342da827b5a9a7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/delete-func.ts @@ -0,0 +1,8 @@ +class Klass { + public delete(s: string) { + console.log("delete " + s); + } +} + +var obj: Klass = new Klass(); +obj.delete("key"); diff --git a/src/MapleFE/test/typescript/unit_tests/delete-func.ts.result b/src/MapleFE/test/typescript/unit_tests/delete-func.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..51eeece4050078672c37fa0780d657d6b6820b5b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/delete-func.ts.result @@ -0,0 +1,20 @@ +Matched 22 tokens. +Matched 32 tokens. +Matched 39 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + func delete(s) throws: + console.log("delete " Add s) + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj.delete("key") diff --git a/src/MapleFE/test/typescript/unit_tests/delete.ts b/src/MapleFE/test/typescript/unit_tests/delete.ts new file mode 100644 index 0000000000000000000000000000000000000000..0af59349c38d6457823f8186a075bb398696b6f4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/delete.ts @@ -0,0 +1,5 @@ +class A { + a?: number = 0; +} +var x: A = new A(); +delete x.a; diff --git a/src/MapleFE/test/typescript/unit_tests/delete.ts.result b/src/MapleFE/test/typescript/unit_tests/delete.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..50d626c96650493b032c8df2d858fffff665357d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/delete.ts.result @@ -0,0 +1,18 @@ +Matched 11 tokens. +Matched 21 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + a?=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: x=new A() +== Sub Tree == + delete x.a diff --git a/src/MapleFE/test/typescript/unit_tests/direct-fd.ts b/src/MapleFE/test/typescript/unit_tests/direct-fd.ts new file mode 100644 index 0000000000000000000000000000000000000000..40cbd1365d05c7c731f74fd5087e20a48b443ddd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/direct-fd.ts @@ -0,0 +1,8 @@ +class Foo { + public f1: number = 0; +} + +var bar : Foo = new Foo; +bar.f1 = 456; +console.log(bar); + diff --git a/src/MapleFE/test/typescript/unit_tests/direct-fd.ts.result b/src/MapleFE/test/typescript/unit_tests/direct-fd.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..005189032378f76e6db9609a96ff8b76934a182b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/direct-fd.ts.result @@ -0,0 +1,21 @@ +Matched 11 tokens. +Matched 19 tokens. +Matched 25 tokens. +Matched 32 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + f1=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: bar=new Foo() +== Sub Tree == +bar.f1 Assign 456 +== Sub Tree == +console.log(bar) diff --git a/src/MapleFE/test/typescript/unit_tests/do-while-stmt.ts b/src/MapleFE/test/typescript/unit_tests/do-while-stmt.ts new file mode 100644 index 0000000000000000000000000000000000000000..9c119e130d4a78251f48c1d8ea218f0f412fb8c5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/do-while-stmt.ts @@ -0,0 +1,5 @@ +var k: number = 1; +do { + console.log(k); + k++; +} while (k < 10); diff --git a/src/MapleFE/test/typescript/unit_tests/do-while-stmt.ts.result b/src/MapleFE/test/typescript/unit_tests/do-while-stmt.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..200759d76d99509b98327e1470263451e213cebd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/do-while-stmt.ts.result @@ -0,0 +1,10 @@ +Matched 7 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: k=1 +== Sub Tree == +do console.log(k) + k Inc + +while k LT 10 diff --git a/src/MapleFE/test/typescript/unit_tests/dynamic-import.ts b/src/MapleFE/test/typescript/unit_tests/dynamic-import.ts new file mode 100644 index 0000000000000000000000000000000000000000..cd79bcfcd82568e002d54c387a4e329bbd542aeb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/dynamic-import.ts @@ -0,0 +1,2 @@ +const x: { f: typeof import("./M") } = {} as any; +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/dynamic-import.ts.result b/src/MapleFE/test/typescript/unit_tests/dynamic-import.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ed15e7f81b3b3cda11b07f941dcaa9693cd01bc5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/dynamic-import.ts.result @@ -0,0 +1,7 @@ +Matched 18 tokens. +Matched 25 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: x= {} +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/else-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/else-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..dd9965a57cfc8382a32c2ae6a50b371fa371ef6d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/else-as-prop-name.ts @@ -0,0 +1,6 @@ +class Klass { + else: number = 0; +} + +var obj: Klass = new Klass(); +console.log(obj, obj.else); diff --git a/src/MapleFE/test/typescript/unit_tests/else-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/else-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b14f7e7d22946f638f60fdd316acf89110a295ee --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/else-as-prop-name.ts.result @@ -0,0 +1,18 @@ +Matched 10 tokens. +Matched 20 tokens. +Matched 31 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + else=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +console.log(obj,obj.else) diff --git a/src/MapleFE/test/typescript/unit_tests/empty-func.ts b/src/MapleFE/test/typescript/unit_tests/empty-func.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ec57fbdc559363f006b0ec83652cbd4f3b3f9d4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/empty-func.ts @@ -0,0 +1 @@ +function func() {} diff --git a/src/MapleFE/test/typescript/unit_tests/empty-func.ts.result b/src/MapleFE/test/typescript/unit_tests/empty-func.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..159c2abca77a363e9b562cdb2ddab1f732415556 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/empty-func.ts.result @@ -0,0 +1,5 @@ +Matched 6 tokens. +============= Module =========== +== Sub Tree == +func func() throws: + diff --git a/src/MapleFE/test/typescript/unit_tests/enum-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/enum-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..413d5b35d0e89424ac23ff66e6a4efd6189b61dc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum-as-prop-name.ts @@ -0,0 +1,3 @@ +interface IFace { + enum?: string[]; +} diff --git a/src/MapleFE/test/typescript/unit_tests/enum-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/enum-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b672b9baab75017a47b4172777339453b4c412e5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum-as-prop-name.ts.result @@ -0,0 +1,4 @@ +Matched 11 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {enum? } diff --git a/src/MapleFE/test/typescript/unit_tests/enum-function-prop.ts b/src/MapleFE/test/typescript/unit_tests/enum-function-prop.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ae2919fc6f049c73b137475db570fa7db557201 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum-function-prop.ts @@ -0,0 +1,5 @@ +enum E { + function = "function" +} + +console.log(E.function); diff --git a/src/MapleFE/test/typescript/unit_tests/enum-function-prop.ts.result b/src/MapleFE/test/typescript/unit_tests/enum-function-prop.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f5d20c02151036ace2241ae8da485a3176253572 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum-function-prop.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 16 tokens. +============= Module =========== +== Sub Tree == +ts_enum: E {function="function" } +== Sub Tree == +console.log(E.function) diff --git a/src/MapleFE/test/typescript/unit_tests/enum-function-prop2.ts b/src/MapleFE/test/typescript/unit_tests/enum-function-prop2.ts new file mode 100644 index 0000000000000000000000000000000000000000..eb2fbd1b7509805546537c8bb2a9e76bec13edcd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum-function-prop2.ts @@ -0,0 +1,5 @@ +enum E { + function = "function" +} + +type T = Array; diff --git a/src/MapleFE/test/typescript/unit_tests/enum-function-prop2.ts.result b/src/MapleFE/test/typescript/unit_tests/enum-function-prop2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5f5b36d334dc04882bcaffa84e426c82787fc0ea --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum-function-prop2.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 17 tokens. +============= Module =========== +== Sub Tree == +ts_enum: E {function="function" } +== Sub Tree == + type T = Array diff --git a/src/MapleFE/test/typescript/unit_tests/enum.ts b/src/MapleFE/test/typescript/unit_tests/enum.ts new file mode 100644 index 0000000000000000000000000000000000000000..29e2a13ca0ffa3abb8e0180b146007acae389fcd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum.ts @@ -0,0 +1,7 @@ +enum ET { + TOP = "top", + BOTTOM = "bottom", +} + +let et = ET.TOP; +console.log(et); diff --git a/src/MapleFE/test/typescript/unit_tests/enum.ts.result b/src/MapleFE/test/typescript/unit_tests/enum.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e4afff30c02415e10dfeab2420a63675b1286d5d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum.ts.result @@ -0,0 +1,10 @@ +Matched 12 tokens. +Matched 19 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +ts_enum: ET {TOP="top";BOTTOM="bottom" } +== Sub Tree == +js_let Decl: et=ET.TOP +== Sub Tree == +console.log(et) diff --git a/src/MapleFE/test/typescript/unit_tests/enum2.ts b/src/MapleFE/test/typescript/unit_tests/enum2.ts new file mode 100644 index 0000000000000000000000000000000000000000..430229eff9a22d1754690fbb81837d8989f7f88c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum2.ts @@ -0,0 +1,7 @@ +export enum ET { + TOP = 1 << 0, + BOTTOM = 1 << 1, +} + +let et = ET.TOP; +console.log(et); diff --git a/src/MapleFE/test/typescript/unit_tests/enum2.ts.result b/src/MapleFE/test/typescript/unit_tests/enum2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..60b0b04f50f3e6fa98ce66861d33f92b5ee837cd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum2.ts.result @@ -0,0 +1,10 @@ +Matched 17 tokens. +Matched 24 tokens. +Matched 31 tokens. +============= Module =========== +== Sub Tree == +export {ts_enum: ET {TOP=1 Shl 0;BOTTOM=1 Shl 1 }} +== Sub Tree == +js_let Decl: et=ET.TOP +== Sub Tree == +console.log(et) diff --git a/src/MapleFE/test/typescript/unit_tests/enum3.ts b/src/MapleFE/test/typescript/unit_tests/enum3.ts new file mode 100644 index 0000000000000000000000000000000000000000..4e588449ceda7d493db9e7cf6d6afbb083195dcf --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum3.ts @@ -0,0 +1,3 @@ +enum E { + "" = 0, +} diff --git a/src/MapleFE/test/typescript/unit_tests/enum3.ts.result b/src/MapleFE/test/typescript/unit_tests/enum3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b9c2c344fee749b41b2484ce4597c74d1c0eb511 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum3.ts.result @@ -0,0 +1,4 @@ +Matched 8 tokens. +============= Module =========== +== Sub Tree == +ts_enum: E {"" = 0 } diff --git a/src/MapleFE/test/typescript/unit_tests/enum4.ts b/src/MapleFE/test/typescript/unit_tests/enum4.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f096dc9a006ef37a5cf17f7361a2d3df629cc20 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum4.ts @@ -0,0 +1,4 @@ +export declare enum ET { + TOP = "top", + BOTTOM = "bottom", +} diff --git a/src/MapleFE/test/typescript/unit_tests/enum4.ts.result b/src/MapleFE/test/typescript/unit_tests/enum4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..701cda2962b78fae780c7c8bec9d2783dcdf9577 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/enum4.ts.result @@ -0,0 +1,4 @@ +Matched 14 tokens. +============= Module =========== +== Sub Tree == +export {declare ts_enum: ET {TOP="top";BOTTOM="bottom" }} diff --git a/src/MapleFE/test/typescript/unit_tests/exp.ts b/src/MapleFE/test/typescript/unit_tests/exp.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2cade21f7e97e57720bd9f96be46380b049b6ab --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/exp.ts @@ -0,0 +1,2 @@ +var x: number = 10; +console.log(x ** (2 ** 3)); diff --git a/src/MapleFE/test/typescript/unit_tests/exp.ts.result b/src/MapleFE/test/typescript/unit_tests/exp.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ef802eb258e4623a51b6e0cedae277248f20db02 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/exp.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 20 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=10 +== Sub Tree == +console.log(x Exp 2 Exp 3) diff --git a/src/MapleFE/test/typescript/unit_tests/export-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/export-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..7d2c55a8dd22d80698da49c821b1b1e390e1dc53 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-as-prop-name.ts @@ -0,0 +1,6 @@ +interface IFace { + export() : string; +} + +var obj: IFace = { export: () => "Export" }; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/export-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/export-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..10708b76b405f378ac63a0d03d00b1a2f35e633c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-as-prop-name.ts.result @@ -0,0 +1,11 @@ +Matched 10 tokens. +Matched 24 tokens. +Matched 31 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {func export() throws: + } +== Sub Tree == +js_var Decl: obj= {export:() -> "Export"} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/export-as-prop-name2.ts b/src/MapleFE/test/typescript/unit_tests/export-as-prop-name2.ts new file mode 100644 index 0000000000000000000000000000000000000000..c1a13a308c4f6208f4a3552767c3606bd8678b25 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-as-prop-name2.ts @@ -0,0 +1,3 @@ +declare class Klass { + export(arg: number): string; +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-as-prop-name2.ts.result b/src/MapleFE/test/typescript/unit_tests/export-as-prop-name2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5102c905c5b420e51d3ec11a98a2ec30bba2f100 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-as-prop-name2.ts.result @@ -0,0 +1,13 @@ +Matched 14 tokens. +============= Module =========== +== Sub Tree == +declare class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + func export(arg) throws: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/export-as-super.ts b/src/MapleFE/test/typescript/unit_tests/export-as-super.ts new file mode 100644 index 0000000000000000000000000000000000000000..3eb9fb29cce720932f685e6b8f16bba1d86a30ba --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-as-super.ts @@ -0,0 +1,2 @@ +declare function func(): number; +export { func as super }; diff --git a/src/MapleFE/test/typescript/unit_tests/export-as-super.ts.result b/src/MapleFE/test/typescript/unit_tests/export-as-super.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..04c1408eb3d4b3dfd856cd0f5efe2f91ddaad437 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-as-super.ts.result @@ -0,0 +1,8 @@ +Matched 8 tokens. +Matched 15 tokens. +============= Module =========== +== Sub Tree == +declare func func() throws: + +== Sub Tree == +export {func as super} diff --git a/src/MapleFE/test/typescript/unit_tests/export-class.ts b/src/MapleFE/test/typescript/unit_tests/export-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..b78a31ce1715a775609bf6539dc0288ee2394ada --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-class.ts @@ -0,0 +1,9 @@ +class Foo { + public f1: number = 0; + private f2: number = 0; + constructor(a: number, b: number) { + this.f1 = a; + this.f2 = b; + } +} +export = Foo; diff --git a/src/MapleFE/test/typescript/unit_tests/export-class.ts.result b/src/MapleFE/test/typescript/unit_tests/export-class.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..63c191f909c73cf2f3f4082df34f7a8c69c08237 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-class.ts.result @@ -0,0 +1,18 @@ +Matched 42 tokens. +Matched 46 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + f1=0 f2=0 + Instance Initializer: + Constructors: + constructor (a,b) throws: + this.f1 Assign a + this.f2 Assign b + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +export { SINGLE Foo} diff --git a/src/MapleFE/test/typescript/unit_tests/export-declare-func.ts b/src/MapleFE/test/typescript/unit_tests/export-declare-func.ts new file mode 100644 index 0000000000000000000000000000000000000000..6be8b9b40d17f990a289fea959b18af8bd5513a1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-declare-func.ts @@ -0,0 +1,2 @@ +export {}; +export declare function func(d: T): T; diff --git a/src/MapleFE/test/typescript/unit_tests/export-declare-func.ts.result b/src/MapleFE/test/typescript/unit_tests/export-declare-func.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2492af15c1738254d462e2f2b09a3d4f010bfae8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-declare-func.ts.result @@ -0,0 +1,8 @@ +Matched 4 tokens. +Matched 19 tokens. +============= Module =========== +== Sub Tree == +export +== Sub Tree == +export {declare func func(d) throws: +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-declare-func2.ts b/src/MapleFE/test/typescript/unit_tests/export-declare-func2.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d8443bba14a4adae8428e7b622ef76747a4a5c9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-declare-func2.ts @@ -0,0 +1 @@ +export declare function isPromise(obj: T | Promise): obj is Promise; diff --git a/src/MapleFE/test/typescript/unit_tests/export-declare-func2.ts.result b/src/MapleFE/test/typescript/unit_tests/export-declare-func2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e0e1b6179a7ec2e907a15cc324b81d428f833719 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-declare-func2.ts.result @@ -0,0 +1,5 @@ +Matched 25 tokens. +============= Module =========== +== Sub Tree == +export {declare func isPromise(obj) throws: +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-deco.ts b/src/MapleFE/test/typescript/unit_tests/export-deco.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff6123a355ac8cbb85bcbc104cb7ac865240f837 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-deco.ts @@ -0,0 +1,8 @@ +function class_deco(ctor: Function): void { + console.log("Class constructor is :", ctor); +} + +@class_deco +export class Foo { + readonly foo_var: number = 1; +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-deco.ts.result b/src/MapleFE/test/typescript/unit_tests/export-deco.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5c959e46ace88c7ac6ac00ead8c6d4533debd4e0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-deco.ts.result @@ -0,0 +1,17 @@ +Matched 20 tokens. +Matched 34 tokens. +============= Module =========== +== Sub Tree == +func class_deco(ctor) throws: + console.log("Class constructor is :",ctor) + +== Sub Tree == +export {class Foo + Fields: + foo_var=1 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-default-as.ts b/src/MapleFE/test/typescript/unit_tests/export-default-as.ts new file mode 100644 index 0000000000000000000000000000000000000000..b4a0da2eac8654d28ca6e4e4c6c49282ec3261d8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-default-as.ts @@ -0,0 +1 @@ +export { default as X } from "./M"; diff --git a/src/MapleFE/test/typescript/unit_tests/export-default-as.ts.result b/src/MapleFE/test/typescript/unit_tests/export-default-as.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3aa8d5dfc340238c8a13ef36bf8f1fd6c99be5af --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-default-as.ts.result @@ -0,0 +1,4 @@ +Matched 9 tokens. +============= Module =========== +== Sub Tree == +export {default as X} "./M" diff --git a/src/MapleFE/test/typescript/unit_tests/export-default-as2.ts b/src/MapleFE/test/typescript/unit_tests/export-default-as2.ts new file mode 100644 index 0000000000000000000000000000000000000000..497f6885918126ec8beea47e47380b8f502f5638 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-default-as2.ts @@ -0,0 +1 @@ +export { default as default } from "./M"; diff --git a/src/MapleFE/test/typescript/unit_tests/export-default-as2.ts.result b/src/MapleFE/test/typescript/unit_tests/export-default-as2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..aff9533e078dcc35dabcffafcf7ab756b6fc2e70 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-default-as2.ts.result @@ -0,0 +1,4 @@ +Matched 9 tokens. +============= Module =========== +== Sub Tree == +export {default as default} "./M" diff --git a/src/MapleFE/test/typescript/unit_tests/export-default-class.ts b/src/MapleFE/test/typescript/unit_tests/export-default-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..387684c291bd160ef90a476efdc1d6aec287e6f7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-default-class.ts @@ -0,0 +1,5 @@ +export default class { + f1: number = 0; + f2: string = ""; +} + diff --git a/src/MapleFE/test/typescript/unit_tests/export-default-class.ts.result b/src/MapleFE/test/typescript/unit_tests/export-default-class.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..623d94e2a205f45382ad5cb95201b3b8dbf8bd9e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-default-class.ts.result @@ -0,0 +1,12 @@ +Matched 17 tokens. +============= Module =========== +== Sub Tree == +export { default as class + Fields: + f1=0 f2="" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-default-function.ts b/src/MapleFE/test/typescript/unit_tests/export-default-function.ts new file mode 100644 index 0000000000000000000000000000000000000000..0ee9984fb9fd9147ff9fc7f5a253fb2c97c7c555 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-default-function.ts @@ -0,0 +1,3 @@ +export default function (arg: T): T[] { + return [arg]; +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-default-function.ts.result b/src/MapleFE/test/typescript/unit_tests/export-default-function.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..421d240a1b0378622e3f2af2013cf207c240b702 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-default-function.ts.result @@ -0,0 +1,6 @@ +Matched 22 tokens. +============= Module =========== +== Sub Tree == +export { default as func (arg) throws: + return [arg] +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-func-as-import.ts b/src/MapleFE/test/typescript/unit_tests/export-func-as-import.ts new file mode 100644 index 0000000000000000000000000000000000000000..93c7e958e8c08c795b8787ff8b80ac3b156fd671 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-func-as-import.ts @@ -0,0 +1,4 @@ +function func(n: string, o?: string): Promise { + return new Promise((resolve, reject) => { resolve("OK"); }); +} +export { func as import }; diff --git a/src/MapleFE/test/typescript/unit_tests/export-func-as-import.ts.result b/src/MapleFE/test/typescript/unit_tests/export-func-as-import.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c42ee9868155c334f0f8a9c5302c15a2241bdcba --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-func-as-import.ts.result @@ -0,0 +1,10 @@ +Matched 41 tokens. +Matched 48 tokens. +============= Module =========== +== Sub Tree == +func func(n,o?) throws: + return new Promise((resolve,reject) -> resolve("OK") +) + +== Sub Tree == +export {func as import} diff --git a/src/MapleFE/test/typescript/unit_tests/export-import.ts b/src/MapleFE/test/typescript/unit_tests/export-import.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8311317972b4b0ffe51e39bbe51c6bc46239826 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-import.ts @@ -0,0 +1,4 @@ +import * as M from "./M"; +declare namespace NS { + export import MM = M; +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-import.ts.result b/src/MapleFE/test/typescript/unit_tests/export-import.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8660fdc0bb88ec7ef9cc0d9b31c225e22d557c2d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-import.ts.result @@ -0,0 +1,9 @@ +Matched 7 tokens. +Matched 18 tokens. +============= Module =========== +== Sub Tree == +import { * as M} "./M" +== Sub Tree == +declare namespace NS + export {import {M as MM} } + diff --git a/src/MapleFE/test/typescript/unit_tests/export-import2.ts b/src/MapleFE/test/typescript/unit_tests/export-import2.ts new file mode 100644 index 0000000000000000000000000000000000000000..483b9ad6397ec420f302ea790aea5b0e36585dc2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-import2.ts @@ -0,0 +1,5 @@ +import myX, * as M from "./M"; +export import getx = M.getx; +console.log(myX, getx()); +M.setx(3); +console.log(myX, getx()); diff --git a/src/MapleFE/test/typescript/unit_tests/export-import2.ts.result b/src/MapleFE/test/typescript/unit_tests/export-import2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..bbda54c0caf3a899e3c1c39685e62a5bcb1cb1fc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-import2.ts.result @@ -0,0 +1,16 @@ +Matched 9 tokens. +Matched 17 tokens. +Matched 28 tokens. +Matched 35 tokens. +Matched 46 tokens. +============= Module =========== +== Sub Tree == +import { default as myX, * as M} "./M" +== Sub Tree == +export {import {M.getx as getx} } +== Sub Tree == +console.log(myX,getx()) +== Sub Tree == +M.setx(3) +== Sub Tree == +console.log(myX,getx()) diff --git a/src/MapleFE/test/typescript/unit_tests/export-in-namespace.ts b/src/MapleFE/test/typescript/unit_tests/export-in-namespace.ts new file mode 100644 index 0000000000000000000000000000000000000000..a2b718d2d750b1ca891a61be12c1c3e973e2023b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-in-namespace.ts @@ -0,0 +1,4 @@ +export declare namespace ns { + class Klass {} + export { Klass }; +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-in-namespace.ts.result b/src/MapleFE/test/typescript/unit_tests/export-in-namespace.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5f86a5325c1fe955130e409e4889f17b956c1a6f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-in-namespace.ts.result @@ -0,0 +1,15 @@ +Matched 15 tokens. +============= Module =========== +== Sub Tree == +export {declare namespace ns + class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + + export {Klass} +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-interface.ts b/src/MapleFE/test/typescript/unit_tests/export-interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..8fcaaf808f30dcdc7ff88153b9b128f611667e86 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-interface.ts @@ -0,0 +1,3 @@ +export interface MapLike { + [index: string]: T; +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-interface.ts.result b/src/MapleFE/test/typescript/unit_tests/export-interface.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7085ccc02b9c0e0b5f72fc9449009a10f06646b7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-interface.ts.result @@ -0,0 +1,4 @@ +Matched 16 tokens. +============= Module =========== +== Sub Tree == +export {ts_interface: MapLike {string index type: T }} diff --git a/src/MapleFE/test/typescript/unit_tests/export-module.d.ts b/src/MapleFE/test/typescript/unit_tests/export-module.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ed719cbd4202180d58496739f3a377fe060545b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-module.d.ts @@ -0,0 +1,5 @@ +declare module "export-module" { + export module Module { + const func: () => boolean; + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/export-module.d.ts.result b/src/MapleFE/test/typescript/unit_tests/export-module.d.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..be802a82355a77c30467f280ea39d7fb2b2cf749 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-module.d.ts.result @@ -0,0 +1,10 @@ +Matched 18 tokens. +============= Module =========== +== Sub Tree == +declare ============= Module =========== +== Sub Tree == +export {============= Module =========== +== Sub Tree == +js_const Decl: func +} + diff --git a/src/MapleFE/test/typescript/unit_tests/export-single.ts b/src/MapleFE/test/typescript/unit_tests/export-single.ts new file mode 100644 index 0000000000000000000000000000000000000000..63c0c96edfea8fd0152dc34a47713119cb6f880a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-single.ts @@ -0,0 +1,4 @@ +class Klass { + name: string = ""; +} +export = Klass; diff --git a/src/MapleFE/test/typescript/unit_tests/export-single.ts.result b/src/MapleFE/test/typescript/unit_tests/export-single.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..530373f531e6a8529f1487355532497834ed7591 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-single.ts.result @@ -0,0 +1,15 @@ +Matched 10 tokens. +Matched 14 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + name="" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +export { SINGLE Klass} diff --git a/src/MapleFE/test/typescript/unit_tests/export-type.ts b/src/MapleFE/test/typescript/unit_tests/export-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..779287f898611afb4e2c780310c2dcc3e751007c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-type.ts @@ -0,0 +1,10 @@ +class Foo { + public out: number = 0; + public in: number = 0; + constructor(a: number, b: number) { + this.out = a; + this.in = b; + } +} + +export type { Foo }; diff --git a/src/MapleFE/test/typescript/unit_tests/export-type.ts.result b/src/MapleFE/test/typescript/unit_tests/export-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..fb266b095ac7a49342bbaf2b55163d9f00e9fb03 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-type.ts.result @@ -0,0 +1,18 @@ +Matched 42 tokens. +Matched 48 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + out=0 in=0 + Instance Initializer: + Constructors: + constructor (a,b) throws: + this.out Assign a + this.in Assign b + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +export type {Foo} diff --git a/src/MapleFE/test/typescript/unit_tests/export-type2.ts b/src/MapleFE/test/typescript/unit_tests/export-type2.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b131b5b183d860a60ca338472abd67c8f9bb4a2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-type2.ts @@ -0,0 +1 @@ +export type { Foo } from "./export-type"; diff --git a/src/MapleFE/test/typescript/unit_tests/export-type2.ts.result b/src/MapleFE/test/typescript/unit_tests/export-type2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..efee0ee0257e1c87546028bec8b3eb5ae44298f0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-type2.ts.result @@ -0,0 +1,4 @@ +Matched 8 tokens. +============= Module =========== +== Sub Tree == +export type {Foo} "./export-type" diff --git a/src/MapleFE/test/typescript/unit_tests/export-type3.ts b/src/MapleFE/test/typescript/unit_tests/export-type3.ts new file mode 100644 index 0000000000000000000000000000000000000000..d3c109ca03bbf74654d82a323bd8da4cd14d6ec2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-type3.ts @@ -0,0 +1,4 @@ +export type Type += Pick> +& Partial> extends infer U ? {[KT in keyof U]: U[KT]} : never; + diff --git a/src/MapleFE/test/typescript/unit_tests/export-type3.ts.result b/src/MapleFE/test/typescript/unit_tests/export-type3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a77c87d926640d0525ca1f33f0cb213be7d25c8a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/export-type3.ts.result @@ -0,0 +1,4 @@ +Matched 55 tokens. +============= Module =========== +== Sub Tree == +export { type Type = intersect = Pick> & Partial> extends infer U ? {[KT in keyof U] : U[KT] } : never} diff --git a/src/MapleFE/test/typescript/unit_tests/extends-infer.ts b/src/MapleFE/test/typescript/unit_tests/extends-infer.ts new file mode 100644 index 0000000000000000000000000000000000000000..c02b328cff278ec8ab93e9ce99aadbabb040c6d1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/extends-infer.ts @@ -0,0 +1,3 @@ +export declare type NT = { + [K in keyof T]: NonNullable extends boolean ? K : never; + } extends { [_ in keyof T]: infer U; } ? U : never; diff --git a/src/MapleFE/test/typescript/unit_tests/extends-infer.ts.result b/src/MapleFE/test/typescript/unit_tests/extends-infer.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..d674cbdb1ff8292e64d108b9e6c1f9f15ec34943 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/extends-infer.ts.result @@ -0,0 +1,4 @@ +Matched 49 tokens. +============= Module =========== +== Sub Tree == +export {declare type NT = {[K in keyof T] : NonNullable extends boolean ? K : never } extends {[_ in keyof T] : infer U } ? U : never} diff --git a/src/MapleFE/test/typescript/unit_tests/fibonacci.ts b/src/MapleFE/test/typescript/unit_tests/fibonacci.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ac2de9082600be3198b3bd64a0e6b418f7b6d47 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/fibonacci.ts @@ -0,0 +1,16 @@ +function fibonacci(m: number) { + var f0: number = 0; + var f1: number = 1; + var f2: number | undefined; + var i: number; + if (m <= 1) { + return m; + } else { + for (i = 2; i <= m; i++) { + f2 = f0 + f1; + f0 = f1; + f1 = f2; + } + return f2; + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/fibonacci.ts.result b/src/MapleFE/test/typescript/unit_tests/fibonacci.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..bf4d4d25ac1bc77785f201d751b2faa2b065761e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/fibonacci.ts.result @@ -0,0 +1,20 @@ +Matched 81 tokens. +============= Module =========== +== Sub Tree == +func fibonacci(m) throws: + js_var Decl: f0=0 + js_var Decl: f1=1 + js_var Decl: f2 + js_var Decl: i + cond-branch cond:m LE 1 + true branch : + return m + false branch : + for ( ) + f2 Assign f0 Add f1 + f0 Assign f1 + f1 Assign f2 + + return f2 + + diff --git a/src/MapleFE/test/typescript/unit_tests/field-func.ts b/src/MapleFE/test/typescript/unit_tests/field-func.ts new file mode 100644 index 0000000000000000000000000000000000000000..b87a09fe7b0d98a4fe9ef95dc8845e1267ac73da --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/field-func.ts @@ -0,0 +1,2 @@ +interface cs {} +declare const calls: { (): cs[] }; diff --git a/src/MapleFE/test/typescript/unit_tests/field-func.ts.result b/src/MapleFE/test/typescript/unit_tests/field-func.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c00be998c394437e2dc100d3e1ee49916a116768 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/field-func.ts.result @@ -0,0 +1,7 @@ +Matched 4 tokens. +Matched 17 tokens. +============= Module =========== +== Sub Tree == +ts_interface: cs { } +== Sub Tree == +declare js_const Decl: calls diff --git a/src/MapleFE/test/typescript/unit_tests/for-in-stmt-1.ts b/src/MapleFE/test/typescript/unit_tests/for-in-stmt-1.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b553722369e3af586716557a82694d326cc3475 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-in-stmt-1.ts @@ -0,0 +1,10 @@ +class Klass { + [key: string]: number | string; + x: number = 0; + s: string = ""; +} + +var obj: Klass = { x: 1, s: "123" }; +for (const k in obj) { + console.log(k, obj[k]); +} diff --git a/src/MapleFE/test/typescript/unit_tests/for-in-stmt-1.ts.result b/src/MapleFE/test/typescript/unit_tests/for-in-stmt-1.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..637f2e422c010a68a832b49954ebfff6bf321a0f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-in-stmt-1.ts.result @@ -0,0 +1,20 @@ +Matched 26 tokens. +Matched 41 tokens. +Matched 62 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + union = number | string x=0 s="" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj= {x:1, s:"123"} +== Sub Tree == +for ( ) + console.log(k,obj[k]) + diff --git a/src/MapleFE/test/typescript/unit_tests/for-in-stmt.ts b/src/MapleFE/test/typescript/unit_tests/for-in-stmt.ts new file mode 100644 index 0000000000000000000000000000000000000000..0cad8e5fa5a9e32ed4a643e90d0aca6abcaab63a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-in-stmt.ts @@ -0,0 +1,10 @@ +class Klass { + [key: string]: number | string; + x: number = 0; + s: string = ""; +} + +var obj: Klass = { x: 1, s: "123" }; +for (var k in obj) { + console.log(k, obj[k]); +} diff --git a/src/MapleFE/test/typescript/unit_tests/for-in-stmt.ts.result b/src/MapleFE/test/typescript/unit_tests/for-in-stmt.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..637f2e422c010a68a832b49954ebfff6bf321a0f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-in-stmt.ts.result @@ -0,0 +1,20 @@ +Matched 26 tokens. +Matched 41 tokens. +Matched 62 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + union = number | string x=0 s="" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj= {x:1, s:"123"} +== Sub Tree == +for ( ) + console.log(k,obj[k]) + diff --git a/src/MapleFE/test/typescript/unit_tests/for-let.ts b/src/MapleFE/test/typescript/unit_tests/for-let.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f9c93f7a61ccea17d0d732e6f0665014e94607e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-let.ts @@ -0,0 +1,3 @@ +for (let i = 0; i < 5; i++) { + console.log(i); +} diff --git a/src/MapleFE/test/typescript/unit_tests/for-let.ts.result b/src/MapleFE/test/typescript/unit_tests/for-let.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8283bf2da4b2f1e9736efff2db680204a4dd84f2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-let.ts.result @@ -0,0 +1,6 @@ +Matched 23 tokens. +============= Module =========== +== Sub Tree == +for ( ) + console.log(i) + diff --git a/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits.ts b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits.ts new file mode 100644 index 0000000000000000000000000000000000000000..a02de7c5d5e568265dc1e876fa8c6f9c4a8d0c62 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits.ts @@ -0,0 +1 @@ +for (let i = 0, j = 3; i < j; i++) console.log(i, j); diff --git a/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits.ts.result b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b27c90e9ea35dcbf7ff637525d063dc58a89791a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits.ts.result @@ -0,0 +1,5 @@ +Matched 27 tokens. +============= Module =========== +== Sub Tree == +for ( ) + console.log(i,j) diff --git a/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits2.ts b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits2.ts new file mode 100644 index 0000000000000000000000000000000000000000..998beff737361ead9b61fe174198a3f0d2c56c19 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits2.ts @@ -0,0 +1,12 @@ +class Klass { + items: number[] = []; + + func(num: number) { + let i, list; + for (i = 0, list = this.items; i < num; i++) console.log(i, list[i]); + } +} + +var obj: Klass = new Klass(); +obj.items.push(1, 2, 3, 4, 5, 6); +obj.func(6); diff --git a/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits2.ts.result b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..81669289b69486f5920246da19dffd3c8d5469d7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits2.ts.result @@ -0,0 +1,26 @@ +Matched 57 tokens. +Matched 67 tokens. +Matched 86 tokens. +Matched 93 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + items=[] + Instance Initializer: + Constructors: + Methods: + func func(num) throws: + js_let Decl: i + js_let Decl: list + for ( ) + console.log(i,list[i]) + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj.items.push(1,2,3,4,5,6) +== Sub Tree == +obj.func(6) diff --git a/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits3.ts b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits3.ts new file mode 100644 index 0000000000000000000000000000000000000000..c028beddbfe0dacdff4947a2767dbf3b8081e2d6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits3.ts @@ -0,0 +1,13 @@ +class Klass { + items: number[] = []; + + func() { + let i, list, len; + for (i = 0, list = this.items, len = this.items.length; i < len; i++) + console.log(i, list[i]); + } +} + +var obj: Klass = new Klass(); +obj.items.push(1, 2, 3, 4, 5, 6); +obj.func(); diff --git a/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits3.ts.result b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..98b323a089f1cd34e55057d364690d0dcaf8c08b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-inits3.ts.result @@ -0,0 +1,27 @@ +Matched 64 tokens. +Matched 74 tokens. +Matched 93 tokens. +Matched 99 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + items=[] + Instance Initializer: + Constructors: + Methods: + func func() throws: + js_let Decl: i + js_let Decl: list + js_let Decl: len + for ( ) + console.log(i,list[i]) + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj.items.push(1,2,3,4,5,6) +== Sub Tree == +obj.func() diff --git a/src/MapleFE/test/typescript/unit_tests/for-loop-multi-updates.ts b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-updates.ts new file mode 100644 index 0000000000000000000000000000000000000000..252807f5ccc5f4350c15a576ce8cdafab35d3ff3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-updates.ts @@ -0,0 +1 @@ +for (let i = 0, j = 3, k = 6; i < j + k; i += 3, j++, k++) console.log(i, j, k); diff --git a/src/MapleFE/test/typescript/unit_tests/for-loop-multi-updates.ts.result b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-updates.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..9c170dfa5ac3ffc4970be942865299bf74b10af1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-loop-multi-updates.ts.result @@ -0,0 +1,5 @@ +Matched 42 tokens. +============= Module =========== +== Sub Tree == +for ( ) + console.log(i,j,k) diff --git a/src/MapleFE/test/typescript/unit_tests/for-of-stmt.ts b/src/MapleFE/test/typescript/unit_tests/for-of-stmt.ts new file mode 100644 index 0000000000000000000000000000000000000000..73764b9435314483f5509160d637d29883deca64 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-of-stmt.ts @@ -0,0 +1,4 @@ +var arr = [1, 2, 3]; +for (var v of arr) { + console.log(v); +} diff --git a/src/MapleFE/test/typescript/unit_tests/for-of-stmt.ts.result b/src/MapleFE/test/typescript/unit_tests/for-of-stmt.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f0611630907487a5e31026d8d58a1450f5e1844b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-of-stmt.ts.result @@ -0,0 +1,9 @@ +Matched 11 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[1,2,3] +== Sub Tree == +for ( ) + console.log(v) + diff --git a/src/MapleFE/test/typescript/unit_tests/for-switch-mixed.ts b/src/MapleFE/test/typescript/unit_tests/for-switch-mixed.ts new file mode 100644 index 0000000000000000000000000000000000000000..71d7d33cb24f5f206c189de160c9db838f66af36 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-switch-mixed.ts @@ -0,0 +1,19 @@ +const nums: number[] = [3, 9, 8, 2, 7, 5, 1, 6, 4]; + +for (const n of nums) { + switch (true) { + case n < 5: + console.log(n, " is less than 5"); + case n > 2 && n < 5: + console.log(n, " + 1 is equal to", n + 1); + break; + case n == 6: + console.log(n, " is equal to 6"); + break; + case n < 8: + console.log(n, " is greater than 4 and less than 8"); + break; + default: + console.log(n, " is greater than 7"); + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/for-switch-mixed.ts.result b/src/MapleFE/test/typescript/unit_tests/for-switch-mixed.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3d64cd1d402e63411a62f81196a0ceef9225cf64 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/for-switch-mixed.ts.result @@ -0,0 +1,10 @@ +Matched 27 tokens. +Matched 123 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: nums=[3,9,8,2,7,5,1,6,4] +== Sub Tree == +for ( ) + A switch + + diff --git a/src/MapleFE/test/typescript/unit_tests/func-builtin.ts b/src/MapleFE/test/typescript/unit_tests/func-builtin.ts new file mode 100644 index 0000000000000000000000000000000000000000..88a893009c6ae2ef31607c869f8c17f4859df287 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func-builtin.ts @@ -0,0 +1,37 @@ +interface Employee { + firstName: string; + lastName: string; +} + +let john: Employee = { + firstName: "John", + lastName: "Smith", +}; + +let jane: Employee = { + firstName: "Jane", + lastName: "Doe", +}; + +var func; +var res; + +function fullName(this: Employee): string { + return this.firstName + " " + this.lastName; +} + +// call() and apply() returns the result of calling the function directly with the obj instance arg +res = fullName.call(john); +console.log("Name: " + res); // output: "Name: John Smith" +res = fullName.call(jane); +console.log("Name: " + res); // output: "Name: Jane Doe" +res = fullName.apply(john); +console.log("Name: " + res); // output: "Name: John Smith" +res = fullName.apply(jane); +console.log("Name: " + res); // output: "Name: Jane Doe" + +// bind() returns a copy of the function bound to the obj instance arg +func = fullName.bind(john); +console.log("Name: " + func()); // output: "Name: John Smith" +func = fullName.bind(jane); +console.log("Name: " + func()); // output: "Name: Jane Doe" diff --git a/src/MapleFE/test/typescript/unit_tests/func-builtin.ts.result b/src/MapleFE/test/typescript/unit_tests/func-builtin.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..84146a9752502f9167057c6864f80c1a950d9ea7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func-builtin.ts.result @@ -0,0 +1,57 @@ +Matched 12 tokens. +Matched 28 tokens. +Matched 44 tokens. +Matched 47 tokens. +Matched 50 tokens. +Matched 72 tokens. +Matched 81 tokens. +Matched 90 tokens. +Matched 99 tokens. +Matched 108 tokens. +Matched 117 tokens. +Matched 126 tokens. +Matched 135 tokens. +Matched 144 tokens. +Matched 153 tokens. +Matched 164 tokens. +Matched 173 tokens. +Matched 184 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Employee {firstName;lastName } +== Sub Tree == +js_let Decl: john= {firstName:"John", lastName:"Smith"} +== Sub Tree == +js_let Decl: jane= {firstName:"Jane", lastName:"Doe"} +== Sub Tree == +js_var Decl: func +== Sub Tree == +js_var Decl: res +== Sub Tree == +func fullName(this) throws: + return this.firstName Add " " Add this.lastName + +== Sub Tree == +res Assign fullName.call(john) +== Sub Tree == +console.log("Name: " Add res) +== Sub Tree == +res Assign fullName.call(jane) +== Sub Tree == +console.log("Name: " Add res) +== Sub Tree == +res Assign fullName.apply(john) +== Sub Tree == +console.log("Name: " Add res) +== Sub Tree == +res Assign fullName.apply(jane) +== Sub Tree == +console.log("Name: " Add res) +== Sub Tree == +func Assign fullName.bind(john) +== Sub Tree == +console.log("Name: " Add func()) +== Sub Tree == +func Assign fullName.bind(jane) +== Sub Tree == +console.log("Name: " Add func()) diff --git a/src/MapleFE/test/typescript/unit_tests/func-call.ts b/src/MapleFE/test/typescript/unit_tests/func-call.ts new file mode 100644 index 0000000000000000000000000000000000000000..0efe45f8133a835e013384634669a76adc364c1c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func-call.ts @@ -0,0 +1,6 @@ +function func(a: number, b: number, c: number): number { + return a + b + c; +} + +var num = 10; +console.log(func(1, 5, -num)); diff --git a/src/MapleFE/test/typescript/unit_tests/func-call.ts.result b/src/MapleFE/test/typescript/unit_tests/func-call.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3b091ae645deb09f0cd555761266dede80492a0b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func-call.ts.result @@ -0,0 +1,12 @@ +Matched 26 tokens. +Matched 31 tokens. +Matched 46 tokens. +============= Module =========== +== Sub Tree == +func func(a,b,c) throws: + return a Add b Add c + +== Sub Tree == +js_var Decl: num=10 +== Sub Tree == +console.log(func(1,5,Minus num)) diff --git a/src/MapleFE/test/typescript/unit_tests/func2.ts b/src/MapleFE/test/typescript/unit_tests/func2.ts new file mode 100644 index 0000000000000000000000000000000000000000..1569fa1aae54cb54667f30504857a64e6a92150c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func2.ts @@ -0,0 +1,12 @@ +function func(this: any, arg: number) { + var x:number; + this.val1 = arg; + x = this.val1; + this.val2 = x; +} + +var a = {}; +var b = new (func as any)(456); // allocate an object and call func as constructor +func.call(a, 123); // pass an existing object to func +console.log(a); +console.log(b); diff --git a/src/MapleFE/test/typescript/unit_tests/func2.ts.result b/src/MapleFE/test/typescript/unit_tests/func2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..625e3d3318cb55f35c53863f451beff326e78473 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func2.ts.result @@ -0,0 +1,24 @@ +Matched 36 tokens. +Matched 42 tokens. +Matched 55 tokens. +Matched 64 tokens. +Matched 71 tokens. +Matched 78 tokens. +============= Module =========== +== Sub Tree == +func func(this,arg) throws: + js_var Decl: x + this.val1 Assign arg + x Assign this.val1 + this.val2 Assign x + +== Sub Tree == +js_var Decl: a= {} +== Sub Tree == +js_var Decl: b=new func(456) +== Sub Tree == +func.call(a,123) +== Sub Tree == +console.log(a) +== Sub Tree == +console.log(b) diff --git a/src/MapleFE/test/typescript/unit_tests/func3.ts b/src/MapleFE/test/typescript/unit_tests/func3.ts new file mode 100644 index 0000000000000000000000000000000000000000..193eef9e3605b7b2b8ce481abe6ee84ebb8a34d4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func3.ts @@ -0,0 +1,17 @@ +interface Foo { + val1: number; + val2: number; +}; + +function func(this: Foo , arg: number) { + var x:number; + this.val1 = arg; + x = this.val1; + this.val2 = x; +} + +var a: Foo = {val1:0, val2:0}; +var b = new (func as any)(456); // allocate an object and call func as constructor +func.call(a, 123); // pass an existing object to func +console.log(a); +console.log(b); diff --git a/src/MapleFE/test/typescript/unit_tests/func3.ts.result b/src/MapleFE/test/typescript/unit_tests/func3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a316b87d3fdb55370db56143852baa5b263dae61 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func3.ts.result @@ -0,0 +1,28 @@ +Matched 12 tokens. +Matched 13 tokens. +Matched 49 tokens. +Matched 64 tokens. +Matched 77 tokens. +Matched 86 tokens. +Matched 93 tokens. +Matched 100 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Foo {val1;val2 } +== Sub Tree == +func func(this,arg) throws: + js_var Decl: x + this.val1 Assign arg + x Assign this.val1 + this.val2 Assign x + +== Sub Tree == +js_var Decl: a= {val1:0, val2:0} +== Sub Tree == +js_var Decl: b=new func(456) +== Sub Tree == +func.call(a,123) +== Sub Tree == +console.log(a) +== Sub Tree == +console.log(b) diff --git a/src/MapleFE/test/typescript/unit_tests/func4.ts b/src/MapleFE/test/typescript/unit_tests/func4.ts new file mode 100644 index 0000000000000000000000000000000000000000..0ecb7843b2d7d2dfa13564ae4d76692782a6770f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func4.ts @@ -0,0 +1,17 @@ +class Foo { + public val1: number = 0; + public val2: number = 0; +}; + +function func(this: Foo , arg: number) { + var x:number; + this.val1 = arg; + x = this.val1; + this.val2 = x; +} + +var a = new Foo(); +var b = new (func as any)(456); // allocate an object and call func as constructor +func.call(a, 123); // pass an existing object to func +console.log(a); +console.log(b); diff --git a/src/MapleFE/test/typescript/unit_tests/func4.ts.result b/src/MapleFE/test/typescript/unit_tests/func4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..bd8ceb2fffed5b2005807c4b3e703831fcc92e33 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func4.ts.result @@ -0,0 +1,36 @@ +Matched 18 tokens. +Matched 19 tokens. +Matched 55 tokens. +Matched 63 tokens. +Matched 76 tokens. +Matched 85 tokens. +Matched 92 tokens. +Matched 99 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + val1=0 val2=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func func(this,arg) throws: + js_var Decl: x + this.val1 Assign arg + x Assign this.val1 + this.val2 Assign x + +== Sub Tree == +js_var Decl: a=new Foo() +== Sub Tree == +js_var Decl: b=new func(456) +== Sub Tree == +func.call(a,123) +== Sub Tree == +console.log(a) +== Sub Tree == +console.log(b) diff --git a/src/MapleFE/test/typescript/unit_tests/func5.ts b/src/MapleFE/test/typescript/unit_tests/func5.ts new file mode 100644 index 0000000000000000000000000000000000000000..07b11f4dbdf8e1528f29059c9047d068967bb4b2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func5.ts @@ -0,0 +1,8 @@ +function func(arg: number): number { + return arg;; +} + +var a = new (func as any)(123); +console.log(a); +console.log(func(123)); + diff --git a/src/MapleFE/test/typescript/unit_tests/func5.ts.result b/src/MapleFE/test/typescript/unit_tests/func5.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..590d2ebbdbd504c9382d5447229f6987690dc0fb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/func5.ts.result @@ -0,0 +1,15 @@ +Matched 15 tokens. +Matched 28 tokens. +Matched 35 tokens. +Matched 45 tokens. +============= Module =========== +== Sub Tree == +func func(arg) throws: + return arg + +== Sub Tree == +js_var Decl: a=new func(123) +== Sub Tree == +console.log(a) +== Sub Tree == +console.log(func(123)) diff --git a/src/MapleFE/test/typescript/unit_tests/function-1.ts b/src/MapleFE/test/typescript/unit_tests/function-1.ts new file mode 100644 index 0000000000000000000000000000000000000000..cba43a07774dad3191704949e40f7d9a4f114f11 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-1.ts @@ -0,0 +1,6 @@ +function add(a: number, b: number) { + return a + b; +} + +var c = add(1, 2); +console.log(c); diff --git a/src/MapleFE/test/typescript/unit_tests/function-1.ts.result b/src/MapleFE/test/typescript/unit_tests/function-1.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..20ef4e8dbefea7b97213d5aa8ee02f751acaaa8a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-1.ts.result @@ -0,0 +1,12 @@ +Matched 18 tokens. +Matched 28 tokens. +Matched 35 tokens. +============= Module =========== +== Sub Tree == +func add(a,b) throws: + return a Add b + +== Sub Tree == +js_var Decl: c=add(1,2) +== Sub Tree == +console.log(c) diff --git a/src/MapleFE/test/typescript/unit_tests/function-2.ts b/src/MapleFE/test/typescript/unit_tests/function-2.ts new file mode 100644 index 0000000000000000000000000000000000000000..aad00728c6cfecb86c45a5fd4bfe59c4a4903fc4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-2.ts @@ -0,0 +1,7 @@ +function add(a: number, b: number) { + return a + b; +} + +// Allowed by ECMAScript 2017 +var c = add(1, 2); +console.log(c); diff --git a/src/MapleFE/test/typescript/unit_tests/function-2.ts.result b/src/MapleFE/test/typescript/unit_tests/function-2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..20ef4e8dbefea7b97213d5aa8ee02f751acaaa8a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-2.ts.result @@ -0,0 +1,12 @@ +Matched 18 tokens. +Matched 28 tokens. +Matched 35 tokens. +============= Module =========== +== Sub Tree == +func add(a,b) throws: + return a Add b + +== Sub Tree == +js_var Decl: c=add(1,2) +== Sub Tree == +console.log(c) diff --git a/src/MapleFE/test/typescript/unit_tests/function-3.ts b/src/MapleFE/test/typescript/unit_tests/function-3.ts new file mode 100644 index 0000000000000000000000000000000000000000..06a994b1570bc4fd78318043b679427c30b45647 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-3.ts @@ -0,0 +1,9 @@ +function func(x: number) { + //if (x < 0) {x = 0}; + if (x < 0) { + x = 0; + } + console.log(x); +} +func(10); +func(-10); diff --git a/src/MapleFE/test/typescript/unit_tests/function-3.ts.result b/src/MapleFE/test/typescript/unit_tests/function-3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..175ff10d9c688788dc56fce8c1a81e31675c9b06 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-3.ts.result @@ -0,0 +1,17 @@ +Matched 28 tokens. +Matched 33 tokens. +Matched 38 tokens. +============= Module =========== +== Sub Tree == +func func(x) throws: + cond-branch cond:x LT 0 + true branch : + x Assign 0 + false branch : + + console.log(x) + +== Sub Tree == +func(10) +== Sub Tree == +func(-10) diff --git a/src/MapleFE/test/typescript/unit_tests/function-arg-obj-literal.ts b/src/MapleFE/test/typescript/unit_tests/function-arg-obj-literal.ts new file mode 100644 index 0000000000000000000000000000000000000000..cedf317fd74b0158feb7c7a9285e2eea9db38f2f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-arg-obj-literal.ts @@ -0,0 +1,6 @@ +const f1: number = 1; +const f2: number = 2; + +function foo(arg: any) {} + +foo({ f1, f2 }); diff --git a/src/MapleFE/test/typescript/unit_tests/function-arg-obj-literal.ts.result b/src/MapleFE/test/typescript/unit_tests/function-arg-obj-literal.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..25f072ce4b3fb244444d4bdf15c89d7f480b9286 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-arg-obj-literal.ts.result @@ -0,0 +1,14 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 23 tokens. +Matched 32 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: f1=1 +== Sub Tree == +js_const Decl: f2=2 +== Sub Tree == +func foo(arg) throws: + +== Sub Tree == +foo( {:f1, :f2}) diff --git a/src/MapleFE/test/typescript/unit_tests/function-type.ts b/src/MapleFE/test/typescript/unit_tests/function-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..b82962914789605b311d4ca0c90c2c36af303777 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-type.ts @@ -0,0 +1,3 @@ +let f: (x: number) => number; +f = (x: number): number => x / 3; +console.log(f(6)); diff --git a/src/MapleFE/test/typescript/unit_tests/function-type.ts.result b/src/MapleFE/test/typescript/unit_tests/function-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..31a87da43ac52c1c41ce6a96becc14929bed746e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-type.ts.result @@ -0,0 +1,10 @@ +Matched 11 tokens. +Matched 25 tokens. +Matched 35 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: f +== Sub Tree == +f Assign (x) -> x Div 3 +== Sub Tree == +console.log(f(6)) diff --git a/src/MapleFE/test/typescript/unit_tests/function-with-this.ts b/src/MapleFE/test/typescript/unit_tests/function-with-this.ts new file mode 100644 index 0000000000000000000000000000000000000000..8512d316801d98d8ed90762288c959f04ea8f8d0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-with-this.ts @@ -0,0 +1,3 @@ +interface Foo { + func(callback: (this: void, v: T) => v is T, thisArg?: any): T; +} diff --git a/src/MapleFE/test/typescript/unit_tests/function-with-this.ts.result b/src/MapleFE/test/typescript/unit_tests/function-with-this.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b4073672ad44981d9989f58b6c38315bbf1f3512 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/function-with-this.ts.result @@ -0,0 +1,5 @@ +Matched 36 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Foo {func func(callback,thisArg?) throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/generate-result.sh b/src/MapleFE/test/typescript/unit_tests/generate-result.sh new file mode 100755 index 0000000000000000000000000000000000000000..8666e69ca4928442d8c44d64076f7704d59f348c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generate-result.sh @@ -0,0 +1,23 @@ +# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +#!/bin/bash +FILES=( class-implements-interface.ts construct-signature.ts interface-keyof.ts) + + +for f in ${FILES[@]} +do + echo "Generating result for $f ..." + ../../../output/typescript/bin/ts2ast $f > $f.result +done diff --git a/src/MapleFE/test/typescript/unit_tests/generator.ts b/src/MapleFE/test/typescript/unit_tests/generator.ts new file mode 100644 index 0000000000000000000000000000000000000000..6841e1c54cbd89c745f6ddd5b794b6996b931f02 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generator.ts @@ -0,0 +1,15 @@ +function* gen(n: number): Generator { + for (var i = 1; i <= n; i++) { + let res = yield i; + console.log(res); + if (res) + break; + } + return "done"; +} + +const obj: Generator = gen(10); +console.log(obj.next()); +console.log(obj.next(false)); +console.log(obj.next(true)); +console.log(obj.next()); diff --git a/src/MapleFE/test/typescript/unit_tests/generator.ts.result b/src/MapleFE/test/typescript/unit_tests/generator.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3bde9f39cf03cfd0dc24a61c026635c834548833 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generator.ts.result @@ -0,0 +1,30 @@ +Matched 57 tokens. +Matched 74 tokens. +Matched 85 tokens. +Matched 97 tokens. +Matched 109 tokens. +Matched 120 tokens. +============= Module =========== +== Sub Tree == +generator gen(n) throws: + for ( ) + js_let Decl: res=yield i + console.log(res) + cond-branch cond:res + true branch : + break: + false branch : + + + return "done" + +== Sub Tree == +js_const Decl: obj=gen(10) +== Sub Tree == +console.log(obj.next()) +== Sub Tree == +console.log(obj.next(false)) +== Sub Tree == +console.log(obj.next(true)) +== Sub Tree == +console.log(obj.next()) diff --git a/src/MapleFE/test/typescript/unit_tests/generator2.ts b/src/MapleFE/test/typescript/unit_tests/generator2.ts new file mode 100644 index 0000000000000000000000000000000000000000..d6c34586107e1575f9ac5c265d2bc9a71f34ac90 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generator2.ts @@ -0,0 +1,20 @@ +function* delegate(num: number) : Generator { + let r = yield num + 100; + return r; +} + +function* gen(n: number): Generator { + for (var i = 1; i <= n; i++) { + let res = yield* delegate(i); + console.log(res); + if (res) + break; + } + return "done"; +} + +const obj: Generator = gen(10); +console.log(obj.next()); +console.log(obj.next(false)); +console.log(obj.next(true)); +console.log(obj.next()); diff --git a/src/MapleFE/test/typescript/unit_tests/generator2.ts.result b/src/MapleFE/test/typescript/unit_tests/generator2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2ea5af65bc91b406983534dca5e4ecbd3891dff6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generator2.ts.result @@ -0,0 +1,36 @@ +Matched 26 tokens. +Matched 87 tokens. +Matched 104 tokens. +Matched 115 tokens. +Matched 127 tokens. +Matched 139 tokens. +Matched 150 tokens. +============= Module =========== +== Sub Tree == +generator delegate(num) throws: + js_let Decl: r=yield num Add 100 + return r + +== Sub Tree == +generator gen(n) throws: + for ( ) + js_let Decl: res=yield* delegate(i) + console.log(res) + cond-branch cond:res + true branch : + break: + false branch : + + + return "done" + +== Sub Tree == +js_const Decl: obj=gen(10) +== Sub Tree == +console.log(obj.next()) +== Sub Tree == +console.log(obj.next(false)) +== Sub Tree == +console.log(obj.next(true)) +== Sub Tree == +console.log(obj.next()) diff --git a/src/MapleFE/test/typescript/unit_tests/generator3.ts b/src/MapleFE/test/typescript/unit_tests/generator3.ts new file mode 100644 index 0000000000000000000000000000000000000000..bebfbb653f42a09ff2d5c5085169a6fe4247fb0d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generator3.ts @@ -0,0 +1,14 @@ +function* foo(index: number) { + while (index < 2) { + yield index; + index++; + } +} + +const iterator = foo(0); + +console.log(iterator.next().value); +// expected output: 0 + +console.log(iterator.next().value); +// expected output: 1 diff --git a/src/MapleFE/test/typescript/unit_tests/generator3.ts.result b/src/MapleFE/test/typescript/unit_tests/generator3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..dee32f9b52d6f90a88b406dcf35a2244e10976f0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generator3.ts.result @@ -0,0 +1,18 @@ +Matched 24 tokens. +Matched 32 tokens. +Matched 45 tokens. +Matched 58 tokens. +============= Module =========== +== Sub Tree == +generator foo(index) throws: + while index LT 2 yield index + index Inc + + + +== Sub Tree == +js_const Decl: iterator=foo(0) +== Sub Tree == +console.log(iterator.next().value) +== Sub Tree == +console.log(iterator.next().value) diff --git a/src/MapleFE/test/typescript/unit_tests/generator4.ts b/src/MapleFE/test/typescript/unit_tests/generator4.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d61465c3a387781224ed42ecf6c87ceeff6dc51 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generator4.ts @@ -0,0 +1,25 @@ +class IterableClass { + public elements: number[]; + + constructor() { + this.elements = []; + } + + add(element:number) { + this.elements.push(element); + } + + * [Symbol.iterator]() { + let element:number; + for (element of this.elements) { + yield element; + } + } +} + +let obj = new IterableClass(); +obj.add(123); +obj.add(456); +for (let e of obj) { + console.log(e); +} diff --git a/src/MapleFE/test/typescript/unit_tests/generator4.ts.result b/src/MapleFE/test/typescript/unit_tests/generator4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b09da6af24a7c4b6cb26f6b81171329ead8cb5d8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generator4.ts.result @@ -0,0 +1,35 @@ +Matched 68 tokens. +Matched 76 tokens. +Matched 83 tokens. +Matched 90 tokens. +Matched 106 tokens. +============= Module =========== +== Sub Tree == +class IterableClass + Fields: + elements + Instance Initializer: + Constructors: + constructor () throws: + this.elements Assign [] + Methods: + func add(element) throws: + this.elements.push(element) + func () throws: + js_let Decl: element + for ( ) + yield element + + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: obj=new IterableClass() +== Sub Tree == +obj.add(123) +== Sub Tree == +obj.add(456) +== Sub Tree == +for ( ) + console.log(e) + diff --git a/src/MapleFE/test/typescript/unit_tests/generic-func-in-interface.ts b/src/MapleFE/test/typescript/unit_tests/generic-func-in-interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f22113aacf9aea268ca30e23dc9c8a66e26c665 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-func-in-interface.ts @@ -0,0 +1,3 @@ +interface IFace { + any(arg: (T | Iterable)[] | string): Iterable; +} diff --git a/src/MapleFE/test/typescript/unit_tests/generic-func-in-interface.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-func-in-interface.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3e9868346023bbbfbfa187744b32abb2f5779acf --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-func-in-interface.ts.result @@ -0,0 +1,5 @@ +Matched 30 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {func any(arg) throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/generic-function.ts b/src/MapleFE/test/typescript/unit_tests/generic-function.ts new file mode 100644 index 0000000000000000000000000000000000000000..770e5fa265e6d3f7f641e61227cd00f0f5e1b079 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-function.ts @@ -0,0 +1,8 @@ +class Klass { + func void>(cb: T): typeof cb { + return cb; + } +} + +var obj: Klass = new Klass(); +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/generic-function.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-function.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f70238895d88062d4df73e715ea244b774516cce --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-function.ts.result @@ -0,0 +1,20 @@ +Matched 30 tokens. +Matched 40 tokens. +Matched 47 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + func func(cb) throws: + return cb + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/generic-function2.ts b/src/MapleFE/test/typescript/unit_tests/generic-function2.ts new file mode 100644 index 0000000000000000000000000000000000000000..4b4462f6ba2240c51da6023455630269c2fc6aa0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-function2.ts @@ -0,0 +1,5 @@ +class Klass { + func void>(cb: T): typeof cb { + return cb; + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/generic-function2.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-function2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..532d8cd1717395cac197f1156d302af708ebe5dc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-function2.ts.result @@ -0,0 +1,14 @@ +Matched 30 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + func func(cb) throws: + return cb + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/generic-lambda.ts b/src/MapleFE/test/typescript/unit_tests/generic-lambda.ts new file mode 100644 index 0000000000000000000000000000000000000000..abd3301280adb0d6c90a5a9076e2a5afdce4f4ff --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-lambda.ts @@ -0,0 +1,2 @@ +const func = (() => ((x: any): x is T[] => x && typeof x.length === 'number'))(); +console.log(func([1,2])); diff --git a/src/MapleFE/test/typescript/unit_tests/generic-lambda.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-lambda.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..15adaddb422ef8b456b40b469b76e2cdaee8117e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-lambda.ts.result @@ -0,0 +1,7 @@ +Matched 36 tokens. +Matched 50 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: func=() -> (x) -> x Land typeof x.length StEq "number"() +== Sub Tree == +console.log(func([1,2])) diff --git a/src/MapleFE/test/typescript/unit_tests/generic-prim-array.ts b/src/MapleFE/test/typescript/unit_tests/generic-prim-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..bc7ecd71559b91547597ac57cbbc3b80359a23a1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-prim-array.ts @@ -0,0 +1,9 @@ +class Klass { + f: T | undefined = undefined; +} + +const t = new Klass(); +t.f = [123, 456]; +console.log(typeof t); + +export type MyType = Klass; diff --git a/src/MapleFE/test/typescript/unit_tests/generic-prim-array.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-prim-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..add060b50d7fb34a9516c23e4f87675edd064c91 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-prim-array.ts.result @@ -0,0 +1,24 @@ +Matched 15 tokens. +Matched 28 tokens. +Matched 38 tokens. +Matched 46 tokens. +Matched 56 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + f=undefined + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_const Decl: t=new Klass() +== Sub Tree == +t.f Assign [123,456] +== Sub Tree == +console.log( typeof t) +== Sub Tree == +export { type MyType = Klass< typeof t>} diff --git a/src/MapleFE/test/typescript/unit_tests/generic-type.ts b/src/MapleFE/test/typescript/unit_tests/generic-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f615ab1c8cee4e83d473a591cb1049ce3e45bf3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-type.ts @@ -0,0 +1 @@ +type TYPE = { [P in K]?: T[P] }; diff --git a/src/MapleFE/test/typescript/unit_tests/generic-type.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..9dba2969ad3ff698e1d3531d3915c036563c9e91 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-type.ts.result @@ -0,0 +1,4 @@ +Matched 25 tokens. +============= Module =========== +== Sub Tree == + type TYPE = {[P in K] : T[P] } diff --git a/src/MapleFE/test/typescript/unit_tests/generic-type2.ts b/src/MapleFE/test/typescript/unit_tests/generic-type2.ts new file mode 100644 index 0000000000000000000000000000000000000000..38e7871591b036632e47aa66e5cae7b90941a97f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-type2.ts @@ -0,0 +1,9 @@ +class Klass { + [x: string]: number; +} + +class EXT { + [key: string]: B; +} + +type TYPE = EXT[keyof Klass]; diff --git a/src/MapleFE/test/typescript/unit_tests/generic-type2.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-type2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..bcb9d64635b5da0e17549af29ad74868693c613f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-type2.ts.result @@ -0,0 +1,26 @@ +Matched 12 tokens. +Matched 29 tokens. +Matched 48 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + number + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class EXT + Fields: + B + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == + type TYPE = EXT[ keyof Klass] diff --git a/src/MapleFE/test/typescript/unit_tests/generic-type3.ts b/src/MapleFE/test/typescript/unit_tests/generic-type3.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d109408f3f7b20d113a13d4a0a61a416904c5cc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-type3.ts @@ -0,0 +1,3 @@ +interface IFace { + func(): Promise ? U : T>; +} diff --git a/src/MapleFE/test/typescript/unit_tests/generic-type3.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-type3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a6f568ecd31d56fb1fe8e20f36b00be8e3f386af --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-type3.ts.result @@ -0,0 +1,5 @@ +Matched 26 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {func func() throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/generic-type4.ts b/src/MapleFE/test/typescript/unit_tests/generic-type4.ts new file mode 100644 index 0000000000000000000000000000000000000000..d9b3d4ab6c6f9460f11cdcfcb427250ae8603eef --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-type4.ts @@ -0,0 +1,2 @@ +type NT = ((args: Array) => PromiseLike>) | ((args: Array) => Array) | ((args: Array) => void); + diff --git a/src/MapleFE/test/typescript/unit_tests/generic-type4.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-type4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..64505c225af2ad79852ee5abebe2f0e1f41826ea --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-type4.ts.result @@ -0,0 +1,4 @@ +Matched 55 tokens. +============= Module =========== +== Sub Tree == + type NT = union = (args) -> | (args) -> | (args) -> diff --git a/src/MapleFE/test/typescript/unit_tests/generic-typeof.ts b/src/MapleFE/test/typescript/unit_tests/generic-typeof.ts new file mode 100644 index 0000000000000000000000000000000000000000..a2df74ba0364c61193d881848145bc34c2132333 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-typeof.ts @@ -0,0 +1,9 @@ +class Klass { + f: T | undefined = undefined; +} + +const t = new Klass(); +t.f = 123; +console.log(typeof t); + +export type MyType = Klass; diff --git a/src/MapleFE/test/typescript/unit_tests/generic-typeof.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-typeof.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e506463ca15a6fe7960c1a4a6239d6a257a124f1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-typeof.ts.result @@ -0,0 +1,24 @@ +Matched 15 tokens. +Matched 26 tokens. +Matched 32 tokens. +Matched 40 tokens. +Matched 50 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + f=undefined + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_const Decl: t=new Klass() +== Sub Tree == +t.f Assign 123 +== Sub Tree == +console.log( typeof t) +== Sub Tree == +export { type MyType = Klass< typeof t>} diff --git a/src/MapleFE/test/typescript/unit_tests/generic-typeof2.ts b/src/MapleFE/test/typescript/unit_tests/generic-typeof2.ts new file mode 100644 index 0000000000000000000000000000000000000000..9afd4945d80956963161c92a58d17e38f57695af --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-typeof2.ts @@ -0,0 +1,17 @@ +class Klass { + f: T; + constructor(t: T) { + this.f = t; + } +} +class Foo { + foo: number; + constructor(n: number) { + this.foo = n; + } +} +const PROP = "foo"; +type FooType = Klass; + +var obj: FooType = new Klass(123); +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/generic-typeof2.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-typeof2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e38a4c22cdbb31899776b7e81a965b4d541ee02a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-typeof2.ts.result @@ -0,0 +1,39 @@ +Matched 25 tokens. +Matched 47 tokens. +Matched 52 tokens. +Matched 64 tokens. +Matched 82 tokens. +Matched 89 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + f + Instance Initializer: + Constructors: + constructor (t) throws: + this.f Assign t + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Foo + Fields: + foo + Instance Initializer: + Constructors: + constructor (n) throws: + this.foo Assign n + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_const Decl: PROP="foo" +== Sub Tree == + type FooType = Klass +== Sub Tree == +js_var Decl: obj=new Klass(123) +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/generic-with-func.ts b/src/MapleFE/test/typescript/unit_tests/generic-with-func.ts new file mode 100644 index 0000000000000000000000000000000000000000..1983eb47463a1799a076cc9cb7863b11a334712d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-with-func.ts @@ -0,0 +1,2 @@ +var map: Map void> = new Map(); +console.log(map); diff --git a/src/MapleFE/test/typescript/unit_tests/generic-with-func.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-with-func.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..040306f38b2205de3b09b7e54a0fe44038ee439e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-with-func.ts.result @@ -0,0 +1,7 @@ +Matched 21 tokens. +Matched 28 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: map=new Map() +== Sub Tree == +console.log(map) diff --git a/src/MapleFE/test/typescript/unit_tests/generic-with-init.ts b/src/MapleFE/test/typescript/unit_tests/generic-with-init.ts new file mode 100644 index 0000000000000000000000000000000000000000..b30c847907193b6aeab06a753f3e559db991cec0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-with-init.ts @@ -0,0 +1,9 @@ +class Klass { + u: number = 0; + v: string = ""; + + constructor ({u, v}: Partial= {}) { + this.u = u ? u : this.u; + this.v = v ? v : this.v; + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/generic-with-init.ts.result b/src/MapleFE/test/typescript/unit_tests/generic-with-init.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2eae95e289350e27ee9220b4904ce31491de6b99 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generic-with-init.ts.result @@ -0,0 +1,15 @@ +Matched 58 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + u=0 v="" + Instance Initializer: + Constructors: + constructor ({:u, :v}) throws: + this.u Assign u ? u : this.u + this.v Assign v ? v : this.v + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/generics-array.ts b/src/MapleFE/test/typescript/unit_tests/generics-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..d5fb5bb87c2efaeb61e9285f3e5ad2f782158641 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generics-array.ts @@ -0,0 +1,32 @@ +// Define generic element pool using array +class Pool { + private _pool: T[] = []; + + public put(element: T) { + this._pool.push(element); + } + public get(): T | undefined{ + return this._pool.pop(); + } + public size(): number { + return this._pool.length; + } +} + +class Foo { + public _id: number; + + constructor(id: number) { + this._id = id; + } +} + +// Create array of primary type values +const primPool = new Pool(); +primPool.put(10); +console.log(primPool.get()); + +// Create array of objects +const objPool = new Pool(); +objPool.put(new Foo(100)); +console.log(objPool.get()?._id); diff --git a/src/MapleFE/test/typescript/unit_tests/generics-array.ts.result b/src/MapleFE/test/typescript/unit_tests/generics-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c330b689fe8a683f11e9156c3df428f819cacddd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generics-array.ts.result @@ -0,0 +1,49 @@ +Matched 69 tokens. +Matched 92 tokens. +Matched 103 tokens. +Matched 110 tokens. +Matched 121 tokens. +Matched 132 tokens. +Matched 143 tokens. +Matched 156 tokens. +============= Module =========== +== Sub Tree == +class Pool + Fields: + _pool=[] + Instance Initializer: + Constructors: + Methods: + func put(element) throws: + this._pool.push(element) + func get() throws: + return this._pool.pop() + func size() throws: + return this._pool.length + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Foo + Fields: + _id + Instance Initializer: + Constructors: + constructor (id) throws: + this._id Assign id + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_const Decl: primPool=new Pool() +== Sub Tree == +primPool.put(10) +== Sub Tree == +console.log(primPool.get()) +== Sub Tree == +js_const Decl: objPool=new Pool() +== Sub Tree == +objPool.put(new Foo(100)) +== Sub Tree == +console.log(objPool.get()._id) diff --git a/src/MapleFE/test/typescript/unit_tests/generics.ts b/src/MapleFE/test/typescript/unit_tests/generics.ts new file mode 100644 index 0000000000000000000000000000000000000000..0202303b548f143be66feaad72d31cf4448e3bed --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generics.ts @@ -0,0 +1,7 @@ +function foo(arg: T): T { + return arg; +} + +let output = foo("abc"); + +console.log(output); diff --git a/src/MapleFE/test/typescript/unit_tests/generics.ts.result b/src/MapleFE/test/typescript/unit_tests/generics.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0d04416aa8ff7aa45337bb340f4562741eacbf0c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generics.ts.result @@ -0,0 +1,12 @@ +Matched 17 tokens. +Matched 28 tokens. +Matched 35 tokens. +============= Module =========== +== Sub Tree == +func foo(arg) throws: + return arg + +== Sub Tree == +js_let Decl: output=foo("abc") +== Sub Tree == +console.log(output) diff --git a/src/MapleFE/test/typescript/unit_tests/generics2.ts b/src/MapleFE/test/typescript/unit_tests/generics2.ts new file mode 100644 index 0000000000000000000000000000000000000000..67ae8d57f8c3637d1428f21ae860a5e807c0d311 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generics2.ts @@ -0,0 +1,11 @@ +class E { + t: T | undefined = undefined; +} + +class Klass { + public n: E<{ s: string }> | undefined = undefined; +} + +var obj: Klass = new Klass(); +obj.n = { t: { s: "example" } }; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/generics2.ts.result b/src/MapleFE/test/typescript/unit_tests/generics2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2c8b746200f832bbb7c110000a9f3fbd2e689ecf --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/generics2.ts.result @@ -0,0 +1,32 @@ +Matched 15 tokens. +Matched 35 tokens. +Matched 45 tokens. +Matched 59 tokens. +Matched 66 tokens. +============= Module =========== +== Sub Tree == +class E + Fields: + t=undefined + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Klass + Fields: + n=undefined + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj.n Assign {t: {s:"example"}} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/getter-setter.ts b/src/MapleFE/test/typescript/unit_tests/getter-setter.ts new file mode 100644 index 0000000000000000000000000000000000000000..373eafc9ddfb268597ee4033fba1c8c45af72b9f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/getter-setter.ts @@ -0,0 +1,13 @@ +const obj = { + prop: "foo", + get getProp(): string { + return this.prop; + }, + set setProp(newVal: string) { + this.prop = newVal; + }, +}; + +console.log(obj.getProp); +obj.setProp = "bar"; +console.log(obj.getProp); diff --git a/src/MapleFE/test/typescript/unit_tests/getter-setter.ts.result b/src/MapleFE/test/typescript/unit_tests/getter-setter.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..da6ab4a6d553a4606e2a71d8606eea5ee9c4505c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/getter-setter.ts.result @@ -0,0 +1,17 @@ +Matched 40 tokens. +Matched 49 tokens. +Matched 55 tokens. +Matched 64 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {prop:"foo", getProp:get getProp() throws: + return this.prop +, setProp:set setProp(newVal) throws: + this.prop Assign newVal +} +== Sub Tree == +console.log(obj.getProp) +== Sub Tree == +obj.setProp Assign "bar" +== Sub Tree == +console.log(obj.getProp) diff --git a/src/MapleFE/test/typescript/unit_tests/getter.ts b/src/MapleFE/test/typescript/unit_tests/getter.ts new file mode 100644 index 0000000000000000000000000000000000000000..c4319fd45d12068e4166543eb704810856a8446c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/getter.ts @@ -0,0 +1,3 @@ +var obj = { name: "dummy" }; +Object.defineProperty(obj, "name", { get() { return "Name"; } }); +console.log(obj.name); diff --git a/src/MapleFE/test/typescript/unit_tests/getter.ts.result b/src/MapleFE/test/typescript/unit_tests/getter.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..67c69550bb773a969a1da079103858e5d6ce29b3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/getter.ts.result @@ -0,0 +1,12 @@ +Matched 9 tokens. +Matched 29 tokens. +Matched 38 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: obj= {name:"dummy"} +== Sub Tree == +Object.defineProperty(obj,"name", {get:func get() throws: + return "Name" +}) +== Sub Tree == +console.log(obj.name) diff --git a/src/MapleFE/test/typescript/unit_tests/global-in-module.ts b/src/MapleFE/test/typescript/unit_tests/global-in-module.ts new file mode 100644 index 0000000000000000000000000000000000000000..d10410d40a7eba58de62d2a88c65d5740f62b5cb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/global-in-module.ts @@ -0,0 +1,6 @@ +declare module "Module" { + global { + const flag: boolean; + } +} + diff --git a/src/MapleFE/test/typescript/unit_tests/global-in-module.ts.result b/src/MapleFE/test/typescript/unit_tests/global-in-module.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f113982c133c24b05e6342d5d88203fb4e47c389 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/global-in-module.ts.result @@ -0,0 +1,7 @@ +Matched 13 tokens. +============= Module =========== +== Sub Tree == +declare ============= Module =========== +== Sub Tree == +declare js_const Decl: flag + diff --git a/src/MapleFE/test/typescript/unit_tests/helloworld.ts b/src/MapleFE/test/typescript/unit_tests/helloworld.ts new file mode 100644 index 0000000000000000000000000000000000000000..940a3ff0ec202582f037ef6f743d606fadab9f32 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/helloworld.ts @@ -0,0 +1 @@ +console.log("Hello world!"); diff --git a/src/MapleFE/test/typescript/unit_tests/helloworld.ts.result b/src/MapleFE/test/typescript/unit_tests/helloworld.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ffe76bce9eb05088e26e69f3499b49ccd80654ba --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/helloworld.ts.result @@ -0,0 +1,4 @@ +Matched 7 tokens. +============= Module =========== +== Sub Tree == +console.log("Hello world!") diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers.ts b/src/MapleFE/test/typescript/unit_tests/identifiers.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf4114c78248c87813d45bf7b23e322a6c007938 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers.ts @@ -0,0 +1,10 @@ +// Valid identifiers: +// abstract as async await +// constructor declare from get +// is module namespace of +// require set type + +function type() { + return "type"; +} +console.log(type()); diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a15445adc884360ece9677f9ceb6a8f5ce727d6e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers.ts.result @@ -0,0 +1,9 @@ +Matched 9 tokens. +Matched 18 tokens. +============= Module =========== +== Sub Tree == +func type() throws: + return "type" + +== Sub Tree == +console.log(type()) diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers10.ts b/src/MapleFE/test/typescript/unit_tests/identifiers10.ts new file mode 100644 index 0000000000000000000000000000000000000000..e1b196a6a6ee5451dba73b5dd2b1957edf077059 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers10.ts @@ -0,0 +1,3 @@ +interface IFace { + throw?: boolean; +} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers10.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers10.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7444472b77e087220bf902b1d2a17477039e76d6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers10.ts.result @@ -0,0 +1,4 @@ +Matched 9 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {throw? } diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers11.ts b/src/MapleFE/test/typescript/unit_tests/identifiers11.ts new file mode 100644 index 0000000000000000000000000000000000000000..5e364b1047e3f264333bf85adb13aef5da68cd1a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers11.ts @@ -0,0 +1,7 @@ +enum ET { + type = "type", + with = "with" +} +abstract class Base { f1: U | null = null; f2: V | null = null; } +declare class Klass extends Base {} + diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers11.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers11.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f9e41d0f91caa8d444bf5cd3f7d36044f9562ea2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers11.ts.result @@ -0,0 +1,26 @@ +Matched 11 tokens. +Matched 41 tokens. +Matched 57 tokens. +============= Module =========== +== Sub Tree == +ts_enum: ET {type="type";with="with" } +== Sub Tree == +class Base + Fields: + f1=null f2=null + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +declare class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers12.ts b/src/MapleFE/test/typescript/unit_tests/identifiers12.ts new file mode 100644 index 0000000000000000000000000000000000000000..6aa95479017d778d0a3703d6ce09e3fe27743e84 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers12.ts @@ -0,0 +1,10 @@ +class Klass { + f1: number = 123; + f2: string = "abc"; +} +const obj = { + func: (o: Klass) : Klass => { + return { ...o, private: false }; + }, +}; +console.log(obj.func(new Klass())); diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers12.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers12.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..87ebf81724a87661aaf93e7663b789129ced54ac --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers12.ts.result @@ -0,0 +1,19 @@ +Matched 16 tokens. +Matched 48 tokens. +Matched 63 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + f1=123 f2="abc" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_const Decl: obj= {func:(o) -> return (any) {:...o, private:false} +} +== Sub Tree == +console.log(obj.func(new Klass())) diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers13.ts b/src/MapleFE/test/typescript/unit_tests/identifiers13.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f84141b35505d04c131242a9923031e3bb9269c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers13.ts @@ -0,0 +1,4 @@ +interface IFace { + type: string; + break: boolean; +} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers13.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers13.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..83468c8dd5fca97802cce142ce32f59e8e9706c8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers13.ts.result @@ -0,0 +1,4 @@ +Matched 12 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {type;break } diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers14.ts b/src/MapleFE/test/typescript/unit_tests/identifiers14.ts new file mode 100644 index 0000000000000000000000000000000000000000..9279f9018ad0e8b6d63540a4bd3033be726e7414 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers14.ts @@ -0,0 +1,3 @@ +interface IFace { + static(n: number): string; +} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers14.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers14.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..323821496c69a5b309b580ec9fae0460784bb42c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers14.ts.result @@ -0,0 +1,5 @@ +Matched 13 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {func static(n) throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers15.ts b/src/MapleFE/test/typescript/unit_tests/identifiers15.ts new file mode 100644 index 0000000000000000000000000000000000000000..a49d4aceb2713a97d9bab889f56a00567c3db13d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers15.ts @@ -0,0 +1,2 @@ +const obj: { class: any } = { class : "Class" }; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers15.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers15.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..4874d30a5c52a3a9d6be7ae319cfb17ac0022368 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers15.ts.result @@ -0,0 +1,7 @@ +Matched 15 tokens. +Matched 22 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {class:"Class"} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers16.ts b/src/MapleFE/test/typescript/unit_tests/identifiers16.ts new file mode 100644 index 0000000000000000000000000000000000000000..d907f06d33903035f39e1ace80e5b29e4186d26e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers16.ts @@ -0,0 +1,2 @@ +const obj: { unknown: any } = { unknown : "Unknown" }; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers16.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers16.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e3c738868ecca035515409697f480231b028c3e1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers16.ts.result @@ -0,0 +1,7 @@ +Matched 15 tokens. +Matched 22 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {unknown:"Unknown"} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers17.ts b/src/MapleFE/test/typescript/unit_tests/identifiers17.ts new file mode 100644 index 0000000000000000000000000000000000000000..dea0e73a4f5c357848ab07bdbc00d44781954bf6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers17.ts @@ -0,0 +1,2 @@ +const obj: { do: any } = { do : "do" }; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers17.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers17.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..eef4e0a980e5fb42aaeb9310582494dcd1375a67 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers17.ts.result @@ -0,0 +1,7 @@ +Matched 15 tokens. +Matched 22 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {do:"do"} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers18.ts b/src/MapleFE/test/typescript/unit_tests/identifiers18.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6ae53f9809719f8a8fb08c30ab8ee04db36ea5b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers18.ts @@ -0,0 +1,5 @@ +interface IFace { + if?: string; + then?: string; + else?: string; +} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers18.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers18.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..dc287fd11da7f2cf24c1e6a186f2208ece445b83 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers18.ts.result @@ -0,0 +1,4 @@ +Matched 19 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {if?;then?;else? } diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers19.ts b/src/MapleFE/test/typescript/unit_tests/identifiers19.ts new file mode 100644 index 0000000000000000000000000000000000000000..c0a7c875a11c3b4da0b3591fd6030d2f03d37138 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers19.ts @@ -0,0 +1,3 @@ +interface IFace { + continue(): void; +} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers19.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers19.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..57e221624fb012faa2709aba01a73f22454a67ab --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers19.ts.result @@ -0,0 +1,5 @@ +Matched 10 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {func continue() throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers2.ts b/src/MapleFE/test/typescript/unit_tests/identifiers2.ts new file mode 100644 index 0000000000000000000000000000000000000000..766bd3d702050e868c326e124a9bb38a6890eff6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers2.ts @@ -0,0 +1,75 @@ +// Valid identifiers: +// abstract as async await +// constructor declare from get +// is module namespace of +// require set type + +function abstract() { + return "abstract"; +} +console.log(abstract()); + +function as() { + return "as"; +} +console.log(as()); + +function async() { + return "async"; +} +console.log(async()); + +function await() { + return "await"; +} +console.log(await()); + +function constructor() { + return "constructor"; +} +console.log(constructor()); + +function declare() { + return "declare"; +} +console.log(declare()); + +function from() { + return "from"; +} +console.log(from()); + +function get() { + return "get"; +} +console.log(get()); + +function is() { + return "is"; +} +console.log(is()); + +function module() { + return "module"; +} +console.log(module()); + +function namespace() { + return "namespace"; +} +console.log(namespace()); + +function of() { + return "of"; +} +console.log(of()); + +function require() { + return "require"; +} +console.log(require()); + +function set() { + return "set"; +} +console.log(set()); diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers2.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2171c7e9c0c72fbc1c1bd8656bd4a91605c2b8e4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers2.ts.result @@ -0,0 +1,113 @@ +Matched 9 tokens. +Matched 18 tokens. +Matched 27 tokens. +Matched 36 tokens. +Matched 45 tokens. +Matched 54 tokens. +Matched 63 tokens. +Matched 72 tokens. +Matched 81 tokens. +Matched 90 tokens. +Matched 99 tokens. +Matched 108 tokens. +Matched 117 tokens. +Matched 126 tokens. +Matched 135 tokens. +Matched 144 tokens. +Matched 153 tokens. +Matched 162 tokens. +Matched 171 tokens. +Matched 180 tokens. +Matched 189 tokens. +Matched 198 tokens. +Matched 207 tokens. +Matched 216 tokens. +Matched 225 tokens. +Matched 234 tokens. +Matched 243 tokens. +Matched 252 tokens. +============= Module =========== +== Sub Tree == +func abstract() throws: + return "abstract" + +== Sub Tree == +console.log(abstract()) +== Sub Tree == +func as() throws: + return "as" + +== Sub Tree == +console.log(as()) +== Sub Tree == +func async() throws: + return "async" + +== Sub Tree == +console.log(async()) +== Sub Tree == +func await() throws: + return "await" + +== Sub Tree == +console.log(await()) +== Sub Tree == +func constructor() throws: + return "constructor" + +== Sub Tree == +console.log(constructor()) +== Sub Tree == +func declare() throws: + return "declare" + +== Sub Tree == +console.log(declare()) +== Sub Tree == +func from() throws: + return "from" + +== Sub Tree == +console.log(from()) +== Sub Tree == +func get() throws: + return "get" + +== Sub Tree == +console.log(get()) +== Sub Tree == +func is() throws: + return "is" + +== Sub Tree == +console.log(is()) +== Sub Tree == +func module() throws: + return "module" + +== Sub Tree == +console.log(module()) +== Sub Tree == +func namespace() throws: + return "namespace" + +== Sub Tree == +console.log(namespace()) +== Sub Tree == +func of() throws: + return "of" + +== Sub Tree == +console.log(of()) +== Sub Tree == +func require() throws: + return "require" + +== Sub Tree == +console.log(require()) +== Sub Tree == +func set() throws: + return "set" + +== Sub Tree == +console.log(set()) diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers20.ts b/src/MapleFE/test/typescript/unit_tests/identifiers20.ts new file mode 100644 index 0000000000000000000000000000000000000000..afe4d26516226adf676dc6949e8967248f417174 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers20.ts @@ -0,0 +1,11 @@ +class Klass { + items: number[] = []; + break() { + for (const i of this.items) + console.log(i); + } +} + +var obj: Klass = new Klass(); +obj.items.push(6, 2, 1, 4, 5, 3); +obj.break(); diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers20.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers20.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e9df6598ad3261266dd98f7b1cf95cb3c98d99a9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers20.ts.result @@ -0,0 +1,24 @@ +Matched 34 tokens. +Matched 44 tokens. +Matched 63 tokens. +Matched 69 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + items=[] + Instance Initializer: + Constructors: + Methods: + func break() throws: + for ( ) + console.log(i) + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj.items.push(6,2,1,4,5,3) +== Sub Tree == +obj.break() diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers3.ts b/src/MapleFE/test/typescript/unit_tests/identifiers3.ts new file mode 100644 index 0000000000000000000000000000000000000000..af4744e292e7bd55cea6f78b7655a522711dee51 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers3.ts @@ -0,0 +1,6 @@ +export declare class Foo { + asserts: boolean; + trueType: string; + falseType: string; + constructor(asserts: boolean, trueType: string, falseType: string); +} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers3.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..649256342bff594978c925f4f3330c1601ae6cc1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers3.ts.result @@ -0,0 +1,13 @@ +Matched 33 tokens. +============= Module =========== +== Sub Tree == +export {declare class Foo + Fields: + asserts trueType falseType + Instance Initializer: + Constructors: + constructor (asserts,trueType,falseType) throws: + Methods: + LocalClasses: + LocalInterfaces: +} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers4.ts b/src/MapleFE/test/typescript/unit_tests/identifiers4.ts new file mode 100644 index 0000000000000000000000000000000000000000..dc8534dae2baabc0e5d0e74d7b31d494719c1822 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers4.ts @@ -0,0 +1,4 @@ +interface Inferf { + return(v: string): string; + throw(e: string): string; +} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers4.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..145b8050dea45cd04f47baa3bf9c962cde3fef56 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers4.ts.result @@ -0,0 +1,6 @@ +Matched 22 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Inferf {func return(v) throws: +;func throw(e) throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers5.ts b/src/MapleFE/test/typescript/unit_tests/identifiers5.ts new file mode 100644 index 0000000000000000000000000000000000000000..afe36ce702b0083941acd589e6e52070543222e2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers5.ts @@ -0,0 +1,3 @@ +interface IFace { + finally(): IFace; +} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers5.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers5.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5377924b5cd82ebf89a9a70847c55e0ba2aaa86e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers5.ts.result @@ -0,0 +1,5 @@ +Matched 16 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {func finally() throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers6.ts b/src/MapleFE/test/typescript/unit_tests/identifiers6.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c13d2ae8877e80973c37af912747f538402cae3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers6.ts @@ -0,0 +1,3 @@ +interface IFace { + for(s: string): any; +} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers6.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers6.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..bb3cb69bf520b441d046957bc591bb1d67d4625b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers6.ts.result @@ -0,0 +1,5 @@ +Matched 13 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {func for(s) throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers7.ts b/src/MapleFE/test/typescript/unit_tests/identifiers7.ts new file mode 100644 index 0000000000000000000000000000000000000000..975eed4d538faead8b25369477fa3d4e0b389798 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers7.ts @@ -0,0 +1,4 @@ +interface Inferf { + return?(v?: string): string; + throw?(e?: string): string; +} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers7.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers7.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ac09659add4eeebbb331a3cee7eaa2618c2c1b2c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers7.ts.result @@ -0,0 +1,6 @@ +Matched 26 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Inferf {func return?(v?) throws: +;func throw?(e?) throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers8.ts b/src/MapleFE/test/typescript/unit_tests/identifiers8.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f2107c4064055b927c4815733ef310d85390a33 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers8.ts @@ -0,0 +1,3 @@ +var func = () => 1; +export { func as function }; + diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers8.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers8.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0b3473672a7a2b78f3b66cee0fd9e67af175ce1d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers8.ts.result @@ -0,0 +1,7 @@ +Matched 8 tokens. +Matched 15 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: func=() -> 1 +== Sub Tree == +export {func as function} diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers9.ts b/src/MapleFE/test/typescript/unit_tests/identifiers9.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d2c02a8a9dacd626ac4b3bdfb0d36de596a3267 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers9.ts @@ -0,0 +1,6 @@ +enum E { + package = "package" +} + +var x: E = E.package; +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/identifiers9.ts.result b/src/MapleFE/test/typescript/unit_tests/identifiers9.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1f59266a702a0a2b14eb28988a4279f7fd21dc3e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/identifiers9.ts.result @@ -0,0 +1,10 @@ +Matched 7 tokens. +Matched 16 tokens. +Matched 23 tokens. +============= Module =========== +== Sub Tree == +ts_enum: E {package="package" } +== Sub Tree == +js_var Decl: x=E.package +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/if-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..c61336ffad50ab0113d6456c62f247e95ad7c504 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name.ts @@ -0,0 +1,3 @@ +interface IFace { + if: string; +} diff --git a/src/MapleFE/test/typescript/unit_tests/if-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b20da9ed661b00c1224343241f99eba3d7d75399 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name.ts.result @@ -0,0 +1,4 @@ +Matched 8 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {if } diff --git a/src/MapleFE/test/typescript/unit_tests/if-as-prop-name2.ts b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name2.ts new file mode 100644 index 0000000000000000000000000000000000000000..558b7aea596503d97597f5410cf6b0f279996440 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name2.ts @@ -0,0 +1,4 @@ +class Klass { + static if: string = "prop"; +} +console.log(Klass.if); diff --git a/src/MapleFE/test/typescript/unit_tests/if-as-prop-name2.ts.result b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f788043747f3ecbc48cd44e7948e59567f37e69e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name2.ts.result @@ -0,0 +1,15 @@ +Matched 11 tokens. +Matched 20 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + if="prop" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +console.log(Klass.if) diff --git a/src/MapleFE/test/typescript/unit_tests/if-as-prop-name3.ts b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name3.ts new file mode 100644 index 0000000000000000000000000000000000000000..a9cdaf09c6b2f2fc3866dca7ceb072072669d7ea --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name3.ts @@ -0,0 +1,2 @@ +const obj = { if() { console.log("if"); } } +obj.if(); diff --git a/src/MapleFE/test/typescript/unit_tests/if-as-prop-name3.ts.result b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..171ccc1b720dd1ef2071cd28c39e3182fa1189bb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-as-prop-name3.ts.result @@ -0,0 +1,9 @@ +Matched 17 tokens. +Matched 23 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {if:func if() throws: + console.log("if") +} +== Sub Tree == +obj.if() diff --git a/src/MapleFE/test/typescript/unit_tests/if-else-1.ts b/src/MapleFE/test/typescript/unit_tests/if-else-1.ts new file mode 100644 index 0000000000000000000000000000000000000000..0edb1d0abd2f9fed9a11d7980826a6e2e9519f8e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-else-1.ts @@ -0,0 +1,4 @@ +var a: number = 1; +var b: number = 2; +if (a > b) console.log("bigger"); +else console.log("smaller"); diff --git a/src/MapleFE/test/typescript/unit_tests/if-else-1.ts.result b/src/MapleFE/test/typescript/unit_tests/if-else-1.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..22c29c9f261138b846a88d1bcf341ce961a71789 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-else-1.ts.result @@ -0,0 +1,13 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 35 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: a=1 +== Sub Tree == +js_var Decl: b=2 +== Sub Tree == +cond-branch cond:a GT b +true branch : + console.log("bigger")false branch : + console.log("smaller") diff --git a/src/MapleFE/test/typescript/unit_tests/if-else-2.ts b/src/MapleFE/test/typescript/unit_tests/if-else-2.ts new file mode 100644 index 0000000000000000000000000000000000000000..1fb2acaadf2221aa6d7f6eb2371b8bfa0cbf3152 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-else-2.ts @@ -0,0 +1,4 @@ +var a: number = 2; +var b: number = 1;; +if (1) a + b; +else a - b; diff --git a/src/MapleFE/test/typescript/unit_tests/if-else-2.ts.result b/src/MapleFE/test/typescript/unit_tests/if-else-2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..add6831277eb203efe3bbd8feea79e13e0b949f7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-else-2.ts.result @@ -0,0 +1,14 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 15 tokens. +Matched 28 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: a=2 +== Sub Tree == +js_var Decl: b=1 +== Sub Tree == +cond-branch cond:1 +true branch : + a Add bfalse branch : + a Sub b diff --git a/src/MapleFE/test/typescript/unit_tests/if-else-3.ts b/src/MapleFE/test/typescript/unit_tests/if-else-3.ts new file mode 100644 index 0000000000000000000000000000000000000000..68d525a28faa6e0bb14b599725bbeaf21a49537a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-else-3.ts @@ -0,0 +1,7 @@ +var x: number = 1; +var a: number = 2; +var b: number = 3; +if (x) a + b; +else if (x) a - b; +else if (x) a * b; +else a / b; diff --git a/src/MapleFE/test/typescript/unit_tests/if-else-3.ts.result b/src/MapleFE/test/typescript/unit_tests/if-else-3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..93d0ecb30469890b7b1edbe10813b908ad7a39eb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-else-3.ts.result @@ -0,0 +1,22 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 21 tokens. +Matched 52 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=1 +== Sub Tree == +js_var Decl: a=2 +== Sub Tree == +js_var Decl: b=3 +== Sub Tree == +cond-branch cond:x +true branch : + a Add bfalse branch : + cond-branch cond:x + true branch : + a Sub b false branch : + cond-branch cond:x + true branch : + a Mul b false branch : + a Div b diff --git a/src/MapleFE/test/typescript/unit_tests/if-stmt-return.ts b/src/MapleFE/test/typescript/unit_tests/if-stmt-return.ts new file mode 100644 index 0000000000000000000000000000000000000000..a0c9900940d3a7ddb2f83abe1fa3404c313f2c2c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-stmt-return.ts @@ -0,0 +1,5 @@ +function func(x: number): void { + if (x > 10) return; + console.log(x); +} +func(2); diff --git a/src/MapleFE/test/typescript/unit_tests/if-stmt-return.ts.result b/src/MapleFE/test/typescript/unit_tests/if-stmt-return.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..9c4909c8379577be7814160d02b9770a695f6ef1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/if-stmt-return.ts.result @@ -0,0 +1,13 @@ +Matched 26 tokens. +Matched 31 tokens. +============= Module =========== +== Sub Tree == +func func(x) throws: + cond-branch cond:x GT 10 + true branch : + return false branch : + + console.log(x) + +== Sub Tree == +func(2) diff --git a/src/MapleFE/test/typescript/unit_tests/iife.ts b/src/MapleFE/test/typescript/unit_tests/iife.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf2f22435ebe42212862e609cec140b3c1386ebf --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/iife.ts @@ -0,0 +1,4 @@ +let x: number = 3; +(function () { + console.log(x * x); +})(); diff --git a/src/MapleFE/test/typescript/unit_tests/iife.ts.result b/src/MapleFE/test/typescript/unit_tests/iife.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f2a003a9a9ae16dbc648b813b6843daa965bb912 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/iife.ts.result @@ -0,0 +1,9 @@ +Matched 7 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: x=3 +== Sub Tree == +func () throws: + console.log(x Mul x) +() diff --git a/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..49dfd11867a37486316b085c3c68a0ee359de450 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name.ts @@ -0,0 +1,6 @@ +interface IFace { + implements : string; +} + +var obj: IFace = { implements: "implements" }; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..85611f66fef88942c741d238ce59e61daf25548e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name.ts.result @@ -0,0 +1,10 @@ +Matched 8 tokens. +Matched 19 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {implements } +== Sub Tree == +js_var Decl: obj= {implements:"implements"} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name2.ts b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name2.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5bae426828e40b8cd9770450e747a965843f426 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name2.ts @@ -0,0 +1,6 @@ +interface IFace { + implements? : string; +} + +var obj: IFace = { implements: "implements" }; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name2.ts.result b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..d491d27e0bf901e973ed0cf90ee7e782e3ebac13 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name2.ts.result @@ -0,0 +1,10 @@ +Matched 9 tokens. +Matched 20 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {implements? } +== Sub Tree == +js_var Decl: obj= {implements:"implements"} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name3.ts b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name3.ts new file mode 100644 index 0000000000000000000000000000000000000000..d457cadedcb3dedc87f55f38531ef4eaeb68b675 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name3.ts @@ -0,0 +1,6 @@ +interface IFace { + implements? : string; +} + +var obj: IFace = { implements: "implements" }; +console.log(obj.implements); diff --git a/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name3.ts.result b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..cc7ad1ff5167b09d496af637e30ca13940684cf1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/implements-as-prop-name3.ts.result @@ -0,0 +1,10 @@ +Matched 9 tokens. +Matched 20 tokens. +Matched 29 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {implements? } +== Sub Tree == +js_var Decl: obj= {implements:"implements"} +== Sub Tree == +console.log(obj.implements) diff --git a/src/MapleFE/test/typescript/unit_tests/import-ambient-module.ts b/src/MapleFE/test/typescript/unit_tests/import-ambient-module.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f98d352e05f8124c1a09b25ceceb52540d2c595 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-ambient-module.ts @@ -0,0 +1,3 @@ +/// +import { X } from "M1"; +import { NS } from "M2"; diff --git a/src/MapleFE/test/typescript/unit_tests/import-ambient-module.ts.result b/src/MapleFE/test/typescript/unit_tests/import-ambient-module.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c71e900f9a1c38da2856901eb5858a378b61611c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-ambient-module.ts.result @@ -0,0 +1,10 @@ +Matched 8 tokens. +Matched 15 tokens. +Matched 22 tokens. +============= Module =========== +== Sub Tree == +trip-slash reference path = "import-in-module.ts" +== Sub Tree == +import {X} "M1" +== Sub Tree == +import {NS} "M2" diff --git a/src/MapleFE/test/typescript/unit_tests/import-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/import-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..98e0884aa562bc94c8fecdaf61e1bab04a2a9749 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-as-prop-name.ts @@ -0,0 +1,3 @@ +declare interface Load { + import(n: string, o?: string): Promise; +} diff --git a/src/MapleFE/test/typescript/unit_tests/import-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/import-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3cb7c20598b67fac6a040d32bcdc13d1d0696e0c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-as-prop-name.ts.result @@ -0,0 +1,5 @@ +Matched 22 tokens. +============= Module =========== +== Sub Tree == +declare ts_interface: Load {func import(n,o?) throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/import-class.ts b/src/MapleFE/test/typescript/unit_tests/import-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..fc319f54b4dc05e65d586f1621822291b3494dee --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-class.ts @@ -0,0 +1,3 @@ +import Bar = require("./export-class"); +let obj = new Bar(123, 456); +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/import-class.ts.result b/src/MapleFE/test/typescript/unit_tests/import-class.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3660e1fc6f0565bc73149797f2ed1ec1a524e5d3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-class.ts.result @@ -0,0 +1,10 @@ +Matched 8 tokens. +Matched 19 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +import { SINGLE "./export-class" as Bar} +== Sub Tree == +js_let Decl: obj=new Bar(123,456) +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/import-class2.ts b/src/MapleFE/test/typescript/unit_tests/import-class2.ts new file mode 100644 index 0000000000000000000000000000000000000000..579dd6551cd5d8d37403afe44d6e2a5611b1b53d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-class2.ts @@ -0,0 +1,3 @@ +import { default as Bar } from "./export-class"; +let obj = new Bar(123, 456); +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/import-class2.ts.result b/src/MapleFE/test/typescript/unit_tests/import-class2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..9f2aae989ad862ee6a2d93cdcce2ed2684efdbef --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-class2.ts.result @@ -0,0 +1,10 @@ +Matched 9 tokens. +Matched 20 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +import {default as Bar} "./export-class" +== Sub Tree == +js_let Decl: obj=new Bar(123,456) +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/import-deco.ts b/src/MapleFE/test/typescript/unit_tests/import-deco.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed4af2f38218a42f5e9de614d3b1d638e6eb7094 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-deco.ts @@ -0,0 +1,12 @@ +import * as deco from "./deco-module"; + +class Klass { + @deco.prop_deco("of") + x: number; + constructor(i: number) { + this.x = i; + } +} + +var c = new Klass(3); +console.log(c.x); diff --git a/src/MapleFE/test/typescript/unit_tests/import-deco.ts.result b/src/MapleFE/test/typescript/unit_tests/import-deco.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b416506be02af92be2390cfdb75dd15052db926e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-deco.ts.result @@ -0,0 +1,23 @@ +Matched 7 tokens. +Matched 36 tokens. +Matched 45 tokens. +Matched 54 tokens. +============= Module =========== +== Sub Tree == +import { * as deco} "./deco-module" +== Sub Tree == +class Klass + Fields: + x + Instance Initializer: + Constructors: + constructor (i) throws: + this.x Assign i + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: c=new Klass(3) +== Sub Tree == +console.log(c.x) diff --git a/src/MapleFE/test/typescript/unit_tests/import-default-class.ts b/src/MapleFE/test/typescript/unit_tests/import-default-class.ts new file mode 100644 index 0000000000000000000000000000000000000000..fdfa5581e5e59b0c7bac91cb4f0b2457361ae6f4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-default-class.ts @@ -0,0 +1,3 @@ +import type Klass from "./export-default-class"; +var obj: Klass = { f1: 123, f2: "abc" }; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/import-default-class.ts.result b/src/MapleFE/test/typescript/unit_tests/import-default-class.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..85e020e5d1ba8d1c4b4bd96398f26e7e12b7c77b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-default-class.ts.result @@ -0,0 +1,10 @@ +Matched 6 tokens. +Matched 21 tokens. +Matched 28 tokens. +============= Module =========== +== Sub Tree == +import { default as Klass} "./export-default-class" +== Sub Tree == +js_var Decl: obj= {f1:123, f2:"abc"} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/import-in-module.ts b/src/MapleFE/test/typescript/unit_tests/import-in-module.ts new file mode 100644 index 0000000000000000000000000000000000000000..cd706044623cdefc7e52f80b0f2821e9516f0fe9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-in-module.ts @@ -0,0 +1,9 @@ +declare module 'M1' { + export interface X {} +} + +declare module 'M2' { + import { X } from "M1"; + export namespace NS { + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/import-in-module.ts.result b/src/MapleFE/test/typescript/unit_tests/import-in-module.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1dc7f0b4475a3f28245bb162d2f6a339efa8f1e7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-in-module.ts.result @@ -0,0 +1,16 @@ +Matched 10 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +declare ============= Module =========== +== Sub Tree == +export {ts_interface: X { }} + +== Sub Tree == +declare ============= Module =========== +== Sub Tree == +import {X} "M1" +== Sub Tree == +export {namespace NS +} + diff --git a/src/MapleFE/test/typescript/unit_tests/import-promise.ts b/src/MapleFE/test/typescript/unit_tests/import-promise.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e3ee013a75a19c62f9517bd469905b43edaf889 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-promise.ts @@ -0,0 +1,2 @@ +import("./M").then(() => { console.log("Completed") } ); + diff --git a/src/MapleFE/test/typescript/unit_tests/import-promise.ts.result b/src/MapleFE/test/typescript/unit_tests/import-promise.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e9813196aa05ea002db4b550d65a4d48c7f8cf3a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-promise.ts.result @@ -0,0 +1,5 @@ +Matched 20 tokens. +============= Module =========== +== Sub Tree == +import "./M".then(() -> console.log("Completed") +) diff --git a/src/MapleFE/test/typescript/unit_tests/import-promise2.ts b/src/MapleFE/test/typescript/unit_tests/import-promise2.ts new file mode 100644 index 0000000000000000000000000000000000000000..5426f510aea1adc4d2e8a4ff99779ef0e2552f35 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-promise2.ts @@ -0,0 +1,6 @@ +const m : string = "./M"; +import(`${m}`).then(() => { + console.log("Completed") +}).catch(() => { + console.log("Failed") +}); diff --git a/src/MapleFE/test/typescript/unit_tests/import-promise2.ts.result b/src/MapleFE/test/typescript/unit_tests/import-promise2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..919ef976f976b0c311810a71d2efa0dddd6706f5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-promise2.ts.result @@ -0,0 +1,10 @@ +Matched 7 tokens. +Matched 42 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: m="./M" +== Sub Tree == +import template-literal: NULL,m.then(() -> console.log("Completed") +).catch(() -> console.log("Failed") +) diff --git a/src/MapleFE/test/typescript/unit_tests/import-type.ts b/src/MapleFE/test/typescript/unit_tests/import-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a61f6f18a5164570d361f7607fd17635f0d09b9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-type.ts @@ -0,0 +1 @@ +import type { Foo } from "./export-type"; diff --git a/src/MapleFE/test/typescript/unit_tests/import-type.ts.result b/src/MapleFE/test/typescript/unit_tests/import-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..202238fb32e24ef6a8669810faa478cb867fa005 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-type.ts.result @@ -0,0 +1,4 @@ +Matched 8 tokens. +============= Module =========== +== Sub Tree == +import {Foo} "./export-type" diff --git a/src/MapleFE/test/typescript/unit_tests/import-type2.ts b/src/MapleFE/test/typescript/unit_tests/import-type2.ts new file mode 100644 index 0000000000000000000000000000000000000000..214a68b24edceea1adc80ca6d92353339d1c7ea9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-type2.ts @@ -0,0 +1 @@ +import type { Foo } from "./export-type2"; diff --git a/src/MapleFE/test/typescript/unit_tests/import-type2.ts.result b/src/MapleFE/test/typescript/unit_tests/import-type2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..99a5ed674470358edcc9961ee0ed6be5083bce3f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-type2.ts.result @@ -0,0 +1,4 @@ +Matched 8 tokens. +============= Module =========== +== Sub Tree == +import {Foo} "./export-type2" diff --git a/src/MapleFE/test/typescript/unit_tests/import-type3.ts b/src/MapleFE/test/typescript/unit_tests/import-type3.ts new file mode 100644 index 0000000000000000000000000000000000000000..093737c50ae88d4521035b70944c883b0ac61d06 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-type3.ts @@ -0,0 +1 @@ +import type * as TY from "./export-type2"; diff --git a/src/MapleFE/test/typescript/unit_tests/import-type3.ts.result b/src/MapleFE/test/typescript/unit_tests/import-type3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..fe57c8b11faf12ffe743e2e0e0e32da2fab13a00 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-type3.ts.result @@ -0,0 +1,4 @@ +Matched 8 tokens. +============= Module =========== +== Sub Tree == +import { * as TY} "./export-type2" diff --git a/src/MapleFE/test/typescript/unit_tests/import-type4.ts b/src/MapleFE/test/typescript/unit_tests/import-type4.ts new file mode 100644 index 0000000000000000000000000000000000000000..21cacbd55c1103bf01d4704cc6e56b2940912681 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-type4.ts @@ -0,0 +1,4 @@ +declare const obj: { + readonly 'X.Foo': Record; +}; +export { obj }; diff --git a/src/MapleFE/test/typescript/unit_tests/import-type4.ts.result b/src/MapleFE/test/typescript/unit_tests/import-type4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..defa7e018de68be5a31a77516b014e8e348d1127 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/import-type4.ts.result @@ -0,0 +1,7 @@ +Matched 22 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +declare js_const Decl: obj +== Sub Tree == +export {obj} diff --git a/src/MapleFE/test/typescript/unit_tests/imported-type.ts b/src/MapleFE/test/typescript/unit_tests/imported-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ebc576861d532c59d68842b2f40aaf84a53e4b0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/imported-type.ts @@ -0,0 +1,3 @@ +declare class Klass { + public get flag(): import("./enum2").ET; +} diff --git a/src/MapleFE/test/typescript/unit_tests/imported-type.ts.result b/src/MapleFE/test/typescript/unit_tests/imported-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..d39d2f1ca4f41e9ff4e7c6be60e0b6f7f14f114f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/imported-type.ts.result @@ -0,0 +1,13 @@ +Matched 18 tokens. +============= Module =========== +== Sub Tree == +declare class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + get flag() throws: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/in-operator.ts b/src/MapleFE/test/typescript/unit_tests/in-operator.ts new file mode 100644 index 0000000000000000000000000000000000000000..574e83ca148e24328aa87bb481b611510bd0ad4e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/in-operator.ts @@ -0,0 +1,3 @@ +var arr: number[] = [1, 2, 3, 4, 5]; +console.log(3 in arr); +console.log(7 in arr); diff --git a/src/MapleFE/test/typescript/unit_tests/in-operator.ts.result b/src/MapleFE/test/typescript/unit_tests/in-operator.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..4a97d98d41df6c250bc686cb7c6582001c9bbee9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/in-operator.ts.result @@ -0,0 +1,10 @@ +Matched 19 tokens. +Matched 28 tokens. +Matched 37 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[1,2,3,4,5] +== Sub Tree == +console.log(3 in arr) +== Sub Tree == +console.log(7 in arr) diff --git a/src/MapleFE/test/typescript/unit_tests/in-operator2.ts b/src/MapleFE/test/typescript/unit_tests/in-operator2.ts new file mode 100644 index 0000000000000000000000000000000000000000..0d0f5ffe7ab5510fe31d8826a9049149da56e804 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/in-operator2.ts @@ -0,0 +1,8 @@ +type T = { + name: string; + age: number; +}; + +var obj: T = { name: "John", age: 30 }; +console.log("name" in obj); +console.log("Age" in obj); diff --git a/src/MapleFE/test/typescript/unit_tests/in-operator2.ts.result b/src/MapleFE/test/typescript/unit_tests/in-operator2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a2534da4adfedc1fe7a6e3c2b35d0c4bfc5e2e7b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/in-operator2.ts.result @@ -0,0 +1,13 @@ +Matched 14 tokens. +Matched 29 tokens. +Matched 38 tokens. +Matched 47 tokens. +============= Module =========== +== Sub Tree == + type T = {name;age } +== Sub Tree == +js_var Decl: obj= {name:"John", age:30} +== Sub Tree == +console.log("name" in obj) +== Sub Tree == +console.log("Age" in obj) diff --git a/src/MapleFE/test/typescript/unit_tests/index-signature-1.ts b/src/MapleFE/test/typescript/unit_tests/index-signature-1.ts new file mode 100644 index 0000000000000000000000000000000000000000..54764a60512f5490c3173692eb894e5670eddfe6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/index-signature-1.ts @@ -0,0 +1,4 @@ +interface dictionary { + [index: string]: number; + id: number; +} diff --git a/src/MapleFE/test/typescript/unit_tests/index-signature-1.ts.result b/src/MapleFE/test/typescript/unit_tests/index-signature-1.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..44784cbe74a45d9e4f156bff07344e7bdce3b31b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/index-signature-1.ts.result @@ -0,0 +1,4 @@ +Matched 16 tokens. +============= Module =========== +== Sub Tree == +ts_interface: dictionary {string index type: numberid } diff --git a/src/MapleFE/test/typescript/unit_tests/index-signature-2.ts b/src/MapleFE/test/typescript/unit_tests/index-signature-2.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4666349860fe800649cb94f27b28e01448fcdca --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/index-signature-2.ts @@ -0,0 +1,5 @@ +class Klass { + [key: string]: number; +}; + +type MyArray = Array; diff --git a/src/MapleFE/test/typescript/unit_tests/index-signature-2.ts.result b/src/MapleFE/test/typescript/unit_tests/index-signature-2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8d4f6fe7da05e49b9238e4cdaf927572bc62ec59 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/index-signature-2.ts.result @@ -0,0 +1,16 @@ +Matched 12 tokens. +Matched 13 tokens. +Matched 36 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + number + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == + type MyArray = Array diff --git a/src/MapleFE/test/typescript/unit_tests/infer-type.ts b/src/MapleFE/test/typescript/unit_tests/infer-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..3b4603d30c2b26ede91fbd5d663917a0269ba08f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/infer-type.ts @@ -0,0 +1,2 @@ +type U = { n: number }; +type E = T extends Array ? T : U; diff --git a/src/MapleFE/test/typescript/unit_tests/infer-type.ts.result b/src/MapleFE/test/typescript/unit_tests/infer-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0500019406dc00110d0225630086c31d28962974 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/infer-type.ts.result @@ -0,0 +1,7 @@ +Matched 9 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == + type U = {n } +== Sub Tree == + type E = T extends Array< infer U> ? T : U diff --git a/src/MapleFE/test/typescript/unit_tests/infer-type2.ts b/src/MapleFE/test/typescript/unit_tests/infer-type2.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e826c6314f637744d5f0764ddf5c8f5551b04b0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/infer-type2.ts @@ -0,0 +1,8 @@ +// Extracted from https://github.com/cocos-creator/engine/blob/develop/cocos/core/gfx/pipeline-state.jsb.ts#L33 +declare type RecursivePartial = { + [P in keyof T]?: T[P] extends Array + ? Array> + : T[P] extends ReadonlyArray + ? ReadonlyArray> + : RecursivePartial; +}; diff --git a/src/MapleFE/test/typescript/unit_tests/infer-type2.ts.result b/src/MapleFE/test/typescript/unit_tests/infer-type2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..489bad3ffdcc6f5007bd545dc3b37712ae98863e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/infer-type2.ts.result @@ -0,0 +1,4 @@ +Matched 62 tokens. +============= Module =========== +== Sub Tree == +declare type RecursivePartial = {[P in keyof T] : T[P] extends Array< infer U> ? Array> : T[P] extends ReadonlyArray< infer V> ? ReadonlyArray> : RecursivePartial } diff --git a/src/MapleFE/test/typescript/unit_tests/infer-type3.ts b/src/MapleFE/test/typescript/unit_tests/infer-type3.ts new file mode 100644 index 0000000000000000000000000000000000000000..3418e72f9e37f5ab0309396b6461d88277b6f55a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/infer-type3.ts @@ -0,0 +1,4 @@ +// Extracted from https://github.com/cocos-creator/engine/blob/develop/cocos/core/gfx/pipeline-state.jsb.ts#L33 +export declare type NT = { + [P in keyof T]: T[P] extends Record ? Exclude | keyof T[P] : T[P]; +}; diff --git a/src/MapleFE/test/typescript/unit_tests/infer-type3.ts.result b/src/MapleFE/test/typescript/unit_tests/infer-type3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7ab557f1d216eb726ec60eb33ce02c3d713907ff --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/infer-type3.ts.result @@ -0,0 +1,4 @@ +Matched 49 tokens. +============= Module =========== +== Sub Tree == +export {declare type NT = {[P in keyof T] : T[P] extends Record ? union = Exclude | keyof T[P] : T[P] }} diff --git a/src/MapleFE/test/typescript/unit_tests/infer-type4.ts b/src/MapleFE/test/typescript/unit_tests/infer-type4.ts new file mode 100644 index 0000000000000000000000000000000000000000..47da6d2db2892b9851f32701905ddc7675158338 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/infer-type4.ts @@ -0,0 +1 @@ +type MyType = K extends [infer U, ...infer V] ? Extract : K; diff --git a/src/MapleFE/test/typescript/unit_tests/infer-type4.ts.result b/src/MapleFE/test/typescript/unit_tests/infer-type4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..039d0a6d76a5a89bb60ddf692d872949c63dbe72 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/infer-type4.ts.result @@ -0,0 +1,4 @@ +Matched 32 tokens. +============= Module =========== +== Sub Tree == + type MyType = K extends [ : infer U , : infer V , ] ? Extract : K diff --git a/src/MapleFE/test/typescript/unit_tests/instanceof-1.ts b/src/MapleFE/test/typescript/unit_tests/instanceof-1.ts new file mode 100644 index 0000000000000000000000000000000000000000..6be225473aaa871c83a5532f6fe8f0d44d17a691 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/instanceof-1.ts @@ -0,0 +1,13 @@ +class Foo {} + +class Bar { + foo: Function = () => null; +} + +var foo:Foo = new Foo(); +var bar:Bar = new Bar(); +bar.foo = Foo; +console.log(foo instanceof Bar); +console.log(foo instanceof bar.foo); +console.log(bar.foo instanceof Bar); + diff --git a/src/MapleFE/test/typescript/unit_tests/instanceof-1.ts.result b/src/MapleFE/test/typescript/unit_tests/instanceof-1.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6137523453960a1ceb93ec0b398681e2978958eb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/instanceof-1.ts.result @@ -0,0 +1,41 @@ +Matched 4 tokens. +Matched 17 tokens. +Matched 27 tokens. +Matched 37 tokens. +Matched 43 tokens. +Matched 52 tokens. +Matched 63 tokens. +Matched 74 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Bar + Fields: + foo=() -> null + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: foo=new Foo() +== Sub Tree == +js_var Decl: bar=new Bar() +== Sub Tree == +bar.foo Assign Foo +== Sub Tree == +console.log(foo instanceof Bar) +== Sub Tree == +console.log(foo instanceof bar.foo) +== Sub Tree == +console.log(bar.foo instanceof Bar) diff --git a/src/MapleFE/test/typescript/unit_tests/instanceof.ts b/src/MapleFE/test/typescript/unit_tests/instanceof.ts new file mode 100644 index 0000000000000000000000000000000000000000..55b72c52ea082d47550af61b77176f77e07a2355 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/instanceof.ts @@ -0,0 +1,2 @@ +var x: any = 3; +console.log(x instanceof Number); diff --git a/src/MapleFE/test/typescript/unit_tests/instanceof.ts.result b/src/MapleFE/test/typescript/unit_tests/instanceof.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..dc62911090503f0b87e40735cf502c0f4059f9f6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/instanceof.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 16 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=3 +== Sub Tree == +console.log(x instanceof Number) diff --git a/src/MapleFE/test/typescript/unit_tests/interface-extends.ts b/src/MapleFE/test/typescript/unit_tests/interface-extends.ts new file mode 100644 index 0000000000000000000000000000000000000000..2796b9867fc612d460451bb249b2c5a262564070 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-extends.ts @@ -0,0 +1,12 @@ +interface Base { + name: string; +} +interface Derived extends Base { + age: number; +} +function dump(obj: Derived) { + console.log(obj.name, obj.age); +} + +let o = { name: "John", age: 30 }; +dump(o); diff --git a/src/MapleFE/test/typescript/unit_tests/interface-extends.ts.result b/src/MapleFE/test/typescript/unit_tests/interface-extends.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ecb6a0965eb37387c924d6af8213367101b2229a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-extends.ts.result @@ -0,0 +1,18 @@ +Matched 8 tokens. +Matched 18 tokens. +Matched 40 tokens. +Matched 53 tokens. +Matched 58 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Base {name } +== Sub Tree == +ts_interface: Derived {age } +== Sub Tree == +func dump(obj) throws: + console.log(obj.name,obj.age) + +== Sub Tree == +js_let Decl: o= {name:"John", age:30} +== Sub Tree == +dump(o) diff --git a/src/MapleFE/test/typescript/unit_tests/interface-extends2.ts b/src/MapleFE/test/typescript/unit_tests/interface-extends2.ts new file mode 100644 index 0000000000000000000000000000000000000000..6cb460097753b5a55cf6ff219fa836b6e8b794f4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-extends2.ts @@ -0,0 +1,14 @@ +interface Base { + name: string; +} +interface Derived extends Base { + age: number; + readonly impl?: any; + initialize?(c: number): void; +} +function dump(obj: Derived) { + console.log(obj.name, obj.age); +} + +let o = { name: "John", age: 30 }; +dump(o); diff --git a/src/MapleFE/test/typescript/unit_tests/interface-extends2.ts.result b/src/MapleFE/test/typescript/unit_tests/interface-extends2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2575af09f78a5135b326e560caf263129fc04d9e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-extends2.ts.result @@ -0,0 +1,19 @@ +Matched 8 tokens. +Matched 34 tokens. +Matched 56 tokens. +Matched 69 tokens. +Matched 74 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Base {name } +== Sub Tree == +ts_interface: Derived {age;impl?func initialize?(c) throws: + } +== Sub Tree == +func dump(obj) throws: + console.log(obj.name,obj.age) + +== Sub Tree == +js_let Decl: o= {name:"John", age:30} +== Sub Tree == +dump(o) diff --git a/src/MapleFE/test/typescript/unit_tests/interface-func.ts b/src/MapleFE/test/typescript/unit_tests/interface-func.ts new file mode 100644 index 0000000000000000000000000000000000000000..01e5a0799bb87aa404d7a0a85e5dabd4c7fcfd97 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-func.ts @@ -0,0 +1,9 @@ +class Klass {} + +export interface Interf { + [key: string]: any; +} + +export interface Interf2 { + func(component: Klass): Interf; +} diff --git a/src/MapleFE/test/typescript/unit_tests/interface-func.ts.result b/src/MapleFE/test/typescript/unit_tests/interface-func.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..fa4ee3c2d9b8041f904d6ac04384dd8e24220609 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-func.ts.result @@ -0,0 +1,19 @@ +Matched 4 tokens. +Matched 17 tokens. +Matched 31 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +export {ts_interface: Interf {string index type: any }} +== Sub Tree == +export {ts_interface: Interf2 {func func(component) throws: + }} diff --git a/src/MapleFE/test/typescript/unit_tests/interface-indexable.ts b/src/MapleFE/test/typescript/unit_tests/interface-indexable.ts new file mode 100644 index 0000000000000000000000000000000000000000..2299b8034efdc1de5b6a3595f55cba7412573901 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-indexable.ts @@ -0,0 +1,13 @@ +const enum TypeID { + Array_Class = 0, + Array, +} + +class Klass {} + +interface DataTypes { + [TypeID.Array_Class]: DataTypes[TypeID.Array][]; + [TypeID.Array]: Klass; +} + +type TYPE = DataTypes[Exclude]; diff --git a/src/MapleFE/test/typescript/unit_tests/interface-indexable.ts.result b/src/MapleFE/test/typescript/unit_tests/interface-indexable.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b5b74c76cd51dabbcb08a5d456131390d249f903 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-indexable.ts.result @@ -0,0 +1,21 @@ +Matched 11 tokens. +Matched 15 tokens. +Matched 42 tokens. +Matched 58 tokens. +============= Module =========== +== Sub Tree == +ts_enum: TypeID {Array_Class=0;Array } +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +ts_interface: DataTypes {[TypeID.Array_Class] : DataTypes[TypeID.Array][];[TypeID.Array] : Klass } +== Sub Tree == + type TYPE = DataTypes[Exclude< keyof DataTypes,TypeID.Array_Class>] diff --git a/src/MapleFE/test/typescript/unit_tests/interface-intersect-nonnullable-intf-fd.ts b/src/MapleFE/test/typescript/unit_tests/interface-intersect-nonnullable-intf-fd.ts new file mode 100644 index 0000000000000000000000000000000000000000..673654135f5736d516b9fdbe83f2ea905c528078 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-intersect-nonnullable-intf-fd.ts @@ -0,0 +1,6 @@ +// ref: cocos game.ts line 922 +interface IntfX { + IntfX_fd: boolean; +} + +type Test = IntfX & { intersect_fd: NonNullable }; diff --git a/src/MapleFE/test/typescript/unit_tests/interface-intersect-nonnullable-intf-fd.ts.result b/src/MapleFE/test/typescript/unit_tests/interface-intersect-nonnullable-intf-fd.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6f7d95622df3540c51ccb5af37021ad1934d0620 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-intersect-nonnullable-intf-fd.ts.result @@ -0,0 +1,7 @@ +Matched 8 tokens. +Matched 25 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IntfX {IntfX_fd } +== Sub Tree == + type Test = intersect = IntfX & {intersect_fd } diff --git a/src/MapleFE/test/typescript/unit_tests/interface-keyof.ts b/src/MapleFE/test/typescript/unit_tests/interface-keyof.ts new file mode 100644 index 0000000000000000000000000000000000000000..df837365df7199f215bf50c55b73383ae9df86ed --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-keyof.ts @@ -0,0 +1,4 @@ +interface Interf { + name: keyof T; + val: T[keyof T]; +} diff --git a/src/MapleFE/test/typescript/unit_tests/interface-keyof.ts.result b/src/MapleFE/test/typescript/unit_tests/interface-keyof.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..eaf8faa25e936c057e33e33b4f64de8b6da2a488 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-keyof.ts.result @@ -0,0 +1,4 @@ +Matched 20 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Interf {name;val } diff --git a/src/MapleFE/test/typescript/unit_tests/interface-opt-def.ts b/src/MapleFE/test/typescript/unit_tests/interface-opt-def.ts new file mode 100644 index 0000000000000000000000000000000000000000..33ee72d0d54b759f175e46cace3e86658e219de5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-opt-def.ts @@ -0,0 +1,11 @@ +interface I { + a: number; + b?: number; +} + +function f({ a, b = 1 }: I): number { + return a + b; +} + +console.log(f({ a: 1 })); +console.log(f({ a: 1, b: 2 })); diff --git a/src/MapleFE/test/typescript/unit_tests/interface-opt-def.ts.result b/src/MapleFE/test/typescript/unit_tests/interface-opt-def.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..46e46a34bcba99730ef9417d1de2207c356d0591 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-opt-def.ts.result @@ -0,0 +1,15 @@ +Matched 13 tokens. +Matched 35 tokens. +Matched 49 tokens. +Matched 67 tokens. +============= Module =========== +== Sub Tree == +ts_interface: I {a;b? } +== Sub Tree == +func f({:a, :b=1}) throws: + return a Add b + +== Sub Tree == +console.log(f( {a:1})) +== Sub Tree == +console.log(f( {a:1, b:2})) diff --git a/src/MapleFE/test/typescript/unit_tests/interface-optional-field.ts b/src/MapleFE/test/typescript/unit_tests/interface-optional-field.ts new file mode 100644 index 0000000000000000000000000000000000000000..3708b9805c41233d33346a17c0ba105fc6ec97bd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-optional-field.ts @@ -0,0 +1,3 @@ +interface Interf { + readonly?: boolean | { flag?: boolean }; +} diff --git a/src/MapleFE/test/typescript/unit_tests/interface-optional-field.ts.result b/src/MapleFE/test/typescript/unit_tests/interface-optional-field.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c92b24340b56389cab065ffce386791c466d58ae --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface-optional-field.ts.result @@ -0,0 +1,4 @@ +Matched 16 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Interf {readonly? } diff --git a/src/MapleFE/test/typescript/unit_tests/interface.ts b/src/MapleFE/test/typescript/unit_tests/interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..1306b78f98647975d8180b677560e4ec9c06347a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface.ts @@ -0,0 +1,14 @@ +interface Employee { + firstName: string; + lastName: string; +} + +let john: Employee = { + firstName: "John", + lastName: "Smith", +}; + +let jane: Employee = { + firstName: "Jane", + lastName: "Doe", +}; diff --git a/src/MapleFE/test/typescript/unit_tests/interface.ts.result b/src/MapleFE/test/typescript/unit_tests/interface.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5b1138ffa5a23ec70f0fdbc6db712ee534db602f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface.ts.result @@ -0,0 +1,10 @@ +Matched 12 tokens. +Matched 28 tokens. +Matched 44 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Employee {firstName;lastName } +== Sub Tree == +js_let Decl: john= {firstName:"John", lastName:"Smith"} +== Sub Tree == +js_let Decl: jane= {firstName:"Jane", lastName:"Doe"} diff --git a/src/MapleFE/test/typescript/unit_tests/interface2.ts b/src/MapleFE/test/typescript/unit_tests/interface2.ts new file mode 100644 index 0000000000000000000000000000000000000000..490ad712035327a8e20301394fe28d6b3753bca6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface2.ts @@ -0,0 +1,3 @@ +interface Interf { + obj: { import: string[] }; +} diff --git a/src/MapleFE/test/typescript/unit_tests/interface2.ts.result b/src/MapleFE/test/typescript/unit_tests/interface2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b619a930d755f8bfef79827f7c005e2a944c3368 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface2.ts.result @@ -0,0 +1,4 @@ +Matched 14 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Interf {obj } diff --git a/src/MapleFE/test/typescript/unit_tests/interface3.ts b/src/MapleFE/test/typescript/unit_tests/interface3.ts new file mode 100644 index 0000000000000000000000000000000000000000..5412585d451cdcd705afbd4c89c1a9812564ed53 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface3.ts @@ -0,0 +1,7 @@ +// tsc -t es6 +interface IFace { + create( + args: Iterable + ): { [k: string]: T }; + create(args: Iterable): any; +} diff --git a/src/MapleFE/test/typescript/unit_tests/interface3.ts.result b/src/MapleFE/test/typescript/unit_tests/interface3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..94e3727736aa37357359b50b82b32fb1c42c69e3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/interface3.ts.result @@ -0,0 +1,6 @@ +Matched 49 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {func create(args) throws: +;func create(args) throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/intersection-type.ts b/src/MapleFE/test/typescript/unit_tests/intersection-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..774714751c5d4aec81009cb9da7373834c8011b9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/intersection-type.ts @@ -0,0 +1,14 @@ +interface A { + id: number; +} + +interface B { + name: string; +} + +type I = A & B; +let v: I; +v!.id = 10; +v!.name = "B"; + +console.log(v!.id, v!.name); diff --git a/src/MapleFE/test/typescript/unit_tests/intersection-type.ts.result b/src/MapleFE/test/typescript/unit_tests/intersection-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5d33332ee88b24e3d03543bbf9e2ee142962dda5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/intersection-type.ts.result @@ -0,0 +1,22 @@ +Matched 8 tokens. +Matched 16 tokens. +Matched 23 tokens. +Matched 28 tokens. +Matched 35 tokens. +Matched 42 tokens. +Matched 57 tokens. +============= Module =========== +== Sub Tree == +ts_interface: A {id } +== Sub Tree == +ts_interface: B {name } +== Sub Tree == + type I = intersect = A & B +== Sub Tree == +js_let Decl: v +== Sub Tree == +v!.id Assign 10 +== Sub Tree == +v!.name Assign "B" +== Sub Tree == +console.log(v!.id,v!.name) diff --git a/src/MapleFE/test/typescript/unit_tests/intersection-type2.ts b/src/MapleFE/test/typescript/unit_tests/intersection-type2.ts new file mode 100644 index 0000000000000000000000000000000000000000..6070c19c10b8f81b7f1d157db4a257b6c968069e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/intersection-type2.ts @@ -0,0 +1,18 @@ +class A { + id: number = 0; +} + +class B { + flag: false = false; +} + +class C { + name: string = ""; +} + +type I = A & (B["flag"] extends true ? B : C); +let v: I = {id: 0, name: ""}; +v!.id = 10; +v!.name = "B"; + +console.log(v!.id, v!.name); diff --git a/src/MapleFE/test/typescript/unit_tests/intersection-type2.ts.result b/src/MapleFE/test/typescript/unit_tests/intersection-type2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0995e58a7314d0af79726755e62fdd9ce8c48f60 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/intersection-type2.ts.result @@ -0,0 +1,49 @@ +Matched 10 tokens. +Matched 20 tokens. +Matched 30 tokens. +Matched 48 tokens. +Matched 63 tokens. +Matched 70 tokens. +Matched 77 tokens. +Matched 92 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + id=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class B + Fields: + flag=false + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class C + Fields: + name="" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == + type I = intersect = A & B["flag"] extends true ? B : C +== Sub Tree == +js_let Decl: v= {id:0, name:""} +== Sub Tree == +v!.id Assign 10 +== Sub Tree == +v!.name Assign "B" +== Sub Tree == +console.log(v!.id,v!.name) diff --git a/src/MapleFE/test/typescript/unit_tests/intersection-type3.ts b/src/MapleFE/test/typescript/unit_tests/intersection-type3.ts new file mode 100644 index 0000000000000000000000000000000000000000..8af426e92796bca034e477453a69fc0c884ae8be --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/intersection-type3.ts @@ -0,0 +1 @@ +declare type Type = { [K in keyof T]: K; }[keyof T] & string; diff --git a/src/MapleFE/test/typescript/unit_tests/intersection-type3.ts.result b/src/MapleFE/test/typescript/unit_tests/intersection-type3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..dfbcdc17edc3cab50bde1dbe039b00a17eafb9b2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/intersection-type3.ts.result @@ -0,0 +1,4 @@ +Matched 25 tokens. +============= Module =========== +== Sub Tree == +declare type Type = intersect = {[K in keyof T] : K }[ keyof T] & string diff --git a/src/MapleFE/test/typescript/unit_tests/iterator.ts b/src/MapleFE/test/typescript/unit_tests/iterator.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4d1e33a670c592af51db17254537877feae63f9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/iterator.ts @@ -0,0 +1,14 @@ +interface Iface { + name: string; +} + +const myIter: Iterator = Object.freeze({ + next () { + return { done: true, value: undefined, }; + }, +}); + + +const iter: Iterable = Object.freeze({ + [Symbol.iterator] () { return myIter; }, +}); diff --git a/src/MapleFE/test/typescript/unit_tests/iterator.ts.result b/src/MapleFE/test/typescript/unit_tests/iterator.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..d4048a3631bf33d36e2c4eb6e05802618574424b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/iterator.ts.result @@ -0,0 +1,14 @@ +Matched 8 tokens. +Matched 42 tokens. +Matched 71 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Iface {name } +== Sub Tree == +js_const Decl: myIter=Object.freeze( {next:func next() throws: + return {done:true, value:undefined} +}) +== Sub Tree == +js_const Decl: iter=Object.freeze( {[Symbol.iterator] : :func () throws: + return myIter +}) diff --git a/src/MapleFE/test/typescript/unit_tests/keyof-property.ts b/src/MapleFE/test/typescript/unit_tests/keyof-property.ts new file mode 100644 index 0000000000000000000000000000000000000000..855d0e42a03ccf24e035a95c9ab4f0122a66abc1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/keyof-property.ts @@ -0,0 +1,6 @@ +class Klass { + prop: { field: number } = { field: 0}; +} +export type T = keyof Klass["prop"]; +var n: T = "field"; +console.log(n); diff --git a/src/MapleFE/test/typescript/unit_tests/keyof-property.ts.result b/src/MapleFE/test/typescript/unit_tests/keyof-property.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7f5be0ce67791d42fc56be3315998309e988a78d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/keyof-property.ts.result @@ -0,0 +1,21 @@ +Matched 18 tokens. +Matched 28 tokens. +Matched 35 tokens. +Matched 42 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + prop= {field:0} + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +export { type T = keyof Klass["prop"]} +== Sub Tree == +js_var Decl: n="field" +== Sub Tree == +console.log(n) diff --git a/src/MapleFE/test/typescript/unit_tests/keyof.ts b/src/MapleFE/test/typescript/unit_tests/keyof.ts new file mode 100644 index 0000000000000000000000000000000000000000..a8eaa08ab49c0e1c012d0d5b3891b03f5ddef0f7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/keyof.ts @@ -0,0 +1,7 @@ +class Klass { + [x: string]: number; +} +var o: Klass = { abc: 10 }; +var x: keyof Klass = "abc"; +console.log(o[x]); +o[x] = 3; diff --git a/src/MapleFE/test/typescript/unit_tests/keyof.ts.result b/src/MapleFE/test/typescript/unit_tests/keyof.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3812d5e9488fd4a4af9ac8939adedea8f0d022a7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/keyof.ts.result @@ -0,0 +1,24 @@ +Matched 12 tokens. +Matched 23 tokens. +Matched 31 tokens. +Matched 41 tokens. +Matched 48 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + number + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: o= {abc:10} +== Sub Tree == +js_var Decl: x="abc" +== Sub Tree == +console.log(o[x]) +== Sub Tree == +o[x] Assign 3 diff --git a/src/MapleFE/test/typescript/unit_tests/keyof2.ts b/src/MapleFE/test/typescript/unit_tests/keyof2.ts new file mode 100644 index 0000000000000000000000000000000000000000..824c5b16f34a05b1226ad862eab89fd4ee76c6dd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/keyof2.ts @@ -0,0 +1,7 @@ +class Klass { + [x: string]: number; +} +var o: Klass = { abc: 10 }; +var x: keyof typeof o = "abc"; +console.log(o[x]); +o[x] = 3; diff --git a/src/MapleFE/test/typescript/unit_tests/keyof2.ts.result b/src/MapleFE/test/typescript/unit_tests/keyof2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..9c56663543344013cf20078ef8dc07ce87fdaff3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/keyof2.ts.result @@ -0,0 +1,24 @@ +Matched 12 tokens. +Matched 23 tokens. +Matched 32 tokens. +Matched 42 tokens. +Matched 49 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + number + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: o= {abc:10} +== Sub Tree == +js_var Decl: x="abc" +== Sub Tree == +console.log(o[x]) +== Sub Tree == +o[x] Assign 3 diff --git a/src/MapleFE/test/typescript/unit_tests/keyof3.ts b/src/MapleFE/test/typescript/unit_tests/keyof3.ts new file mode 100644 index 0000000000000000000000000000000000000000..824c5b16f34a05b1226ad862eab89fd4ee76c6dd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/keyof3.ts @@ -0,0 +1,7 @@ +class Klass { + [x: string]: number; +} +var o: Klass = { abc: 10 }; +var x: keyof typeof o = "abc"; +console.log(o[x]); +o[x] = 3; diff --git a/src/MapleFE/test/typescript/unit_tests/keyof3.ts.result b/src/MapleFE/test/typescript/unit_tests/keyof3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..9c56663543344013cf20078ef8dc07ce87fdaff3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/keyof3.ts.result @@ -0,0 +1,24 @@ +Matched 12 tokens. +Matched 23 tokens. +Matched 32 tokens. +Matched 42 tokens. +Matched 49 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + number + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: o= {abc:10} +== Sub Tree == +js_var Decl: x="abc" +== Sub Tree == +console.log(o[x]) +== Sub Tree == +o[x] Assign 3 diff --git a/src/MapleFE/test/typescript/unit_tests/labeled-block.ts b/src/MapleFE/test/typescript/unit_tests/labeled-block.ts new file mode 100644 index 0000000000000000000000000000000000000000..080acf9cfebe603c78ae9899556812ca395fc6c3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/labeled-block.ts @@ -0,0 +1,12 @@ +var x: number = 10; + +outer: { + if (x > 5) { + if (x > 8) { + console.log("x is greater than 8"); + break outer; + } + console.log("x is greater than 5"); + } else console.log("x is less than or equal to 5"); + console.log("out of block"); +} diff --git a/src/MapleFE/test/typescript/unit_tests/labeled-block.ts.result b/src/MapleFE/test/typescript/unit_tests/labeled-block.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3fa087629698ce26f806c1b7b7e726bcf3950c47 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/labeled-block.ts.result @@ -0,0 +1,21 @@ +Matched 7 tokens. +Matched 59 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=10 +== Sub Tree == +outer: +cond-branch cond:x GT 5 +true branch : + cond-branch cond:x GT 8 + true branch : + console.log("x is greater than 8") + break:outer + + false branch : + + console.log("x is greater than 5") +false branch : + console.log("x is less than or equal to 5") +console.log("out of block") + diff --git a/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt-in-loop.ts b/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt-in-loop.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a98d672373c03d15fc58bdd170ddc7948e7f663 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt-in-loop.ts @@ -0,0 +1,15 @@ +var x: number = 10; +for (var i = 0; i < 10; ++i) { + x--; + outer: if (x > 0) { + if (x > 5) { + if (x > 8) { + console.log("x is greater than 8"); + break outer; + } + console.log("x is greater than 5"); + break; + } else console.log("x is less than or equal to 5"); + console.log("out of nested if-stmt"); + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt-in-loop.ts.result b/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt-in-loop.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a381c1c4ff519e34f01ffbeffeca61285866f19e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt-in-loop.ts.result @@ -0,0 +1,30 @@ +Matched 7 tokens. +Matched 86 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=10 +== Sub Tree == +for ( ) + x Dec + + outer: + cond-branch cond:x GT 0 + true branch : + cond-branch cond:x GT 5 + true branch : + cond-branch cond:x GT 8 + true branch : + console.log("x is greater than 8") + break:outer + + false branch : + + console.log("x is greater than 5") + break: + + false branch : + console.log("x is less than or equal to 5") + console.log("out of nested if-stmt") + false branch : + + diff --git a/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt.ts b/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt.ts new file mode 100644 index 0000000000000000000000000000000000000000..183b80995227e21c976176cab0c273793429588f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt.ts @@ -0,0 +1,10 @@ +var x: number = 10; +if (x > 0) { + outer: if (x > 5) { + if (x > 8) { + console.log("x is greater than 8"); + break outer; + } + console.log("x is greater than 5"); + } else console.log("x is less than or equal to 5"); +} diff --git a/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt.ts.result b/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..29aa37d8b7d71faa0dc795bdbbffb1217c9a2106 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/labeled-if-stmt.ts.result @@ -0,0 +1,23 @@ +Matched 7 tokens. +Matched 58 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=10 +== Sub Tree == +cond-branch cond:x GT 0 +true branch : + outer: + cond-branch cond:x GT 5 + true branch : + cond-branch cond:x GT 8 + true branch : + console.log("x is greater than 8") + break:outer + + false branch : + + console.log("x is greater than 5") + false branch : + console.log("x is less than or equal to 5") +false branch : + diff --git a/src/MapleFE/test/typescript/unit_tests/labeled-loop.ts b/src/MapleFE/test/typescript/unit_tests/labeled-loop.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3724dbfcccc2f4bd6fef274568759709050c8b6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/labeled-loop.ts @@ -0,0 +1,12 @@ +var arr: number[] = [7, 4, 5, 9, 2, 8, 1, 6, 3]; +var len: number = arr.length; +var sum: number = 0; +outer: for (var i = 0; i < len; ++i) { + for (var j = i + 1; j < len; ++j) { + sum += arr[i]; + console.log(sum); + if (arr[j] > 5) continue outer; + if (sum >= 60) break outer; + } +} +console.log(sum); diff --git a/src/MapleFE/test/typescript/unit_tests/labeled-loop.ts.result b/src/MapleFE/test/typescript/unit_tests/labeled-loop.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ad0f4192f4dc37582d42ad0061377fb54b121b5a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/labeled-loop.ts.result @@ -0,0 +1,32 @@ +Matched 27 tokens. +Matched 36 tokens. +Matched 43 tokens. +Matched 114 tokens. +Matched 121 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[7,4,5,9,2,8,1,6,3] +== Sub Tree == +js_var Decl: len=arr.length +== Sub Tree == +js_var Decl: sum=0 +== Sub Tree == +outer: +for ( ) + for ( ) + sum AddAssign arr[i] + console.log(sum) + cond-branch cond:arr[j] GT 5 + true branch : + continue:outer + false branch : + + cond-branch cond:sum GE 60 + true branch : + break:outer + false branch : + + + +== Sub Tree == +console.log(sum) diff --git a/src/MapleFE/test/typescript/unit_tests/lambda.ts b/src/MapleFE/test/typescript/unit_tests/lambda.ts new file mode 100644 index 0000000000000000000000000000000000000000..e1303aa1555b657369ca3099566539e7bbdb65b2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/lambda.ts @@ -0,0 +1,4 @@ +var add = (x: number, y: number): number => { + return x + y; +}; +console.log(add(2, 3)); diff --git a/src/MapleFE/test/typescript/unit_tests/lambda.ts.result b/src/MapleFE/test/typescript/unit_tests/lambda.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f51402f201435e2a0672de19a4de0e3f7a17c8f1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/lambda.ts.result @@ -0,0 +1,8 @@ +Matched 23 tokens. +Matched 35 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: add=(x,y) -> return x Add y + +== Sub Tree == +console.log(add(2,3)) diff --git a/src/MapleFE/test/typescript/unit_tests/lambda2.ts b/src/MapleFE/test/typescript/unit_tests/lambda2.ts new file mode 100644 index 0000000000000000000000000000000000000000..180811544bbaf5207cb361def63f2fbe35b418d0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/lambda2.ts @@ -0,0 +1,2 @@ +var sqare: (x: number) => number = (x) => x * x; +console.log(sqare(2)); diff --git a/src/MapleFE/test/typescript/unit_tests/lambda2.ts.result b/src/MapleFE/test/typescript/unit_tests/lambda2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5c31f72bdcdd397ad1ee96be0944c14f251cccfb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/lambda2.ts.result @@ -0,0 +1,7 @@ +Matched 19 tokens. +Matched 29 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: sqare=(x) -> x Mul x +== Sub Tree == +console.log(sqare(2)) diff --git a/src/MapleFE/test/typescript/unit_tests/lambda3.ts b/src/MapleFE/test/typescript/unit_tests/lambda3.ts new file mode 100644 index 0000000000000000000000000000000000000000..b8b89b94fef7dbb892f35191c52354fb4a17154b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/lambda3.ts @@ -0,0 +1,8 @@ +// ref: cocos scheduler.ts line 58 +class CLS_test { + public static get = () => { + return 1; + }; +} + +console.log(CLS_test.get()); diff --git a/src/MapleFE/test/typescript/unit_tests/lambda3.ts.result b/src/MapleFE/test/typescript/unit_tests/lambda3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..354262be7c4ced3a0df15737cfd69e6b3d814837 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/lambda3.ts.result @@ -0,0 +1,16 @@ +Matched 17 tokens. +Matched 28 tokens. +============= Module =========== +== Sub Tree == +class CLS_test + Fields: + get=() -> return 1 + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +console.log(CLS_test.get()) diff --git a/src/MapleFE/test/typescript/unit_tests/let-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/let-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..0fee34fb08d4d74cedd49c0a0b9a30e0f8a80ff7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/let-as-prop-name.ts @@ -0,0 +1,32 @@ +export function func(arg: {let: Function | null}): void { + if (!arg.let) { + console.log("null"); + } else { + arg.let(); + } +} + +func({let: null}); +func({let: () => { console.log("calling let()"); }}); + +export function func1(arg: {var: Function | null}): void { + if (!arg.var) { + console.log("null"); + } else { + arg.var(); + } +} + +func1({var: null}); +func1({var: () => { console.log("calling var()"); }}); + +export function func2(arg: {break: Function | null}): void { + if (!arg.break) { + console.log("null"); + } else { + arg.break(); + } +} + +func2({break: null}); +func2({break: () => { console.log("calling break()"); }}); diff --git a/src/MapleFE/test/typescript/unit_tests/let-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/let-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5ecae0f33fd4d81d52516d162c474d52fbfcf9fc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/let-as-prop-name.ts.result @@ -0,0 +1,52 @@ +Matched 43 tokens. +Matched 52 tokens. +Matched 72 tokens. +Matched 115 tokens. +Matched 124 tokens. +Matched 144 tokens. +Matched 187 tokens. +Matched 196 tokens. +Matched 216 tokens. +============= Module =========== +== Sub Tree == +export {func func(arg) throws: + cond-branch cond:Not arg.let + true branch : + console.log("null") + false branch : + arg.let() + +} +== Sub Tree == +func( {let:null}) +== Sub Tree == +func( {let:() -> console.log("calling let()") +}) +== Sub Tree == +export {func func1(arg) throws: + cond-branch cond:Not arg.var + true branch : + console.log("null") + false branch : + arg.var() + +} +== Sub Tree == +func1( {var:null}) +== Sub Tree == +func1( {var:() -> console.log("calling var()") +}) +== Sub Tree == +export {func func2(arg) throws: + cond-branch cond:Not arg.break + true branch : + console.log("null") + false branch : + arg.break() + +} +== Sub Tree == +func2( {break:null}) +== Sub Tree == +func2( {break:() -> console.log("calling break()") +}) diff --git a/src/MapleFE/test/typescript/unit_tests/let-multi-decls.ts b/src/MapleFE/test/typescript/unit_tests/let-multi-decls.ts new file mode 100644 index 0000000000000000000000000000000000000000..b3f44de9688766101aa9072b18f38f3b14c6ee6e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/let-multi-decls.ts @@ -0,0 +1,5 @@ +let i: number, + j = 3, + k = 5; +i = 10; +console.log(i + j + k); diff --git a/src/MapleFE/test/typescript/unit_tests/let-multi-decls.ts.result b/src/MapleFE/test/typescript/unit_tests/let-multi-decls.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..61311782f069bcb318ced21cd6a6605b8ab759b8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/let-multi-decls.ts.result @@ -0,0 +1,14 @@ +Matched 13 tokens. +Matched 17 tokens. +Matched 28 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: i +== Sub Tree == +js_let Decl: j=3 +== Sub Tree == +js_let Decl: k=5 +== Sub Tree == +i Assign 10 +== Sub Tree == +console.log(i Add j Add k) diff --git a/src/MapleFE/test/typescript/unit_tests/let-multi-decls2.ts b/src/MapleFE/test/typescript/unit_tests/let-multi-decls2.ts new file mode 100644 index 0000000000000000000000000000000000000000..4de255fbb6deac156255950f8b84f650ff2faa6f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/let-multi-decls2.ts @@ -0,0 +1,11 @@ +function func() { + let i = 1, + j = 2, + k; + i = 10; + j = 3; + k = 5; + console.log(i + j + k); +} + +func(); diff --git a/src/MapleFE/test/typescript/unit_tests/let-multi-decls2.ts.result b/src/MapleFE/test/typescript/unit_tests/let-multi-decls2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a3bff642f5297036c4d30db6426ba8737485c92e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/let-multi-decls2.ts.result @@ -0,0 +1,15 @@ +Matched 40 tokens. +Matched 44 tokens. +============= Module =========== +== Sub Tree == +func func() throws: + js_let Decl: i=1 + js_let Decl: j=2 + js_let Decl: k + i Assign 10 + j Assign 3 + k Assign 5 + console.log(i Add j Add k) + +== Sub Tree == +func() diff --git a/src/MapleFE/test/typescript/unit_tests/literal-type.ts b/src/MapleFE/test/typescript/unit_tests/literal-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..af5b84b57d5f3a63def536bf38b53a6516a46e3d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/literal-type.ts @@ -0,0 +1,4 @@ +var x: 0 | -1 = 0; +console.log(x); +x = -1; +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/literal-type.ts.result b/src/MapleFE/test/typescript/unit_tests/literal-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..4597f8a34230202abe303aa580fe746b40c07cec --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/literal-type.ts.result @@ -0,0 +1,13 @@ +Matched 9 tokens. +Matched 16 tokens. +Matched 20 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=0 +== Sub Tree == +console.log(x) +== Sub Tree == +x Assign -1 +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/long-string.ts b/src/MapleFE/test/typescript/unit_tests/long-string.ts new file mode 100644 index 0000000000000000000000000000000000000000..4a3f849389269ee2960233a3b17ca6e382b2b36c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/long-string.ts @@ -0,0 +1,5 @@ +const obj = { + str: "this is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...", +}; + +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/long-string.ts.result b/src/MapleFE/test/typescript/unit_tests/long-string.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..96d27c6557181486010fb6d34da5f2d99640294c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/long-string.ts.result @@ -0,0 +1,7 @@ +Matched 10 tokens. +Matched 17 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {str:"this is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string...\nthis is a long long long string..."} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/mapped-type-with-modifier.ts b/src/MapleFE/test/typescript/unit_tests/mapped-type-with-modifier.ts new file mode 100644 index 0000000000000000000000000000000000000000..b45c6f5d9fcef9a78f17bfffc6abe75708c2a651 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/mapped-type-with-modifier.ts @@ -0,0 +1,6 @@ +// ref: cocos splash-screen.ts line 59. +// ref: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers + +type mutableType = { + -readonly [prop in keyof T]: T[prop]; +}; diff --git a/src/MapleFE/test/typescript/unit_tests/mapped-type-with-modifier.ts.result b/src/MapleFE/test/typescript/unit_tests/mapped-type-with-modifier.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b5634f4b07b05db1f5f2f83e352b5f42510b2ca4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/mapped-type-with-modifier.ts.result @@ -0,0 +1,4 @@ +Matched 23 tokens. +============= Module =========== +== Sub Tree == + type mutableType = {[prop in keyof T] : T[prop] } diff --git a/src/MapleFE/test/typescript/unit_tests/mapped-type.ts b/src/MapleFE/test/typescript/unit_tests/mapped-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..7b53529ee2da333b564d1a80f43237a91098913b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/mapped-type.ts @@ -0,0 +1,9 @@ +class Base { + [key: string]: number | string; +} +class Derived extends Base {} +type T = { [key in E[keyof E]]: string }; + +var obj: T = { str: "abc" }; +obj[0] = "zero"; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/mapped-type.ts.result b/src/MapleFE/test/typescript/unit_tests/mapped-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8df9e1714836cfd209ca567021afe6fbde22755d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/mapped-type.ts.result @@ -0,0 +1,35 @@ +Matched 14 tokens. +Matched 20 tokens. +Matched 42 tokens. +Matched 56 tokens. +Matched 63 tokens. +Matched 70 tokens. +============= Module =========== +== Sub Tree == +class Base + Fields: + union = number | string + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Derived + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == + type T = {[key in E[ keyof E]] : string } +== Sub Tree == +js_var Decl: obj= {str:"abc"} +== Sub Tree == +obj[0] Assign "zero" +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/mapping-modifier.ts b/src/MapleFE/test/typescript/unit_tests/mapping-modifier.ts new file mode 100644 index 0000000000000000000000000000000000000000..884989b2e1e1e291a87423f7ada1b91e7c16e56a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/mapping-modifier.ts @@ -0,0 +1,16 @@ +type Concrete = { + [P in keyof T]-?: T[P]; +}; + +interface IFace { + name: string; + age?: number; +} + +class Klass implements Concrete { + name: string = "No-name"; + age: number = 0; +} + +var obj: Klass = new Klass(); +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/mapping-modifier.ts.result b/src/MapleFE/test/typescript/unit_tests/mapping-modifier.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3769a5b1ddd713aa96dcec088ce2baa0119c5ed8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/mapping-modifier.ts.result @@ -0,0 +1,24 @@ +Matched 23 tokens. +Matched 36 tokens. +Matched 57 tokens. +Matched 67 tokens. +Matched 74 tokens. +============= Module =========== +== Sub Tree == + type Concrete = {[P in keyof T] : T[P] } +== Sub Tree == +ts_interface: IFace {name;age? } +== Sub Tree == +class Klass + Fields: + name="No-name" age=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/member-function-with-callback.ts b/src/MapleFE/test/typescript/unit_tests/member-function-with-callback.ts new file mode 100644 index 0000000000000000000000000000000000000000..935df78071b308aa2d1961fcb7bd34f444be9b26 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/member-function-with-callback.ts @@ -0,0 +1,19 @@ +abstract class Base { + func(f: () => void): void { + f(); + } + public abstract func2(f: () => void): void; +} + +class Klass extends Base { + func2(f: () => void): void { + f(); + } +} + +function foo(): void { + console.log("foo"); +} + +var obj: Klass = new Klass(); +obj.func(foo); diff --git a/src/MapleFE/test/typescript/unit_tests/member-function-with-callback.ts.result b/src/MapleFE/test/typescript/unit_tests/member-function-with-callback.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e397573a814cc33d5c5e09d37f064bcdf952214e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/member-function-with-callback.ts.result @@ -0,0 +1,39 @@ +Matched 36 tokens. +Matched 59 tokens. +Matched 74 tokens. +Matched 84 tokens. +Matched 91 tokens. +============= Module =========== +== Sub Tree == +class Base + Fields: + + Instance Initializer: + Constructors: + Methods: + func func(f) throws: + f() + func func2(f) throws: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + func func2(f) throws: + f() + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func foo() throws: + console.log("foo") + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj.func(foo) diff --git a/src/MapleFE/test/typescript/unit_tests/member-functions.ts b/src/MapleFE/test/typescript/unit_tests/member-functions.ts new file mode 100644 index 0000000000000000000000000000000000000000..510006896b64fabdb2bda9055aeca02586a88ff1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/member-functions.ts @@ -0,0 +1,20 @@ +class MyClass { + operand: number; + + constructor(opr: number) { + this.operand = opr; + } + + calc?: (x: number) => number; + + add = (x: number): number => this.operand + x; +} + +MyClass.prototype.calc = function (this: MyClass, x: number) { + return this.operand + x; +}; + +var myObj = new MyClass(1); + +console.log(myObj.calc!(2)); +console.log(myObj.add(3)); diff --git a/src/MapleFE/test/typescript/unit_tests/member-functions.ts.result b/src/MapleFE/test/typescript/unit_tests/member-functions.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1b0eefdc31cfa556f681a8c6766d65cfbcf9df9a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/member-functions.ts.result @@ -0,0 +1,28 @@ +Matched 49 tokens. +Matched 75 tokens. +Matched 84 tokens. +Matched 97 tokens. +Matched 109 tokens. +============= Module =========== +== Sub Tree == +class MyClass + Fields: + operand calc? add=(x) -> this.operand Add x + Instance Initializer: + Constructors: + constructor (opr) throws: + this.operand Assign opr + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +MyClass.prototype.calc Assign func (this,x) throws: + return this.operand Add x + +== Sub Tree == +js_var Decl: myObj=new MyClass(1) +== Sub Tree == +console.log(myObj.calc!(2)) +== Sub Tree == +console.log(myObj.add(3)) diff --git a/src/MapleFE/test/typescript/unit_tests/method-of-interface.ts b/src/MapleFE/test/typescript/unit_tests/method-of-interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..17c6a390b7d9ea2a6f16f352109a7abec77beb87 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/method-of-interface.ts @@ -0,0 +1,9 @@ +interface Klass1 {} + +interface Klass2 { + name: string; +} + +interface Klass3 { + getObj(o: Klass1): Klass2; +} diff --git a/src/MapleFE/test/typescript/unit_tests/method-of-interface.ts.result b/src/MapleFE/test/typescript/unit_tests/method-of-interface.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0eacf21e19f3cd9b7640007aabadedd32ae5e140 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/method-of-interface.ts.result @@ -0,0 +1,11 @@ +Matched 4 tokens. +Matched 12 tokens. +Matched 25 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Klass1 { } +== Sub Tree == +ts_interface: Klass2 {name } +== Sub Tree == +ts_interface: Klass3 {func getObj(o) throws: + } diff --git a/src/MapleFE/test/typescript/unit_tests/method-with-return-as-name.ts b/src/MapleFE/test/typescript/unit_tests/method-with-return-as-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..abdbb740153406141e2d96b5ece5574a456df3f6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/method-with-return-as-name.ts @@ -0,0 +1,11 @@ +class Klass { + return(x: number) { + console.log(x); + } + foo(x: number) { + this.return(x); + } +} + +var obj: Klass = new Klass(); +obj.foo(10); diff --git a/src/MapleFE/test/typescript/unit_tests/method-with-return-as-name.ts.result b/src/MapleFE/test/typescript/unit_tests/method-with-return-as-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5cca1761f0b53ba18d5fc67ad77223d03288031f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/method-with-return-as-name.ts.result @@ -0,0 +1,22 @@ +Matched 34 tokens. +Matched 44 tokens. +Matched 51 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + func return(x) throws: + console.log(x) + func foo(x) throws: + this.return(x) + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj.foo(10) diff --git a/src/MapleFE/test/typescript/unit_tests/module-a.ts b/src/MapleFE/test/typescript/unit_tests/module-a.ts new file mode 100644 index 0000000000000000000000000000000000000000..e514f1b27e2be2e0a93d5eab7b58ee2a2fec9906 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/module-a.ts @@ -0,0 +1,3 @@ +import { add } from "./module-b"; +var x: number = 20; +console.log(add(x)); diff --git a/src/MapleFE/test/typescript/unit_tests/module-a.ts.result b/src/MapleFE/test/typescript/unit_tests/module-a.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3a3b8908dae1bd8e0c91149bae1d9a88ff430b54 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/module-a.ts.result @@ -0,0 +1,10 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 24 tokens. +============= Module =========== +== Sub Tree == +import {add} "./module-b" +== Sub Tree == +js_var Decl: x=20 +== Sub Tree == +console.log(add(x)) diff --git a/src/MapleFE/test/typescript/unit_tests/module-b.ts b/src/MapleFE/test/typescript/unit_tests/module-b.ts new file mode 100644 index 0000000000000000000000000000000000000000..071ca9289a55d6b3a6af41bb232c2d9ce844fc6a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/module-b.ts @@ -0,0 +1,4 @@ +var x: number = 10; +export function add(y: number) { + return x + y; +} diff --git a/src/MapleFE/test/typescript/unit_tests/module-b.ts.result b/src/MapleFE/test/typescript/unit_tests/module-b.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..59eb90cbd7e943c75ea5b74a72d52b8e2a40ae13 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/module-b.ts.result @@ -0,0 +1,9 @@ +Matched 7 tokens. +Matched 22 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=10 +== Sub Tree == +export {func add(y) throws: + return x Add y +} diff --git a/src/MapleFE/test/typescript/unit_tests/module-c.ts b/src/MapleFE/test/typescript/unit_tests/module-c.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c69ac6668f1151318cdbec775f00724102b7565 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/module-c.ts @@ -0,0 +1,2 @@ +import * as x from "./module-b"; +console.log(x.add(100)); diff --git a/src/MapleFE/test/typescript/unit_tests/module-c.ts.result b/src/MapleFE/test/typescript/unit_tests/module-c.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..426f361cf0ca0dd0d4d6b5fd7e41af3dd913851f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/module-c.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 19 tokens. +============= Module =========== +== Sub Tree == +import { * as x} "./module-b" +== Sub Tree == +console.log(x.add(100)) diff --git a/src/MapleFE/test/typescript/unit_tests/module-vs-namespace.ts b/src/MapleFE/test/typescript/unit_tests/module-vs-namespace.ts new file mode 100644 index 0000000000000000000000000000000000000000..a5fbe24b3e2fbb615004c17788a984a93892080b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/module-vs-namespace.ts @@ -0,0 +1,24 @@ +module m_for_in { + let arr : Array = [12, 34, 56]; + for (let x in arr) { + console.log(x, arr[x]); + } +} +module m_for_of { + let arr : Array = [11, 22, 33]; + for (let x of arr) { + console.log(x); + } +} +namespace ns_for_in { + let arr : Array = [12, 34, 56]; + for (let x in arr) { + console.log(x, arr[x]); + } +} +namespace ns_for_of { + let arr : Array = [11, 22, 33]; + for (let x of arr) { + console.log(x); + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/module-vs-namespace.ts.result b/src/MapleFE/test/typescript/unit_tests/module-vs-namespace.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c569cd8d5134a72cd3038fc769ebf5a17ec55257 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/module-vs-namespace.ts.result @@ -0,0 +1,37 @@ +Matched 41 tokens. +Matched 77 tokens. +Matched 118 tokens. +Matched 154 tokens. +============= Module =========== +== Sub Tree == +============= Module =========== +== Sub Tree == +js_let Decl: arr=[12,34,56] +== Sub Tree == +for ( ) + console.log(x,arr[x]) + + +== Sub Tree == +============= Module =========== +== Sub Tree == +js_let Decl: arr=[11,22,33] +== Sub Tree == +for ( ) + console.log(x) + + +== Sub Tree == +namespace ns_for_in + js_let Decl: arr=[12,34,56] + for ( ) + console.log(x,arr[x]) + + +== Sub Tree == +namespace ns_for_of + js_let Decl: arr=[11,22,33] + for ( ) + console.log(x) + + diff --git a/src/MapleFE/test/typescript/unit_tests/multi-dim-array.ts b/src/MapleFE/test/typescript/unit_tests/multi-dim-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..615b0602ccdfd19e65692507e3e89c6217b46f02 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/multi-dim-array.ts @@ -0,0 +1 @@ +type Type = { func: () => Array>; }; diff --git a/src/MapleFE/test/typescript/unit_tests/multi-dim-array.ts.result b/src/MapleFE/test/typescript/unit_tests/multi-dim-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..18f2ae887f4b1242a010cc3bf86159bb4cc81d68 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/multi-dim-array.ts.result @@ -0,0 +1,4 @@ +Matched 18 tokens. +============= Module =========== +== Sub Tree == + type Type = {func } diff --git a/src/MapleFE/test/typescript/unit_tests/multi-line-string-literal.ts b/src/MapleFE/test/typescript/unit_tests/multi-line-string-literal.ts new file mode 100644 index 0000000000000000000000000000000000000000..26e132fab12b23e33936c24408faf09f8fedf865 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/multi-line-string-literal.ts @@ -0,0 +1,4 @@ +var str: string = "This \ +is \ +a string literal"; +console.log(str); diff --git a/src/MapleFE/test/typescript/unit_tests/multi-line-string-literal.ts.result b/src/MapleFE/test/typescript/unit_tests/multi-line-string-literal.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7a631af42512bbc917e468232fa4ac02bdac890c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/multi-line-string-literal.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 14 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: str="This is a string literal" +== Sub Tree == +console.log(str) diff --git a/src/MapleFE/test/typescript/unit_tests/multi-vars.ts b/src/MapleFE/test/typescript/unit_tests/multi-vars.ts new file mode 100644 index 0000000000000000000000000000000000000000..db336810cdcb5ebf7ef079ca24fc1b0a82e3931c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/multi-vars.ts @@ -0,0 +1,2 @@ +var x: number, y: number, z: number; +x = y = z = 1; diff --git a/src/MapleFE/test/typescript/unit_tests/multi-vars.ts.result b/src/MapleFE/test/typescript/unit_tests/multi-vars.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..abc43558d167ef5df41fd1541ff3fa3a8183d66c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/multi-vars.ts.result @@ -0,0 +1,11 @@ +Matched 13 tokens. +Matched 21 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x +== Sub Tree == +js_var Decl: y +== Sub Tree == +js_var Decl: z +== Sub Tree == +x Assign y Assign z Assign 1 diff --git a/src/MapleFE/test/typescript/unit_tests/namespace-with-closure.ts b/src/MapleFE/test/typescript/unit_tests/namespace-with-closure.ts new file mode 100644 index 0000000000000000000000000000000000000000..4adc7d8c09b8ec05265a671f6fc83e6bbc33aa9e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/namespace-with-closure.ts @@ -0,0 +1,16 @@ +namespace ns { + export function func() : Function { + let i: number = 10; + return () => ++i; + } +} + +import myFunc = ns.func; + +var f: Function = myFunc(); +console.log(f()); +console.log(f()); + +f = ns.func(); +console.log(f()); +console.log(f()); diff --git a/src/MapleFE/test/typescript/unit_tests/namespace-with-closure.ts.result b/src/MapleFE/test/typescript/unit_tests/namespace-with-closure.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3c7a2f5a188279e7137694a6266b8470a849d27c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/namespace-with-closure.ts.result @@ -0,0 +1,30 @@ +Matched 27 tokens. +Matched 34 tokens. +Matched 43 tokens. +Matched 52 tokens. +Matched 61 tokens. +Matched 69 tokens. +Matched 78 tokens. +Matched 87 tokens. +============= Module =========== +== Sub Tree == +namespace ns + export {func func() throws: + js_let Decl: i=10 + return () -> PreInc i +} + +== Sub Tree == +import {ns.func as myFunc} +== Sub Tree == +js_var Decl: f=myFunc() +== Sub Tree == +console.log(f()) +== Sub Tree == +console.log(f()) +== Sub Tree == +f Assign ns.func() +== Sub Tree == +console.log(f()) +== Sub Tree == +console.log(f()) diff --git a/src/MapleFE/test/typescript/unit_tests/namespace-with-closure2.ts b/src/MapleFE/test/typescript/unit_tests/namespace-with-closure2.ts new file mode 100644 index 0000000000000000000000000000000000000000..7d574427d5eb747f51d950fa45eb7649bec1c480 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/namespace-with-closure2.ts @@ -0,0 +1,16 @@ +namespace ns { + let i: number = 10; + export function func() : Function { + return () => ++i; + } +} + +import myFunc = ns.func; + +var f: Function = myFunc(); +console.log(f()); +console.log(f()); + +f = ns.func(); +console.log(f()); +console.log(f()); diff --git a/src/MapleFE/test/typescript/unit_tests/namespace-with-closure2.ts.result b/src/MapleFE/test/typescript/unit_tests/namespace-with-closure2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..575d2bbaa036fb2a261238713849b0c26c47f524 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/namespace-with-closure2.ts.result @@ -0,0 +1,30 @@ +Matched 27 tokens. +Matched 34 tokens. +Matched 43 tokens. +Matched 52 tokens. +Matched 61 tokens. +Matched 69 tokens. +Matched 78 tokens. +Matched 87 tokens. +============= Module =========== +== Sub Tree == +namespace ns + js_let Decl: i=10 + export {func func() throws: + return () -> PreInc i +} + +== Sub Tree == +import {ns.func as myFunc} +== Sub Tree == +js_var Decl: f=myFunc() +== Sub Tree == +console.log(f()) +== Sub Tree == +console.log(f()) +== Sub Tree == +f Assign ns.func() +== Sub Tree == +console.log(f()) +== Sub Tree == +console.log(f()) diff --git a/src/MapleFE/test/typescript/unit_tests/namespace.ts b/src/MapleFE/test/typescript/unit_tests/namespace.ts new file mode 100644 index 0000000000000000000000000000000000000000..0063f3281a004f26a4ef1b65ede34749f5456c02 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/namespace.ts @@ -0,0 +1,8 @@ +namespace ns_a { + var hello: string = "hello"; + export function foo(): string { + return hello; + } +} +console.log(ns_a.foo()); +export { ns_a as ns_1 }; diff --git a/src/MapleFE/test/typescript/unit_tests/namespace.ts.result b/src/MapleFE/test/typescript/unit_tests/namespace.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5bf02293716c720a8fc021ad99f67d75326cf63e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/namespace.ts.result @@ -0,0 +1,15 @@ +Matched 23 tokens. +Matched 34 tokens. +Matched 41 tokens. +============= Module =========== +== Sub Tree == +namespace ns_a + js_var Decl: hello="hello" + export {func foo() throws: + return hello +} + +== Sub Tree == +console.log(ns_a.foo()) +== Sub Tree == +export {ns_a as ns_1} diff --git a/src/MapleFE/test/typescript/unit_tests/namespace2.ts b/src/MapleFE/test/typescript/unit_tests/namespace2.ts new file mode 100644 index 0000000000000000000000000000000000000000..daf0a9e0e53b67d0d35d05944387690cc344ddc6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/namespace2.ts @@ -0,0 +1,10 @@ +namespace ns_a { + var x: number = 10; + var hello: string = "hello"; + export function foo(): string { + return hello; + } + for (var i = 0; i < x; ++i) console.log(i); +} +console.log(ns_a.foo()); +export { ns_a as ns_1 }; diff --git a/src/MapleFE/test/typescript/unit_tests/namespace2.ts.result b/src/MapleFE/test/typescript/unit_tests/namespace2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..4cedbcd03f32b0053c73e2f37da2373d190a9e5e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/namespace2.ts.result @@ -0,0 +1,18 @@ +Matched 51 tokens. +Matched 62 tokens. +Matched 69 tokens. +============= Module =========== +== Sub Tree == +namespace ns_a + js_var Decl: x=10 + js_var Decl: hello="hello" + export {func foo() throws: + return hello +} + for ( ) + console.log(i) + +== Sub Tree == +console.log(ns_a.foo()) +== Sub Tree == +export {ns_a as ns_1} diff --git a/src/MapleFE/test/typescript/unit_tests/namespace3.ts b/src/MapleFE/test/typescript/unit_tests/namespace3.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4e3550e0e43ed8db691f96cbba102d5bc69f397 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/namespace3.ts @@ -0,0 +1,7 @@ +namespace ns.a { + var hello: string = "hello"; + export function foo(): string { + return hello; + } +} +console.log(ns.a.foo()); diff --git a/src/MapleFE/test/typescript/unit_tests/namespace3.ts.result b/src/MapleFE/test/typescript/unit_tests/namespace3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..39f5a1f51e0770d99a529b86247cce0e6329f80d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/namespace3.ts.result @@ -0,0 +1,12 @@ +Matched 25 tokens. +Matched 38 tokens. +============= Module =========== +== Sub Tree == +namespace ns.a + js_var Decl: hello="hello" + export {func foo() throws: + return hello +} + +== Sub Tree == +console.log(ns.a.foo()) diff --git a/src/MapleFE/test/typescript/unit_tests/nested-loop.ts b/src/MapleFE/test/typescript/unit_tests/nested-loop.ts new file mode 100644 index 0000000000000000000000000000000000000000..bf840bd995669375a43dab0b299876cd9eff1035 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nested-loop.ts @@ -0,0 +1,12 @@ +var arr: number[] = [7, 4, 5, 9, 2, 8, 1, 6, 3]; +var len: number = arr.length; +for (var i = 1; i < len; ++i) { + var j: number = i - 1; + var n = arr[i]; + while (n < arr[j] && j >= 0) { + arr[j + 1] = arr[j]; + --j; + } + arr[j + 1] = n; +} +console.log(arr); diff --git a/src/MapleFE/test/typescript/unit_tests/nested-loop.ts.result b/src/MapleFE/test/typescript/unit_tests/nested-loop.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2f6bfa14e1794283fb23017275fa6b9f0c322e7f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nested-loop.ts.result @@ -0,0 +1,20 @@ +Matched 27 tokens. +Matched 36 tokens. +Matched 108 tokens. +Matched 115 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[7,4,5,9,2,8,1,6,3] +== Sub Tree == +js_var Decl: len=arr.length +== Sub Tree == +for ( ) + js_var Decl: j=i Sub 1 + js_var Decl: n=arr[i] + while n LT arr[j] Land j GE 0 arr[j Add 1] Assign arr[j] + PreDec j + + arr[j Add 1] Assign n + +== Sub Tree == +console.log(arr) diff --git a/src/MapleFE/test/typescript/unit_tests/nested-switch.ts b/src/MapleFE/test/typescript/unit_tests/nested-switch.ts new file mode 100644 index 0000000000000000000000000000000000000000..5c5169341037312f061a69a01d82760808fbd242 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nested-switch.ts @@ -0,0 +1,23 @@ +var n: number = 3; +outer: switch (true) { + case n < 5: + console.log(n, " is less than 5"); + case n > 2 && n < 5: + switch (n) { + case 3: + console.log(3); + break outer; + case 4: + console.log(4); + } + console.log(n, " + 1 is equal to", n + 1); + break; + case n == 6: + console.log(n, " is equal to 6"); + break; + case n < 8: + console.log(n, " is greater than 4 and less than 8"); + break; + default: + console.log(n, " is greater than 7"); +} diff --git a/src/MapleFE/test/typescript/unit_tests/nested-switch.ts.result b/src/MapleFE/test/typescript/unit_tests/nested-switch.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..d3cc51c43e971c32eeaa11cd84f0b1048cb026b4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nested-switch.ts.result @@ -0,0 +1,8 @@ +Matched 7 tokens. +Matched 125 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: n=3 +== Sub Tree == +A switch + diff --git a/src/MapleFE/test/typescript/unit_tests/nested.ts b/src/MapleFE/test/typescript/unit_tests/nested.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa3a1265240d29bd72004b89f33d2c5e5b247c80 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nested.ts @@ -0,0 +1,11 @@ +let x: number = 10; + +function outer(y: number): number { + let x: number = 20; + function inner(): number { + return x + y; + } + return inner(); +} + +console.log(outer(100)); diff --git a/src/MapleFE/test/typescript/unit_tests/nested.ts.result b/src/MapleFE/test/typescript/unit_tests/nested.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0eb487d7f9410554c4bf0c4b89dc3e742e4b6cc5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nested.ts.result @@ -0,0 +1,16 @@ +Matched 7 tokens. +Matched 43 tokens. +Matched 53 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: x=10 +== Sub Tree == +func outer(y) throws: + js_let Decl: x=20 + func inner() throws: + return x Add y + + return inner() + +== Sub Tree == +console.log(outer(100)) diff --git a/src/MapleFE/test/typescript/unit_tests/new-array.ts b/src/MapleFE/test/typescript/unit_tests/new-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b43f4bd71e633f38ca7c4fc5801100d33a9db9e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/new-array.ts @@ -0,0 +1,6 @@ +var v: boolean = (() => { + const buf = new ArrayBuffer(2); + new DataView(buf).setInt16(0, 256, true); + return new Int16Array(buf)[0] === 256; +})(); +console.log(v); diff --git a/src/MapleFE/test/typescript/unit_tests/new-array.ts.result b/src/MapleFE/test/typescript/unit_tests/new-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..343c86d07ff381b8ec2bfe9c59df0657bd2fb08b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/new-array.ts.result @@ -0,0 +1,10 @@ +Matched 51 tokens. +Matched 58 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: v=() -> js_const Decl: buf=new ArrayBuffer(2) +new DataView(buf).setInt16(0,256,true) +return new Int16Array(buf)[0] StEq 256 +() +== Sub Tree == +console.log(v) diff --git a/src/MapleFE/test/typescript/unit_tests/new-typed.ts b/src/MapleFE/test/typescript/unit_tests/new-typed.ts new file mode 100644 index 0000000000000000000000000000000000000000..b4ce46d179ff0d57b7eb08fcdbb81337778a4670 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/new-typed.ts @@ -0,0 +1,5 @@ +class A { + a: number = 0; +} +var x : Function = A; +var y : A = new A(); diff --git a/src/MapleFE/test/typescript/unit_tests/new-typed.ts.result b/src/MapleFE/test/typescript/unit_tests/new-typed.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..061c44ed79a8fba937f33fdb2cc90d852af9ca1b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/new-typed.ts.result @@ -0,0 +1,18 @@ +Matched 10 tokens. +Matched 17 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + a=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: x=A +== Sub Tree == +js_var Decl: y=new A() diff --git a/src/MapleFE/test/typescript/unit_tests/new.ts b/src/MapleFE/test/typescript/unit_tests/new.ts new file mode 100644 index 0000000000000000000000000000000000000000..e15cd8cf434620b82476a358ed2d8fb1d73ad417 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/new.ts @@ -0,0 +1,5 @@ +class A { + a: number = 0; +} +var x = A; +var y = new A(); diff --git a/src/MapleFE/test/typescript/unit_tests/new.ts.result b/src/MapleFE/test/typescript/unit_tests/new.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b04a81a2f86a804f93954656c46a02a950ebb11e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/new.ts.result @@ -0,0 +1,18 @@ +Matched 10 tokens. +Matched 15 tokens. +Matched 23 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + a=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: x=A +== Sub Tree == +js_var Decl: y=new A() diff --git a/src/MapleFE/test/typescript/unit_tests/non-null-assertion-this.ts b/src/MapleFE/test/typescript/unit_tests/non-null-assertion-this.ts new file mode 100644 index 0000000000000000000000000000000000000000..56e3e9b6072acfea70473ecce6e42c59d2b202c2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/non-null-assertion-this.ts @@ -0,0 +1,6 @@ +class Foo { + public _val: number = 0; + public func(): number { + return this._val! as number; + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/non-null-assertion-this.ts.result b/src/MapleFE/test/typescript/unit_tests/non-null-assertion-this.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c1164fc9ae80badf698158420119fd189d987dae --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/non-null-assertion-this.ts.result @@ -0,0 +1,14 @@ +Matched 27 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + _val=0 + Instance Initializer: + Constructors: + Methods: + func func() throws: + return this._val! + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/non-null-assertion.ts b/src/MapleFE/test/typescript/unit_tests/non-null-assertion.ts new file mode 100644 index 0000000000000000000000000000000000000000..f45fb51b3d4b3642942aef6c8a293f3105bf68e2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/non-null-assertion.ts @@ -0,0 +1,6 @@ +// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#non-null-assertion-operator +// used in cocos director.ts +function processEntity(e?: any) { + let s = e!.name; // Assert that e is non-null and access name + let t = e.name!; +} diff --git a/src/MapleFE/test/typescript/unit_tests/non-null-assertion.ts.result b/src/MapleFE/test/typescript/unit_tests/non-null-assertion.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6128e1977886dfada07b6d220535976a53290442 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/non-null-assertion.ts.result @@ -0,0 +1,7 @@ +Matched 26 tokens. +============= Module =========== +== Sub Tree == +func processEntity(e?) throws: + js_let Decl: s=e!.name + js_let Decl: t=e.name! + diff --git a/src/MapleFE/test/typescript/unit_tests/non-null-assertion2.ts b/src/MapleFE/test/typescript/unit_tests/non-null-assertion2.ts new file mode 100644 index 0000000000000000000000000000000000000000..f9baf6a8064932ecf8e720b1dbf0f9779a5e8cad --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/non-null-assertion2.ts @@ -0,0 +1,9 @@ +function foo(): Object | null { + return new Object(); +} + +export const obj = (() => { + return foo()!; +})(); + +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/non-null-assertion2.ts.result b/src/MapleFE/test/typescript/unit_tests/non-null-assertion2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..eeb0773123f8b1a989b172ced8916c6d6168658c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/non-null-assertion2.ts.result @@ -0,0 +1,13 @@ +Matched 16 tokens. +Matched 36 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +func foo() throws: + return new Object() + +== Sub Tree == +export {js_const Decl: obj=() -> return foo() +()} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/non-null-assertion3.ts b/src/MapleFE/test/typescript/unit_tests/non-null-assertion3.ts new file mode 100644 index 0000000000000000000000000000000000000000..a14849ff45cfbd56822b5391d7458c0ccf6de887 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/non-null-assertion3.ts @@ -0,0 +1,9 @@ +function foo(): Object | null { + return new Array(); +} + +export const obj = (() => { + return foo()! as unknown as Array; +})(); + +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/non-null-assertion3.ts.result b/src/MapleFE/test/typescript/unit_tests/non-null-assertion3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c1e0b4969cc0c35977380fb5b41128d91db051a1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/non-null-assertion3.ts.result @@ -0,0 +1,13 @@ +Matched 16 tokens. +Matched 43 tokens. +Matched 50 tokens. +============= Module =========== +== Sub Tree == +func foo() throws: + return new Array() + +== Sub Tree == +export {js_const Decl: obj=() -> return foo() +()} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/non-null-assertion4.ts b/src/MapleFE/test/typescript/unit_tests/non-null-assertion4.ts new file mode 100644 index 0000000000000000000000000000000000000000..594f1d1799a4b8c7a2f75c4879ce0341a14fd7e9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/non-null-assertion4.ts @@ -0,0 +1,3 @@ +var arr: Object[] = [new Object()]; +var obj = arr[0]!; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/non-null-assertion4.ts.result b/src/MapleFE/test/typescript/unit_tests/non-null-assertion4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1cb1d5237e689f6223c691aeb4b9d1cff6001dd3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/non-null-assertion4.ts.result @@ -0,0 +1,10 @@ +Matched 14 tokens. +Matched 23 tokens. +Matched 30 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[new Object()] +== Sub Tree == +js_var Decl: obj=arr[0] +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/nullish-assignment.ts b/src/MapleFE/test/typescript/unit_tests/nullish-assignment.ts new file mode 100644 index 0000000000000000000000000000000000000000..0624026d18104f1dad29eb3c55f0828b44c90cd9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nullish-assignment.ts @@ -0,0 +1,6 @@ +function func(num?: number): number { + num ??= 2; + return num * num; +} +console.log(func(10)); +console.log(func()); diff --git a/src/MapleFE/test/typescript/unit_tests/nullish-assignment.ts.result b/src/MapleFE/test/typescript/unit_tests/nullish-assignment.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f46445509ede779ac84e48bc3951eb61442bf54c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nullish-assignment.ts.result @@ -0,0 +1,13 @@ +Matched 21 tokens. +Matched 31 tokens. +Matched 40 tokens. +============= Module =========== +== Sub Tree == +func func(num?) throws: + num NullAssign 2 + return num Mul num + +== Sub Tree == +console.log(func(10)) +== Sub Tree == +console.log(func()) diff --git a/src/MapleFE/test/typescript/unit_tests/nullist-coalescing.ts b/src/MapleFE/test/typescript/unit_tests/nullist-coalescing.ts new file mode 100644 index 0000000000000000000000000000000000000000..958714e1fce13126fb96c2bc6cdd325c0c86db5e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nullist-coalescing.ts @@ -0,0 +1,4 @@ +// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#nullish-coalescing +let a: any = null; +let b: boolean = a ?? true; +console.log(a, b); diff --git a/src/MapleFE/test/typescript/unit_tests/nullist-coalescing.ts.result b/src/MapleFE/test/typescript/unit_tests/nullist-coalescing.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ef193ece82ba4def24b6c52122acf3b35243f346 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nullist-coalescing.ts.result @@ -0,0 +1,10 @@ +Matched 7 tokens. +Matched 16 tokens. +Matched 25 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: a=null +== Sub Tree == +js_let Decl: b=a NullCoalesce true +== Sub Tree == +console.log(a,b) diff --git a/src/MapleFE/test/typescript/unit_tests/nullist-coalescing2.ts b/src/MapleFE/test/typescript/unit_tests/nullist-coalescing2.ts new file mode 100644 index 0000000000000000000000000000000000000000..2df1b8b9292897fd467b8844b3d9c1192adb7892 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nullist-coalescing2.ts @@ -0,0 +1,7 @@ +function func(x: any): any { + return x; +} +let a: any = { f: false }; +// https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining +let b: boolean = func(a)?.f ?? true; +console.log(a, b); diff --git a/src/MapleFE/test/typescript/unit_tests/nullist-coalescing2.ts.result b/src/MapleFE/test/typescript/unit_tests/nullist-coalescing2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..949c3926980ec2d7f6934f77de6333c1a022fc8e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/nullist-coalescing2.ts.result @@ -0,0 +1,15 @@ +Matched 14 tokens. +Matched 25 tokens. +Matched 39 tokens. +Matched 48 tokens. +============= Module =========== +== Sub Tree == +func func(x) throws: + return x + +== Sub Tree == +js_let Decl: a= {f:false} +== Sub Tree == +js_let Decl: b=func(a).f NullCoalesce true +== Sub Tree == +console.log(a,b) diff --git a/src/MapleFE/test/typescript/unit_tests/number-array.ts b/src/MapleFE/test/typescript/unit_tests/number-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4db7ddbcd1e3fcb4294e87be3f9fb035d09e967 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/number-array.ts @@ -0,0 +1,2 @@ +var arr: number[]; +var arr: number[] = [1]; diff --git a/src/MapleFE/test/typescript/unit_tests/number-array.ts.result b/src/MapleFE/test/typescript/unit_tests/number-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..95c41af3f33de13ad52751301695806a37248bff --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/number-array.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 18 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr +== Sub Tree == +js_var Decl: arr=[1] diff --git a/src/MapleFE/test/typescript/unit_tests/number-literal.ts b/src/MapleFE/test/typescript/unit_tests/number-literal.ts new file mode 100644 index 0000000000000000000000000000000000000000..901536ae9582089642c65f4959d052483f7ba2d9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/number-literal.ts @@ -0,0 +1,3 @@ +const x: number = .2; +const y: number = -.2; +console.log(x, y); diff --git a/src/MapleFE/test/typescript/unit_tests/number-literal.ts.result b/src/MapleFE/test/typescript/unit_tests/number-literal.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..577b2fff51d9752b137b0d5ba212dff293b9c373 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/number-literal.ts.result @@ -0,0 +1,10 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 23 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: x=0.2 +== Sub Tree == +js_const Decl: y=-0.2 +== Sub Tree == +console.log(x,y) diff --git a/src/MapleFE/test/typescript/unit_tests/number-var.ts b/src/MapleFE/test/typescript/unit_tests/number-var.ts new file mode 100644 index 0000000000000000000000000000000000000000..257f24faa4df5439f6cf4f99501500eb9092f555 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/number-var.ts @@ -0,0 +1,7 @@ +var func: (number: number) => string; +function conv(number: number): string { + return number as unknown as string; +} + +func = conv; +console.log(func(123)); diff --git a/src/MapleFE/test/typescript/unit_tests/number-var.ts.result b/src/MapleFE/test/typescript/unit_tests/number-var.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a1d0390d3fd0ea86fc6899efcd842cb7db124c69 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/number-var.ts.result @@ -0,0 +1,15 @@ +Matched 11 tokens. +Matched 29 tokens. +Matched 33 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: func +== Sub Tree == +func conv(number) throws: + return number + +== Sub Tree == +func Assign conv +== Sub Tree == +console.log(func(123)) diff --git a/src/MapleFE/test/typescript/unit_tests/number.ts b/src/MapleFE/test/typescript/unit_tests/number.ts new file mode 100644 index 0000000000000000000000000000000000000000..b0ed7e5f07171b97cbba2cf2ce4a08b2940dde42 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/number.ts @@ -0,0 +1,4 @@ +var x = 4278190335; +console.log(x); +x = -1; +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/number.ts.result b/src/MapleFE/test/typescript/unit_tests/number.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..836c3a5037a175231a1c1e698785a51d0f4eedb8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/number.ts.result @@ -0,0 +1,13 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 16 tokens. +Matched 23 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=4278190335 +== Sub Tree == +console.log(x) +== Sub Tree == +x Assign -1 +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/obj.ts b/src/MapleFE/test/typescript/unit_tests/obj.ts new file mode 100644 index 0000000000000000000000000000000000000000..1582c89d2e038dd77e8dda82d9b9fc76b2e0e6b4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/obj.ts @@ -0,0 +1,3 @@ +let john = { + lastName: "Smith" +}; diff --git a/src/MapleFE/test/typescript/unit_tests/obj.ts.result b/src/MapleFE/test/typescript/unit_tests/obj.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..9c213f7401e72104ae4458172b7e61bfacb2ed20 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/obj.ts.result @@ -0,0 +1,4 @@ +Matched 9 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: john= {lastName:"Smith"} diff --git a/src/MapleFE/test/typescript/unit_tests/object-destructing.ts b/src/MapleFE/test/typescript/unit_tests/object-destructing.ts new file mode 100644 index 0000000000000000000000000000000000000000..9a189b6f038798483f376138a50ef441b841ac5d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/object-destructing.ts @@ -0,0 +1,4 @@ +var x = [{ a: 1 }, { b: 2 }, { c: 3 }]; +console.log(x.length); +var [{ a: u }, { b: v }] = x; +console.log(u, v); diff --git a/src/MapleFE/test/typescript/unit_tests/object-destructing.ts.result b/src/MapleFE/test/typescript/unit_tests/object-destructing.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..91161a894104ece0a4634175afda0438c20f6eee --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/object-destructing.ts.result @@ -0,0 +1,13 @@ +Matched 23 tokens. +Matched 32 tokens. +Matched 49 tokens. +Matched 58 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=[ {a:1}, {b:2}, {c:3}] +== Sub Tree == +console.log(x.length) +== Sub Tree == +js_var Decl: {{a:u}, {b:v}} +== Sub Tree == +console.log(u,v) diff --git a/src/MapleFE/test/typescript/unit_tests/object-destructing2.ts b/src/MapleFE/test/typescript/unit_tests/object-destructing2.ts new file mode 100644 index 0000000000000000000000000000000000000000..0dfbec3fd8ae78fa700968e7fad94b84f13eafb9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/object-destructing2.ts @@ -0,0 +1,6 @@ +function func(args: any): any { + const {foo, ...others} = args; + return others; +} + +console.log(func({foo: "Foo", bar: "Bar", tee: "Tee"})); diff --git a/src/MapleFE/test/typescript/unit_tests/object-destructing2.ts.result b/src/MapleFE/test/typescript/unit_tests/object-destructing2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6fc4e5d75956688e09ecf1d36a431fe684dae084 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/object-destructing2.ts.result @@ -0,0 +1,10 @@ +Matched 24 tokens. +Matched 46 tokens. +============= Module =========== +== Sub Tree == +func func(args) throws: + js_const Decl: {:foo, :...others} + return others + +== Sub Tree == +console.log(func( {foo:"Foo", bar:"Bar", tee:"Tee"})) diff --git a/src/MapleFE/test/typescript/unit_tests/object-func-prop.ts b/src/MapleFE/test/typescript/unit_tests/object-func-prop.ts new file mode 100644 index 0000000000000000000000000000000000000000..178b591ac2ab36db3bed90ac019d3e067689bd7b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/object-func-prop.ts @@ -0,0 +1,7 @@ +const initializer: any = { + foo(data: string) { + console.log(data); + }, +}; + +initializer.foo("test"); diff --git a/src/MapleFE/test/typescript/unit_tests/object-func-prop.ts.result b/src/MapleFE/test/typescript/unit_tests/object-func-prop.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3fbfed7752d0f03706a8c021e16058787818956c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/object-func-prop.ts.result @@ -0,0 +1,9 @@ +Matched 24 tokens. +Matched 31 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: initializer= {foo:func foo(data) throws: + console.log(data) +} +== Sub Tree == +initializer.foo("test") diff --git a/src/MapleFE/test/typescript/unit_tests/object-keys-arr-map.ts b/src/MapleFE/test/typescript/unit_tests/object-keys-arr-map.ts new file mode 100644 index 0000000000000000000000000000000000000000..49a05a210e6a0d7bc1375281636431b25957b98c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/object-keys-arr-map.ts @@ -0,0 +1,4 @@ +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map +var objA = { objB: { objC: {} } }; +const list = Object.keys(objA.objB.objC).map((x) => objA.objB.objC[x]); diff --git a/src/MapleFE/test/typescript/unit_tests/object-keys-arr-map.ts.result b/src/MapleFE/test/typescript/unit_tests/object-keys-arr-map.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..60163cf00d8476cecead062e5c0c3b47276d79e1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/object-keys-arr-map.ts.result @@ -0,0 +1,7 @@ +Matched 14 tokens. +Matched 44 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: objA= {objB: {objC: {}}} +== Sub Tree == +js_const Decl: list=Object.keys(objA.objB.objC).map((x) -> objA.objB.objC[x]) diff --git a/src/MapleFE/test/typescript/unit_tests/object-literal.ts b/src/MapleFE/test/typescript/unit_tests/object-literal.ts new file mode 100644 index 0000000000000000000000000000000000000000..701e019ea40eeee9a9444f576f93cb35dbd8148b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/object-literal.ts @@ -0,0 +1,2 @@ +var x: any = { n: [-1.5, 0, 1.0] }; +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/object-literal.ts.result b/src/MapleFE/test/typescript/unit_tests/object-literal.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e5424fa6f8f3ef9115ccebc1bec2a4faf5d2f44f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/object-literal.ts.result @@ -0,0 +1,7 @@ +Matched 17 tokens. +Matched 24 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x= {n:[-1.5,0,1]} +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/objects.ts b/src/MapleFE/test/typescript/unit_tests/objects.ts new file mode 100644 index 0000000000000000000000000000000000000000..15f2f507ab535d94d382ee52ea7e4278c5e7fe36 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/objects.ts @@ -0,0 +1,22 @@ +// different ways of creating an object + +function func() {} + +let funcObj = function (name: string) { + this._name = name; +}; + +class ObjClass { + private _name: string; + constructor(name: string) { + this._name = name; + } +} + +let obj_a: Object = {}; +let obj_b: Object = Object.create({}); +let obj_c: Object = Object.create(null); +let obj_d: Object = new Object(); +let obj_e: Object = new func(); +let obj_f: Object = new funcObj("John"); +let obj_g: Object = new ObjClass("John"); diff --git a/src/MapleFE/test/typescript/unit_tests/objects.ts.result b/src/MapleFE/test/typescript/unit_tests/objects.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1888e60831d18dbe197bf43457cc8b20dc138707 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/objects.ts.result @@ -0,0 +1,44 @@ +Matched 6 tokens. +Matched 24 tokens. +Matched 47 tokens. +Matched 55 tokens. +Matched 68 tokens. +Matched 80 tokens. +Matched 90 tokens. +Matched 100 tokens. +Matched 111 tokens. +Matched 122 tokens. +============= Module =========== +== Sub Tree == +func func() throws: + +== Sub Tree == +js_let Decl: funcObj=func (name) throws: + this._name Assign name + +== Sub Tree == +class ObjClass + Fields: + _name + Instance Initializer: + Constructors: + constructor (name) throws: + this._name Assign name + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: obj_a= {} +== Sub Tree == +js_let Decl: obj_b=Object.create( {}) +== Sub Tree == +js_let Decl: obj_c=Object.create(null) +== Sub Tree == +js_let Decl: obj_d=new Object() +== Sub Tree == +js_let Decl: obj_e=new func() +== Sub Tree == +js_let Decl: obj_f=new funcObj("John") +== Sub Tree == +js_let Decl: obj_g=new ObjClass("John") diff --git a/src/MapleFE/test/typescript/unit_tests/optional-chaining.ts b/src/MapleFE/test/typescript/unit_tests/optional-chaining.ts new file mode 100644 index 0000000000000000000000000000000000000000..c17627bdbe8af6e60d5a3aeea6e2c5bee0645bbe --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-chaining.ts @@ -0,0 +1,7 @@ +function func(arr?: number[]) { + return arr?.[0]; +} + +let arr: number[] = [1, 2, 3]; +console.log(func(arr)); +console.log(func()); diff --git a/src/MapleFE/test/typescript/unit_tests/optional-chaining.ts.result b/src/MapleFE/test/typescript/unit_tests/optional-chaining.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f08105ea81725c5c5454525f8d18adb18bfb86db --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-chaining.ts.result @@ -0,0 +1,15 @@ +Matched 19 tokens. +Matched 34 tokens. +Matched 44 tokens. +Matched 53 tokens. +============= Module =========== +== Sub Tree == +func func(arr?) throws: + return arr?[0] + +== Sub Tree == +js_let Decl: arr=[1,2,3] +== Sub Tree == +console.log(func(arr)) +== Sub Tree == +console.log(func()) diff --git a/src/MapleFE/test/typescript/unit_tests/optional-chaining2.ts b/src/MapleFE/test/typescript/unit_tests/optional-chaining2.ts new file mode 100644 index 0000000000000000000000000000000000000000..7b62c4ca9453e63f1fca540343ab5bc5efa2c4df --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-chaining2.ts @@ -0,0 +1,6 @@ +const obj = { + func: function () { + return 123; + }, +}; +console.log(obj.func?.()); diff --git a/src/MapleFE/test/typescript/unit_tests/optional-chaining2.ts.result b/src/MapleFE/test/typescript/unit_tests/optional-chaining2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3d0d7d1474b2f473ba1360e1985b5b97f1f9d1bb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-chaining2.ts.result @@ -0,0 +1,9 @@ +Matched 17 tokens. +Matched 29 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {func:func () throws: + return 123 +} +== Sub Tree == +console.log(obj.func()) diff --git a/src/MapleFE/test/typescript/unit_tests/optional-chaining3.ts b/src/MapleFE/test/typescript/unit_tests/optional-chaining3.ts new file mode 100644 index 0000000000000000000000000000000000000000..69722086d3e21fe50e10b751cfc3577011d72c55 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-chaining3.ts @@ -0,0 +1,10 @@ +const obj = { + func: function () { + return 123; + }, +}; + +function foo() { + return obj; +} +console.log(foo()?.func?.()); diff --git a/src/MapleFE/test/typescript/unit_tests/optional-chaining3.ts.result b/src/MapleFE/test/typescript/unit_tests/optional-chaining3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..958a6fde5c0f84277c676150dabbff01cd10b563 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-chaining3.ts.result @@ -0,0 +1,14 @@ +Matched 17 tokens. +Matched 26 tokens. +Matched 40 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {func:func () throws: + return 123 +} +== Sub Tree == +func foo() throws: + return obj + +== Sub Tree == +console.log(foo().func()) diff --git a/src/MapleFE/test/typescript/unit_tests/optional-method.ts b/src/MapleFE/test/typescript/unit_tests/optional-method.ts new file mode 100644 index 0000000000000000000000000000000000000000..585b9d26f326619164d176d53812903416b4540b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-method.ts @@ -0,0 +1,3 @@ +class Klass { + protected func?(): void; +} diff --git a/src/MapleFE/test/typescript/unit_tests/optional-method.ts.result b/src/MapleFE/test/typescript/unit_tests/optional-method.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1e36537786314b0f5e55efb76027d902fc1a223d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-method.ts.result @@ -0,0 +1,13 @@ +Matched 12 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + func func?() throws: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/optional-param.ts b/src/MapleFE/test/typescript/unit_tests/optional-param.ts new file mode 100644 index 0000000000000000000000000000000000000000..44d22da25c68181a5a71f3ff275137923836e813 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-param.ts @@ -0,0 +1,10 @@ +class Foo { + public a: string = ""; +} + +function func(x?: Foo): Foo { + return x ? x : { a: "default:a" }; +} + +console.log(func()); +console.log(func({ a: "Foo:a" })); diff --git a/src/MapleFE/test/typescript/unit_tests/optional-param.ts.result b/src/MapleFE/test/typescript/unit_tests/optional-param.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..fb05f46048eb9cc0d723b79fd7b1f3d747561fd0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-param.ts.result @@ -0,0 +1,23 @@ +Matched 11 tokens. +Matched 34 tokens. +Matched 43 tokens. +Matched 57 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + a="" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func func(x?) throws: + return x ? x : {a:"default:a"} + +== Sub Tree == +console.log(func()) +== Sub Tree == +console.log(func( {a:"Foo:a"})) diff --git a/src/MapleFE/test/typescript/unit_tests/optional-prop.ts b/src/MapleFE/test/typescript/unit_tests/optional-prop.ts new file mode 100644 index 0000000000000000000000000000000000000000..d635013d7e144fc5bffbebfd3f427200b35209f3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-prop.ts @@ -0,0 +1,11 @@ +class Klass { + a: number = 0; + b?: number; +} + +function f({ a, b = 1 }: Klass): number { + return a + b; +} + +console.log(f({ a: 1 })); +console.log(f({ a: 1, b: 2 })); diff --git a/src/MapleFE/test/typescript/unit_tests/optional-prop.ts.result b/src/MapleFE/test/typescript/unit_tests/optional-prop.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1dd4128a6ba5c4ffa15c49f2ec29766006cf2704 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/optional-prop.ts.result @@ -0,0 +1,23 @@ +Matched 15 tokens. +Matched 37 tokens. +Matched 51 tokens. +Matched 69 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + a=0 b? + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func f({:a, :b=1}) throws: + return a Add b + +== Sub Tree == +console.log(f( {a:1})) +== Sub Tree == +console.log(f( {a:1, b:2})) diff --git a/src/MapleFE/test/typescript/unit_tests/pick-key.ts b/src/MapleFE/test/typescript/unit_tests/pick-key.ts new file mode 100644 index 0000000000000000000000000000000000000000..a8ba3a4bc304b0ab536d985022bbea1427937241 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/pick-key.ts @@ -0,0 +1,6 @@ +interface IFace { + s: string; + n: number; +} +declare type Type = { [K in keyof Pick]: true; }; + diff --git a/src/MapleFE/test/typescript/unit_tests/pick-key.ts.result b/src/MapleFE/test/typescript/unit_tests/pick-key.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..03c535cb9bdf5df29aeb068ed4d28f20fca2d1e0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/pick-key.ts.result @@ -0,0 +1,7 @@ +Matched 12 tokens. +Matched 33 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {s;n } +== Sub Tree == +declare type Type = {[K in keyof Pick] : true } diff --git a/src/MapleFE/test/typescript/unit_tests/priv-declare.ts b/src/MapleFE/test/typescript/unit_tests/priv-declare.ts new file mode 100644 index 0000000000000000000000000000000000000000..8babfc0eeb8ece6cfa8e0b3a04f260f829a8c2e3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/priv-declare.ts @@ -0,0 +1,3 @@ +class CLS_test { + private declare priv_fd: number; +} diff --git a/src/MapleFE/test/typescript/unit_tests/priv-declare.ts.result b/src/MapleFE/test/typescript/unit_tests/priv-declare.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2c1241d605350d8dd7d5c873694daefc5696e6ec --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/priv-declare.ts.result @@ -0,0 +1,13 @@ +Matched 10 tokens. +============= Module =========== +== Sub Tree == +class CLS_test + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + Declares: + declare js_var Decl: priv_fd diff --git a/src/MapleFE/test/typescript/unit_tests/private-constructor.ts b/src/MapleFE/test/typescript/unit_tests/private-constructor.ts new file mode 100644 index 0000000000000000000000000000000000000000..280daea9af883d7eefca14378dc8cdebf33ad1ca --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/private-constructor.ts @@ -0,0 +1,6 @@ +declare namespace NS { + class Klass { + n: number; + private constructor(); + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/private-constructor.ts.result b/src/MapleFE/test/typescript/unit_tests/private-constructor.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ff6c6a0630e64923c7d45837a6072f9843fdbbb5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/private-constructor.ts.result @@ -0,0 +1,15 @@ +Matched 18 tokens. +============= Module =========== +== Sub Tree == +declare namespace NS + class Klass + Fields: + n + Instance Initializer: + Constructors: + constructor () throws: + Methods: + LocalClasses: + LocalInterfaces: + + diff --git a/src/MapleFE/test/typescript/unit_tests/private-field.d.ts b/src/MapleFE/test/typescript/unit_tests/private-field.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..70fb72ce9d09c8f65d5aa8e226f9cd7a06a7df2c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/private-field.d.ts @@ -0,0 +1,7 @@ +// #private; for ECMAScript’s pound (#) private fields +// https://www.typescriptlang.org/docs/handbook/2/classes.html#caveats +// https://github.com/microsoft/TypeScript/issues/38050 +declare class Klass { + #private; + constructor(); +} diff --git a/src/MapleFE/test/typescript/unit_tests/private-field.d.ts.result b/src/MapleFE/test/typescript/unit_tests/private-field.d.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7375df4dcbb2cf727e745c73eb8aa1818d5ff888 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/private-field.d.ts.result @@ -0,0 +1,13 @@ +Matched 12 tokens. +============= Module =========== +== Sub Tree == +declare class Klass + Fields: + private + Instance Initializer: + Constructors: + constructor () throws: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/private-prop.ts b/src/MapleFE/test/typescript/unit_tests/private-prop.ts new file mode 100644 index 0000000000000000000000000000000000000000..f59dc26801875779246b6c39d23851493ac83077 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/private-prop.ts @@ -0,0 +1,5 @@ +class Klass { + private "Klass.#private" = "abc"; +} +var obj : Klass = new Klass(); +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/private-prop.ts.result b/src/MapleFE/test/typescript/unit_tests/private-prop.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8804c42005a08a0b80281bbc1dfe7c3fe449577d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/private-prop.ts.result @@ -0,0 +1,18 @@ +Matched 9 tokens. +Matched 19 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + "Klass.#private" = "abc" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/prop-name-extends.ts b/src/MapleFE/test/typescript/unit_tests/prop-name-extends.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a7afdd521d8706a8e00cbc5e200c22a8ea57938 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/prop-name-extends.ts @@ -0,0 +1 @@ +function func(arg: { extends: null | Function }) {} diff --git a/src/MapleFE/test/typescript/unit_tests/prop-name-extends.ts.result b/src/MapleFE/test/typescript/unit_tests/prop-name-extends.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b8774ca191a1440ea1eaebd14c13818adafd5721 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/prop-name-extends.ts.result @@ -0,0 +1,5 @@ +Matched 15 tokens. +============= Module =========== +== Sub Tree == +func func(arg) throws: + diff --git a/src/MapleFE/test/typescript/unit_tests/property-deco.ts b/src/MapleFE/test/typescript/unit_tests/property-deco.ts new file mode 100644 index 0000000000000000000000000000000000000000..cefae64156bc3fdd2374ab837e508db7fec6f399 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/property-deco.ts @@ -0,0 +1,16 @@ +function prop_deco(msg: string) { + return function (target: any, name: string) { + console.log("Accessed", name, msg, target); + }; +} + +class Klass { + @prop_deco("of") + x: number; + constructor(i: number) { + this.x = i; + } +} + +var c = new Klass(3); +console.log(c.x); diff --git a/src/MapleFE/test/typescript/unit_tests/property-deco.ts.result b/src/MapleFE/test/typescript/unit_tests/property-deco.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1ab368a50744badc22012660a8e8a7a6d211698d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/property-deco.ts.result @@ -0,0 +1,27 @@ +Matched 36 tokens. +Matched 63 tokens. +Matched 72 tokens. +Matched 81 tokens. +============= Module =========== +== Sub Tree == +func prop_deco(msg) throws: + return func (target,name) throws: + console.log("Accessed",name,msg,target) + + +== Sub Tree == +class Klass + Fields: + x + Instance Initializer: + Constructors: + constructor (i) throws: + this.x Assign i + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: c=new Klass(3) +== Sub Tree == +console.log(c.x) diff --git a/src/MapleFE/test/typescript/unit_tests/property-deco2.ts b/src/MapleFE/test/typescript/unit_tests/property-deco2.ts new file mode 100644 index 0000000000000000000000000000000000000000..5727298d19469dfcdcb8d5ba4cf7657d53a7ce2b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/property-deco2.ts @@ -0,0 +1,20 @@ +function prop_deco(msg: string) { + return function (target: any, name: string) { + console.log("Accessed", name, msg, target); + }; +} + +class Klass { + _x: number; + constructor(i: number) { + this._x = i; + } + + @prop_deco("of") + get x() { + return this._x; + } +} + +var c = new Klass(3); +console.log(c.x); diff --git a/src/MapleFE/test/typescript/unit_tests/property-deco2.ts.result b/src/MapleFE/test/typescript/unit_tests/property-deco2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3870d964ac97e61a58afca083c1530b5b2a8128c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/property-deco2.ts.result @@ -0,0 +1,29 @@ +Matched 36 tokens. +Matched 74 tokens. +Matched 83 tokens. +Matched 92 tokens. +============= Module =========== +== Sub Tree == +func prop_deco(msg) throws: + return func (target,name) throws: + console.log("Accessed",name,msg,target) + + +== Sub Tree == +class Klass + Fields: + _x + Instance Initializer: + Constructors: + constructor (i) throws: + this._x Assign i + Methods: + get x() throws: + return this._x + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: c=new Klass(3) +== Sub Tree == +console.log(c.x) diff --git a/src/MapleFE/test/typescript/unit_tests/property-deco3.ts b/src/MapleFE/test/typescript/unit_tests/property-deco3.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f9686568426ed71dfd8b6a7e85bd5b01b7a6e01 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/property-deco3.ts @@ -0,0 +1,16 @@ +function type(msg: string) { + return function (target: any, name: string) { + console.log("Accessed", name, msg, target); + }; +} + +class Klass { + @type("of") + x: number; + constructor(i: number) { + this.x = i; + } +} + +var c = new Klass(3); +console.log(c.x); diff --git a/src/MapleFE/test/typescript/unit_tests/property-deco3.ts.result b/src/MapleFE/test/typescript/unit_tests/property-deco3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e1ebece167f1202a4fa8d0e70f8eab7f754cc60d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/property-deco3.ts.result @@ -0,0 +1,27 @@ +Matched 36 tokens. +Matched 63 tokens. +Matched 72 tokens. +Matched 81 tokens. +============= Module =========== +== Sub Tree == +func type(msg) throws: + return func (target,name) throws: + console.log("Accessed",name,msg,target) + + +== Sub Tree == +class Klass + Fields: + x + Instance Initializer: + Constructors: + constructor (i) throws: + this.x Assign i + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: c=new Klass(3) +== Sub Tree == +console.log(c.x) diff --git a/src/MapleFE/test/typescript/unit_tests/property-deco4.ts b/src/MapleFE/test/typescript/unit_tests/property-deco4.ts new file mode 100644 index 0000000000000000000000000000000000000000..539811a971930c13f0f9fd145bf259a0b1350c4d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/property-deco4.ts @@ -0,0 +1,21 @@ +function type(msg: string) { + return function (target: any, name: string) { + console.log("Accessed", name, msg, target); + }; +} + +function deco(target: any, name: string) { + console.log("Accessed", name, "OF", target); +} + +class Klass { + @deco + @type("of") + x: number; + constructor(i: number) { + this.x = i; + } +} + +var c = new Klass(3); +console.log(c.x); diff --git a/src/MapleFE/test/typescript/unit_tests/property-deco4.ts.result b/src/MapleFE/test/typescript/unit_tests/property-deco4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..9aa9229bb9e5ebfd33877ffb7ade40f59dd11358 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/property-deco4.ts.result @@ -0,0 +1,32 @@ +Matched 36 tokens. +Matched 62 tokens. +Matched 91 tokens. +Matched 100 tokens. +Matched 109 tokens. +============= Module =========== +== Sub Tree == +func type(msg) throws: + return func (target,name) throws: + console.log("Accessed",name,msg,target) + + +== Sub Tree == +func deco(target,name) throws: + console.log("Accessed",name,"OF",target) + +== Sub Tree == +class Klass + Fields: + x + Instance Initializer: + Constructors: + constructor (i) throws: + this.x Assign i + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: c=new Klass(3) +== Sub Tree == +console.log(c.x) diff --git a/src/MapleFE/test/typescript/unit_tests/public-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/public-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..19784d994c4a50459b669a7b8fdac749a57847e0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/public-as-prop-name.ts @@ -0,0 +1,3 @@ +interface IFace { + public: string; +} diff --git a/src/MapleFE/test/typescript/unit_tests/public-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/public-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..55d9de52e70c78571eb902a72d547fc194f37043 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/public-as-prop-name.ts.result @@ -0,0 +1,4 @@ +Matched 8 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {public } diff --git a/src/MapleFE/test/typescript/unit_tests/re-export.ts b/src/MapleFE/test/typescript/unit_tests/re-export.ts new file mode 100644 index 0000000000000000000000000000000000000000..dea206bb65b44a718d251b8587b08ac6019a319a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/re-export.ts @@ -0,0 +1,4 @@ +export * from "./M"; +export { default as x } from "./M"; +import { default as x } from "./M"; +export { x as default }; diff --git a/src/MapleFE/test/typescript/unit_tests/re-export.ts.result b/src/MapleFE/test/typescript/unit_tests/re-export.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..cd3ee09e619a0c75c2353490484d6898c513b07e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/re-export.ts.result @@ -0,0 +1,13 @@ +Matched 5 tokens. +Matched 14 tokens. +Matched 23 tokens. +Matched 30 tokens. +============= Module =========== +== Sub Tree == +export { *} "./M" +== Sub Tree == +export {default as x} "./M" +== Sub Tree == +import {default as x} "./M" +== Sub Tree == +export {x as default} diff --git a/src/MapleFE/test/typescript/unit_tests/re-export2.ts b/src/MapleFE/test/typescript/unit_tests/re-export2.ts new file mode 100644 index 0000000000000000000000000000000000000000..387bd489e6ab49fbeb3d2832e7979469a1ac4d97 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/re-export2.ts @@ -0,0 +1,5 @@ +export * from "./M"; +export { default as Y } from "./M"; +import { default as x } from "./M"; +export { x as default }; +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/re-export2.ts.result b/src/MapleFE/test/typescript/unit_tests/re-export2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..9794f6a145438cc1d64fab0250b29722b9e5f5e6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/re-export2.ts.result @@ -0,0 +1,16 @@ +Matched 5 tokens. +Matched 14 tokens. +Matched 23 tokens. +Matched 30 tokens. +Matched 37 tokens. +============= Module =========== +== Sub Tree == +export { *} "./M" +== Sub Tree == +export {default as Y} "./M" +== Sub Tree == +import {default as x} "./M" +== Sub Tree == +export {x as default} +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/re-export4.ts b/src/MapleFE/test/typescript/unit_tests/re-export4.ts new file mode 100644 index 0000000000000000000000000000000000000000..63ca2a02303b91f291aa96355171cc1a13c5f580 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/re-export4.ts @@ -0,0 +1,2 @@ +export * as MM from "./M"; +export { default as default } from "./M"; diff --git a/src/MapleFE/test/typescript/unit_tests/re-export4.ts.result b/src/MapleFE/test/typescript/unit_tests/re-export4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..877e3451ab06c83951e3d35059a90f57ecf1af12 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/re-export4.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 16 tokens. +============= Module =========== +== Sub Tree == +export { * as MM} "./M" +== Sub Tree == +export {default as default} "./M" diff --git a/src/MapleFE/test/typescript/unit_tests/readonly-return.ts b/src/MapleFE/test/typescript/unit_tests/readonly-return.ts new file mode 100644 index 0000000000000000000000000000000000000000..6fd9bb123332380f7d89f5814cc8610e446fa723 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/readonly-return.ts @@ -0,0 +1,6 @@ +function foo(): readonly number[] { + var v: number = 1; + return [v, v]; +} + +console.log(foo()); diff --git a/src/MapleFE/test/typescript/unit_tests/readonly-return.ts.result b/src/MapleFE/test/typescript/unit_tests/readonly-return.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..4c57aa2b0093bd379d0d19f9037a1f84bb80d844 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/readonly-return.ts.result @@ -0,0 +1,10 @@ +Matched 25 tokens. +Matched 34 tokens. +============= Module =========== +== Sub Tree == +func foo() throws: + js_var Decl: v=1 + return [v,v] + +== Sub Tree == +console.log(foo()) diff --git a/src/MapleFE/test/typescript/unit_tests/readonly-return2.ts b/src/MapleFE/test/typescript/unit_tests/readonly-return2.ts new file mode 100644 index 0000000000000000000000000000000000000000..1754cffadfc19ee8679584edd24160437c0388cb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/readonly-return2.ts @@ -0,0 +1,6 @@ +class Klass {} + +export interface Interface { + foo(): readonly Klass[]; + bar(): void; +} diff --git a/src/MapleFE/test/typescript/unit_tests/readonly-return2.ts.result b/src/MapleFE/test/typescript/unit_tests/readonly-return2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..08c169df65f6fd8f75bbdb2858c91e49abaef68a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/readonly-return2.ts.result @@ -0,0 +1,17 @@ +Matched 4 tokens. +Matched 24 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +export {ts_interface: Interface {func foo() throws: +;func bar() throws: + }} diff --git a/src/MapleFE/test/typescript/unit_tests/readonly.ts b/src/MapleFE/test/typescript/unit_tests/readonly.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8744efac8f3502a85c0d856571dd7d7f7a2f69f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/readonly.ts @@ -0,0 +1,3 @@ +export class Foo { + readonly foo_var: number = 1; +} diff --git a/src/MapleFE/test/typescript/unit_tests/readonly.ts.result b/src/MapleFE/test/typescript/unit_tests/readonly.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0be5e3d965213c608c710de39a5c8a81b6755575 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/readonly.ts.result @@ -0,0 +1,12 @@ +Matched 12 tokens. +============= Module =========== +== Sub Tree == +export {class Foo + Fields: + foo_var=1 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: +} diff --git a/src/MapleFE/test/typescript/unit_tests/record-parameter.ts b/src/MapleFE/test/typescript/unit_tests/record-parameter.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6a2d644b8ced589ebe37d1671d212326d94d7dc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/record-parameter.ts @@ -0,0 +1,3 @@ +class Klass { + func(map: Record void>) {} +} diff --git a/src/MapleFE/test/typescript/unit_tests/record-parameter.ts.result b/src/MapleFE/test/typescript/unit_tests/record-parameter.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e84b88f33294cce537889c15676d3940720a379d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/record-parameter.ts.result @@ -0,0 +1,13 @@ +Matched 39 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + func func(map) throws: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/record.ts b/src/MapleFE/test/typescript/unit_tests/record.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f71dde3de55dfe187008f0c2ffd36dbfeb3d2ab --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/record.ts @@ -0,0 +1,12 @@ +enum Direction { + LEFT, + RIGHT, +} + +const rec: Record = { + [Direction.LEFT]: "left", + [Direction.RIGHT]: "right", + default: "Unknown", +}; + +console.log(rec); diff --git a/src/MapleFE/test/typescript/unit_tests/record.ts.result b/src/MapleFE/test/typescript/unit_tests/record.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ac4d471a66850d660556cc5a15a014052cf182f9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/record.ts.result @@ -0,0 +1,10 @@ +Matched 8 tokens. +Matched 41 tokens. +Matched 48 tokens. +============= Module =========== +== Sub Tree == +ts_enum: Direction {LEFT;RIGHT } +== Sub Tree == +js_const Decl: rec= {[Direction.LEFT] : :"left", [Direction.RIGHT] : :"right", default:"Unknown"} +== Sub Tree == +console.log(rec) diff --git a/src/MapleFE/test/typescript/unit_tests/regexp-array.ts b/src/MapleFE/test/typescript/unit_tests/regexp-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..9622797aa2089c79a9c0f5c7bc6923f588b3c7d9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp-array.ts @@ -0,0 +1,7 @@ +const obj = { + arr: [ + /[/\\]@cocos1/, + /[/\\]@cocos2/, + ], +}; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/regexp-array.ts.result b/src/MapleFE/test/typescript/unit_tests/regexp-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ef3e3385429d05a519a0a4c67c3cbb3508b85ad4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp-array.ts.result @@ -0,0 +1,7 @@ +Matched 15 tokens. +Matched 22 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {arr:[reg expr : [/\\]@cocos1,reg expr : [/\\]@cocos2]} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/regexp-array2.ts b/src/MapleFE/test/typescript/unit_tests/regexp-array2.ts new file mode 100644 index 0000000000000000000000000000000000000000..cd8922dc441a16dacdc86f2464f1274fdb4aee8c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp-array2.ts @@ -0,0 +1,7 @@ +const obj = { + arr: [{ + ex1: /[/\\]@cocos1/, + ex2: /[/\\]@cocos2/, + }], +}; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/regexp-array2.ts.result b/src/MapleFE/test/typescript/unit_tests/regexp-array2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e1e3c3558685c6a71d9f4b9c5a3cdbc20b7f43a4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp-array2.ts.result @@ -0,0 +1,7 @@ +Matched 21 tokens. +Matched 28 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {arr:[ {ex1:reg expr : [/\\]@cocos1, ex2:reg expr : [/\\]@cocos2}]} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/regexp-array3.ts b/src/MapleFE/test/typescript/unit_tests/regexp-array3.ts new file mode 100644 index 0000000000000000000000000000000000000000..8188aebbf0c52f880aefa5799c82e931ee5eabe1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp-array3.ts @@ -0,0 +1,4 @@ +const obj = { + arr : [ /[/\\]@cocos1/, /[/\\]@cocos2/] +}; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/regexp-array3.ts.result b/src/MapleFE/test/typescript/unit_tests/regexp-array3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a170be2cd1c56ef5ce70110dda04c63793c40d45 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp-array3.ts.result @@ -0,0 +1,7 @@ +Matched 13 tokens. +Matched 20 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {arr:[reg expr : [/\\]@cocos1,reg expr : [/\\]@cocos2]} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/regexp-in-array.ts b/src/MapleFE/test/typescript/unit_tests/regexp-in-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab5b96853e42e1dd45b7ba167f70a1e449245858 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp-in-array.ts @@ -0,0 +1,3 @@ +var x: Array<[RegExp, string]> = []; +x.push([/</g, "<"]); +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/regexp-in-array.ts.result b/src/MapleFE/test/typescript/unit_tests/regexp-in-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..643a8cebf99c240a6111a4d15a6bdb75b3a3a27e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp-in-array.ts.result @@ -0,0 +1,10 @@ +Matched 15 tokens. +Matched 26 tokens. +Matched 33 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=[] +== Sub Tree == +x.push([reg expr : < g,"<"]) +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/regexp.ts b/src/MapleFE/test/typescript/unit_tests/regexp.ts new file mode 100644 index 0000000000000000000000000000000000000000..78e2c0dfbb6ebdc2fa530060df5421717cbb2de1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp.ts @@ -0,0 +1,4 @@ +var str: string = "abcba"; +console.log(str); +str = str.replace(/b/g, "B"); +console.log(str); diff --git a/src/MapleFE/test/typescript/unit_tests/regexp.ts.result b/src/MapleFE/test/typescript/unit_tests/regexp.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2562eb3a8b49eee841b3ba10fe403d999d336e51 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp.ts.result @@ -0,0 +1,13 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 25 tokens. +Matched 32 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: str="abcba" +== Sub Tree == +console.log(str) +== Sub Tree == +str Assign str.replace(reg expr : b g,"B") +== Sub Tree == +console.log(str) diff --git a/src/MapleFE/test/typescript/unit_tests/regexp2.ts b/src/MapleFE/test/typescript/unit_tests/regexp2.ts new file mode 100644 index 0000000000000000000000000000000000000000..8145277a03845be1179d65075b731565db26802e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp2.ts @@ -0,0 +1,4 @@ +function repl(s: string) { + return s.replace(/\s\S/g, "."); +} +console.log(repl("abc def gh")); diff --git a/src/MapleFE/test/typescript/unit_tests/regexp2.ts.result b/src/MapleFE/test/typescript/unit_tests/regexp2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..19c8b14acbddb03a6003b9e69cba5b5e77fecb72 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp2.ts.result @@ -0,0 +1,9 @@ +Matched 19 tokens. +Matched 29 tokens. +============= Module =========== +== Sub Tree == +func repl(s) throws: + return s.replace(reg expr : \s\S g,".") + +== Sub Tree == +console.log(repl("abc def gh")) diff --git a/src/MapleFE/test/typescript/unit_tests/regexp3.ts b/src/MapleFE/test/typescript/unit_tests/regexp3.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec93450ba34f8c801a0c0f0d40eb165062148812 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp3.ts @@ -0,0 +1,3 @@ +var s = "abc de fg"; +s = s.replace(/[^A-Za-z0-9\+\/\=]/g, ""); +console.log(s); diff --git a/src/MapleFE/test/typescript/unit_tests/regexp3.ts.result b/src/MapleFE/test/typescript/unit_tests/regexp3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b6c6aa92deba4b1ca791a99c5f2115f262f11288 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp3.ts.result @@ -0,0 +1,10 @@ +Matched 5 tokens. +Matched 16 tokens. +Matched 23 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: s="abc de fg" +== Sub Tree == +s Assign s.replace(reg expr : [^A-Za-z0-9\+\/\=] g,"") +== Sub Tree == +console.log(s) diff --git a/src/MapleFE/test/typescript/unit_tests/regexp4.ts b/src/MapleFE/test/typescript/unit_tests/regexp4.ts new file mode 100644 index 0000000000000000000000000000000000000000..50e475c0b422254e6077879251892e1854c0e755 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp4.ts @@ -0,0 +1,5 @@ +var str: string = "abc/ab/1234abcdef"; +var re = /.*[/\\][0-9a-fA-F]{2}[/\\]([0-9a-fA-F-@]{8,}).*/; +console.log(str); +str = str.replace(re, "replaced"); +console.log(str); diff --git a/src/MapleFE/test/typescript/unit_tests/regexp4.ts.result b/src/MapleFE/test/typescript/unit_tests/regexp4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c3641c93a5c57867aff677abd58f16559fae3028 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp4.ts.result @@ -0,0 +1,16 @@ +Matched 7 tokens. +Matched 12 tokens. +Matched 19 tokens. +Matched 30 tokens. +Matched 37 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: str="abc/ab/1234abcdef" +== Sub Tree == +js_var Decl: re=reg expr : .*[/\\][0-9a-fA-F]{2}[/\\]([0-9a-fA-F-@]{8,}).* +== Sub Tree == +console.log(str) +== Sub Tree == +str Assign str.replace(re,"replaced") +== Sub Tree == +console.log(str) diff --git a/src/MapleFE/test/typescript/unit_tests/regexp5.ts b/src/MapleFE/test/typescript/unit_tests/regexp5.ts new file mode 100644 index 0000000000000000000000000000000000000000..feec44b29704eb4c28475e9a85d9ac025f49f5ac --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp5.ts @@ -0,0 +1,2 @@ +var x = true && /\/t/.test("/test"); +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/regexp5.ts.result b/src/MapleFE/test/typescript/unit_tests/regexp5.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..4b499ad4e3a5f7d3eefd34c22db3148c1a5cc09e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp5.ts.result @@ -0,0 +1,7 @@ +Matched 12 tokens. +Matched 19 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=true Land reg expr : \/t.test("/test") +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/regexp6.ts b/src/MapleFE/test/typescript/unit_tests/regexp6.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c93d2254f766ac6cbe8074fe07642b976597b58 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp6.ts @@ -0,0 +1,3 @@ +const str = "foo bar tee"; +let res: null | any[] = /Foo/.exec(str) || /bar/.exec(str); +console.log(res); diff --git a/src/MapleFE/test/typescript/unit_tests/regexp6.ts.result b/src/MapleFE/test/typescript/unit_tests/regexp6.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..4c7a7ef2c6cf41c6d2c5b1d948d8f2923dee0af8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp6.ts.result @@ -0,0 +1,10 @@ +Matched 5 tokens. +Matched 28 tokens. +Matched 35 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: str="foo bar tee" +== Sub Tree == +js_let Decl: res=reg expr : Foo.exec(str) Lor reg expr : bar.exec(str) +== Sub Tree == +console.log(res) diff --git a/src/MapleFE/test/typescript/unit_tests/regexp7.ts b/src/MapleFE/test/typescript/unit_tests/regexp7.ts new file mode 100644 index 0000000000000000000000000000000000000000..c9af3f44c5cab284ff0bdc1a41c4dec8bb34d1c9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp7.ts @@ -0,0 +1,2 @@ +export const re = + /["\u0000-\u001f]/g diff --git a/src/MapleFE/test/typescript/unit_tests/regexp7.ts.result b/src/MapleFE/test/typescript/unit_tests/regexp7.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b272ca0aea8e35cf16f504ab4e4c193d4ba3b6c1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regexp7.ts.result @@ -0,0 +1,4 @@ +Matched 5 tokens. +============= Module =========== +== Sub Tree == +export {js_const Decl: re=reg expr : ["\u0000-\u001f] g} diff --git a/src/MapleFE/test/typescript/unit_tests/regular-type.ts b/src/MapleFE/test/typescript/unit_tests/regular-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..d78d711bd0597d5c8a52a922ed1f93954dd473f2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regular-type.ts @@ -0,0 +1,3 @@ +class Klass {} +type K = Klass; +var a: K; diff --git a/src/MapleFE/test/typescript/unit_tests/regular-type.ts.result b/src/MapleFE/test/typescript/unit_tests/regular-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..bcc4082835a4e0350e46b808105292def0d5fc17 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/regular-type.ts.result @@ -0,0 +1,18 @@ +Matched 4 tokens. +Matched 9 tokens. +Matched 14 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == + type K = Klass +== Sub Tree == +js_var Decl: a diff --git a/src/MapleFE/test/typescript/unit_tests/rest-in-array.ts b/src/MapleFE/test/typescript/unit_tests/rest-in-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..0701d0a959d2cf15b64849d072608c91eeeb17d8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-in-array.ts @@ -0,0 +1,6 @@ +const enum TypeID { + Array_Class = 0, + Array, +} + +type TYPE = [string, string[], number, ...TypeID[]]; diff --git a/src/MapleFE/test/typescript/unit_tests/rest-in-array.ts.result b/src/MapleFE/test/typescript/unit_tests/rest-in-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8f69208f6e74b4388dbea5b833a559233a2f6f88 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-in-array.ts.result @@ -0,0 +1,7 @@ +Matched 11 tokens. +Matched 29 tokens. +============= Module =========== +== Sub Tree == +ts_enum: TypeID {Array_Class=0;Array } +== Sub Tree == + type TYPE = [ : string , : prim array-TBD , : number , : ...TypeID[] , ] diff --git a/src/MapleFE/test/typescript/unit_tests/rest-in-array2.ts b/src/MapleFE/test/typescript/unit_tests/rest-in-array2.ts new file mode 100644 index 0000000000000000000000000000000000000000..403d8e2af74983e42cea05db5c19c81a392c73da --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-in-array2.ts @@ -0,0 +1,4 @@ +module M { + let arr : Array = ["a", "b"]; + console.log([...arr, "c"]); +} diff --git a/src/MapleFE/test/typescript/unit_tests/rest-in-array2.ts.result b/src/MapleFE/test/typescript/unit_tests/rest-in-array2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f9a4286d2aee7e12ebae0f702b84d0a7b70302b7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-in-array2.ts.result @@ -0,0 +1,9 @@ +Matched 30 tokens. +============= Module =========== +== Sub Tree == +============= Module =========== +== Sub Tree == +js_let Decl: arr=["a","b"] +== Sub Tree == +console.log([...arr,"c"]) + diff --git a/src/MapleFE/test/typescript/unit_tests/rest-object-literal.ts b/src/MapleFE/test/typescript/unit_tests/rest-object-literal.ts new file mode 100644 index 0000000000000000000000000000000000000000..cd6a6ec0ccc71868e1aa2d647bf92d379d32dd91 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-object-literal.ts @@ -0,0 +1,8 @@ +function func(x: T): T { + return x; +} +var list = { f1: 0, f2: 1 }; +class Klass { + public static fd = func({ ...list }); +} +console.log(Klass.fd); diff --git a/src/MapleFE/test/typescript/unit_tests/rest-object-literal.ts.result b/src/MapleFE/test/typescript/unit_tests/rest-object-literal.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b30f75590b39455c4352e517e3555ecd3abfb098 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-object-literal.ts.result @@ -0,0 +1,23 @@ +Matched 17 tokens. +Matched 30 tokens. +Matched 46 tokens. +Matched 55 tokens. +============= Module =========== +== Sub Tree == +func func(x) throws: + return x + +== Sub Tree == +js_var Decl: list= {f1:0, f2:1} +== Sub Tree == +class Klass + Fields: + fd=func( {:...list}) + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +console.log(Klass.fd) diff --git a/src/MapleFE/test/typescript/unit_tests/rest-object-literal2.ts b/src/MapleFE/test/typescript/unit_tests/rest-object-literal2.ts new file mode 100644 index 0000000000000000000000000000000000000000..54f1135ba1b380cffadcb676d275254861bcaa70 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-object-literal2.ts @@ -0,0 +1,6 @@ +class Klass { + list = { f1: 0, f2: 1 }; +} +var obj: Klass = new Klass(); +var list2 = true ? { ...obj.list } : obj.list; +console.log(list2); diff --git a/src/MapleFE/test/typescript/unit_tests/rest-object-literal2.ts.result b/src/MapleFE/test/typescript/unit_tests/rest-object-literal2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..eedd040f94d5af412ce4e590fea6e01f2fd7f553 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-object-literal2.ts.result @@ -0,0 +1,21 @@ +Matched 16 tokens. +Matched 26 tokens. +Matched 42 tokens. +Matched 49 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + list= {f1:0, f2:1} + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +js_var Decl: list2=true ? {:obj.list} : obj.list +== Sub Tree == +console.log(list2) diff --git a/src/MapleFE/test/typescript/unit_tests/rest-object-literal3.ts b/src/MapleFE/test/typescript/unit_tests/rest-object-literal3.ts new file mode 100644 index 0000000000000000000000000000000000000000..b746a03c57b68d454631bd74026d885540c25664 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-object-literal3.ts @@ -0,0 +1,6 @@ +class Klass { + arr = [{ list: { f1: 0, f2: 1 } }]; +} +var obj: Klass = new Klass(); +var list2 = true ? { ...obj.arr[0] } : obj.arr[0].list; +console.log(list2); diff --git a/src/MapleFE/test/typescript/unit_tests/rest-object-literal3.ts.result b/src/MapleFE/test/typescript/unit_tests/rest-object-literal3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..555f965426b909d0ac2d6d29a53d68b160095939 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-object-literal3.ts.result @@ -0,0 +1,21 @@ +Matched 22 tokens. +Matched 32 tokens. +Matched 56 tokens. +Matched 63 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + arr=[ {list: {f1:0, f2:1}}] + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +js_var Decl: list2=true ? {:obj.arr[0]} : obj.arr[0].list +== Sub Tree == +console.log(list2) diff --git a/src/MapleFE/test/typescript/unit_tests/rest-params.ts b/src/MapleFE/test/typescript/unit_tests/rest-params.ts new file mode 100644 index 0000000000000000000000000000000000000000..977851d3b76b9ae7008600072cd4a7e90f7467d7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-params.ts @@ -0,0 +1,5 @@ +function func(msg: string, ...params: any[]) { + console.log(msg, params); +} + +func("Rest: ", 1, 2, 3, "abc", "def"); diff --git a/src/MapleFE/test/typescript/unit_tests/rest-params.ts.result b/src/MapleFE/test/typescript/unit_tests/rest-params.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..41eea9e79e3ce410c5b851e16d0140d2f81f1cc5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/rest-params.ts.result @@ -0,0 +1,9 @@ +Matched 25 tokens. +Matched 40 tokens. +============= Module =========== +== Sub Tree == +func func(msg,...params) throws: + console.log(msg,params) + +== Sub Tree == +func("Rest: ",1,2,3,"abc","def") diff --git a/src/MapleFE/test/typescript/unit_tests/return-as-any.ts b/src/MapleFE/test/typescript/unit_tests/return-as-any.ts new file mode 100644 index 0000000000000000000000000000000000000000..758d806c20e513dd666b5280fe081bd76f7c22e8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/return-as-any.ts @@ -0,0 +1,2 @@ +const func = () => 0 as any; +console.log(func); diff --git a/src/MapleFE/test/typescript/unit_tests/return-as-any.ts.result b/src/MapleFE/test/typescript/unit_tests/return-as-any.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..4e68a8a2716740a6e91fd36a430e406a07884273 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/return-as-any.ts.result @@ -0,0 +1,7 @@ +Matched 10 tokens. +Matched 17 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: func=() -> 0 +== Sub Tree == +console.log(func) diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing.ts new file mode 100644 index 0000000000000000000000000000000000000000..a418f65ca258ae23ba4ca0e9adf74d2621f4e640 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing.ts @@ -0,0 +1,10 @@ +class Klass {} + +export interface Interf { + [key: string]: any; +} + +export interface Interf2 { + func(component: Klass): Interf; + func2(component: Klass): Interf; +} diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8b1f0dd44491b6d303a9c5243986f0117df2c3b3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing.ts.result @@ -0,0 +1,20 @@ +Matched 4 tokens. +Matched 17 tokens. +Matched 40 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +export {ts_interface: Interf {string index type: any }} +== Sub Tree == +export {ts_interface: Interf2 {func func(component) throws: +;func func2(component) throws: + }} diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing10.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing10.ts new file mode 100644 index 0000000000000000000000000000000000000000..88c2e5ad80a6eb91cbd1d00d4eeb60a6333a60e9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing10.ts @@ -0,0 +1,11 @@ +function func(arr: Array): number { + var len = arr.length; + var sum = 0; + while(len > 0) { + len-- + sum += arr[len]; + } + return sum; +} + +console.log(func([1, 2, 3, 4])); diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing10.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing10.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..dca83fd7b5dc81f4341cce66d1d3f8332c48a468 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing10.ts.result @@ -0,0 +1,15 @@ +Matched 46 tokens. +Matched 64 tokens. +============= Module =========== +== Sub Tree == +func func(arr) throws: + js_var Decl: len=arr.length + js_var Decl: sum=0 + while len GT 0 len Dec + + sum AddAssign arr[len] + + return sum + +== Sub Tree == +console.log(func([1,2,3,4])) diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing11.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing11.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d563b22096797e7a6d4aaf7714839dbbc2b700a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing11.ts @@ -0,0 +1,3 @@ +export type Type = + | string + | number diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing11.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing11.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b3595f039db09b7776161fbc660c2ed0fc7ada81 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing11.ts.result @@ -0,0 +1,4 @@ +Matched 8 tokens. +============= Module =========== +== Sub Tree == +export { type Type = union = string | number} diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing12.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing12.ts new file mode 100644 index 0000000000000000000000000000000000000000..08a3a4bbe0c6f7723a75520983fe2d9dda70d20f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing12.ts @@ -0,0 +1,2 @@ +console.log('Hello') +console.log diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing12.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing12.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c499b0516d5c4150e7c79c227737c21af60edb8b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing12.ts.result @@ -0,0 +1,7 @@ +Matched 6 tokens. +Matched 9 tokens. +============= Module =========== +== Sub Tree == +console.log("Hello") +== Sub Tree == +console.log diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing13.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing13.ts new file mode 100644 index 0000000000000000000000000000000000000000..31d304467719e802d76e2cde45fb395b1086a5be --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing13.ts @@ -0,0 +1,2 @@ +console.log +console.log(null) diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing13.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing13.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a2f1cd875bc566c3ab5a97f1cdefe2334ab24e3b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing13.ts.result @@ -0,0 +1,7 @@ +Matched 3 tokens. +Matched 9 tokens. +============= Module =========== +== Sub Tree == +console.log +== Sub Tree == +console.log(null) diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing14.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing14.ts new file mode 100644 index 0000000000000000000000000000000000000000..2311369e565c20dfa593325081aab7dc46b80c02 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing14.ts @@ -0,0 +1,21 @@ +class Car { + private _make: string; + constructor(make: string) { + this._make = make; + } + public getMake(): string { + return this._make; + } +} + +class Model extends Car { + private _model: string; + constructor(make: string, model: string) {super(make) this._model = super.getMake() + model; + } + public getModel(): string { + return this._model; + } +} + +let passat: Model = new Model("VW", "Passat"); +console.log(passat.getMake(), passat.getModel()); diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing14.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing14.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5368fc30da365058f5d1934d73ee3dfecd5b2e61 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing14.ts.result @@ -0,0 +1,38 @@ +Matched 36 tokens. +Matched 88 tokens. +Matched 101 tokens. +Matched 118 tokens. +============= Module =========== +== Sub Tree == +class Car + Fields: + _make + Instance Initializer: + Constructors: + constructor (make) throws: + this._make Assign make + Methods: + func getMake() throws: + return this._make + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Model + Fields: + _model + Instance Initializer: + Constructors: + constructor (make,model) throws: + super(make) + this._model Assign super.getMake() Add model + Methods: + func getModel() throws: + return this._model + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: passat=new Model("VW","Passat") +== Sub Tree == +console.log(passat.getMake(),passat.getModel()) diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing15.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing15.ts new file mode 100644 index 0000000000000000000000000000000000000000..a21a6ce8a1190aa1bc6a8f85e5d85179ee1dbbb8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing15.ts @@ -0,0 +1,16 @@ +var n: number = 1; +switch (true) { + case n < 5: + console.log(n, " is less than 5"); + case n > 2 && n < 5: + console.log(n, " + 1 is equal to", n + 1); + break; + case n == 6: + console.log(n, " is equal to 6"); + break; + case n < 8: + console.log(n, " is greater than 4 and less than 8"); + break + default: + console.log(n, " is greater than 7"); +} diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing15.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing15.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..78c460f980018fd17fd60b48153b7b3b98ca4a9e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing15.ts.result @@ -0,0 +1,8 @@ +Matched 7 tokens. +Matched 93 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: n=1 +== Sub Tree == +A switch + diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing16.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing16.ts new file mode 100644 index 0000000000000000000000000000000000000000..3caad616a659fe6951afcd48192e7063c6a0f87c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing16.ts @@ -0,0 +1,8 @@ +function func(arg: number): number | undefined { + if(arg < 1) return + for(let i = 0; i < arg; i++) + console.log(i); + return arg * 10; +} +console.log(func(3)); + diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing16.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing16.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5a85dd3971104c3fd5b7e648634c0a1e7b0ff316 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing16.ts.result @@ -0,0 +1,15 @@ +Matched 46 tokens. +Matched 56 tokens. +============= Module =========== +== Sub Tree == +func func(arg) throws: + cond-branch cond:arg LT 1 + true branch : + return false branch : + + for ( ) + console.log(i) + return arg Mul 10 + +== Sub Tree == +console.log(func(3)) diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing17.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing17.ts new file mode 100644 index 0000000000000000000000000000000000000000..f5c4aff91fda35a3bfecf34ccd70dfe72cdf7624 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing17.ts @@ -0,0 +1,9 @@ +function func(arg: number): number | undefined { + for(let i = 0; i < arg; i++) { + if(i % 2 > 0) continue + console.log(i); + } + return arg * 10; +} +console.log(func(5)); + diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing17.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing17.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6de52c4b72ce0abb85198d4eeeaf62bc051bb110 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing17.ts.result @@ -0,0 +1,17 @@ +Matched 50 tokens. +Matched 60 tokens. +============= Module =========== +== Sub Tree == +func func(arg) throws: + for ( ) + cond-branch cond:i Mod 2 GT 0 + true branch : + continue: + false branch : + + console.log(i) + + return arg Mul 10 + +== Sub Tree == +console.log(func(5)) diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing2.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing2.ts new file mode 100644 index 0000000000000000000000000000000000000000..99880ccb1eac73c69c9625ca9eb44b5f06691f42 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing2.ts @@ -0,0 +1,5 @@ +export abstract class Klass { + public abstract f1(a: boolean): void; + public abstract f2(a: boolean): void; + public abstract f3(): void; +} diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing2.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..13effeab0dfc010356ebd8f18422ff1e5105af5f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing2.ts.result @@ -0,0 +1,15 @@ +Matched 36 tokens. +============= Module =========== +== Sub Tree == +export {class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + func f1(a) throws: + func f2(a) throws: + func f3() throws: + LocalClasses: + LocalInterfaces: +} diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing3.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing3.ts new file mode 100644 index 0000000000000000000000000000000000000000..426aba5e7a0bbd8a1f28fbbd5878ee92575821f6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing3.ts @@ -0,0 +1,4 @@ +let func = function (n: number): number { + return n; +}; +console.log(func(123)); diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing3.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8aa220a9386b4d42d86b7d616c74e1f6cc36c38a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing3.ts.result @@ -0,0 +1,9 @@ +Matched 17 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: func=func (n) throws: + return n + +== Sub Tree == +console.log(func(123)) diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing4.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing4.ts new file mode 100644 index 0000000000000000000000000000000000000000..e97a274786ba79926076cd2c814ef01bf381b09e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing4.ts @@ -0,0 +1,11 @@ +class Klass { + func?: (n: number) => number; +} +var obj: Klass = new Klass(); +obj.func = function (n: number): number { + return n; +}; + +export function show() { + console.log(obj.func!(123)); +} diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing4.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..75efc0950a5dab815e9838e99d620abbca3e49ff --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing4.ts.result @@ -0,0 +1,25 @@ +Matched 15 tokens. +Matched 25 tokens. +Matched 43 tokens. +Matched 63 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + func? + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj.func Assign func (n) throws: + return n + +== Sub Tree == +export {func show() throws: + console.log(obj.func!(123)) +} diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing5.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing5.ts new file mode 100644 index 0000000000000000000000000000000000000000..c9172d85056a295a43e80f7849f69f8aa1d14f33 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing5.ts @@ -0,0 +1,17 @@ +class Klass { + prop: string = ""; + get getProp(): string { + return this.prop; + } + init(val: string) { + this.prop = val; + } + set setProp(newVal: string) { + this.init(newVal); + } +} + +var obj: Klass = new Klass(); +console.log(obj.getProp); +obj.setProp = "bar"; +console.log(obj.getProp); diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing5.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing5.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..89bf2f9ee60c3a0ce49bf43ff3d95a91d766069c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing5.ts.result @@ -0,0 +1,30 @@ +Matched 53 tokens. +Matched 63 tokens. +Matched 72 tokens. +Matched 78 tokens. +Matched 87 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + prop="" + Instance Initializer: + Constructors: + Methods: + get getProp() throws: + return this.prop + func init(val) throws: + this.prop Assign val + set setProp(newVal) throws: + this.init(newVal) + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +console.log(obj.getProp) +== Sub Tree == +obj.setProp Assign "bar" +== Sub Tree == +console.log(obj.getProp) diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing6.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing6.ts new file mode 100644 index 0000000000000000000000000000000000000000..db3654a5e2d29f83342e24b2627cd03a8f074d5c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing6.ts @@ -0,0 +1,4 @@ +export declare function func(s: string): string | null; +export declare function func2(s: string): string | null; +export declare const re1: RegExp; +export declare const re2: RegExp; diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing6.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing6.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ae1342002187e83e5e53b08ce875ebd74acb167f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing6.ts.result @@ -0,0 +1,15 @@ +Matched 14 tokens. +Matched 28 tokens. +Matched 35 tokens. +Matched 42 tokens. +============= Module =========== +== Sub Tree == +export {declare func func(s) throws: +} +== Sub Tree == +export {declare func func2(s) throws: +} +== Sub Tree == +export {declare js_const Decl: re1} +== Sub Tree == +export {declare js_const Decl: re2} diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing7.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing7.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b33409dbeae625edc38d0e58fe5f6b53043c4fd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing7.ts @@ -0,0 +1,4 @@ +declare namespace NS { + const num: number + interface IFace { } +} diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing7.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing7.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..05a1750950448b03ed5e993826e4d5d394d35d05 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing7.ts.result @@ -0,0 +1,7 @@ +Matched 13 tokens. +============= Module =========== +== Sub Tree == +declare namespace NS + js_const Decl: num + ts_interface: IFace { } + diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing8.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing8.ts new file mode 100644 index 0000000000000000000000000000000000000000..1dbb25e8f5d11d002e2f93fa50404e4e35b707bd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing8.ts @@ -0,0 +1,8 @@ +function func(f: Function): void { + f(); +} + +func((e:any) => { + if (e) throw e + console.log('OK') +}) diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing8.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing8.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ddb68873c2ab84dac90529c3ad1053b9c0c53b00 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing8.ts.result @@ -0,0 +1,15 @@ +Matched 15 tokens. +Matched 38 tokens. +============= Module =========== +== Sub Tree == +func func(f) throws: + f() + +== Sub Tree == +func((e) -> cond-branch cond:e +true branch : + throw e +false branch : + +console.log("OK") +) diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing9.ts b/src/MapleFE/test/typescript/unit_tests/semicolon-missing9.ts new file mode 100644 index 0000000000000000000000000000000000000000..0c3d27d2febe5cc14b4a7467a93fef56731a57ea --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing9.ts @@ -0,0 +1,3 @@ +console.log("hello") +console.log; +console.log("world") diff --git a/src/MapleFE/test/typescript/unit_tests/semicolon-missing9.ts.result b/src/MapleFE/test/typescript/unit_tests/semicolon-missing9.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7106ec4ab1e08bd860ff523ba58da85e5a904ca0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/semicolon-missing9.ts.result @@ -0,0 +1,10 @@ +Matched 6 tokens. +Matched 10 tokens. +Matched 16 tokens. +============= Module =========== +== Sub Tree == +console.log("hello") +== Sub Tree == +console.log +== Sub Tree == +console.log("world") diff --git a/src/MapleFE/test/typescript/unit_tests/shebang.ts b/src/MapleFE/test/typescript/unit_tests/shebang.ts new file mode 100644 index 0000000000000000000000000000000000000000..114bffa6991b2997b4bb27fe419b528762dd4962 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/shebang.ts @@ -0,0 +1,2 @@ +#!/usr/bin/env node +console.log("Hello world!"); diff --git a/src/MapleFE/test/typescript/unit_tests/shebang.ts.result b/src/MapleFE/test/typescript/unit_tests/shebang.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ffe76bce9eb05088e26e69f3499b49ccd80654ba --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/shebang.ts.result @@ -0,0 +1,4 @@ +Matched 7 tokens. +============= Module =========== +== Sub Tree == +console.log("Hello world!") diff --git a/src/MapleFE/test/typescript/unit_tests/some.ts b/src/MapleFE/test/typescript/unit_tests/some.ts new file mode 100644 index 0000000000000000000000000000000000000000..3990a95e2ca6e87beada2fc49f0e7fb76a1c5ec2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/some.ts @@ -0,0 +1,3 @@ +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some +console.log([2, 5, 8, 1, 4].some((x) => x > 10)); // false +console.log([12, 5, 8, 1, 4].some((x) => x > 10)); // true diff --git a/src/MapleFE/test/typescript/unit_tests/some.ts.result b/src/MapleFE/test/typescript/unit_tests/some.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ea756cf94adbc08570cf333fc5a0c4e89c516530 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/some.ts.result @@ -0,0 +1,7 @@ +Matched 28 tokens. +Matched 56 tokens. +============= Module =========== +== Sub Tree == +console.log([2,5,8,1,4].some((x) -> x GT 10)) +== Sub Tree == +console.log([12,5,8,1,4].some((x) -> x GT 10)) diff --git a/src/MapleFE/test/typescript/unit_tests/spread-param.d.ts b/src/MapleFE/test/typescript/unit_tests/spread-param.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..0a2a6bedb2b34d62770a667684e4e1a3994bcfcf --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/spread-param.d.ts @@ -0,0 +1,2 @@ +declare function func( s1: T, s2: T | U, ...ss: Array< T | U | ((e: T | null) => void)>,): T; + diff --git a/src/MapleFE/test/typescript/unit_tests/spread-param.d.ts.result b/src/MapleFE/test/typescript/unit_tests/spread-param.d.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..78d64c1b433ff33b1c4dc7838ced36ace25c6f17 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/spread-param.d.ts.result @@ -0,0 +1,5 @@ +Matched 45 tokens. +============= Module =========== +== Sub Tree == +declare func func(s1,s2,...ss) throws: + diff --git a/src/MapleFE/test/typescript/unit_tests/spread.ts b/src/MapleFE/test/typescript/unit_tests/spread.ts new file mode 100644 index 0000000000000000000000000000000000000000..6f62a3faf38feb28f2aec371f1ca7bb2de8ce8f9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/spread.ts @@ -0,0 +1,9 @@ +const arr: number[] = [1, 2, 3]; +var arr2 = [ 0, ...arr ]; +console.log(arr2); + +function func() { + return { f1: 123, f2: "abc" }; +} +var obj2 = { f0: "OK", ...func() }; +console.log(obj2); diff --git a/src/MapleFE/test/typescript/unit_tests/spread.ts.result b/src/MapleFE/test/typescript/unit_tests/spread.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..99807845e80260e556cfbd48c0a0050d644ce2c6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/spread.ts.result @@ -0,0 +1,21 @@ +Matched 15 tokens. +Matched 25 tokens. +Matched 32 tokens. +Matched 49 tokens. +Matched 63 tokens. +Matched 70 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: arr=[1,2,3] +== Sub Tree == +js_var Decl: arr2=[0,...arr] +== Sub Tree == +console.log(arr2) +== Sub Tree == +func func() throws: + return {f1:123, f2:"abc"} + +== Sub Tree == +js_var Decl: obj2= {f0:"OK", :func()} +== Sub Tree == +console.log(obj2) diff --git a/src/MapleFE/test/typescript/unit_tests/static-readonly.ts b/src/MapleFE/test/typescript/unit_tests/static-readonly.ts new file mode 100644 index 0000000000000000000000000000000000000000..eeaf2b3f5673f100122aa9a28e7f444cb68dc197 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/static-readonly.ts @@ -0,0 +1,3 @@ +class Foo { + static readonly x: number = 0; +} diff --git a/src/MapleFE/test/typescript/unit_tests/static-readonly.ts.result b/src/MapleFE/test/typescript/unit_tests/static-readonly.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..42288272104e2894c17a108a743c00a5f83a4575 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/static-readonly.ts.result @@ -0,0 +1,12 @@ +Matched 12 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + x=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/static.ts b/src/MapleFE/test/typescript/unit_tests/static.ts new file mode 100644 index 0000000000000000000000000000000000000000..fbfac9dfb4f115725ec0f167f42fe079936c6d80 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/static.ts @@ -0,0 +1,9 @@ +class Foo { + static x: number = 1; + static inc(y: number) { + return this.x + y; + } +} + +console.log(Foo.x); +console.log(Foo.inc(10)); diff --git a/src/MapleFE/test/typescript/unit_tests/static.ts.result b/src/MapleFE/test/typescript/unit_tests/static.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3c0381cbd6314dae3720c496e1acdfd9699d1932 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/static.ts.result @@ -0,0 +1,20 @@ +Matched 27 tokens. +Matched 36 tokens. +Matched 48 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + x=1 + Instance Initializer: + Constructors: + Methods: + func inc(y) throws: + return this.x Add y + LocalClasses: + LocalInterfaces: + +== Sub Tree == +console.log(Foo.x) +== Sub Tree == +console.log(Foo.inc(10)) diff --git a/src/MapleFE/test/typescript/unit_tests/string-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/string-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..a1ddbdd1e005b91a095748138ae2fa5c8315a478 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/string-as-prop-name.ts @@ -0,0 +1,6 @@ +interface IFace { + "func-name"() : string; +} + +var obj: IFace = { "func-name": () => "Function name" }; +console.log(obj); diff --git a/src/MapleFE/test/typescript/unit_tests/string-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/string-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..47937f1f5d539a47af772c519227becc30709fa2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/string-as-prop-name.ts.result @@ -0,0 +1,11 @@ +Matched 10 tokens. +Matched 24 tokens. +Matched 31 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {func () throws: + } +== Sub Tree == +js_var Decl: obj= {"func-name":() -> "Function name"} +== Sub Tree == +console.log(obj) diff --git a/src/MapleFE/test/typescript/unit_tests/stringString.ts b/src/MapleFE/test/typescript/unit_tests/stringString.ts new file mode 100644 index 0000000000000000000000000000000000000000..8ce486a185eb399671b0cc6cd0ba72573886a0ba --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/stringString.ts @@ -0,0 +1,6 @@ +class Student { + name: string = ""; +}; +class Parent { + name: String = ""; +}; diff --git a/src/MapleFE/test/typescript/unit_tests/stringString.ts.result b/src/MapleFE/test/typescript/unit_tests/stringString.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..19f19f0de5f7a28448d744781c09d982c18a117d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/stringString.ts.result @@ -0,0 +1,25 @@ +Matched 10 tokens. +Matched 11 tokens. +Matched 21 tokens. +Matched 22 tokens. +============= Module =========== +== Sub Tree == +class Student + Fields: + name="" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Parent + Fields: + name="" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/structural-typing.ts b/src/MapleFE/test/typescript/unit_tests/structural-typing.ts new file mode 100644 index 0000000000000000000000000000000000000000..c1c067e52b792e6d744f48a4e0bbda60c4c76f60 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/structural-typing.ts @@ -0,0 +1,16 @@ +class Foo { + f1: number = 0; + f2: string = ""; +} + +class Bar { + f1: number = 0; + f2: string = ""; +} + +var x = { f1: 123, f2: "John" }; +var y: Foo; +var z: Bar; +y = x; +z = y; +console.log(y, z); diff --git a/src/MapleFE/test/typescript/unit_tests/structural-typing.ts.result b/src/MapleFE/test/typescript/unit_tests/structural-typing.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6ba4006bdf6be05974e90d09b395a3bb1873624b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/structural-typing.ts.result @@ -0,0 +1,41 @@ +Matched 16 tokens. +Matched 32 tokens. +Matched 45 tokens. +Matched 50 tokens. +Matched 55 tokens. +Matched 59 tokens. +Matched 63 tokens. +Matched 72 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + f1=0 f2="" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Bar + Fields: + f1=0 f2="" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: x= {f1:123, f2:"John"} +== Sub Tree == +js_var Decl: y +== Sub Tree == +js_var Decl: z +== Sub Tree == +y Assign x +== Sub Tree == +z Assign y +== Sub Tree == +console.log(y,z) diff --git a/src/MapleFE/test/typescript/unit_tests/switch-in-loop.ts b/src/MapleFE/test/typescript/unit_tests/switch-in-loop.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d2fd8889ec1d233929e172c08f29003bd3a02b9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/switch-in-loop.ts @@ -0,0 +1,19 @@ +for (var i: number = 1; i < 10; ++i) { + if (i < 5) + switch (i) { + case 2: + console.log(i, ", continue"); + continue; + case 3: + console.log(i, ", fall-through"); + case 4: + console.log(i, ", break"); + break; + default: + console.log(i, ", default"); + } + else { + console.log(i, ", else branch"); + break; + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/switch-in-loop.ts.result b/src/MapleFE/test/typescript/unit_tests/switch-in-loop.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2a2cbafd0e41b584a9c38e06861d9dd36b2ab782 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/switch-in-loop.ts.result @@ -0,0 +1,13 @@ +Matched 95 tokens. +============= Module =========== +== Sub Tree == +for ( ) + cond-branch cond:i LT 5 + true branch : + A switch + false branch : + console.log(i,", else branch") + break: + + + diff --git a/src/MapleFE/test/typescript/unit_tests/switch-in-loop2.ts b/src/MapleFE/test/typescript/unit_tests/switch-in-loop2.ts new file mode 100644 index 0000000000000000000000000000000000000000..a569c469f9e35d5954e75aa5769569bd78d7eb8d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/switch-in-loop2.ts @@ -0,0 +1,18 @@ +class Klass { + [key: number]: string; +} +function func() { + var obj: Klass = {}; + for (var i: number = 1; i < 4; ++i) { + switch (i) { + case 2: + break; + default: + obj[i] = "OK"; + break; + } + } + return obj; +} + +console.log(func()); diff --git a/src/MapleFE/test/typescript/unit_tests/switch-in-loop2.ts.result b/src/MapleFE/test/typescript/unit_tests/switch-in-loop2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3d3d8dcc03457c6e80a6696b1ff77224ee97f98e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/switch-in-loop2.ts.result @@ -0,0 +1,25 @@ +Matched 12 tokens. +Matched 69 tokens. +Matched 78 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + string + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func func() throws: + js_var Decl: obj= {} + for ( ) + A switch + + + return obj + +== Sub Tree == +console.log(func()) diff --git a/src/MapleFE/test/typescript/unit_tests/switch-stmt-case.ts b/src/MapleFE/test/typescript/unit_tests/switch-stmt-case.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad2a522153e283538fcb3105740c4c63975625b6 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/switch-stmt-case.ts @@ -0,0 +1,8 @@ +let obj: number = 1; + +switch (typeof obj) { + case "number": + case "string": + console.log(obj); + break; +} diff --git a/src/MapleFE/test/typescript/unit_tests/switch-stmt-case.ts.result b/src/MapleFE/test/typescript/unit_tests/switch-stmt-case.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1595ff943185d42c79f846e64828056b090f69aa --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/switch-stmt-case.ts.result @@ -0,0 +1,8 @@ +Matched 7 tokens. +Matched 29 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: obj=1 +== Sub Tree == +A switch + diff --git a/src/MapleFE/test/typescript/unit_tests/switch-stmt.ts b/src/MapleFE/test/typescript/unit_tests/switch-stmt.ts new file mode 100644 index 0000000000000000000000000000000000000000..51c42c254b34d4cfef490a40e1797b48d57bc89f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/switch-stmt.ts @@ -0,0 +1,16 @@ +var n: number = 1; +switch (true) { + case n < 5: + console.log(n, " is less than 5"); + case n > 2 && n < 5: + console.log(n, " + 1 is equal to", n + 1); + break; + case n == 6: + console.log(n, " is equal to 6"); + break; + case n < 8: + console.log(n, " is greater than 4 and less than 8"); + break; + default: + console.log(n, " is greater than 7"); +} diff --git a/src/MapleFE/test/typescript/unit_tests/switch-stmt.ts.result b/src/MapleFE/test/typescript/unit_tests/switch-stmt.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7f4347709053422b86a49935942a0c76ddf5f791 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/switch-stmt.ts.result @@ -0,0 +1,8 @@ +Matched 7 tokens. +Matched 94 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: n=1 +== Sub Tree == +A switch + diff --git a/src/MapleFE/test/typescript/unit_tests/symbol-as-key.ts b/src/MapleFE/test/typescript/unit_tests/symbol-as-key.ts new file mode 100644 index 0000000000000000000000000000000000000000..dd746c034c05f67221086af6961b8e80be42e597 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/symbol-as-key.ts @@ -0,0 +1,18 @@ +// tsc --target es2015 +const tag: unique symbol = Symbol("my symbol"); +interface IFace { + [tag]?: number; +} + +class Klass implements IFace { + [tag]: number; + s: string = "example"; +} + +var obj: Klass = new Klass(); +obj[tag] = 123; +console.log(obj); +console.log(Symbol.keyFor(tag)); + +const shared: symbol = Symbol.for("shared symbol"); +console.log(Symbol.keyFor(shared)); diff --git a/src/MapleFE/test/typescript/unit_tests/symbol-as-key.ts.result b/src/MapleFE/test/typescript/unit_tests/symbol-as-key.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ad51f89159c1cdc33f5af4558aed683808eccaf0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/symbol-as-key.ts.result @@ -0,0 +1,36 @@ +Matched 11 tokens. +Matched 22 tokens. +Matched 40 tokens. +Matched 50 tokens. +Matched 57 tokens. +Matched 64 tokens. +Matched 76 tokens. +Matched 88 tokens. +Matched 100 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: tag=Symbol("my symbol") +== Sub Tree == +ts_interface: IFace {[tag] : number } +== Sub Tree == +class Klass + Fields: + [tag] : number s="example" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +obj[tag] Assign 123 +== Sub Tree == +console.log(obj) +== Sub Tree == +console.log(Symbol.keyFor(tag)) +== Sub Tree == +js_const Decl: shared=Symbol.for("shared symbol") +== Sub Tree == +console.log(Symbol.keyFor(shared)) diff --git a/src/MapleFE/test/typescript/unit_tests/tagged-template.ts b/src/MapleFE/test/typescript/unit_tests/tagged-template.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa39ee7a152f3e7b23e67a207d2472ac603e490d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/tagged-template.ts @@ -0,0 +1,12 @@ +// Tagged Template Literal +function bar(a: TemplateStringsArray, b:number, c:string) { + return "bar: a=[" + a + "] b=[" + b + "] c=[" + c + "]"; +} +function f() { + let x: number = 10; + let y: string = "abc"; + return bar`PX + ${x}px${y}PX + `; +} +console.log(f()); diff --git a/src/MapleFE/test/typescript/unit_tests/tagged-template.ts.result b/src/MapleFE/test/typescript/unit_tests/tagged-template.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..9d34dab4a01b6db066facfbae2e991c7add09c19 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/tagged-template.ts.result @@ -0,0 +1,18 @@ +Matched 32 tokens. +Matched 56 tokens. +Matched 65 tokens. +Matched 66 tokens. +Matched 67 tokens. +============= Module =========== +== Sub Tree == +func bar(a,b,c) throws: + return "bar: a=[" Add a Add "] b=[" Add b Add "] c=[" Add c Add "]" + +== Sub Tree == +func f() throws: + js_let Decl: x=10 + js_let Decl: y="abc" + return bar() + +== Sub Tree == +console.log(f()) diff --git a/src/MapleFE/test/typescript/unit_tests/template-literal-as-type.ts b/src/MapleFE/test/typescript/unit_tests/template-literal-as-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8f2ece1da5366386c807255c8e160979b11fc42 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literal-as-type.ts @@ -0,0 +1,4 @@ +const X = "X"; +const T: `${typeof X}type` = `${X}type`; +console.log(typeof T); +console.log(T); diff --git a/src/MapleFE/test/typescript/unit_tests/template-literal-as-type.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literal-as-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e209915dffe9b82f8a18836edc7377d1be4210b2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literal-as-type.ts.result @@ -0,0 +1,15 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 20 tokens. +Matched 27 tokens. +Matched 29 tokens. +Matched 30 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: X="X" +== Sub Tree == +js_const Decl: T= template-literal: NULL,X,"type",NULL +== Sub Tree == +console.log( typeof T) +== Sub Tree == +console.log(T) diff --git a/src/MapleFE/test/typescript/unit_tests/template-literal-in.ts b/src/MapleFE/test/typescript/unit_tests/template-literal-in.ts new file mode 100644 index 0000000000000000000000000000000000000000..3cab93dc7dabf5318ed0458a6ab2b9d17bf64ca9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literal-in.ts @@ -0,0 +1,3 @@ +type MyType> = { + [K in`${Extract}`]: B[K] +}; diff --git a/src/MapleFE/test/typescript/unit_tests/template-literal-in.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literal-in.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..da3d29940e4fd9b84cddd9c1b867d564208ebdab --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literal-in.ts.result @@ -0,0 +1,5 @@ +Matched 27 tokens. +Matched 36 tokens. +============= Module =========== +== Sub Tree == + type MyType = {[K in template-literal: NULL,Extract< keyof B,union = string | number>] : B[K] } diff --git a/src/MapleFE/test/typescript/unit_tests/template-literal-infer.ts b/src/MapleFE/test/typescript/unit_tests/template-literal-infer.ts new file mode 100644 index 0000000000000000000000000000000000000000..c94cf4771ce39a9e357cd30219973e68cda9a568 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literal-infer.ts @@ -0,0 +1,11 @@ +// https://github.com/microsoft/TypeScript/pull/40336 +type Split = + string extends S ? string[] : + S extends '' ? [] : + S extends `${infer T}${D}${infer U}` ? [T, ...Split] : + [S]; + +type T40 = Split<'foo', '.'>; // ['foo'] +type T41 = Split<'foo.bar.baz', '.'>; // ['foo', 'bar', 'baz'] +type T42 = Split<'foo.bar', ''>; // ['f', 'o', 'o', '.', 'b', 'a', 'r'] +type T43 = Split; // string[] diff --git a/src/MapleFE/test/typescript/unit_tests/template-literal-infer.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literal-infer.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1798d6ece23d77e6e2dafcba54644f57b0e74d80 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literal-infer.ts.result @@ -0,0 +1,19 @@ +Matched 47 tokens. +Matched 57 tokens. +Matched 67 tokens. +Matched 77 tokens. +Matched 87 tokens. +Matched 89 tokens. +Matched 90 tokens. +Matched 92 tokens. +============= Module =========== +== Sub Tree == + type Split = string extends S ? prim array-TBD : S extends "" ? prim array-TBD : S extends template-literal: NULL, infer T,NULL,D,NULL, infer U ? [ : T , : Split , ] : [ : S , ] +== Sub Tree == + type T40 = Split<"foo","."> +== Sub Tree == + type T41 = Split<"foo.bar.baz","."> +== Sub Tree == + type T42 = Split<"foo.bar",""> +== Sub Tree == + type T43 = Split diff --git a/src/MapleFE/test/typescript/unit_tests/template-literal-type.ts b/src/MapleFE/test/typescript/unit_tests/template-literal-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..073bae7598a49870fb29a75da43f6c479ed99402 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literal-type.ts @@ -0,0 +1,12 @@ +class Num { + neg: boolean = false; + val: number = 0; +} + +function func(v: Num): `${string}n` | `-${string}n` { + return `${v.neg ? '-' : ''}${v.val}n`; +} + +var obj : Num = {neg: true, val: 123}; +console.log(func(obj)); +console.log(typeof func(obj)); diff --git a/src/MapleFE/test/typescript/unit_tests/template-literal-type.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literal-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..70ca48c63fb79ef537785175df99a5d33a80e5f2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literal-type.ts.result @@ -0,0 +1,30 @@ +Matched 16 tokens. +Matched 32 tokens. +Matched 47 tokens. +Matched 57 tokens. +Matched 68 tokens. +Matched 69 tokens. +Matched 70 tokens. +Matched 77 tokens. +Matched 80 tokens. +============= Module =========== +== Sub Tree == +class Num + Fields: + neg=false val=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func func(v) throws: + return template-literal: NULL,v.neg ? "-" : "",NULL,v.val,"n",NULL + +== Sub Tree == +js_var Decl: obj= {neg:true, val:123} +== Sub Tree == +console.log(func(obj)) +== Sub Tree == +console.log( typeof func(obj)) diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals.ts b/src/MapleFE/test/typescript/unit_tests/template-literals.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8a9c9453dcb712fbf151594ac4d09940a7cb93d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals.ts @@ -0,0 +1,7 @@ +// Template Literal +let x = 10; +let y: number = 20; +let Left = `${x}px`; +let Right: string = `${x}px`; +let Top = `${y}px`; +let Bottom: string = `${y}px`; diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literals.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..17888604cec117983ac361103ca68b3ebf8166d2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals.ts.result @@ -0,0 +1,23 @@ +Matched 5 tokens. +Matched 12 tokens. +Matched 17 tokens. +Matched 24 tokens. +Matched 29 tokens. +Matched 36 tokens. +Matched 37 tokens. +Matched 38 tokens. +Matched 39 tokens. +Matched 40 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: x=10 +== Sub Tree == +js_let Decl: y=20 +== Sub Tree == +js_let Decl: Left= template-literal: NULL,x,"px",NULL +== Sub Tree == +js_let Decl: Right= template-literal: NULL,x,"px",NULL +== Sub Tree == +js_let Decl: Top= template-literal: NULL,y,"px",NULL +== Sub Tree == +js_let Decl: Bottom= template-literal: NULL,y,"px",NULL diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals10.ts b/src/MapleFE/test/typescript/unit_tests/template-literals10.ts new file mode 100644 index 0000000000000000000000000000000000000000..03f001540185e855c1b3f0357465a76ff312e734 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals10.ts @@ -0,0 +1,6 @@ +var flag = false; +var a = ".x"; +console.log( + `${`if(typeof ${flag ? "(prop)" : "prop"}!=="object"){` + "o"}${a}=prop;` + + `}` +); diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals10.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literals10.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..959e7eeac8353c83c9073b71840ba10f000c8d13 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals10.ts.result @@ -0,0 +1,13 @@ +Matched 5 tokens. +Matched 10 tokens. +Matched 19 tokens. +Matched 22 tokens. +Matched 23 tokens. +Matched 28 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: flag=false +== Sub Tree == +js_var Decl: a=".x" +== Sub Tree == +console.log( template-literal: NULL, template-literal: "if(typeof ",flag ? "(prop)" : "prop","!=="object"){",NULL Add "o",NULL,a,"=prop;",NULL Add template-literal: "}",NULL) diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals11.ts b/src/MapleFE/test/typescript/unit_tests/template-literals11.ts new file mode 100644 index 0000000000000000000000000000000000000000..723fb535f8673d9c1cc854db4c6df38a90b24340 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals11.ts @@ -0,0 +1,3 @@ +function func(name: string) { + return Function("target", `${"try {\n" + " target."}${name}();\n` + `}`); +} diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals11.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literals11.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ebe9d1b700acf828762510171e4a15bd80e330dd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals11.ts.result @@ -0,0 +1,8 @@ +Matched 19 tokens. +Matched 22 tokens. +Matched 23 tokens. +============= Module =========== +== Sub Tree == +func func(name) throws: + return Function("target", template-literal: NULL,"try {\n" Add " target.",NULL,name,"();\n",NULL Add template-literal: "}",NULL) + diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals2.ts b/src/MapleFE/test/typescript/unit_tests/template-literals2.ts new file mode 100644 index 0000000000000000000000000000000000000000..7945e9ce5bf481797cb1073d68e205309ceb47dd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals2.ts @@ -0,0 +1,5 @@ +// Template Literal +function func(msg: string): string { + return "MSG: " + msg; +} +console.log(`Status: ${func("OK")}`); diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals2.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literals2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5ba2dd8e30834f775d51197b5461a189c6a0b26d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals2.ts.result @@ -0,0 +1,10 @@ +Matched 16 tokens. +Matched 23 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +func func(msg) throws: + return "MSG: " Add msg + +== Sub Tree == +console.log( template-literal: "Status: ",func("OK")) diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals3.ts b/src/MapleFE/test/typescript/unit_tests/template-literals3.ts new file mode 100644 index 0000000000000000000000000000000000000000..aee708bb7fbf93c373981d704ba01a2d52e3d35d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals3.ts @@ -0,0 +1,2 @@ +var x: number = 20; +let Left = `${x}px`; diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals3.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literals3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..4359ca868c85380f840515525338bbceede24871 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals3.ts.result @@ -0,0 +1,8 @@ +Matched 7 tokens. +Matched 12 tokens. +Matched 13 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=20 +== Sub Tree == +js_let Decl: Left= template-literal: NULL,x,"px",NULL diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals4.ts b/src/MapleFE/test/typescript/unit_tests/template-literals4.ts new file mode 100644 index 0000000000000000000000000000000000000000..a04949c7aec8aa1dd36e0700bac24970a469138d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals4.ts @@ -0,0 +1,6 @@ +var x: number = 2; +var y: number = 4; +var z: number = 6; + +let px = `${x + y}px and ${z ? x + z : y + z}px`; +console.log(px); diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals4.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literals4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b90002372ff4582ca9ac1f4293e5daa176bb8401 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals4.ts.result @@ -0,0 +1,18 @@ +Matched 7 tokens. +Matched 14 tokens. +Matched 21 tokens. +Matched 26 tokens. +Matched 33 tokens. +Matched 36 tokens. +Matched 45 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=2 +== Sub Tree == +js_var Decl: y=4 +== Sub Tree == +js_var Decl: z=6 +== Sub Tree == +js_let Decl: px= template-literal: NULL,x Add y,"px and ",z ? x Add z : y Add z,"px",NULL +== Sub Tree == +console.log(px) diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals5.ts b/src/MapleFE/test/typescript/unit_tests/template-literals5.ts new file mode 100644 index 0000000000000000000000000000000000000000..d04070aa091d9388f8d3625a35a328117a60179e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals5.ts @@ -0,0 +1,3 @@ +var x: number = 20; +let Left = `${x}px`; +console.log(Left); diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals5.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literals5.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6ef3205e3dffededef95c6b69605836fc7c6f62e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals5.ts.result @@ -0,0 +1,11 @@ +Matched 7 tokens. +Matched 12 tokens. +Matched 19 tokens. +Matched 20 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=20 +== Sub Tree == +js_let Decl: Left= template-literal: NULL,x,"px",NULL +== Sub Tree == +console.log(Left) diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals6.ts b/src/MapleFE/test/typescript/unit_tests/template-literals6.ts new file mode 100644 index 0000000000000000000000000000000000000000..bd273860a3cfdf95fdb5b3510b11f24db1d267dc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals6.ts @@ -0,0 +1,2 @@ +console.log(`string text line 1 +string text line 2`); diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals6.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literals6.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..217df2d2d9560b9142ef8187de7b7cb1bb76298c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals6.ts.result @@ -0,0 +1,5 @@ +Matched 7 tokens. +============= Module =========== +== Sub Tree == +console.log( template-literal: "string text line 1 +string text line 2",NULL) diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals7.ts b/src/MapleFE/test/typescript/unit_tests/template-literals7.ts new file mode 100644 index 0000000000000000000000000000000000000000..68d7abbd0909d3eac4fa71894b14184edb24740a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals7.ts @@ -0,0 +1,3 @@ +var arr: number[] = [1, 2, 3]; +var s: string = `${arr[0] + 1}/${arr[1] + 1}/${arr[2] + 1}`; +console.log(s); diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals7.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literals7.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b4e72dc0a251032ac79f6856d19450f84da53a25 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals7.ts.result @@ -0,0 +1,13 @@ +Matched 15 tokens. +Matched 22 tokens. +Matched 29 tokens. +Matched 35 tokens. +Matched 41 tokens. +Matched 47 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[1,2,3] +== Sub Tree == +js_var Decl: s= template-literal: NULL,arr[0] Add 1,"/",arr[1] Add 1,"/",arr[2] Add 1 +== Sub Tree == +console.log(s) diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals8.ts b/src/MapleFE/test/typescript/unit_tests/template-literals8.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5dbf4db9cf53febe8cba505acdecf59f4459d32 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals8.ts @@ -0,0 +1,5 @@ +function func() { + return `${{}}`; +} + +console.log(func()); diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals8.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literals8.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6f3e6604c048c3440cee9f6354000a535a841b02 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals8.ts.result @@ -0,0 +1,10 @@ +Matched 9 tokens. +Matched 18 tokens. +Matched 20 tokens. +============= Module =========== +== Sub Tree == +func func() throws: + return template-literal: NULL, {} + +== Sub Tree == +console.log(func()) diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals9.ts b/src/MapleFE/test/typescript/unit_tests/template-literals9.ts new file mode 100644 index 0000000000000000000000000000000000000000..723fb535f8673d9c1cc854db4c6df38a90b24340 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals9.ts @@ -0,0 +1,3 @@ +function func(name: string) { + return Function("target", `${"try {\n" + " target."}${name}();\n` + `}`); +} diff --git a/src/MapleFE/test/typescript/unit_tests/template-literals9.ts.result b/src/MapleFE/test/typescript/unit_tests/template-literals9.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ebe9d1b700acf828762510171e4a15bd80e330dd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/template-literals9.ts.result @@ -0,0 +1,8 @@ +Matched 19 tokens. +Matched 22 tokens. +Matched 23 tokens. +============= Module =========== +== Sub Tree == +func func(name) throws: + return Function("target", template-literal: NULL,"try {\n" Add " target.",NULL,name,"();\n",NULL Add template-literal: "}",NULL) + diff --git a/src/MapleFE/test/typescript/unit_tests/ternary-op-1.ts b/src/MapleFE/test/typescript/unit_tests/ternary-op-1.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8c730a03b379f30c2a94db988402c5af2634c62 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ternary-op-1.ts @@ -0,0 +1,8 @@ +function func(x: number): number { + return (x > 10 ? x : x * x) ? x * 2 : x * 3; +} + +let r = func(12); +console.log(r); +r = func(3); +console.log(r); diff --git a/src/MapleFE/test/typescript/unit_tests/ternary-op-1.ts.result b/src/MapleFE/test/typescript/unit_tests/ternary-op-1.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7890ae20aab32b63d32e01246dcacad6c25ce37d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ternary-op-1.ts.result @@ -0,0 +1,18 @@ +Matched 32 tokens. +Matched 40 tokens. +Matched 47 tokens. +Matched 54 tokens. +Matched 61 tokens. +============= Module =========== +== Sub Tree == +func func(x) throws: + return x GT 10 ? x : x Mul x ? x Mul 2 : x Mul 3 + +== Sub Tree == +js_let Decl: r=func(12) +== Sub Tree == +console.log(r) +== Sub Tree == +r Assign func(3) +== Sub Tree == +console.log(r) diff --git a/src/MapleFE/test/typescript/unit_tests/ternary-op.ts b/src/MapleFE/test/typescript/unit_tests/ternary-op.ts new file mode 100644 index 0000000000000000000000000000000000000000..96a416388641155447c5ac7cce9cc819540216aa --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ternary-op.ts @@ -0,0 +1,8 @@ +function func(x: number): number { + return x > 10 ? x : x * x; +} + +let r = func(12); +console.log(r); +r = func(3); +console.log(r); diff --git a/src/MapleFE/test/typescript/unit_tests/ternary-op.ts.result b/src/MapleFE/test/typescript/unit_tests/ternary-op.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2c97387863fe9be8681cf371febd97e63997442e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ternary-op.ts.result @@ -0,0 +1,18 @@ +Matched 22 tokens. +Matched 30 tokens. +Matched 37 tokens. +Matched 44 tokens. +Matched 51 tokens. +============= Module =========== +== Sub Tree == +func func(x) throws: + return x GT 10 ? x : x Mul x + +== Sub Tree == +js_let Decl: r=func(12) +== Sub Tree == +console.log(r) +== Sub Tree == +r Assign func(3) +== Sub Tree == +console.log(r) diff --git a/src/MapleFE/test/typescript/unit_tests/this-as-any.ts b/src/MapleFE/test/typescript/unit_tests/this-as-any.ts new file mode 100644 index 0000000000000000000000000000000000000000..5eb26e6910a2dba57f7f0a2847cae53661171d29 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/this-as-any.ts @@ -0,0 +1,23 @@ +class Car { + private _make: string; + constructor(make: string) { + this._make = make; + } + public getMake(): string { + return this._make; + } +} + +class Model extends Car { + private _model?: string; + constructor(make: string, model: string) { + super(make); + (this as any)._model = model; + } + public getModel(): string { + return this._model!; + } +} + +let passat: Model = new Model("VW", "Passat"); +console.log(passat.getMake(), passat.getModel()); diff --git a/src/MapleFE/test/typescript/unit_tests/this-as-any.ts.result b/src/MapleFE/test/typescript/unit_tests/this-as-any.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..948cd8e6b5e2334da5cf0f8bf4b014c2e07cd41d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/this-as-any.ts.result @@ -0,0 +1,38 @@ +Matched 36 tokens. +Matched 89 tokens. +Matched 102 tokens. +Matched 119 tokens. +============= Module =========== +== Sub Tree == +class Car + Fields: + _make + Instance Initializer: + Constructors: + constructor (make) throws: + this._make Assign make + Methods: + func getMake() throws: + return this._make + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Model + Fields: + _model? + Instance Initializer: + Constructors: + constructor (make,model) throws: + super(make) + this._model Assign model + Methods: + func getModel() throws: + return this._model! + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: passat=new Model("VW","Passat") +== Sub Tree == +console.log(passat.getMake(),passat.getModel()) diff --git a/src/MapleFE/test/typescript/unit_tests/this-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/this-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..8e35935ccc41c875c6d85539a7476d87692ea293 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/this-as-prop-name.ts @@ -0,0 +1,7 @@ +interface IFace { + this: Object; +}; + +var obj: IFace = { this: {name: "Name"} }; +console.log(obj); +console.log(obj["this"]); diff --git a/src/MapleFE/test/typescript/unit_tests/this-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/this-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..cf25f818b82006fb4e16b6dc769cedd2d8c78590 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/this-as-prop-name.ts.result @@ -0,0 +1,14 @@ +Matched 8 tokens. +Matched 9 tokens. +Matched 24 tokens. +Matched 31 tokens. +Matched 41 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {this } +== Sub Tree == +js_var Decl: obj= {this: {name:"Name"}} +== Sub Tree == +console.log(obj) +== Sub Tree == +console.log(obj["this"]) diff --git a/src/MapleFE/test/typescript/unit_tests/this-parameter.ts b/src/MapleFE/test/typescript/unit_tests/this-parameter.ts new file mode 100644 index 0000000000000000000000000000000000000000..909c2a101c0ce74fd7e57827a893d14b6f7f658b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/this-parameter.ts @@ -0,0 +1,26 @@ +class Klass { + [key: string]: Function | number; +} + +var func = (obj: Klass) => { + const desc = Object.getOwnPropertyDescriptor(obj, "f"); + console.log(desc); + if (typeof desc!.value === "function") { + const v = desc!.value; + obj["f"] = function (this) { + console.log("Calling the new function"); + return v.call(this, ...arguments); + }; + } +}; + +var o = { + n: 123, + f: function () { + console.log("Calling f()"); + return this; + }, +}; + +func(o); +console.log(o.f()); diff --git a/src/MapleFE/test/typescript/unit_tests/this-parameter.ts.result b/src/MapleFE/test/typescript/unit_tests/this-parameter.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..397e70c685d2143e702fd7d88f347e71ef5909c5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/this-parameter.ts.result @@ -0,0 +1,38 @@ +Matched 14 tokens. +Matched 95 tokens. +Matched 123 tokens. +Matched 128 tokens. +Matched 139 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + union = Function | number + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: func=(obj) -> js_const Decl: desc=Object.getOwnPropertyDescriptor(obj,"f") +console.log(desc) +cond-branch cond: typeof desc!.value StEq "function" +true branch : + js_const Decl: v=desc!.value + obj["f"] Assign func (this) throws: + console.log("Calling the new function") + return v.call(this,...arguments) + +false branch : + + +== Sub Tree == +js_var Decl: o= {n:123, f:func () throws: + console.log("Calling f()") + return this +} +== Sub Tree == +func(o) +== Sub Tree == +console.log(o.f()) diff --git a/src/MapleFE/test/typescript/unit_tests/three-dim-array.ts b/src/MapleFE/test/typescript/unit_tests/three-dim-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..ef80ea4042f85508a7f9b4a9d42848bf60caa227 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/three-dim-array.ts @@ -0,0 +1,6 @@ +class Klass { + n: number[][][] = [[[3]]]; +} + +var c = new Klass(); +console.log(c); diff --git a/src/MapleFE/test/typescript/unit_tests/three-dim-array.ts.result b/src/MapleFE/test/typescript/unit_tests/three-dim-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..2091e6f5a3cdd08dd9b15e1b7018b250c0cae068 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/three-dim-array.ts.result @@ -0,0 +1,18 @@ +Matched 22 tokens. +Matched 30 tokens. +Matched 37 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + n=[[[3]]] + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: c=new Klass() +== Sub Tree == +console.log(c) diff --git a/src/MapleFE/test/typescript/unit_tests/ti_call.ts b/src/MapleFE/test/typescript/unit_tests/ti_call.ts new file mode 100644 index 0000000000000000000000000000000000000000..c4f2d88d11bbae6e7bbcea747deae6495996f5ac --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ti_call.ts @@ -0,0 +1,5 @@ +function bar(value: number): number { + return value; +} + +bar(13); diff --git a/src/MapleFE/test/typescript/unit_tests/ti_call.ts.result b/src/MapleFE/test/typescript/unit_tests/ti_call.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7c335d8840e91417f3ba2277d8b755c650768431 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ti_call.ts.result @@ -0,0 +1,9 @@ +Matched 14 tokens. +Matched 19 tokens. +============= Module =========== +== Sub Tree == +func bar(value) throws: + return value + +== Sub Tree == +bar(13) diff --git a/src/MapleFE/test/typescript/unit_tests/ti_call2.ts b/src/MapleFE/test/typescript/unit_tests/ti_call2.ts new file mode 100644 index 0000000000000000000000000000000000000000..61245bfe40820426ebbf6e88e1be5d27b62123f2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ti_call2.ts @@ -0,0 +1,6 @@ +function bar(value: number): number { + return value; +} + +bar(13); +bar(13.9); diff --git a/src/MapleFE/test/typescript/unit_tests/ti_call2.ts.result b/src/MapleFE/test/typescript/unit_tests/ti_call2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e07fd001e55edc36c077d8cdb6082de6a70e0040 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ti_call2.ts.result @@ -0,0 +1,12 @@ +Matched 14 tokens. +Matched 19 tokens. +Matched 24 tokens. +============= Module =========== +== Sub Tree == +func bar(value) throws: + return value + +== Sub Tree == +bar(13) +== Sub Tree == +bar(13.9) diff --git a/src/MapleFE/test/typescript/unit_tests/ti_call_array.ts b/src/MapleFE/test/typescript/unit_tests/ti_call_array.ts new file mode 100644 index 0000000000000000000000000000000000000000..099c7511c64003dd5cae9c4db22ff849da00fc7a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ti_call_array.ts @@ -0,0 +1,6 @@ +function foo(array: number[], value: number): number { + return 0; +} + +var arr: number[] = [13, 21]; +foo(arr, 13); diff --git a/src/MapleFE/test/typescript/unit_tests/ti_call_array.ts.result b/src/MapleFE/test/typescript/unit_tests/ti_call_array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3d9b30e817b14a4dd300e064b91cc5b543403e76 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ti_call_array.ts.result @@ -0,0 +1,12 @@ +Matched 20 tokens. +Matched 33 tokens. +Matched 40 tokens. +============= Module =========== +== Sub Tree == +func foo(array,value) throws: + return 0 + +== Sub Tree == +js_var Decl: arr=[13,21] +== Sub Tree == +foo(arr,13) diff --git a/src/MapleFE/test/typescript/unit_tests/ti_call_array2.ts b/src/MapleFE/test/typescript/unit_tests/ti_call_array2.ts new file mode 100644 index 0000000000000000000000000000000000000000..7be49ffe3f4975c94b9d08253a84b337e6fb8c20 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ti_call_array2.ts @@ -0,0 +1,8 @@ +function foo(array: number[], value: number): number { + return 0; +} + +var arr: number[] = [13, 21]; +foo(arr, 13); +var arrf: number[] = [13.5, 21.5]; +foo(arrf, 13.5); diff --git a/src/MapleFE/test/typescript/unit_tests/ti_call_array2.ts.result b/src/MapleFE/test/typescript/unit_tests/ti_call_array2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..21a6c20b1bd8626041366302837a0538123acfcc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ti_call_array2.ts.result @@ -0,0 +1,18 @@ +Matched 20 tokens. +Matched 33 tokens. +Matched 40 tokens. +Matched 53 tokens. +Matched 60 tokens. +============= Module =========== +== Sub Tree == +func foo(array,value) throws: + return 0 + +== Sub Tree == +js_var Decl: arr=[13,21] +== Sub Tree == +foo(arr,13) +== Sub Tree == +js_var Decl: arrf=[13.5,21.5] +== Sub Tree == +foo(arrf,13.5) diff --git a/src/MapleFE/test/typescript/unit_tests/ti_export_func.ts b/src/MapleFE/test/typescript/unit_tests/ti_export_func.ts new file mode 100644 index 0000000000000000000000000000000000000000..c5de99ce61e765984fc2646a2c084eb56f3cabb1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ti_export_func.ts @@ -0,0 +1,5 @@ +export function bar(value: number): number { + return value; +} + +bar(13); diff --git a/src/MapleFE/test/typescript/unit_tests/ti_export_func.ts.result b/src/MapleFE/test/typescript/unit_tests/ti_export_func.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8cad8e66135ff3ac57ead29d7e64239c9e3d9603 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ti_export_func.ts.result @@ -0,0 +1,9 @@ +Matched 15 tokens. +Matched 20 tokens. +============= Module =========== +== Sub Tree == +export {func bar(value) throws: + return value +} +== Sub Tree == +bar(13) diff --git a/src/MapleFE/test/typescript/unit_tests/trailing-commas.ts b/src/MapleFE/test/typescript/unit_tests/trailing-commas.ts new file mode 100644 index 0000000000000000000000000000000000000000..aea4967b6dbb44b774e9d60d13cfe4fc47f6af46 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/trailing-commas.ts @@ -0,0 +1,15 @@ +export { a, o, func, u as U, v as V }; + +var a: number[] = [1, 2, 3]; +console.log(a.length); + +var o: Object = { x: 1, y: "abc" }; +console.log(o); + +function func(n: number): number { + return n * n; +} +console.log(func(10)); + +var [u, v] = a; +console.log(u, v); diff --git a/src/MapleFE/test/typescript/unit_tests/trailing-commas.ts.result b/src/MapleFE/test/typescript/unit_tests/trailing-commas.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..019848c0dd0af7b13854c195a814aa40e67ba0b0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/trailing-commas.ts.result @@ -0,0 +1,30 @@ +Matched 17 tokens. +Matched 32 tokens. +Matched 41 tokens. +Matched 56 tokens. +Matched 63 tokens. +Matched 79 tokens. +Matched 89 tokens. +Matched 98 tokens. +Matched 107 tokens. +============= Module =========== +== Sub Tree == +export {a,o,func,u as U,v as V} +== Sub Tree == +js_var Decl: a=[1,2,3] +== Sub Tree == +console.log(a.length) +== Sub Tree == +js_var Decl: o= {x:1, y:"abc"} +== Sub Tree == +console.log(o) +== Sub Tree == +func func(n) throws: + return n Mul n + +== Sub Tree == +console.log(func(10)) +== Sub Tree == +js_var Decl: {:u, :v} +== Sub Tree == +console.log(u,v) diff --git a/src/MapleFE/test/typescript/unit_tests/trailing-commas2.ts b/src/MapleFE/test/typescript/unit_tests/trailing-commas2.ts new file mode 100644 index 0000000000000000000000000000000000000000..6003c285d2efcf74774e250b16a847c43f8a44e3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/trailing-commas2.ts @@ -0,0 +1,9 @@ +class Klass { + n: T | undefined = undefined; +} + +function func(x = 0.5, y: Klass = { n: 3 }): number { + return x + y.n!; +} + +console.log(func()); diff --git a/src/MapleFE/test/typescript/unit_tests/trailing-commas2.ts.result b/src/MapleFE/test/typescript/unit_tests/trailing-commas2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..905afb4210f3344d535611006e77fc03ebd62cd7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/trailing-commas2.ts.result @@ -0,0 +1,20 @@ +Matched 15 tokens. +Matched 47 tokens. +Matched 56 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + n=undefined + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func func(x=0.5,y= {n:3}) throws: + return x Add y.n! + +== Sub Tree == +console.log(func()) diff --git a/src/MapleFE/test/typescript/unit_tests/trailing-commas3.ts b/src/MapleFE/test/typescript/unit_tests/trailing-commas3.ts new file mode 100644 index 0000000000000000000000000000000000000000..b84579b57c617df71bc019a5a80481b049da4a63 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/trailing-commas3.ts @@ -0,0 +1,7 @@ +class Klass {} +function func(m?: Klass | number) { + return m; +} + +var obj: Klass = new Klass(); +console.log(func(obj)); diff --git a/src/MapleFE/test/typescript/unit_tests/trailing-commas3.ts.result b/src/MapleFE/test/typescript/unit_tests/trailing-commas3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..78af9b55080e024e39e4490864f098e0c3f8efd9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/trailing-commas3.ts.result @@ -0,0 +1,23 @@ +Matched 4 tokens. +Matched 19 tokens. +Matched 29 tokens. +Matched 39 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func func(m?) throws: + return m + +== Sub Tree == +js_var Decl: obj=new Klass() +== Sub Tree == +console.log(func(obj)) diff --git a/src/MapleFE/test/typescript/unit_tests/trailing-commas4.ts b/src/MapleFE/test/typescript/unit_tests/trailing-commas4.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf7481284cabbd766f05027ed46f64236855227b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/trailing-commas4.ts @@ -0,0 +1,7 @@ +var obj = { + x: false, +}; +var obj2 = { + x: false, +}; +console.log(obj, obj2); diff --git a/src/MapleFE/test/typescript/unit_tests/trailing-commas4.ts.result b/src/MapleFE/test/typescript/unit_tests/trailing-commas4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0c861a083e6c5d23c4eb4c1961677354017873bb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/trailing-commas4.ts.result @@ -0,0 +1,10 @@ +Matched 10 tokens. +Matched 20 tokens. +Matched 29 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: obj= {x:false} +== Sub Tree == +js_var Decl: obj2= {x:false} +== Sub Tree == +console.log(obj,obj2) diff --git a/src/MapleFE/test/typescript/unit_tests/triple-slash-comment.ts b/src/MapleFE/test/typescript/unit_tests/triple-slash-comment.ts new file mode 100644 index 0000000000000000000000000000000000000000..29e5a31ca3b3a3ba94f49fbc89206d3bd06ec68c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/triple-slash-comment.ts @@ -0,0 +1,10 @@ +enum ET { + TOP = "top", /// < top string + BOTTOM = "bottom", ///< bottom string +} + +/// +/// + +let et = ET.TOP; +console.log(et); diff --git a/src/MapleFE/test/typescript/unit_tests/triple-slash-comment.ts.result b/src/MapleFE/test/typescript/unit_tests/triple-slash-comment.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e4afff30c02415e10dfeab2420a63675b1286d5d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/triple-slash-comment.ts.result @@ -0,0 +1,10 @@ +Matched 12 tokens. +Matched 19 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +ts_enum: ET {TOP="top";BOTTOM="bottom" } +== Sub Tree == +js_let Decl: et=ET.TOP +== Sub Tree == +console.log(et) diff --git a/src/MapleFE/test/typescript/unit_tests/triple-slash-dir.d.ts b/src/MapleFE/test/typescript/unit_tests/triple-slash-dir.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..c083b3bd4df8491a83d938882dca65783f30fa18 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/triple-slash-dir.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/src/MapleFE/test/typescript/unit_tests/triple-slash-dir.d.ts.result b/src/MapleFE/test/typescript/unit_tests/triple-slash-dir.d.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0e74c743cd4c0c3b70270bc58d388ad13603002f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/triple-slash-dir.d.ts.result @@ -0,0 +1,7 @@ +Matched 8 tokens. +Matched 16 tokens. +============= Module =========== +== Sub Tree == +trip-slash reference no-default-lib = "true" +== Sub Tree == +trip-slash reference lib = "es5" diff --git a/src/MapleFE/test/typescript/unit_tests/try-catch.ts b/src/MapleFE/test/typescript/unit_tests/try-catch.ts new file mode 100644 index 0000000000000000000000000000000000000000..25c2b3928a413450936c5b1e2ee40933c7d0a07f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/try-catch.ts @@ -0,0 +1,10 @@ +for (var i = 3; i >= 0; --i) { + try { + if (i == 0) throw new Error("Zero"); + console.log("try", 3 / i); + } catch (err) { + console.log("catch", err); + } finally { + console.log("finally", i); + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/try-catch.ts.result b/src/MapleFE/test/typescript/unit_tests/try-catch.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..619a4107820fac62047cc6d3f43f2881d4552701 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/try-catch.ts.result @@ -0,0 +1,14 @@ +Matched 70 tokens. +============= Module =========== +== Sub Tree == +for ( ) + try cond-branch cond:i EQ 0 + true branch : + throw new Error("Zero") + false branch : + + console.log("try",3 Div i) + catch() console.log("catch",err) + finally console.log("finally",i) + + diff --git a/src/MapleFE/test/typescript/unit_tests/try-catch2.ts b/src/MapleFE/test/typescript/unit_tests/try-catch2.ts new file mode 100644 index 0000000000000000000000000000000000000000..8e1f52c7ac07882bd5d0c33f2110ce5974cdcfd9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/try-catch2.ts @@ -0,0 +1,17 @@ +class Klass { + str: string = "no"; +} +function func(obj: Klass) { + if (obj.str === "yes") { + return obj; + } else { + try { + throw "Exception"; + } catch (e: unknown) { + console.log(e); + return obj; + } + } +} + +console.log(func(new Klass())); diff --git a/src/MapleFE/test/typescript/unit_tests/try-catch2.ts.result b/src/MapleFE/test/typescript/unit_tests/try-catch2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7ba89ee85c6afd8dba50bf6aca8355ccc46ff421 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/try-catch2.ts.result @@ -0,0 +1,29 @@ +Matched 10 tokens. +Matched 59 tokens. +Matched 72 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + str="no" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +func func(obj) throws: + cond-branch cond:obj.str StEq "yes" + true branch : + return obj + false branch : + try throw "Exception" + + catch() console.log(e) + return obj + + + +== Sub Tree == +console.log(func(new Klass())) diff --git a/src/MapleFE/test/typescript/unit_tests/try-catch3.ts b/src/MapleFE/test/typescript/unit_tests/try-catch3.ts new file mode 100644 index 0000000000000000000000000000000000000000..a2e76318bc62f93506435685ac50fa02826aa276 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/try-catch3.ts @@ -0,0 +1,7 @@ +for (var i = 3; i >= 0; --i) { + try { + if (i == 0) throw new Error("Zero"); + console.log("try", 3 / i); + } catch { + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/try-catch3.ts.result b/src/MapleFE/test/typescript/unit_tests/try-catch3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..49ac9127a4893cb5c77f4947eb002ba7c50f5785 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/try-catch3.ts.result @@ -0,0 +1,12 @@ +Matched 46 tokens. +============= Module =========== +== Sub Tree == +for ( ) + try cond-branch cond:i EQ 0 + true branch : + throw new Error("Zero") + false branch : + + console.log("try",3 Div i) + catch() + diff --git a/src/MapleFE/test/typescript/unit_tests/ts-maplike.d.ts b/src/MapleFE/test/typescript/unit_tests/ts-maplike.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..7b447e47157c5e18fc2d28050d07616f9ec8c827 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ts-maplike.d.ts @@ -0,0 +1 @@ +export declare const map: (m: import("./export-interface").MapLike) => string; diff --git a/src/MapleFE/test/typescript/unit_tests/ts-maplike.d.ts.result b/src/MapleFE/test/typescript/unit_tests/ts-maplike.d.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..d25ca12a57a2ebd394b583994396179135a9cd52 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/ts-maplike.d.ts.result @@ -0,0 +1,4 @@ +Matched 23 tokens. +============= Module =========== +== Sub Tree == +export {declare js_const Decl: map} diff --git a/src/MapleFE/test/typescript/unit_tests/tuple-type.ts b/src/MapleFE/test/typescript/unit_tests/tuple-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..1dbec1d7edc0790d2253797478554d7615fdea60 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/tuple-type.ts @@ -0,0 +1,6 @@ +function func(t: Function | [Function] | any): string { + return typeof t; +} + +var f: Function = func; +console.log(func(f)); diff --git a/src/MapleFE/test/typescript/unit_tests/tuple-type.ts.result b/src/MapleFE/test/typescript/unit_tests/tuple-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f3c4b75bb345ff34d1017b1f23a3b0c98465722f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/tuple-type.ts.result @@ -0,0 +1,12 @@ +Matched 21 tokens. +Matched 28 tokens. +Matched 38 tokens. +============= Module =========== +== Sub Tree == +func func(t) throws: + return typeof t + +== Sub Tree == +js_var Decl: f=func +== Sub Tree == +console.log(func(f)) diff --git a/src/MapleFE/test/typescript/unit_tests/tuple-type2.ts b/src/MapleFE/test/typescript/unit_tests/tuple-type2.ts new file mode 100644 index 0000000000000000000000000000000000000000..ccbb98b125039c8b6efef21c98a39d20177d0240 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/tuple-type2.ts @@ -0,0 +1,2 @@ +const x: Record = {}; +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/tuple-type2.ts.result b/src/MapleFE/test/typescript/unit_tests/tuple-type2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6ca8e406818f231dad3ad132cac6e2e21bd3fa0b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/tuple-type2.ts.result @@ -0,0 +1,7 @@ +Matched 17 tokens. +Matched 24 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: x= {} +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/two-dim-array.ts b/src/MapleFE/test/typescript/unit_tests/two-dim-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..b89e718d091878d176728582eec14bed4a5a9b7c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/two-dim-array.ts @@ -0,0 +1,7 @@ +var arr: number[][] = [ + [1, 2, 3], + [4, 5, 6], +]; +console.log(arr[0][1]); +console.log(arr[1][0]); +console.log(arr); diff --git a/src/MapleFE/test/typescript/unit_tests/two-dim-array.ts.result b/src/MapleFE/test/typescript/unit_tests/two-dim-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e0f27cff73934a255016676bb7cdc43fc69dab19 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/two-dim-array.ts.result @@ -0,0 +1,13 @@ +Matched 28 tokens. +Matched 41 tokens. +Matched 54 tokens. +Matched 61 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: arr=[[1,2,3],[4,5,6]] +== Sub Tree == +console.log(arr[0][1]) +== Sub Tree == +console.log(arr[1][0]) +== Sub Tree == +console.log(arr) diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias.ts b/src/MapleFE/test/typescript/unit_tests/type-alias.ts new file mode 100644 index 0000000000000000000000000000000000000000..d632a4656fad6d9f448fd3cad8539deb4385888a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias.ts @@ -0,0 +1,7 @@ +type Foo = { name: "foo" }; +type Bar = { name: "bar" }; +type Tee = Foo | Bar; + +var f: Tee = { name: "foo" }; +var b: Tee = { name: "bar" }; +console.log(f, b); diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias.ts.result b/src/MapleFE/test/typescript/unit_tests/type-alias.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3c1b4194ed51d235c91a2ebb14423e508a751671 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias.ts.result @@ -0,0 +1,19 @@ +Matched 9 tokens. +Matched 18 tokens. +Matched 25 tokens. +Matched 36 tokens. +Matched 47 tokens. +Matched 56 tokens. +============= Module =========== +== Sub Tree == + type Foo = {name } +== Sub Tree == + type Bar = {name } +== Sub Tree == + type Tee = union = Foo | Bar +== Sub Tree == +js_var Decl: f= {name:"foo"} +== Sub Tree == +js_var Decl: b= {name:"bar"} +== Sub Tree == +console.log(f,b) diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias2.ts b/src/MapleFE/test/typescript/unit_tests/type-alias2.ts new file mode 100644 index 0000000000000000000000000000000000000000..1111d0624f8bc92dfa03036c33c4ddef2ffacf75 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias2.ts @@ -0,0 +1,4 @@ +type UT = { + base: T; + ext: T extends ReadonlyArray ? UT : T; +}[I extends -1 ? "base" : "ext"]; diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias2.ts.result b/src/MapleFE/test/typescript/unit_tests/type-alias2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3f929a59f616245895ca6fe1737ccab5d9c0c277 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias2.ts.result @@ -0,0 +1,4 @@ +Matched 56 tokens. +============= Module =========== +== Sub Tree == + type UT = {base;ext }[I extends -1 ? "base" : "ext"] diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias3.ts b/src/MapleFE/test/typescript/unit_tests/type-alias3.ts new file mode 100644 index 0000000000000000000000000000000000000000..0dd747577fcbda545425b5f5102f2a4a926eeaf2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias3.ts @@ -0,0 +1,8 @@ +type Default = "default"; +type DefaultUnknown = "unknown"; + +type MyType = { + [K: string]: typeof K extends Default ? string : + typeof K extends DefaultUnknown ? unknown : never +}; + diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias3.ts.result b/src/MapleFE/test/typescript/unit_tests/type-alias3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b0d79f9a442e6c4dec640eac1b53bfc9a762a5d4 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias3.ts.result @@ -0,0 +1,10 @@ +Matched 5 tokens. +Matched 10 tokens. +Matched 37 tokens. +============= Module =========== +== Sub Tree == + type Default = "default" +== Sub Tree == + type DefaultUnknown = "unknown" +== Sub Tree == + type MyType = {string index type: typeof K extends Default ? string : typeof K extends DefaultUnknown ? unknown : never } diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias4.ts b/src/MapleFE/test/typescript/unit_tests/type-alias4.ts new file mode 100644 index 0000000000000000000000000000000000000000..98d356dc0ee7449aaa685389e05929284ee0cefc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias4.ts @@ -0,0 +1,2 @@ +type MyType = T extends string ? T : string; +type UT = MyType extends string ? string : number; diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias4.ts.result b/src/MapleFE/test/typescript/unit_tests/type-alias4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..d4a6dbad714c0183de803f17d3e2eb3135e4b5d8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias4.ts.result @@ -0,0 +1,7 @@ +Matched 14 tokens. +Matched 31 tokens. +============= Module =========== +== Sub Tree == + type MyType = T extends string ? T : string +== Sub Tree == + type UT = MyType extends string ? string : number diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias5.ts b/src/MapleFE/test/typescript/unit_tests/type-alias5.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d5a7e8727089856075d67170b4b96036690995b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias5.ts @@ -0,0 +1 @@ +type U = T extends unknown ? unknown extends T ? T extends true ? true : false : false : false; diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias5.ts.result b/src/MapleFE/test/typescript/unit_tests/type-alias5.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5541ed585ab913028dc7444372a12fae127dce32 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias5.ts.result @@ -0,0 +1,4 @@ +Matched 26 tokens. +============= Module =========== +== Sub Tree == + type U = T extends unknown ? unknown extends T ? T extends true ? true : false : false : false diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias6.ts b/src/MapleFE/test/typescript/unit_tests/type-alias6.ts new file mode 100644 index 0000000000000000000000000000000000000000..0dbe94b9a61ff87efe7c7def6a28ff46a693b517 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias6.ts @@ -0,0 +1,3 @@ +type RemoveFirstType = + T['length'] extends 0 ? undefined : + (((...b: T) => void) extends (a: any, ...b: infer I) => void ? I : []) diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias6.ts.result b/src/MapleFE/test/typescript/unit_tests/type-alias6.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..d0bda51d72b5ecc93698426cf5fd96c8f36235f5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias6.ts.result @@ -0,0 +1,4 @@ +Matched 50 tokens. +============= Module =========== +== Sub Tree == + type RemoveFirstType = T["length"] extends 0 ? undefined : (b) -> extends (a,b) -> ? I : prim array-TBD diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias7.ts b/src/MapleFE/test/typescript/unit_tests/type-alias7.ts new file mode 100644 index 0000000000000000000000000000000000000000..c1ea47795e0e05bc6074a897d1cac15f05df0a51 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias7.ts @@ -0,0 +1,6 @@ +class Klass { + value: number = 0; + key: string = ""; +} + +type MyType= Array>; diff --git a/src/MapleFE/test/typescript/unit_tests/type-alias7.ts.result b/src/MapleFE/test/typescript/unit_tests/type-alias7.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..20e1da6916ecde0509ef457e5cb217444e5dd219 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-alias7.ts.result @@ -0,0 +1,15 @@ +Matched 16 tokens. +Matched 31 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + value=0 key="" + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == + type MyType = Array> diff --git a/src/MapleFE/test/typescript/unit_tests/type-assertion-as.ts b/src/MapleFE/test/typescript/unit_tests/type-assertion-as.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d35b9c66907e1e9935c79e0e180fdff24bff1d8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-assertion-as.ts @@ -0,0 +1,2 @@ +let code: any = 123; +let employeeCode = code as number; diff --git a/src/MapleFE/test/typescript/unit_tests/type-assertion-as.ts.result b/src/MapleFE/test/typescript/unit_tests/type-assertion-as.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..83ded8c5176f2f819c11eb07f6731688b3aa1fee --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-assertion-as.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 14 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: code=123 +== Sub Tree == +js_let Decl: employeeCode=code diff --git a/src/MapleFE/test/typescript/unit_tests/type-assertion-as2.ts b/src/MapleFE/test/typescript/unit_tests/type-assertion-as2.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e585d7121f97f6462f9097dfc3096aafcebbb5f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-assertion-as2.ts @@ -0,0 +1,6 @@ +function func(e: T) : Array { + return [e]; +} +function foo(arg: any) { + return func(arg)[0] as T; +} diff --git a/src/MapleFE/test/typescript/unit_tests/type-assertion-as2.ts.result b/src/MapleFE/test/typescript/unit_tests/type-assertion-as2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8a4fb1dbd6372aeaf04f7e7c1ec3ef0faf3ede99 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-assertion-as2.ts.result @@ -0,0 +1,11 @@ +Matched 22 tokens. +Matched 48 tokens. +============= Module =========== +== Sub Tree == +func func(e) throws: + return [e] + +== Sub Tree == +func foo(arg) throws: + return func(arg)[0] + diff --git a/src/MapleFE/test/typescript/unit_tests/type-assertion-retval.ts b/src/MapleFE/test/typescript/unit_tests/type-assertion-retval.ts new file mode 100644 index 0000000000000000000000000000000000000000..7e94c7c6c291de0b644044d7a6f185b778835176 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-assertion-retval.ts @@ -0,0 +1,7 @@ +class Foo { + public func() { + return 10; + } +} +let obj = new Foo(); +let employeeCode = obj.func() as number; diff --git a/src/MapleFE/test/typescript/unit_tests/type-assertion-retval.ts.result b/src/MapleFE/test/typescript/unit_tests/type-assertion-retval.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ba9e0c2d31c761e58b928187bef6ea8ce49b6077 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-assertion-retval.ts.result @@ -0,0 +1,20 @@ +Matched 13 tokens. +Matched 21 tokens. +Matched 32 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + + Instance Initializer: + Constructors: + Methods: + func func() throws: + return 10 + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_let Decl: obj=new Foo() +== Sub Tree == +js_let Decl: employeeCode=obj.func() diff --git a/src/MapleFE/test/typescript/unit_tests/type-assertion-this.ts b/src/MapleFE/test/typescript/unit_tests/type-assertion-this.ts new file mode 100644 index 0000000000000000000000000000000000000000..d7d0c97a5d0852b14ad172c9faf676cde041a287 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-assertion-this.ts @@ -0,0 +1,6 @@ +class Foo { + public _val: number = 0; + public func(): number { + return this._val as number; + } +} diff --git a/src/MapleFE/test/typescript/unit_tests/type-assertion-this.ts.result b/src/MapleFE/test/typescript/unit_tests/type-assertion-this.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..69d1ccc316f88a7d554168f5ec87bf9d1b9a6909 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-assertion-this.ts.result @@ -0,0 +1,14 @@ +Matched 26 tokens. +============= Module =========== +== Sub Tree == +class Foo + Fields: + _val=0 + Instance Initializer: + Constructors: + Methods: + func func() throws: + return this._val + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/type-cast.ts b/src/MapleFE/test/typescript/unit_tests/type-cast.ts new file mode 100644 index 0000000000000000000000000000000000000000..2bdac558b996636acc0fe27c56a77233a5788ee8 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-cast.ts @@ -0,0 +1,18 @@ +interface Base { + name: string; +} +interface Derived extends Base { + age: number; +} + +let o = { name: "John", age: 30 }; + +function dump(obj: Base) { + console.log(obj.name, (obj).age); +} +dump(o); + +function dump2(obj: Base) { + console.log(obj.name, (obj as Derived).age); +} +dump2(o); diff --git a/src/MapleFE/test/typescript/unit_tests/type-cast.ts.result b/src/MapleFE/test/typescript/unit_tests/type-cast.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b1e67b53bf15ff1e0587607fe54c0ff88972e57f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-cast.ts.result @@ -0,0 +1,26 @@ +Matched 8 tokens. +Matched 18 tokens. +Matched 31 tokens. +Matched 58 tokens. +Matched 63 tokens. +Matched 89 tokens. +Matched 94 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Base {name } +== Sub Tree == +ts_interface: Derived {age } +== Sub Tree == +js_let Decl: o= {name:"John", age:30} +== Sub Tree == +func dump(obj) throws: + console.log(obj.name,(Derived)obj.age) + +== Sub Tree == +dump(o) +== Sub Tree == +func dump2(obj) throws: + console.log(obj.name,obj.age) + +== Sub Tree == +dump2(o) diff --git a/src/MapleFE/test/typescript/unit_tests/type-only-export.ts b/src/MapleFE/test/typescript/unit_tests/type-only-export.ts new file mode 100644 index 0000000000000000000000000000000000000000..9152f5d448eedbe119eed47461f71eb880d5403e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-only-export.ts @@ -0,0 +1,4 @@ +class Klass { + n: number = 0; +} +export type K = Klass; diff --git a/src/MapleFE/test/typescript/unit_tests/type-only-export.ts.result b/src/MapleFE/test/typescript/unit_tests/type-only-export.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a81448254ce65483220fbf223428b10515c71b0d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-only-export.ts.result @@ -0,0 +1,15 @@ +Matched 10 tokens. +Matched 16 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + n=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +export { type K = Klass} diff --git a/src/MapleFE/test/typescript/unit_tests/type-only-import.ts b/src/MapleFE/test/typescript/unit_tests/type-only-import.ts new file mode 100644 index 0000000000000000000000000000000000000000..9505ab8d55aebdf2a1ded8646778077bf4c6f55d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-only-import.ts @@ -0,0 +1,4 @@ +import type { K } from "./type-only-export"; + +var x: K = { n: 123 }; +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/type-only-import.ts.result b/src/MapleFE/test/typescript/unit_tests/type-only-import.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..389dcc86a93b459f9d207dde338115a4dd50b242 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-only-import.ts.result @@ -0,0 +1,10 @@ +Matched 8 tokens. +Matched 19 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +import {K} "./type-only-export" +== Sub Tree == +js_var Decl: x= {n:123} +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/type-predicate.ts b/src/MapleFE/test/typescript/unit_tests/type-predicate.ts new file mode 100644 index 0000000000000000000000000000000000000000..7c8df56a02bcbd316f51592e442f657ca333a564 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-predicate.ts @@ -0,0 +1,24 @@ +interface Foo { + foo: number; +} + +interface Bar { + bar: number; +} + +function isFoo(arg: any): arg is Foo { + return arg.foo !== undefined; +} + +// user defined type guard +function doStuff(arg: Foo | Bar) { + if (isFoo(arg)) { + console.log(arg.foo); + } + else { + console.log(arg.bar); + } +} + +doStuff({ foo: 123 }); +doStuff({ bar: 123 }); diff --git a/src/MapleFE/test/typescript/unit_tests/type-predicate.ts.result b/src/MapleFE/test/typescript/unit_tests/type-predicate.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e51159f7779d196b7b0be90db2c6dce2ab6fe59d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/type-predicate.ts.result @@ -0,0 +1,28 @@ +Matched 8 tokens. +Matched 16 tokens. +Matched 36 tokens. +Matched 77 tokens. +Matched 86 tokens. +Matched 95 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Foo {foo } +== Sub Tree == +ts_interface: Bar {bar } +== Sub Tree == +func isFoo(arg) throws: + return arg.foo StNe undefined + +== Sub Tree == +func doStuff(arg) throws: + cond-branch cond:isFoo(arg) + true branch : + console.log(arg.foo) + false branch : + console.log(arg.bar) + + +== Sub Tree == +doStuff( {foo:123}) +== Sub Tree == +doStuff( {bar:123}) diff --git a/src/MapleFE/test/typescript/unit_tests/typed-array.ts b/src/MapleFE/test/typescript/unit_tests/typed-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..e30281a9778cdc16822dbf57201c942448771833 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/typed-array.ts @@ -0,0 +1,49 @@ +let buf = new ArrayBuffer(16); +let bytes = new Uint8Array(buf); +for (let i = 0; i < bytes.length; i++) + bytes[i] = i * 15; + +console.log("\nInt8Array", Int8Array); +let Int8View = new Int8Array(buf); +for (let i = 0; i < Int8View.length; i++) + console.log(i, Int8View[i]); +console.log("\nUint8Array", Uint8Array); +let Uint8View = new Uint8Array(buf); +for (let i = 0; i < Uint8View.length; i++) + console.log(i, Uint8View[i]); +console.log("\nUint8ClampedArray", Uint8ClampedArray); +let Uint8ClampedView = new Uint8ClampedArray(buf); +for (let i = 0; i < Uint8ClampedView.length; i++) + console.log(i, Uint8ClampedView[i]); +console.log("\nInt16Array", Int16Array); +let Int16View = new Int16Array(buf); +for (let i = 0; i < Int16View.length; i++) + console.log(i, Int16View[i]); +console.log("\nUint16Array", Uint16Array); +let Uint16View = new Uint16Array(buf); +for (let i = 0; i < Uint16View.length; i++) + console.log(i, Uint16View[i]); +console.log("\nInt32Array", Int32Array); +let Int32View = new Int32Array(buf); +for (let i = 0; i < Int32View.length; i++) + console.log(i, Int32View[i]); +console.log("\nUint32Array", Uint32Array); +let Uint32View = new Uint32Array(buf); +for (let i = 0; i < Uint32View.length; i++) + console.log(i, Uint32View[i]); +console.log("\nFloat32Array", Float32Array); +let Float32View = new Float32Array(buf); +for (let i = 0; i < Float32View.length; i++) + console.log(i, Float32View[i]); +console.log("\nFloat64Array", Float64Array); +let Float64View = new Float64Array(buf); +for (let i = 0; i < Float64View.length; i++) + console.log(i, Float64View[i]); +// console.log("\nBigInt64Array", BigInt64Array); +// let BigInt64View = new BigInt64Array(buf); +// for (let i = 0; i < BigInt64View.length; i++) +// console.log(i, BigInt64View[i]); +// console.log("\nBigUint64Array", BigUint64Array); +// let BigUint64View = new BigUint64Array(buf); +// for (let i = 0; i < BigUint64View.length; i++) +// console.log(i, BigUint64View[i]); diff --git a/src/MapleFE/test/typescript/unit_tests/typed-array.ts.result b/src/MapleFE/test/typescript/unit_tests/typed-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..543fad1c4316b00ca8dca19dae69cea805a88a16 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/typed-array.ts.result @@ -0,0 +1,101 @@ +Matched 9 tokens. +Matched 18 tokens. +Matched 43 tokens. +Matched 52 tokens. +Matched 61 tokens. +Matched 89 tokens. +Matched 98 tokens. +Matched 107 tokens. +Matched 135 tokens. +Matched 144 tokens. +Matched 153 tokens. +Matched 181 tokens. +Matched 190 tokens. +Matched 199 tokens. +Matched 227 tokens. +Matched 236 tokens. +Matched 245 tokens. +Matched 273 tokens. +Matched 282 tokens. +Matched 291 tokens. +Matched 319 tokens. +Matched 328 tokens. +Matched 337 tokens. +Matched 365 tokens. +Matched 374 tokens. +Matched 383 tokens. +Matched 411 tokens. +Matched 420 tokens. +Matched 429 tokens. +Matched 457 tokens. +============= Module =========== +== Sub Tree == +js_let Decl: buf=new ArrayBuffer(16) +== Sub Tree == +js_let Decl: bytes=new Uint8Array(buf) +== Sub Tree == +for ( ) + bytes[i] Assign i Mul 15 +== Sub Tree == +console.log("\nInt8Array",Int8Array) +== Sub Tree == +js_let Decl: Int8View=new Int8Array(buf) +== Sub Tree == +for ( ) + console.log(i,Int8View[i]) +== Sub Tree == +console.log("\nUint8Array",Uint8Array) +== Sub Tree == +js_let Decl: Uint8View=new Uint8Array(buf) +== Sub Tree == +for ( ) + console.log(i,Uint8View[i]) +== Sub Tree == +console.log("\nUint8ClampedArray",Uint8ClampedArray) +== Sub Tree == +js_let Decl: Uint8ClampedView=new Uint8ClampedArray(buf) +== Sub Tree == +for ( ) + console.log(i,Uint8ClampedView[i]) +== Sub Tree == +console.log("\nInt16Array",Int16Array) +== Sub Tree == +js_let Decl: Int16View=new Int16Array(buf) +== Sub Tree == +for ( ) + console.log(i,Int16View[i]) +== Sub Tree == +console.log("\nUint16Array",Uint16Array) +== Sub Tree == +js_let Decl: Uint16View=new Uint16Array(buf) +== Sub Tree == +for ( ) + console.log(i,Uint16View[i]) +== Sub Tree == +console.log("\nInt32Array",Int32Array) +== Sub Tree == +js_let Decl: Int32View=new Int32Array(buf) +== Sub Tree == +for ( ) + console.log(i,Int32View[i]) +== Sub Tree == +console.log("\nUint32Array",Uint32Array) +== Sub Tree == +js_let Decl: Uint32View=new Uint32Array(buf) +== Sub Tree == +for ( ) + console.log(i,Uint32View[i]) +== Sub Tree == +console.log("\nFloat32Array",Float32Array) +== Sub Tree == +js_let Decl: Float32View=new Float32Array(buf) +== Sub Tree == +for ( ) + console.log(i,Float32View[i]) +== Sub Tree == +console.log("\nFloat64Array",Float64Array) +== Sub Tree == +js_let Decl: Float64View=new Float64Array(buf) +== Sub Tree == +for ( ) + console.log(i,Float64View[i]) diff --git a/src/MapleFE/test/typescript/unit_tests/typename-as-var.ts b/src/MapleFE/test/typescript/unit_tests/typename-as-var.ts new file mode 100644 index 0000000000000000000000000000000000000000..4aa37a9a22f356ec02a890abe03afbc5306c0ba7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/typename-as-var.ts @@ -0,0 +1,7 @@ +const boolean = Boolean; +var b = new boolean(false); +console.log(boolean, b); + +const string = String; +var s = new string("abc"); +console.log(string, s); diff --git a/src/MapleFE/test/typescript/unit_tests/typename-as-var.ts.result b/src/MapleFE/test/typescript/unit_tests/typename-as-var.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..b13ac1054fdcc3f0e2088ac0c47b328aa453ed9c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/typename-as-var.ts.result @@ -0,0 +1,19 @@ +Matched 5 tokens. +Matched 14 tokens. +Matched 23 tokens. +Matched 28 tokens. +Matched 37 tokens. +Matched 46 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: boolean=Boolean +== Sub Tree == +js_var Decl: b=new boolean(false) +== Sub Tree == +console.log(boolean,b) +== Sub Tree == +js_const Decl: string=String +== Sub Tree == +js_var Decl: s=new string("abc") +== Sub Tree == +console.log(string,s) diff --git a/src/MapleFE/test/typescript/unit_tests/typeof.d.ts b/src/MapleFE/test/typescript/unit_tests/typeof.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..da86045759b7942cfee07feb09f277189b22ef71 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/typeof.d.ts @@ -0,0 +1,3 @@ +export declare const E: readonly ["left", "right", "top", "down"]; +export declare type A = (typeof E)[number]; + diff --git a/src/MapleFE/test/typescript/unit_tests/typeof.d.ts.result b/src/MapleFE/test/typescript/unit_tests/typeof.d.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..dc4d89f967c5db2a1158279a2b0cddaf331d6722 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/typeof.d.ts.result @@ -0,0 +1,7 @@ +Matched 16 tokens. +Matched 29 tokens. +============= Module =========== +== Sub Tree == +export {declare js_const Decl: E} +== Sub Tree == +export {declare type A = typeof E[number]} diff --git a/src/MapleFE/test/typescript/unit_tests/types.ts b/src/MapleFE/test/typescript/unit_tests/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf9e393b3e7fd6fedf04bb6e6411ecb2a9d1ba44 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/types.ts @@ -0,0 +1,48 @@ +// ECMAScript language types (aka primitive type, literal type, etc..) +console.log(typeof(undefined)); // undefined +console.log(typeof(null)); // object (javascrupt legacy) +console.log(typeof(true)); // boolean +console.log(typeof(false)); // boolean +console.log(typeof("abc")); // string +console.log(typeof(Symbol())); // symbol +console.log(typeof(123)); // number +//console.log(typeof(123n)); // bigint +//console.log(typeof(BigInt(123))); // bigint + +// complex/compound type +console.log(typeof({})); // object +console.log({} instanceof Object); // true +console.log(typeof([])); +console.log([] instanceof Array); +console.log(typeof(new Array)); +console.log("===="); +console.log(typeof Object()); // object +console.log(typeof new Object()); // object +console.log(Object() instanceof Object); // true +console.log(new Object instanceof Object); // true + +// builtin objects +console.log(typeof(String())); // string +console.log(typeof(Boolean())); // boolean +console.log(typeof(Date())); // string +console.log(typeof(Number())); // number +//console.log(typeof(BigInt(123))); // bigint +console.log(typeof(new String())); // object +console.log(typeof(new Boolean())); // object +console.log(typeof(new Date())); // object +console.log(typeof(new Number())); // object + +//console.log(String() instanceof String); +//console.log(Boolean() instanceof Boolean); +//console.log(Date() instanceof Date); +//console.log(Number() instanceof Number); +console.log(new String() instanceof String); // true +console.log(new Boolean() instanceof Boolean); // true +console.log(new Date() instanceof Date); // true +console.log(new Number() instanceof Number); // true + +console.log(typeof(class {} )); // function +console.log(class{} instanceof Function);// Function +console.log(typeof(new class {} )); // object +console.log(new class {} instanceof Object); // object + diff --git a/src/MapleFE/test/typescript/unit_tests/types.ts.result b/src/MapleFE/test/typescript/unit_tests/types.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..daf52ff17fb31e35eb90acea22e0008ff0690444 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/types.ts.result @@ -0,0 +1,116 @@ +Matched 10 tokens. +Matched 20 tokens. +Matched 30 tokens. +Matched 40 tokens. +Matched 50 tokens. +Matched 62 tokens. +Matched 72 tokens. +Matched 83 tokens. +Matched 93 tokens. +Matched 104 tokens. +Matched 114 tokens. +Matched 125 tokens. +Matched 132 tokens. +Matched 142 tokens. +Matched 153 tokens. +Matched 164 tokens. +Matched 174 tokens. +Matched 186 tokens. +Matched 198 tokens. +Matched 210 tokens. +Matched 222 tokens. +Matched 235 tokens. +Matched 248 tokens. +Matched 261 tokens. +Matched 274 tokens. +Matched 286 tokens. +Matched 298 tokens. +Matched 310 tokens. +Matched 322 tokens. +Matched 334 tokens. +Matched 345 tokens. +Matched 358 tokens. +Matched 370 tokens. +============= Module =========== +== Sub Tree == +console.log( typeof undefined) +== Sub Tree == +console.log( typeof null) +== Sub Tree == +console.log( typeof true) +== Sub Tree == +console.log( typeof false) +== Sub Tree == +console.log( typeof "abc") +== Sub Tree == +console.log( typeof Symbol()) +== Sub Tree == +console.log( typeof 123) +== Sub Tree == +console.log( typeof {}) +== Sub Tree == +console.log( {} instanceof Object) +== Sub Tree == +console.log( typeof []) +== Sub Tree == +console.log([] instanceof Array) +== Sub Tree == +console.log( typeof new Array()) +== Sub Tree == +console.log("====") +== Sub Tree == +console.log( typeof Object()) +== Sub Tree == +console.log( typeof new Object()) +== Sub Tree == +console.log(Object() instanceof Object) +== Sub Tree == +console.log(new Object() instanceof Object) +== Sub Tree == +console.log( typeof String()) +== Sub Tree == +console.log( typeof Boolean()) +== Sub Tree == +console.log( typeof Date()) +== Sub Tree == +console.log( typeof Number()) +== Sub Tree == +console.log( typeof new String()) +== Sub Tree == +console.log( typeof new Boolean()) +== Sub Tree == +console.log( typeof new Date()) +== Sub Tree == +console.log( typeof new Number()) +== Sub Tree == +console.log(new String() instanceof String) +== Sub Tree == +console.log(new Boolean() instanceof Boolean) +== Sub Tree == +console.log(new Date() instanceof Date) +== Sub Tree == +console.log(new Number() instanceof Number) +== Sub Tree == +console.log( typeof class + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: +) +== Sub Tree == +console.log(class + Fields: + + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + instanceof Function) +== Sub Tree == +console.log( typeof new ()) +== Sub Tree == +console.log(new () instanceof Object) diff --git a/src/MapleFE/test/typescript/unit_tests/unary_op.ts b/src/MapleFE/test/typescript/unit_tests/unary_op.ts new file mode 100644 index 0000000000000000000000000000000000000000..34893c274ab5c0094b0329a96c925fba46dc2300 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/unary_op.ts @@ -0,0 +1,27 @@ +class A { + a?: number = 0; + b: number = 0; +} +var x: A = {a: 1, b: 2}; +delete x.a; + +console.log(void 0); + +console.log(typeof 8); + +var a: number = 8; +console.log(++a); +console.log(--a); + +console.log(+8); +console.log(+"-8"); + +console.log(-"8"); +console.log(-a); + +console.log(~8); +console.log(~"8"); +console.log(~a); + +console.log(!false); +console.log(!true); diff --git a/src/MapleFE/test/typescript/unit_tests/unary_op.ts.result b/src/MapleFE/test/typescript/unit_tests/unary_op.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..44e37f79c25eb54a182e3e0b76a14104c195739c --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/unary_op.ts.result @@ -0,0 +1,60 @@ +Matched 17 tokens. +Matched 32 tokens. +Matched 37 tokens. +Matched 45 tokens. +Matched 53 tokens. +Matched 60 tokens. +Matched 68 tokens. +Matched 76 tokens. +Matched 83 tokens. +Matched 91 tokens. +Matched 99 tokens. +Matched 107 tokens. +Matched 115 tokens. +Matched 123 tokens. +Matched 131 tokens. +Matched 139 tokens. +Matched 147 tokens. +============= Module =========== +== Sub Tree == +class A + Fields: + a?=0 b=0 + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + +== Sub Tree == +js_var Decl: x= {a:1, b:2} +== Sub Tree == + delete x.a +== Sub Tree == +console.log(void) +== Sub Tree == +console.log( typeof 8) +== Sub Tree == +js_var Decl: a=8 +== Sub Tree == +console.log(PreInc a) +== Sub Tree == +console.log(PreDec a) +== Sub Tree == +console.log(8) +== Sub Tree == +console.log(Plus "-8") +== Sub Tree == +console.log(Minus "8") +== Sub Tree == +console.log(Minus a) +== Sub Tree == +console.log(Bcomp 8) +== Sub Tree == +console.log(Bcomp "8") +== Sub Tree == +console.log(Bcomp a) +== Sub Tree == +console.log(Not false) +== Sub Tree == +console.log(Not true) diff --git a/src/MapleFE/test/typescript/unit_tests/undefined-assign.ts b/src/MapleFE/test/typescript/unit_tests/undefined-assign.ts new file mode 100644 index 0000000000000000000000000000000000000000..d3677a2574853dea16c54071dc58e2b006899cf1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/undefined-assign.ts @@ -0,0 +1 @@ +var x = undefined; diff --git a/src/MapleFE/test/typescript/unit_tests/undefined-assign.ts.result b/src/MapleFE/test/typescript/unit_tests/undefined-assign.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..06beeb38ee7c3d68b0b9f5aed1b4fc79404025f9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/undefined-assign.ts.result @@ -0,0 +1,4 @@ +Matched 5 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=undefined diff --git a/src/MapleFE/test/typescript/unit_tests/undefined-type.ts b/src/MapleFE/test/typescript/unit_tests/undefined-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0e3c2e89988257e58d32b2283b301ce4c12137a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/undefined-type.ts @@ -0,0 +1,9 @@ +function func(x: unknown): number | undefined { + if (typeof x === "number") return x * x; + return undefined; +} + +let v = func("a"); +console.log(v); +v = func(3); +console.log(v); diff --git a/src/MapleFE/test/typescript/unit_tests/undefined-type.ts.result b/src/MapleFE/test/typescript/unit_tests/undefined-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..1f6d4c0e72c7c45e604a7413f242f2df326f6b2a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/undefined-type.ts.result @@ -0,0 +1,22 @@ +Matched 28 tokens. +Matched 36 tokens. +Matched 43 tokens. +Matched 50 tokens. +Matched 57 tokens. +============= Module =========== +== Sub Tree == +func func(x) throws: + cond-branch cond: typeof x StEq "number" + true branch : + return x Mul x false branch : + + return undefined + +== Sub Tree == +js_let Decl: v=func("a") +== Sub Tree == +console.log(v) +== Sub Tree == +v Assign func(3) +== Sub Tree == +console.log(v) diff --git a/src/MapleFE/test/typescript/unit_tests/unicode-string.ts b/src/MapleFE/test/typescript/unit_tests/unicode-string.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ba9688f86fe738ce3ee1f8b19e8411e4bde6810 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/unicode-string.ts @@ -0,0 +1 @@ +console.log("cd/m²"); diff --git a/src/MapleFE/test/typescript/unit_tests/unicode-string.ts.result b/src/MapleFE/test/typescript/unit_tests/unicode-string.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a88eebc76c306d06da149cceb7082e77bc5df551 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/unicode-string.ts.result @@ -0,0 +1,4 @@ +Matched 7 tokens. +============= Module =========== +== Sub Tree == +console.log("cd/m²") diff --git a/src/MapleFE/test/typescript/unit_tests/unicode-string2.ts b/src/MapleFE/test/typescript/unit_tests/unicode-string2.ts new file mode 100644 index 0000000000000000000000000000000000000000..ef5a5d83d01f52dc678ee48daa431cf4ceb9110a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/unicode-string2.ts @@ -0,0 +1 @@ +console.log("你好"); diff --git a/src/MapleFE/test/typescript/unit_tests/unicode-string2.ts.result b/src/MapleFE/test/typescript/unit_tests/unicode-string2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..da685ec3174d1781efee3e577deaa9681cd33c11 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/unicode-string2.ts.result @@ -0,0 +1,4 @@ +Matched 7 tokens. +============= Module =========== +== Sub Tree == +console.log("你好") diff --git a/src/MapleFE/test/typescript/unit_tests/unicode-string3.ts b/src/MapleFE/test/typescript/unit_tests/unicode-string3.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d285ea0dc11a1e4b4f2539c3d798b55790ee95e --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/unicode-string3.ts @@ -0,0 +1,5 @@ +var 变量: string | number = "abc"; +// UTF-16 codes for 变量: 53d8 91cf +console.log(变量); +变量 = 123; +console.log(变量); diff --git a/src/MapleFE/test/typescript/unit_tests/unicode-string4.ts b/src/MapleFE/test/typescript/unit_tests/unicode-string4.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f2aa9007640701f1f5ab6375c796acd49a86eea --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/unicode-string4.ts @@ -0,0 +1,2 @@ +const str = "\u001F"; +console.log(str); diff --git a/src/MapleFE/test/typescript/unit_tests/unicode-string4.ts.result b/src/MapleFE/test/typescript/unit_tests/unicode-string4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3b23caffe9b938ea8c8863e6fd0b0dc2c94cc840 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/unicode-string4.ts.result @@ -0,0 +1,7 @@ +Matched 5 tokens. +Matched 12 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: str="\u001F" +== Sub Tree == +console.log(str) diff --git a/src/MapleFE/test/typescript/unit_tests/union-import-types.d.ts b/src/MapleFE/test/typescript/unit_tests/union-import-types.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..35f88d5860cf8136f1cb7a33e0ec2e3c7fea88d3 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-import-types.d.ts @@ -0,0 +1 @@ +export declare var x: { f: typeof import("./M") | import("./enum2").ET }; diff --git a/src/MapleFE/test/typescript/unit_tests/union-import-types.d.ts.result b/src/MapleFE/test/typescript/unit_tests/union-import-types.d.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..258f571ece0e0a0ecc73ad3117aa406503b01384 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-import-types.d.ts.result @@ -0,0 +1,4 @@ +Matched 22 tokens. +============= Module =========== +== Sub Tree == +export {declare js_var Decl: x} diff --git a/src/MapleFE/test/typescript/unit_tests/union-of-literals.ts b/src/MapleFE/test/typescript/unit_tests/union-of-literals.ts new file mode 100644 index 0000000000000000000000000000000000000000..6bcb1d3d3763db2aa116640d020aa279890af4be --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-of-literals.ts @@ -0,0 +1,6 @@ +var x: 0 | 1 | 2; +x = 1; +console.log(x); +var y: "left" | "right"; +y = "left"; +console.log(y); diff --git a/src/MapleFE/test/typescript/unit_tests/union-of-literals.ts.result b/src/MapleFE/test/typescript/unit_tests/union-of-literals.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..70069d55f920008984d3e0594a1879d77bb783e0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-of-literals.ts.result @@ -0,0 +1,19 @@ +Matched 9 tokens. +Matched 13 tokens. +Matched 20 tokens. +Matched 27 tokens. +Matched 31 tokens. +Matched 38 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x +== Sub Tree == +x Assign 1 +== Sub Tree == +console.log(x) +== Sub Tree == +js_var Decl: y +== Sub Tree == +y Assign "left" +== Sub Tree == +console.log(y) diff --git a/src/MapleFE/test/typescript/unit_tests/union-of-literals2.ts b/src/MapleFE/test/typescript/unit_tests/union-of-literals2.ts new file mode 100644 index 0000000000000000000000000000000000000000..56fb44c11dd899b62925c176bb5c7987988016a1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-of-literals2.ts @@ -0,0 +1,3 @@ +var y: "left" | "right" | string | undefined; +y = "left"; +console.log(y); diff --git a/src/MapleFE/test/typescript/unit_tests/union-of-literals2.ts.result b/src/MapleFE/test/typescript/unit_tests/union-of-literals2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e04ce3af94ad93c2c09053dae77cd908911e1ead --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-of-literals2.ts.result @@ -0,0 +1,10 @@ +Matched 11 tokens. +Matched 15 tokens. +Matched 22 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: y +== Sub Tree == +y Assign "left" +== Sub Tree == +console.log(y) diff --git a/src/MapleFE/test/typescript/unit_tests/union-of-prim-array.ts b/src/MapleFE/test/typescript/unit_tests/union-of-prim-array.ts new file mode 100644 index 0000000000000000000000000000000000000000..89331dd9f6efc0d056b83994ceb74818bbabf37a --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-of-prim-array.ts @@ -0,0 +1,4 @@ +var x: number[] | string[] = [1, 2, 3]; +console.log(x); +x = ["abc", "def"]; +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/union-of-prim-array.ts.result b/src/MapleFE/test/typescript/unit_tests/union-of-prim-array.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..cd5ee9bb2c95af4127fa23d80982f35852249412 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-of-prim-array.ts.result @@ -0,0 +1,13 @@ +Matched 19 tokens. +Matched 26 tokens. +Matched 34 tokens. +Matched 41 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=[1,2,3] +== Sub Tree == +console.log(x) +== Sub Tree == +x Assign ["abc","def"] +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/union-type.ts b/src/MapleFE/test/typescript/unit_tests/union-type.ts new file mode 100644 index 0000000000000000000000000000000000000000..f78209a4fdf5508ebd5cd43ac29d2aba2be8a2ce --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type.ts @@ -0,0 +1,7 @@ +type UnionType = number | string; +function add(x: UnionType, y: UnionType): UnionType { + if (typeof x === "number" && typeof y == "number") return x + y; + else return x.toString() + y.toString(); +} +console.log(add(1, 2)); +console.log(add("a", "b")); diff --git a/src/MapleFE/test/typescript/unit_tests/union-type.ts.result b/src/MapleFE/test/typescript/unit_tests/union-type.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..590db9e8c87f10865dcac5d536883101e0b5b763 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type.ts.result @@ -0,0 +1,18 @@ +Matched 7 tokens. +Matched 53 tokens. +Matched 65 tokens. +Matched 77 tokens. +============= Module =========== +== Sub Tree == + type UnionType = union = number | string +== Sub Tree == +func add(x,y) throws: + cond-branch cond: typeof x StEq "number" Land typeof y EQ "number" + true branch : + return x Add y false branch : + return x.toString() Add y.toString() + +== Sub Tree == +console.log(add(1,2)) +== Sub Tree == +console.log(add("a","b")) diff --git a/src/MapleFE/test/typescript/unit_tests/union-type2.ts b/src/MapleFE/test/typescript/unit_tests/union-type2.ts new file mode 100644 index 0000000000000000000000000000000000000000..22a02a0c38c5ffb464190190b43a56d25edd02a5 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type2.ts @@ -0,0 +1,7 @@ +type UT = string | ((k: number) => number); +var s: UT = "abc"; +console.log(s); +s = function func(k: number): number { + return k + k; +}; +console.log(s, s(3)); diff --git a/src/MapleFE/test/typescript/unit_tests/union-type2.ts.result b/src/MapleFE/test/typescript/unit_tests/union-type2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f368b31edb44b8836b9cf8b6b111ca760d09b6a7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type2.ts.result @@ -0,0 +1,18 @@ +Matched 15 tokens. +Matched 22 tokens. +Matched 29 tokens. +Matched 48 tokens. +Matched 60 tokens. +============= Module =========== +== Sub Tree == + type UT = union = string | (k) -> +== Sub Tree == +js_var Decl: s="abc" +== Sub Tree == +console.log(s) +== Sub Tree == +s Assign func func(k) throws: + return k Add k + +== Sub Tree == +console.log(s,s(3)) diff --git a/src/MapleFE/test/typescript/unit_tests/union-type3.ts b/src/MapleFE/test/typescript/unit_tests/union-type3.ts new file mode 100644 index 0000000000000000000000000000000000000000..42629ed59ec65e77aade9dbe3e95734c29663874 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type3.ts @@ -0,0 +1,9 @@ +function func(k: number): number { + return k + k; +} + +type UT = string | typeof func; +var s: UT = "abc"; +console.log(s); +s = func; +console.log(s, s(3)); diff --git a/src/MapleFE/test/typescript/unit_tests/union-type3.ts.result b/src/MapleFE/test/typescript/unit_tests/union-type3.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..3851bff8bc5ce2d7843d5b859a4e7f1091e0474b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type3.ts.result @@ -0,0 +1,21 @@ +Matched 16 tokens. +Matched 24 tokens. +Matched 31 tokens. +Matched 38 tokens. +Matched 42 tokens. +Matched 54 tokens. +============= Module =========== +== Sub Tree == +func func(k) throws: + return k Add k + +== Sub Tree == + type UT = union = string | typeof func +== Sub Tree == +js_var Decl: s="abc" +== Sub Tree == +console.log(s) +== Sub Tree == +s Assign func +== Sub Tree == +console.log(s,s(3)) diff --git a/src/MapleFE/test/typescript/unit_tests/union-type4.ts b/src/MapleFE/test/typescript/unit_tests/union-type4.ts new file mode 100644 index 0000000000000000000000000000000000000000..994b3993c430f861e8ecd0bff161573ddd9d3929 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type4.ts @@ -0,0 +1,11 @@ +function func(k: number): number { + return k + k; +} + +type UT = string | typeof func | Array; +var s: UT = "abc"; +console.log(s); +s = func; +console.log(s, s(3)); +s = new Array("first", "second"); +console.log(s); diff --git a/src/MapleFE/test/typescript/unit_tests/union-type4.ts.result b/src/MapleFE/test/typescript/unit_tests/union-type4.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..cb4401473c8420858aa766a4dbf9ec2d59c4ca32 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type4.ts.result @@ -0,0 +1,27 @@ +Matched 16 tokens. +Matched 29 tokens. +Matched 36 tokens. +Matched 43 tokens. +Matched 47 tokens. +Matched 59 tokens. +Matched 69 tokens. +Matched 76 tokens. +============= Module =========== +== Sub Tree == +func func(k) throws: + return k Add k + +== Sub Tree == + type UT = union = string | typeof func | Array +== Sub Tree == +js_var Decl: s="abc" +== Sub Tree == +console.log(s) +== Sub Tree == +s Assign func +== Sub Tree == +console.log(s,s(3)) +== Sub Tree == +s Assign new Array("first","second") +== Sub Tree == +console.log(s) diff --git a/src/MapleFE/test/typescript/unit_tests/union-type5.ts b/src/MapleFE/test/typescript/unit_tests/union-type5.ts new file mode 100644 index 0000000000000000000000000000000000000000..81947c80bc1ac1bc570eae8b920db913aa9a346b --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type5.ts @@ -0,0 +1,2 @@ +var x: { [key: string]: number } | null = null; +console.log(x); diff --git a/src/MapleFE/test/typescript/unit_tests/union-type5.ts.result b/src/MapleFE/test/typescript/unit_tests/union-type5.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..e586c3fc840d25af28e83b6ae36cd8bd8b63b4ea --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type5.ts.result @@ -0,0 +1,7 @@ +Matched 17 tokens. +Matched 24 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=null +== Sub Tree == +console.log(x) diff --git a/src/MapleFE/test/typescript/unit_tests/union-type6.ts b/src/MapleFE/test/typescript/unit_tests/union-type6.ts new file mode 100644 index 0000000000000000000000000000000000000000..28b76547e39b54d70539067d76c5a4c055d80c43 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type6.ts @@ -0,0 +1,6 @@ +var s: string | number | undefined = 123; +console.log(s); +s = "abc"; +console.log(s); +s = undefined; +console.log(s); diff --git a/src/MapleFE/test/typescript/unit_tests/union-type6.ts.result b/src/MapleFE/test/typescript/unit_tests/union-type6.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ba46d8f7a64b4ecd4d111c9ad498efe876a7d021 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type6.ts.result @@ -0,0 +1,19 @@ +Matched 11 tokens. +Matched 18 tokens. +Matched 22 tokens. +Matched 29 tokens. +Matched 33 tokens. +Matched 40 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: s=123 +== Sub Tree == +console.log(s) +== Sub Tree == +s Assign "abc" +== Sub Tree == +console.log(s) +== Sub Tree == +s Assign undefined +== Sub Tree == +console.log(s) diff --git a/src/MapleFE/test/typescript/unit_tests/union-type7.ts b/src/MapleFE/test/typescript/unit_tests/union-type7.ts new file mode 100644 index 0000000000000000000000000000000000000000..596d4563ff945c39883b00ad48c05ba4c1e4e7b0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type7.ts @@ -0,0 +1 @@ +type AType = (new() => Error) | Error; diff --git a/src/MapleFE/test/typescript/unit_tests/union-type7.ts.result b/src/MapleFE/test/typescript/unit_tests/union-type7.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..87d45a853db99d735fbbb05f038519ed1238fdd9 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type7.ts.result @@ -0,0 +1,4 @@ +Matched 13 tokens. +============= Module =========== +== Sub Tree == + type AType = union = new () -> | Error diff --git a/src/MapleFE/test/typescript/unit_tests/union-type8.ts b/src/MapleFE/test/typescript/unit_tests/union-type8.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e43c4f8d1a1009015f18bbde2c41049fba3a7cc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type8.ts @@ -0,0 +1,9 @@ +interface IFace { + num: number; +} + +interface IFace2< +T extends null | IFace, +> extends IFace { + prop: T; +} diff --git a/src/MapleFE/test/typescript/unit_tests/union-type8.ts.result b/src/MapleFE/test/typescript/unit_tests/union-type8.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0275638610cec08579102cb7492bf5ced8c1c685 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/union-type8.ts.result @@ -0,0 +1,7 @@ +Matched 8 tokens. +Matched 26 tokens. +============= Module =========== +== Sub Tree == +ts_interface: IFace {num } +== Sub Tree == +ts_interface: IFace2 {prop } diff --git a/src/MapleFE/test/typescript/unit_tests/utility-type-instancetype.ts b/src/MapleFE/test/typescript/unit_tests/utility-type-instancetype.ts new file mode 100644 index 0000000000000000000000000000000000000000..ca53fcb7d1ff15dc2284e19987196f87b6b34a00 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/utility-type-instancetype.ts @@ -0,0 +1,10 @@ +class Klass { + x: number = 33; + public getNum() { + return this.x >> 2; + } +} + +class Klass2 { + map: Map> | undefined = undefined; +} diff --git a/src/MapleFE/test/typescript/unit_tests/utility-type-instancetype.ts.result b/src/MapleFE/test/typescript/unit_tests/utility-type-instancetype.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..06c16c8b85c9a43a8f376755c90bec74f4748f3f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/utility-type-instancetype.ts.result @@ -0,0 +1,25 @@ +Matched 23 tokens. +Matched 43 tokens. +============= Module =========== +== Sub Tree == +class Klass + Fields: + x=33 + Instance Initializer: + Constructors: + Methods: + func getNum() throws: + return this.x Shr 2 + LocalClasses: + LocalInterfaces: + +== Sub Tree == +class Klass2 + Fields: + map=undefined + Instance Initializer: + Constructors: + Methods: + LocalClasses: + LocalInterfaces: + diff --git a/src/MapleFE/test/typescript/unit_tests/utility-type-nonnullable.ts b/src/MapleFE/test/typescript/unit_tests/utility-type-nonnullable.ts new file mode 100644 index 0000000000000000000000000000000000000000..55b36eb5650f6a5daca29469a1d2d6c019c868f1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/utility-type-nonnullable.ts @@ -0,0 +1,7 @@ +interface Interf { + prop: { + pos: Object; + }; +} + +type TYPE = NonNullable; diff --git a/src/MapleFE/test/typescript/unit_tests/utility-type-nonnullable.ts.result b/src/MapleFE/test/typescript/unit_tests/utility-type-nonnullable.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..733641e3852fb19e3bc1d2aa320a4f0062cd5a02 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/utility-type-nonnullable.ts.result @@ -0,0 +1,7 @@ +Matched 13 tokens. +Matched 27 tokens. +============= Module =========== +== Sub Tree == +ts_interface: Interf {prop } +== Sub Tree == + type TYPE = NonNullable diff --git a/src/MapleFE/test/typescript/unit_tests/utility-type-parameters.ts b/src/MapleFE/test/typescript/unit_tests/utility-type-parameters.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f9ef082bc38ba80af812d4931a219eda88213cc --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/utility-type-parameters.ts @@ -0,0 +1,6 @@ +var list = { f1: 0, f2: "abc" }; +function f(...list: any[]) {} +function func(t: Parameters[0]): Parameters[1] { + return list.f2 + t; +} +console.log(func(123)); diff --git a/src/MapleFE/test/typescript/unit_tests/utility-type-parameters.ts.result b/src/MapleFE/test/typescript/unit_tests/utility-type-parameters.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..5ba7c640a1851e4c661b4cdc47ce455ce072921d --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/utility-type-parameters.ts.result @@ -0,0 +1,16 @@ +Matched 13 tokens. +Matched 25 tokens. +Matched 57 tokens. +Matched 67 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: list= {f1:0, f2:"abc"} +== Sub Tree == +func f(...list) throws: + +== Sub Tree == +func func(t) throws: + return list.f2 Add t + +== Sub Tree == +console.log(func(123)) diff --git a/src/MapleFE/test/typescript/unit_tests/utility-type-parameters2.ts b/src/MapleFE/test/typescript/unit_tests/utility-type-parameters2.ts new file mode 100644 index 0000000000000000000000000000000000000000..730ac18acb3457c414ac6ada64924b34c909c954 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/utility-type-parameters2.ts @@ -0,0 +1,12 @@ +function func(n: number, s: string): string { + return n + s; +} + +function wrapper( + n: Parameters[0], + s: Parameters[1] | undefined +): string { + return func(n, s!); +} + +console.log(wrapper(123, "abc")); diff --git a/src/MapleFE/test/typescript/unit_tests/utility-type-parameters2.ts.result b/src/MapleFE/test/typescript/unit_tests/utility-type-parameters2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..a2f0036f2bb1f283383ebcc2a3030ea1d2abc5df --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/utility-type-parameters2.ts.result @@ -0,0 +1,14 @@ +Matched 20 tokens. +Matched 60 tokens. +Matched 72 tokens. +============= Module =========== +== Sub Tree == +func func(n,s) throws: + return n Add s + +== Sub Tree == +func wrapper(n,s) throws: + return func(n,s!) + +== Sub Tree == +console.log(wrapper(123,"abc")) diff --git a/src/MapleFE/test/typescript/unit_tests/values.ts b/src/MapleFE/test/typescript/unit_tests/values.ts new file mode 100644 index 0000000000000000000000000000000000000000..a57009b4ba6947604df116a233182bcfd0f6ab95 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/values.ts @@ -0,0 +1 @@ +export const values = [{ brand: "BMW", model: "325" }, {}]; diff --git a/src/MapleFE/test/typescript/unit_tests/values.ts.result b/src/MapleFE/test/typescript/unit_tests/values.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..19f5259985cf2198eeb7e6f60eb2f36ff9ccc5f2 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/values.ts.result @@ -0,0 +1,4 @@ +Matched 19 tokens. +============= Module =========== +== Sub Tree == +export {js_const Decl: values=[ {brand:"BMW", model:"325"}, {}]} diff --git a/src/MapleFE/test/typescript/unit_tests/var-as-prop-name.ts b/src/MapleFE/test/typescript/unit_tests/var-as-prop-name.ts new file mode 100644 index 0000000000000000000000000000000000000000..bd97f5cab3b2af51e3f45bca1c7320496a53b5ff --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-as-prop-name.ts @@ -0,0 +1,10 @@ +const obj = { + else() { + return this; + }, + var() { + console.log("var"); + } +} + +obj.else().var(); diff --git a/src/MapleFE/test/typescript/unit_tests/var-as-prop-name.ts.result b/src/MapleFE/test/typescript/unit_tests/var-as-prop-name.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7fcef6b23a7beaf3d03a4115b40cfebcf5da9d1f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-as-prop-name.ts.result @@ -0,0 +1,11 @@ +Matched 26 tokens. +Matched 36 tokens. +============= Module =========== +== Sub Tree == +js_const Decl: obj= {else:func else() throws: + return this +, var:func var() throws: + console.log("var") +} +== Sub Tree == +obj.else().var() diff --git a/src/MapleFE/test/typescript/unit_tests/var-const.ts b/src/MapleFE/test/typescript/unit_tests/var-const.ts new file mode 100644 index 0000000000000000000000000000000000000000..70ad5911b8e2534198fcd0e5afeb2f8df39919b7 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-const.ts @@ -0,0 +1,10 @@ +function foo(j: number): number { + { + const i: number = 4; + j += 10 * i; + } + var i = 8; + return i + j; +} + +console.log(foo(5)); diff --git a/src/MapleFE/test/typescript/unit_tests/var-const.ts.result b/src/MapleFE/test/typescript/unit_tests/var-const.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..ae3c888bc2c46dc035ef4e6b1eea66c280e10644 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-const.ts.result @@ -0,0 +1,13 @@ +Matched 36 tokens. +Matched 46 tokens. +============= Module =========== +== Sub Tree == +func foo(j) throws: + js_const Decl: i=4 + j AddAssign 10 Mul i + + js_var Decl: i=8 + return i Add j + +== Sub Tree == +console.log(foo(5)) diff --git a/src/MapleFE/test/typescript/unit_tests/var-dup.ts b/src/MapleFE/test/typescript/unit_tests/var-dup.ts new file mode 100644 index 0000000000000000000000000000000000000000..935641621371303cef7f1dbeb0077525d6903beb --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-dup.ts @@ -0,0 +1,14 @@ +function foo(a: number) { + var sum = 0; + for (var i = 0; i < a; i++) { + var i = 4; + for (var i = 0; i < a; i++) { + let i = 8; + sum += i; + } + } + + return sum; +} + +console.log(foo(10)); diff --git a/src/MapleFE/test/typescript/unit_tests/var-dup.ts.result b/src/MapleFE/test/typescript/unit_tests/var-dup.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..8eb5ad8a69fec678a79cafa4625152bb409834b1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-dup.ts.result @@ -0,0 +1,17 @@ +Matched 63 tokens. +Matched 73 tokens. +============= Module =========== +== Sub Tree == +func foo(a) throws: + js_var Decl: sum=0 + for ( ) + js_var Decl: i=4 + for ( ) + js_let Decl: i=8 + sum AddAssign i + + + return sum + +== Sub Tree == +console.log(foo(10)) diff --git a/src/MapleFE/test/typescript/unit_tests/var-in-function.ts b/src/MapleFE/test/typescript/unit_tests/var-in-function.ts new file mode 100644 index 0000000000000000000000000000000000000000..71f0660cbef5dac84cfbdaa37e3584ccf16bcd47 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-in-function.ts @@ -0,0 +1,7 @@ +function func() { + const res = { + pos: [0.5, -0.5, 0], + }; + return res; +} +console.log(func()); diff --git a/src/MapleFE/test/typescript/unit_tests/var-in-function.ts.result b/src/MapleFE/test/typescript/unit_tests/var-in-function.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..02502c6870f4d9eb02ef83cd7aa344191ed7e352 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-in-function.ts.result @@ -0,0 +1,10 @@ +Matched 25 tokens. +Matched 34 tokens. +============= Module =========== +== Sub Tree == +func func() throws: + js_const Decl: res= {pos:[0.5,-0.5,0]} + return res + +== Sub Tree == +console.log(func()) diff --git a/src/MapleFE/test/typescript/unit_tests/var-scope.ts b/src/MapleFE/test/typescript/unit_tests/var-scope.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ccfeb6eabeb9aabd71aa4cc2cd5aeacbf3618cd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-scope.ts @@ -0,0 +1,16 @@ +var i: number = 5; + +function foo(j: number): number { + i = j; + { + let i: number = 2; + j += 100 * i; + } + { + let i: number = 4; + j += 10 * i; + } + return i + j; +} + +console.log(foo(5)); diff --git a/src/MapleFE/test/typescript/unit_tests/var-scope.ts.result b/src/MapleFE/test/typescript/unit_tests/var-scope.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..f8c807fa7c41397190bc3766d0d85e958374086f --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-scope.ts.result @@ -0,0 +1,19 @@ +Matched 7 tokens. +Matched 57 tokens. +Matched 67 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: i=5 +== Sub Tree == +func foo(j) throws: + i Assign j + js_let Decl: i=2 + j AddAssign 100 Mul i + + js_let Decl: i=4 + j AddAssign 10 Mul i + + return i Add j + +== Sub Tree == +console.log(foo(5)) diff --git a/src/MapleFE/test/typescript/unit_tests/var-use-first.ts b/src/MapleFE/test/typescript/unit_tests/var-use-first.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0c3d35b44361aef9696cc25634c9903d70819be --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-use-first.ts @@ -0,0 +1,7 @@ +function foo(j: number): number { + i = j; + var i: number = 4; + return i + j; +} + +console.log(foo(5)); diff --git a/src/MapleFE/test/typescript/unit_tests/var-use-first.ts.result b/src/MapleFE/test/typescript/unit_tests/var-use-first.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0a4550222ae6c27478f607b1c206fcdc04582983 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var-use-first.ts.result @@ -0,0 +1,11 @@ +Matched 27 tokens. +Matched 37 tokens. +============= Module =========== +== Sub Tree == +func foo(j) throws: + i Assign j + js_var Decl: i=4 + return i Add j + +== Sub Tree == +console.log(foo(5)) diff --git a/src/MapleFE/test/typescript/unit_tests/var.ts b/src/MapleFE/test/typescript/unit_tests/var.ts new file mode 100644 index 0000000000000000000000000000000000000000..370d5d30f71af1090875871aba51068550bc39bf --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var.ts @@ -0,0 +1,2 @@ +var a: number = 1; +console.log(a); diff --git a/src/MapleFE/test/typescript/unit_tests/var.ts.result b/src/MapleFE/test/typescript/unit_tests/var.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..c9c995c9ef89f05aed1a00e3bf818a13d1da5eda --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/var.ts.result @@ -0,0 +1,7 @@ +Matched 7 tokens. +Matched 14 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: a=1 +== Sub Tree == +console.log(a) diff --git a/src/MapleFE/test/typescript/unit_tests/void-zero.ts b/src/MapleFE/test/typescript/unit_tests/void-zero.ts new file mode 100644 index 0000000000000000000000000000000000000000..96176e42e8c0e3152540dd449059e5618a50aad1 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/void-zero.ts @@ -0,0 +1,3 @@ +var x: number | undefined = void 0; +console.log(x); +console.log(typeof x); diff --git a/src/MapleFE/test/typescript/unit_tests/void-zero.ts.result b/src/MapleFE/test/typescript/unit_tests/void-zero.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..7debc43dd58ea3dda242c7f773be3a7ad2dbda04 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/void-zero.ts.result @@ -0,0 +1,10 @@ +Matched 10 tokens. +Matched 17 tokens. +Matched 25 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=void +== Sub Tree == +console.log(x) +== Sub Tree == +console.log( typeof x) diff --git a/src/MapleFE/test/typescript/unit_tests/void-zero2.ts b/src/MapleFE/test/typescript/unit_tests/void-zero2.ts new file mode 100644 index 0000000000000000000000000000000000000000..caf1ac79394882cf39ce65dae45dc54d3eed14d0 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/void-zero2.ts @@ -0,0 +1,6 @@ +var x: number | undefined = void 0; +console.log(x); +console.log(typeof x); +x = 123; +console.log(x); +console.log(typeof x); diff --git a/src/MapleFE/test/typescript/unit_tests/void-zero2.ts.result b/src/MapleFE/test/typescript/unit_tests/void-zero2.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..0a400cde2108a958f4bf5259e47fb18b0f84c5cd --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/void-zero2.ts.result @@ -0,0 +1,19 @@ +Matched 10 tokens. +Matched 17 tokens. +Matched 25 tokens. +Matched 29 tokens. +Matched 36 tokens. +Matched 44 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: x=void +== Sub Tree == +console.log(x) +== Sub Tree == +console.log( typeof x) +== Sub Tree == +x Assign 123 +== Sub Tree == +console.log(x) +== Sub Tree == +console.log( typeof x) diff --git a/src/MapleFE/test/typescript/unit_tests/while-stmt.ts b/src/MapleFE/test/typescript/unit_tests/while-stmt.ts new file mode 100644 index 0000000000000000000000000000000000000000..828da50719d0e1ccbef4dc4ba7a2eac2ce8d5161 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/while-stmt.ts @@ -0,0 +1,6 @@ +var k: number = 1; +while (k < 10) { + console.log(k); + if (k == 8) break; + k++; +} diff --git a/src/MapleFE/test/typescript/unit_tests/while-stmt.ts.result b/src/MapleFE/test/typescript/unit_tests/while-stmt.ts.result new file mode 100644 index 0000000000000000000000000000000000000000..6364c9367e427b8de5e1aa50ff47e940ce2b0d83 --- /dev/null +++ b/src/MapleFE/test/typescript/unit_tests/while-stmt.ts.result @@ -0,0 +1,15 @@ +Matched 7 tokens. +Matched 33 tokens. +============= Module =========== +== Sub Tree == +js_var Decl: k=1 +== Sub Tree == +while k LT 10 console.log(k) + cond-branch cond:k EQ 8 + true branch : + break: + false branch : + + k Inc + + diff --git a/src/MapleFE/autogen/include/expr_gen.h b/src/MapleFE/tools/obfuscate/include/obfuscate.h similarity index 47% rename from src/MapleFE/autogen/include/expr_gen.h rename to src/MapleFE/tools/obfuscate/include/obfuscate.h index cef6a1a7c20e9013cae0d8cb1a79a24528a4e20c..63574ba6d02657eb5293605a36236e4a14374fe3 100644 --- a/src/MapleFE/autogen/include/expr_gen.h +++ b/src/MapleFE/tools/obfuscate/include/obfuscate.h @@ -1,5 +1,5 @@ /* -* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2022] Futurewei Technologies, Inc. All rights reverved. * * OpenArkFE is licensed under the Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. @@ -12,29 +12,41 @@ * FIT FOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. */ -//////////////////////////////////////////////////////////////////////// -// Expr Generation // -//////////////////////////////////////////////////////////////////////// -#ifndef __EXPR_GEN_H__ -#define __EXPR_GEN_H__ +////////////////////////////////////////////////////////////////////////////////////////////// +// This is the interface to translate AST to C++ +////////////////////////////////////////////////////////////////////////////////////////////// -#include "base_gen.h" -#include "all_supported.h" +#ifndef __OBFUSCATE_HEADER__ +#define __OBFUSCATE_HEADER__ + +#include "astopt.h" +#include "ast_handler.h" +#include "ast_module.h" namespace maplefe { -class ExprGen : public BaseGen { +class Obfuscate : public AstOpt { +private: + AST_Handler *mASTHandler; + unsigned mFlags; + unsigned mIndexImported; + public: - ExprGen(const char *dfile, const char *hfile, const char *cfile) - : BaseGen(dfile, hfile, cfile) {} - ~ExprGen(){} + explicit Obfuscate(AST_Handler *h, unsigned flags) : + AstOpt(h, flags), + mASTHandler(h), + mFlags(flags), + mIndexImported(0) {} + ~Obfuscate() = default; - void Generate(); - void GenCppFile(); - void GenHeaderFile(); + void EmitTS(); + bool LoadImportedModules(); + + // return 0 if successful + // return non-zero if failed + int ProcessAST(); }; } - #endif diff --git a/src/MapleFE/tools/obfuscate/src/main.cpp b/src/MapleFE/tools/obfuscate/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0865f8545ed5116743448c3bb710b7e33cb9289a --- /dev/null +++ b/src/MapleFE/tools/obfuscate/src/main.cpp @@ -0,0 +1,109 @@ +/* +* Copyright (C) [2022] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2022] Tencent. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include "gen_astload.h" +#include "ast_handler.h" +#include "obfuscate.h" + +static void help() { + std::cout << "obfuscate a.ast[,b.ast] [options]:" << std::endl; + std::cout << " --out=x.ts : ts output file" << std::endl; + std::cout << " --help : print this help" << std::endl; + std::cout << " --trace=n : Emit trace with 4-bit combo levels 1...15" << std::endl; + std::cout << " 1 : Emit ast tree visits" << std::endl; + std::cout << " 2 : Emit graph" << std::endl; + std::cout << " --emit-ts-only : Emit ts code only" << std::endl; + std::cout << " --emit-ts : Emit ts code" << std::endl; + std::cout << " --format-cpp : Format cpp" << std::endl; + std::cout << " --no-imported : Do not process the imported modules" << std::endl; + std::cout << "default out name uses the first input name: a.cpp" << std::endl; +} + +int main (int argc, char *argv[]) { + if (argc == 1 || (!strncmp(argv[1], "--help", 6) && (strlen(argv[1]) == 6))) { + help(); + exit(-1); + } + + unsigned flags; + // one or more input .ast files separated by ',' + const char *inputname = argv[1]; + // output .ast file + const char *outputname = nullptr; + + // Parse the argument + for (unsigned i = 2; i < argc; i++) { + if (!strncmp(argv[i], "--trace=", 8)) { + int val = atoi(argv[i] + 8); + if (val < 1 || val > 15) { + help(); + exit(-1); + } + flags |= val; + } else if (!strncmp(argv[i], "--emit-ts-only", 14)) { + flags |= maplefe::FLG_emit_ts_only; + } else if (!strncmp(argv[i], "--emit-ts", 9)) { + flags |= maplefe::FLG_emit_ts; + } else if (!strncmp(argv[i], "--format-cpp", 12)) { + flags |= maplefe::FLG_format_cpp; + } else if (!strncmp(argv[i], "--no-imported", 13)) { + flags |= maplefe::FLG_no_imported; + } else if (!strncmp(argv[i], "--in=", 5)) { + inputname = argv[i]+5; + } else if (!strncmp(argv[i], "--out=", 6)) { + outputname = argv[i]+6; + } else { + std::cerr << "unknown option " << argv[i] << std::endl; + exit(-1); + } + } + + // input ast files + std::vector inputfiles; + if (inputname) { + std::stringstream ss; + ss.str(inputname); + std::string item; + while (std::getline(ss, item, ',')) { + // std::cout << "item " << item << " xxx"<< std::endl; + inputfiles.push_back(item); + } + } + + unsigned trace = (flags & maplefe::FLG_trace); + maplefe::AST_Handler handler(trace); + for (auto astfile: inputfiles) { + std::ifstream input(astfile, std::ifstream::binary); + input >> std::noskipws; + std::istream_iterator s(input), e; + maplefe::AstBuffer vec(s, e); + maplefe::AstLoad loadAst; + maplefe::ModuleNode *mod = loadAst.LoadFromAstBuf(vec); + // add mod to the vector + while(mod) { + handler.AddModule(mod); + mod = loadAst.Next(); + } + } + + maplefe::Obfuscate *obfuscate = new maplefe::Obfuscate(&handler, flags); + int res = obfuscate->ProcessAST(); + + return res; +} diff --git a/src/MapleFE/tools/obfuscate/src/obfuscate.cpp b/src/MapleFE/tools/obfuscate/src/obfuscate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cec38cbc9cd61b600310f72967651b849431cc77 --- /dev/null +++ b/src/MapleFE/tools/obfuscate/src/obfuscate.cpp @@ -0,0 +1,168 @@ +/* +* Copyright (C) [2022] Futurewei Technologies, Inc. All rights reverved. +* Copyright (C) [2022] Tencent. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include +#include +#include +#include +#include + +#include "obfuscate.h" +#include "ast_handler.h" +#include "gen_astdump.h" +#include "gen_astgraph.h" +#include "gen_aststore.h" +#include "gen_astload.h" +#include "cpp_definition.h" +#include "cpp_declaration.h" +#include "a2c_util.h" + +namespace maplefe { + +bool Obfuscate::LoadImportedModules() { + std::queue queue; + for (HandlerIndex i = 0; i < GetModuleNum(); i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + ModuleNode *module = handler->GetASTModule(); + ImportedFiles imported(module); + imported.VisitTreeNode(module); + for(const auto &e: imported.mFilenames) + queue.push(e); + } + + bool err = false; + while(!queue.empty()) { + std::string filename = queue.front(); + queue.pop(); + if(mASTHandler->GetHandlerIndex(filename.c_str()) == HandlerNotFound) { + std::ifstream input(filename, std::ifstream::binary); + if(input.fail()) { + std::cerr << "Error: File " << filename << " not found for imported module" << std::endl; + err = true; + continue; + } + input >> std::noskipws; + std::istream_iterator s(input), e; + maplefe::AstBuffer vec(s, e); + maplefe::AstLoad loadAst; + maplefe::ModuleNode *mod = loadAst.LoadFromAstBuf(vec); + // add mod to the vector + while(mod) { + mASTHandler->AddModule(mod); + ImportedFiles imported(mod); + imported.VisitTreeNode(mod); + for(const auto &e: imported.mFilenames) + queue.push(e); + mod = loadAst.Next(); + } + } + } + return err; +} + +// starting point of AST +int Obfuscate::ProcessAST() { + mIndexImported = GetModuleNum(); + + // load all imported modules + if (!(mFlags & FLG_no_imported)) { + if (LoadImportedModules()) { + return 1; + } + } + + // loop through module handlers + for (HandlerIndex i = 0; i < GetModuleNum(); i++) { + Module_Handler *handler = mASTHandler->GetModuleHandler(i); + ModuleNode *module = handler->GetASTModule(); + + if (mFlags & FLG_trace_1) { + std::cout << "============= in ProcessAST ===========" << std::endl; + std::cout << "srcLang : " << module->GetSrcLangString() << std::endl; + + for(unsigned k = 0; k < module->GetTreesNum(); k++) { + TreeNode *tnode = module->GetTree(k); + if (mFlags & FLG_trace_1) { + tnode->Dump(0); + std::cout << std::endl; + } + } + } + + if (mFlags & FLG_trace_2) { + std::cout << "============= AstGraph ===========" << std::endl; + AstGraph graph(module); + graph.DumpGraph("After LoadFromAstBuf()", &std::cout); + } + } + + // build dependency of modules + PreprocessModules(); + + // loop through module handlers in import/export dependency order + for (auto handler: mHandlersInOrder) { + ModuleNode *module = handler->GetASTModule(); + + // basic analysis + handler->BasicAnalysis(); + + if (mFlags & FLG_trace_2) { + std::cout << "============= After BasicAnalysis ===========" << std::endl; + for(unsigned k = 0; k < module->GetTreesNum(); k++) { + TreeNode *tnode = module->GetTree(k); + if (mFlags & FLG_trace_1) { + tnode->Dump(0); + std::cout << std::endl; + } + } + AstGraph graph(module); + graph.DumpGraph("After BasicAnalysis()", &std::cout); + } + } + + if (mFlags & FLG_trace_3) { + gStringPool.Dump(); + } + + gStringPool.SetAltStrIdxMap(); + + if (mFlags & FLG_trace_3) { + gStringPool.Dump(); + gStringPool.DumpAlt(); + } + + gStringPool.SetUseAltStr(true); + + for (auto handler: mHandlersInOrder) { + ModuleNode *module = handler->GetASTModule(); + + std::cout << "============= Emitter ===========" << std::endl; + maplefe::Emitter emitter(handler); + std::string code = emitter.Emit("Convert AST to TypeScript code"); + + // Emit to file + std::string of_name(module->GetFilename()); + of_name += ".obf"; + std::ofstream ofs; + ofs.open(of_name.c_str(), std::ofstream::out); + ofs << code; + ofs.close(); + } + + return 0; +} + +} // namespace maplefe diff --git a/src/MapleFE/typescript/Makefile b/src/MapleFE/typescript/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..266eec091a2e64f82189cca8c5f43e40f0207878 --- /dev/null +++ b/src/MapleFE/typescript/Makefile @@ -0,0 +1,26 @@ +# Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +include ../Makefile.in + +TARGS = ts2cpp + +$(TARGS): + $(MAKE) -C src + +clean: + rm -rf $(BUILDDIR)/typescript + +.PHONY: $(TARGS) + diff --git a/src/MapleFE/java/local_var.spec b/src/MapleFE/typescript/attr.spec similarity index 41% rename from src/MapleFE/java/local_var.spec rename to src/MapleFE/typescript/attr.spec index 3c7d8ac3c032e56b8eb60d2abe453cf12aa4869c..a632ede282f8dc13a14de62879ffafb1afacd429 100644 --- a/src/MapleFE/java/local_var.spec +++ b/src/MapleFE/typescript/attr.spec @@ -12,29 +12,29 @@ # See the Mulan PSL v2 for more details. # ################################################################################### -# This file defines the Java Local Variable declaration. +# This file defines the Attribute, Modifier, or any other terms which are used +# to describe some features of certian syntax component. # +# The keyword duplex is defined as <"keyword", AttributeId>. The AttributeId is defined +# in shared/supported_attributes.def and included in shared/supported.h. The 'keyword' +# is the keyword in a language defining that specific attribute. ################################################################################### -####include "type.spec" -###rule VariableModifier: (one of) Annotation final -rule VariableModifier: "final" +STRUCT Attribute : (("abstract", abstract), + ("const", const), + ("volatile", volatile), + ("final", final), + ("native", native), + ("private", private), + ("protected", protected), + ("public", public), + ("readonly", readonly), + ("static", static), + ("strictfp", strictfp), + ("default", default), + ("get", getter), + ("set", setter), + ("async", async), + ("synchronized", synchronized)) -#rule VariableDeclarator : VariableDeclaratorId + ZEROORONE('=' + VariableInitializer) -rule VariableDeclarator : VariableDeclaratorId -rule VariableDeclaratorList : VariableDeclarator + ZEROORMORE(',' + VariableDeclarator) - -###rule VariableDeclaratorId : Identifier [Dims] -rule VariableDeclaratorId : Identifier - -#rule UnannPrimitiveType : ONEOF(NumericType, Boolean) -rule UnannPrimitiveType : ONEOF("int", "boolean") - -###rule UnannType : ONEOF(UnannPrimitiveType, UnannReferenceType) -rule UnannType : ONEOF(UnannPrimitiveType) - -###rule LocalVariableDeclaration : ZEROORMORE(VariableModifier) + UnannType + VariableDeclaratorList -rule LocalVariableDeclaration : UnannType + VariableDeclaratorList - -rule LocalVariableDeclarationStatement : LocalVariableDeclaration + ';' diff --git a/src/MapleFE/typescript/identifier.spec b/src/MapleFE/typescript/identifier.spec new file mode 100644 index 0000000000000000000000000000000000000000..5723b480b3cd59e04d86d6d935f9bd949971c926 --- /dev/null +++ b/src/MapleFE/typescript/identifier.spec @@ -0,0 +1,20 @@ +# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +# An identifier is an unlimited-length sequence of Java letters and Java digits, the +# first of which must be a Java letter +# +rule JavaChar : ONEOF(CHAR, '_' , '$') +rule CharOrDigit : ONEOF(JavaChar, DIGIT) +rule Identifier : ONEOF("no-default-lib", + JavaChar + ZEROORMORE(CharOrDigit)) diff --git a/src/MapleFE/typescript/include/lang_builtin.def b/src/MapleFE/typescript/include/lang_builtin.def new file mode 100644 index 0000000000000000000000000000000000000000..791452525da5c9d65a88608d27840c712bfd885e --- /dev/null +++ b/src/MapleFE/typescript/include/lang_builtin.def @@ -0,0 +1,66 @@ +// Copyright (C) [2022] Futurewei Technologies, Inc. All rights reverved. +// +// OpenArkFE is licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// + +// refer to docs/builtin-constructors.md + +// javascript builtin object types +BUILTIN(AggregateError) +BUILTIN(Array) +BUILTIN(ArrayBuffer) +BUILTIN(AsyncFunction) +BUILTIN(BigInt64Array) +BUILTIN(BigUint64Array) +BUILTIN(Boolean) +BUILTIN(DataView) +BUILTIN(Date) +BUILTIN(Error) +BUILTIN(EvalError) +BUILTIN(FinalizationRegistry) +BUILTIN(Float32Array) +BUILTIN(Float64Array) +BUILTIN(Function) +BUILTIN(Generator) +BUILTIN(GeneratorFunction) +BUILTIN(Int16Array) +BUILTIN(Int32Array) +BUILTIN(Int8Array) +BUILTIN(InternalError (Mozilla only)) +BUILTIN(Map) +BUILTIN(Number) +BUILTIN(Object) +BUILTIN(Promise) +BUILTIN(Proxy) +BUILTIN(RangeError) +BUILTIN(ReferenceError) +BUILTIN(RegExp) +BUILTIN(Set) +BUILTIN(SharedArrayBuffer) +BUILTIN(String) +BUILTIN(Symbol) +BUILTIN(SyntaxError) +BUILTIN(TypeError) +BUILTIN(Uint16Array) +BUILTIN(Uint32Array) +BUILTIN(Uint8Array) +BUILTIN(Uint8ClampedArray) +BUILTIN(URIError) +BUILTIN(WeakMap) +BUILTIN(WeakRef) +BUILTIN(WeakSet) + +// typescript builtin object types +BUILTIN(Record) +BUILTIN(Tuple) +BUILTIN(Iterable) +BUILTIN(Iterator) diff --git a/src/MapleFE/typescript/include/lang_keywords.def b/src/MapleFE/typescript/include/lang_keywords.def new file mode 100644 index 0000000000000000000000000000000000000000..096966bd2bc2907809676225773b9e3120929021 --- /dev/null +++ b/src/MapleFE/typescript/include/lang_keywords.def @@ -0,0 +1,122 @@ +// Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +// +// OpenArkFE is licensed under the Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// +// http://license.coscl.org.cn/MulanPSL2 +// +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// + +LANGKEYWORD(boolean) +LANGKEYWORD(number) +LANGKEYWORD(string) +LANGKEYWORD(symbol) +LANGKEYWORD(unique) +LANGKEYWORD(any) +LANGKEYWORD(unknown) +LANGKEYWORD(never) +LANGKEYWORD(undefined) +LANGKEYWORD(type) + +LANGKEYWORD(get) +LANGKEYWORD(set) +LANGKEYWORD(as) +LANGKEYWORD(from) +LANGKEYWORD(constructor) +LANGKEYWORD(namespace) +LANGKEYWORD(module) +LANGKEYWORD(declare) + +LANGKEYWORD(break) +LANGKEYWORD(do) +LANGKEYWORD(in) +LANGKEYWORD(is) +LANGKEYWORD(of) +LANGKEYWORD(typeof) +LANGKEYWORD(keyof) +LANGKEYWORD(infer) +LANGKEYWORD(case) +LANGKEYWORD(else) +LANGKEYWORD(instanceof) +LANGKEYWORD(var) +LANGKEYWORD(catch) +LANGKEYWORD(export) +LANGKEYWORD(new) +LANGKEYWORD(void) +LANGKEYWORD(class) +LANGKEYWORD(extends) +LANGKEYWORD(return) +LANGKEYWORD(while) +LANGKEYWORD(const) +LANGKEYWORD(finally) +LANGKEYWORD(super) +LANGKEYWORD(with) +LANGKEYWORD(continue) +LANGKEYWORD(for) +LANGKEYWORD(switch) +LANGKEYWORD(yield) +LANGKEYWORD(debugger) +LANGKEYWORD(function) +// LANGKEYWORD(this) +LANGKEYWORD(default) +LANGKEYWORD(if) +LANGKEYWORD(throw) +LANGKEYWORD(delete) +LANGKEYWORD(import) +LANGKEYWORD(require) +LANGKEYWORD(try) +LANGKEYWORD(asserts) + +LANGKEYWORD(let) +LANGKEYWORD(static) +LANGKEYWORD(implements) +LANGKEYWORD(protected) +LANGKEYWORD(interface) +LANGKEYWORD(private) +LANGKEYWORD(public) +LANGKEYWORD(abstract) + +LANGKEYWORD(readonly) + +LANGKEYWORD(enum) +LANGKEYWORD(await) +LANGKEYWORD(async) + +LANGKEYWORD(global) + +// Utility Types +LANGKEYWORD(Partial) +LANGKEYWORD(Required) +LANGKEYWORD(Readonly) +LANGKEYWORD(Record) +LANGKEYWORD(Pick) +LANGKEYWORD(Omit) +LANGKEYWORD(Exclude) +LANGKEYWORD(Extract) +LANGKEYWORD(NonNullable) +LANGKEYWORD(Parameters) +LANGKEYWORD(ConstructorParameters) +LANGKEYWORD(ReturnType) +LANGKEYWORD(InstanceType) +LANGKEYWORD(ThisParameterType) +LANGKEYWORD(OmitThisParameter) +LANGKEYWORD(ThisType) +LANGKEYWORD(Uppercase) +LANGKEYWORD(Lowercase) +LANGKEYWORD(Capitalize) +LANGKEYWORD(Uncapitalize) + +LANGKEYWORD(Error) +LANGKEYWORD(toString) + +// extra + +LANGKEYWORD(console) +LANGKEYWORD(log) + +LANGKEYWORD(null) diff --git a/src/MapleFE/typescript/include/lang_spec.h b/src/MapleFE/typescript/include/lang_spec.h new file mode 100644 index 0000000000000000000000000000000000000000..96aef8bf12195fd32df8cf8630e6beb6632f8c9a --- /dev/null +++ b/src/MapleFE/typescript/include/lang_spec.h @@ -0,0 +1,68 @@ +/* +* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ +///////////////////////////////////////////////////////////////////////////////// +// Language Specific Implementations // +///////////////////////////////////////////////////////////////////////////////// + +#ifndef __LANG_SPEC_H__ +#define __LANG_SPEC_H__ + +#include "stringutil.h" +#include "token.h" +#include "lexer.h" +#include "parser.h" + +namespace maplefe { + +class StringToValueImpl : public StringToValue { +public: + float StringToFloat(std::string &s); + double StringToDouble(std::string &s); + bool StringToBool(std::string &s); + Char StringToChar(std::string &s); + bool StringIsNull(std::string &s); + const char* StringToString(std::string &); +}; + +extern LitData ProcessLiteral(LitId type, const char *str); + +//////////////////////////////////////////////////////////////////////////////////// +// Typescript Lexer +//////////////////////////////////////////////////////////////////////////////////// + +class TypescriptLexer : public Lexer { +public: + bool CharIsSeparator(const char); + + TempLitData* GetTempLit(); + bool FindNextTLFormat(unsigned start, std::string& s, unsigned& end); + bool FindNextTLPlaceHolder(unsigned start, std::string& s, unsigned& end); + bool FindTripleSlash(); +}; + +//////////////////////////////////////////////////////////////////////////////////// +// Typescript Parser +//////////////////////////////////////////////////////////////////////////////////// + +class TypescriptParser : public Parser { +public: + TypescriptParser(const char *f) : Parser(f) {} + Token* GetRegExpr(Token *t); + bool TokenSplit(Token *); + bool TraverseASI(RuleTable*, AppealNode*, AppealNode *&); +}; + +} +#endif diff --git a/src/MapleFE/typescript/keyword.spec b/src/MapleFE/typescript/keyword.spec new file mode 100644 index 0000000000000000000000000000000000000000..cbc04c0c4085bb06aed62e0ae3c951f539f7f4ec --- /dev/null +++ b/src/MapleFE/typescript/keyword.spec @@ -0,0 +1,104 @@ +# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +################################################################################## +# This file contains the keyword of a language. It doesn't clarify the semantics +# of a keyword, which will be done by RULEs, i.e., the parser will check the keyword +# while traversing the rule tables. +# +# The generated table of keywords are only used for +# (1) Parser to check while traversing rule tables +# (2) check the correctness of names so as not to conflict with keywords +################################################################################## + +STRUCT KeyWord : ((boolean), + (number), + (string), + (symbol), + (unique), + (any), + (unknown), + (never), + (undefined), + (type), + + (get), + (set), + (as), + (from), + (constructor), + (namespace), + (module), + (declare), + + (break), + (do), + (in), + (is), + (of), + (typeof), + (keyof), + (infer), + (case), + (else), + (instanceof), + (var), + (catch), + (export), + (new), + (void), + (class), + (extends), + (return), + (while), + (const), + (finally), + (super), + (with), + (continue), + (for), + (switch), + (yield), + (debugger), + (function), + (this), + (default), + (if), + (throw), + (delete), + (import), + (require), + (try), + (asserts), + +#this part is for strict mode + (let), + (static), + (implements), + (protected), + (interface), + (private), + (public), + (abstract), + + (readonly), + +#this part is for future reserved + (enum), + (await), + (async), + + (global), + +#this is for 'fake rule only' + (this_is_for_fake_rule)) diff --git a/src/MapleFE/typescript/literal.spec b/src/MapleFE/typescript/literal.spec new file mode 100644 index 0000000000000000000000000000000000000000..c2d61bb1213c8138ac01d449458ab29f0cba73b7 --- /dev/null +++ b/src/MapleFE/typescript/literal.spec @@ -0,0 +1,158 @@ +# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +# A literal is the source code representation of a value of a primitive type, the +# String type, or the null type. +# +# NOTE: Make sure there is a 'rule Literal'. This is the official rule recognized +# by autogen. + +######################################################################### +## Integer ## +######################################################################### + +### Decimal rules + +rule NonZeroDigit : ONEOF('1', '2', '3', '4', '5', '6', '7', '8', '9') +rule Underscores : '_' + ZEROORMORE('_') +rule Digit : ONEOF('0', NonZeroDigit) +rule DigitOrUnderscore : ONEOF(Digit, '_') +rule DigitsAndUnderscores : DigitOrUnderscore + ZEROORMORE(DigitOrUnderscore) +rule Digits : ONEOF(Digit, Digit + ZEROORONE(DigitsAndUnderscores) + Digit) + attr.property.%2 : SecondTry + +rule DecimalNumeral : ONEOF('0', NonZeroDigit + ZEROORONE(Digits), + NonZeroDigit + Underscores + Digits) + +### Hexadecimal rules + +rule HexDigit : ONEOF('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', + 'A', 'B', 'C', 'D', 'E', 'F') +rule HexDigitOrUnderscore : ONEOF(HexDigit, '_') +rule HexDigitsAndUnderscores:HexDigitOrUnderscore + ZEROORMORE(HexDigitOrUnderscore) +rule HexDigits : ONEOF(HexDigit, + HexDigit + ZEROORONE(HexDigitsAndUnderscores) + HexDigit) + attr.property.%2 : SecondTry +rule HexNumeral : ONEOF("0x" + HexDigits, "0X" + HexDigits) + +### Octal rules + +rule OctalDigit : ONEOF('0', '1', '2', '3', '4', '5', '6', '7') +rule OctalDigitOrUnderscore : ONEOF(OctalDigit, '_') +rule OctalDigitsAndUnderscores:OctalDigitOrUnderscore + ZEROORMORE(OctalDigitOrUnderscore) +rule OctalDigits : ONEOF(OctalDigit, + OctalDigit + ZEROORONE(OctalDigitsAndUnderscores) + OctalDigit) + attr.property.%2 : SecondTry +rule OctalNumeral : ONEOF('0' + OctalDigits, '0' + Underscores + OctalDigits) + +### Binary rules + +rule BinDigit : ONEOF('0', '1') +rule BinDigitOrUnderscore : ONEOF(BinDigit, '_') +rule BinDigitsAndUnderscores:BinDigitOrUnderscore + ZEROORMORE(BinDigitOrUnderscore) +rule BinDigits : ONEOF(BinDigit, + BinDigit + ZEROORONE(BinDigitsAndUnderscores) + BinDigit) + attr.property.%2 : SecondTry +rule BinNumeral : ONEOF("0b" + BinDigits, "0B" + BinDigits) + +########## + +rule IntegerTypeSuffix : ONEOF('L', 'l') + +rule DecimalIntegerLiteral: DecimalNumeral + ZEROORONE(IntegerTypeSuffix) +rule HexIntegerLiteral : HexNumeral + ZEROORONE(IntegerTypeSuffix) +rule OctalIntegerLiteral : OctalNumeral + ZEROORONE(IntegerTypeSuffix) +rule BinaryIntegerLiteral : BinNumeral + ZEROORONE(IntegerTypeSuffix) + +rule IntegerLiteral: ONEOF(DecimalIntegerLiteral, + HexIntegerLiteral, + OctalIntegerLiteral, + BinaryIntegerLiteral) + +######################################################################### +## Floating Point ## +######################################################################### + +##### Decimal floating point literal + +rule Sign : ONEOF('+', '-') +rule FloatTypeSuffix : ONEOF('f', 'F', 'd', 'D') +rule ExponentIndicator : ONEOF('e', 'E') +rule SignedInteger : ZEROORONE(Sign) + Digits +rule ExponentPart : ExponentIndicator + SignedInteger + +rule DecFPLiteral : ONEOF(Digits + '.' + ZEROORONE(Digits) + ZEROORONE(ExponentPart) + ZEROORONE(FloatTypeSuffix), + '.'+Digits + ZEROORONE(ExponentPart) + ZEROORONE(FloatTypeSuffix), + Digits + ExponentPart + ZEROORONE(FloatTypeSuffix), + Digits + ZEROORONE(ExponentPart)) + +####### Hex floating point literal + +rule BinaryExponentIndicator : ONEOF('p', 'P') +rule BinaryExponent : BinaryExponentIndicator + SignedInteger +rule HexSignificand : ONEOF(HexNumeral + ZEROORONE('.'), + "0x" + ZEROORONE(HexDigits) + '.' + HexDigits, + "0X" + ZEROORONE(HexDigits) + '.' + HexDigits) +rule HexFPLiteral: HexSignificand + BinaryExponent + ZEROORONE(FloatTypeSuffix) + +###### Floating POint Literal + +rule FPLiteral : ONEOF(DecFPLiteral, HexFPLiteral) + +######################################################################### +## Boolean ## +######################################################################### + +rule BooleanLiteral : ONEOF ("true", "false") + +######################################################################### +## Character ## +## ESCAPE is a reserved rule in reserved.spec. ## +######################################################################### + +# I decided to simplify the unicode escape a little bit. I don't want to +# handle all odd cases. +rule UnicodeEscape: '\' + 'u' + HEXDIGIT + HEXDIGIT + HEXDIGIT + HEXDIGIT +rule RawInputCharacter : ONEOF(ASCII, ESCAPE, UTF8) +rule SingleCharacter: ONEOF(UnicodeEscape, RawInputCharacter) + +rule OctalEscape : ONEOF('\' + '0', '\' + '1') +rule EscapeSequence : ONEOF(ESCAPE, OctalEscape) +rule CharacterLiteral : ''' + ONEOF(SingleCharacter, EscapeSequence) + ''' + +######################################################################### +## String ## +######################################################################### +# The UnicodeEscape is limited from \u0000 to \u00ff. +rule StringUnicodeEscape: '\' + 'u' + '0' + '0' + HEXDIGIT + HEXDIGIT +rule SingleStringCharater: ONEOF(StringUnicodeEscape, RawInputCharacter, IRREGULAR_CHAR, '"') +rule DoubleStringCharater: ONEOF(StringUnicodeEscape, RawInputCharacter, IRREGULAR_CHAR, ''') +rule StringLiteral : ONEOF('"' + ZEROORMORE(DoubleStringCharater) + '"', + ''' + ZEROORMORE(SingleStringCharater) + ''') + +######################################################################### +## Null ## +######################################################################### + +rule NullLiteral : "null" + +######################################################################### +## Literal ## +######################################################################### + +rule Literal : ONEOF(IntegerLiteral, + FPLiteral, + BooleanLiteral, + StringLiteral, + NullLiteral) diff --git a/src/MapleFE/typescript/operator.spec b/src/MapleFE/typescript/operator.spec new file mode 100644 index 0000000000000000000000000000000000000000..d09db223d3cdc7069e1300fde8861a08f6ff9b8d --- /dev/null +++ b/src/MapleFE/typescript/operator.spec @@ -0,0 +1,79 @@ +# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +########################################################################## +# The syntax of operator.spec contains two parts. +# 1. The Keyword STRUCT defining the of all operations. +# keyword : the text defined in the language +# opr : the standard Autogen defined operator. +# See autogen/include/supported_operators.def +# 2. The rule part, defining the language restrictions of each operator. +########################################################################## + +# NOTE +# Some languages could have one synatx belonging to both separator and operators. +# eg., ':' in Java 8, it's both a separator colon and operator select. +# We need avoid such duplication in .spec files. + +STRUCT Operator : ( + # Arithmetic + ("+", Add), + ("-", Sub), + ("*", Mul), + ("/", Div), + ("%", Mod), + ("++", Inc), + ("--", Dec), + ("**", Exp), + ("??", NullCoalesce), + ("??=", NullAssign), + # Relation + ("==", EQ), + ("!=", NE), + (">", GT), + ("<", LT), + (">=", GE), + ("<=", LE), + ("===", StEq), + ("!==", StNe), + # Bitwise + ("&", Band), + ("|", Bor), + ("^", Bxor), + ("~", Bcomp), + # Shift + ("<<", Shl), + (">>", Shr), + (">>>", Zext), + # Logical + ("&&", Land), + ("||", Lor), + ("!", Not), + # Assign + ("=", Assign), + ("+=", AddAssign), + ("-=", SubAssign), + ("*=", MulAssign), + ("/=", DivAssign), + ("%=", ModAssign), + ("<<=", ShlAssign), + (">>=", ShrAssign), + ("&=", BandAssign), + ("|=", BorAssign), + ("^=", BxorAssign), + (">>>=", ZextAssign), + + ("///", TripleSlash), + + # arrow function + ("=>", ArrowFunction)) diff --git a/src/MapleFE/typescript/separator.spec b/src/MapleFE/typescript/separator.spec new file mode 100644 index 0000000000000000000000000000000000000000..b06a949337eb48de6e69c481724f8b14af47f545 --- /dev/null +++ b/src/MapleFE/typescript/separator.spec @@ -0,0 +1,45 @@ +# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +# NOTE - 1 +# +# This file defines the separator. The separators are defined using a STRUCT. +# Each separator in this STRUCT is a set of 2 elements. +# STRUCT Separator : ( ("(", LeftParenthesis), +# (")", RightParenthesis), +# The first element is the literal name of separator, it needs to be a string +# The second is the ID of the separator. Please check shared/include/supported_separators.def +# to see the supported separator ID. + +# NOTE - 2 +# Some languages could have one synatx belonging to both separator and operators. +# eg., ':' in Java 8, it's both a separator colon and operator select. +# We need avoid such duplication in .spec files. + +STRUCT Separator : ((" ", Whitespace), + ("(", Lparen), + (")", Rparen), + ("{", Lbrace), + ("}", Rbrace), + ("[", Lbrack), + ("]", Rbrack), + (";", Semicolon), + (",", Comma), + (".", Dot), + ("...", Dotdotdot), + (":", Colon), + ("?", Select), + ("?.",Optional), + ("@", At), + ("#", Pound), + ("\t", Tab)) diff --git a/src/MapleFE/typescript/src/Makefile b/src/MapleFE/typescript/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..392dc308bc7852a4e8b14578efad9d2f52306413 --- /dev/null +++ b/src/MapleFE/typescript/src/Makefile @@ -0,0 +1,80 @@ +# Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +include ../../Makefile.in +BUILDBIN=$(BUILDDIR)/bin +BUILD=$(BUILDDIR)/typescript +BUILDGEN=$(BUILDDIR)/gen +BUILDASTGEN=$(BUILDDIR)/ast_gen/shared +$(shell $(MKDIR_P) $(BUILD) $(BUILDGEN)) + +SRC=$(wildcard *.cpp) +OBJ :=$(patsubst %.cpp,%.o,$(SRC)) +DEP :=$(patsubst %.cpp,%.d,$(SRC)) + +SRCG := $(wildcard $(BUILDGEN)/gen*.cpp) +OBJG := $(patsubst %.cpp, %.o, $(SRCG)) +DEPG := $(patsubst %.cpp, %.d, $(SRCG)) + +OBJS :=$(foreach obj,$(OBJ), $(BUILD)/$(obj)) $(OBJG) +DEPS :=$(foreach dep,$(DEP), $(BUILD)/$(dep)) $(DEPG) + +INCLUDES := -I $(MAPLEFE_ROOT)/shared/include \ + -I $(MAPLEFE_ROOT)/typescript/include \ + -I $(MAPLEFE_ROOT)/autogen/include \ + -I ${BUILDDIR}/ast_gen/shared \ + -I $(BUILDGEN) + +INCLUDEGEN := -I $(BUILDGEN) -I $(MAPLEFE_ROOT)/shared/include + +TARGET=ts2ast + +SHAREDLIB = $(BUILDDIR)/shared/shared.a $(BUILDASTGEN)/genast.a + +.PHONY: all +all: $(BUILDBIN)/$(TARGET) + +-include $(DEPS) +.PHONY: clean + +vpath %.o $(BUILD) +vpath %.d $(BUILD) + +# Pattern Rules +$(BUILD)/%.o : %.cpp + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDES) -w -c $< -o $@ + +$(BUILD)/%.d : %.cpp + @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDES) $< > $@ + @mv -f $(BUILD)/$*.d $(BUILD)/$*.d.tmp + @sed -e 's|.*:|$(BUILD)/$*.o:|' < $(BUILD)/$*.d.tmp > $(BUILD)/$*.d + @rm -f $(BUILD)/$*.d.tmp + +$(BUILDGEN)/%.o : $(BUILDGEN)/%.cpp $(BUILDGEN)/%.d + $(CXX) $(CXXFLAGS) -fpermissive $(INCLUDEGEN) -w -c $< -o $@ + +$(BUILDGEN)/%.d : $(BUILDGEN)/%.cpp + @$(CXX) $(CXXFLAGS) -std=c++11 -MM $(INCLUDEGEN) $< > $@ + @mv -f $(BUILDGEN)/$*.d $(BUILDGEN)/$*.d.tmp + @sed -e 's|.*:|$(BUILDGEN)/$*.o:|' < $(BUILDGEN)/$*.d.tmp > $(BUILDGEN)/$*.d + @rm -f $(BUILDGEN)/$*.d.tmp + +# TARGET depends on OBJS and shared OBJS from shared directory +# as well as mapleall libraries +$(BUILDBIN)/$(TARGET): $(OBJS) $(SHAREDLIB) + @mkdir -p $(BUILDBIN) + $(LD) -o $(BUILDBIN)/$(TARGET) $(OBJS) $(SHAREDLIB) + +clean: + rm -rf $(BUILD) diff --git a/src/MapleFE/typescript/src/lang_spec.cpp b/src/MapleFE/typescript/src/lang_spec.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d51d1f312d0184badb28eac07e422c6a24a65632 --- /dev/null +++ b/src/MapleFE/typescript/src/lang_spec.cpp @@ -0,0 +1,661 @@ +/* +* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ +#include "lang_spec.h" +#include "stringpool.h" + +namespace maplefe { + +// For all the string to value functions below, we assume the syntax of 's' is correct +// for a literal in Java. + +float StringToValueImpl::StringToFloat(std::string &s) { + return stof(s); +} + +// Java use 'd' or 'D' as double suffix. C++ use 'l' or 'L'. +double StringToValueImpl::StringToDouble(std::string &s) { + std::string str = s; + char suffix = str[str.length() - 1]; + if (suffix == 'd' || suffix == 'D') + str[str.length() - 1] = 'L'; + return stod(str); +} + +bool StringToValueImpl::StringToBool(std::string &s) { + if ((s.size() == 4) && (s.compare("true") == 0)) + return true; + else if ((s.size() == 5) && (s.compare("false") == 0)) + return false; + else + MERROR("unknown bool literal"); +} + +bool StringToValueImpl::StringIsNull(std::string &s) {return false;} + +const char* StringToValueImpl::StringToString(std::string &in_str) { + std::string target; + + // For most languages, the input 'in_str' still contains the leading " or ' and the + // ending " or '. They need to be removed. + std::string str; + + // If empty string literal, return the empty 'target'. + if (in_str.size() == 2) { + const char *s = gStringPool.FindString(target); + return s; + } else { + str.assign(in_str, 1, in_str.size() - 2); + } + + // For typescript, if a string literal is: + // s : string = "abc \ + // efg"; + // The \ is actually connnecting the next line into the string literal. + // We need handle the connection. + + std::string s_ret; + for (unsigned i = 0; i < str.length(); i++) { + char c = str[i]; + if (c == '\\') { + if ((i < str.length() - 1) && (str[i+1] == '\n')) { + // skip \ and \n + i += 1; + continue; + } + } + s_ret.push_back(c); + } + + const char *s = gStringPool.FindString(s_ret); + return s; +} + +static char DeEscape(char c) { + switch(c) { + case 'b': + return '\b'; + case 't': + return '\t'; + case 'n': + return '\n'; + case 'f': + return '\f'; + case 'r': + return '\r'; + case '"': + return '\"'; + case '\'': + return '\''; + case '\\': + return '\\'; + case '0': + return '\0'; + default: + MERROR("Unsupported in DeEscape()."); + } +} + +static int char2int(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else + MERROR("Unsupported char in char2int()."); +} + +Char StringToValueImpl::StringToChar(std::string &s) { + Char ret_char; + ret_char.mIsUnicode = false; + MASSERT (s[0] == '\''); + if (s[1] == '\\') { + if (s[2] == 'u') { + ret_char.mIsUnicode = true; + int first = char2int(s[3]); + int second = char2int(s[4]); + int third = char2int(s[5]); + int forth = char2int(s[6]); + MASSERT(s[7] == '\''); + ret_char.mData.mUniValue = (first << 12) + (second << 8) + + (third << 4) + forth; + } else { + ret_char.mData.mChar = DeEscape(s[2]); + } + } else { + MASSERT(s[2] == '\''); + ret_char.mData.mChar = s[1]; + } + return ret_char; +} + +// Each language has its own format of literal. So this function handles Typescript literals. +// It translate a string into a literal. +// +// 'str' is in the Lexer's string pool. +// +LitData ProcessLiteral(LitId id, const char *str) { + LitData data; + std::string value_text(str); + StringToValueImpl s2v; + + switch (id) { + case LT_IntegerLiteral: { + long l = s2v.StringToLong(value_text); + data.mType = LT_IntegerLiteral; + data.mData.mInt = l; + break; + } + case LT_FPLiteral: { + // Java spec doesn't define rules for double. Both float and double + // are covered by Float Point. But we need differentiate here. + // Check if it's a float of double. Non-suffix means double. + char suffix = value_text[value_text.length() - 1]; + if (suffix == 'f' || suffix == 'F') { + float f = s2v.StringToFloat(value_text); + data.mType = LT_FPLiteral; + data.mData.mFloat = f; + } else { + double d = s2v.StringToDouble(value_text); + data.mType = LT_DoubleLiteral; + data.mData.mDouble = d; + } + break; + } + case LT_BooleanLiteral: { + bool b = s2v.StringToBool(value_text); + data.mType = LT_BooleanLiteral; + data.mData.mBool = b; + break; } + case LT_CharacterLiteral: { + Char c = s2v.StringToChar(value_text); + data.mType = LT_CharacterLiteral; + data.mData.mChar = c; + break; } + case LT_StringLiteral: { + const char *s = s2v.StringToString(value_text); + data.mType = LT_StringLiteral; + data.mData.mStrIdx = gStringPool.GetStrIdx(s); + break; } + case LT_NullLiteral: { + // Just need set the id + data.mType = LT_NullLiteral; + break; } + case LT_NA: // N/A, + default: + data.mType = LT_NA; + break; + } + + return data; +} + +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// +// Implementation of typescript Lexer +///////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////// + +bool TypescriptLexer::CharIsSeparator(const char c) { + if (c == '`') + return true; + return false; +} + +// NOTE: right now we rely on 'tsc' to assure the input is legal, +// so I'll make many things easier and will skip many lexical +// checks. Just make it easy for now. +// Also, I assume we don't handle multiple line template literal +// for the time being. +TempLitData* TypescriptLexer::GetTempLit() { + TempLitData *tld = NULL; + unsigned old_cur_idx = curidx; + + if (line[curidx] == '`') { + // It's certain that this is a template literal because tsc assures it. + tld = new TempLitData; + + unsigned start_idx; + unsigned end_idx; + start_idx = curidx + 1; + while(1) { + // Try string + end_idx = 0; + std::string fmt_str = ""; + bool s_found = FindNextTLFormat(start_idx, fmt_str, end_idx); + const char *addr = NULL; + if (s_found) { + MASSERT(fmt_str.size() > 0 && "found token has 0 data?"); + addr = gStringPool.FindString(fmt_str); + start_idx = end_idx + 1; + } + + // Try pattern + end_idx = 0; + const char *addr_ph = NULL; + std::string pl_str = ""; + bool p_found = FindNextTLPlaceHolder(start_idx, pl_str, end_idx); + if (p_found) { + unsigned len = pl_str.size(); + MASSERT(len > 0 && "found token has 0 data?"); + addr_ph = gStringPool.FindString(pl_str); + // We need skip the ending '}' of a pattern. + start_idx = end_idx + 2; + } + + // If both string and pattern failed to be found + if (!s_found && !p_found) { + break; + } else { + tld->mStrings.PushBack(addr); + tld->mStrings.PushBack(addr_ph); + } + } + + // It's for sure that this is the ending '`'. + MASSERT(line[start_idx] == '`'); + curidx = start_idx + 1; + } + + return tld; +} + +// Find the pure string of a template literal. +// Set end_idx as the last char of string. +bool TypescriptLexer::FindNextTLFormat(unsigned start_idx, std::string &str, unsigned& end_idx) { + unsigned working_idx = start_idx; + while(1) { + if ((line[working_idx] == '$' && line[working_idx+1] == '{') + || line[working_idx] == '`' ){ + end_idx = working_idx - 1; + break; + } + + // Template Literal allows \n in format and place holder. + // the \n was removed by Lexer in the beginning of ReadALine(); + if (working_idx == current_line_size) { + str += '\n'; + ReadALine(); + if (endoffile) + return false; + working_idx = 0; + continue; + } + + str += line[working_idx]; + working_idx++; + } + + if (str.size() > 0) + return true; + else + return false; +} + +// Find the pattern string of a template literal. +// Set end_idx as the last char of string. +// +// [NOTE] For nested template literals, we will matching the outmost +// template literal and treat the inner template literal as +// a plain string. The innter template literal will later +// be handled by the parsing of the outmost template literal. +// This makes things easier. +// +// [NOTE] We only support two level of nesting temp lit !! + +bool TypescriptLexer::FindNextTLPlaceHolder(unsigned start_idx, std::string& str, unsigned& end_idx) { + unsigned working_idx = start_idx; + if (line[working_idx] != '$' || line[working_idx+1] != '{') + return false; + + working_idx = start_idx + 2; + + // There could be {..} inside placeholder. + unsigned num_left_brace = 0; + + // There could be string literal inside placeholder, + bool in_string_literal = false; + + // There could be nested template literal inside a place holder. + bool in_nested_temp_lit = false; + bool waiting_right_brace = false; + unsigned num_left_brace_inner = 0; // there could be {..} for inner temp lit. + + while(1) { + + if (line[working_idx] == '`') { + if (in_nested_temp_lit) { + // finish inner temp lit. Need clear the status. + in_nested_temp_lit = false; + num_left_brace_inner = 0; + } else { + in_nested_temp_lit = true; + } + } else if (line[working_idx] == '$' && line[working_idx+1] == '{') { + MASSERT(in_nested_temp_lit); + str += line[working_idx]; + str += line[working_idx + 1]; + working_idx += 2; + waiting_right_brace = true; + continue; + } else if (line[working_idx] == '\'' || line[working_idx] == '\"') { + in_string_literal = in_string_literal ? false : true; + } else if (line[working_idx] == '{') { + if (!in_string_literal) { + if (in_nested_temp_lit) + num_left_brace_inner++; + else + num_left_brace++; + } + } else if (line[working_idx] == '}') { + if (!in_string_literal) { + if (waiting_right_brace) + waiting_right_brace = false; + else if (!in_nested_temp_lit && num_left_brace > 0) + num_left_brace--; + else if (in_nested_temp_lit && num_left_brace_inner > 0) + num_left_brace_inner--; + else + break; + } + } + + // Template Literal allows \n in format and place holder. + // the \n was removed by Lexer in the beginning of ReadALine(); + // + // I don't need worry about if the template literal is ended or not, + // since tsc guarantees it's correct. + if (working_idx == current_line_size) { + str += '\n'; + ReadALine(); + if (endoffile) + return false; + working_idx = 0; + } else { + str += line[working_idx]; + working_idx++; + } + } + + end_idx = working_idx - 1; + return true; +} + +// This is to catch TS triple-slash directives : /// IsOperator()) + return t; + + if (t->GetOprId() != OPR_Div) + return t; + + unsigned size = mActiveTokens.GetNum(); + if (size < 2) + return t; + + // We take care of only the following scenarios. + // If more need support, we will add later. + // (/abc*/g, ) + // [/abc*/g, ] + // =/abc*/g; + // && /abc*/g; + // ,/abc*/g; + // : /abc*/g; + // || /abc*/g; + + Token *sep = mActiveTokens.ValueAtIndex(size - 1); + bool is_sep = false; + if (sep->IsSeparator() && (sep->GetSepId() == SEP_Lparen)) + is_sep = true; + if (sep->IsSeparator() && (sep->GetSepId() == SEP_Lbrack)) + is_sep = true; + if (sep->IsSeparator() && (sep->GetSepId() == SEP_Comma)) + is_sep = true; + if (sep->IsSeparator() && (sep->GetSepId() == SEP_Colon)) + is_sep = true; + if (sep->IsOperator() && (sep->GetOprId() == OPR_Assign)) + is_sep = true; + if (sep->IsOperator() && (sep->GetOprId() == OPR_Land)) + is_sep = true; + if (sep->IsOperator() && (sep->GetOprId() == OPR_Lor)) + is_sep = true; + if (!is_sep) + return t; + + Token *regexpr = mLexer->FindRegExprToken(); + if (regexpr) + t = regexpr; + + return t; +} + +// return true if t should be split into multiple tokens. +// [NOTE] t is not push into mActiveTokens yet. +// +// We will handle these cases specifically. +// +// We take care of only one scenarios right now.. +// typename= initval +// Look at the '>='. It first recognazied by lexer as GE, +// but it's actually a > and a =. +// +// Another case is +// typename= s; + +bool TypescriptParser::TokenSplit(Token *t) { + if (!t->IsOperator() || t->GetOprId() != OPR_GE) + return false; + unsigned size = mActiveTokens.GetNum(); + if (size < 2) + return false; + + Token *type_arg = mActiveTokens.ValueAtIndex(size - 1); + if (!type_arg->IsIdentifier()) + return false; + + Token *extends_token = FindKeywordToken("extends"); + + Token *lt = mActiveTokens.ValueAtIndex(size - 2); + + if (lt->Equal(extends_token)) { + // This is a good candidate. Do nothing + } else { + if (!lt->IsOperator() || lt->GetOprId() != OPR_LT) + return false; + + Token *type_name = mActiveTokens.ValueAtIndex(size - 3); + if (!type_name->IsIdentifier()) + return false; + } + + // Now we got a matching case. + Token *gt_token = FindOperatorToken(OPR_GT); + Token *assign_token = FindOperatorToken(OPR_Assign); + mActiveTokens.PushBack(gt_token); + mActiveTokens.PushBack(assign_token); + + if (mLexer->mTrace) { + std::cout << "Split >= to > and =" << std::endl; + } + + return true; +} + + +// 'appeal' is the node of 'rule_table'. +// 'child' was NULL when passed in. +bool TypescriptParser::TraverseASI(RuleTable *rule_table, + AppealNode *appeal, + AppealNode *&child) { + // Usually mCurToken is a new token to be matched. So if it's end of file, we simply return false. + // However, (1) if mCurToken is actually an ATMToken, which means it needs to be matched + // multiple times, we are NOT at the end yet. + // (2) If we are traverse a Concatenate rule, and the previous sub-rule has multiple matches, + // and we are trying the current sub-rule, ie. 'data', using one of the matches. + // The lexer actually reaches the EndOfFile in previous matchings, but the mCurToken + // we are working on right now is not the last token. It's one of the previous matches. + // So we need check if we are matching the last token. + //if (mEndOfFile && mCurToken >= mActiveTokens.GetNum()) { + // if (!(mInAltTokensMatching && (mCurToken == mATMToken))) + // return false; + //} + + if (mCurToken <= 1) + return false; + + if (mEndOfFile && mCurToken == mActiveTokens.GetNum()) + return true; + + unsigned old_pos = mCurToken; + bool found = false; + Token *curr_token = GetActiveToken(mCurToken); + Token *prev_token = GetActiveToken(mCurToken - 1); + + MASSERT((rule_table->mNum == 1) && "ASI node has more than one elements?"); + + TableData *data = rule_table->mData; + MASSERT(data->mType == DT_Token && "ASI data is not a token?"); + + Token *semicolon = &gSystemTokens[data->mData.mTokenId]; + MASSERT(semicolon->IsSeparator()); + MASSERT(semicolon->GetSepId() == SEP_Semicolon); + + if (curr_token->Equal(semicolon)) { + // To simplify the code, I reused TraverseToken(). + found = TraverseToken(semicolon, appeal, child); + } else { + // case 1. We are crossing lines. + if (curr_token->mLineBegin && prev_token->mLineEnd) { + // If prev token (line end) is a separator + if (prev_token->IsSeparator() && + (prev_token->GetSepId() == SEP_Rbrace || + prev_token->GetSepId() == SEP_Rbrack || + prev_token->GetSepId() == SEP_Rparen)) { + if (mTraceTable) { + std::cout << "TraverseASI, Auto-insert one semicolon." << std::endl; + } + found = true; + } + + // if prev token is identifier or keyword AND the curr token is also id or keyword + // we can try to insert semicolon. A simple case is: + // a <-- we can insert semicolon + // console.log(); + if ( (prev_token->IsIdentifier() || prev_token->IsKeyword()) && + (curr_token->IsIdentifier() || curr_token->IsKeyword()) ){ + if (mTraceTable) { + std::cout << "TraverseASI, Auto-insert one semicolon." << std::endl; + } + found = true; + } + + if (found) + return found; + } + + // case 2. like: + // {foo()} <-- , is missed before } + if (curr_token->IsSeparator() && (curr_token->GetSepId() == SEP_Rbrace)) + return true; + + // case 3. This is a special case we want to catch: + // foo(x) a=b; <-- , is missing before a=b + // { foo(x) a=b; } <-- , is missing before a=b + // There could be many more similar cases, but we just match this special one in our + // unit test. We don't encourage people write weird code. + if ( (curr_token->IsIdentifier() || curr_token->IsKeyword()) && + (prev_token->IsSeparator() && (prev_token->GetSepId() == SEP_Rparen)) && + mActiveTokens.GetNum() > 4 ){ + Token *prev_2_token = GetActiveToken(mCurToken - 2); + Token *prev_3_token = GetActiveToken(mCurToken - 3); + Token *prev_4_token = GetActiveToken(mCurToken - 4); + + bool lbrace_ok = false; + if (mActiveTokens.GetNum() > 5){ + Token *prev_5_token = GetActiveToken(mCurToken - 5); + if (prev_5_token->IsSeparator() && (prev_5_token->GetSepId() == SEP_Lbrace)) + lbrace_ok = true; + } + + if ( (prev_4_token->mLineBegin || lbrace_ok) && + (prev_4_token->IsIdentifier() || prev_4_token->IsKeyword()) && + (prev_2_token->IsIdentifier() || prev_2_token->IsKeyword()) && + (prev_3_token->IsSeparator() && (prev_3_token->GetSepId() == SEP_Lparen)) ){ + // NOTE: Need make sure foo(x) is not if(x) or while(x). + found = true; + if (prev_4_token->IsKeyword() && + (!strncmp(prev_4_token->GetName(), "if", 2) || + !strncmp(prev_4_token->GetName(), "while", 5)) ) + found = false; + + if (found) + return true; + } + } + } + + if (child) { + child->SetChildIndex(0); + appeal->CopyMatch(child); + } + + return found; +} + +} diff --git a/src/MapleFE/typescript/src/main.cpp b/src/MapleFE/typescript/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a999a29d72b96978293c0b6f6127e023771e605b --- /dev/null +++ b/src/MapleFE/typescript/src/main.cpp @@ -0,0 +1,125 @@ +/* +* Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +* +* OpenArkFE is licensed under the Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* +* http://license.coscl.org.cn/MulanPSL2 +* +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +* FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +#include // std::ofstream +#include "parser.h" +#include "token.h" +#include "common_header_autogen.h" +#include "ruletable_util.h" +#include "gen_summary.h" +#include "gen_aststore.h" +#include "gen_astdump.h" +#include "gen_astgraph.h" +#include "lang_spec.h" + +static void help() { + std::cout << "ts2ast sourcefile [options]:\n" << std::endl; + std::cout << " --help : print this help" << std::endl; + std::cout << " --trace-lexer : Trace lexing" << std::endl; + std::cout << " --trace-table : Trace rule table when entering and exiting" << std::endl; + std::cout << " --trace-left-rec : Trace left recursion parsing" << std::endl; + std::cout << " --trace-appeal : Trace appeal process" << std::endl; + std::cout << " --trace-failed : Trace failed tokens of table" << std::endl; + std::cout << " --trace-timing : Trace parsing time" << std::endl; + std::cout << " --trace-stack : Trace visited-token stack of table" << std::endl; + std::cout << " --trace-sortout : Trace SortOut" << std::endl; + std::cout << " --trace-ast-build : Trace AST Builder" << std::endl; + std::cout << " --trace-patch-was-succ : Trace Patching of WasSucc nodes" << std::endl; + std::cout << " --trace-warning : Print Warning" << std::endl; + std::cout << " --dump-ast : Dump AST in text format" << std::endl; + std::cout << " --dump-dot : Dump AST in dot format" << std::endl; +} + +int main (int argc, char *argv[]) { + if (argc == 1 || (!strncmp(argv[1], "--help", 6) && (strlen(argv[1]) == 6))) { + help(); + exit(-1); + } + + maplefe::Parser *parser = new maplefe::TypescriptParser(argv[1]); + + bool dump_ast = false; + bool dump_dot = false; + bool succ; + + // Parse the argument + for (unsigned i = 2; i < argc; i++) { + if (!strncmp(argv[i], "--trace-lexer", 13) && (strlen(argv[i]) == 13)) { + parser->SetLexerTrace(); + } else if (!strncmp(argv[i], "--trace-table", 13) && (strlen(argv[i]) == 13)) { + parser->mTraceTable = true; + } else if (!strncmp(argv[i], "--trace-left-rec", 16) && (strlen(argv[i]) == 16)) { + parser->mTraceLeftRec = true; + } else if (!strncmp(argv[i], "--trace-appeal", 14) && (strlen(argv[i]) == 14)) { + parser->mTraceAppeal = true; + } else if (!strncmp(argv[i], "--trace-stack", 13) && (strlen(argv[i]) == 13)) { + parser->mTraceVisited = true; + } else if (!strncmp(argv[i], "--trace-failed", 14) && (strlen(argv[i]) == 14)) { + parser->mTraceFailed = true; + } else if (!strncmp(argv[i], "--trace-timing", 14) && (strlen(argv[i]) == 14)) { + parser->mTraceTiming = true; + } else if (!strncmp(argv[i], "--trace-sortout", 15) && (strlen(argv[i]) == 15)) { + parser->mTraceSortOut = true; + } else if (!strncmp(argv[i], "--trace-ast-build", 17) && (strlen(argv[i]) == 17)) { + parser->mTraceAstBuild = true; + } else if (!strncmp(argv[i], "--trace-patch-was-succ", 22) && (strlen(argv[i]) == 22)) { + parser->mTracePatchWasSucc = true; + } else if (!strncmp(argv[i], "--trace-warning", 15) && (strlen(argv[i]) == 15)) { + parser->mTraceWarning = true; + } else if (!strncmp(argv[i], "--dump-ast", 10) && (strlen(argv[i]) == 10)) { + dump_ast = true; + } else if (!strncmp(argv[i], "--dump-dot", 10) && (strlen(argv[i]) == 10)) { + dump_dot = true; + } else { + std::cerr << "unknown option " << argv[i] << std::endl; + exit(-1); + } + } + + parser->InitRecursion(); + succ = parser->Parse(); + if (!succ) { + delete parser; + return 1; + } + + // the module from parser + maplefe::ModuleNode *module = parser->GetModule(); + + if(dump_ast) { + maplefe::AstDump astdump(module); + astdump.Dump("ts2ast: Initial AST", &std::cout); + } + + if(dump_dot) { + maplefe::AstGraph graph(module); + graph.DumpGraph("ts2ast: Initial AST", &std::cout); + } + + maplefe::AstStore saveAst(module); + saveAst.StoreInAstBuf(); + maplefe::AstBuffer &ast_buf = saveAst.GetAstBuf(); + + std::ofstream ofs; + std::string fname(module->GetFilename()); + fname += ".ast"; + ofs.open(fname, std::ofstream::out); + const char *addr = (const char *)(&(ast_buf[0])); + ofs.write(addr, ast_buf.size()); + ofs.close(); + + delete parser; + return 0; +} diff --git a/src/MapleFE/typescript/stmt.spec b/src/MapleFE/typescript/stmt.spec new file mode 100644 index 0000000000000000000000000000000000000000..4bce8140eb6f1eb77e346f706f1f7210234aba67 --- /dev/null +++ b/src/MapleFE/typescript/stmt.spec @@ -0,0 +1,2491 @@ +# Copyright (C) [2021] Futurewei Technologies, Inc. All rights reverved. +# Copyright 2022 Tencent. All rights reverved. +# +# MapleFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# + +#------------------------------------------------------------------------------- +# A.1 Lexical Grammar +#------------------------------------------------------------------------------- + +#### Template and TemplateLiteral are too complicated to be described +#### in rules. We handle them specifically in the source code of lexer. + +##Template :: +##NoSubstitutionTemplate +##TemplateHead + +##NoSubstitutionTemplate :: +##` TemplateCharactersopt ` + +##TemplateHead :: +##` TemplateCharactersopt ${ + +##See 11.8.6 +##TemplateSubstitutionTail :: +##TemplateMiddle +##TemplateTail +##See 11.8.6 +##TemplateMiddle :: +##} TemplateCharactersopt ${ +##See 11.8.6 +##TemplateTail :: +##} TemplateCharactersopt ` + +##TemplateCharacters :: +##TemplateCharacter TemplateCharactersopt + +##TemplateCharacter :: +##$ [lookahead ≠ { ] +##\ EscapeSequence +##LineContinuation +##LineTerminatorSequence +##SourceCharacter but not one of ` or \ or $ or LineTerminator + +#------------------------------------------------------------------------------- +# A.2 Expressions +#------------------------------------------------------------------------------- + +rule KeywordIdentifier : ONEOF("type", + "with", + "boolean", + "string", + "catch", + "get", + "set", + "undefined", + "never", + "number", + "symbol", + "unique", + "any", + "constructor", + "delete", + "abstract", + "private", + "static", + "as", + "async", + "await", + "finally", + "from", + "is", + "in", + "of", + "declare", + "readonly", + "debugger", + "default", + "namespace", + "module", + "switch", + "infer", + "asserts", + "require", + "global", + "throw", + "class", + "unknown", + "do", + "for") +## " + attr.action : BuildIdentifier() + +rule JSIdentifier: ONEOF(Identifier, + KeywordIdentifier, + Identifier + '!', + Identifier + '?', + KeywordIdentifier + '?') + attr.action.%3 : SetIsNonNull(%1) + attr.action.%4 : SetIsOptional(%1) + attr.action.%5 : SetIsOptional(%1) + +rule AsType : "as" + Type + attr.action : BuildAsType(%2) + +##----------------------------------- +##rule IdentifierReference[Yield] : +## Identifier +## [~Yield] yield + +rule IdentifierReference : ONEOF( + JSIdentifier) +# "yield") + +##----------------------------------- +##rule BindingIdentifier[Yield] : +## Identifier +## [~Yield] yield + +rule BindingIdentifier : ONEOF(JSIdentifier) + +##----------------------------------- +##rule LabelIdentifier[Yield] : +## Identifier +## [~Yield] yield +rule LabelIdentifier : ONEOF( + JSIdentifier) + +##----------------------------------- +##rule Identifier : +## IdentifierName but not ReservedWord +## +## Identifier and IdentifierName are tricky in Javascript. +## (1) Some 'keywords' like 'get', 'set', should be keyword and reserved, +## however, they are allowed as identifiers. +## (2) Identifier is a reserved rule in 'autogen', we won't define it +## in this spec. +## +## I decided to use JSIdentifier instead of Identifier and then I +## can include 'get', 'set' in the JSIdentifier. + +##----------------------------------- +##rule PrimaryExpression[Yield] : +## this +## IdentifierReference[?Yield] +## Literal +## ArrayLiteral[?Yield] +## ObjectLiteral[?Yield] +## FunctionExpression +## ClassExpression[?Yield] +## GeneratorExpression +## RegularExpressionLiteral +## TemplateLiteral[?Yield] +## CoverParenthesizedExpressionAndArrowParameterList[?Yield] + +rule PrimaryExpression : ONEOF("this", + "super", + IdentifierReference, + Literal, + ArrayLiteral, + ObjectLiteral, + FunctionExpression, +# ClassExpression[?Yield] +# GeneratorExpression + RegularExpression, + TemplateLiteral, + ParenthesizedExpression) + +##----------------------------------- +##rule CoverParenthesizedExpressionAndArrowParameterList[Yield] : +## ( Expression[In, ?Yield] ) +## ( ) +## ( ... BindingIdentifier[?Yield] ) +## ( Expression[In, ?Yield] , ... BindingIdentifier[?Yield] ) +## When processing the production +## PrimaryExpression[Yield] : CoverParenthesizedExpressionAndArrowParameterList[?Yield] +## the interpretation of CoverParenthesizedExpressionAndArrowParameterList is refined using the following grammar: +## ParenthesizedExpression[Yield] : +## ( Expression[In, ?Yield] ) +rule ParenthesizedExpression : '(' + Expression + ')' + +rule CoverParenthesizedExpressionAndArrowParameterList : ONEOF( + '(' + Expression + ')', + '(' + ')', + '(' + "..." + BindingIdentifier + ')', + '(' + "..." + BindingPattern + ')', + '(' + Expression + ',' + "..." + BindingIdentifier + ')', + '(' + Expression + ',' + "..." + BindingPattern + ')') + +##----------------------------------- + +##----------------------------------- +##rule Literal : +## NullLiteral +## BooleanLiteral +## NumericLiteral +## StringLiteral + +# Literal is handled in lexer as a token. Also we don't do any Lookahead detect or recursion detect +# inside Literal. So it means parsing stops at Literal. This works for most languages. +# +# NullLiteral, BooleanLiteral, NumericLiteral, StringLiteral can be handled specifically in parser +# to see if it's a string literal. + +##----------------------------------- +##rule ArrayLiteral[Yield] : +## [ Elisionopt ] +## [ ElementList[?Yield] ] +## [ ElementList[?Yield] , Elisionopt ] +rule ArrayLiteral : ONEOF( + '[' + ZEROORONE(Elision) + ']' + '[' + ElementList + ']' + '[' + ElementList + ',' + ZEROORONE(Elision) + ']') + attr.action.%1,%2,%3 : BuildArrayLiteral(%2) + +##----------------------------------- +##rule ElementList[Yield] : +## Elisionopt AssignmentExpression[In, ?Yield] +## Elisionopt SpreadElement[?Yield] +## ElementList[?Yield] , Elisionopt AssignmentExpression[In, ?Yield] +## ElementList[?Yield] , Elisionopt SpreadElement[?Yield] +rule ElementList : ONEOF( + ZEROORONE(Elision) + AssignmentExpression, + ZEROORONE(Elision) + SpreadElement, + ElementList + ',' + ZEROORONE(Elision) + AssignmentExpression, + ElementList + ',' + ZEROORONE(Elision) + SpreadElement) + attr.action.%1,%2 : PassChild(%2) + attr.action.%3,%4 : BuildExprList(%1, %4) + +##----------------------------------- +##rule Elision : +## , +## Elision , + +rule Elision : ONEOF(',', + Elision + ',') + +##----------------------------------- +##rule SpreadElement[Yield] : +## ... AssignmentExpression[In, ?Yield] +rule SpreadElement : "..." + AssignmentExpression + ZEROORONE(TypeArguments) + attr.action : SetIsRest(%2) + attr.action : PassChild(%2) + +##----------------------------------- +##rule ObjectLiteral[Yield] : +## { } +## { PropertyDefinitionList[?Yield] } +## { PropertyDefinitionList[?Yield] , } +rule ObjectLiteral : ONEOF('{' + '}', + '{' + PropertyDefinitionList + '}', + '{' + PropertyDefinitionList + ',' + '}') + attr.action.%1 : BuildStructLiteral() + attr.action.%2,%3 : BuildStructLiteral(%2) + +##----------------------------------- +##rule PropertyDefinitionList[Yield] : +## PropertyDefinition[?Yield] +## PropertyDefinitionList[?Yield] , PropertyDefinition[?Yield] +rule PropertyDefinitionList : ONEOF( + PropertyDefinition, + PropertyDefinitionList + ',' + PropertyDefinition) + +##----------------------------------- +# modified in 2016 +##rule PropertyDefinition[Yield] : +## IdentifierReference[?Yield] +## CoverInitializedName[?Yield] +## PropertyName[?Yield] : AssignmentExpression[In, ?Yield] +## MethodDefinition[?Yield] + +##----------------------------------- +##rule PropertyName[Yield] : +## LiteralPropertyName +## ComputedPropertyName[?Yield] +rule PropertyName : ONEOF(LiteralPropertyName, + ComputedPropertyName) + +##----------------------------------- +##rule LiteralPropertyName : +## IdentifierName +## StringLiteral +## NumericLiteral + +# I used Identifier instead of IdentifierName because keywords +# are processed before Identifier, and so Identifier is the same +# as IdentifierName here. +# +# I extend StringLiteral/NumericLiteral to Literal. 'tsc' will +# make sure it's legal and I don't need worry about it. + +rule LiteralPropertyName : ONEOF(JSIdentifier, Literal) + +##----------------------------------- +##rule ComputedPropertyName[Yield] : +## [ AssignmentExpression[In, ?Yield] ] +rule ComputedPropertyName : ONEOF( + '[' + AssignmentExpression + ']', + ZEROORONE(IndexSigPrefix) + ZEROORONE(IndexSigModifier) + '[' + AssignmentExpression + ']' + ZEROORONE(IndexSigPrefix) + ZEROORONE(IndexSigModifier)) + attr.action.%1 : BuildComputedName(%2) + attr.action.%2 : BuildComputedName(%4) + attr.action.%2 : AddModifier(%1, %2) + attr.action.%2 : AddModifier(%6, %7) + +##----------------------------------- +##rule CoverInitializedName[Yield] : +## IdentifierReference[?Yield] Initializer[In, ?Yield] +rule CoverInitializedName : IdentifierReference + Initializer + +##----------------------------------- +##rule Initializer[In, Yield] : +## = AssignmentExpression[?In, ?Yield] +rule Initializer : '=' + AssignmentExpression + +##----------------------------------- +##rule TemplateLiteral[Yield] : +## NoSubstitutionTemplate +## TemplateHead Expression[In, ?Yield] TemplateSpans[?Yield] +## +## NOTE: TemplateLiteral will be handled specifically in lexer code. +## rule TemplateLiteral : "this_is_for_fake_rule" is defined in reserved.spec + +##----------------------------------- +##rule TemplateSpans[Yield] : +## TemplateTail +## TemplateMiddleList[?Yield] TemplateTail + +##----------------------------------- +##rule TemplateMiddleList[Yield] : +## TemplateMiddle Expression[In, ?Yield] +## TemplateMiddleList[?Yield] TemplateMiddle Expression[In, ?Yield] + +##----------------------------------- +##rule MemberExpression[Yield] : +## PrimaryExpression[?Yield] +## MemberExpression[?Yield] [ Expression[In, ?Yield] ] +## MemberExpression[?Yield] . IdentifierName +## MemberExpression[?Yield] TemplateLiteral[?Yield] +## SuperProperty[?Yield] +## MetaProperty +## new MemberExpression[?Yield] Arguments[?Yield] + +rule KeywordPropName : ONEOF("break", + "this", + "public", + "export", + "const", + "if", + "try", + "else", + "continue", + "implements", + "enum", + "function", + "let", + "return", + "extends", + "import", + "get", + "set", + "var") + attr.action : BuildIdentifier() + +rule MemberExpression : ONEOF( + PrimaryExpression + ZEROORMORE(AsType), + MemberExpression + '[' + Expression + ']' + ZEROORMORE(AsType), + MemberExpression + '.' + JSIdentifier + ZEROORMORE(AsType), + MemberExpression + "?." + JSIdentifier + ZEROORMORE(AsType), + MemberExpression + TemplateLiteral, +# SuperProperty[?Yield] +# MetaProperty + "new" + MemberExpression + ZEROORONE(Arguments), +# NOTE: I created this rule. Typescript extended Type system and allow 'new' +# on a TypeReference + "new" + TypeReference + ZEROORONE(Arguments), + MemberExpression + "?." + '[' + Expression + ']' + ZEROORMORE(AsType), + IsExpression, + MemberExpression + '[' + KeyOf + ']', + MemberExpression + '!', + MemberExpression + "as" + "const", + '<' + Type + '>' + MemberExpression, + MemberExpression + '.' + KeywordPropName) + attr.action.%1 : AddAsType(%1, %2) + attr.action.%2 : BuildArrayElement(%1, %3) + attr.action.%2 : AddAsType(%5) + attr.action.%3 : BuildField(%1, %3) + attr.action.%3 : AddAsType(%4) + attr.action.%4 : SetIsOptional(%1) + attr.action.%4 : BuildField(%1, %3) + attr.action.%4 : AddAsType(%4) + attr.action.%6,%7 : BuildNewOperation(%2, %3) + attr.action.%8 : SetIsOptional(%1) + attr.action.%8 : BuildArrayElement(%1, %4) + attr.action.%8 : AddAsType(%6) + attr.action.%10: BuildArrayElement(%1, %3) + attr.action.%11: SetIsNonNull(%1) + attr.action.%12: SetIsConst(%1) + attr.action.%13: BuildCast(%2, %4) + attr.action.%14 : BuildField(%1, %3) + +rule IsExpression: ONEOF(PrimaryExpression + "is" + Type, + ArrowFunction + "is" + Type) + attr.action.%1,%2 : BuildIs(%1, %3) + +rule AssertExpression : "asserts" + MemberExpression + attr.action : BuildAssert(%2) + +##----------------------------------- +##rule SuperProperty[Yield] : +## super [ Expression[In, ?Yield] ] +## super . IdentifierName + +##----------------------------------- +##rule MetaProperty : +## NewTarget + +##----------------------------------- +##rule NewTarget : +## new . target + +##----------------------------------- +##rule NewExpression[Yield] : +## MemberExpression[?Yield] +## new NewExpression[?Yield] +rule NewExpression : ONEOF(MemberExpression, + "new" + NewExpression, + "new" + ClassDeclaration, + "new" + '(' + ClassDeclaration + ')') + attr.action.%2,%3 : BuildNewOperation(%2) + attr.action.%4 : BuildNewOperation(%3) + +##----------------------------------- +##rule CallExpression[Yield] : +## MemberExpression[?Yield] Arguments[?Yield] +## SuperCall[?Yield] +## CallExpression[?Yield] Arguments[?Yield] +## CallExpression[?Yield] [ Expression[In, ?Yield] ] +## CallExpression[?Yield] . IdentifierName +## CallExpression[?Yield] TemplateLiteral[?Yield] + +rule ImportFunction : ONEOF("import" + '(' + Literal + ')', + "import" + '(' + TemplateLiteral + ')') + attr.action.%1,%2 : BuildImport() + attr.action.%1,%2 : SetFromModule(%3) + +rule CallExpression : ONEOF( + MemberExpression + ZEROORONE(TypeArguments) + Arguments + ZEROORMORE(AsType), + SuperCall, + CallExpression + Arguments + ZEROORMORE(AsType), + CallExpression + '[' + Expression + ']' + ZEROORONE(AsType), + CallExpression + '.' + JSIdentifier + ZEROORMORE(AsType), + CallExpression + TemplateLiteral, + CallExpression + '!' + ZEROORMORE(AsType), + CallExpression + "?." + JSIdentifier + ZEROORMORE(AsType), + MemberExpression + "?." + ZEROORONE(TypeArguments) + Arguments + ZEROORMORE(AsType), + "set" + ZEROORONE(TypeArguments) + Arguments + ZEROORMORE(AsType), + "get" + ZEROORONE(TypeArguments) + Arguments + ZEROORMORE(AsType), + CallExpression + "?." + Arguments + ZEROORMORE(AsType), + ImportFunction, + CallExpression + '.' + KeywordPropName + ZEROORMORE(AsType)) + attr.action.%1,%3,%10,%11 : BuildCall(%1) + attr.action.%1,%10,%11 : AddAsType(%4) + attr.action.%1,%10,%11 : AddTypeGenerics(%2) + attr.action.%1,%10,%11 : AddArguments(%3) + attr.action.%3 : AddArguments(%2) + attr.action.%3 : AddAsType(%3) + attr.action.%4 : BuildArrayElement(%1, %3) + attr.action.%4 : AddAsType(%5) + attr.action.%5,%14 : BuildField(%1, %3) + attr.action.%5,%14 : AddAsType(%4) + attr.action.%7 : SetIsNonNull(%1) + attr.action.%7 : AddAsType(%1, %3) + attr.action.%8 : SetIsOptional(%1) + attr.action.%8 : BuildField(%1, %3) + attr.action.%8 : AddAsType(%4) + attr.action.%9 : SetIsOptional(%1) + attr.action.%9 : BuildCall(%1) + attr.action.%9 : AddTypeGenerics(%3) + attr.action.%9 : AddArguments(%4) + attr.action.%9 : AddAsType(%5) + attr.action.%12: SetIsOptional(%1) + attr.action.%12: BuildCall(%1) + attr.action.%12: AddArguments(%3) + attr.action.%12: AddAsType(%4) + +##----------------------------------- +##rule SuperCall[Yield] : +## super Arguments[?Yield] +rule SuperCall : "super" + Arguments + +##----------------------------------- +##rule Arguments[Yield] : +## ( ) +## ( ArgumentList[?Yield] ) + +rule Arguments : ONEOF( + '(' + ')', + '(' + ArgumentList + ')') + attr.action.%2 : PassChild(%2) + +##----------------------------------- +##rule ArgumentList[Yield] : +## AssignmentExpression[In, ?Yield] +## ... AssignmentExpression[In, ?Yield] +## ArgumentList[?Yield] , AssignmentExpression[In, ?Yield] +## ArgumentList[?Yield] , ... AssignmentExpression[In, ?Yield] + +## child #3, I added ZEROORONE() since ECMAScript 2017 allows empty argument after ','. +rule ArgumentList : ONEOF(AssignmentExpression, + "..." + AssignmentExpression, + ArgumentList + ',' + ZEROORONE(AssignmentExpression), + ArgumentList + ',' + "..." + AssignmentExpression) + attr.action.%2 : SetIsRest(%2) + attr.action.%4 : SetIsRest(%4) + +##----------------------------------- +##rule LeftHandSideExpression[Yield] : +## NewExpression[?Yield] +## CallExpression[?Yield] + +rule LeftHandSideExpression : ONEOF(NewExpression, + CallExpression, + "..." + NewExpression, + "..." + CallExpression, + "await" + CallExpression, + "await" + NewExpression) + attr.action.%3,%4 : SetIsRest(%2) + attr.action.%5,%6 : BuildAwait(%2) + +##----------------------------------- +##rule PostfixExpression[Yield] : +## LeftHandSideExpression[?Yield] +## LeftHandSideExpression[?Yield] [no LineTerminator here] ++ +## LeftHandSideExpression[?Yield] [no LineTerminator here] -- + +rule PostfixExpression : ONEOF( + LeftHandSideExpression, + LeftHandSideExpression + "++", + LeftHandSideExpression + "--") + attr.action.%2,%3 : BuildPostfixOperation(%2, %1) + +##----------------------------------- +##rule UnaryExpression[Yield] : +## PostfixExpression[?Yield] +## delete UnaryExpression[?Yield] +## void UnaryExpression[?Yield] +## typeof UnaryExpression[?Yield] +## ++ UnaryExpression[?Yield] +## -- UnaryExpression[?Yield] +## + UnaryExpression[?Yield] +## - UnaryExpression[?Yield] +## ~ UnaryExpression[?Yield] +## ! UnaryExpression[?Yield] + +rule UnaryExpression : ONEOF( + PostfixExpression, + "delete" + UnaryExpression, + "void" + UnaryExpression, + "typeof" + UnaryExpression, + "++" + UnaryExpression, + "--" + UnaryExpression, + '+' + UnaryExpression, + '-' + UnaryExpression, + '~' + UnaryExpression, + '!' + UnaryExpression, + "typeof" + '(' + ClassDeclaration + ')') + attr.action.%2 : BuildDeleteOperation(%2) + attr.action.%3 : BuildLiteral(%1) + attr.action.%4 : BuildTypeOf(%2) + attr.action.%5,%6,%7,%8,%9,%10 : BuildUnaryOperation(%1, %2) + attr.action.%11 : BuildTypeOf(%3) + +## UpdateExpression[Yield]: +## LeftHandSideExpression[?Yield] +## LeftHandSideExpression[?Yield][no LineTerminator here]++ +## LeftHandSideExpression[?Yield][no LineTerminator here]-- +## ++UnaryExpression[?Yield] +## --UnaryExpression[?Yield] +rule UpdateExpression : ONEOF(LeftHandSideExpression, + LeftHandSideExpression + "++", + LeftHandSideExpression + "--", + "++" + UnaryExpression, + "--" + UnaryExpression) + attr.action.%2,%3 : BuildPostfixOperation(%2, %1) + attr.action.%4,%5: BuildUnaryOperation(%1, %2) + + +## Added in 2016 +## ExponentiationExpression[Yield]: +## UnaryExpression[?Yield] +## UpdateExpression[?Yield]**ExponentiationExpression[?Yield] +rule ExponentiationExpression : ONEOF(UnaryExpression, + UpdateExpression + "**" + ExponentiationExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +##----------------------------------- +##rule MultiplicativeExpression[Yield] : +## UnaryExpression[?Yield] +## MultiplicativeExpression[?Yield] MultiplicativeOperator UnaryExpression[?Yield] +## 2016 +## MultiplicativeExpression[Yield]: +## ExponentiationExpression[?Yield] +## MultiplicativeExpression[?Yield]MultiplicativeOperatorExponentiationExpression[?Yield] + +rule MultiplicativeExpression : ONEOF( + ExponentiationExpression, + MultiplicativeExpression + MultiplicativeOperator + ExponentiationExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +##----------------------------------- +##rule MultiplicativeOperator : one of +## * / % + +rule MultiplicativeOperator : ONEOF( '*', '/', '%') + +##----------------------------------- +##rule AdditiveExpression[Yield] : +## MultiplicativeExpression[?Yield] +## AdditiveExpression[?Yield] + MultiplicativeExpression[?Yield] +## AdditiveExpression[?Yield] - MultiplicativeExpression[?Yield] + +rule AdditiveExpression : ONEOF( + MultiplicativeExpression, + AdditiveExpression + '+' + MultiplicativeExpression, + AdditiveExpression + '-' + MultiplicativeExpression) + attr.action.%2,%3 : BuildBinaryOperation(%1, %2, %3) + +##----------------------------------- +##rule ShiftExpression[Yield] : +## AdditiveExpression[?Yield] +## ShiftExpression[?Yield] << AdditiveExpression[?Yield] +## ShiftExpression[?Yield] >> AdditiveExpression[?Yield] +## ShiftExpression[?Yield] >>> AdditiveExpression[?Yield] +rule ShiftExpression : ONEOF(AdditiveExpression, + ShiftExpression + "<<" + AdditiveExpression, + ShiftExpression + ">>" + AdditiveExpression, + ShiftExpression + ">>>" + AdditiveExpression) + attr.action.%2,%3,%4 : BuildBinaryOperation(%1, %2, %3) + +##----------------------------------- +##rule RelationalExpression[In, Yield] : +## ShiftExpression[?Yield] +## RelationalExpression[?In, ?Yield] < ShiftExpression[?Yield] +## RelationalExpression[?In, ?Yield] > ShiftExpression[?Yield] +## RelationalExpression[?In, ?Yield] <= ShiftExpression[? Yield] +## RelationalExpression[?In, ?Yield] >= ShiftExpression[?Yield] +## RelationalExpression[?In, ?Yield] instanceof ShiftExpression[?Yield] +## [+In] RelationalExpression[In, ?Yield] in ShiftExpression[?Yield] + +rule InExpression : RelationalExpression + "in" + ONEOF(ShiftExpression, Type) +## " + attr.action : BuildIn(%1, %3) + +rule RelationalExpression : ONEOF(ShiftExpression, + RelationalExpression + '<' + ShiftExpression, + RelationalExpression + '>' + ShiftExpression, + RelationalExpression + "<=" + ShiftExpression, + RelationalExpression + ">=" + ShiftExpression, + RelationalExpression + "instanceof" + ShiftExpression, + ClassDeclaration + "instanceof" + ShiftExpression, + InExpression) + attr.property.%3 : NoAltToken + attr.action.%2,%3,%4,%5 : BuildBinaryOperation(%1, %2, %3) + attr.action.%6,%7 : BuildInstanceOf(%1, %3) + + +##----------------------------------- +##rule EqualityExpression[In, Yield] : +## RelationalExpression[?In, ?Yield] +## EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield] +## EqualityExpression[?In, ?Yield] != RelationalExpression[?In, ?Yield] +## EqualityExpression[?In, ?Yield] === RelationalExpression[?In, ?Yield] +## EqualityExpression[?In, ?Yield] !== RelationalExpression[?In, ?Yield] + +rule EqualityExpression : ONEOF( + RelationalExpression, + EqualityExpression + "==" + RelationalExpression, + EqualityExpression + "!=" + RelationalExpression, + EqualityExpression + "===" + RelationalExpression, + EqualityExpression + "!==" + RelationalExpression) + attr.action.%2,%3,%4,%5 : BuildBinaryOperation(%1, %2, %3) + +##----------------------------------- +##rule BitwiseANDExpression[In, Yield] : +## EqualityExpression[?In, ?Yield] +## BitwiseANDExpression[?In, ?Yield] & EqualityExpression[?In, ?Yield] + +rule BitwiseANDExpression : ONEOF( + EqualityExpression, + BitwiseANDExpression + '&' + EqualityExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +##----------------------------------- +##rule BitwiseXORExpression[In, Yield] : +## BitwiseANDExpression[?In, ?Yield] +## BitwiseXORExpression[?In, ?Yield] ^ BitwiseANDExpression[?In, ?Yield] + +rule BitwiseXORExpression : ONEOF( + BitwiseANDExpression, + BitwiseXORExpression + '^' + BitwiseANDExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +##----------------------------------- +##rule BitwiseORExpression[In, Yield] : +## BitwiseXORExpression[?In, ?Yield] +## BitwiseORExpression[?In, ?Yield] | BitwiseXORExpression[?In, ?Yield] + +rule BitwiseORExpression : ONEOF( + BitwiseXORExpression, + BitwiseORExpression + '|' + BitwiseXORExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +##----------------------------------- +##rule LogicalANDExpression[In, Yield] : +## BitwiseORExpression[?In, ?Yield] +## LogicalANDExpression[?In, ?Yield] && BitwiseORExpression[?In, ?Yield] + +rule LogicalANDExpression : ONEOF( + BitwiseORExpression, + LogicalANDExpression + "&&" + BitwiseORExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +##----------------------------------- +##rule LogicalORExpression[In, Yield] : +## LogicalANDExpression[?In, ?Yield] +## LogicalORExpression[?In, ?Yield] || LogicalANDExpression[?In, ?Yield] + +rule LogicalORExpression : ONEOF( + LogicalANDExpression, + LogicalORExpression + "||" + LogicalANDExpression) + attr.action.%2 : BuildBinaryOperation(%1, %2, %3) + +##----------------------------------- +##rule ConditionalExpression[In, Yield] : +## LogicalORExpression[?In, ?Yield] +## LogicalORExpression[?In,?Yield] ? AssignmentExpression[In, ?Yield] : AssignmentExpression[?In, ?Yield] +rule ConditionalExpression : ONEOF( + LogicalORExpression, + LogicalORExpression + '?' + AssignmentExpression + ':' + AssignmentExpression, + ConditionalExpression + "??" + ConditionalExpression) + attr.action.%2 : BuildTernaryOperation(%1, %3, %5) + attr.action.%3 : BuildBinaryOperation(%1, %2, %3) + +##----------------------------------- +##rule AssignmentExpression[In, Yield] : +## ConditionalExpression[?In, ?Yield] +## [+Yield] YieldExpression[?In] +## ArrowFunction[?In, ?Yield] +## LeftHandSideExpression[?Yield] = AssignmentExpression[?In, ?Yield] +## LeftHandSideExpression[?Yield] AssignmentOperator AssignmentExpression[?In, ?Yield] + +rule AssignmentExpression : ONEOF( + ConditionalExpression, + YieldExpression, + ArrowFunction, + LeftHandSideExpression + '=' + AssignmentExpression, + LeftHandSideExpression + AssignmentOperator + AssignmentExpression) + attr.action.%4,%5 : BuildAssignment(%1, %2, %3) + +rule AssignmentOperator : ONEOF("*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|=", "??=") + +##----------------------------------- +##rule Expression[In, Yield] : +## AssignmentExpression[?In, ?Yield] +## Expression[?In, ?Yield] , AssignmentExpression[?In, ?Yield] + +## NOTE. I added "undefined" to expression because "undefined" is both a type and +## a value in Typescript. This is a weird rule. +rule Expression : ONEOF( + AssignmentExpression, + Expression + ',' + AssignmentExpression, + "undefined") + +#------------------------------------------------------------------------------- +# Statements +#------------------------------------------------------------------------------- + +rule TripleSlash : ONEOF( "///" + '<' + "reference" + "path" + '=' + Literal + '/' + '>', + "///" + '<' + "reference" + "types" + '=' + Literal + '/' + '>', + "///" + '<' + "reference" + "lib" + '=' + Literal + '/' + '>', + "///" + '<' + "reference" + "no-default-lib" + '=' + Literal + '/' + '>') + attr.action.%1,%2,%3,%4 : BuildTripleSlash(%4, %6) + +##----------------------------------- +##rule Statement[Yield, Return] : +## BlockStatement[?Yield, ?Return] +## VariableStatement[?Yield] +## EmptyStatement +## ExpressionStatement[?Yield] +## IfStatement[?Yield, ?Return] +## BreakableStatement[?Yield, ?Return] +## ContinueStatement[?Yield] +## BreakStatement[?Yield] +## [+Return] ReturnStatement[?Yield] +## WithStatement[?Yield, ?Return] +## LabelledStatement[?Yield, ?Return] +## ThrowStatement[?Yield] +## TryStatement[?Yield, ?Return] +## DebuggerStatement + +rule Statement : ONEOF( + BlockStatement, + VariableStatement, + EmptyStatement, + ExpressionStatement, + IfStatement, + BreakableStatement, + ContinueStatement, + BreakStatement, + ReturnStatement, +# WithStatement[?Yield, ?Return] + LabelledStatement, + ThrowStatement, + TryStatement, + TripleSlash) +# DebuggerStatement + attr.property : Top + attr.property : Single # This is extremely important to give CallExpression the + # last chance IFF all previous rules fail. + +##----------------------------------- +##rule Declaration[Yield] : +## HoistableDeclaration[?Yield] +## ClassDeclaration[?Yield] +## LexicalDeclaration[In, ?Yield] + +## NOTE. Typescript added InterfaceDeclaration, TypeAliasDeclaration, EnumDeclaration +rule Declaration : ONEOF(HoistableDeclaration, + ClassDeclaration, + LexicalDeclaration + ZEROORONE(';'), + InterfaceDeclaration, + TypeAliasDeclaration, + EnumDeclaration, + NamespaceDeclaration, + ExternalDeclaration, + GlobalDeclaration) + attr.property : Top + +##----------------------------------- +##rule HoistableDeclaration[Yield, Default] : +## FunctionDeclaration[?Yield,?Default] +## GeneratorDeclaration[?Yield, ?Default] +rule HoistableDeclaration : ONEOF(FunctionDeclaration, + GeneratorDeclaration) + +##----------------------------------- +##rule BreakableStatement[Yield, Return] : +## IterationStatement[?Yield, ?Return] +## SwitchStatement[?Yield, ?Return] +rule BreakableStatement : ONEOF(IterationStatement, + SwitchStatement) + +##----------------------------------- +##rule BlockStatement[Yield, Return] : +## Block[?Yield, ?Return] +rule BlockStatement : Block + +##----------------------------------- +##rule Block[Yield, Return] : +## { StatementList[?Yield, ?Return]opt } +rule Block : '{' + ZEROORONE(StatementList) + '}' + attr.action : BuildBlock(%2) + +##----------------------------------- +##rule StatementList[Yield, Return] : +## StatementListItem[?Yield, ?Return] +## StatementList[?Yield, ?Return] StatementListItem[?Yield, ?Return] +rule StatementList : ONEOF(StatementListItem, + StatementList + StatementListItem) + +##----------------------------------- +##rule StatementListItem[Yield, Return] : +## Statement[?Yield, ?Return] +## Declaration[?Yield] +rule StatementListItem : ONEOF(Statement, Declaration) + +##----------------------------------- +##rule LexicalDeclaration[In, Yield] : +## LetOrConst BindingList[?In, ?Yield] ; +rule LexicalDeclaration : ONEOF("let" + BindingList, + "const" + BindingList) + attr.action.%1,%2 : BuildDecl(%2) + attr.action.%1 : SetJSLet() + attr.action.%2 : SetJSConst() + +##----------------------------------- +##rule LetOrConst : +## let +## const +rule LetOrConst : ONEOF("let", "const") + +##----------------------------------- +##rule BindingList[In, Yield] : +## LexicalBinding[?In, ?Yield] +## BindingList[?In, ?Yield] , LexicalBinding[?In, ?Yield] +rule BindingList : ONEOF(LexicalBinding, + BindingList + ',' + LexicalBinding) + +##----------------------------------- +##rule LexicalBinding[In, Yield] : +## BindingIdentifier[?Yield] Initializer[?In, ?Yield]opt +## BindingPattern[?Yield] Initializer[?In, ?Yield] +rule LexicalBinding : ONEOF(BindingIdentifier + ZEROORONE(Initializer), + BindingIdentifier + ":" + Type + ZEROORONE(Initializer), + BindingPattern + ZEROORONE(Initializer), + BindingPattern + ":" + Type + ZEROORONE(Initializer)) + attr.action.%1,%3 : AddInitTo(%1, %2) + attr.action.%2,%4 : AddInitTo(%1, %4) + attr.action.%2,%4 : AddType(%1, %3) + +##----------------------------------- +##rule VariableStatement[Yield] : +## var VariableDeclarationList[In, ?Yield] ; +rule VariableStatement : "var" + VariableDeclarationList + ZEROORONE(';') + attr.action : PassChild(%2) + +##----------------------------------- +##rule VariableDeclarationList[In, Yield] : +## VariableDeclaration[?In, ?Yield] +## VariableDeclarationList[?In, ?Yield] , VariableDeclaration[?In, ?Yield] +rule VariableDeclarationList : ONEOF( + VariableDeclaration, + VariableDeclarationList + ',' + VariableDeclaration) + +##----------------------------------- +##rule VariableDeclaration[In, Yield] : +## BindingIdentifier[?Yield] Initializer[?In, ?Yield]opt +## BindingPattern[?Yield] Initializer[?In, ?Yield] + +# Typescript ask for explicit type. But it also allows implicit type if referrable. +rule VariableDeclaration : ONEOF(BindingIdentifier + ':' + Type + ZEROORONE(Initializer), + BindingIdentifier + ZEROORONE(Initializer), + BindingPattern + ZEROORONE(TypeAnnotation) + Initializer) + attr.action.%1 : AddInitTo(%1, %4) + attr.action.%1 : BuildDecl(%3, %1) + attr.action.%1 : SetJSVar() + attr.action.%2 : AddInitTo(%1, %2) + attr.action.%2 : BuildDecl(%1) + attr.action.%2 : SetJSVar() + attr.action.%3 : AddInitTo(%1, %3) + attr.action.%3 : BuildDecl(%2, %1) + attr.action.%3 : SetJSVar() + +##----------------------------------- +##rule BindingPattern[Yield] : +## ObjectBindingPattern[?Yield] +## ArrayBindingPattern[?Yield] +rule BindingPattern : ONEOF(ObjectBindingPattern, ArrayBindingPattern) + +##----------------------------------- +##rule ObjectBindingPattern[Yield] : +## { } +## { BindingPropertyList[?Yield] } +## { BindingPropertyList[?Yield] , } +rule ObjectBindingPattern : ONEOF('{' + '}', + '{' + BindingPropertyList + '}', + '{' + BindingPropertyList + ',' + '}') + attr.action.%1 : BuildBindingPattern() + attr.action.%2,%3 : BuildBindingPattern(%2) + attr.action.%1,%2,%3 : SetObjectBinding() + +##----------------------------------- +##rule ArrayBindingPattern[Yield] : +## [ Elisionopt BindingRestElement[?Yield]opt ] +## [ BindingElementList[?Yield] ] +## [ BindingElementList[?Yield] , Elisionopt BindingRestElement[?Yield]opt ] +rule ArrayBindingPattern : ONEOF( + '[' + ZEROORONE(Elision) + ZEROORONE(BindingRestElement) + ']', + '[' + BindingElementList + ']', + '[' + BindingElementList + ',' + ZEROORONE(Elision) + ZEROORONE(BindingRestElement) + ']') + attr.action.%1 : BuildBindingPattern(%3) + attr.action.%2,%3 : BuildBindingPattern(%2) + attr.action.%1,%2,%3 : SetArrayBinding() + +##----------------------------------- +##rule BindingPropertyList[Yield] : +## BindingProperty[?Yield] +## BindingPropertyList[?Yield] , BindingProperty[?Yield] +rule BindingPropertyList : ONEOF(BindingProperty, + BindingPropertyList + ',' + BindingProperty, + BindingPropertyList + ',' + BindingRestProperty) + +##----------------------------------- +##rule BindingElementList[Yield] : +## BindingElisionElement[?Yield] +## BindingElementList[?Yield] , BindingElisionElement[?Yield] +rule BindingElementList : ONEOF( + BindingElisionElement, + BindingElementList + ',' + BindingElisionElement) + +##----------------------------------- +##rule BindingElisionElement[Yield] : +## Elisionopt BindingElement[?Yield] +rule BindingElisionElement : ZEROORONE(Elision) + BindingElement + attr.action : PassChild(%2) + +##----------------------------------- +##rule BindingProperty[Yield] : +## SingleNameBinding[?Yield] +## PropertyName[?Yield] : BindingElement[?Yield] +rule BindingProperty : ONEOF(SingleNameBinding, + PropertyName + ':' + BindingElement) + attr.action.%2 : BuildBindingElement(%1, %3) + +rule BindingRestProperty : BindingRestElement + +##----------------------------------- +##rule BindingElement[Yield] : +## SingleNameBinding[?Yield] +## BindingPattern[?Yield] Initializer[In, ?Yield]opt +rule BindingElement : ONEOF(SingleNameBinding, + BindingPattern + ZEROORONE(Initializer)) + attr.action.%2 : AddInitTo(%1, %2) + +##----------------------------------- +##rule SingleNameBinding[Yield] : +## BindingIdentifier[?Yield] Initializer[In, ?Yield]opt +rule SingleNameBinding : BindingIdentifier + ZEROORONE(Initializer) + attr.action : AddInitTo(%1, %2) + attr.action : BuildBindingElement(%1) + +##----------------------------------- +##rule BindingRestElement[Yield] : +## ... BindingIdentifier[?Yield] +rule BindingRestElement : "..." + BindingIdentifier + attr.action : SetIsRest(%2) + attr.action : BuildBindingElement(%2) + +##----------------------------------- +##rule EmptyStatement : +## ; +rule EmptyStatement : ';' + +##----------------------------------- +##rule ExpressionStatement[Yield] : +## [lookahead NotIn {{, function, class, let [}] Expression[In, ?Yield] ; + +rule ExpressionStatement : ONEOF( + ConditionalExpression + ASI(';'), + YieldExpression + ';', + ArrowFunction + ';', + LeftHandSideExpression + '=' + AssignmentExpression + ZEROORONE(';'), + LeftHandSideExpression + AssignmentOperator + AssignmentExpression + ZEROORONE(';'), + Expression + ',' + AssignmentExpression + ';', + "undefined" + ';', + LeftHandSideExpression + "++", + LeftHandSideExpression + "--") + + attr.action.%4,%5 : BuildAssignment(%1, %2, %3) + attr.action.%8,%9 : BuildPostfixOperation(%2, %1) + +##----------------------------------- +##rule IfStatement[Yield, Return] : +## if ( Expression[In, ?Yield] ) Statement[?Yield, ?Return] else Statement[?Yield, ?Return] +## if ( Expression[In, ?Yield] ) Statement[?Yield, ?Return] +rule IfStatement : ONEOF( + "if" + '(' + Expression + ')' + Statement + "else" + Statement, + "if" + '(' + Expression + ')' + Statement) + attr.action.%1,%2: BuildCondBranch(%3) + attr.action.%1,%2: AddCondBranchTrueStatement(%5) + attr.action.%1: AddCondBranchFalseStatement(%7) + +## " // This line is to make my vim in right color + +##----------------------------------- +##rule IterationStatement[Yield, Return] : +## do Statement[?Yield, ?Return] while ( Expression[In, ?Yield] ) ; +## while ( Expression[In, ?Yield] ) Statement[?Yield, ?Return] +## for ( [lookahead NotIn {let [}] Expression[?Yield]opt ; Expression[In, ?Yield]opt ; Expression[In, ?Yield]opt ) Statement[?Yield, ?Return] +## for ( var VariableDeclarationList[?Yield] ; Expression[In, ?Yield]opt ; Expression[In, ?Yield]opt ) Statement[?Yield, ?Return] +## for ( LexicalDeclaration[?Yield] Expression[In, ?Yield]opt ; Expression[In, ?Yield]opt ) Statement[?Yield, ?Return] +## for ( [lookahead NotIn {let [}] LeftHandSideExpression[?Yield] in Expression[In, ?Yield] ) Statement[?Yield, ?Return] +## for ( var ForBinding[?Yield] in Expression[In, ?Yield] ) Statement[?Yield, ?Return] +## for ( ForDeclaration[?Yield] in Expression[In, ?Yield] ) Statement[?Yield, ?Return] +## for ( [lookahead NotEq let ] LeftHandSideExpression[?Yield] of AssignmentExpression[In, ?Yield] ) Statement[?Yield, ?Return] +## for ( var ForBinding[?Yield] of AssignmentExpression[In, ?Yield] ) Statement[?Yield, ?Return] +## for ( ForDeclaration[?Yield] of AssignmentExpression[In, ?Yield] ) Statement[?Yield, ?Return] +rule IterationStatement : ONEOF( + "do" + Statement + "while" + '(' + Expression + ')' + ';', + "while" + '(' + Expression + ')' + Statement, + "for" + '(' + ZEROORONE(Expression) + ';' + ZEROORONE(Expression) + ';' + ZEROORONE(Expression) + ')' + Statement, + "for" + '(' + "var" + VariableDeclarationList + ';' + ZEROORONE(Expression) + ';' + ZEROORONE(Expression) + ')' + Statement, + "for" + '(' + LexicalDeclaration + ';' + ZEROORONE(Expression) + ';' + ZEROORONE(Expression) + ')' + Statement, + "for" + '(' + LeftHandSideExpression + "in" + Expression + ')' + Statement, + "for" + '(' + "var" + ForBinding + "in" + Expression + ')' + Statement, + "for" + '(' + ForDeclaration + "in" + Expression + ')' + Statement, + "for" + '(' + LeftHandSideExpression + "of" + AssignmentExpression + ')' + Statement, + "for" + '(' + "var" + ForBinding + "of" + AssignmentExpression + ')' + Statement, + "for" + '(' + "let" + ForBinding + "of" + AssignmentExpression + ')' + Statement, + "for" + '(' + "const" + ForBinding + "of" + AssignmentExpression + ')' + Statement, + ) + attr.action.%1 : BuildDoLoop(%5, %2) + attr.action.%2 : BuildWhileLoop(%3, %5) + attr.action.%3 : BuildForLoop(%3, %5, %7, %9) + attr.action.%4 : BuildForLoop(%4, %6, %8, %10) + attr.action.%5 : BuildForLoop(%3, %5, %7, %9) + + attr.action.%7,%10 : BuildDecl(%4) + attr.action.%7,%10 : SetJSVar() + attr.action.%7 : BuildForLoop_In(%6, %8) + attr.action.%6,%8 : BuildForLoop_In(%3, %5, %7) + attr.action.%9 : BuildForLoop_Of(%3, %5, %7) + attr.action.%10 : BuildForLoop_Of(%6, %8) + + attr.action.%11,%12 : BuildDecl(%4) + attr.action.%11 : SetJSLet() + attr.action.%12 : SetJSConst() + attr.action.%11,%12 : BuildForLoop_Of(%6, %8) + +##----------------------------------- +##rule ForDeclaration[Yield] : +## LetOrConst ForBinding[?Yield] +rule ForDeclaration : ONEOF("let" + ForBinding, + "const" + ForBinding) + attr.action.%1,%2 : BuildDecl(%2) + attr.action.%1 : SetJSLet() + attr.action.%2 : SetJSConst() + +##----------------------------------- +##rule ForBinding[Yield] : +## BindingIdentifier[?Yield] +## BindingPattern[?Yield] +rule ForBinding : ONEOF(BindingIdentifier, + BindingPattern) + +##----------------------------------- +##rule ContinueStatement[Yield] : +## continue ; +## continue [no LineTerminator here] LabelIdentifier[?Yield] ; +rule ContinueStatement : ONEOF( + "continue" + ZEROORONE(';'), + "continue" + NoLineTerminator + LabelIdentifier + ZEROORONE(';')) + attr.action.%1 : BuildContinue() + attr.action.%2 : BuildContinue(%3) + +##----------------------------------- +##rule BreakStatement[Yield] : +## break ; +## break [no LineTerminator here] LabelIdentifier[?Yield] ; +rule BreakStatement : ONEOF( + "break" + ZEROORONE(';'), + "break" + NoLineTerminator + LabelIdentifier + ZEROORONE(';')) + attr.action.%1 : BuildBreak() + attr.action.%2 : BuildBreak(%3) + +##----------------------------------- +##rule ReturnStatement[Yield] : +## return ; +## return [no LineTerminator here] Expression[In, ?Yield] ; +rule ReturnStatement :ONEOF("return" + ZEROORONE(';'), + "return" + NoLineTerminator + Expression + ZEROORONE(';')) + attr.action.%1 : BuildReturn() + attr.action.%2 : BuildReturn(%3) + +##----------------------------------- +##rule WithStatement[Yield, Return] : +## with ( Expression[In, ?Yield] ) Statement[?Yield, ?Return] + +##----------------------------------- +##rule SwitchStatement[Yield, Return] : +## switch ( Expression[In, ?Yield] ) CaseBlock[?Yield, ?Return] +rule SwitchStatement : + "switch" + '(' + Expression + ')' + CaseBlock + attr.action : BuildSwitch(%3, %5) + +##----------------------------------- +##rule CaseBlock[Yield, Return] : +## { CaseClauses[?Yield, ?Return]opt } +## { CaseClauses[?Yield, ?Return]opt DefaultClause[?Yield, ?Return] CaseClauses[?Yield, ?Return]opt } +rule CaseBlock : ONEOF( + '{' + ZEROORONE(CaseClauses) + '}', + '{' + ZEROORONE(CaseClauses) + DefaultClause + ZEROORONE(CaseClauses) + '}') + +##----------------------------------- +##rule CaseClauses[Yield, Return] : +## CaseClause[?Yield, ?Return] +## CaseClauses[?Yield, ?Return] CaseClause[?Yield, ?Return] +rule CaseClauses : ONEOF( + CaseClause, + CaseClauses + CaseClause) + +##----------------------------------- +##rule CaseClause[Yield, Return] : +## case Expression[In, ?Yield] : StatementList[?Yield, ?Return]opt +rule CaseClause : + "case" + Expression + ':' + ZEROORONE(StatementList) + attr.action : BuildSwitchLabel(%2) + attr.action : BuildOneCase(%4) + +##----------------------------------- +##rule DefaultClause[Yield, Return] : +## default : StatementList[?Yield, ?Return]opt +rule DefaultClause : + "default" + ':' + ZEROORONE(StatementList) + attr.action : BuildDefaultSwitchLabel() + attr.action : BuildOneCase(%3) + +##----------------------------------- +##rule LabelledStatement[Yield, Return] : +## LabelIdentifier[?Yield] : LabelledItem[?Yield, ?Return] +rule LabelledStatement : + LabelIdentifier + ':' + LabelledItem + attr.action : AddLabel(%3, %1) + +##----------------------------------- +##rule LabelledItem[Yield, Return] : +## Statement[?Yield, ?Return] +## FunctionDeclaration[?Yield] +rule LabelledItem : ONEOF(Statement, FunctionDeclaration) + +##----------------------------------- +##rule ThrowStatement[Yield] : +## throw [no LineTerminator here] Expression[In, ?Yield] ; +rule ThrowStatement : "throw" + Expression + ZEROORONE(';') + attr.action : BuildThrows(%2) + +##----------------------------------- +##rule TryStatement[Yield, Return] : +## try Block[?Yield, ?Return] Catch[?Yield, ?Return] +## try Block[?Yield, ?Return] Finally[?Yield, ?Return] +## try Block[?Yield, ?Return] Catch[?Yield, ?Return] Finally[?Yield, ?Return] +rule TryStatement : ONEOF( + "try" + Block + Catch, + "try" + Block + Finally, + "try" + Block + Catch + Finally) + attr.action.%1,%2,%3 : BuildTry(%2) + attr.action.%1,%3 : AddCatch(%3) + attr.action.%2 : AddFinally(%3) + attr.action.%3 : AddFinally(%4) + +##----------------------------------- +##rule Catch[Yield, Return] : +## catch ( CatchParameter[?Yield] ) Block[?Yield, ?Return] +rule Catch : ONEOF("catch" + '(' + CatchParameter + ')' + Block, + "catch" + Block) + attr.action.%1 : BuildCatch(%3, %5) + attr.action.%2 : BuildCatch(%2) + +##----------------------------------- +##rule Finally[Yield, Return] : +## finally Block[?Yield, ?Return] +rule Finally : "finally" + Block + attr.action : BuildFinally(%2) + +##----------------------------------- +##rule CatchParameter[Yield] : +## BindingIdentifier[?Yield] +## BindingPattern[?Yield] +rule CatchParameter : ONEOF(BindingIdentifier + ZEROORONE(TypeAnnotation), + BindingPattern) + attr.action.%1 : AddType(%1, %2) + +##----------------------------------- +rule DebuggerStatement : "debugger" + ';' + + +###################################################################### +## Function and Class +###################################################################### + +## NOTE: Replaced by TS +## FunctionDeclaration[Yield, Default] : +## function BindingIdentifier[?Yield] ( FormalParameters ) { FunctionBody } +## [+Default] function ( FormalParameters ) { FunctionBody } + +## +## FunctionExpression : +## function BindingIdentifieropt ( FormalParameters ) { FunctionBody } + +## +## StrictFormalParameters[Yield] : +## FormalParameters[?Yield] +rule StrictFormalParameters : FormalParameters + +## +## FormalParameters[Yield] : +## [empty] +## FormalParameterList[?Yield] +rule FormalParameters : ZEROORONE(FormalParameterList) + +## +## FormalParameterList[Yield] : +## FunctionRestParameter[?Yield] +## FormalsList[?Yield] +## FormalsList[?Yield] , FunctionRestParameter[?Yield] +rule FormalParameterList : ONEOF(FunctionRestParameter, + FormalsList, + FormalsList + ',' + FunctionRestParameter) + +## +## FormalsList[Yield] : +## FormalParameter[?Yield] +## FormalsList[?Yield] , FormalParameter[?Yield] +rule FormalsList : ONEOF(FormalParameter, + FormalsList + ',' + FormalParameter) + +## +## FunctionRestParameter[Yield] : +## BindingRestElement[?Yield] +rule FunctionRestParameter : BindingRestElement + +## +## FormalParameter[Yield] : +## BindingElement[?Yield] + +## Typescript requires type. So this is different than JS spec. +rule FormalParameter : BindingElement + attr.action : BuildDecl(%3, %1) + +## +## FunctionBody[Yield] : +## FunctionStatementList[?Yield] +## NOTE. I used ZEROORONE(StatementList) directly in order to avoid +## an issue where FunctionStatementList fail when looking for +## its lookahead, if function body is empty. +rule FunctionBody : ZEROORONE(StatementList) + attr.action : BuildBlock(%1) + +## +## FunctionStatementList[Yield] : +## StatementList[?Yield, Return]opt +rule FunctionStatementList : ZEROORONE(StatementList) + +## See 14.2 +## ArrowFunction[In, Yield] : +## ArrowParameters[?Yield] [no LineTerminator here] => ConciseBody[?In] + +# (1) I inline ArrowParameters +# (2) In CoverParent.... is replaced by ArrowFormalParameters which in turn is changed +# to CallSignature in Typescript. I inline CallSignature here. +rule ArrowFunction : ONEOF( + BindingIdentifier + "=>" + ConciseBody, + ZEROORONE(AccessibilityModifier) + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + "=>" + ConciseBody) + attr.action.%1 : BuildLambda(%1, %3) + attr.action.%2 : BuildLambda(%4, %8) + attr.action.%2 : AddType(%6) + attr.action.%2 : AddTypeGenerics(%2) + attr.action.%2 : AddModifier(%1) + attr.action.%1,%2 : SetArrowFunction() + +## See 14.2 +## ArrowParameters[Yield] : +## BindingIdentifier[?Yield] +## CoverParenthesizedExpressionAndArrowParameterList[?Yield] +## When the production ArrowParameters:CoverParenthesizedExpressionAndArrowParameterList is recognized the following +## grammar is used to refine the interpretation of CoverParenthesizedExpressionAndArrowParameterList: +##ArrowFormalParameters[Yield]: +##(StrictFormalParameters[?Yield]) +rule ArrowParameters : ONEOF(BindingIdentifier, + ArrowFormalParameters) + +rule ArrowFormalParameters : '(' + StrictFormalParameters + ')' + +## See 14.2 +## ConciseBody[In] : +## [lookahead ≠ { ] AssignmentExpression[?In] +## { FunctionBody } +rule ConciseBody : ONEOF(AssignmentExpression, + '{' + FunctionBody + '}') + +## +## See 14.3 +## MethodDefinition[Yield] : +## PropertyName[?Yield] ( StrictFormalParameters ) { FunctionBody } +## GeneratorMethod[?Yield] +## get PropertyName[?Yield] ( ) { FunctionBody } +## set PropertyName[?Yield] ( PropertySetParameterList ) { FunctionBody } + +## See 14.3 +## PropertySetParameterList : +## FormalParameter +## See 14.4 +## GeneratorMethod[Yield] : +## * PropertyName[?Yield] ( StrictFormalParameters[Yield] ) { GeneratorBody } + +## See 14.4 +## GeneratorDeclaration[Yield, Default] : +## function * BindingIdentifier[?Yield] ( FormalParameters[Yield] ) { GeneratorBody } +## [+Default] function * ( FormalParameters[Yield] ) { GeneratorBody } +rule GeneratorDeclaration : + "function" + '*' + BindingIdentifier + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + '{' + FunctionBody + '}' + attr.action : BuildFunction(%3) + attr.action : AddParams(%5) + attr.action : AddType(%7) + attr.action : AddFunctionBody(%9) + attr.action : SetIsGenerator() + +## See 14.4 +## GeneratorExpression : +## function * BindingIdentifier[Yield]opt ( FormalParameters[Yield] ) { GeneratorBody } + +## See 14.4 +## GeneratorBody : +## FunctionBody[Yield] + +## See 14.4 +## YieldExpression[In] : +## yield +## yield [no LineTerminator here] AssignmentExpression[?In, Yield] +## yield [no LineTerminator here] * AssignmentExpression[?In, Yield] + +rule YieldExpression : ONEOF("yield", + "yield" + AssignmentExpression, + "yield" + '*' + AssignmentExpression) + attr.action.%1: BuildYield() + attr.action.%2: BuildYield(%2) + attr.action.%3: BuildYield(%3) + attr.action.%3: SetIsTransfer() + +## See 14.5 +## ClassDeclaration[Yield, Default] : +## class BindingIdentifier[?Yield] ClassTail[?Yield] +## [+Default] class ClassTail[?Yield] +## See 14.5 +## ClassExpression[Yield] : +## class BindingIdentifier[?Yield]opt ClassTail[?Yield] +## See 14.5 +## ClassTail[Yield] : +## ClassHeritage[?Yield]opt { ClassBody[?Yield]opt } +## See 14.5 +## ClassHeritage[Yield] : +## extends LeftHandSideExpression[?Yield] + +## See 14.5 +## ClassBody[Yield] : +## ClassElementList[?Yield] +rule ClassBody : ClassElementList + attr.action: BuildBlock(%1) + +## See 14.5 +## ClassElementList[Yield] : +## ClassElement[?Yield] +## ClassElementList[?Yield] ClassElement[?Yield] +rule ClassElementList : ONEOF(ClassElement, + ClassElementList + ClassElement) + +## See 14.5 +## ClassElement[Yield] : +## MethodDefinition[?Yield] +## static MethodDefinition[?Yield] +## ; + +############################################################################# +## A.5 Scripts and Modules +############################################################################# + +## See 15.1 +## Script : ## ScriptBodyopt +rule Script : ZEROORONE(ScriptBody) + +## See 15.1 +## ScriptBody : ## StatementList +rule ScriptBody : StatementList + +## Module : ModuleBodyopt +rule Module : ZEROORONE(ModuleBody) + +## ModuleBody : ModuleItemList +rule ModuleBody : ModuleItemList + +## ModuleItemList : +## ModuleItem +## ModuleItemList ModuleItem +rule ModuleItemList : ONEOF(ModuleItem, + ModuleItemList + ModuleItem) + +## ModuleItem : +## ImportDeclaration +## ExportDeclaration +## StatementListItem +rule ModuleItem : ONEOF(ImportDeclaration, + ExportDeclaration, + StatementListItem) + +## ImportDeclaration : +## import ImportClause FromClause ; +## import ModuleSpecifier ; +rule ImportDeclaration : ONEOF("import" + ImportClause + FromClause + ZEROORONE(';'), + "import" + ModuleSpecifier + ZEROORONE(';'), + "import" + BindingIdentifier + '=' + "require" + '(' + AssignmentExpression + ')' + ZEROORONE(';'), + "import" + "type" + NamedImports + FromClause + ZEROORONE(';'), + "import" + "type" + NameSpaceImport + FromClause + ZEROORONE(';'), + "import" + "type" + ImportedDefaultBinding + FromClause + ZEROORONE(';'), + ImportAliasDeclaration) + attr.property : Top + attr.action.%1,%2,%3,%4,%5,%6 : BuildImport() + attr.action.%1 : SetPairs(%2) + attr.action.%1 : SetFromModule(%3) + attr.action.%2 : SetFromModule(%2) + attr.action.%3 : SetSinglePairs(%6, %2) + attr.action.%4,%5,%6 : SetPairs(%3) + attr.action.%4,%5,%6 : SetFromModule(%4) + attr.action.%4,%5,%6 : SetIsXXportType() + +## ImportClause : +## ImportedDefaultBinding +## NameSpaceImport +## NamedImports +## ImportedDefaultBinding , NameSpaceImport +## ImportedDefaultBinding , NamedImports +rule ImportClause : ONEOF(ImportedDefaultBinding, + NameSpaceImport, + NamedImports, + ImportedDefaultBinding + ',' + NameSpaceImport, + ImportedDefaultBinding + ',' + NamedImports) + +## See 15.2.2 +## ImportedDefaultBinding : +## ImportedBinding +rule ImportedDefaultBinding : ImportedBinding + attr.action : BuildXXportAsPairDefault(%1) + +## See 15.2.2 +## NameSpaceImport : +## * as ImportedBinding +rule NameSpaceImport : '*' + "as" + ImportedBinding + attr.action : BuildXXportAsPairEverything(%3) + +## See 15.2.2 +## NamedImports : +## { } +## { ImportsList } +## { ImportsList , } +rule NamedImports : ONEOF('{' + '}', + '{' + ImportsList + '}', + '{' + ImportsList + ',' + '}') + +## See 15.2.2 +## FromClause : +## from ModuleSpecifier +rule FromClause : "from" + ModuleSpecifier + +## See 15.2.2 +## ImportsList : +## ImportSpecifier +## ImportsList , ImportSpecifier +rule ImportsList : ONEOF(ImportSpecifier, + ImportsList + ',' + ImportSpecifier) + +## See 15.2.2 +## ImportSpecifier : +## ImportedBinding +## IdentifierName as ImportedBinding +rule ImportSpecifier : ONEOF(ImportedBinding, + JSIdentifier + "as" + ImportedBinding, + "default" + "as" + ImportedBinding) + attr.action.%2 : BuildXXportAsPair(%1, %3) + attr.action.%3 : BuildXXportAsPairDefault(%3) + +## See 15.2.2 +## ModuleSpecifier : +## StringLiteral +## NOTE. I extend StringLiteral to Literal to ease parser. 'tsc' will make sure +## it's a string literal. +rule ModuleSpecifier : Literal + +## See 15.2.2 +## ImportedBinding : +## BindingIdentifier +rule ImportedBinding : BindingIdentifier + +## See 15.2.3 +## ExportDeclaration : +## export * FromClause ; +## export ExportClause FromClause ; +## export ExportClause ; +## export VariableStatement +## export Declaration +## export default HoistableDeclaration[Default] +## export default ClassDeclaration[Default] +## export default [lookahead ∉ {function, class}] AssignmentExpression[In] ; + +# export = expr; +# is for export single syntax. +rule ExportDeclaration : ONEOF(ZEROORMORE(Annotation) + "export" + '*' + FromClause + ZEROORONE(';'), + ZEROORMORE(Annotation) + "export" + ExportClause + FromClause + ZEROORONE(';'), + ZEROORMORE(Annotation) + "export" + ExportClause + ZEROORONE(';'), + ZEROORMORE(Annotation) + "export" + VariableStatement, + ZEROORMORE(Annotation) + "export" + Declaration + ZEROORONE(';'), + ZEROORMORE(Annotation) + "export" + "default" + HoistableDeclaration, + ZEROORMORE(Annotation) + "export" + "default" + ClassDeclaration, + ZEROORMORE(Annotation) + "export" + "default" + AssignmentExpression + ZEROORONE(';'), + ZEROORMORE(Annotation) + "export" + "=" + AssignmentExpression + ZEROORONE(';'), + ZEROORMORE(Annotation) + "export" + "type" + ExportClause + FromClause + ZEROORONE(';'), + ZEROORMORE(Annotation) + "export" + "type" + ExportClause + ZEROORONE(';'), + ZEROORMORE(Annotation) + "export" + AsNamespace + ZEROORONE(';'), + ZEROORMORE(Annotation) + "export" + ExternalModuleDeclaration + ZEROORONE(';'), + ZEROORMORE(Annotation) + "export" + NameSpaceExport + FromClause + ZEROORONE(';'), + ZEROORMORE(Annotation) + "export" + ImportAliasDeclaration, + ZEROORMORE(Annotation) + "export" + TypeAliasDeclaration + ZEROORONE(';')) + attr.property : Top + attr.action.%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15,%16 : BuildExport() + attr.action.%1,%2,%3,%4,%5,%6,%7,%8,%9,%10,%11,%12,%13,%14,%15,%16 : AddModifier(%1) + attr.action.%1 : SetIsEverything() + attr.action.%2,%3,%4,%5,%12,%13,%14,%15,%16 : SetPairs(%3) + attr.action.%6,%7,%8 : SetDefaultPairs(%4) + attr.action.%1,%2,%14 : SetFromModule(%4) + attr.action.%9 : SetSinglePairs(%4) + attr.action.%10,%11 : SetPairs(%4) + attr.action.%10,%11 : SetIsXXportType() + attr.action.%10 : SetFromModule(%5) + +rule AsNamespace : "as" + "namespace" + JSIdentifier + attr.action : BuildXXportAsPair(%3) + attr.action : SetAsNamespace() + +rule NameSpaceExport : '*' + "as" + JSIdentifier + attr.action : BuildXXportAsPairEverything(%3) + +## See 15.2.3 +## ExportClause : +## { } +## { ExportsList } +## { ExportsList , } +rule ExportClause : ONEOF('{' + '}', + '{' + ExportsList + '}', + '{' + ExportsList + ',' + '}') + +## ExportsList : +## ExportSpecifier +## ExportsList , ExportSpecifier +rule ExportsList : ONEOF(ExportSpecifier, + ExportsList + ',' + ExportSpecifier) + +## See 15.2.3 +## ExportSpecifier : +## IdentifierName +## IdentifierName as IdentifierName +rule KeywordExportName : ONEOF("import") + attr.action : BuildIdentifier() + +rule ExportSpecifier : ONEOF(JSIdentifier, + JSIdentifier + "as" + BindingIdentifier, + JSIdentifier + "as" + "default", + "default" + "as" + JSIdentifier, + JSIdentifier + "as" + "super", + JSIdentifier + "as" + "function", + JSIdentifier + "as" + KeywordExportName) + attr.action.%2,%5,%6,%7 : BuildXXportAsPair(%1, %3) + attr.action.%3 : BuildXXportAsPairDefault(%1) + attr.action.%4 : BuildXXportAsPairDefault(%3) + +############################################################################# +############################################################################# +############################################################################# +## Below is Typescript specific +############################################################################# +############################################################################# +############################################################################# + +############################################################################# +## A.1 Type section +############################################################################# + +## rule TypeParameters: < TypeParameterList > +rule TypeParameters: '<' + TypeParameterList + '>' + +rule TypeParameterList: ONEOF(TypeParameter + ZEROORONE(Elision), + TypeParameterList + ',' + TypeParameter + ZEROORONE(Elision)) + +## rule TypeParameter: BindingIdentifier Constraintopt +## It supports default type value of type parameter now. +rule TypeParameter: BindingIdentifier + ZEROORONE(Constraint) + ZEROORONE(TypeInitializer) + attr.action : BuildTypeParameter(%1) + attr.action : AddInit(%3) + attr.action : AddTypeParameterExtends(%2) + +rule TypeInitializer : '=' + Type + +## rule Constraint: extends Type +rule Constraint: "extends" + Type + attr.action : PassChild(%2) + +## rule TypeArguments: < TypeArgumentList > +rule TypeArguments: '<' + TypeArgumentList + '>' + +## rule TypeArgumentList: TypeArgument TypeArgumentList , TypeArgument +rule TypeArgumentList: ONEOF(TypeArgument, + TypeArgumentList + ',' + TypeArgument) + +## rule TypeArgument: Type +rule TypeArgument: Type + +rule ConditionalType : ONEOF(MemberExpression + "extends" + Type + '?' + Type + ':' + Type, + TypeReference + "extends" + Type + '?' + Type + ':' + Type, + ObjectType + "extends" + Type + '?' + Type + ':' + Type, + "unknown" + "extends" + Type + '?' + Type + ':' + Type, + PrimaryType + "extends" + Type + '?' + Type + ':' + Type, + TypeQuery + "extends" + Type + '?' + Type + ':' + Type, + TypeArray + "extends" + Type + '?' + Type + ':' + Type) + attr.action.%1,%2,%3,%4,%5,%6,%7 : BuildConditionalType(%1, %3, %5, %7) + +rule KeyOf : ONEOF("keyof" + Identifier, + "keyof" + '(' + TypeQuery + ')', + "keyof" + TypeQuery, + "keyof" + MemberExpression, + "keyof" + TypeReference) + attr.action.%1,%3,%4,%5 : BuildKeyOf(%2) + attr.action.%2 : BuildKeyOf(%3) + +rule InferType : "infer" + Identifier + attr.action : BuildInfer(%2) + +rule TypeArray : ONEOF(PrimaryType + '[' + PrimaryExpression + ']', + PrimaryType + '[' + TypeReference + ']', + TypeArray + '[' + PrimaryExpression + ']', + PrimaryType + '[' + ConditionalType + ']', + PrimaryType + '[' + TypeArray + ']') + attr.action.%1,%2,%3,%4,%5 : BuildArrayElement(%1, %3) + +rule PrimaryTypeKeyOf : PrimaryType + '[' + KeyOf + ']' + attr.action : BuildArrayElement(%1, %3) + +#rule Type : ONEOF(UnionOrIntersectionOrPrimaryType, +# FunctionType, +# ConstructorType) +rule Type : ONEOF(UnionOrIntersectionOrPrimaryType, + FunctionType, + ConstructorType, + KeyOf, + ConditionalType, + # Typescript interface[index] can be seen as a type + TypeArray, + MemberExpression + '[' + KeyOf + ']', + PrimaryTypeKeyOf, + InferType, + IsExpression, + PrimaryType + '[' + TypeQuery + ']', + TemplateLiteral) + attr.action.%7,%11 : BuildArrayElement(%1, %3) + +#rule UnionOrIntersectionOrPrimaryType: ONEOF(UnionType, +# IntersectionOrPrimaryType) +rule UnionOrIntersectionOrPrimaryType: ONEOF(UnionType, + IntersectionOrPrimaryType) + +#rule IntersectionOrPrimaryType : ONEOF(IntersectionType, +# PrimaryType) +rule IntersectionOrPrimaryType : ONEOF(IntersectionType, PrimaryType, TypeArray) + +## rule PrimaryType: ParenthesizedType PredefinedType TypeReference ObjectType ArrayType TupleType TypeQuery ThisType +rule PrimaryType: ONEOF(ParenthesizedType, + PredefinedType, + TypeReference, + ObjectType, + ArrayType, + TupleType, + TypeQuery, + ThisType, + NeverArrayType, + Literal, + ArrayLiteral, + ImportFunction, + ImportFunction + '.' + TypeReference) + attr.action.%13 : BuildField(%1, %3) + +rule NeverArrayType : '[' + ']' + attr.action : BuildNeverArrayType() + +## rule ParenthesizedType: ( Type ) +rule ParenthesizedType: '(' + Type + ')' + +## rule PredefinedType: any number boolean string symbol void +rule PredefinedType: ONEOF(TYPE, + "unique" + TYPE) + attr.action.%2 : SetIsUnique(%2) + +## rule TypeReference: TypeName [no LineTerminator here] TypeArgumentsopt +rule TypeReference: TypeName + ZEROORONE(TypeArguments) + ZEROORMORE(AsType) + attr.action : BuildUserType(%1) + attr.action : AddTypeGenerics(%2) + attr.action : AddAsType(%3) + +## rule TypeName: IdentifierReference NamespaceName . IdentifierReference +rule TypeName: ONEOF(IdentifierReference, + NamespaceName + '.' + IdentifierReference, + NamespaceName + '.' + KeywordPropName, + '(' + IdentifierReference + ')', + '(' + NamespaceName + '.' + IdentifierReference + ')') + attr.action.%2,%3 : BuildField(%1, %3) + attr.action.%5 : BuildField(%2, %4) + +## rule NamespaceName: IdentifierReference NamespaceName . IdentifierReference +rule NamespaceName: ONEOF(IdentifierReference, + NamespaceName + '.' + IdentifierReference) + attr.action.%2 : BuildField(%1, %3) + +## rule ObjectType: { TypeBodyopt } +rule ObjectType : '{' + ZEROORONE(TypeBody) + '}' + attr.action : BuildStruct() + attr.action : AddStructField(%2) + +## rule TypeBody: TypeMemberList ;opt TypeMemberList ,opt +rule TypeBody : ONEOF(TypeMemberList + ZEROORONE(';'), + TypeMemberList + ZEROORONE(',')) + +## rule TypeMemberList: TypeMember TypeMemberList ; TypeMember TypeMemberList , TypeMember +rule TypeMemberList : ONEOF(TypeMember, + TypeMemberList + ZEROORONE(';') + TypeMember, + TypeMemberList + ZEROORONE(',') + TypeMember) + +## rule TypeMember: PropertySignature CallSignature ConstructSignature IndexSignature MethodSignature +rule TypeMember : ONEOF(PropertySignature, + CallSignature, + ConstructSignature, + IndexSignature, + MethodSignature) + +## rule ArrayType: PrimaryType [no LineTerminator here] [ ] +rule ArrayType: ONEOF(ZEROORONE("readonly") + PrimaryType + '[' + ']', + SpreadElement + '[' + ']', + MemberExpression + '[' + ']') + attr.action.%1 : BuildArrayType(%2, %2) + attr.action.%1 : AddModifier(%1) + attr.action.%2 : BuildArrayType(%1, %1) + attr.action.%3 : BuildArrayType(%1, %1) + +## rule TupleType: [ TupleElementTypes ] +rule TupleType: ZEROORONE("readonly") + '[' + TupleElementTypes + ZEROORONE(Elision) + ']' + attr.action : BuildTupleType() + attr.action : AddModifier(%1) + attr.action : AddStructField(%3) + +## rule TupleElementTypes: TupleElementType TupleElementTypes , TupleElementType +rule TupleElementTypes: ONEOF(TupleElementType, + TupleElementTypes + ',' + TupleElementType) + +## rule TupleElementType: Type +rule TupleElementType: ONEOF(ZEROORONE(JSIdentifier + ':') + Type, + "..." + Type) + attr.action.%1 : BuildNameTypePair(%1, %2) + attr.action.%2 : SetIsRest(%2) + attr.action.%2 : BuildNameTypePair(%2) + +## rule UnionType: UnionOrIntersectionOrPrimaryType | IntersectionOrPrimaryType +rule UnionType : ONEOF(ZEROORONE('|') + UnionOrIntersectionOrPrimaryType + '|' + IntersectionOrPrimaryType, + UnionOrIntersectionOrPrimaryType + '|' + KeyOf, + KeyOf + '|' + UnionOrIntersectionOrPrimaryType, + TypeQuery + '|' + UnionOrIntersectionOrPrimaryType, + TemplateLiteral + '|' + TemplateLiteral) + attr.action.%1 : BuildUnionUserType(%2, %4) + attr.action.%2,%3,%4,%5 : BuildUnionUserType(%1, %3) + +## rule IntersectionType: IntersectionOrPrimaryType & PrimaryType +rule IntersectionType: ONEOF(IntersectionOrPrimaryType + '&' + PrimaryType, + IntersectionOrPrimaryType + '&' + ConditionalType, + PrimaryTypeKeyOf + '&' + PrimaryType) + attr.action.%1,%2,%3 : BuildInterUserType(%1, %3) + +## rule FunctionType: TypeParametersopt ( ParameterListopt ) => Type +rule FunctionType: ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + "=>" + Type + attr.action : BuildLambda(%3) + attr.action : AddType(%6) + attr.action : AddTypeGenerics(%1) + +## rule ConstructorType: new TypeParametersopt ( ParameterListopt ) => Type +## This actually a literal. +rule ConstructorType: ZEROORONE(AccessibilityModifier) + "new" + FunctionType + attr.action : BuildNewOperation(%3) + attr.action : AddModifier(%1) + +## rule TypeQuery: typeof TypeQueryExpression +rule TypeQuery: ONEOF("typeof" + TypeQueryExpression, + "typeof" + '(' + ClassDeclaration + ')') + attr.action.%1 : BuildTypeOf(%2) + attr.action.%2 : BuildTypeOf(%3) + +## rule TypeQueryExpression: IdentifierReference TypeQueryExpression . IdentifierName +rule TypeQueryExpression: ONEOF(IdentifierReference, + TypeQueryExpression + '.' + JSIdentifier, + UnaryExpression, + ImportFunction) + attr.action.%2 : BuildField(%1, %3) + +## rule ThisType: this +rule ThisType: "this" + +rule PropertySignatureName : ONEOF(PropertyName, KeywordPropName) + +## rule PropertySignature: PropertyName ?opt TypeAnnotationopt +## +## NOTE: for KeywordPropName we require them to have an explicit TypeAnnotation, or ',' or ';' +## following it. Otherwise there will be ambiguity, like: +## interface A { +## export() : string; +## } +## It could be parsed as one property 'export' and one call signature "() : string". + +rule PropertySignature: ONEOF(ZEROORONE(AccessibilityModifier) + PropertyName + ZEROORONE(TypeAnnotation), + ZEROORONE(AccessibilityModifier) + PropertySignatureName + '?' + ZEROORONE(TypeAnnotation), + ZEROORONE(AccessibilityModifier) + KeywordPropName + TypeAnnotation, + ZEROORONE(AccessibilityModifier) + KeywordPropName + ',', + ZEROORONE(AccessibilityModifier) + KeywordPropName + ';') + attr.action.%1,%3 : AddType(%2, %3) + attr.action.%2 : AddType(%2, %4) + attr.action.%2 : SetIsOptional(%2) + attr.action.%1,%2,%3,%4,%5: AddModifierTo(%2, %1) + +## JS ECMA has more definition than this Typescript one. I use ECMA one. +## rule PropertyName: IdentifierName StringLiteral NumericLiteral +##rule PropertyName : ONEOF(JSIdentifier, + ##StringLiteral, + ##NumericLiteral, +## ) + +## rule TypeAnnotation: : Type +rule TypeAnnotation: ':' + Type + +## rule CallSignature: TypeParametersopt ( ParameterListopt ) TypeAnnotationopt +rule CallSignature: ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + attr.action : BuildFunction() + attr.action : AddParams(%3) + attr.action : AddType(%5) + attr.action : SetCallSignature() + +## rule ParameterList: RequiredParameterList OptionalParameterList RestParameter RequiredParameterList , OptionalParameterList RequiredParameterList , RestParameter OptionalParameterList , RestParameter RequiredParameterList , OptionalParameterList , RestParameter +rule ParameterList: ONEOF(RequiredParameterList + ZEROORONE(Elision), + OptionalParameterList + ZEROORONE(Elision), + RestParameter + ZEROORONE(Elision), + RequiredParameterList + ',' + OptionalParameterList + ZEROORONE(Elision), + RequiredParameterList + ',' + RestParameter + ZEROORONE(Elision), + OptionalParameterList + ',' + RestParameter + ZEROORONE(Elision), + RequiredParameterList + ',' + OptionalParameterList + ',' + RestParameter + ZEROORONE(Elision)) + +## rule RequiredParameterList: RequiredParameter RequiredParameterList , RequiredParameter +rule RequiredParameterList: ONEOF(RequiredParameter, + RequiredParameterList + ',' + RequiredParameter) + +## rule RequiredParameter: AccessibilityModifieropt BindingIdentifierOrPattern TypeAnnotationopt BindingIdentifier : StringLiteral +## NOTE: I extend StringLiteral to Literal. +## NOTE: I Added initializer. I guess the spec missed this part. +rule RequiredParameter: ONEOF( + ZEROORMORE(AccessibilityModifier) + BindingIdentifierOrPattern + ZEROORONE(TypeAnnotation) + ZEROORONE(Initializer), + "this" + ZEROORONE(TypeAnnotation), + BindingIdentifier + ':' + Literal, + ObjectType) + attr.action.%1 : AddInitTo(%2, %4) + attr.action.%1 : BuildDecl(%3, %2) + attr.action.%2 : BuildDecl(%2, %1) + +## rule AccessibilityModifier: public private protected +rule AccessibilityModifier: ONEOF("public", "private", "protected", "readonly", "static", "abstract", "async") + +## rule BindingIdentifierOrPattern: BindingIdentifier BindingPattern +rule BindingIdentifierOrPattern: ONEOF(BindingIdentifier, BindingPattern) + +## rule OptionalParameterList: OptionalParameter OptionalParameterList , OptionalParameter +rule OptionalParameterList: ONEOF(OptionalParameter, + OptionalParameterList + ',' + OptionalParameter) + +## rule OptionalParameter: AccessibilityModifieropt BindingIdentifierOrPattern ? TypeAnnotationopt AccessibilityModifieropt BindingIdentifierOrPattern TypeAnnotationopt Initializer BindingIdentifier ? : StringLiteral +rule OptionalParameter: ONEOF( + ZEROORMORE(AccessibilityModifier) + BindingIdentifierOrPattern + '?' + ZEROORONE(TypeAnnotation), + ZEROORMORE(AccessibilityModifier) + BindingIdentifierOrPattern + ZEROORONE(TypeAnnotation) + Initializer, + BindingIdentifier + '?' + ':' + Literal) + attr.action.%1 : SetIsOptional(%2) + attr.action.%1 : BuildDecl(%4, %2) + attr.action.%2 : AddInitTo(%2, %4) + attr.action.%2 : BuildDecl(%3, %2) + attr.action.%3 : SetIsOptional(%1) + +## rule RestParameter: ... BindingIdentifier TypeAnnotationopt +rule RestParameter: "..." + BindingIdentifier + ZEROORONE(TypeAnnotation) + attr.action : AddType(%2, %3) + attr.action : SetIsRest(%2) + +## rule ConstructSignature: new TypeParametersopt ( ParameterListopt ) TypeAnnotationopt +rule ConstructSignature : + "new" + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + attr.action : BuildFunction() + attr.action : AddParams(%4) + attr.action : AddType(%6) + attr.action : SetConstructSignature() + +## rule IndexSignature: [ BindingIdentifier : string ] TypeAnnotation [ BindingIdentifier : number ] TypeAnnotation +rule IndexSigPrefix : ONEOF('+', '-') +rule IndexSigModifier : ONEOF("readonly", '?') + +rule IndexSignature: ONEOF( + ZEROORONE(IndexSigPrefix) + ZEROORONE(IndexSigModifier) + '[' + BindingIdentifier + ':' + "string" + ']' + ZEROORONE(IndexSigPrefix) + ZEROORONE(IndexSigModifier) + TypeAnnotation, + ZEROORONE(IndexSigPrefix) + ZEROORONE(IndexSigModifier) + '[' + BindingIdentifier + ':' + "number" + ']' + ZEROORONE(IndexSigPrefix) + ZEROORONE(IndexSigModifier) + TypeAnnotation) + attr.action.%1 : BuildStrIndexSig(%4, %10) + attr.action.%2 : BuildNumIndexSig(%4, %10) + +rule KeywordMethodName : ONEOF("return", + "throw", + "continue", + "if", + "import", + "export") + attr.action : BuildIdentifier() + +## rule MethodSignature: PropertyName ?opt CallSignature +## I inlined CallSignature +rule MethodSignature: ONEOF( + PropertyName + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation), + PropertyName + '?' + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation), + KeywordMethodName + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation), + KeywordMethodName + '?' + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation)) + attr.action.%1,%2,%3,%4 : BuildFunction(%1) + attr.action.%1,%3 : AddParams(%4) + attr.action.%1,%3 : AddType(%6) + attr.action.%1,%3 : AddTypeGenerics(%2) + attr.action.%2,%4 : SetIsOptional(%1) + attr.action.%2,%4 : AddParams(%5) + attr.action.%2,%4 : AddType(%7) + attr.action.%2,%4 : AddTypeGenerics(%3) + +## rule TypeAliasDeclaration: type BindingIdentifier TypeParametersopt = Type ; +rule TypeAliasDeclaration: "type" + BindingIdentifier + ZEROORONE(TypeParameters) + '=' + Type + ZEROORONE(';') + attr.action : BuildTypeAlias(%2, %5) + attr.action : AddTypeGenerics(%3) + + +############################################################################################## +## A.2 Expression +############################################################################################## + +rule AllPropertyName : ONEOF(PropertyName, KeywordPropName) + +## PropertyDefinition: ( Modified ) IdentifierReference CoverInitializedName PropertyName : AssignmentExpression PropertyName CallSignature { FunctionBody } GetAccessor SetAccessor +rule PropertyDefinition: ONEOF(IdentifierReference, + CoverInitializedName, + AllPropertyName + ':' + AssignmentExpression, + ZEROORONE(AccessibilityModifier) + AllPropertyName + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + + ZEROORONE(TypeAnnotation) + '{' + FunctionBody + '}', + GetAccessor, + SetAccessor, + SpreadElement) + attr.action.%3 : BuildFieldLiteral(%1, %3) + attr.action.%4 : BuildFunction(%2) + attr.action.%4 : AddType(%7) + attr.action.%4 : AddParams(%5) + attr.action.%4 : AddFunctionBody(%9) + +## GetAccessor: get PropertyName ( ) TypeAnnotationopt { FunctionBody } +rule GetAccessor: ONEOF(ZEROORONE(AccessibilityModifier) + "get" + PropertyName + '(' + ')' + ZEROORONE(TypeAnnotation) + '{' + FunctionBody + '}', + ZEROORONE(AccessibilityModifier) + "get" + '(' + "this" + ')' + ZEROORONE(TypeAnnotation) + '{' + FunctionBody + '}', + ZEROORONE(AccessibilityModifier) + "get" + PropertyName + '(' + ')' + ZEROORONE(TypeAnnotation) + ';', + ZEROORONE(AccessibilityModifier) + "get" + '(' + "this" + ')' + ZEROORONE(TypeAnnotation) + ';', + ZEROORONE(AccessibilityModifier) + "get" + '(' + ')' + ZEROORONE(TypeAnnotation) + '{' + FunctionBody + '}') + attr.action.%1,%3 : BuildFunction(%3) + attr.action.%1,%3 : SetGetAccessor() + attr.action.%1,%3 : AddType(%6) + attr.action.%1 : AddFunctionBody(%8) + attr.action.%1,%3 : AddModifier(%2) + attr.action.%1,%3 : AddModifier(%1) + attr.action.%2,%4,%5 : BuildFunction(%2) + attr.action.%2,%4,%5 : SetGetAccessor() + attr.action.%2,%4 : AddType(%6) + attr.action.%2 : AddFunctionBody(%8) + attr.action.%2,%4 : AddModifier(%2) + attr.action.%2,%4 : AddModifier(%1) + attr.action.%5 : AddType(%5) + attr.action.%5 : AddFunctionBody(%7) + +## SetAccessor: set PropertyName ( BindingIdentifierOrPattern TypeAnnotationopt ) { FunctionBody } +rule SetAccessor: ONEOF(ZEROORONE(AccessibilityModifier) + "set" + PropertyName + '(' + BindingIdentifierOrPattern + ZEROORONE(TypeAnnotation) + ')' + '{' + FunctionBody + '}', + ZEROORONE(AccessibilityModifier) + "set" + '(' + "this" + ',' + BindingIdentifierOrPattern + ZEROORONE(TypeAnnotation) + ')' + '{' + FunctionBody + '}', + ZEROORONE(AccessibilityModifier) + "set" + PropertyName + '(' + BindingIdentifierOrPattern + ZEROORONE(TypeAnnotation) + ')' + ';', + ZEROORONE(AccessibilityModifier) + "set" + '(' + "this" + ',' + BindingIdentifierOrPattern + ZEROORONE(TypeAnnotation) + ')' + ';', + ZEROORONE(AccessibilityModifier) + "set" + '(' BindingIdentifierOrPattern + ZEROORONE(TypeAnnotation) + ')' + '{' + FunctionBody + '}') + attr.action.%1,%3 : AddType(%5, %6) + attr.action.%1,%3 : BuildFunction(%3) + attr.action.%1,%3 : SetSetAccessor() + attr.action.%1,%3 : AddParams(%5) + attr.action.%1 : AddFunctionBody(%9) + attr.action.%1,%3 : AddModifier(%2) + attr.action.%1,%3 : AddModifier(%1) + attr.action.%2,%4 : AddType(%6, %7) + attr.action.%2,%4,%5 : BuildFunction() + attr.action.%2,%4,%5 : SetSetAccessor() + attr.action.%2,%4 : AddParams(%6) + attr.action.%2 : AddFunctionBody(%10) + attr.action.%2,%4 : AddModifier(%2) + attr.action.%2,%4 : AddModifier(%1) + attr.action.%5 : AddParams(%4) + attr.action.%5 : AddFunctionBody(%8) + attr.action.%5 : AddModifier(%1) + +## We allow get/set as identifier for function name only. +## we don't want to see keywords as identifier happening in everywhere. +rule FunctionNameKeyword : ONEOF("get", "set") +rule FunctionName : ONEOF(BindingIdentifier, FunctionNameKeyword) + +## FunctionExpression: ( Modified ) function BindingIdentifieropt CallSignature { FunctionBody } +## FunctionExpression has the same syntax as FunctionDeclaration. But it appears as an expression. We will build it +## as a FunctionNode in AST. +rule FunctionExpression : + "function" + ZEROORONE(FunctionName) + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + '{' + FunctionBody + '}' + attr.action : BuildFunction(%2) + attr.action : AddTypeGenerics(%3) + attr.action : AddParams(%5) + attr.action : AddType(%7) + attr.action : AddFunctionBody(%9) + +# ArrowFormalParameter is used in ArrowFunction, and Typescript modified +# it to be CallSignature. As usual, I'd like to inline CallSignature in +# those rules. +## ArrowFormalParameters: ( Modified ) CallSignature + +## Arguments: ( Modified ) TypeArgumentsopt ( ArgumentListopt ) +## UnaryExpression: ( Modified ) … < Type > UnaryExpression + +############################################################################################## +## A.4 Functions +############################################################################################## + +## FunctionDeclaration: ( Modified ) +## function BindingIdentifieropt CallSignature { FunctionBody } +## function BindingIdentifieropt CallSignature ; + +# NOTE: Inline Call signature to make it easier to write action. +rule FunctionDeclaration : ONEOF( + ZEROORMORE(AccessibilityModifier) + "function" + ZEROORONE(FunctionName) + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + '{' + FunctionBody + '}', + ZEROORMORE(AccessibilityModifier) + "function" + ZEROORONE(FunctionName) + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ':' + AssertExpression + '{' + FunctionBody + '}', + ZEROORMORE(AccessibilityModifier) + "function" + ZEROORONE(FunctionName) + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ':' + IsExpression + '{' + FunctionBody + '}', + ZEROORMORE(AccessibilityModifier) + "function" + ZEROORONE(FunctionName) + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + ZEROORONE(';'), + ZEROORMORE(AccessibilityModifier) + "function" + ZEROORONE(FunctionName) + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ':' + IsExpression + ZEROORONE(';')) + attr.action.%1,%2,%3,%4,%5 : BuildFunction(%3) + attr.action.%1,%2,%3,%4,%5 : AddParams(%6) + attr.action.%1,%2,%3,%4,%5 : AddModifier(%1) + attr.action.%1,%4 : AddType(%8) + attr.action.%1,%2,%3,%4,%5 : AddTypeGenerics(%4) + attr.action.%2,%3,%5 : AddAssert(%9) + attr.action.%1 : AddFunctionBody(%10) + attr.action.%2,%3 : AddFunctionBody(%11) + +############################################################################################## +## A.5 Interface +############################################################################################## + +##InterfaceDeclaration: interface BindingIdentifier TypeParametersopt InterfaceExtendsClauseopt ObjectType +rule InterfaceDeclaration : + "interface" + BindingIdentifier + ZEROORONE(TypeParameters) + ZEROORONE(InterfaceExtendsClause) + '{' + ZEROORONE(TypeBody) + '}' + attr.action : BuildStruct(%2) + attr.action : SetTSInterface() + attr.action : AddTypeGenerics(%3) + attr.action : AddStructField(%6) + attr.action : AddSuperInterface(%4) + +##InterfaceExtendsClause: extends ClassOrInterfaceTypeList +rule InterfaceExtendsClause: "extends" + ClassOrInterfaceTypeList + +##ClassOrInterfaceTypeList: ClassOrInterfaceType ClassOrInterfaceTypeList , ClassOrInterfaceType +rule ClassOrInterfaceTypeList: ONEOF(ClassOrInterfaceType, + ClassOrInterfaceTypeList + ',' + ClassOrInterfaceType) + +##ClassOrInterfaceType: TypeReference +rule ClassOrInterfaceType: TypeReference + +############################################################################################## +## A.6 Class declaration +############################################################################################## + +## ClassDeclaration: ( Modified ) class BindingIdentifieropt TypeParametersopt ClassHeritage { ClassBody } +## NOTE. I inlined ClassHeritage to avoid 'lookahead fail' +rule ClassDeclaration: + ZEROORMORE(Annotation) + ZEROORONE("abstract") + "class" + ZEROORONE(BindingIdentifier) + ZEROORONE(TypeParameters) + ZEROORONE(ClassExtendsClause) + ZEROORONE(ImplementsClause) + '{' + ZEROORONE(ClassBody) + '}' + attr.action : BuildClass(%4) + attr.action : AddModifier(%1) + attr.action : AddModifier(%2) + attr.action : AddTypeGenerics(%5) + attr.action : AddSuperClass(%6) + attr.action : AddSuperInterface(%7) + attr.action : AddClassBody(%9) + +rule Annotation : '@' + MemberExpression + ZEROORONE(Arguments) + attr.action : BuildAnnotation(%2) + attr.action : AddArguments(%3) + +## ClassHeritage: ( Modified ) ClassExtendsClauseopt ImplementsClauseopt +rule ClassHeritage: ZEROORONE(ClassExtendsClause) + ZEROORONE(ImplementsClause) + +## ClassExtendsClause: extends ClassType +rule ClassExtendsClause: ONEOF("extends" + ZEROORONE('(') + ClassType + ZEROORONE(')'), + "extends" + CallExpression) + +## ClassType: TypeReference +rule ClassType: TypeReference + +## ImplementsClause: implements ClassOrInterfaceTypeList +rule ImplementsClause: "implements" + ClassOrInterfaceTypeList + +## ClassElement: ( Modified ) ConstructorDeclaration PropertyMemberDeclaration IndexMemberDeclaration +rule ClassElement: ONEOF(ConstructorDeclaration, + PropertyMemberDeclaration, + IndexMemberDeclaration) + attr.property : Single + +## ConstructorDeclaration: AccessibilityModifieropt constructor ( ParameterListopt ) { FunctionBody } AccessibilityModifieropt constructor ( ParameterListopt ) ; +rule ConstructorDeclaration: ONEOF( + ZEROORONE(AccessibilityModifier) + "constructor" + '(' + ZEROORONE(ParameterList) + ')' + '{' + FunctionBody + '}', + ZEROORONE(AccessibilityModifier) + "constructor" + '(' + ZEROORONE(ParameterList) + ')' + ';') + attr.action.%1,%2 : BuildConstructor() + attr.action.%1,%2 : AddParams(%4) + attr.action.%1,%2 : AddModifier(%1) + attr.action.%1 : AddFunctionBody(%7) + +## PropertyMemberDeclaration: MemberVariableDeclaration MemberFunctionDeclaration MemberAccessorDeclaration +rule PropertyMemberDeclaration: ONEOF(MemberVariableDeclaration, + MemberFunctionDeclaration + ZEROORONE(';'), + MemberAccessorDeclaration + ZEROORONE(';'), + MemberExternalDeclaration) + +## MemberVariableDeclaration: AccessibilityModifieropt staticopt PropertyName TypeAnnotationopt Initializeropt ; +rule MemberVariableDeclaration: ONEOF( + ZEROORMORE(Annotation) + ZEROORMORE(AccessibilityModifier) + PropertySignatureName + ZEROORONE(TypeAnnotation) + ZEROORONE(Initializer) + ZEROORONE(';'), + ZEROORMORE(Annotation) + ZEROORMORE(AccessibilityModifier) + PropertySignatureName + '?' + ZEROORONE(TypeAnnotation) + ZEROORONE(Initializer) + ZEROORONE(';'), + ZEROORMORE(Annotation) + ZEROORMORE(AccessibilityModifier) + "get" + '=' + ArrowFunction + ZEROORONE(';'), + ZEROORMORE(Annotation) + ZEROORMORE(AccessibilityModifier) + "set" + '=' + ArrowFunction + ZEROORONE(';'), + '#' + PropertySignatureName + ZEROORONE(TypeAnnotation) + ZEROORONE(Initializer) + ZEROORONE(';'), + '#' + "private" + ZEROORONE(TypeAnnotation) + ZEROORONE(Initializer) + ZEROORONE(';'), + ZEROORMORE(Annotation) + ZEROORMORE(AccessibilityModifier) + "if" + ZEROORONE(TypeAnnotation) + ZEROORONE(Initializer) + ZEROORONE(';')) + attr.action.%1: AddInitTo(%3, %5) + attr.action.%1: AddType(%3, %4) + attr.action.%1: AddModifierTo(%3, %2) + attr.action.%1: AddModifierTo(%3, %1) + attr.action.%1: BuildDecl(%4, %3) + attr.action.%2: AddInitTo(%3, %6) + attr.action.%2: AddType(%3, %5) + attr.action.%2: AddModifierTo(%3, %2) + attr.action.%2: AddModifierTo(%3, %1) + attr.action.%2: SetIsOptional(%3) + attr.action.%2: BuildDecl(%4, %3) + attr.action.%3,%4: BuildIdentifier(%3) + attr.action.%3,%4: AddInitTo(%5) + attr.action.%3,%4: AddModifier(%2) + attr.action.%3,%4: AddModifier(%1) + attr.action.%3,%4: BuildDecl() + attr.action.%5: AddInitTo(%2, %4) + attr.action.%6: BuildIdentifier(%2) + attr.action.%6: AddInitTo(%4) + attr.action.%5,%6: AddType(%3) + attr.action.%5,%6: AddModifier(%1) + attr.action.%5,%6: BuildDecl() + attr.action.%7 : BuildIdentifier(%3) + attr.action.%7 : AddType(%4) + attr.action.%7 : AddModifier(%1) + attr.action.%7 : AddModifier(%2) + attr.action.%7 : AddInitTo(%5) + attr.action.%7 : BuildDecl() + +rule KeywordMemberFunctionName : ONEOF("return", + "get", + "set", + "continue", + "break", + "const", + "let", + "var", + "if", + "else", + "for", + "try", + "export") + attr.action : BuildIdentifier() + +## MemberFunctionDeclaration: AccessibilityModifieropt staticopt PropertyName CallSignature { FunctionBody } AccessibilityModifieropt staticopt PropertyName CallSignature ; +#NOTE: I inlined CallSignature to make it easier for building function. +#rule CallSignature: ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) +rule MemberFunctionDeclaration: ONEOF( + ZEROORONE(Annotation) + ZEROORMORE(AccessibilityModifier) + PropertyName + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + '{' + FunctionBody + '}', + ZEROORONE(Annotation) + ZEROORMORE(AccessibilityModifier) + PropertyName + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + ZEROORONE(';'), + ZEROORONE(Annotation) + ZEROORMORE(AccessibilityModifier) + PropertyName + '?' + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + '{' + FunctionBody + '}', + ZEROORONE(Annotation) + ZEROORMORE(AccessibilityModifier) + PropertyName + '?' + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + ZEROORONE(';'), + ZEROORONE(Annotation) + ZEROORMORE(AccessibilityModifier) + PropertyName + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ':' + IsExpression + '{' + FunctionBody + '}', + ZEROORONE(Annotation) + ZEROORMORE(AccessibilityModifier) + PropertyName + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ':' + IsExpression + ZEROORONE(';'), + + ZEROORONE(Annotation) + ZEROORMORE(AccessibilityModifier) + KeywordMemberFunctionName + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + '{' + FunctionBody + '}', + + ZEROORONE(Annotation) + ZEROORMORE(AccessibilityModifier) + KeywordMemberFunctionName + ZEROORONE(TypeParameters) + '(' + ZEROORONE(ParameterList) + ')' + ZEROORONE(TypeAnnotation) + ZEROORONE(';'), + '*' + '[' + MemberExpression + ']' + '(' + ')' + '{' + FunctionBody + '}') + attr.action.%1,%2,%3,%4,%5,%6,%7,%8,%9 : BuildFunction(%3) + attr.action.%1,%2,%3,%4,%5,%6,%7,%8 : AddModifier(%2) + attr.action.%1,%2,%3,%4,%5,%6,%7,%8 : AddModifier(%1) + attr.action.%1,%2,%5,%6,%7,%8 : AddTypeGenerics(%4) + attr.action.%1,%2,%5,%6,%7,%8 : AddParams(%6) + attr.action.%1,%2,%7,%8 : AddType(%8) + attr.action.%1,%7 : AddFunctionBody(%10) + attr.action.%3,%4 : AddTypeGenerics(%5) + attr.action.%3,%4 : AddParams(%7) + attr.action.%3,%4 : AddType(%9) + attr.action.%3 : AddFunctionBody(%11) + attr.action.%3,%4 : SetIsOptional(%3) + attr.action.%5,%6 : AddType(%9) + attr.action.%5 : AddFunctionBody(%11) + attr.action.%9 : SetIsIterator() + attr.action.%9 : AddFunctionBody(%8) + +## MemberAccessorDeclaration: AccessibilityModifieropt staticopt GetAccessor AccessibilityModifieropt staticopt SetAccessor +rule MemberAccessorDeclaration: ONEOF( + ZEROORONE(Annotation) + ZEROORMORE(AccessibilityModifier) + GetAccessor, + ZEROORONE(Annotation) + ZEROORMORE(AccessibilityModifier) + SetAccessor) + attr.action.%1,%2 : AddModifierTo(%3, %1) + +## IndexMemberDeclaration: IndexSignature ; +rule IndexMemberDeclaration: IndexSignature + ZEROORONE(';') + +rule MemberExternalDeclaration : ZEROORMORE(AccessibilityModifier) + "declare" + VariableDeclaration + ';' + attr.action : BuildExternalDeclaration(%3) + attr.action : AddModifier(%1) +################################################################################################# +# A.7 Enums +################################################################################################# +## EnumDeclaration: constopt enum BindingIdentifier { EnumBodyopt } +rule EnumDeclaration: + ZEROORONE("const") + "enum" + BindingIdentifier + '{' + ZEROORONE(EnumBody) + '}' + attr.action : BuildStruct(%3) + attr.action : SetTSEnum() + attr.action : AddStructField(%5) + +## EnumBody: EnumMemberList ,opt +rule EnumBody: EnumMemberList + ZEROORONE(',') + +## EnumMemberList: EnumMember EnumMemberList , EnumMember +rule EnumMemberList: ONEOF(EnumMember, + EnumMemberList + ',' + EnumMember) + +## EnumMember: PropertyName PropertyName = EnumValue +rule EnumMember: ONEOF(PropertyName, + PropertyName + '=' + EnumValue, + KeywordPropName + '=' + EnumValue) + attr.action.%2,%3 : AddInitTo(%1, %3) + +## EnumValue: AssignmentExpression +rule EnumValue: AssignmentExpression + +################################################################################################# +## A.8 Namespaces +################################################################################################# + +##NamespaceDeclaration: namespace IdentifierPath { NamespaceBody } +rule NamespaceDeclaration: "namespace" + IdentifierPath + '{' + NamespaceBody + '}' + attr.property : Top + attr.action : BuildNamespace(%2) + attr.action : AddNamespaceBody(%4) + +##IdentifierPath: BindingIdentifier IdentifierPath . BindingIdentifier +rule IdentifierPath: ONEOF(BindingIdentifier, + IdentifierPath + '.' + BindingIdentifier) + attr.action.%2 : BuildField(%1, %3) + +##NamespaceBody: NamespaceElementsopt +rule NamespaceBody: ZEROORONE(NamespaceElements) + +##NamespaceElements: NamespaceElement NamespaceElements NamespaceElement +rule NamespaceElements: ONEOF(NamespaceElement, + NamespaceElements + NamespaceElement) + +##NamespaceElement: Statement LexicalDeclaration FunctionDeclaration GeneratorDeclaration ClassDeclaration InterfaceDeclaration TypeAliasDeclaration EnumDeclaration NamespaceDeclaration AmbientDeclaration ImportAliasDeclaration ExportNamespaceElement +rule NamespaceElement: ONEOF(Statement, + LexicalDeclaration + ZEROORONE(';'), + FunctionDeclaration, + #GeneratorDeclaration, + ClassDeclaration, + InterfaceDeclaration, + TypeAliasDeclaration, + EnumDeclaration, + NamespaceDeclaration, + #AmbientDeclaration, + ImportAliasDeclaration, + ExportNamespaceElement) + +##ExportNamespaceElement: export VariableStatement export LexicalDeclaration export FunctionDeclaration export GeneratorDeclaration export ClassDeclaration export InterfaceDeclaration export TypeAliasDeclaration export EnumDeclaration export NamespaceDeclaration export AmbientDeclaration export ImportAliasDeclaration +rule ExportNamespaceElement: ONEOF("export" + VariableStatement, + "export" + LexicalDeclaration + ZEROORONE(';'), + "export" + FunctionDeclaration, +# "export" + GeneratorDeclaration, + "export" + ClassDeclaration, + "export" + InterfaceDeclaration, + "export" + TypeAliasDeclaration, + "export" + EnumDeclaration, + "export" + NamespaceDeclaration, +# "export" + AmbientDeclaration, + "export" + ImportAliasDeclaration, + ExportDeclaration) + attr.action.%1,%2,%3,%4,%5,%6,%7,%8,%9 : BuildExport() + attr.action.%1,%2,%3,%4,%5,%6,%7,%8,%9 : SetPairs(%2) + +##ImportAliasDeclaration: import BindingIdentifier = EntityName ; +rule NamespaceImportPair: BindingIdentifier + '=' + EntityName + attr.action : BuildXXportAsPair(%3, %1) + +rule ImportAliasDeclaration: "import" + NamespaceImportPair + ';' + attr.action : BuildImport() + attr.action : SetPairs(%2) + +##EntityName: NamespaceName NamespaceName . IdentifierReference +rule EntityName: ONEOF(NamespaceName, + NamespaceName + '.' + IdentifierReference) + attr.action.%2 : BuildField(%1, %3) + +################################################################################################# +# declare syntax +################################################################################################# + +rule ExternalDeclaration : ONEOF("declare" + NamespaceDeclaration, + "declare" + LexicalDeclaration + ZEROORONE(';'), + "declare" + ClassDeclaration, + "declare" + InterfaceDeclaration, + "declare" + FunctionDeclaration, + "declare" + VariableStatement, + "declare" + TypeAliasDeclaration, + "declare" + EnumDeclaration, + "declare" + ExternalModuleDeclaration) + attr.action.%1,%2,%3,%4,%5,%6,%7,%8,%9 : BuildExternalDeclaration(%2) + +## for global declaration +## https://www.typescriptlang.org/docs/handbook/declaration-files/templates/global-modifying-module-d-ts.html +rule GlobalDeclMember : ONEOF(NamespaceDeclaration, + LexicalDeclaration + ZEROORONE(';'), + ClassDeclaration, + InterfaceDeclaration, + FunctionDeclaration, + VariableStatement, + TypeAliasDeclaration, + EnumDeclaration, + ExternalModuleDeclaration) +rule GlobalDeclMembers : "global" + '{' + ZEROORMORE(GlobalDeclMember) + '}' + attr.action : BuildGlobalExternalDeclaration(%3) +rule GlobalDeclaration : "declare" + GlobalDeclMembers + attr.action : PassChild(%2) + +################################################################################################# +# A.9 Scripts and Modules +################################################################################################# + +# The module name could be an identifier or string literal. +rule ExternalModuleDeclaration : ONEOF("module" + IdentifierReference + '{' + DeclarationModule + '}', + "module" + Literal + '{' + DeclarationModule + '}') + attr.property : Top + attr.action.%1,%2 : BuildModule(%2) + attr.action.%1,%2 : AddModuleBody(%4) + attr.action.%2 : SetIsAmbient() + +#DeclarationElement: InterfaceDeclaration TypeAliasDeclaration NamespaceDeclaration AmbientDeclaration ImportAliasDeclaration +rule DeclarationElement: ONEOF(InterfaceDeclaration, + TypeAliasDeclaration, + LexicalDeclaration + ZEROORONE(';'), + VariableDeclaration, + FunctionDeclaration, + ClassDeclaration, + EnumDeclaration, + NamespaceDeclaration, + AmbientDeclaration, + GlobalDeclMembers, + ImportAliasDeclaration) + +# ImplementationModule: ImplementationModuleElementsopt +# ImplementationModuleElements: ImplementationModuleElement ImplementationModuleElements ImplementationModuleElement +# ImplementationModuleElement: ImplementationElement ImportDeclaration ImportAliasDeclaration ImportRequireDeclaration ExportImplementationElement ExportDefaultImplementationElement ExportListDeclaration ExportAssignment + +# DeclarationModule: DeclarationModuleElementsopt +rule DeclarationModule: ZEROORONE(DeclarationModuleElements) + +# DeclarationModuleElements: DeclarationModuleElement DeclarationModuleElements DeclarationModuleElement +rule DeclarationModuleElements: ONEOF(DeclarationModuleElement, + DeclarationModuleElements + DeclarationModuleElement) + +# DeclarationModuleElement: DeclarationElement ImportDeclaration ImportAliasDeclaration ExportDeclarationElement ExportDefaultDeclarationElement ExportListDeclaration ExportAssignment +rule DeclarationModuleElement: ONEOF(DeclarationElement, + ImportDeclaration, + ImportAliasDeclaration, + ExportDeclaration, + Statement) + #ExportDefaultDeclarationElement, + #ExportListDeclaration, + #ExportAssignment) + +################################################################################################# +# A.10 Ambient +# NOTE : I changed the rules a lot, making it quite different than v1.8 spec. +################################################################################################# + +# AmbientDeclaration: declare AmbientVariableDeclaration declare AmbientFunctionDeclaration declare AmbientClassDeclaration declare AmbientEnumDeclaration declare AmbientNamespaceDeclaration +rule AmbientDeclaration: ONEOF("declare" + VariableDeclaration, + "declare" + FunctionDeclaration, + "declare" + ClassDeclaration, + "declare" + EnumDeclaration, + "declare" + NamespaceDeclaration) + attr.action.%1,%2,%3,%4,%5 : BuildExternalDeclaration(%2) diff --git a/src/MapleFE/typescript/type.spec b/src/MapleFE/typescript/type.spec new file mode 100644 index 0000000000000000000000000000000000000000..42f739d09b86610e5d10efc2602feae3666b4848 --- /dev/null +++ b/src/MapleFE/typescript/type.spec @@ -0,0 +1,81 @@ +# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# +# OpenArkFE is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +################################################################################### +# This file defines the Java types. +# +# 1. Child rules have to be defined before parent rules. +# 2. For type.spec, Autogen allows the programmer to have special keyword section to +# define the individual . Please keep in mind this +# keyword section has to appear before the rule section. +# +# Keyword section is defined through STRUCT(). +# +# 3. Autogen will first read in the keyword section by TypeGen functions, then +# read the rules section by inheriting BaseGen::Parse, etc. +# 4. The keyword duplex is defined as . +# [NOTE] TYPE should be one of those recognized by the "parser". Please refer +# to ../shared/include/type.h. The data representation of same type +# doesnt have to be the same in each language, we just need have the +# same name of TYPE. The physical representation of each type of +# different language will be handled by HandleType() by each language. +# e.g. Char in java and in C are different. but Autogen doesnt care. +# java2mpl and c2mpl will provide their own HandleType() to map this +# to the correct types in Maple IR. +# +# So there are 4 type systems involved in frontend. +# (1) Types in the .spec file, of each language +# (2) Types in Autogen. Super set of (1) in all languages. +# types in Autogen have an exact mapping to those in Parser. +# Autogen will generate type related files used in parser, mapping +# types to it. +# (3) Types in Parser. From now on, physical representation is defined. +# Each language has its own HandleTypes() to map type in Parser to +# those in MapleIR, considering physical representation. +# (4) Types in Maple IR. This is the only place where types have physical +# representation. +# +# 5. The supported STRUCT in type.spec is: +# Keyword +# Right now, only one STRUCT is supported. +# +# It is highly possible that a .spec file needs more than one STRUCT. +################################################################################### + +# The types recoganized by Autogen are in shared/supported_types.def +# where Boolean, Byte, .. are defined. That said, "Boolean" and the likes are +# used in type.spec as a keyword. +# +# This STRUCT tells the primitive types + +STRUCT Keyword : (("boolean", Boolean), + ("string", String), + ("number", Number), + ("symbol", Symbol), + ("any", Any), + ("void", Void), + ("unknown", Unknown), + ("never", Never), + ("undefined", Undefined)) + +rule BooleanType : "boolean" +rule NumberType : "number" +rule SymbolType : "symbol" +rule AnyType : "any" +rule StringType : "string" +rule VoidType : "void" +rule UnknownType : "unknown" +rule NeverType : "never" +rule UndefinedType : "undefined" + +rule TYPE : ONEOF(BooleanType, NumberType, SymbolType, AnyType, StringType, VoidType, UnknownType, NeverType, UndefinedType) diff --git a/src/hir2mpl/BUILD.gn b/src/hir2mpl/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..80b4e5e920ecc003426b7bf3ef3ded50aad58a32 --- /dev/null +++ b/src/hir2mpl/BUILD.gn @@ -0,0 +1,403 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] +if (COV_CHECK == 1) { + cflags = [ "-DENABLE_COV_CHECK=1" ] +} + +cflags += [ + "-DMIR_FEATURE_FULL=1", + "-DHIR2MPL_FULL_INFO_DUMP=1", + "-DJAVA_OBJ_IN_MFILE=1", +] + +if (MAST == 1) { + cflags += [ + "-w", + "-DENABLE_MAST", + ] +} + +include_directories = [ + "${HIR2MPL_ROOT}/common/include", + "${HIR2MPL_ROOT}/optimize/include", + "${HIR2MPL_ROOT}/bytecode_input/class/include", + "${HIR2MPL_ROOT}/bytecode_input/common/include", + "${HIR2MPL_ROOT}/bytecode_input/dex/include", + "${MAPLEALL_ROOT}/maple_ir/include", + "${MAPLEALL_ROOT}/maple_ipa/include", + "${MAPLEALL_ROOT}/maple_ipa/include/old", + "${MAPLEALL_ROOT}/maple_util/include", + "${MAPLEALL_ROOT}/maple_phase/include", + "${MAPLEALL_ROOT}/maple_driver/include", + "${MAPLEALL_ROOT}/mpl2mpl/include", + "${MAPLEALL_ROOT}/maple_me/include", + "${MAPLEALL_ROOT}/mempool/include", + "${THIRD_PARTY_ROOT}/bounds_checking_function/include", + "${HIR2MPL_ROOT}/ast_input/clang/include", + "${HIR2MPL_ROOT}/ast_input/clang/lib", + "${HIR2MPL_ROOT}/ast_input/common/include", + "${HIR2MPL_ROOT}/ast_input/maple/include", + "${HIR2MPL_ROOT}/ast_input/maple/lib", + "${LLVMINC}", + "${THIRD_PARTY_ROOT}/llvm_modified/clang/tools", +] + +if (MAST == 1) { + include_directories += [ + "${MAPLE_PARSER_PATH}/output/c/ast_gen/shared", + "${MAPLE_PARSER_PATH}/shared/include", + "${MAPLE_PARSER_PATH}/astopt/include", + ] +} + +static_library("lib_hir2mpl_common") { + sources = [ + "${HIR2MPL_ROOT}/common/src/base64.cpp", + "${HIR2MPL_ROOT}/common/src/basic_io.cpp", + "${HIR2MPL_ROOT}/common/src/fe_config_parallel.cpp", + "${HIR2MPL_ROOT}/common/src/fe_file_ops.cpp", + "${HIR2MPL_ROOT}/common/src/fe_file_type.cpp", + "${HIR2MPL_ROOT}/common/src/fe_function.cpp", + "${HIR2MPL_ROOT}/common/src/fe_function_phase_result.cpp", + "${HIR2MPL_ROOT}/common/src/fe_input_helper.cpp", + "${HIR2MPL_ROOT}/common/src/fe_java_string_manager.cpp", + "${HIR2MPL_ROOT}/common/src/fe_manager.cpp", + "${HIR2MPL_ROOT}/common/src/fe_options.cpp", + "${HIR2MPL_ROOT}/common/src/fe_struct_elem_info.cpp", + "${HIR2MPL_ROOT}/common/src/fe_timer_ns.cpp", + "${HIR2MPL_ROOT}/common/src/fe_type_hierarchy.cpp", + "${HIR2MPL_ROOT}/common/src/fe_type_manager.cpp", + "${HIR2MPL_ROOT}/common/src/fe_utils.cpp", + "${HIR2MPL_ROOT}/common/src/fe_utils_ast.cpp", + "${HIR2MPL_ROOT}/common/src/fe_utils_java.cpp", + "${HIR2MPL_ROOT}/common/src/fe_diag_manager.cpp", + "${HIR2MPL_ROOT}/common/src/feir_builder.cpp", + "${HIR2MPL_ROOT}/common/src/feir_stmt.cpp", + "${HIR2MPL_ROOT}/common/src/feir_type.cpp", + "${HIR2MPL_ROOT}/common/src/feir_type_helper.cpp", + "${HIR2MPL_ROOT}/common/src/feir_type_infer.cpp", + "${HIR2MPL_ROOT}/common/src/feir_var.cpp", + "${HIR2MPL_ROOT}/common/src/feir_var_name.cpp", + "${HIR2MPL_ROOT}/common/src/feir_var_reg.cpp", + "${HIR2MPL_ROOT}/common/src/feir_var_type_scatter.cpp", + "${HIR2MPL_ROOT}/common/src/hir2mpl_compiler.cpp", + "${HIR2MPL_ROOT}/common/src/hir2mpl_compiler_component.cpp", + "${HIR2MPL_ROOT}/common/src/hir2mpl_env.cpp", + "${HIR2MPL_ROOT}/common/src/hir2mpl_options.cpp", + "${HIR2MPL_ROOT}/common/src/simple_xml.cpp", + "${HIR2MPL_ROOT}/common/src/simple_zip.cpp", + "${HIR2MPL_ROOT}/common/src/generic_attrs.cpp", + "${HIR2MPL_ROOT}/common/src/enhance_c_checker.cpp", + ] + include_dirs = include_directories + output_dir = "${root_out_dir}/ar" + + if (MAJOR_VERSION != "") { + cflags_cc += [ "-DMAJOR_VERSION=${MAJOR_VERSION}", ] + } + + if (MINOR_VERSION != "") { + cflags_cc += [ "-DMINOR_VERSION=${MINOR_VERSION}", ] + } + + if (RELEASE_VERSION != "") { + cflags_cc += [ "-DRELEASE_VERSION=\"${RELEASE_VERSION}\"", ] + } + + if (BUILD_VERSION != "") { + cflags_cc += [ "-DBUILD_VERSION=${BUILD_VERSION}", ] + } + + if (GIT_REVISION != "") { + cflags_cc += [ "-DGIT_REVISION=\"${GIT_REVISION}\"", ] + } +} + +static_library("lib_hir2mpl_optimize") { + sources = [ + "${HIR2MPL_ROOT}/optimize/src/ror.cpp", + "${HIR2MPL_ROOT}/optimize/src/conditional_operator.cpp", + "${HIR2MPL_ROOT}/optimize/src/feir_lower.cpp", + "${HIR2MPL_ROOT}/optimize/src/feir_bb.cpp", + "${HIR2MPL_ROOT}/optimize/src/feir_cfg.cpp", + "${HIR2MPL_ROOT}/optimize/src/feir_dfg.cpp" + ] + include_dirs = include_directories + output_dir = "${root_out_dir}/ar" +} + +static_library("lib_hir2mpl_input_helper") { + sources = [ "${HIR2MPL_ROOT}/common/src/fe_input_helper.cpp" ] + include_dirs = include_directories + output_dir = "${root_out_dir}/ar" +} + +executable("hir2mpl") { + sources = [ "${HIR2MPL_ROOT}/common/src/hir2mpl.cpp" ] + include_dirs = include_directories + deps = [ + ":lib_hir2mpl_ast_input_clang", + ":lib_hir2mpl_ast_input_common", + ":lib_hir2mpl_bytecode_input_common", + ":lib_hir2mpl_bytecode_input_dex", + ":lib_hir2mpl_input_helper", + ":lib_hir2mpl_bytecode_input_class", + ":lib_hir2mpl_common", + ":lib_hir2mpl_optimize", + "${MAPLEALL_ROOT}/maple_driver:libdriver_option", + "${MAPLEALL_ROOT}/maple_ir:libmplir", + "${MAPLEALL_ROOT}/maple_util:libmplutil", + "${MAPLEALL_ROOT}/mempool:libmempool", + "${MAPLEALL_ROOT}/mpl2mpl:libmpl2mpl", + "${THIRD_PARTY_ROOT}/bounds_checking_function:libHWSecureC", + ] + if (MAST == 1) { + deps += [ + ":lib_hir2mpl_ast_input_maple", + ] + } + ldflags = [ + "-lz", + "-rdynamic", + "-L${LLVMLIBDIR}/", + ] + + if (MAST == 1) { + ldflags += [ + "-lstdc++fs", + "-L${MAPLE_PARSER_PATH}/output/c/ast_gen/shared", + ] + } +} + +include_bytecode_input_jbc_directories = [ + "${HIR2MPL_ROOT}/common/include", + "${HIR2MPL_ROOT}/optimize/include", + "${HIR2MPL_ROOT}/bytecode_input/class/include", + "${MAPLEALL_ROOT}/maple_ir/include", + "${MAPLEALL_ROOT}/maple_util/include", + "${MAPLEALL_ROOT}/maple_driver/include", + "${MAPLEALL_ROOT}/mempool/include", + "${THIRD_PARTY_ROOT}/bounds_checking_function/include", +] + +static_library("lib_hir2mpl_bytecode_input_class") { + sources = [ + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_attr.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_attr_item.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_bb.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_class.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_class2fe_helper.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_class_const.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_class_const_pool.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_compiler_component.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_function.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_function_context.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_input.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_opcode.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_opcode_helper.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_stack2fe_helper.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_stack_helper.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_stmt.cpp", + "${HIR2MPL_ROOT}/bytecode_input/class/src/jbc_util.cpp", + ] + include_dirs = include_bytecode_input_jbc_directories + output_dir = "${root_out_dir}/ar" +} + +include_bytecode_input_common_directories = [ + "${HIR2MPL_ROOT}/common/include", + "${HIR2MPL_ROOT}/optimize/include", + "${HIR2MPL_ROOT}/bytecode_input/common/include", + "${HIR2MPL_ROOT}/bytecode_input/dex/include", + "${MAPLEALL_ROOT}/maple_ir/include", + "${MAPLEALL_ROOT}/maple_util/include", + "${MAPLEALL_ROOT}/maple_driver/include", + "${MAPLEALL_ROOT}/mempool/include", + "${THIRD_PARTY_ROOT}/bounds_checking_function/include", +] + +static_library("lib_hir2mpl_bytecode_input_common") { + sources = [ + "${HIR2MPL_ROOT}/bytecode_input/common/src/ark_annotation_map.cpp", + "${HIR2MPL_ROOT}/bytecode_input/common/src/ark_annotation_processor.cpp", + "${HIR2MPL_ROOT}/bytecode_input/common/src/bc_class.cpp", + "${HIR2MPL_ROOT}/bytecode_input/common/src/bc_class2fe_helper.cpp", + "${HIR2MPL_ROOT}/bytecode_input/common/src/bc_function.cpp", + "${HIR2MPL_ROOT}/bytecode_input/common/src/bc_instruction.cpp", + "${HIR2MPL_ROOT}/bytecode_input/common/src/bc_io.cpp", + "${HIR2MPL_ROOT}/bytecode_input/common/src/bc_parser_base.cpp", + "${HIR2MPL_ROOT}/bytecode_input/common/src/bc_pragma.cpp", + "${HIR2MPL_ROOT}/bytecode_input/common/src/bc_util.cpp", + "${HIR2MPL_ROOT}/bytecode_input/common/src/rc_setter.cpp", + ] + include_dirs = include_bytecode_input_common_directories + output_dir = "${root_out_dir}/ar" +} + +include_bytecode_input_dex_directories = [ + "${HIR2MPL_ROOT}/common/include", + "${HIR2MPL_ROOT}/optimize/include", + "${HIR2MPL_ROOT}/bytecode_input/common/include", + "${HIR2MPL_ROOT}/bytecode_input/dex/include", + "${MAPLEALL_ROOT}/maple_ir/include", + "${MAPLEALL_ROOT}/maple_util/include", + "${MAPLEALL_ROOT}/maple_driver/include", + "${MAPLEALL_ROOT}/mempool/include", + "${THIRD_PARTY_ROOT}/bounds_checking_function/include", +] + +static_library("lib_hir2mpl_bytecode_input_dex") { + sources = [ + "${HIR2MPL_ROOT}/bytecode_input/dex/src/class_linker.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/class_loader_context.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dex_class.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dex_class2fe_helper.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dex_encode_value.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dex_file_util.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dex_op.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dex_pragma.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dex_strfac.cpp", + ] + + # for libdexfile + include_dirs_dex = [ "${THIRD_PARTY_ROOT}/aosp_modified/system/core/include" ] + include_dirs_libdexfile = [ + #for libdexfile -start + "${THIRD_PARTY_ROOT}/aosp_modified/system/core/liblog/include", + "${THIRD_PARTY_ROOT}/aosp_modified/system/core/libutils/include", + "${THIRD_PARTY_ROOT}/aosp_modified/system/core/base/include", + "${THIRD_PARTY_ROOT}/aosp_modified/system/core/libziparchive/include", + "${THIRD_PARTY_ROOT}/aosp_modified/art/libartpalette/include", + "${THIRD_PARTY_ROOT}/aosp_modified/art/libartbase", + "${THIRD_PARTY_ROOT}/aosp_modified/art/libdexfile", + "${THIRD_PARTY_ROOT}/aosp_modified/include", + "${THIRD_PARTY_ROOT}/aosp_modified/libnativehelper/include_jni", + + #for libdexfile -end + ] + + sources += [ + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dex_parser.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dex_reader.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dexfile_factory.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dexfile_interface.cpp", + "${HIR2MPL_ROOT}/bytecode_input/dex/src/dexfile_libdexfile.cpp", + ] + deps_libdexfile = [ + "${THIRD_PARTY_ROOT}/aosp_modified/art/libdexfile:libdexfile", + "${THIRD_PARTY_ROOT}/aosp_modified/system/core/libziparchive:libziparchive", + "${THIRD_PARTY_ROOT}/aosp_modified/system/core/base:libbase", + ] + lib_dex = [ "${THIRD_PARTY_ROOT}/aosp_modified/system/core/liblog/liblog.a" ] + deps = deps_libdexfile + libs = lib_dex + include_dirs = + include_bytecode_input_dex_directories + include_dirs_libdexfile + include_dirs_dex + output_dir = "${root_out_dir}/ar" +} + +static_library("lib_hir2mpl_ast_input_clang_lib") { + sources = [ "${HIR2MPL_ROOT}/ast_input/clang/lib/ast_interface.cpp" ] + include_dirs = include_directories + defines = [ + "CLANG_ENABLE_ARCMT", + "CLANG_ENABLE_OBJC_REWRITER", + "CLANG_ENABLE_STATIC_ANALYZER", + "GTEST_HAS_RTTI=0", + "_DEBUG", + "_GNU_SOURCE", + "__STDC_CONSTANT_MACROS", + "__STDC_FORMAT_MACROS", + "__STDC_LIMIT_MACROS", + ] + + output_dir = "${root_out_dir}/ar" + libs = [ + "${LLVMLIBDIR}/libclang.so", + "${LLVMLIBDIR}/libclang-cpp.so", + "${LLVMLIBDIR}/libclangFrontend.a", + "${LLVMLIBDIR}/libclangDriver.a", + "${LLVMLIBDIR}/libclangSerialization.a", + "${LLVMLIBDIR}/libclangParse.a", + "${LLVMLIBDIR}/libclangSema.a", + "${LLVMLIBDIR}/libclangEdit.a", + "${LLVMLIBDIR}/libclangLex.a", + "${LLVMLIBDIR}/libclangAnalysis.a", + "${LLVMLIBDIR}/libclangAST.a", + "${LLVMLIBDIR}/libclangBasic.a", + "${LLVMLIBDIR}/libLLVMDemangle.a", + "${LLVMLIBDIR}/libLLVMMCParser.a", + "${LLVMLIBDIR}/libLLVMMC.a", + "${LLVMLIBDIR}/libLLVMBitReader.a", + "${LLVMLIBDIR}/libLLVMCore.a", + "${LLVMLIBDIR}/libLLVMBinaryFormat.a", + "${LLVMLIBDIR}/libLLVMProfileData.a", + "${LLVMLIBDIR}/libLLVMOption.a", + "${LLVMLIBDIR}/libLLVMSupport.a", + ] +} + +static_library("lib_hir2mpl_ast_input_common") { + sources = [ + "${HIR2MPL_ROOT}/ast_input/common/src/ast_decl.cpp", + ] + include_dirs = include_directories + output_dir = "${root_out_dir}/ar" +} + +static_library("lib_hir2mpl_ast_input_clang") { + sources = [ + "${HIR2MPL_ROOT}/ast_input/clang/lib/ast_type.cpp", + "${HIR2MPL_ROOT}/ast_input/clang/lib/ast_util.cpp", + "${HIR2MPL_ROOT}/ast_input/clang/src/ast_expr.cpp", + "${HIR2MPL_ROOT}/ast_input/clang/src/ast_function.cpp", + "${HIR2MPL_ROOT}/ast_input/clang/src/ast_parser.cpp", + "${HIR2MPL_ROOT}/ast_input/clang/src/ast_parser_builting_func.cpp", + "${HIR2MPL_ROOT}/ast_input/clang/src/ast_stmt.cpp", + "${HIR2MPL_ROOT}/ast_input/clang/src/ast_struct2fe_helper.cpp", + ] + include_dirs = include_directories + deps = [ ":lib_hir2mpl_ast_input_clang_lib" ] + output_dir = "${root_out_dir}/ar" +} + +if (MAST == 1) { + static_library("lib_hir2mpl_ast_input_maple_lib") { + sources = [ "${HIR2MPL_ROOT}/ast_input/maple/lib/maple_ast_interface.cpp" ] + include_dirs = include_directories + defines = [ + "DEBUG", + ] + output_dir = "${root_out_dir}/ar" + libs = [ + "${MAPLE_PARSER_PATH}/output/c/ast_gen/shared/genast.a", + "${MAPLE_PARSER_PATH}/output/c/shared/shared.a", + "${MAPLE_PARSER_PATH}/output/c/gen/gen.a", + "${MAPLE_PARSER_PATH}/output/c/astopt/astopt.a", + ] + } + + static_library("lib_hir2mpl_ast_input_maple") { + sources = [ + "${HIR2MPL_ROOT}/ast_input/maple/src/maple_ast_parser.cpp", + ] + include_dirs = include_directories + deps = [ ":lib_hir2mpl_ast_input_maple_lib" ] + output_dir = "${root_out_dir}/ar" + } +} + diff --git a/src/hir2mpl/README.md b/src/hir2mpl/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ce48eeaad2359730fbff5b92d4f0f74db6395bdf --- /dev/null +++ b/src/hir2mpl/README.md @@ -0,0 +1,108 @@ +``` +# +# Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# +# http://license.coscl.org.cn/MulanPSL2 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v2 for more details. +# +``` + +Hir2mpl supports .ast, .dex, .class and .jar as inputs. Currently, .class and .jar are not enabled. +hir2mpl enables the corresponding compilation process based on the inputs. + +## Building hir2mpl + +source build/envsetup.sh arm release/debug + +make hir2mpl + +## Usage + +hir2mpl -h to view available options + +## Compile .dex + +First, use java2dex to generate the required xxx.dex file from xxx.java. + +bash ${OUT_ROOT}/tools/bin/java2dex -o xxx.dex -p -i xxx.java + +If the xxx.dex file depends on other files, use the -mplt command to add the depended file. + +the depended mplts need to compile firstly. Also, you can use the -Xbootclasspath to + +load the dependent JAR package. + +${OUT_ROOT}/aarch64-clang-release/bin/hir2mpl -mplt xxx.dex -o xxx.mpl + +${OUT_ROOT}/aarch64-clang-release/bin/hir2mpl -Xbootclasspath= xxx.dex -o xxx.mpl + +Note: +1. The GC mode is used for memory management by default. + If you want to use the RC mode, you can use the "-rc" option to switch. +2. Invalid option scope "ast Compile Options" and "Security Check". + +## Compile .ast + +First, use clang to generate the required xxx.ast file from xxx.c. + +${MAPLE_ROOT}/tools/clang+llvm-10.0.0-x86_64-linux-gnu-ubuntu-18.04/bin/clang -emit-ast xxx.c -o xxx.ast + +${OUT_ROOT}/aarch64-clang-release/bin/hir2mpl xxx.ast -o xxx.mpl + +Note: +1. The backend supports variable arrays that are incomplete. + By default, the frontend intercepts variable arrays. + You can use the "-enable-variable-array" option to enable the frontend to support variable arrays. + +2. hir2mpl supports static security check and check statement insertion based on source code annotation. + However, the source code must be compiled using the Clang binary provided by the Maple community. + You can enable the corresponding check by selecting the corresponding option "-npe-check-dynamic" + and "-boundary-check-dynamic". + +3. Invalid option scope "BC Bytecode Compile Options" and "On Demand Type Creation". + +## UT Test + +Building UT target : make hir2mplUT + +Before running the UT test, compile the libcore which the UT depends. + +make libcore + +bash $MAPLE_ROOT/src/hir2mpl/test/hir2mplUT_check.sh + +## Directory structure + +hir2mpl +├── ast_input # .ast/.mast parser +│   ├── clang +│   ├── common +│   └── maple +├── BUILD.gn # build configuration files +├── bytecode_input # .class/.dex parser +│   ├── class +│   ├── common +│   └── dex +├── common # feir part +│   ├── include +│   └── src +├── optimize # lower/cfg/dfg(TODO Refactoring) and pattern match opt +│   ├── include +│   └── src +├── README.md +└── test # UT test + ├── ast_input + ├── BUILD.gn + ├── bytecode_input + ├── common + ├── cov_check.sh + ├── hir2mplUT_check.sh + └── ops_ut_check.sh diff --git a/src/hir2mpl/ast_input/clang/include/ast_builtin_func.def b/src/hir2mpl/ast_input/clang/include/ast_builtin_func.def new file mode 100644 index 0000000000000000000000000000000000000000..d324177fa8e2cddc8a6f17c81c115c4f0f9b9aa9 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/include/ast_builtin_func.def @@ -0,0 +1,25 @@ +// BUILTIN_FUNC(funcName) +BUILTIN_FUNC(printf) +BUILTIN_FUNC(snprintf) +BUILTIN_FUNC(strncpy) +BUILTIN_FUNC(strcpy) +BUILTIN_FUNC(strcmp) +BUILTIN_FUNC(strncmp) +BUILTIN_FUNC(strlen) +BUILTIN_FUNC(strchr) +BUILTIN_FUNC(strrchr) +BUILTIN_FUNC(memcmp) +BUILTIN_FUNC(memcpy) +BUILTIN_FUNC(memset) +BUILTIN_FUNC(memmove) +BUILTIN_FUNC(__memcpy_chk) +BUILTIN_FUNC(__memset_chk) +BUILTIN_FUNC(abs) +BUILTIN_FUNC(abort) +BUILTIN_FUNC(frame_address) +BUILTIN_FUNC(setjmp) +BUILTIN_FUNC(longjmp) +BUILTIN_FUNC(bswap32) +BUILTIN_FUNC(bswap64) +BUILTIN_FUNC(bswap16) +BUILTIN_FUNC(mul_overflow) diff --git a/src/hir2mpl/ast_input/clang/include/ast_expr.h b/src/hir2mpl/ast_input/clang/include/ast_expr.h new file mode 100644 index 0000000000000000000000000000000000000000..88832e5024f6e8f06064e4d936eef0702e505253 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/include/ast_expr.h @@ -0,0 +1,1684 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_AST_INPUT_INCLUDE_AST_EXPR_H +#define HIR2MPL_AST_INPUT_INCLUDE_AST_EXPR_H +#include +#include "ast_op.h" +#include "feir_stmt.h" + +namespace maple { +class ASTDecl; +class ASTFunc; +class ASTStmt; +struct ASTValue { + union Value { + uint8 u8; + uint16 u16; + uint32 u32; + uint64 u64; + int8 i8; + int16 i16; + int32 i32; + float f32; + int64 i64; + double f64; + UStrIdx strIdx; + } val = { 0 }; + PrimType pty = PTY_begin; + + PrimType GetPrimType() const { + return pty; + } + + MIRConst *Translate2MIRConst() const; +}; + +enum ParentFlag { + kNoParent, + kArrayParent, + kStructParent +}; + +class ASTExpr { + public: + explicit ASTExpr(ASTOp o) : op(o) {} + virtual ~ASTExpr() = default; + UniqueFEIRExpr Emit2FEExpr(std::list &stmts) const; + UniqueFEIRExpr ImplicitInitFieldValue(MIRType *type, std::list &stmts) const; + + virtual MIRType *GetType() const { + return mirType; + } + + void SetType(MIRType *type) { + mirType = type; + } + + void SetASTDecl(ASTDecl *astDecl) { + refedDecl = astDecl; + } + + ASTDecl *GetASTDecl() const { + return GetASTDeclImpl(); + } + + ASTOp GetASTOp() const { + return op; + } + + void SetConstantValue(ASTValue *val) { + isConstantFolded = (val != nullptr); + value = val; + } + + bool IsConstantFolded() const { + return isConstantFolded; + } + + ASTValue *GetConstantValue() const { + return GetConstantValueImpl(); + } + + MIRConst *GenerateMIRConst() const { + return GenerateMIRConstImpl(); + } + + void SetSrcLOC(uint32 fileIdx, uint32 lineNum) { + srcFileIdx = fileIdx; + srcFileLineNum = lineNum; + } + + uint32 GetSrcFileIdx() const { + return srcFileIdx; + } + + uint32 GetSrcFileLineNum() const { + return srcFileLineNum; + } + + virtual void SetShortCircuitIdx(uint32 leftIdx, uint32 rightIdx) {} + + protected: + virtual ASTValue *GetConstantValueImpl() const { + return value; + } + virtual MIRConst *GenerateMIRConstImpl() const; + virtual UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const = 0; + + virtual ASTDecl *GetASTDeclImpl() const { + return refedDecl; + } + + ASTOp op; + MIRType *mirType = nullptr; + ASTDecl *refedDecl = nullptr; + bool isConstantFolded = false; + ASTValue *value = nullptr; + + uint32 srcFileIdx = 0; + uint32 srcFileLineNum = 0; +}; + +class ASTCastExpr : public ASTExpr { + public: + ASTCastExpr() : ASTExpr(kASTOpCast) {} + ~ASTCastExpr() = default; + + void SetASTExpr(ASTExpr *expr) { + child = expr; + } + + const ASTExpr *GetASTExpr() const { + return child; + } + + void SetSrcType(MIRType *type) { + src = type; + } + + const MIRType *GetSrcType() const { + return src; + } + + void SetDstType(MIRType *type) { + dst = type; + } + + const MIRType *GetDstType() const { + return dst; + } + + void SetNeededCvt(bool cvt) { + isNeededCvt = cvt; + } + + bool IsNeededCvt(const UniqueFEIRExpr &expr) const { + if (!isNeededCvt || expr == nullptr || dst == nullptr) { + return false; + } + PrimType srcPrimType = expr->GetPrimType(); + return srcPrimType != dst->GetPrimType() && srcPrimType != PTY_agg && srcPrimType != PTY_void; + } + + void SetComplexType(MIRType *type) { + complexType = type; + } + + void SetComplexCastKind(bool flag) { + imageZero = flag; + } + + void SetIsArrayToPointerDecay(bool flag) { + isArrayToPointerDecay = flag; + } + + bool IsBuilinFunc() const { + return isBuilinFunc; + } + + void SetBuilinFunc(bool flag) { + isBuilinFunc = flag; + } + + void SetUnionCast(bool flag) { + isUnoinCast = flag; + } + + void SetBitCast(bool flag) { + isBitCast = flag; + } + + void SetVectorSplat(bool flag) { + isVectorSplat = flag; + } + + protected: + MIRConst *GenerateMIRConstImpl() const override; + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + + ASTDecl *GetASTDeclImpl() const override { + return child->GetASTDecl(); + } + + UniqueFEIRExpr Emit2FEExprForComplex(const UniqueFEIRExpr &subExpr, const UniqueFEIRType &srcType, + std::list &stmts) const; + private: + MIRConst *GenerateMIRDoubleConst() const; + MIRConst *GenerateMIRFloatConst() const; + MIRConst *GenerateMIRIntConst() const; + UniqueFEIRExpr EmitExprVdupVector(PrimType primtype, UniqueFEIRExpr &subExpr) const; + void CheckNonnullFieldInStruct() const; + + ASTExpr *child = nullptr; + MIRType *src = nullptr; + MIRType *dst = nullptr; + bool isNeededCvt = false; + bool isBitCast = false; + MIRType *complexType = nullptr; + bool imageZero = false; + bool isArrayToPointerDecay = false; + bool isBuilinFunc = false; + bool isUnoinCast = false; + bool isVectorSplat = false; +}; + +class ASTDeclRefExpr : public ASTExpr { + public: + ASTDeclRefExpr() : ASTExpr(kASTOpRef) {} + ~ASTDeclRefExpr() = default; + + protected: + MIRConst *GenerateMIRConstImpl() const override; + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTUnaryOperatorExpr : public ASTExpr { + public: + explicit ASTUnaryOperatorExpr(ASTOp o) : ASTExpr(o) {} + virtual ~ASTUnaryOperatorExpr() = default; + void SetUOExpr(ASTExpr*); + + const ASTExpr *GetUOExpr() const { + return expr; + } + + void SetSubType(MIRType *type); + + const MIRType *GetMIRType() const { + return subType; + } + + void SetUOType(MIRType *type) { + uoType = type; + } + + const MIRType *GetUOType() const { + return uoType; + } + + void SetPointeeLen(int64 len) { + pointeeLen = len; + } + + int64 GetPointeeLen() const { + return pointeeLen; + } + + void SetGlobal(bool isGlobalArg) { + isGlobal = isGlobalArg; + } + + bool IsGlobal() const { + return isGlobal; + } + + UniqueFEIRExpr ASTUOSideEffectExpr(Opcode op, std::list &stmts, + const std::string &varName = "", bool post = false) const; + + protected: + bool isGlobal = false; + ASTExpr *expr = nullptr; + MIRType *subType = nullptr; + MIRType *uoType = nullptr; + int64 pointeeLen = 0; +}; + +class ASTUOMinusExpr: public ASTUnaryOperatorExpr { + public: + ASTUOMinusExpr() : ASTUnaryOperatorExpr(kASTOpMinus) {} + ~ASTUOMinusExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTUONotExpr: public ASTUnaryOperatorExpr { + public: + ASTUONotExpr() : ASTUnaryOperatorExpr(kASTOpNot) {} + ~ASTUONotExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTUOLNotExpr: public ASTUnaryOperatorExpr { + public: + ASTUOLNotExpr() : ASTUnaryOperatorExpr(kASTOpLNot) {} + ~ASTUOLNotExpr() = default; + + void SetShortCircuitIdx(uint32 leftIdx, uint32 rightIdx) override { + trueIdx = leftIdx; + falseIdx = rightIdx; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + uint32 trueIdx = 0; + uint32 falseIdx = 0; +}; + +class ASTUOPostIncExpr: public ASTUnaryOperatorExpr { + public: + ASTUOPostIncExpr() : ASTUnaryOperatorExpr(kASTOpPostInc), tempVarName(FEUtils::GetSequentialName("postinc_")) {} + ~ASTUOPostIncExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + std::string tempVarName; +}; + +class ASTUOPostDecExpr: public ASTUnaryOperatorExpr { + public: + ASTUOPostDecExpr() : ASTUnaryOperatorExpr(kASTOpPostDec), tempVarName(FEUtils::GetSequentialName("postdec_")) {} + ~ASTUOPostDecExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + std::string tempVarName; +}; + +class ASTUOPreIncExpr: public ASTUnaryOperatorExpr { + public: + ASTUOPreIncExpr() : ASTUnaryOperatorExpr(kASTOpPreInc) {} + ~ASTUOPreIncExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTUOPreDecExpr: public ASTUnaryOperatorExpr { + public: + ASTUOPreDecExpr() : ASTUnaryOperatorExpr(kASTOpPreDec) {} + ~ASTUOPreDecExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + std::string tempVarName; +}; + +class ASTUOAddrOfExpr: public ASTUnaryOperatorExpr { + public: + ASTUOAddrOfExpr() : ASTUnaryOperatorExpr(kASTOpAddrOf) {} + ~ASTUOAddrOfExpr() = default; + + protected: + MIRConst *GenerateMIRConstImpl() const override; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTUOAddrOfLabelExpr : public ASTUnaryOperatorExpr { + public: + ASTUOAddrOfLabelExpr() : ASTUnaryOperatorExpr(kASTOpAddrOfLabel) {} + ~ASTUOAddrOfLabelExpr() = default; + + void SetLabelName(const std::string &name) { + labelName = name; + } + + protected: + MIRConst *GenerateMIRConstImpl() const override; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + std::string labelName; +}; + +class ASTUODerefExpr: public ASTUnaryOperatorExpr { + public: + ASTUODerefExpr() : ASTUnaryOperatorExpr(kASTOpDeref) {} + ~ASTUODerefExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + void InsertNonnullChecking(std::list &stmts, UniqueFEIRExpr baseExpr) const; + bool InsertBoundaryChecking(std::list &stmts, UniqueFEIRExpr expr) const; +}; + +class ASTUOPlusExpr: public ASTUnaryOperatorExpr { + public: + ASTUOPlusExpr() : ASTUnaryOperatorExpr(kASTOpPlus) {} + ~ASTUOPlusExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTUORealExpr: public ASTUnaryOperatorExpr { + public: + ASTUORealExpr() : ASTUnaryOperatorExpr(kASTOpReal) {} + ~ASTUORealExpr() = default; + + void SetElementType(MIRType *type) { + elementType = type; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + MIRType *elementType = nullptr; +}; + +class ASTUOImagExpr: public ASTUnaryOperatorExpr { + public: + ASTUOImagExpr() : ASTUnaryOperatorExpr(kASTOpImag) {} + ~ASTUOImagExpr() = default; + + void SetElementType(MIRType *type) { + elementType = type; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + MIRType *elementType = nullptr; +}; + +class ASTUOExtensionExpr: public ASTUnaryOperatorExpr { + public: + ASTUOExtensionExpr() : ASTUnaryOperatorExpr(kASTOpExtension) {} + ~ASTUOExtensionExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTUOCoawaitExpr: public ASTUnaryOperatorExpr { + public: + ASTUOCoawaitExpr() : ASTUnaryOperatorExpr(kASTOpCoawait) {} + ~ASTUOCoawaitExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTPredefinedExpr : public ASTExpr { + public: + ASTPredefinedExpr() : ASTExpr(kASTOpPredefined) {} + ~ASTPredefinedExpr() = default; + void SetASTExpr(ASTExpr*); + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + ASTExpr *child = nullptr; +}; + +class ASTOpaqueValueExpr : public ASTExpr { + public: + ASTOpaqueValueExpr() : ASTExpr(kASTOpOpaqueValue) {} + ~ASTOpaqueValueExpr() = default; + void SetASTExpr(ASTExpr*); + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + ASTExpr *child = nullptr; +}; + +class ASTNoInitExpr : public ASTExpr { + public: + ASTNoInitExpr() : ASTExpr(kASTOpNoInitExpr) {} + ~ASTNoInitExpr() = default; + void SetNoInitType(MIRType *type); + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + MIRType *noInitType = nullptr; +}; + +class ASTCompoundLiteralExpr : public ASTExpr { + public: + ASTCompoundLiteralExpr() : ASTExpr(kASTOpCompoundLiteralExpr) {} + ~ASTCompoundLiteralExpr() = default; + void SetCompoundLiteralType(MIRType *clType); + void SetASTExpr(ASTExpr*); + + void SetAddrof(bool flag) { + isAddrof = flag; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + MIRConst *GenerateMIRConstImpl() const override; + MIRConst *GenerateMIRPtrConst() const; + ASTExpr *child = nullptr; + MIRType *compoundLiteralType = nullptr; + bool isAddrof = false; +}; + +class ASTOffsetOfExpr : public ASTExpr { + public: + ASTOffsetOfExpr() : ASTExpr(kASTOpOffsetOfExpr) {} + ~ASTOffsetOfExpr() = default; + void SetStructType(MIRType *stype); + void SetFieldName(const std::string &fName); + + void SetOffset(size_t val) { + offset = val; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + MIRType *structType = nullptr; + std::string fieldName; + size_t offset = 0; +}; + +class ASTInitListExpr : public ASTExpr { + public: + ASTInitListExpr() : ASTExpr(kASTOpInitListExpr) {} + ~ASTInitListExpr() = default; + void SetInitExprs(ASTExpr *astExpr); + void SetInitListType(MIRType *type); + + const MIRType *GetInitListType() const { + return initListType; + } + + std::vector GetInitExprs() const { + return initExprs; + } + + void SetInitListVarName(const std::string &argVarName) { + varName = argVarName; + } + + const std::string &GetInitListVarName() const { + return varName; + } + + void SetParentFlag(ParentFlag argParentFlag) { + parentFlag = argParentFlag; + } + + void SetUnionInitFieldIdx(uint32 idx) { + unionInitFieldIdx = idx; + } + + uint32 GetUnionInitFieldIdx() const { + return unionInitFieldIdx; + } + + void SetHasArrayFiller(bool flag) { + hasArrayFiller = flag; + } + + bool HasArrayFiller() const { + return hasArrayFiller; + } + + void SetTransparent(bool flag) { + isTransparent = flag; + } + + bool IsTransparent() const { + return isTransparent; + } + + void SetArrayFiller(ASTExpr *expr) { + arrayFillerExpr = expr; + } + + const ASTExpr *GetArrayFillter() const { + return arrayFillerExpr; + } + + void SetHasVectorType(bool flag) { + hasVectorType = flag; + } + + bool HasVectorType() const { + return hasVectorType; + } + + private: + MIRConst *GenerateMIRConstImpl() const override; + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + void ProcessInitList(std::variant, UniqueFEIRExpr> &base, ASTInitListExpr *initList, + std::list &stmts) const; + void ProcessArrayInitList(const UniqueFEIRExpr &addrOfArray, ASTInitListExpr *initList, + std::list &stmts) const; + void ProcessStructInitList(std::variant, UniqueFEIRExpr> &base, + ASTInitListExpr *initList, std::list &stmts) const; + void ProcessVectorInitList(std::variant, UniqueFEIRExpr> &base, + ASTInitListExpr *initList, std::list &stmts) const; + MIRIntrinsicID SetVectorSetLane(const MIRType &type) const; + void ProcessDesignatedInitUpdater(std::variant, UniqueFEIRExpr> &base, + ASTExpr *expr, std::list &stmts) const; + void ProcessStringLiteralInitList(const UniqueFEIRExpr &addrOfCharArray, const UniqueFEIRExpr &addrOfStringLiteral, + size_t stringLength, std::list &stmts) const; + void ProcessImplicitInit(const UniqueFEIRExpr &addrExpr, uint32 initSize, uint32 total, uint32 elemSize, + std::list &stmts) const; + MIRConst *GenerateMIRConstForArray() const; + MIRConst *GenerateMIRConstForStruct() const; + std::vector initExprs; + ASTExpr *arrayFillerExpr = nullptr; + MIRType *initListType = nullptr; + std::string varName; + ParentFlag parentFlag = kNoParent; + uint32 unionInitFieldIdx = UINT32_MAX; + bool hasArrayFiller = false; + bool isTransparent = false; + bool hasVectorType = false; +}; + +class ASTBinaryConditionalOperator : public ASTExpr { + public: + ASTBinaryConditionalOperator() : ASTExpr(kASTOpBinaryConditionalOperator) {} + ~ASTBinaryConditionalOperator() = default; + void SetCondExpr(ASTExpr *expr); + void SetFalseExpr(ASTExpr *expr); + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + ASTExpr *condExpr = nullptr; + ASTExpr *falseExpr = nullptr; +}; + +class ASTBinaryOperatorExpr : public ASTExpr { + public: + explicit ASTBinaryOperatorExpr(ASTOp o) : ASTExpr(o) {} + ASTBinaryOperatorExpr() + : ASTExpr(kASTOpBO), varName(FEUtils::GetSequentialName("shortCircuit_")) {} + + ~ASTBinaryOperatorExpr() override = default; + + void SetRetType(MIRType *type) { + retType = type; + } + + MIRType *GetRetType() const { + return retType; + } + + void SetLeftExpr(ASTExpr *expr) { + leftExpr = expr; + } + + void SetRightExpr(ASTExpr *expr) { + rightExpr = expr; + } + + void SetOpcode(Opcode op) { + opcode = op; + } + + Opcode GetOp() const { + return opcode; + } + + void SetComplexElementType(MIRType *type) { + complexElementType = type; + } + + void SetComplexLeftRealExpr(ASTExpr *expr) { + leftRealExpr = expr; + } + + void SetComplexLeftImagExpr(ASTExpr *expr) { + leftImagExpr = expr; + } + + void SetComplexRightRealExpr(ASTExpr *expr) { + rightRealExpr = expr; + } + + void SetComplexRightImagExpr(ASTExpr *expr) { + rightImagExpr = expr; + } + + void SetCvtNeeded(bool needed) { + cvtNeeded = needed; + } + + void SetShortCircuitIdx(uint32 leftIdx, uint32 rightIdx) override { + trueIdx = leftIdx; + falseIdx = rightIdx; + } + + UniqueFEIRType SelectBinaryOperatorType(UniqueFEIRExpr &left, UniqueFEIRExpr &right) const; + + protected: + MIRConst *GenerateMIRConstImpl() const override; + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + UniqueFEIRExpr Emit2FEExprComplexCalculations(std::list &stmts) const; + UniqueFEIRExpr Emit2FEExprComplexCompare(std::list &stmts) const; + UniqueFEIRExpr Emit2FEExprLogicOperate(std::list &stmts) const; + UniqueFEIRExpr Emit2FEExprLogicOperateSimplify(std::list &stmts) const; + + Opcode opcode = OP_undef; + MIRType *retType = nullptr; + MIRType *complexElementType = nullptr; + ASTExpr *leftExpr = nullptr; + ASTExpr *rightExpr = nullptr; + ASTExpr *leftRealExpr = nullptr; + ASTExpr *leftImagExpr = nullptr; + ASTExpr *rightRealExpr = nullptr; + ASTExpr *rightImagExpr = nullptr; + bool cvtNeeded = false; + std::string varName; + uint32 trueIdx = 0; + uint32 falseIdx = 0; +}; + +class ASTImplicitValueInitExpr : public ASTExpr { + public: + ASTImplicitValueInitExpr() : ASTExpr(kASTImplicitValueInitExpr) {} + ~ASTImplicitValueInitExpr() = default; + + protected: + MIRConst *GenerateMIRConstImpl() const override; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTStringLiteral : public ASTExpr { + public: + ASTStringLiteral() : ASTExpr(kASTStringLiteral) {} + ~ASTStringLiteral() = default; + + void SetLength(size_t len) { + length = len; + } + + size_t GetLength() const { + return length; + } + + void SetCodeUnits(std::vector &units) { + codeUnits = std::move(units); + } + + const std::vector &GetCodeUnits() const { + return codeUnits; + } + + void SetStr(const std::string &strIn) { + str = strIn; + } + + const std::string &GetStr() const { + return str; + } + + void SetIsArrayToPointerDecay(bool argIsArrayToPointerDecay) { + isArrayToPointerDecay = argIsArrayToPointerDecay; + } + + bool IsArrayToPointerDecay() const { + return isArrayToPointerDecay; + } + + protected: + MIRConst *GenerateMIRConstImpl() const override; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + size_t length = 0; + std::vector codeUnits; + std::string str; // Ascii string + bool isArrayToPointerDecay = false; +}; + +class ASTArraySubscriptExpr : public ASTExpr { + public: + ASTArraySubscriptExpr() : ASTExpr(kASTSubscriptExpr) {} + ~ASTArraySubscriptExpr() = default; + + void SetBaseExpr(ASTExpr *astExpr) { + baseExpr = astExpr; + } + + const ASTExpr *GetBaseExpr() const { + return baseExpr; + } + + void SetIdxExpr(ASTExpr *astExpr) { + idxExpr = astExpr; + } + + const ASTExpr *GetIdxExpr() const { + return idxExpr; + } + + void SetArrayType(MIRType *ty) { + arrayType = ty; + } + + const MIRType *GetArrayType() const { + return arrayType; + } + + size_t CalculateOffset() const; + + void SetIsVLA(bool flag) { + isVLA = flag; + } + + private: + ASTExpr *FindFinalBase() const; + MIRConst *GenerateMIRConstImpl() const override; + bool CheckFirstDimIfZero(const MIRType *arrayType) const; + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + void InsertNonnullChecking(std::list &stmts, const UniqueFEIRExpr &idxExpr, + const UniqueFEIRExpr &addrOfArray) const; + bool InsertBoundaryChecking(std::list &stmts, UniqueFEIRExpr indexExpr, + UniqueFEIRExpr baseAddrFEExpr) const; + + ASTExpr *baseExpr = nullptr; + MIRType *arrayType = nullptr; + ASTExpr *idxExpr = nullptr; + bool isVLA = false; +}; + +class ASTExprUnaryExprOrTypeTraitExpr : public ASTExpr { + public: + ASTExprUnaryExprOrTypeTraitExpr() : ASTExpr(kASTExprUnaryExprOrTypeTraitExpr) {} + ~ASTExprUnaryExprOrTypeTraitExpr() = default; + + void SetIsType(bool type) { + isType = type; + } + + void SetArgType(MIRType *type) { + argType = type; + } + + void SetArgExpr(ASTExpr *astExpr) { + argExpr = astExpr; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + bool isType = false; + MIRType *argType = nullptr; + ASTExpr *argExpr = nullptr; +}; + +class ASTMemberExpr : public ASTExpr { + public: + ASTMemberExpr() : ASTExpr(kASTMemberExpr) {} + ~ASTMemberExpr() = default; + + void SetBaseExpr(ASTExpr *astExpr) { + baseExpr = astExpr; + } + + ASTExpr *GetBaseExpr() const { + return baseExpr; + } + + void SetMemberName(std::string name) { + memberName = std::move(name); + } + + std::string GetMemberName() const { + return memberName; + } + + void SetMemberType(MIRType *type) { + memberType = type; + } + + void SetBaseType(MIRType *type) { + baseType = type; + } + + const MIRType *GetMemberType() const { + return memberType; + } + + const MIRType *GetBaseType() const { + return baseType; + } + + void SetIsArrow(bool arrow) { + isArrow = arrow; + } + + bool GetIsArrow() const { + return isArrow; + } + + void SetFiledOffsetBits(uint64 offset) { + fieldOffsetBits = offset; + } + + uint64 GetFieldOffsetBits() const { + return fieldOffsetBits; + } + + private: + MIRConst *GenerateMIRConstImpl() const override; + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + const ASTMemberExpr *FindFinalMember(const ASTMemberExpr *startExpr, std::list &memberNames) const; + void InsertNonnullChecking(std::list &stmts, UniqueFEIRExpr baseFEExpr) const; + + ASTExpr *baseExpr = nullptr; + std::string memberName; + MIRType *memberType = nullptr; + MIRType *baseType = nullptr; + bool isArrow = false; + uint64 fieldOffsetBits = 0; +}; + +class ASTDesignatedInitUpdateExpr : public ASTExpr { + public: + ASTDesignatedInitUpdateExpr() : ASTExpr(kASTASTDesignatedInitUpdateExpr) {} + ~ASTDesignatedInitUpdateExpr() = default; + + void SetBaseExpr(ASTExpr *astExpr) { + baseExpr = astExpr; + } + + ASTExpr *GetBaseExpr() const{ + return baseExpr; + } + + void SetUpdaterExpr(ASTExpr *astExpr) { + updaterExpr = astExpr; + } + + ASTExpr *GetUpdaterExpr() const{ + return updaterExpr; + } + + void SetInitListType(MIRType *type) { + initListType = type; + } + + MIRType *GetInitListType() const { + return initListType; + } + + void SetInitListVarName (const std::string &name) { + initListVarName = name; + } + + const std::string &GetInitListVarName() const { + return initListVarName; + } + + private: + MIRConst *GenerateMIRConstImpl() const override; + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + ASTExpr *baseExpr = nullptr; + ASTExpr *updaterExpr = nullptr; + MIRType *initListType = nullptr; + std::string initListVarName; +}; + +class ASTAssignExpr : public ASTBinaryOperatorExpr { + public: + ASTAssignExpr() : ASTBinaryOperatorExpr(kASTOpAssign), isCompoundAssign(false) {} + ~ASTAssignExpr() override = default; + + void SetIsCompoundAssign(bool argIsCompoundAssign) { + isCompoundAssign = argIsCompoundAssign; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + void GetActualRightExpr(UniqueFEIRExpr &right, const UniqueFEIRExpr &left) const; + bool IsInsertNonnullChecking(const UniqueFEIRExpr &rExpr) const; + bool isCompoundAssign = false; +}; + +class ASTBOComma : public ASTBinaryOperatorExpr { + public: + ASTBOComma() : ASTBinaryOperatorExpr(kASTOpComma) {} + ~ASTBOComma() override = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTBOPtrMemExpr : public ASTBinaryOperatorExpr { + public: + ASTBOPtrMemExpr() : ASTBinaryOperatorExpr(kASTOpPtrMemD) {} + ~ASTBOPtrMemExpr() override = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTCallExpr : public ASTExpr { + public: + ASTCallExpr() : ASTExpr(kASTOpCall), varName(FEUtils::GetSequentialName("retVar_")) {} + ~ASTCallExpr() = default; + void SetCalleeExpr(ASTExpr *astExpr) { + calleeExpr = astExpr; + } + + ASTExpr *GetCalleeExpr() const { + return calleeExpr; + } + + void SetArgs(std::vector &argsVector){ + args = std::move(argsVector); + } + + const std::vector &GetArgsExpr() const { + return args; + } + + void SetRetType(MIRType *typeIn) { + retType = typeIn; + } + + MIRType *GetRetType() const { + return retType; + } + + const std::string &GetRetVarName() const { + return varName; + } + + void SetFuncName(const std::string &name) { + funcName = name; + } + + const std::string &GetFuncName() const { + return funcName; + } + + void SetFuncAttrs(const FuncAttrs &attrs) { + funcAttrs = attrs; + } + + const FuncAttrs &GetFuncAttrs() const { + return funcAttrs; + } + + void SetIcall(bool icall) { + isIcall = icall; + } + + bool IsIcall() const { + return isIcall; + } + + bool IsNeedRetExpr() const { + return retType->GetPrimType() != PTY_void; + } + + bool IsFirstArgRet() const { + // If the return value exceeds 16 bytes, it is passed as the first parameter. + return retType->GetPrimType() == PTY_agg && retType->GetSize() > 16; + } + + void SetFuncDecl(ASTFunc *decl) { + funcDecl = decl; + } + + std::string CvtBuiltInFuncName(std::string builtInName) const; + UniqueFEIRExpr ProcessBuiltinFunc(std::list &stmts, bool &isFinish) const; + std::unique_ptr GenCallStmt() const; + void AddArgsExpr(const std::unique_ptr &callStmt, std::list &stmts) const; + UniqueFEIRExpr AddRetExpr(const std::unique_ptr &callStmt) const; + void InsertBoundaryCheckingInArgs(std::list &stmts) const; + void InsertBoundaryCheckingInArgsForICall(std::list &stmts, const UniqueFEIRExpr &calleeFEExpr) const; + void InsertBoundaryVarInRet(std::list &stmts) const; + void InsertNonnullCheckingForIcall(const UniqueFEIRExpr &expr, std::list &stmts) const; + void CheckNonnullFieldInStruct() const; + + private: + using FuncPtrBuiltinFunc = UniqueFEIRExpr (ASTCallExpr::*)(std::list &stmts) const; + static std::unordered_map InitBuiltinFuncPtrMap(); + UniqueFEIRExpr CreateIntrinsicopForC(std::list &stmts, MIRIntrinsicID argIntrinsicID, + bool genTempVar = true) const; + UniqueFEIRExpr CreateIntrinsicCallForC(std::list &stmts, + MIRIntrinsicID argIntrinsicID) const; + UniqueFEIRExpr CreateBinaryExpr(std::list &stmts, Opcode op) const; + UniqueFEIRExpr EmitBuiltinFunc(std::list &stmts) const; + UniqueFEIRExpr EmitBuiltinVectorZip(std::list &stmts, bool &isFinish) const; + UniqueFEIRExpr EmitBuiltinRotate(std::list &stmts, PrimType rotType, bool isLeft) const; +#define EMIT_BUILTIIN_FUNC(FUNC) EmitBuiltin##FUNC(std::list &stmts) const + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Ctz); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Ctzl); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Clz); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Clzl); + + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Popcount); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Popcountl); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Popcountll); + + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Parity); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Parityl); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Parityll); + + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Clrsb); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Clrsbl); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Clrsbll); + + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Ffs); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Ffsl); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Ffsll); + + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(IsAligned); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(AlignUp); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(AlignDown); + + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Alloca); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Expect); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(VaStart); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(VaEnd); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(VaCopy); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Prefetch); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Unreachable); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Abs); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(ACos); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(ACosf); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(ASin); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(ASinf); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(ATan); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(ATanf); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Cos); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Cosf); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Cosh); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Coshf); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Sin); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Sinf); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Sinh); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Sinhf); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Exp); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Expf); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Fmax); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Fmin); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Log); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Logf); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Log10); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Log10f); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Isunordered); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Isless); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Islessequal); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Isgreater); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Isgreaterequal); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Islessgreater); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(WarnMemsetZeroLen); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(RotateLeft8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(RotateLeft16); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(RotateLeft32); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(RotateLeft64); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(RotateRight8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(RotateRight16); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(RotateRight32); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(RotateRight64); + + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncAddAndFetch8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncAddAndFetch4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncAddAndFetch2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncAddAndFetch1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncSubAndFetch8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncSubAndFetch4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncSubAndFetch2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncSubAndFetch1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndSub8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndSub4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndSub2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndSub1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndAdd8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndAdd4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndAdd2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndAdd1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncBoolCompareAndSwap1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncBoolCompareAndSwap2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncBoolCompareAndSwap4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncBoolCompareAndSwap8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncLockTestAndSet8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncLockTestAndSet4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncLockTestAndSet2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncLockTestAndSet1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncValCompareAndSwap8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncValCompareAndSwap4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncValCompareAndSwap2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncValCompareAndSwap1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncLockRelease8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncLockRelease4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncLockRelease2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncLockRelease1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndAnd1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndAnd2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndAnd4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndAnd8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndOr1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndOr2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndOr4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndOr8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndXor1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndXor2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndXor4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndXor8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndNand1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndNand2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndNand4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncFetchAndNand8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncAndAndFetch1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncAndAndFetch2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncAndAndFetch4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncAndAndFetch8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncOrAndFetch1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncOrAndFetch2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncOrAndFetch4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncOrAndFetch8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncXorAndFetch1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncXorAndFetch2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncXorAndFetch4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncXorAndFetch8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncNandAndFetch1); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncNandAndFetch2); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncNandAndFetch4); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncNandAndFetch8); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(SyncSynchronize); + + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(ReturnAddress); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(ExtractReturnAddr); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Memcpy); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Memmove); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Memset); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Strcpy); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Strncpy); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Memcmp); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Strlen); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Strcmp); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Strncmp); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Strchr); + UniqueFEIRExpr EMIT_BUILTIIN_FUNC(Strrchr); + +// vector builtinfunc +#define DEF_MIR_INTRINSIC(STR, NAME, INTRN_CLASS, RETURN_TYPE, ...) \ +UniqueFEIRExpr EmitBuiltin##STR(std::list &stmts) const; +#include "intrinsic_vector.def" +#undef DEF_MIR_INTRINSIC + + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + + static std::unordered_map builtingFuncPtrMap; + std::vector args; + ASTExpr *calleeExpr = nullptr; + MIRType *retType = nullptr; + std::string funcName; + FuncAttrs funcAttrs; + bool isIcall = false; + std::string varName; + ASTFunc *funcDecl = nullptr; +}; + +class ASTParenExpr : public ASTExpr { + public: + ASTParenExpr() : ASTExpr(kASTParen) {} + ~ASTParenExpr() = default; + + void SetASTExpr(ASTExpr *astExpr) { + child = astExpr; + } + + void SetShortCircuitIdx(uint32 leftIdx, uint32 rightIdx) override { + trueIdx = leftIdx; + falseIdx = rightIdx; + } + + protected: + MIRConst *GenerateMIRConstImpl() const override { + return child->GenerateMIRConst(); + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + + ASTValue *GetConstantValueImpl() const override { + return child->GetConstantValue(); + } + + ASTExpr *child = nullptr; + uint32 trueIdx = 0; + uint32 falseIdx = 0; +}; + +class ASTIntegerLiteral : public ASTExpr { + public: + ASTIntegerLiteral() : ASTExpr(kASTIntegerLiteral) {} + ~ASTIntegerLiteral() = default; + + int64 GetVal() const { + return val; + } + + void SetVal(int64 valIn) { + val = valIn; + } + + protected: + MIRConst *GenerateMIRConstImpl() const override; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + + int64 val = 0; +}; + +enum FloatKind { + F32, + F64 +}; + +class ASTFloatingLiteral : public ASTExpr { + public: + ASTFloatingLiteral() : ASTExpr(kASTFloatingLiteral) {} + ~ASTFloatingLiteral() = default; + + double GetVal() const { + return val; + } + + void SetVal(double valIn) { + val = valIn; + } + + void SetKind(FloatKind argKind) { + kind = argKind; + } + + FloatKind GetKind() const { + return kind; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + MIRConst *GenerateMIRConstImpl() const override; + double val = 0; + FloatKind kind = F32; +}; + +class ASTCharacterLiteral : public ASTExpr { + public: + ASTCharacterLiteral() : ASTExpr(kASTCharacterLiteral) {} + ~ASTCharacterLiteral() = default; + + int64 GetVal() const { + return val; + } + + void SetVal(int64 valIn) { + val = valIn; + } + + void SetPrimType(PrimType primType) { + type = primType; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + int64 val = 0; + PrimType type = PTY_begin; +}; + +struct VaArgInfo { + bool isGPReg; // GP or FP/SIMD arg reg + int regOffset; + int stackOffset; + // If the argument type is a Composite Type that is larger than 16 bytes, + // then the argument is copied to memory allocated by the caller and replaced by a pointer to the copy. + bool isCopyedMem; + MIRType *HFAType; // Homogeneous Floating-point Aggregate +}; + +class ASTVAArgExpr : public ASTExpr { + public: + ASTVAArgExpr() : ASTExpr(kASTVAArgExpr) {} + ~ASTVAArgExpr() = default; + + void SetASTExpr(ASTExpr *astExpr) { + child = astExpr; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + VaArgInfo ProcessValistArgInfo(const MIRType &type) const; + MIRType *IsHFAType(const MIRStructType &type) const; + void CvtHFA2Struct(const MIRStructType &type, MIRType &fieldType, const UniqueFEIRVar &vaArgVar, + std::list &stmts) const; + void ProcessBigEndianForReg(std::list &stmts, MIRType &vaArgType, + const UniqueFEIRVar &offsetVar, const VaArgInfo &info) const; + void ProcessBigEndianForStack(std::list &stmts, MIRType &vaArgType, + const UniqueFEIRVar &vaArgVar) const; + + ASTExpr *child = nullptr; +}; + +class ASTConstantExpr : public ASTExpr { + public: + ASTConstantExpr() : ASTExpr(kConstantExpr) {} + ~ASTConstantExpr() = default; + void SetASTExpr(ASTExpr *astExpr) { + child = astExpr; + } + + protected: + MIRConst *GenerateMIRConstImpl() const override; + + private: + ASTExpr *child = nullptr; + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTImaginaryLiteral : public ASTExpr { + public: + ASTImaginaryLiteral() : ASTExpr(kASTImaginaryLiteral) {} + ~ASTImaginaryLiteral() = default; + void SetASTExpr(ASTExpr *astExpr) { + child = astExpr; + } + + void SetComplexType(MIRType *structType) { + complexType = structType; + } + + void SetElemType(MIRType *type) { + elemType = type; + } + + private: + MIRType *complexType = nullptr; + MIRType *elemType = nullptr; + ASTExpr *child = nullptr; + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTConditionalOperator : public ASTExpr { + public: + ASTConditionalOperator() : ASTExpr(kASTConditionalOperator) {} + ~ASTConditionalOperator() = default; + + void SetCondExpr(ASTExpr *astExpr) { + condExpr = astExpr; + } + + void SetTrueExpr(ASTExpr *astExpr) { + trueExpr = astExpr; + } + + void SetFalseExpr(ASTExpr *astExpr) { + falseExpr = astExpr; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + + MIRConst *GenerateMIRConstImpl() const override { + MIRConst *condConst = condExpr->GenerateMIRConst(); + if (condConst->IsZero()) { + return falseExpr->GenerateMIRConst(); + } else { + return trueExpr->GenerateMIRConst(); + } + } + + ASTExpr *condExpr = nullptr; + ASTExpr *trueExpr = nullptr; + ASTExpr *falseExpr = nullptr; + std::string varName = FEUtils::GetSequentialName("levVar_"); +}; + +class ASTArrayInitLoopExpr : public ASTExpr { + public: + ASTArrayInitLoopExpr() : ASTExpr(kASTOpArrayInitLoop) {} + ~ASTArrayInitLoopExpr() = default; + + void SetCommonExpr(ASTExpr *expr) { + commonExpr = expr; + } + + const ASTExpr *GetCommonExpr() const { + return commonExpr; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + ASTExpr* commonExpr = nullptr; +}; + +class ASTArrayInitIndexExpr : public ASTExpr { + public: + ASTArrayInitIndexExpr() : ASTExpr(kASTOpArrayInitLoop) {} + ~ASTArrayInitIndexExpr() = default; + + void SetPrimType(MIRType *pType) { + primType = pType; + } + + void SetValueStr(const std::string &val) { + valueStr = val; + } + + const MIRType *GetPrimeType() const { + return primType; + } + + std::string GetValueStr() const { + return valueStr; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + MIRType *primType = nullptr; + std::string valueStr; +}; + +class ASTExprWithCleanups : public ASTExpr { + public: + ASTExprWithCleanups() : ASTExpr(kASTOpExprWithCleanups) {} + ~ASTExprWithCleanups() = default; + + void SetSubExpr(ASTExpr *sub) { + subExpr = sub; + } + + const ASTExpr *GetSubExpr() const { + return subExpr; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + ASTExpr *subExpr = nullptr; +}; + +class ASTMaterializeTemporaryExpr : public ASTExpr { + public: + ASTMaterializeTemporaryExpr() : ASTExpr(kASTOpMaterializeTemporary) {} + ~ASTMaterializeTemporaryExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTSubstNonTypeTemplateParmExpr : public ASTExpr { + public: + ASTSubstNonTypeTemplateParmExpr() : ASTExpr(kASTOpSubstNonTypeTemplateParm) {} + ~ASTSubstNonTypeTemplateParmExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTDependentScopeDeclRefExpr : public ASTExpr { + public: + ASTDependentScopeDeclRefExpr() : ASTExpr(kASTOpDependentScopeDeclRef) {} + ~ASTDependentScopeDeclRefExpr() = default; + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; +}; + +class ASTAtomicExpr : public ASTExpr { + public: + ASTAtomicExpr() : ASTExpr(kASTOpAtomic) {} + ~ASTAtomicExpr() = default; + + void SetRefType(MIRType *ref) { + refType = ref; + } + + void SetAtomicOp(ASTAtomicOp op) { + atomicOp = op; + } + + const MIRType *GetRefType() const { + return refType; + } + + ASTAtomicOp GetAtomicOp() const { + return atomicOp; + } + + void SetValExpr1(ASTExpr *val) { + valExpr1 = val; + } + + void SetValExpr2(ASTExpr *val) { + valExpr2 = val; + } + + void SetObjExpr(ASTExpr *obj) { + objExpr = obj; + } + + void SetOrderExpr(ASTExpr *order) { + orderExpr = order; + } + + const ASTExpr *GetValExpr1() const { + return valExpr1; + } + + const ASTExpr *GetValExpr2() const { + return valExpr2; + } + + const ASTExpr *GetObjExpr() const { + return objExpr; + } + + const ASTExpr *GetOrderExpr() const { + return orderExpr; + } + + void SetVal1Type(MIRType *ty) { + val1Type = ty; + } + + void SetVal2Type(MIRType *ty) { + val2Type = ty; + } + + void SetFromStmt(bool fromStmt) { + isFromStmt = fromStmt; + } + + bool IsFromStmt() const { + return isFromStmt; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + MIRType *refType = nullptr; + MIRType *val1Type = nullptr; + MIRType *val2Type = nullptr; + ASTExpr *objExpr = nullptr; + ASTExpr *valExpr1 = nullptr; + ASTExpr *valExpr2 = nullptr; + ASTExpr *orderExpr = nullptr; + ASTAtomicOp atomicOp = kAtomicOpUndefined; + bool isFromStmt = false; +}; + +class ASTExprStmtExpr : public ASTExpr { + public: + ASTExprStmtExpr() : ASTExpr(kASTOpStmtExpr) {} + ~ASTExprStmtExpr() = default; + void SetCompoundStmt(ASTStmt *sub) { + cpdStmt = sub; + } + + const ASTStmt *GetSubExpr() const { + return cpdStmt; + } + + private: + UniqueFEIRExpr Emit2FEExprImpl(std::list &stmts) const override; + + ASTStmt *cpdStmt = nullptr; +}; +} +#endif //HIR2MPL_AST_INPUT_INCLUDE_AST_EXPR_H diff --git a/src/hir2mpl/ast_input/clang/include/ast_function.h b/src/hir2mpl/ast_input/clang/include/ast_function.h new file mode 100644 index 0000000000000000000000000000000000000000..ed97568b027d91d27ede76321702a018c80c1c3d --- /dev/null +++ b/src/hir2mpl/ast_input/clang/include/ast_function.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL_FE_AST_INPUT_AST_FUNTION_H +#define MPL_FE_AST_INPUT_AST_FUNTION_H +#include "fe_function.h" +#include "ast_struct2fe_helper.h" + +namespace maple { +class ASTFunction : public FEFunction { + public: + ASTFunction(const ASTFunc2FEHelper &argMethodHelper, MIRFunction &mirFunc, + const std::unique_ptr &argPhaseResultTotal); + virtual ~ASTFunction() = default; + + protected: + bool GenerateGeneralStmt(const std::string &phaseName) override { + WARN(kLncWarn, "Phase: %s may not need.", phaseName.c_str()); + return true; + } + + bool GenerateArgVarList(const std::string &phaseName) override; + bool GenerateAliasVars(const std::string &phaseName) override; + + bool PreProcessTypeNameIdx() override { + return true; + } + + void GenerateGeneralStmtFailCallBack() override {} + + void GenerateGeneralDebugInfo() override {} + + bool VerifyGeneral() override { + return true; + } + + void VerifyGeneralFailCallBack() override {} + + bool HasThis() override { + return funcHelper.HasThis(); + } + + bool IsNative() override { + return funcHelper.IsNative(); + } + + bool EmitToFEIRStmt(const std::string &phaseName) override; + + void PreProcessImpl() override; + bool ProcessImpl() override; + bool ProcessFEIRFunction() override; + void FinishImpl() override; + bool EmitToMIR(const std::string &phaseName) override; + void SetMIRFunctionInfo(); + + const ASTFunc2FEHelper &funcHelper; + ASTFunc &astFunc; + bool error = false; +}; +} // namespace maple +#endif // MPL_FE_AST_INPUT_AST_FUNTION_H \ No newline at end of file diff --git a/src/hir2mpl/ast_input/clang/include/ast_op.h b/src/hir2mpl/ast_input/clang/include/ast_op.h new file mode 100644 index 0000000000000000000000000000000000000000..6bd51b80664aa2169c96442da5f9d86b8846708f --- /dev/null +++ b/src/hir2mpl/ast_input/clang/include/ast_op.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_AST_INPUT_INCLUDE_AST_OP_H +#define HIR2MPL_AST_INPUT_INCLUDE_AST_OP_H +namespace maple { +enum ASTOp { + kASTOpNone = 0, + kASTStringLiteral, + kASTSubscriptExpr, + kASTExprUnaryExprOrTypeTraitExpr, + kASTMemberExpr, + kASTASTDesignatedInitUpdateExpr, + kASTImplicitValueInitExpr, + kASTOpRef, + + // unaryopcode + kASTOpMinus, + kASTOpNot, + kASTOpLNot, + kASTOpPostInc, + kASTOpPostDec, + kASTOpPreInc, + kASTOpPreDec, + kASTOpAddrOf, + kASTOpAddrOfLabel, + kASTOpDeref, + kASTOpPlus, + kASTOpReal, + kASTOpImag, + kASTOpExtension, + kASTOpCoawait, + + // BinaryOperators + // [C++ 5.5] Pointer-to-member operators. + kASTOpBO, + kASTOpCompoundAssign, + kASTOpPtrMemD, + kASTOpPtrMemI, + // [C99 6.5.5] Multiplicative operators. + kASTOpMul, + kASTOpDiv, + kASTOpRem, + // [C99 6.5.6] Additive operators. + kASTOpAdd, + kASTOpSub, + // [C99 6.5.7] Bitwise shift operators. + kASTOpShl, + kASTOpShr, + // [C99 6.5.8] Relational operators. + kASTOpLT, + kASTOpGT, + kASTOpLE, + kASTOpGE, + // [C99 6.5.9] Equality operators. + kASTOpEQ, + kASTOpNE, + // [C99 6.5.10] Bitwise AND operator. + kASTOpAnd, + // [C99 6.5.11] Bitwise XOR operator. + kASTOpXor, + // [C99 6.5.12] Bitwise OR operator. + kASTOpOr, + // [C99 6.5.13] Logical AND operator. + kASTOpLAnd, + // [C99 6.5.14] Logical OR operator. + kASTOpLOr, + // [C99 6.5.16] Assignment operators. + kASTOpAssign, + kASTOpMulAssign, + kASTOpDivAssign, + kASTOpRemAssign, + kASTOpAddAssign, + kASTOpSubAssign, + kASTOpShlAssign, + kASTOpShrAssign, + kASTOpAndAssign, + kASTOpXorAssign, + kASTOpOrAssign, + // [C99 6.5.17] Comma operator. + kASTOpComma, + // cast + kASTOpCast, + + // call + kASTOpCall, + + kASTParen, + kASTIntegerLiteral, + kASTFloatingLiteral, + kASTCharacterLiteral, + kASTConditionalOperator, + kConstantExpr, + kASTImaginaryLiteral, + kASTCallExpr, + kCpdAssignOp, + kASTVAArgExpr, + + // others + kASTOpPredefined, + kASTOpOpaqueValue, + kASTOpBinaryConditionalOperator, + kASTOpNoInitExpr, + kASTOpCompoundLiteralExpr, + kASTOpOffsetOfExpr, + kASTOpGenericSelectionExpr, + kASTOpInitListExpr, + kASTOpArrayInitLoop, + kASTOpArrayInitIndex, + kASTOpExprWithCleanups, + kASTOpMaterializeTemporary, + kASTOpSubstNonTypeTemplateParm, + kASTOpDependentScopeDeclRef, + kASTOpAtomic, + kASTOpStmtExpr, +}; + +enum ASTStmtOp { + kASTStmtNone, + kASTStmtDummy, + // branch + kASTStmtIf, + kASTStmtGoto, + kASTStmtIndirectGoto, + + kASTStmtLabel, + + kASTStmtDo, + kASTStmtFor, + kASTStmtWhile, + kASTStmtBreak, + kASTStmtContinue, + + kASTStmtReturn, + kASTStmtBO, + kASTStmtBOAssign, + kASTStmtBOCompoundAssign, + kASTStmtUO, + kASTStmtCompound, + kASTStmtSwitch, + kASTStmtCase, + kASTStmtDefault, + kASTStmtNull, + kASTStmtDecl, + kASTStmtCAO, + kASTStmtImplicitCastExpr, + kASTStmtParenExpr, + kASTStmtIntegerLiteral, + kASTStmtFloatingLiteral, + kASTStmtVAArgExpr, + kASTStmtConditionalOperator, + kASTStmtCharacterLiteral, + kASTStmtStmtExpr, + kASTStmtCStyleCastExpr, + kASTStmtCallExpr, + kASTStmtAtomicExpr, + kASTStmtGCCAsmStmt, + kASTOffsetOfStmt, + kASTGenericSelectionExprStmt, + kASTStmtAttributed, +}; +} // namespace maple +#endif // HIR2MPL_AST_INPUT_INCLUDE_AST_OP_H diff --git a/src/hir2mpl/ast_input/clang/include/ast_parser.h b/src/hir2mpl/ast_input/clang/include/ast_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..7d05e26fc4f69d5bdb28dfc379dbb40268cf98d2 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/include/ast_parser.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_AST_INPUT_INCLUDE_AST_PARSER_H +#define HIR2MPL_AST_INPUT_INCLUDE_AST_PARSER_H +#include +#include +#include "mempool_allocator.h" +#include "ast_decl.h" +#include "ast_interface.h" + +namespace maple { +class ASTParser { + public: + ASTParser(MapleAllocator &allocatorIn, uint32 fileIdxIn, const std::string &fileNameIn, + MapleList &astStructsIn, MapleList &astFuncsIn, MapleList &astVarsIn, + MapleList &astFileScopeAsmsIn) + : fileIdx(fileIdxIn), fileName(fileNameIn), globalVarDecles(allocatorIn.Adapter()), + funcDecles(allocatorIn.Adapter()), recordDecles(allocatorIn.Adapter()), + globalEnumDecles(allocatorIn.Adapter()), globalTypeDefDecles(allocatorIn.Adapter()), + globalFileScopeAsm(allocatorIn.Adapter()), astStructs(astStructsIn), astFuncs(astFuncsIn), + astVars(astVarsIn), astFileScopeAsms(astFileScopeAsmsIn) {} + virtual ~ASTParser() = default; + bool OpenFile(); + bool Verify() const; + bool PreProcessAST(); + + bool RetrieveStructs(MapleAllocator &allocator); + bool RetrieveFuncs(MapleAllocator &allocator); + bool RetrieveGlobalVars(MapleAllocator &allocator); + bool RetrieveFileScopeAsms(MapleAllocator &allocator); + + bool ProcessGlobalTypeDef(MapleAllocator &allocator); + + const std::string &GetSourceFileName() const; + const uint32 GetFileIdx() const; + + // ProcessStmt + ASTStmt *ProcessStmt(MapleAllocator &allocator, const clang::Stmt &stmt); + ASTStmt *ProcessFunctionBody(MapleAllocator &allocator, const clang::CompoundStmt &cpdStmt); +#define PROCESS_STMT(CLASS) ProcessStmt##CLASS(MapleAllocator&, const clang::CLASS&) + ASTStmt *PROCESS_STMT(AttributedStmt); + ASTStmt *PROCESS_STMT(UnaryOperator); + ASTStmt *PROCESS_STMT(BinaryOperator); + ASTStmt *PROCESS_STMT(CompoundAssignOperator); + ASTStmt *PROCESS_STMT(ImplicitCastExpr); + ASTStmt *PROCESS_STMT(ParenExpr); + ASTStmt *PROCESS_STMT(IntegerLiteral); + ASTStmt *PROCESS_STMT(FloatingLiteral); + ASTStmt *PROCESS_STMT(VAArgExpr); + ASTStmt *PROCESS_STMT(ConditionalOperator); + ASTStmt *PROCESS_STMT(CharacterLiteral); + ASTStmt *PROCESS_STMT(StmtExpr); + ASTStmt *PROCESS_STMT(CallExpr); + ASTStmt *PROCESS_STMT(ReturnStmt); + ASTStmt *PROCESS_STMT(IfStmt); + ASTStmt *PROCESS_STMT(ForStmt); + ASTStmt *PROCESS_STMT(WhileStmt); + ASTStmt *PROCESS_STMT(DoStmt); + ASTStmt *PROCESS_STMT(BreakStmt); + ASTStmt *PROCESS_STMT(LabelStmt); + ASTStmt *PROCESS_STMT(ContinueStmt); + ASTStmt *PROCESS_STMT(CompoundStmt); + ASTStmt *PROCESS_STMT(GotoStmt); + ASTStmt *PROCESS_STMT(IndirectGotoStmt); + ASTStmt *PROCESS_STMT(SwitchStmt); + ASTStmt *PROCESS_STMT(CaseStmt); + ASTStmt *PROCESS_STMT(DefaultStmt); + ASTStmt *PROCESS_STMT(NullStmt); + ASTStmt *PROCESS_STMT(CStyleCastExpr); + ASTStmt *PROCESS_STMT(DeclStmt); + ASTStmt *PROCESS_STMT(AtomicExpr); + ASTStmt *PROCESS_STMT(GCCAsmStmt); + ASTStmt *PROCESS_STMT(OffsetOfExpr); + ASTStmt *PROCESS_STMT(GenericSelectionExpr); + bool HasDefault(const clang::Stmt &stmt); + + // ProcessExpr + const clang::Expr *PeelParen(const clang::Expr &expr); + const clang::Expr *PeelParen2(const clang::Expr &expr); + ASTUnaryOperatorExpr *AllocUnaryOperatorExpr(MapleAllocator &allocator, const clang::UnaryOperator &expr); + ASTValue *AllocASTValue(const MapleAllocator &allocator) const; + ASTValue *TranslateExprEval(MapleAllocator &allocator, const clang::Expr *expr) const; + ASTExpr *EvaluateExprAsConst(MapleAllocator &allocator, const clang::Expr *expr); + ASTExpr *ProcessExpr(MapleAllocator &allocator, const clang::Expr *expr); + ASTExpr *ProcessExprInType(MapleAllocator &allocator, const clang::QualType &qualType); + ASTBinaryOperatorExpr *AllocBinaryOperatorExpr(MapleAllocator &allocator, const clang::BinaryOperator &bo); + ASTExpr *ProcessExprCastExpr(MapleAllocator &allocator, const clang::CastExpr &expr); +#define PROCESS_EXPR(CLASS) ProcessExpr##CLASS(MapleAllocator&, const clang::CLASS&) + ASTExpr *PROCESS_EXPR(UnaryOperator); + ASTExpr *PROCESS_EXPR(AddrLabelExpr); + ASTExpr *PROCESS_EXPR(NoInitExpr); + ASTExpr *PROCESS_EXPR(PredefinedExpr); + ASTExpr *PROCESS_EXPR(OpaqueValueExpr); + ASTExpr *PROCESS_EXPR(BinaryConditionalOperator); + ASTExpr *PROCESS_EXPR(CompoundLiteralExpr); + ASTExpr *PROCESS_EXPR(OffsetOfExpr); + ASTExpr *PROCESS_EXPR(InitListExpr); + ASTExpr *PROCESS_EXPR(BinaryOperator); + ASTExpr *PROCESS_EXPR(ImplicitValueInitExpr); + ASTExpr *PROCESS_EXPR(StringLiteral); + ASTExpr *PROCESS_EXPR(ArraySubscriptExpr); + ASTExpr *PROCESS_EXPR(UnaryExprOrTypeTraitExpr); + ASTExpr *PROCESS_EXPR(MemberExpr); + ASTExpr *PROCESS_EXPR(DesignatedInitUpdateExpr); + ASTExpr *PROCESS_EXPR(ImplicitCastExpr); + ASTExpr *PROCESS_EXPR(DeclRefExpr); + ASTExpr *PROCESS_EXPR(ParenExpr); + ASTExpr *PROCESS_EXPR(IntegerLiteral); + ASTExpr *PROCESS_EXPR(FloatingLiteral); + ASTExpr *PROCESS_EXPR(CharacterLiteral); + ASTExpr *PROCESS_EXPR(ConditionalOperator); + ASTExpr *PROCESS_EXPR(VAArgExpr); + ASTExpr *PROCESS_EXPR(GNUNullExpr); + ASTExpr *PROCESS_EXPR(SizeOfPackExpr); + ASTExpr *PROCESS_EXPR(UserDefinedLiteral); + ASTExpr *PROCESS_EXPR(ShuffleVectorExpr); + ASTExpr *PROCESS_EXPR(TypeTraitExpr); + ASTExpr *PROCESS_EXPR(ConstantExpr); + ASTExpr *PROCESS_EXPR(ImaginaryLiteral); + ASTExpr *PROCESS_EXPR(CallExpr); + ASTExpr *PROCESS_EXPR(CompoundAssignOperator); + ASTExpr *PROCESS_EXPR(StmtExpr); + ASTExpr *PROCESS_EXPR(CStyleCastExpr); + ASTExpr *PROCESS_EXPR(ArrayInitLoopExpr); + ASTExpr *PROCESS_EXPR(ArrayInitIndexExpr); + ASTExpr *PROCESS_EXPR(ExprWithCleanups); + ASTExpr *PROCESS_EXPR(MaterializeTemporaryExpr); + ASTExpr *PROCESS_EXPR(SubstNonTypeTemplateParmExpr); + ASTExpr *PROCESS_EXPR(DependentScopeDeclRefExpr); + ASTExpr *PROCESS_EXPR(AtomicExpr); + ASTExpr *PROCESS_EXPR(ChooseExpr); + ASTExpr *PROCESS_EXPR(GenericSelectionExpr); + + ASTDecl *ProcessDecl(MapleAllocator &allocator, const clang::Decl &decl); +#define PROCESS_DECL(CLASS) ProcessDecl##CLASS##Decl(MapleAllocator &allocator, const clang::CLASS##Decl&) + ASTDecl *PROCESS_DECL(Field); + ASTDecl *PROCESS_DECL(Function); + ASTDecl *PROCESS_DECL(Record); + ASTDecl *PROCESS_DECL(Var); + ASTDecl *PROCESS_DECL(ParmVar); + ASTDecl *PROCESS_DECL(Enum); + ASTDecl *PROCESS_DECL(Typedef); + ASTDecl *PROCESS_DECL(EnumConstant); + ASTDecl *PROCESS_DECL(FileScopeAsm); + ASTDecl *PROCESS_DECL(Label); + ASTDecl *PROCESS_DECL(StaticAssert); + + static ASTExpr *GetAddrShiftExpr(MapleAllocator &allocator, ASTExpr *expr, uint32 typeSize); + + private: + void ProcessNonnullFuncAttrs(const clang::FunctionDecl &funcDecl, ASTFunc &astFunc); + void ProcessNonnullFuncPtrAttrs(const clang::ValueDecl &valueDecl, ASTDecl &astVar); + void ProcessBoundaryFuncAttrs(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, ASTFunc &astFunc); + void ProcessByteBoundaryFuncAttrs(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, ASTFunc &astFunc); + void ProcessBoundaryFuncAttrsByIndex(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, + ASTFunc &astFunc); + void ProcessBoundaryParamAttrs(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, ASTFunc &astFunc); + void ProcessBoundaryParamAttrsByIndex(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, + ASTFunc &astFunc); + void ProcessBoundaryVarAttrs(MapleAllocator &allocator, const clang::VarDecl &varDecl, ASTVar &astVar); + void ProcessBoundaryFieldAttrs(MapleAllocator &allocator, const ASTStruct &structDecl, + const clang::RecordDecl &recDecl); + void ProcessBoundaryFuncPtrAttrs(MapleAllocator &allocator, const clang::ValueDecl &valueDecl, ASTDecl &astDecl); + template + bool ProcessBoundaryFuncPtrAttrsForParams(T *attr, MapleAllocator &allocator, const MIRFuncType &funcType, + const clang::FunctionProtoType &proto, std::vector &attrsVec); + template + bool ProcessBoundaryFuncPtrAttrsForRet(T *attr, MapleAllocator &allocator, const MIRFuncType &funcType, + const clang::FunctionType &clangFuncType, TypeAttrs &retAttr); + void ProcessBoundaryFuncPtrAttrsByIndex(const clang::ValueDecl &valueDecl, ASTDecl &astDecl, + const MIRFuncType &funcType); + template + bool ProcessBoundaryFuncPtrAttrsByIndexForParams(T *attr, ASTDecl &astDecl, const MIRFuncType &funcType, + std::vector &attrsVec); + void ProcessBoundaryLenExpr(MapleAllocator &allocator, ASTDecl &ptrDecl, const clang::QualType &qualType, + const std::function &getLenExprFromStringLiteral, + ASTExpr *lenExpr, bool isSize); + void ProcessBoundaryLenExprInFunc(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, + unsigned int idx, ASTFunc &astFunc, ASTExpr *lenExpr, bool isSize); + void ProcessBoundaryLenExprInFunc(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, + unsigned int idx, ASTFunc &astFunc, unsigned int lenIdx, bool isSize); + void ProcessBoundaryLenExprInVar(MapleAllocator &allocator, ASTDecl &ptrDecl, const clang::VarDecl &varDecl, + ASTExpr *lenExpr, bool isSize); + void ProcessBoundaryLenExprInVar(MapleAllocator &allocator, ASTDecl &ptrDecl, const clang::QualType &qualType, + ASTExpr *lenExpr, bool isSize); + void ProcessBoundaryLenExprInField(MapleAllocator &allocator, ASTDecl &ptrDecl, const ASTStruct &structDecl, + const clang::QualType &qualType, ASTExpr *lenExpr, bool isSize); + ASTValue *TranslateConstantValue2ASTValue(MapleAllocator &allocator, const clang::Expr *expr) const; + ASTValue *TranslateLValue2ASTValue(MapleAllocator &allocator, + const clang::Expr::EvalResult &result, const clang::Expr *expr) const; + void TraverseDecl(const clang::Decl *decl, std::function const &functor); + ASTDecl *GetAstDeclOfDeclRefExpr(MapleAllocator &allocator, const clang::Expr &expr); + uint32 GetSizeFromQualType(const clang::QualType qualType); + ASTExpr *GetTypeSizeFromQualType(MapleAllocator &allocator, const clang::QualType qualType); + uint32_t GetAlignOfType(const clang::QualType currQualType, clang::UnaryExprOrTypeTrait exprKind); + uint32_t GetAlignOfExpr(const clang::Expr &expr, clang::UnaryExprOrTypeTrait exprKind); + ASTExpr *BuildExprToComputeSizeFromVLA(MapleAllocator &allocator, const clang::QualType &qualType); + ASTExpr *ProcessExprBinaryOperatorComplex(MapleAllocator &allocator, const clang::BinaryOperator &bo); + +using FuncPtrBuiltinFunc = ASTExpr *(ASTParser::*)(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const; +static std::map InitBuiltinFuncPtrMap(); +ASTExpr *ProcessBuiltinFuncByName(MapleAllocator &allocator, const clang::CallExpr &expr, std::stringstream &ss, + const std::string &name) const; +ASTExpr *ParseBuiltinFunc(MapleAllocator &allocator, const clang::CallExpr &expr, std::stringstream &ss) const; +#define PARSE_BUILTIIN_FUNC(FUNC) ParseBuiltin##FUNC(MapleAllocator &allocator, const clang::CallExpr &expr,\ + std::stringstream &ss) const + ASTExpr *PARSE_BUILTIIN_FUNC(ClassifyType); + ASTExpr *PARSE_BUILTIIN_FUNC(ConstantP); + ASTExpr *PARSE_BUILTIIN_FUNC(Isinfsign); + ASTExpr *PARSE_BUILTIIN_FUNC(HugeVal); + ASTExpr *PARSE_BUILTIIN_FUNC(HugeValf); + ASTExpr *PARSE_BUILTIIN_FUNC(Inf); + ASTExpr *PARSE_BUILTIIN_FUNC(Inff); + ASTExpr *PARSE_BUILTIIN_FUNC(Nan); + ASTExpr *PARSE_BUILTIIN_FUNC(Nanf); + ASTExpr *PARSE_BUILTIIN_FUNC(Signbit); + ASTExpr *PARSE_BUILTIIN_FUNC(SignBitf); + ASTExpr *PARSE_BUILTIIN_FUNC(SignBitl); + ASTExpr *PARSE_BUILTIIN_FUNC(Trap); + ASTExpr *PARSE_BUILTIIN_FUNC(IsUnordered); + ASTExpr *PARSE_BUILTIIN_FUNC(Copysignf); + ASTExpr *PARSE_BUILTIIN_FUNC(Copysign); + ASTExpr *PARSE_BUILTIIN_FUNC(Copysignl); + ASTExpr *PARSE_BUILTIIN_FUNC(Objectsize); + + static std::map builtingFuncPtrMap; + uint32 fileIdx; + const std::string fileName; + std::unique_ptr astFile; + AstUnitDecl *astUnitDecl = nullptr; + MapleList globalVarDecles; + MapleList funcDecles; + MapleList recordDecles; + MapleList globalEnumDecles; + MapleList globalTypeDefDecles; + MapleList globalFileScopeAsm; + + MapleList &astStructs; + MapleList &astFuncs; + MapleList &astVars; + MapleList &astFileScopeAsms; +}; +} // namespace maple +#endif // HIR2MPL_AST_INPUT_INCLUDE_AST_PARSER_H diff --git a/src/hir2mpl/ast_input/clang/include/ast_stmt.h b/src/hir2mpl/ast_input/clang/include/ast_stmt.h new file mode 100644 index 0000000000000000000000000000000000000000..4a053bb43957715bdcf1de748b3fb429c28cfe38 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/include/ast_stmt.h @@ -0,0 +1,628 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_AST_INPUT_INCLUDE_AST_STMT_H +#define HIR2MPL_AST_INPUT_INCLUDE_AST_STMT_H +#include "ast_op.h" +#include "ast_expr.h" +#include "feir_stmt.h" + +namespace maple { +class ASTDecl; + +enum SafeSS { + kNoneSS, + kSafeSS, + kUnsafeSS, +}; + +class ASTStmt { + public: + explicit ASTStmt(ASTStmtOp o = kASTStmtNone) : op(o) {} + virtual ~ASTStmt() = default; + void SetASTExpr(ASTExpr* astExpr); + + std::list Emit2FEStmt() const { + return Emit2FEStmtImpl(); + } + + ASTStmtOp GetASTStmtOp() const { + return op; + } + + const std::vector &GetExprs() const { + return exprs; + } + + void SetSrcLOC(uint32 fileIdx, uint32 lineNum) { + srcFileIdx = fileIdx; + srcFileLineNum = lineNum; + } + + uint32 GetSrcFileIdx() const { + return srcFileIdx; + } + + uint32 GetSrcFileLineNum() const { + return srcFileLineNum; + } + + protected: + virtual std::list Emit2FEStmtImpl() const = 0; + ASTStmtOp op; + std::vector exprs; + + uint32 srcFileIdx = 0; + uint32 srcFileLineNum = 0; +}; + +class ASTStmtDummy : public ASTStmt { + public: + ASTStmtDummy() : ASTStmt(kASTStmtDummy) {} + ~ASTStmtDummy() = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTCompoundStmt : public ASTStmt { + public: + ASTCompoundStmt() : ASTStmt(kASTStmtCompound) {} + ~ASTCompoundStmt() = default; + void SetASTStmt(ASTStmt*); + void InsertASTStmtsAtFront(const std::list &stmts); + const std::list &GetASTStmtList() const; + + void SetSafeSS(SafeSS state) { + safeSS = state; + } + + SafeSS GetSafeSS() const { + return safeSS; + } + + private: + SafeSS safeSS = kNoneSS; + std::list astStmts; // stmts + std::list Emit2FEStmtImpl() const override; +}; + +// Any other expressions or stmts should be extended here +class ASTReturnStmt : public ASTStmt { + public: + ASTReturnStmt() : ASTStmt(kASTStmtReturn) {} + ~ASTReturnStmt() = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTAttributedStmt : public ASTStmt { + public: + ASTAttributedStmt() : ASTStmt(kASTStmtAttributed) {} + ~ASTAttributedStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override{ return {}; }; +}; + +class ASTIfStmt : public ASTStmt { + public: + ASTIfStmt() : ASTStmt(kASTStmtIf) {} + ~ASTIfStmt() override = default; + + void SetCondExpr(ASTExpr *astExpr) { + condExpr = astExpr; + } + + void SetThenStmt(ASTStmt *astStmt) { + thenStmt = astStmt; + } + + void SetElseStmt(ASTStmt *astStmt) { + elseStmt = astStmt; + } + + private: + std::list Emit2FEStmtImpl() const override; + ASTExpr *condExpr = nullptr; + ASTStmt *thenStmt = nullptr; + ASTStmt *elseStmt = nullptr; +}; + +class ASTForStmt : public ASTStmt { + public: + ASTForStmt() : ASTStmt(kASTStmtFor) {} + ~ASTForStmt() override = default; + + void SetInitStmt(ASTStmt *astStmt) { + initStmt = astStmt; + } + + void SetCondExpr(ASTExpr *astExpr) { + condExpr = astExpr; + } + + void SetIncExpr(ASTExpr *astExpr) { + incExpr = astExpr; + } + + void SetBodyStmt(ASTStmt *astStmt) { + bodyStmt = astStmt; + } + + private: + std::list Emit2FEStmtImpl() const override; + ASTStmt *initStmt = nullptr; + ASTExpr *condExpr = nullptr; + ASTExpr *incExpr = nullptr; + ASTStmt *bodyStmt = nullptr; +}; + +class ASTWhileStmt : public ASTStmt { + public: + ASTWhileStmt() : ASTStmt(kASTStmtWhile) {} + ~ASTWhileStmt() override = default; + + void SetCondExpr(ASTExpr *astExpr) { + condExpr = astExpr; + } + + void SetBodyStmt(ASTStmt *astStmt) { + bodyStmt = astStmt; + } + + private: + std::list Emit2FEStmtImpl() const override; + ASTExpr *condExpr = nullptr; + ASTStmt *bodyStmt = nullptr; +}; + +class ASTDoStmt : public ASTStmt { + public: + ASTDoStmt() : ASTStmt(kASTStmtDo) {} + ~ASTDoStmt() override = default; + + void SetCondExpr(ASTExpr *astExpr) { + condExpr = astExpr; + } + + void SetBodyStmt(ASTStmt *astStmt) { + bodyStmt = astStmt; + } + + private: + std::list Emit2FEStmtImpl() const override; + ASTExpr *condExpr = nullptr; + ASTStmt *bodyStmt = nullptr; +}; + +class ASTBreakStmt : public ASTStmt { + public: + ASTBreakStmt() : ASTStmt(kASTStmtBreak) {} + ~ASTBreakStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTLabelStmt : public ASTStmt { + public: + ASTLabelStmt() : ASTStmt(kASTStmtLabel) {} + ~ASTLabelStmt() override = default; + + void SetSubStmt(ASTStmt *stmt) { + subStmt = stmt; + } + + void SetLabelName(const std::string &name) { + labelName = name; + } + + private: + std::list Emit2FEStmtImpl() const override; + std::string labelName; + ASTStmt *subStmt = nullptr; +}; + +class ASTContinueStmt : public ASTStmt { + public: + ASTContinueStmt() : ASTStmt(kASTStmtContinue) {} + ~ASTContinueStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTUnaryOperatorStmt : public ASTStmt { + public: + ASTUnaryOperatorStmt() : ASTStmt(kASTStmtUO) {} + ~ASTUnaryOperatorStmt() = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTBinaryOperatorStmt : public ASTStmt { + public: + ASTBinaryOperatorStmt() : ASTStmt(kASTStmtBO) {} + ~ASTBinaryOperatorStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTGotoStmt : public ASTStmt { + public: + ASTGotoStmt() : ASTStmt(kASTStmtGoto) {} + ~ASTGotoStmt() = default; + + std::string GetLabelName() const { + return labelName; + } + + void SetLabelName(const std::string &name) { + labelName = name; + } + + private: + std::list Emit2FEStmtImpl() const override; + std::string labelName; +}; + +class ASTIndirectGotoStmt : public ASTStmt { + public: + ASTIndirectGotoStmt() : ASTStmt(kASTStmtIndirectGoto) {} + ~ASTIndirectGotoStmt() = default; + + protected: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTSwitchStmt : public ASTStmt { + public: + ASTSwitchStmt() : ASTStmt(kASTStmtSwitch) {} + ~ASTSwitchStmt() = default; + + void SetCondStmt(ASTStmt *cond) { + condStmt = cond; + } + + void SetBodyStmt(ASTStmt *body) { + bodyStmt = body; + } + + void SetCondExpr(ASTExpr *cond) { + condExpr = cond; + } + + const ASTStmt *GetCondStmt() const { + return condStmt; + } + + const ASTExpr *GetCondExpr() const { + return condExpr; + } + + const ASTStmt *GetBodyStmt() const { + return bodyStmt; + } + + void SetHasDefault(bool argHasDefault) { + hasDefualt = argHasDefault; + } + + bool HasDefault() const { + return hasDefualt; + } + + void SetCondType(MIRType *type) { + condType = type; + } + + private: + std::list Emit2FEStmtImpl() const override; + ASTStmt *condStmt = nullptr; + ASTExpr *condExpr = nullptr; + ASTStmt *bodyStmt = nullptr; + MIRType *condType = nullptr; + bool hasDefualt = false; +}; + +class ASTCaseStmt : public ASTStmt { + public: + ASTCaseStmt() : ASTStmt(kASTStmtCase) {} + ~ASTCaseStmt() = default; + + void SetLHS(ASTExpr *l) { + lhs = l; + } + + void SetRHS(ASTExpr *r) { + rhs = r; + } + + void SetSubStmt(ASTStmt *sub) { + subStmt = sub; + } + + const ASTExpr *GetLHS() const { + return lhs; + } + + const ASTExpr *GetRHS() const { + return rhs; + } + + const ASTStmt *GetSubStmt() const { + return subStmt; + } + + int64 GetLCaseTag() const { + return lCaseTag; + } + + int64 GetRCaseTag() const { + return rCaseTag; + } + + void SetLCaseTag(int64 l) { + lCaseTag = l; + } + + void SetRCaseTag(int64 r) { + rCaseTag = r; + } + + private: + std::list Emit2FEStmtImpl() const override; + ASTExpr *lhs = nullptr; + ASTExpr *rhs = nullptr; + ASTStmt *subStmt = nullptr; + int64 lCaseTag = 0; + int64 rCaseTag = 0; +}; + +class ASTDefaultStmt : public ASTStmt { + public: + ASTDefaultStmt() : ASTStmt(kASTStmtDefault) {} + ~ASTDefaultStmt() = default; + + void SetChildStmt(ASTStmt* ch) { + child = ch; + } + + const ASTStmt* GetChildStmt() const { + return child; + } + + private: + std::list Emit2FEStmtImpl() const override; + ASTStmt* child = nullptr; +}; + +class ASTNullStmt : public ASTStmt { + public: + ASTNullStmt() : ASTStmt(kASTStmtNull) {} + ~ASTNullStmt() = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTDeclStmt : public ASTStmt { + public: + ASTDeclStmt() : ASTStmt(kASTStmtDecl) {} + ~ASTDeclStmt() = default; + + void SetSubDecl(ASTDecl *decl) { + subDecls.emplace_back(decl); + } + + const std::list& GetSubDecls() const { + return subDecls; + } + + private: + std::list Emit2FEStmtImpl() const override; + void InsertBoundaryVar(ASTDecl *ptrDecl, std::list &stmts) const; + + std::list subDecls; +}; + +class ASTCompoundAssignOperatorStmt : public ASTStmt { + public: + ASTCompoundAssignOperatorStmt() : ASTStmt(kASTStmtCAO) {} + ~ASTCompoundAssignOperatorStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTImplicitCastExprStmt : public ASTStmt { + public: + ASTImplicitCastExprStmt() : ASTStmt(kASTStmtImplicitCastExpr) {} + ~ASTImplicitCastExprStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTParenExprStmt : public ASTStmt { + public: + ASTParenExprStmt() : ASTStmt(kASTStmtParenExpr) {} + ~ASTParenExprStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTIntegerLiteralStmt : public ASTStmt { + public: + ASTIntegerLiteralStmt() : ASTStmt(kASTStmtIntegerLiteral) {} + ~ASTIntegerLiteralStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTFloatingLiteralStmt : public ASTStmt { + public: + ASTFloatingLiteralStmt() : ASTStmt(kASTStmtFloatingLiteral) {} + ~ASTFloatingLiteralStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTVAArgExprStmt : public ASTStmt { + public: + ASTVAArgExprStmt() : ASTStmt(kASTStmtVAArgExpr) {} + ~ASTVAArgExprStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTConditionalOperatorStmt : public ASTStmt { + public: + ASTConditionalOperatorStmt() : ASTStmt(kASTStmtConditionalOperator) {} + ~ASTConditionalOperatorStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTCharacterLiteralStmt : public ASTStmt { + public: + ASTCharacterLiteralStmt() : ASTStmt(kASTStmtCharacterLiteral) {} + ~ASTCharacterLiteralStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTStmtExprStmt : public ASTStmt { + public: + ASTStmtExprStmt() : ASTStmt(kASTStmtStmtExpr) {} + ~ASTStmtExprStmt() override = default; + + void SetBodyStmt(ASTStmt *stmt) { + cpdStmt = stmt; + } + + ASTStmt *GetBodyStmt() { + return cpdStmt; + } + + private: + std::list Emit2FEStmtImpl() const override; + + ASTStmt *cpdStmt = nullptr; +}; + +class ASTCStyleCastExprStmt : public ASTStmt { + public: + ASTCStyleCastExprStmt() : ASTStmt(kASTStmtCStyleCastExpr) {} + ~ASTCStyleCastExprStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTCallExprStmt : public ASTStmt { + public: + ASTCallExprStmt() : ASTStmt(kASTStmtCallExpr), varName(FEUtils::GetSequentialName("retVar_")) {} + ~ASTCallExprStmt() override = default; + + private: + using FuncPtrBuiltinFunc = std::list (ASTCallExprStmt::*)() const; + static std::map InitFuncPtrMap(); + std::list Emit2FEStmtImpl() const override; + + std::string varName; +}; + +class ASTAtomicExprStmt : public ASTStmt { + public: + ASTAtomicExprStmt() : ASTStmt(kASTStmtAtomicExpr) {} + ~ASTAtomicExprStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTGCCAsmStmt : public ASTStmt { + public: + ASTGCCAsmStmt() : ASTStmt(kASTStmtGCCAsmStmt) {} + ~ASTGCCAsmStmt() override = default; + + void SetAsmStr(const std::string &str) { + asmStr = str; + } + + void InsertOutput(std::tuple &&output) { + outputs.emplace_back(output); + } + + void InsertInput(std::pair &&input) { + inputs.emplace_back(input); + } + + void InsertClobber(std::string &&clobber) { + clobbers.emplace_back(clobber); + } + + void InsertLabel(const std::string &label) { + labels.emplace_back(label); + } + + void SetIsGoto(bool flag) { + isGoto = flag; + } + + void SetIsVolatile(bool flag) { + isVolatile = flag; + } + + private: + std::list Emit2FEStmtImpl() const override; + std::string asmStr; + std::vector> outputs; + std::vector> inputs; + std::vector clobbers; + std::vector labels; + bool isGoto = false; + bool isVolatile = false; +}; + +class ASTOffsetOfStmt : public ASTStmt { + public: + ASTOffsetOfStmt() : ASTStmt(kASTOffsetOfStmt) {} + ~ASTOffsetOfStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; + +class ASTGenericSelectionExprStmt : public ASTStmt { + public: + ASTGenericSelectionExprStmt() : ASTStmt(kASTGenericSelectionExprStmt) {} + ~ASTGenericSelectionExprStmt() override = default; + + private: + std::list Emit2FEStmtImpl() const override; +}; +} // namespace maple +#endif // HIR2MPL_AST_INPUT_INCLUDE_AST_STMT_H diff --git a/src/hir2mpl/ast_input/clang/include/ast_struct2fe_helper.h b/src/hir2mpl/ast_input/clang/include/ast_struct2fe_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..772a0639055c5cc70f6fd4e8fbae97b8f9002fd9 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/include/ast_struct2fe_helper.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_AST_INPUT_INCLUDE_AST_STRUCT2FE_HELPER_H +#define HIR2MPL_AST_INPUT_INCLUDE_AST_STRUCT2FE_HELPER_H +#include "fe_input_helper.h" +#include "ast_decl.h" +#include "mempool_allocator.h" + +namespace maple { +class ASTStruct2FEHelper : public FEInputStructHelper { + public: + ASTStruct2FEHelper(MapleAllocator &allocator, const ASTStruct &structIn); + ~ASTStruct2FEHelper() = default; + + protected: + bool ProcessDeclImpl() override; + void InitFieldHelpersImpl() override; + void InitMethodHelpersImpl() override; + TypeAttrs GetStructAttributeFromInputImpl() const override; + std::string GetStructNameOrinImpl() const override; + std::string GetStructNameMplImpl() const override; + std::list GetSuperClassNamesImpl() const override; + std::vector GetInterfaceNamesImpl() const override; + std::string GetSourceFileNameImpl() const override; + MIRStructType *CreateMIRStructTypeImpl(bool &error) const override; + uint64 GetRawAccessFlagsImpl() const override; + virtual GStrIdx GetIRSrcFileSigIdxImpl() const override; + virtual bool IsMultiDefImpl() const override; + std::string GetSrcFileNameImpl() const override; + + const ASTStruct &astStruct; +}; + +class ASTGlobalVar2FEHelper : public FEInputGlobalVarHelper { + public: + ASTGlobalVar2FEHelper(MapleAllocator &allocatorIn, const ASTVar &varIn) + : FEInputGlobalVarHelper(allocatorIn), + astVar(varIn) {} + ~ASTGlobalVar2FEHelper() = default; + + protected: + bool ProcessDeclImpl(MapleAllocator &allocator) override; + const ASTVar &astVar; +}; + +class ASTFileScopeAsm2FEHelper : public FEInputFileScopeAsmHelper { + public: + ASTFileScopeAsm2FEHelper(MapleAllocator &allocatorIn, const ASTFileScopeAsm &astAsmIn) + : FEInputFileScopeAsmHelper(allocatorIn), + astAsm(astAsmIn) {} + ~ASTFileScopeAsm2FEHelper() = default; + + protected: + bool ProcessDeclImpl(MapleAllocator &allocator) override; + const ASTFileScopeAsm &astAsm; +}; + +class ASTStructField2FEHelper : public FEInputFieldHelper { + public: + ASTStructField2FEHelper(MapleAllocator &allocator, const ASTField &fieldIn, const MIRType &structTypeIn) + : FEInputFieldHelper(allocator), + field(fieldIn), structType(structTypeIn) {} + ~ASTStructField2FEHelper() = default; + + protected: + bool ProcessDeclImpl(MapleAllocator &allocator) override; + bool ProcessDeclWithContainerImpl(MapleAllocator &allocator) override; + const ASTField &field; + const MIRType &structType; +}; + +class ASTFunc2FEHelper : public FEInputMethodHelper { + public: + ASTFunc2FEHelper(MapleAllocator &allocator, ASTFunc &funcIn) + : FEInputMethodHelper(allocator), + func(funcIn) { + srcLang = kSrcLangC; + } + ~ASTFunc2FEHelper() = default; + ASTFunc &GetMethod() const { + return func; + } + + const std::string &GetSrcFileName() const; + + protected: + bool ProcessDeclImpl(MapleAllocator &allocator) override; + void SolveReturnAndArgTypesImpl(MapleAllocator &allocator) override; + std::string GetMethodNameImpl(bool inMpl, bool full) const override; + bool IsVargImpl() const override; + bool HasThisImpl() const override; + MIRType *GetTypeForThisImpl() const override; + FuncAttrs GetAttrsImpl() const override; + bool IsStaticImpl() const override; + bool IsVirtualImpl() const override; + bool IsNativeImpl() const override; + bool HasCodeImpl() const override; + + ASTFunc &func; + bool firstArgRet = false; +}; +} // namespace maple +#endif // HIR2MPL_AST_INPUT_INCLUDE_AST_STRUCT2FE_HELPER_H diff --git a/src/hir2mpl/ast_input/clang/include/builtin_func_emit.def b/src/hir2mpl/ast_input/clang/include/builtin_func_emit.def new file mode 100644 index 0000000000000000000000000000000000000000..a444fd3a37e6bacbf29c529cf361ed098201e744 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/include/builtin_func_emit.def @@ -0,0 +1,190 @@ +BUILTIN_FUNC_EMIT("alloca", &ASTCallExpr::EmitBuiltinAlloca) +BUILTIN_FUNC_EMIT("__builtin_ctz", &ASTCallExpr::EmitBuiltinCtz) +BUILTIN_FUNC_EMIT("__builtin_ctzl", &ASTCallExpr::EmitBuiltinCtzl) +BUILTIN_FUNC_EMIT("__builtin_ctzll", &ASTCallExpr::EmitBuiltinCtzl) +BUILTIN_FUNC_EMIT("__builtin_clz", &ASTCallExpr::EmitBuiltinClz) +BUILTIN_FUNC_EMIT("__builtin_clzl", &ASTCallExpr::EmitBuiltinClzl) +BUILTIN_FUNC_EMIT("__builtin_clzll", &ASTCallExpr::EmitBuiltinClzl) +BUILTIN_FUNC_EMIT("__builtin_popcount", &ASTCallExpr::EmitBuiltinPopcount) +BUILTIN_FUNC_EMIT("__builtin_popcountl", &ASTCallExpr::EmitBuiltinPopcountl) +BUILTIN_FUNC_EMIT("__builtin_popcountll", &ASTCallExpr::EmitBuiltinPopcountll) +BUILTIN_FUNC_EMIT("__builtin_parity", &ASTCallExpr::EmitBuiltinParity) +BUILTIN_FUNC_EMIT("__builtin_parityl", &ASTCallExpr::EmitBuiltinParityl) +BUILTIN_FUNC_EMIT("__builtin_parityll", &ASTCallExpr::EmitBuiltinParityll) +BUILTIN_FUNC_EMIT("__builtin_clrsb", &ASTCallExpr::EmitBuiltinClrsb) +BUILTIN_FUNC_EMIT("__builtin_clrsbl", &ASTCallExpr::EmitBuiltinClrsbl) +BUILTIN_FUNC_EMIT("__builtin_clrsbll", &ASTCallExpr::EmitBuiltinClrsbll) +BUILTIN_FUNC_EMIT("__builtin_ffs", &ASTCallExpr::EmitBuiltinFfs) +BUILTIN_FUNC_EMIT("__builtin_ffsl", &ASTCallExpr::EmitBuiltinFfsl) +BUILTIN_FUNC_EMIT("__builtin_ffsll", &ASTCallExpr::EmitBuiltinFfsll) +BUILTIN_FUNC_EMIT("__builtin_is_aligned", &ASTCallExpr::EmitBuiltinIsAligned) +BUILTIN_FUNC_EMIT("__builtin_align_up", &ASTCallExpr::EmitBuiltinAlignUp) +BUILTIN_FUNC_EMIT("__builtin_align_down", &ASTCallExpr::EmitBuiltinAlignDown) +BUILTIN_FUNC_EMIT("__builtin_alloca", &ASTCallExpr::EmitBuiltinAlloca) +BUILTIN_FUNC_EMIT("__builtin_expect", &ASTCallExpr::EmitBuiltinExpect) +BUILTIN_FUNC_EMIT("__builtin_va_start", &ASTCallExpr::EmitBuiltinVaStart) +BUILTIN_FUNC_EMIT("__builtin_va_end", &ASTCallExpr::EmitBuiltinVaEnd) +BUILTIN_FUNC_EMIT("__builtin_va_copy", &ASTCallExpr::EmitBuiltinVaCopy) +BUILTIN_FUNC_EMIT("__builtin_prefetch", &ASTCallExpr::EmitBuiltinPrefetch) +BUILTIN_FUNC_EMIT("__builtin_abs", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("__builtin_fabs", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("__builtin_fabsf", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("__builtin_fabsl", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("__builtin_fabsf16", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("__builtin_fabsf128", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("__builtin_labs", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("__builtin_llabs", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("__builtin_unreachable", &ASTCallExpr::EmitBuiltinUnreachable) +BUILTIN_FUNC_EMIT("abs", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("labs", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("llabs", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("fabs", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("fabsf", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("fabsl", &ASTCallExpr::EmitBuiltinAbs) +BUILTIN_FUNC_EMIT("__builtin_acos", &ASTCallExpr::EmitBuiltinACos) +BUILTIN_FUNC_EMIT("acos", &ASTCallExpr::EmitBuiltinACos) +BUILTIN_FUNC_EMIT("__builtin_acosf", &ASTCallExpr::EmitBuiltinACosf) +BUILTIN_FUNC_EMIT("acosf", &ASTCallExpr::EmitBuiltinACosf) +BUILTIN_FUNC_EMIT("__builtin_asin", &ASTCallExpr::EmitBuiltinASin) +BUILTIN_FUNC_EMIT("asin", &ASTCallExpr::EmitBuiltinASin) +BUILTIN_FUNC_EMIT("__builtin_asinf", &ASTCallExpr::EmitBuiltinASinf) +BUILTIN_FUNC_EMIT("asinf", &ASTCallExpr::EmitBuiltinASinf) +BUILTIN_FUNC_EMIT("__builtin_atan", &ASTCallExpr::EmitBuiltinATan) +BUILTIN_FUNC_EMIT("atan", &ASTCallExpr::EmitBuiltinATan) +BUILTIN_FUNC_EMIT("__builtin_atanf", &ASTCallExpr::EmitBuiltinATanf) +BUILTIN_FUNC_EMIT("atanf", &ASTCallExpr::EmitBuiltinATanf) +BUILTIN_FUNC_EMIT("__builtin_cos", &ASTCallExpr::EmitBuiltinCos) +BUILTIN_FUNC_EMIT("cos", &ASTCallExpr::EmitBuiltinCos) +BUILTIN_FUNC_EMIT("__builtin_cosf", &ASTCallExpr::EmitBuiltinCosf) +BUILTIN_FUNC_EMIT("cosf", &ASTCallExpr::EmitBuiltinCosf) +BUILTIN_FUNC_EMIT("__builtin_cosh", &ASTCallExpr::EmitBuiltinCosh) +BUILTIN_FUNC_EMIT("cosh", &ASTCallExpr::EmitBuiltinCosh) +BUILTIN_FUNC_EMIT("__builtin_coshf", &ASTCallExpr::EmitBuiltinCoshf) +BUILTIN_FUNC_EMIT("coshf", &ASTCallExpr::EmitBuiltinCoshf) +BUILTIN_FUNC_EMIT("__builtin_sin", &ASTCallExpr::EmitBuiltinSin) +BUILTIN_FUNC_EMIT("sin", &ASTCallExpr::EmitBuiltinSin) +BUILTIN_FUNC_EMIT("__builtin_sinf", &ASTCallExpr::EmitBuiltinSinf) +BUILTIN_FUNC_EMIT("sinf", &ASTCallExpr::EmitBuiltinSinf) +BUILTIN_FUNC_EMIT("__builtin_sinh", &ASTCallExpr::EmitBuiltinSinh) +BUILTIN_FUNC_EMIT("sinh", &ASTCallExpr::EmitBuiltinSinh) +BUILTIN_FUNC_EMIT("__builtin_sinhf", &ASTCallExpr::EmitBuiltinSinhf) +BUILTIN_FUNC_EMIT("sinhf", &ASTCallExpr::EmitBuiltinSinhf) +BUILTIN_FUNC_EMIT("__builtin_exp", &ASTCallExpr::EmitBuiltinExp) +BUILTIN_FUNC_EMIT("exp", &ASTCallExpr::EmitBuiltinExp) +BUILTIN_FUNC_EMIT("__builtin_expf", &ASTCallExpr::EmitBuiltinExpf) +BUILTIN_FUNC_EMIT("expf", &ASTCallExpr::EmitBuiltinExpf) +BUILTIN_FUNC_EMIT("__builtin_fmax", &ASTCallExpr::EmitBuiltinFmax) +BUILTIN_FUNC_EMIT("__builtin_fmaxf", &ASTCallExpr::EmitBuiltinFmax) +BUILTIN_FUNC_EMIT("__builtin_fmaxf16", &ASTCallExpr::EmitBuiltinFmax) +BUILTIN_FUNC_EMIT("__builtin_fmaxl", &ASTCallExpr::EmitBuiltinFmax) +BUILTIN_FUNC_EMIT("fmax", &ASTCallExpr::EmitBuiltinFmax) +BUILTIN_FUNC_EMIT("fmaxf", &ASTCallExpr::EmitBuiltinFmax) +BUILTIN_FUNC_EMIT("fmaxl", &ASTCallExpr::EmitBuiltinFmax) +BUILTIN_FUNC_EMIT("__builtin_fmin", &ASTCallExpr::EmitBuiltinFmin) +BUILTIN_FUNC_EMIT("__builtin_fminf", &ASTCallExpr::EmitBuiltinFmin) +BUILTIN_FUNC_EMIT("__builtin_fmin16", &ASTCallExpr::EmitBuiltinFmin) +BUILTIN_FUNC_EMIT("__builtin_fminl", &ASTCallExpr::EmitBuiltinFmin) +BUILTIN_FUNC_EMIT("fmin", &ASTCallExpr::EmitBuiltinFmin) +BUILTIN_FUNC_EMIT("fminf", &ASTCallExpr::EmitBuiltinFmin) +BUILTIN_FUNC_EMIT("fminl", &ASTCallExpr::EmitBuiltinFmin) +BUILTIN_FUNC_EMIT("__builtin_log", &ASTCallExpr::EmitBuiltinLog) +BUILTIN_FUNC_EMIT("__builtin_logf", &ASTCallExpr::EmitBuiltinLogf) +BUILTIN_FUNC_EMIT("__builtin_log10", &ASTCallExpr::EmitBuiltinLog10) +BUILTIN_FUNC_EMIT("__builtin_log10f", &ASTCallExpr::EmitBuiltinLog10f) +BUILTIN_FUNC_EMIT("__builtin_isunordered", &ASTCallExpr::EmitBuiltinIsunordered) +BUILTIN_FUNC_EMIT("__builtin_isless", &ASTCallExpr::EmitBuiltinIsless) +BUILTIN_FUNC_EMIT("__builtin_islessequal", &ASTCallExpr::EmitBuiltinIslessequal) +BUILTIN_FUNC_EMIT("__builtin_isgreater", &ASTCallExpr::EmitBuiltinIsgreater) +BUILTIN_FUNC_EMIT("__builtin_isgreaterequal", &ASTCallExpr::EmitBuiltinIsgreaterequal) +BUILTIN_FUNC_EMIT("__builtin_islessgreater", &ASTCallExpr::EmitBuiltinIslessgreater) +BUILTIN_FUNC_EMIT("__warn_memset_zero_len", &ASTCallExpr::EmitBuiltinWarnMemsetZeroLen) +BUILTIN_FUNC_EMIT("__builtin_rotateleft8", &ASTCallExpr::EmitBuiltinRotateLeft8) +BUILTIN_FUNC_EMIT("__builtin_rotateleft16", &ASTCallExpr::EmitBuiltinRotateLeft16) +BUILTIN_FUNC_EMIT("__builtin_rotateleft32", &ASTCallExpr::EmitBuiltinRotateLeft32) +BUILTIN_FUNC_EMIT("__builtin_rotateleft64", &ASTCallExpr::EmitBuiltinRotateLeft64) +BUILTIN_FUNC_EMIT("__builtin_rotateright8", &ASTCallExpr::EmitBuiltinRotateRight8) +BUILTIN_FUNC_EMIT("__builtin_rotateright16", &ASTCallExpr::EmitBuiltinRotateRight16) +BUILTIN_FUNC_EMIT("__builtin_rotateright32", &ASTCallExpr::EmitBuiltinRotateRight32) +BUILTIN_FUNC_EMIT("__builtin_rotateright64", &ASTCallExpr::EmitBuiltinRotateRight64) + +BUILTIN_FUNC_EMIT("__sync_add_and_fetch_8", &ASTCallExpr::EmitBuiltinSyncAddAndFetch8) +BUILTIN_FUNC_EMIT("__sync_add_and_fetch_4", &ASTCallExpr::EmitBuiltinSyncAddAndFetch4) +BUILTIN_FUNC_EMIT("__sync_add_and_fetch_2", &ASTCallExpr::EmitBuiltinSyncAddAndFetch2) +BUILTIN_FUNC_EMIT("__sync_add_and_fetch_1", &ASTCallExpr::EmitBuiltinSyncAddAndFetch1) +BUILTIN_FUNC_EMIT("__sync_sub_and_fetch_8", &ASTCallExpr::EmitBuiltinSyncSubAndFetch8) +BUILTIN_FUNC_EMIT("__sync_sub_and_fetch_4", &ASTCallExpr::EmitBuiltinSyncSubAndFetch4) +BUILTIN_FUNC_EMIT("__sync_sub_and_fetch_2", &ASTCallExpr::EmitBuiltinSyncSubAndFetch2) +BUILTIN_FUNC_EMIT("__sync_sub_and_fetch_1", &ASTCallExpr::EmitBuiltinSyncSubAndFetch1) +BUILTIN_FUNC_EMIT("__sync_fetch_and_sub_8", &ASTCallExpr::EmitBuiltinSyncFetchAndSub8) +BUILTIN_FUNC_EMIT("__sync_fetch_and_sub_4", &ASTCallExpr::EmitBuiltinSyncFetchAndSub4) +BUILTIN_FUNC_EMIT("__sync_fetch_and_sub_2", &ASTCallExpr::EmitBuiltinSyncFetchAndSub2) +BUILTIN_FUNC_EMIT("__sync_fetch_and_sub_1", &ASTCallExpr::EmitBuiltinSyncFetchAndSub1) +BUILTIN_FUNC_EMIT("__sync_fetch_and_add_8", &ASTCallExpr::EmitBuiltinSyncFetchAndAdd8) +BUILTIN_FUNC_EMIT("__sync_fetch_and_add_4", &ASTCallExpr::EmitBuiltinSyncFetchAndAdd4) +BUILTIN_FUNC_EMIT("__sync_fetch_and_add_2", &ASTCallExpr::EmitBuiltinSyncFetchAndAdd2) +BUILTIN_FUNC_EMIT("__sync_fetch_and_add_1", &ASTCallExpr::EmitBuiltinSyncFetchAndAdd1) +BUILTIN_FUNC_EMIT("__sync_bool_compare_and_swap_8", &ASTCallExpr::EmitBuiltinSyncBoolCompareAndSwap8) +BUILTIN_FUNC_EMIT("__sync_bool_compare_and_swap_4", &ASTCallExpr::EmitBuiltinSyncBoolCompareAndSwap4) +BUILTIN_FUNC_EMIT("__sync_bool_compare_and_swap_2", &ASTCallExpr::EmitBuiltinSyncBoolCompareAndSwap2) +BUILTIN_FUNC_EMIT("__sync_bool_compare_and_swap_1", &ASTCallExpr::EmitBuiltinSyncBoolCompareAndSwap1) +BUILTIN_FUNC_EMIT("__sync_val_compare_and_swap_8", &ASTCallExpr::EmitBuiltinSyncValCompareAndSwap8) +BUILTIN_FUNC_EMIT("__sync_val_compare_and_swap_4", &ASTCallExpr::EmitBuiltinSyncValCompareAndSwap4) +BUILTIN_FUNC_EMIT("__sync_val_compare_and_swap_2", &ASTCallExpr::EmitBuiltinSyncValCompareAndSwap2) +BUILTIN_FUNC_EMIT("__sync_val_compare_and_swap_1", &ASTCallExpr::EmitBuiltinSyncValCompareAndSwap1) +BUILTIN_FUNC_EMIT("__sync_lock_test_and_set_8", &ASTCallExpr::EmitBuiltinSyncLockTestAndSet8) +BUILTIN_FUNC_EMIT("__sync_lock_test_and_set_4", &ASTCallExpr::EmitBuiltinSyncLockTestAndSet4) +BUILTIN_FUNC_EMIT("__sync_lock_test_and_set_2", &ASTCallExpr::EmitBuiltinSyncLockTestAndSet2) +BUILTIN_FUNC_EMIT("__sync_lock_test_and_set_1", &ASTCallExpr::EmitBuiltinSyncLockTestAndSet1) +BUILTIN_FUNC_EMIT("__sync_lock_release_8", &ASTCallExpr::EmitBuiltinSyncLockRelease8) +BUILTIN_FUNC_EMIT("__sync_lock_release_4", &ASTCallExpr::EmitBuiltinSyncLockRelease4) +BUILTIN_FUNC_EMIT("__sync_lock_release_2", &ASTCallExpr::EmitBuiltinSyncLockRelease2) +BUILTIN_FUNC_EMIT("__sync_lock_release_1", &ASTCallExpr::EmitBuiltinSyncLockRelease1) +BUILTIN_FUNC_EMIT("__sync_fetch_and_and_1", &ASTCallExpr::EmitBuiltinSyncFetchAndAnd1) +BUILTIN_FUNC_EMIT("__sync_fetch_and_and_2", &ASTCallExpr::EmitBuiltinSyncFetchAndAnd2) +BUILTIN_FUNC_EMIT("__sync_fetch_and_and_4", &ASTCallExpr::EmitBuiltinSyncFetchAndAnd4) +BUILTIN_FUNC_EMIT("__sync_fetch_and_and_8", &ASTCallExpr::EmitBuiltinSyncFetchAndAnd8) +BUILTIN_FUNC_EMIT("__sync_fetch_and_or_1", &ASTCallExpr::EmitBuiltinSyncFetchAndOr1) +BUILTIN_FUNC_EMIT("__sync_fetch_and_or_2", &ASTCallExpr::EmitBuiltinSyncFetchAndOr2) +BUILTIN_FUNC_EMIT("__sync_fetch_and_or_4", &ASTCallExpr::EmitBuiltinSyncFetchAndOr4) +BUILTIN_FUNC_EMIT("__sync_fetch_and_or_8", &ASTCallExpr::EmitBuiltinSyncFetchAndOr8) +BUILTIN_FUNC_EMIT("__sync_fetch_and_xor_1", &ASTCallExpr::EmitBuiltinSyncFetchAndXor1) +BUILTIN_FUNC_EMIT("__sync_fetch_and_xor_2", &ASTCallExpr::EmitBuiltinSyncFetchAndXor2) +BUILTIN_FUNC_EMIT("__sync_fetch_and_xor_4", &ASTCallExpr::EmitBuiltinSyncFetchAndXor4) +BUILTIN_FUNC_EMIT("__sync_fetch_and_xor_8", &ASTCallExpr::EmitBuiltinSyncFetchAndXor8) +BUILTIN_FUNC_EMIT("__sync_fetch_and_nand_1", &ASTCallExpr::EmitBuiltinSyncFetchAndNand1) +BUILTIN_FUNC_EMIT("__sync_fetch_and_nand_2", &ASTCallExpr::EmitBuiltinSyncFetchAndNand2) +BUILTIN_FUNC_EMIT("__sync_fetch_and_nand_4", &ASTCallExpr::EmitBuiltinSyncFetchAndNand4) +BUILTIN_FUNC_EMIT("__sync_fetch_and_nand_8", &ASTCallExpr::EmitBuiltinSyncFetchAndNand8) +BUILTIN_FUNC_EMIT("__sync_and_and_fetch_1", &ASTCallExpr::EmitBuiltinSyncAndAndFetch1) +BUILTIN_FUNC_EMIT("__sync_and_and_fetch_2", &ASTCallExpr::EmitBuiltinSyncAndAndFetch2) +BUILTIN_FUNC_EMIT("__sync_and_and_fetch_4", &ASTCallExpr::EmitBuiltinSyncAndAndFetch4) +BUILTIN_FUNC_EMIT("__sync_and_and_fetch_8", &ASTCallExpr::EmitBuiltinSyncAndAndFetch8) +BUILTIN_FUNC_EMIT("__sync_or_and_fetch_1", &ASTCallExpr::EmitBuiltinSyncOrAndFetch1) +BUILTIN_FUNC_EMIT("__sync_or_and_fetch_2", &ASTCallExpr::EmitBuiltinSyncOrAndFetch2) +BUILTIN_FUNC_EMIT("__sync_or_and_fetch_4", &ASTCallExpr::EmitBuiltinSyncOrAndFetch4) +BUILTIN_FUNC_EMIT("__sync_or_and_fetch_8", &ASTCallExpr::EmitBuiltinSyncOrAndFetch8) +BUILTIN_FUNC_EMIT("__sync_xor_and_fetch_1", &ASTCallExpr::EmitBuiltinSyncXorAndFetch1) +BUILTIN_FUNC_EMIT("__sync_xor_and_fetch_2", &ASTCallExpr::EmitBuiltinSyncXorAndFetch2) +BUILTIN_FUNC_EMIT("__sync_xor_and_fetch_4", &ASTCallExpr::EmitBuiltinSyncXorAndFetch4) +BUILTIN_FUNC_EMIT("__sync_xor_and_fetch_8", &ASTCallExpr::EmitBuiltinSyncXorAndFetch8) +BUILTIN_FUNC_EMIT("__sync_nand_and_fetch_1", &ASTCallExpr::EmitBuiltinSyncNandAndFetch1) +BUILTIN_FUNC_EMIT("__sync_nand_and_fetch_2", &ASTCallExpr::EmitBuiltinSyncNandAndFetch2) +BUILTIN_FUNC_EMIT("__sync_nand_and_fetch_4", &ASTCallExpr::EmitBuiltinSyncNandAndFetch4) +BUILTIN_FUNC_EMIT("__sync_nand_and_fetch_8", &ASTCallExpr::EmitBuiltinSyncNandAndFetch8) +BUILTIN_FUNC_EMIT("__sync_synchronize", &ASTCallExpr::EmitBuiltinSyncSynchronize) + +BUILTIN_FUNC_EMIT("__builtin_return_address", &ASTCallExpr::EmitBuiltinReturnAddress) +BUILTIN_FUNC_EMIT("__builtin_extract_return_addr", &ASTCallExpr::EmitBuiltinExtractReturnAddr) + +BUILTIN_FUNC_EMIT("__builtin_memcpy", &ASTCallExpr::EmitBuiltinMemcpy) +BUILTIN_FUNC_EMIT("__builtin_memmove", &ASTCallExpr::EmitBuiltinMemmove) +BUILTIN_FUNC_EMIT("__builtin_memset", &ASTCallExpr::EmitBuiltinMemset) +BUILTIN_FUNC_EMIT("__builtin_strcpy", &ASTCallExpr::EmitBuiltinStrcpy) +BUILTIN_FUNC_EMIT("__builtin_strncpy", &ASTCallExpr::EmitBuiltinStrncpy) + +BUILTIN_FUNC_EMIT("__builtin_memcmp", &ASTCallExpr::EmitBuiltinMemcmp) +BUILTIN_FUNC_EMIT("__builtin_strlen", &ASTCallExpr::EmitBuiltinStrlen) +BUILTIN_FUNC_EMIT("__builtin_strcmp", &ASTCallExpr::EmitBuiltinStrcmp) +BUILTIN_FUNC_EMIT("__builtin_strncmp", &ASTCallExpr::EmitBuiltinStrncmp) +BUILTIN_FUNC_EMIT("__builtin_strchr", &ASTCallExpr::EmitBuiltinStrchr) +BUILTIN_FUNC_EMIT("__builtin_strrchr", &ASTCallExpr::EmitBuiltinStrrchr) diff --git a/src/hir2mpl/ast_input/clang/include/builtin_func_parse.def b/src/hir2mpl/ast_input/clang/include/builtin_func_parse.def new file mode 100644 index 0000000000000000000000000000000000000000..888736e5c9dc81d40f2ada87112948126763f4ac --- /dev/null +++ b/src/hir2mpl/ast_input/clang/include/builtin_func_parse.def @@ -0,0 +1,20 @@ +BUILTIN_FUNC_PARSE("__builtin_classify_type", &ASTParser::ParseBuiltinClassifyType) +BUILTIN_FUNC_PARSE("__builtin_constant_p", &ASTParser::ParseBuiltinConstantP) +BUILTIN_FUNC_PARSE("__builtin_isinf_sign", &ASTParser::ParseBuiltinIsinfsign) +BUILTIN_FUNC_PARSE("__builtin_huge_val", &ASTParser::ParseBuiltinHugeVal) +BUILTIN_FUNC_PARSE("__builtin_huge_valf", &ASTParser::ParseBuiltinHugeValf) +BUILTIN_FUNC_PARSE("__builtin_huge_vall", &ASTParser::ParseBuiltinHugeVal) +BUILTIN_FUNC_PARSE("__builtin_inf", &ASTParser::ParseBuiltinInf) +BUILTIN_FUNC_PARSE("__builtin_inff", &ASTParser::ParseBuiltinInff) +BUILTIN_FUNC_PARSE("__builtin_infl", &ASTParser::ParseBuiltinInf) +BUILTIN_FUNC_PARSE("__builtin_nan", &ASTParser::ParseBuiltinNan) +BUILTIN_FUNC_PARSE("__builtin_nanf", &ASTParser::ParseBuiltinNanf) +BUILTIN_FUNC_PARSE("__builtin_nanl", &ASTParser::ParseBuiltinNan) +BUILTIN_FUNC_PARSE("__builtin_signbit", &ASTParser::ParseBuiltinSignbit) +BUILTIN_FUNC_PARSE("__builtin_signbitf", &ASTParser::ParseBuiltinSignBitf) +BUILTIN_FUNC_PARSE("__builtin_signbitl", &ASTParser::ParseBuiltinSignBitl) +BUILTIN_FUNC_PARSE("__builtin_trap", &ASTParser::ParseBuiltinTrap) +BUILTIN_FUNC_PARSE("__builtin_copysignf", &ASTParser::ParseBuiltinCopysignf) +BUILTIN_FUNC_PARSE("__builtin_copysign", &ASTParser::ParseBuiltinCopysign) +BUILTIN_FUNC_PARSE("__builtin_copysignl", &ASTParser::ParseBuiltinCopysignl) +BUILTIN_FUNC_PARSE("__builtin_object_size", &ASTParser::ParseBuiltinObjectsize) \ No newline at end of file diff --git a/src/hir2mpl/ast_input/clang/lib/ast_alias.h b/src/hir2mpl/ast_input/clang/lib/ast_alias.h new file mode 100644 index 0000000000000000000000000000000000000000..548c22d36e43dfc270bf41164e316ae1bc019c8e --- /dev/null +++ b/src/hir2mpl/ast_input/clang/lib/ast_alias.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_AST_FILE_INCLUDE_AST_ALIAS_H +#define HIR2MPL_AST_FILE_INCLUDE_AST_ALIAS_H +#include "clang-c/Index.h" +#include "libclang/CIndexer.h" +#include "libclang/CXTranslationUnit.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/AST/Decl.h" +#include "clang/AST/AST.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/GlobalDecl.h" +#include "clang/AST/Mangle.h" +#include "clang/AST/VTableBuilder.h" +#include "clang/AST/VTTBuilder.h" +#include "clang/Lex/Lexer.h" +#include "clang/Frontend/ASTConsumers.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/AST/DeclBase.h" + +namespace maple { + using AstASTContext = clang::ASTContext; + using AstUnitDecl = clang::TranslationUnitDecl; + using AstASTUnit = clang::ASTUnit; +} // namespace maple +#endif // HIR2MPL_AST_FILE_INCLUDE_AST_ALIAS_H diff --git a/src/hir2mpl/ast_input/clang/lib/ast_interface.cpp b/src/hir2mpl/ast_input/clang/lib/ast_interface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d138bcce75a894a25ae280a2f485b6d15af26f5f --- /dev/null +++ b/src/hir2mpl/ast_input/clang/lib/ast_interface.cpp @@ -0,0 +1,519 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ast_interface.h" +#include "mpl_logging.h" +#include "ast_util.h" +#include "fe_utils.h" +#include "fe_manager.h" + +namespace maple { +bool LibAstFile::Open(const std::string &fileName, + int excludeDeclFromPCH, int displayDiagnostics) { + astFileName = fileName; + CXIndex index = clang_createIndex(excludeDeclFromPCH, displayDiagnostics); + CXTranslationUnit translationUnit = clang_createTranslationUnit(index, fileName.c_str()); + if (translationUnit == nullptr) { + return false; + } + clang::ASTUnit *astUnit = translationUnit->TheASTUnit; + if (astUnit == nullptr) { + return false; + } + astContext = &astUnit->getASTContext(); + if (astContext == nullptr) { + return false; + } + astUnitDecl = astContext->getTranslationUnitDecl(); + if (astUnitDecl == nullptr) { + return false; + } + mangleContext = astContext->createMangleContext(); + if (mangleContext == nullptr) { + return false; + } + return true; +} + +const AstASTContext *LibAstFile::GetAstContext() const { + return astContext; +} + +AstASTContext *LibAstFile::GetNonConstAstContext() const { + return astContext; +} + +AstUnitDecl *LibAstFile::GetAstUnitDecl() { + return astUnitDecl; +} + +std::string LibAstFile::GetMangledName(const clang::NamedDecl &decl) { + std::string mangledName; + if (!mangleContext->shouldMangleDeclName(&decl)) { + mangledName = decl.getNameAsString(); + } else { + llvm::raw_string_ostream ostream(mangledName); + if (llvm::isa(&decl)) { + const auto *ctor = static_cast(&decl); + mangleContext->mangleCtorBlock(ctor, static_cast(0), nullptr, ostream); + } else if (llvm::isa(&decl)) { + const auto *dtor = static_cast(&decl); + mangleContext->mangleDtorBlock(dtor, static_cast(0), nullptr, ostream); + } else { + mangleContext->mangleName(&decl, ostream); + } + ostream.flush(); + } + return mangledName; +} + +Pos LibAstFile::GetDeclPosInfo(const clang::Decl &decl) const { + clang::FullSourceLoc fullLocation = astContext->getFullLoc(decl.getBeginLoc()); + return std::make_pair(static_cast(fullLocation.getSpellingLineNumber()), + static_cast(fullLocation.getSpellingColumnNumber())); +} + +Pos LibAstFile::GetStmtLOC(const clang::Stmt &stmt) const { + return GetLOC(stmt.getBeginLoc()); +} + +Pos LibAstFile::GetExprLOC(const clang::Expr &expr) const { + return GetLOC(expr.getExprLoc()); +} + +Pos LibAstFile::GetLOC(const clang::SourceLocation &srcLoc) const { + if (srcLoc.isInvalid()) { + return std::make_pair(0, 0); + } + if (srcLoc.isFileID()) { + clang::PresumedLoc pLOC = astContext->getSourceManager().getPresumedLoc(srcLoc); + if (pLOC.isInvalid()) { + return std::make_pair(0, 0); + } + std::string fileName = pLOC.getFilename(); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fileName); + for (const auto &info : FEManager::GetModule().GetSrcFileInfo()) { + if (info.first == strIdx) { + return std::make_pair(info.second, static_cast(pLOC.getLine())); + } + } + if (FEManager::GetModule().GetSrcFileInfo().empty()) { + // src files start from 2, 1 is mpl file + FEManager::GetModule().PushbackFileInfo(MIRInfoPair(strIdx, 2)); + return std::make_pair(2, static_cast(pLOC.getLine())); + } else { + auto last = FEManager::GetModule().GetSrcFileInfo().rbegin(); + FEManager::GetModule().PushbackFileInfo(MIRInfoPair(strIdx, last->second + 1)); + return std::make_pair(last->second + 1, static_cast(pLOC.getLine())); + } + } + + return GetLOC(astContext->getSourceManager().getExpansionLoc(srcLoc)); +} + +uint32 LibAstFile::GetMaxAlign(const clang::Decl &decl) const { + uint32 align = 0; + const clang::Decl *canonicalDecl = decl.getCanonicalDecl(); + if (canonicalDecl->getKind() == clang::Decl::Field) { + const clang::FieldDecl *fieldDecl = llvm::cast(canonicalDecl); + clang::QualType qualTy = fieldDecl->getType().getCanonicalType(); + align = RetrieveAggTypeAlign(qualTy.getTypePtr()); + } + uint32 selfAlign = canonicalDecl->getMaxAlignment(); + return align > selfAlign ? align : selfAlign; +} + +uint32 LibAstFile::RetrieveAggTypeAlign(const clang::Type *ty) const { + if (ty->isRecordType()) { + const auto *recordType = llvm::cast(ty); + clang::RecordDecl *recordDecl = recordType->getDecl(); + return (recordDecl->getMaxAlignment()) >> 3; // 8 bit = 2^3 bit = 1 byte + } else if (ty->isArrayType()) { + const clang::Type *elemType = ty->getArrayElementTypeNoTypeQual(); + return RetrieveAggTypeAlign(elemType); + } + return 0; +} + +void LibAstFile::GetCVRAttrs(uint32_t qualifiers, GenericAttrs &genAttrs) { + if (qualifiers & clang::Qualifiers::Const) { + genAttrs.SetAttr(GENATTR_const); + } + if (qualifiers & clang::Qualifiers::Restrict) { + genAttrs.SetAttr(GENATTR_restrict); + } + if (qualifiers & clang::Qualifiers::Volatile) { + genAttrs.SetAttr(GENATTR_volatile); + } +} + +void LibAstFile::GetSClassAttrs(const clang::StorageClass storageClass, GenericAttrs &genAttrs) const { + switch (storageClass) { + case clang::SC_Extern: + case clang::SC_PrivateExtern: + genAttrs.SetAttr(GENATTR_extern); + break; + case clang::SC_Static: + genAttrs.SetAttr(GENATTR_static); + break; + default: + break; + } +} + +void LibAstFile::GetStorageAttrs(const clang::NamedDecl &decl, GenericAttrs &genAttrs) const { + switch (decl.getKind()) { + case clang::Decl::Function: + case clang::Decl::CXXMethod: { + const auto *funcDecl = llvm::cast(&decl); + const clang::StorageClass storageClass = funcDecl->getStorageClass(); + GetSClassAttrs(storageClass, genAttrs); + // static or extern maybe missing in current FunctionDecls, + // Since a given function can be declared several times in a program, + // Only one of those FunctionDecls will be found when traversing the list of declarations in the context. + const clang::FunctionDecl *prev = funcDecl->getPreviousDecl(); + while (prev != nullptr && prev->isDefined()) { + GetStorageAttrs(*prev, genAttrs); + prev = prev->getPreviousDecl(); + } + break; + } + case clang::Decl::ParmVar: + case clang::Decl::Var: { + const auto *varDecl = llvm::cast(&decl); + const clang::StorageClass storageClass = varDecl->getStorageClass(); + GetSClassAttrs(storageClass, genAttrs); + break; + } + case clang::Decl::Field: + default: + break; + } + return; +} + +void LibAstFile::GetAccessAttrs(AccessKind access, GenericAttrs &genAttrs) { + switch (access) { + case kPublic: + genAttrs.SetAttr(GENATTR_public); + break; + case kProtected: + genAttrs.SetAttr(GENATTR_protected); + break; + case kPrivate: + genAttrs.SetAttr(GENATTR_private); + break; + case kNone: + break; + default: + ASSERT(false, "shouldn't reach here"); + break; + } + return; +} + +void LibAstFile::GetQualAttrs(const clang::NamedDecl &decl, GenericAttrs &genAttrs) { + switch (decl.getKind()) { + case clang::Decl::Function: + case clang::Decl::CXXMethod: + case clang::Decl::ParmVar: + case clang::Decl::Var: + case clang::Decl::Field: { + const auto *valueDecl = llvm::dyn_cast(&decl); + ASSERT(valueDecl != nullptr, "ERROR:null pointer!"); + const clang::QualType qualType = valueDecl->getType(); + uint32_t qualifiers = qualType.getCVRQualifiers(); + GetCVRAttrs(qualifiers, genAttrs); + break; + } + default: + break; + } +} + +void LibAstFile::CollectAttrs(const clang::NamedDecl &decl, GenericAttrs &genAttrs, AccessKind access) { + GetStorageAttrs(decl, genAttrs); + GetAccessAttrs(access, genAttrs); + GetQualAttrs(decl, genAttrs); + if (decl.isImplicit()) { + genAttrs.SetAttr(GENATTR_implicit); + } + if (decl.isUsed()) { + genAttrs.SetAttr(GENATTR_used); + } + if (decl.hasAttr()) { + genAttrs.SetAttr(GENATTR_weak); + } + if (decl.hasAttr() && decl.getKind() != clang::Decl::Function) { + for (const auto *nonNull : decl.specific_attrs()) { + if (nonNull->args_size() > 0) { + // nonnull with args in function type pointers need special handling to mark nonnull arg + continue; + } + genAttrs.SetAttr(GENATTR_nonnull); + } + } +} + +void LibAstFile::CollectFuncAttrs(const clang::FunctionDecl &decl, GenericAttrs &genAttrs, AccessKind access) { + CollectAttrs(decl, genAttrs, access); + if (decl.isVirtualAsWritten()) { + genAttrs.SetAttr(GENATTR_virtual); + } + if (decl.isDeletedAsWritten()) { + genAttrs.SetAttr(GENATTR_delete); + } + if (decl.isPure()) { + genAttrs.SetAttr(GENATTR_pure); + } + if (decl.isInlineSpecified()) { + genAttrs.SetAttr(GENATTR_inline); + } else if (decl.hasAttr()) { + genAttrs.SetAttr(GENATTR_noinline); + } + if (decl.isDefaulted()) { + genAttrs.SetAttr(GENATTR_default); + } + if (decl.getKind() == clang::Decl::CXXConstructor) { + genAttrs.SetAttr(GENATTR_constructor); + } + if (decl.getKind() == clang::Decl::CXXDestructor) { + genAttrs.SetAttr(GENATTR_destructor); + } + if (decl.isVariadic()) { + genAttrs.SetAttr(GENATTR_varargs); + } + if (decl.isNoReturn()) { + genAttrs.SetAttr(GENATTR_noreturn); + } + clang::AliasAttr *aliasAttr = decl.getAttr(); + if (aliasAttr != nullptr) { + genAttrs.SetAttr(GENATTR_alias); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(aliasAttr->getAliasee().str()); + genAttrs.InsertStrIdxContentMap(GENATTR_alias, strIdx); + } + clang::ConstructorAttr *constructorAttr = decl.getAttr(); + if (constructorAttr != nullptr) { + genAttrs.SetAttr(GENATTR_constructor_priority); + genAttrs.InsertIntContentMap(GENATTR_constructor_priority, constructorAttr->getPriority()); + } + clang::DestructorAttr *destructorAttr = decl.getAttr(); + if (destructorAttr != nullptr) { + genAttrs.SetAttr(GENATTR_destructor_priority); + genAttrs.InsertIntContentMap(GENATTR_destructor_priority, destructorAttr->getPriority()); + } + CheckUnsupportedFuncAttrs(decl); +} + +void LibAstFile::CheckUnsupportedFuncAttrs(const clang::FunctionDecl &decl) { + if (!decl.hasAttrs()) { + return; + } + std::string unsupportedFuncAttrs = ""; + const clang::AttrVec &funcAttrs = decl.getAttrs(); + for (const auto *attr : funcAttrs) { + clang::attr::Kind attrKind = attr->getKind(); + auto iterator = LibAstFile::unsupportedFuncAttrsMap.find(attrKind); + if (iterator != LibAstFile::unsupportedFuncAttrsMap.end()) { + unsupportedFuncAttrs += iterator->second + " "; + } + } + CHECK_FATAL(unsupportedFuncAttrs.empty(), "%s:%d error: The function %s has unsupported attribute(s): %s", + FEManager::GetModule().GetFileNameFromFileNum(GetLOC(decl.getLocation()).first).c_str(), + GetLOC(decl.getLocation()).second, + GetMangledName(decl).c_str(), + unsupportedFuncAttrs.c_str()); +} + +void LibAstFile::CollectVarAttrs(const clang::VarDecl &decl, GenericAttrs &genAttrs, AccessKind access) { + CollectAttrs(decl, genAttrs, access); + // handle __thread + if (decl.getTLSKind() == clang::VarDecl::TLS_Static) { + genAttrs.SetAttr(GENATTR_tls_static); + } else if (decl.getTLSKind() == clang::VarDecl::TLS_Dynamic) { + genAttrs.SetAttr(GENATTR_tls_dynamic); + } + // one elem vector type + if (IsOneElementVector(decl.getType())) { + genAttrs.SetAttr(GENATTR_oneelem_simd); + } + CheckUnsupportedVarAttrs(decl); +} + +void LibAstFile::CheckUnsupportedVarAttrs(const clang::VarDecl &decl) { + if (!decl.hasAttrs()) { + return; + } + std::string unsupportedVarAttrs = ""; + const clang::AttrVec &varAttrs = decl.getAttrs(); + for (const auto *attr : varAttrs) { + clang::attr::Kind attrKind = attr->getKind(); + auto iterator = LibAstFile::unsupportedVarAttrsMap.find(attrKind); + if (iterator != LibAstFile::unsupportedVarAttrsMap.end()) { + unsupportedVarAttrs += iterator->second + " "; + } + } + CHECK_FATAL(unsupportedVarAttrs.empty(), "%s:%d error: The variable %s has unsupported attribute(s): %s", + FEManager::GetModule().GetFileNameFromFileNum(GetLOC(decl.getLocation()).first).c_str(), + GetLOC(decl.getLocation()).second, + GetMangledName(decl).c_str(), + unsupportedVarAttrs.c_str()); +} + +void LibAstFile::CollectRecordAttrs(const clang::RecordDecl &decl, GenericAttrs &genAttrs, AccessKind access) { + clang::PackedAttr *packedAttr = decl.getAttr(); + if (packedAttr != nullptr) { + genAttrs.SetAttr(GENATTR_pack); + genAttrs.InsertIntContentMap(GENATTR_pack, 1); // 1 byte + } + clang::MaxFieldAlignmentAttr *maxFieldAlignAttr = decl.getAttr(); + if (maxFieldAlignAttr != nullptr) { + genAttrs.SetAttr(GENATTR_pack); + genAttrs.InsertIntContentMap(GENATTR_pack, static_cast(maxFieldAlignAttr->getAlignment() / 8)); + } + CheckUnsupportedTypeAttrs(decl); +} + +void LibAstFile::CheckUnsupportedTypeAttrs(const clang::RecordDecl &decl) { + if (!decl.hasAttrs()) { + return; + } + std::string unsupportedTypeAttrs = ""; + const clang::AttrVec &typeAttrs = decl.getAttrs(); + for (const auto *attr : typeAttrs) { + clang::attr::Kind attrKind = attr->getKind(); + auto iterator = LibAstFile::unsupportedTypeAttrsMap.find(attrKind); + if (iterator != LibAstFile::unsupportedTypeAttrsMap.end()) { + unsupportedTypeAttrs += iterator->second + " "; + } + } + CHECK_FATAL(unsupportedTypeAttrs.empty(), "%s:%d error: struct or union %s has unsupported type attribute(s): %s", + FEManager::GetModule().GetFileNameFromFileNum(GetLOC(decl.getLocation()).first).c_str(), + GetLOC(decl.getLocation()).second, + GetMangledName(decl).c_str(), + unsupportedTypeAttrs.c_str()); +} + +void LibAstFile::CollectFieldAttrs(const clang::FieldDecl &decl, GenericAttrs &genAttrs, AccessKind access) { + CollectAttrs(decl, genAttrs, access); + clang::PackedAttr *packedAttr = decl.getAttr(); + if (packedAttr != nullptr) { + genAttrs.SetAttr(GENATTR_pack); + genAttrs.InsertIntContentMap(GENATTR_pack, 1); // 1 byte + } +} + +void LibAstFile::EmitTypeName(const clang::QualType qualType, std::stringstream &ss) { + switch (qualType->getTypeClass()) { + case clang::Type::LValueReference: { + ss << "R"; + const clang::QualType pointeeType = qualType->castAs()->getPointeeType(); + EmitTypeName(pointeeType, ss); + break; + } + case clang::Type::Pointer: { + ss << "P"; + const clang::QualType pointeeType = qualType->castAs()->getPointeeType(); + EmitTypeName(pointeeType, ss); + break; + } + case clang::Type::Record: { + EmitTypeName(*qualType->getAs(), ss); + break; + } + default: { + EmitQualifierName(qualType, ss); + MIRType *type = CvtType(qualType); + ss << ASTUtil::GetTypeString(*type); + break; + } + } +} + +void LibAstFile::EmitQualifierName(const clang::QualType qualType, std::stringstream &ss) { + uint32_t cvrQual = qualType.getCVRQualifiers(); + if ((cvrQual & clang::Qualifiers::Const) != 0) { + ss << "K"; + } + if (cvrQual & clang::Qualifiers::Volatile) { + ss << "U"; + } +} + +const std::string LibAstFile::GetOrCreateMappedUnnamedName(uint32_t id) { + std::map::iterator it = unnamedSymbolMap.find(id); + if (it == unnamedSymbolMap.end()) { + std::string name = FEUtils::GetSequentialName("unNamed"); + unnamedSymbolMap[id] = name; + } + return unnamedSymbolMap[id]; +} + +void LibAstFile::EmitTypeName(const clang::RecordType &recoType, std::stringstream &ss) { + clang::RecordDecl *recoDecl = recoType.getDecl(); + std::string str = recoType.desugar().getAsString(); + if (!recoDecl->isAnonymousStructOrUnion() && str.find("anonymous") == std::string::npos) { + clang::DeclContext *ctx = recoDecl->getDeclContext(); + MapleStack nsStack(module->GetMPAllocator().Adapter()); + while (!ctx->isTranslationUnit()) { + auto *primCtxNsDc = llvm::dyn_cast(ctx->getPrimaryContext()); + if (primCtxNsDc != nullptr) { + nsStack.push(primCtxNsDc); + } + auto *primCtxRecoDc = llvm::dyn_cast(ctx->getPrimaryContext()); + if (primCtxRecoDc != nullptr) { + nsStack.push(primCtxRecoDc); + } + ctx = ctx->getParent(); + } + while (!nsStack.empty()) { + auto *nsDc = llvm::dyn_cast(nsStack.top()); + if (nsDc != nullptr) { + ss << nsDc->getName().data() << "|"; + } + auto *rcDc = llvm::dyn_cast(nsStack.top()); + if (rcDc != nullptr) { + EmitTypeName(*rcDc->getTypeForDecl()->getAs(), ss); + } + nsStack.pop(); + } + auto nameStr = recoDecl->getName().str(); + if (nameStr.empty()) { + nameStr = GetTypedefNameFromUnnamedStruct(*recoDecl); + } + if (nameStr.empty()) { + uint32_t id = recoType.getDecl()->getLocation().getRawEncoding(); + nameStr = GetOrCreateMappedUnnamedName(id); + } + ss << nameStr; + } else { + uint32_t id = recoType.getDecl()->getLocation().getRawEncoding(); + ss << GetOrCreateMappedUnnamedName(id); + } + + if (!recoDecl->isDefinedOutsideFunctionOrMethod()) { + Pos p = GetDeclPosInfo(*recoDecl); + ss << "_" << p.first << "_" << p.second; + } +} + +// get TypedefDecl name for the unnamed struct, e.g. typedef struct {} foo; +std::string LibAstFile::GetTypedefNameFromUnnamedStruct(const clang::RecordDecl &recoDecl) { + auto *defnameDcel = recoDecl.getTypedefNameForAnonDecl(); + if (defnameDcel != nullptr) { + return defnameDcel->getQualifiedNameAsString(); + } + return std::string(); +} +} // namespace maple diff --git a/src/hir2mpl/ast_input/clang/lib/ast_interface.h b/src/hir2mpl/ast_input/clang/lib/ast_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..09a61009bb6721a6556f34babf47c15516780d88 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/lib/ast_interface.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_AST_FILE_INCLUDE_AST_INTERFACE_H +#define HIR2MPL_AST_FILE_INCLUDE_AST_INTERFACE_H +#include +#include "ast_alias.h" +#include "mir_type.h" +#include "mir_nodes.h" +#include "mpl_logging.h" +#include "generic_attrs.h" +#include "fe_utils.h" +#include "clang/Basic/AttrKinds.h" + +namespace maple { +using Pos = std::pair; +enum AccessKind { + kPublic, + kProtected, + kPrivate, + kNone +}; +typedef std::unordered_map AttributesMap; +class LibAstFile { + public: + explicit LibAstFile(MapleList &recordDeclesIn) : recordDecles(recordDeclesIn) {} + ~LibAstFile() = default; + + bool Open(const std::string &fileName, + int excludeDeclFromPCH, int displayDiagnostics); + const AstASTContext *GetAstContext() const; + AstASTContext *GetNonConstAstContext() const; + AstUnitDecl *GetAstUnitDecl(); + std::string GetMangledName(const clang::NamedDecl &decl); + const std::string GetOrCreateMappedUnnamedName(uint32_t id); + + void EmitTypeName(const clang::QualType qualType, std::stringstream &ss); + void EmitTypeName(const clang::RecordType &qualType, std::stringstream &ss); + void EmitQualifierName(const clang::QualType qualType, std::stringstream &ss); + std::string GetTypedefNameFromUnnamedStruct(const clang::RecordDecl &recoDecl); + void CollectBaseEltTypeAndSizesFromConstArrayDecl(const clang::QualType &qualType, MIRType *&elemType, + TypeAttrs &elemAttr, std::vector &operands); + + void CollectBaseEltTypeAndDimFromVariaArrayDecl(const clang::QualType &qualType, MIRType *&elemType, + TypeAttrs &elemAttr, uint8_t &dim); + + void CollectBaseEltTypeAndDimFromDependentSizedArrayDecl(const clang::QualType qualType, MIRType *&elemType, + TypeAttrs &elemAttr, std::vector &operands); + + void GetCVRAttrs(uint32_t qualifiers, GenericAttrs &genAttrs); + void GetSClassAttrs(const clang::StorageClass storageClass, GenericAttrs &genAttrs) const; + void GetStorageAttrs(const clang::NamedDecl &decl, GenericAttrs &genAttrs) const; + void GetAccessAttrs(AccessKind access, GenericAttrs &genAttrs); + void GetQualAttrs(const clang::NamedDecl &decl, GenericAttrs &genAttrs); + void CollectAttrs(const clang::NamedDecl &decl, GenericAttrs &genAttrs, AccessKind access); + void CollectFuncAttrs(const clang::FunctionDecl &decl, GenericAttrs &genAttrs, AccessKind access); + void CheckUnsupportedFuncAttrs(const clang::FunctionDecl &decl); + void CollectVarAttrs(const clang::VarDecl &decl, GenericAttrs &genAttrs, AccessKind access); + void CheckUnsupportedVarAttrs(const clang::VarDecl &decl); + void CollectRecordAttrs(const clang::RecordDecl &decl, GenericAttrs &genAttrs, AccessKind access); + void CheckUnsupportedTypeAttrs(const clang::RecordDecl &decl); + void CollectFieldAttrs(const clang::FieldDecl &decl, GenericAttrs &genAttrs, AccessKind access); + MIRType *CvtPrimType(const clang::QualType qualType) const; + PrimType CvtPrimType(const clang::BuiltinType::Kind) const; + MIRType *CvtType(const clang::QualType qualType); + MIRType *CvtOtherType(const clang::QualType srcType); + MIRType *CvtArrayType(const clang::QualType srcType); + MIRType *CvtFunctionType(const clang::QualType srcType); + MIRType *CvtRecordType(const clang::QualType srcType); + MIRType *CvtFieldType(const clang::NamedDecl &decl); + MIRType *CvtComplexType(const clang::QualType srcType); + MIRType *CvtVectorType(const clang::QualType srcType); + bool TypeHasMayAlias(const clang::QualType srcType); + static bool IsOneElementVector(const clang::QualType &qualType); + static bool IsOneElementVector(const clang::Type &type); + + const clang::ASTContext *GetContext() const { + return astContext; + } + + const std::string GetAstFileNameHashStr() const { + return FEUtils::GetFileNameHashStr(astFileName); + } + + Pos GetDeclPosInfo(const clang::Decl &decl) const; + Pos GetStmtLOC(const clang::Stmt &stmt) const; + Pos GetExprLOC(const clang::Expr &expr) const; + Pos GetLOC(const clang::SourceLocation &srcLoc) const; + uint32 GetMaxAlign(const clang::Decl &decl) const; + uint32 RetrieveAggTypeAlign(const clang::Type *ty) const; + + private: + using RecordDeclMap = std::map; + RecordDeclMap recordDeclMap; + std::set recordDeclSet; + std::map unnamedSymbolMap; + std::map CompoundLiteralExprInitSymbolMap; + MIRModule *module = nullptr; + + MapleList &recordDecles; + + clang::ASTContext *astContext = nullptr; + clang::TranslationUnitDecl *astUnitDecl = nullptr; + clang::MangleContext *mangleContext = nullptr; + std::string astFileName; + const AttributesMap unsupportedFuncAttrsMap = { + {clang::attr::NoInstrumentFunction, "no_instrument_function"}, + {clang::attr::StdCall, "stdcall"}, + {clang::attr::CDecl, "cdecl"}, + {clang::attr::MipsLongCall, "mips_long_call"}, + {clang::attr::MipsShortCall, "mips_short_call"}, + {clang::attr::ARMInterrupt, "arm_interrupt"}, + {clang::attr::AnyX86Interrupt, "x86_interrupt"}, + {clang::attr::Naked, "naked"}, + {clang::attr::AllocAlign, "alloc_align"}, + {clang::attr::AssumeAligned, "assume_aligned"}, + {clang::attr::Flatten, "flatten"}, + {clang::attr::GNUInline, "gnu_inline"}, + {clang::attr::Cold, "cold"}, + {clang::attr::IFunc, "ifunc"}, + {clang::attr::NoSanitize, "no_sanitize"}, + {clang::attr::NoSplitStack, "no_split_stack"}, + {clang::attr::PatchableFunctionEntry, "patchable_function_entry"}, + {clang::attr::Target, "target"} + }; + const AttributesMap unsupportedVarAttrsMap = { + {clang::attr::Mode, "mode"}, + {clang::attr::NoCommon, "nocommon"}, + {clang::attr::TransparentUnion, "transparent_union"}, + {clang::attr::Alias, "alias"}, + {clang::attr::Cleanup, "cleanup"}, + {clang::attr::Common, "common"}, + {clang::attr::Uninitialized, "uninitialized"} + }; + const AttributesMap unsupportedTypeAttrsMap = { + {clang::attr::MSStruct, "ms_struct"} + }; +}; +} // namespace maple +#endif // HIR2MPL_AST_FILE_INCLUDE_AST_INTERFACE_H diff --git a/src/hir2mpl/ast_input/clang/lib/ast_macros.h b/src/hir2mpl/ast_input/clang/lib/ast_macros.h new file mode 100644 index 0000000000000000000000000000000000000000..9e319854d0f8d7f5140c7f1df3e43732a13ac7ed --- /dev/null +++ b/src/hir2mpl/ast_input/clang/lib/ast_macros.h @@ -0,0 +1,253 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef AST2MPL_INCLUDE_ASTMACROS_H +#define AST2MPL_INCLUDE_ASTMACROS_H +#include +#include + +const uint32_t kSrcFileNum = 2; + +// ast2mpl options +// these values can be use such as -o=1 at command lines +const uint32_t kCheckAssertion = 1; +const uint32_t kNoComment = 2; +const uint32_t kNoLoc = 4; + +// these values can be use such as -d=3 at command lines +const int kDebugLevelZero = 0; +const int kDebugLevelOne = 1; +const int kDebugLevelTwo = 2; +const int kDebugLevelThree = 3; + +const int kComplexRealID = 1; +const int kComplexImagID = 2; + +const int kBitToByteShift = 3; + +const uint32_t kFloat128Size = 2; +const uint32_t kInt32Width = 32; +const uint32_t kInt32Mask = 0xFFFFFFFFULL; +const int kDefaultIndent = 1; + +#define ASTDEBUG +#ifdef ASTDEBUG +#define LOCATION __func__ << "() at " << __FILE__ << ":" << __LINE__ + +#define DUMPINFO(stmtClass, s) \ + if (maple::ast2mplDebug > kDebugLevelOne) { \ + std::cout << LOCATION << '\n'; \ + s->dump(); \ + std::cout << " " << '\n'; \ + } + +#define NOTYETHANDLED(s) \ + std::cout << "\n" << LOCATION << " <<<<<<<<<<<<<<<<<< Not Yet Handled: " << s << "<<<<<<<<<<<<<<<<<<" << '\n'; \ + if (maple::ast2mplOption & kCheckAssertion) { \ + ASSERT(false, "Not yet handled"); \ + } \ +// print empty line +#define DEBUGPRINT_N(n) \ + do { \ + if (maple::ast2mplDebug >= n) { \ + std::cout << " " << '\n'; \ + } \ + } while (0); + +// print indent +#define DEBUGPRINTIND(n) \ + do { \ + if (maple::ast2mplDebug > kDebugLevelZero) { \ + PrintIndentation(n); \ + } \ + } while (0); + +// print str +#define DEBUGPRINT_S_LEVEL(str, level) \ + do { \ + if (maple::ast2mplDebug >= level) { \ + PrintIndentation(ast2mplDebugIndent); \ + std::cout << " " << str << '\n'; \ + } \ + } while (0); + +#define DEBUGPRINT_FUNC(name) \ + do { \ + int ind = maple::ast2mplDebugIndent; \ + Util::SetIndent(kDefaultIndent); \ + if (maple::ast2mplDebug > kDebugLevelZero) { \ + PrintIndentation(ast2mplDebugIndent); \ + std::cout << name << " {" << '\n'; \ + } \ + Util::SetIndent(ind); \ + } while (0); + +#define DEBUGPRINT_FUNC_END(name) \ + do { \ + int ind = maple::ast2mplDebugIndent; \ + Util::SetIndent(kDefaultIndent); \ + if (maple::ast2mplDebug > kDebugLevelZero) { \ + PrintIndentation(ast2mplDebugIndent); \ + std::cout << "}\n" << '\n'; \ + } \ + Util::SetIndent(ind); \ + } while (0); + +#define DEBUGPRINT_NODE(node, type) \ + do { \ + if (maple::ast2mplDebug > kDebugLevelOne) { \ + PrintIndentation(maple::ast2mplDebugIndent); \ + std::cout << " >> node: "; \ + static_cast(node)->Print(static_cast(module), 0); \ + std::cout << "\n"; \ + } \ + } while (0); + +// print var = val +#define DEBUGPRINT_V_LEVEL(var, level) \ + do { \ + if (maple::ast2mplDebug >= level) { \ + PrintIndentation(maple::ast2mplDebugIndent); \ + std::cout << LOCATION << " " << #var << " = " << var << '\n'; \ + } \ + } while (0); + +#define DEBUGPRINT_X_LEVEL(var, level) \ + do { \ + if (maple::ast2mplDebug >= level) { \ + PrintIndentation(maple::ast2mplDebugIndent); \ + std::cout << LOCATION << " " << #var << " = " << std::hex << "0x" << var << std::dec << '\n'; \ + } \ + } while (0); + +// print var = val +#define DEBUGPRINT_V_LEVEL_PURE(var, level) \ + do { \ + if (maple::ast2mplDebug >= level) { \ + PrintIndentation(maple::ast2mplDebugIndent); \ + std::cout << #var << " = " << var << '\n'; \ + } \ + } while (0); + +// print val0 val1 +#define DEBUGPRINT_NN_LEVEL(var0, var1, level) \ + do { \ + if (maple::ast2mplDebug >= level) { \ + PrintIndentation(maple::ast2mplDebugIndent); \ + std::cout << var0 << " " << var1; \ + } \ + } while (0); + +// print var0 = val0, var1 = val1 +#define DEBUGPRINT_VV_LEVEL(var0, var1, level) \ + do { \ + if (maple::ast2mplDebug >= level) { \ + PrintIndentation(maple::ast2mplDebugIndent); \ + std::cout << LOCATION << " " << #var0 << " = " << var0 << ", " << #var1 << " = " << var1 << '\n'; \ + } \ + } while (0); + +// print val0, var = val +#define DEBUGPRINT_SV_LEVEL(val0, var, level) \ + do { \ + if (maple::ast2mplDebug >= level) { \ + PrintIndentation(maple::ast2mplDebugIndent); \ + std::cout << LOCATION << " " << val0 << ", " << #var << " = " << var << '\n'; \ + } \ + } while (0); + +#define DEBUGPRINT_SX_LEVEL(val0, var, level) \ + do { \ + if (maple::ast2mplDebug >= level) { \ + PrintIndentation(maple::ast2mplDebugIndent); \ + std::cout << LOCATION << " " << val0 << ", " << #var << " = " << std::hex << "0x" << var << std::dec \ + << '\n'; \ + } \ + } while (0); +#else + +#define DUMPINFO(stmtClass, s) +#define NOTHANDLED +#define DEBUGPRINT_N(n) +#define DEBUGPRINTIND(n) +#define DEBUGPRINT_S_LEVEL(str, level) +#define DEBUGPRINT_FUNC(name) +#define DEBUGPRINT_FUNC_END(name) +#define DEBUGPRINT_NODE(node, type) +#define DEBUGPRINT_V_LEVEL(var, level) +#define DEBUGPRINT_X_LEVEL(var, level) +#define DEBUGPRINT_V_LEVEL_PURE(var, level) +#define DEBUGPRINT_NN_LEVEL(var0, var1, level) +#define DEBUGPRINT_VV_LEVEL(var0, var1, level) +#define DEBUGPRINT_SV_LEVEL(val0, var, level) +#endif + +#define DEBUGPRINT00 DEBUGPRINT_N(0) +#define DEBUGPRINT01 DEBUGPRINT_N(1) +#define DEBUGPRINT02 DEBUGPRINT_N(2) +#define DEBUGPRINT03 DEBUGPRINT_N(3) + +#define DEBUGPRINT_S(var) DEBUGPRINT_S_LEVEL(var, 1) +#define DEBUGPRINT_S2(var) DEBUGPRINT_S_LEVEL(var, 2) +#define DEBUGPRINT_S3(var) DEBUGPRINT_S_LEVEL(var, 3) +#define DEBUGPRINT_S4(var) DEBUGPRINT_S_LEVEL(var, 4) +#define DEBUGPRINT_S5(var) DEBUGPRINT_S_LEVEL(var, 5) +#define DEBUGPRINT_S6(var) DEBUGPRINT_S_LEVEL(var, 6) + +#define DEBUGPRINT0(var) DEBUGPRINT_V_LEVEL(var, 0) +#define DEBUGPRINT(var) DEBUGPRINT_V_LEVEL(var, 1) +#define DEBUGPRINT2(var) DEBUGPRINT_V_LEVEL(var, 2) +#define DEBUGPRINT3(var) DEBUGPRINT_V_LEVEL(var, 3) +#define DEBUGPRINT4(var) DEBUGPRINT_V_LEVEL(var, 4) +#define DEBUGPRINT5(var) DEBUGPRINT_V_LEVEL(var, 5) +#define DEBUGPRINT6(var) DEBUGPRINT_V_LEVEL(var, 6) + +#define DEBUGPRINT_X(var) DEBUGPRINT_X_LEVEL(var, 1) +#define DEBUGPRINT_X2(var) DEBUGPRINT_X_LEVEL(var, 2) +#define DEBUGPRINT_X3(var) DEBUGPRINT_X_LEVEL(var, 3) +#define DEBUGPRINT_X4(var) DEBUGPRINT_X_LEVEL(var, 4) +#define DEBUGPRINT_X5(var) DEBUGPRINT_X_LEVEL(var, 5) +#define DEBUGPRINT_X6(var) DEBUGPRINT_X_LEVEL(var, 6) + +#define DEBUGPRINT_PURE(var) DEBUGPRINT_V_LEVEL_PURE(var, 1) +#define DEBUGPRINT2_PURE(var) DEBUGPRINT_V_LEVEL_PURE(var, 2) +#define DEBUGPRINT3_PURE(var) DEBUGPRINT_V_LEVEL_PURE(var, 3) +#define DEBUGPRINT4_PURE(var) DEBUGPRINT_V_LEVEL_PURE(var, 4) +#define DEBUGPRINT5_PURE(var) DEBUGPRINT_V_LEVEL_PURE(var, 5) +#define DEBUGPRINT6_PURE(var) DEBUGPRINT_V_LEVEL_PURE(var, 6) + +#define DEBUGPRINT_NN(var0, var1) DEBUGPRINT_NN_LEVEL(var0, var1, 1) +#define DEBUGPRINT_NN_2(var0, var1) DEBUGPRINT_NN_LEVEL(var0, var1, 2) +#define DEBUGPRINT_NN_3(var0, var1) DEBUGPRINT_NN_LEVEL(var0, var1, 3) + +#define DEBUGPRINT_VV(var0, var1) DEBUGPRINT_VV_LEVEL(var0, var1, 1) +#define DEBUGPRINT_VV_2(var0, var1) DEBUGPRINT_VV_LEVEL(var0, var1, 2) +#define DEBUGPRINT_VV_3(var0, var1) DEBUGPRINT_VV_LEVEL(var0, var1, 3) + +#define DEBUGPRINT_SV(var0, var) DEBUGPRINT_SV_LEVEL(var0, var, 1) +#define DEBUGPRINT_SV_2(var0, var) DEBUGPRINT_SV_LEVEL(var0, var, 2) +#define DEBUGPRINT_SV_3(var0, var) DEBUGPRINT_SV_LEVEL(var0, var, 3) + +#define DEBUGPRINT_SX(var0, var) DEBUGPRINT_SX_LEVEL(var0, var, 1) +#define DEBUGPRINT_SX_2(var0, var) DEBUGPRINT_SX_LEVEL(var0, var, 2) +#define DEBUGPRINT_SX_3(var0, var) DEBUGPRINT_SX_LEVEL(var0, var, 3) + +// A: module->fileinfo, B:"filename", +// C: stridx, D:module->fileinfo_isstring, E:true; +#define SET_INFO_PAIR(a, b, c, d, e) \ + a.emplace_back(builder->GetOrCreateStringIndex(b), c); \ + d.emplace_back(e) + +#endif // AST2MPL_INCLUDE_ASTMACROS_H diff --git a/src/hir2mpl/ast_input/clang/lib/ast_type.cpp b/src/hir2mpl/ast_input/clang/lib/ast_type.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a2d3b89ccbbd02852804b38ce7ee4d0fe2f26d98 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/lib/ast_type.cpp @@ -0,0 +1,500 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ast_macros.h" +#include "ast_interface.h" +#include "ast_util.h" +#include "fe_manager.h" +#include "fe_options.h" + +namespace maple { +MIRType *LibAstFile::CvtPrimType(const clang::QualType qualType) const { + clang::QualType srcType = qualType.getCanonicalType(); + if (srcType.isNull()) { + return nullptr; + } + + MIRType *destType = nullptr; + if (llvm::isa(srcType)) { + const auto *builtinType = llvm::cast(srcType); + PrimType primType = CvtPrimType(builtinType->getKind()); + destType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(primType); + } + return destType; +} + +PrimType LibAstFile::CvtPrimType(const clang::BuiltinType::Kind kind) const { + switch (kind) { + case clang::BuiltinType::Bool: + return PTY_u1; + case clang::BuiltinType::Char_U: + return FEOptions::GetInstance().IsUseSignedChar() ? PTY_i8 : PTY_u8; + case clang::BuiltinType::UChar: + return PTY_u8; + case clang::BuiltinType::WChar_U: + return FEOptions::GetInstance().IsUseSignedChar() ? PTY_i16 : PTY_u16; + case clang::BuiltinType::UShort: + return PTY_u16; + case clang::BuiltinType::UInt: + return PTY_u32; + case clang::BuiltinType::ULong: +#if ILP32 + return PTY_u32; +#else + return PTY_u64; +#endif + case clang::BuiltinType::ULongLong: + return PTY_u64; + case clang::BuiltinType::UInt128: + return PTY_u128; + case clang::BuiltinType::Char_S: + case clang::BuiltinType::SChar: + return PTY_i8; + case clang::BuiltinType::WChar_S: + case clang::BuiltinType::Short: + case clang::BuiltinType::Char16: + return PTY_i16; + case clang::BuiltinType::Char32: + case clang::BuiltinType::Int: + return PTY_i32; + case clang::BuiltinType::Long: +#if ILP32 + return PTY_i32; +#else + return PTY_i64; +#endif + case clang::BuiltinType::LongLong: + return PTY_i64; + case clang::BuiltinType::Int128: + return PTY_i128; + case clang::BuiltinType::Float: + return PTY_f32; + case clang::BuiltinType::Double: + case clang::BuiltinType::LongDouble: + return PTY_f64; + case clang::BuiltinType::Float128: + return PTY_f64; + case clang::BuiltinType::NullPtr: // default 64-bit, need to update + return PTY_a64; + case clang::BuiltinType::Half: // PTY_f16, NOTYETHANDLED + case clang::BuiltinType::Float16: + CHECK_FATAL(false, "Float16 types not implemented yet"); + return PTY_void; + case clang::BuiltinType::Void: + default: + return PTY_void; + } +} + +bool LibAstFile::TypeHasMayAlias(const clang::QualType srcType) { + auto *td = srcType->getAsTagDecl(); + if (td != nullptr && td->hasAttr()) { + return true; + } + + clang::QualType qualType = srcType; + while (auto *tt = qualType->getAs()) { + if (tt->getDecl()->hasAttr()) { + return true; + } + qualType = tt->desugar(); + } + + return false; +} + +MIRType *LibAstFile::CvtType(const clang::QualType qualType) { + clang::QualType srcType = qualType.getCanonicalType(); + if (srcType.isNull()) { + return nullptr; + } + + MIRType *destType = CvtPrimType(srcType); + if (destType != nullptr) { + return destType; + } + + // handle pointer types + const clang::QualType srcPteType = srcType->getPointeeType(); + if (!srcPteType.isNull()) { + MIRType *mirPointeeType = CvtType(srcPteType); + if (mirPointeeType == nullptr) { + return nullptr; + } + TypeAttrs attrs; + // Get alignment from the pointee type + uint32 alignmentBits = astContext->getTypeAlignIfKnown(srcPteType); + if (alignmentBits) { + if (alignmentBits > astContext->getTypeUnadjustedAlign(srcPteType)) { + attrs.SetAlign(alignmentBits / 8); + } + } + if (IsOneElementVector(srcPteType)) { + attrs.SetAttr(ATTR_oneelem_simd); + } + + // Currently, only the pointer type is needed to handle may alias. + // The input parameter must be the raw pointee type. + if (TypeHasMayAlias(qualType->getPointeeType())) { + attrs.SetAttr(ATTR_may_alias); + } + + MIRPtrType *prtType; + if (attrs == TypeAttrs()) { + prtType = static_cast(GlobalTables::GetTypeTable().GetOrCreatePointerType(*mirPointeeType)); + } else { + prtType = static_cast( + GlobalTables::GetTypeTable().GetOrCreatePointerType(*mirPointeeType, PTY_ptr, attrs)); + } + return prtType; + } + + return CvtOtherType(srcType); +} + +MIRType *LibAstFile::CvtOtherType(const clang::QualType srcType) { + MIRType *destType = nullptr; + if (srcType->isArrayType()) { + destType = CvtArrayType(srcType); + } else if (srcType->isRecordType()) { + destType = CvtRecordType(srcType); + // isComplexType() does not include complex integers (a GCC extension) + } else if (srcType->isAnyComplexType()) { + destType = CvtComplexType(srcType); + } else if (srcType->isFunctionType()) { + destType = CvtFunctionType(srcType); + } else if (srcType->isEnumeralType()) { + const clang::EnumType *enumTy = llvm::dyn_cast(srcType); + clang::QualType qt = enumTy->getDecl()->getIntegerType(); + destType = CvtType(qt); + } else if (srcType->isAtomicType()) { + const auto *atomicType = llvm::cast(srcType); + destType = CvtType(atomicType->getValueType()); + } else if (srcType->isVectorType()) { + destType = CvtVectorType(srcType); + } + CHECK_NULL_FATAL(destType); + return destType; +} + +MIRType *LibAstFile::CvtRecordType(const clang::QualType srcType) { + const auto *recordType = llvm::cast(srcType); + clang::RecordDecl *recordDecl = recordType->getDecl(); + if (!recordDecl->isLambda() && recordDeclSet.emplace(recordDecl).second == true) { + auto itor = std::find(recordDecles.begin(), recordDecles.end(), recordDecl); + if (itor == recordDecles.end()) { + recordDecles.emplace_back(recordDecl); + } + } + MIRStructType *type = nullptr; + std::stringstream ss; + EmitTypeName(srcType, ss); + std::string name(ss.str()); + if (!ASTUtil::IsValidName(name)) { + uint32_t id = recordType->getDecl()->getLocation().getRawEncoding(); + name = GetOrCreateMappedUnnamedName(id); + } else if (FEOptions::GetInstance().GetFuncInlineSize() != 0) { + std::string recordLayoutStr = recordDecl->getDefinition() == nullptr ? "" : + ASTUtil::GetRecordLayoutString(astContext->getASTRecordLayout(recordDecl->getDefinition())); + std::string filename = astContext->getSourceManager().getFilename(recordDecl->getLocation()).str(); + name = name + FEUtils::GetFileNameHashStr(filename + recordLayoutStr); + } + type = FEManager::GetTypeManager().GetOrCreateStructType(name); + type->SetMIRTypeKind(srcType->isUnionType() ? kTypeUnion : kTypeStruct); + if(recordDecl->getDefinition() == nullptr) { + type->SetMIRTypeKind(kTypeStructIncomplete); + } + return recordDecl->isLambda() ? GlobalTables::GetTypeTable().GetOrCreatePointerType(*type) : type; +} + +MIRType *LibAstFile::CvtArrayType(const clang::QualType srcType) { + MIRType *elemType = nullptr; + TypeAttrs elemAttrs; + std::vector operands; + uint8_t dim = 0; + if (srcType->isConstantArrayType()) { + CollectBaseEltTypeAndSizesFromConstArrayDecl(srcType, elemType, elemAttrs, operands); + ASSERT(operands.size() < kMaxArrayDim, "The max array dimension is kMaxArrayDim"); + dim = static_cast(operands.size()); + } else if (srcType->isIncompleteArrayType()) { + const auto *arrayType = llvm::cast(srcType); + CollectBaseEltTypeAndSizesFromConstArrayDecl(arrayType->getElementType(), elemType, elemAttrs, operands); + dim = static_cast(operands.size()); + ASSERT(operands.size() < kMaxArrayDim, "The max array dimension is kMaxArrayDim"); + } else if (srcType->isVariableArrayType()) { + CollectBaseEltTypeAndDimFromVariaArrayDecl(srcType, elemType, elemAttrs, dim); + } else if (srcType->isDependentSizedArrayType()) { + CollectBaseEltTypeAndDimFromDependentSizedArrayDecl(srcType, elemType, elemAttrs, operands); + dim = static_cast(operands.size()); + } else { + NOTYETHANDLED(srcType.getAsString().c_str()); + } + uint32_t *sizeArray = nullptr; + uint32_t tempSizeArray[kMaxArrayDim]; + MIRType *retType = nullptr; + if (dim > 0) { + if (!srcType->isVariableArrayType()) { + for (uint8_t k = 0; k < dim; ++k) { + tempSizeArray[k] = operands[k]; + } + sizeArray = tempSizeArray; + } + retType = GlobalTables::GetTypeTable().GetOrCreateArrayType(*elemType, dim, sizeArray, elemAttrs); + } else { + bool asFlag = srcType->isIncompleteArrayType(); + CHECK_FATAL(asFlag, "Incomplete Array Type"); + retType = elemType; + } + + if (srcType->isIncompleteArrayType()) { + // For an incomplete array type, assume a length of 1. If enable MIRFarrayType, delete ATTR_incomplete_array + elemAttrs.SetAttr(ATTR_incomplete_array); + retType = GlobalTables::GetTypeTable().GetOrCreateArrayType(*retType, 1, elemAttrs); + } + return retType; +} + +MIRType *LibAstFile::CvtComplexType(const clang::QualType srcType) { + clang::QualType srcElemType = llvm::cast(srcType)->getElementType(); + MIRType *destElemType = CvtPrimType(srcElemType); + CHECK_NULL_FATAL(destElemType); + return FEManager::GetTypeManager().GetOrCreateComplexStructType(*destElemType); +} + +MIRType *LibAstFile::CvtFunctionType(const clang::QualType srcType) { + const auto *funcType = llvm::cast(srcType); + MIRType *retType = CvtType(funcType->getReturnType()); + std::vector argsVec; + std::vector attrsVec; + if (srcType->isFunctionProtoType()) { + const auto *funcProtoType = llvm::cast(srcType); + using ItType = clang::FunctionProtoType::param_type_iterator; + for (ItType it = funcProtoType->param_type_begin(); it != funcProtoType->param_type_end(); ++it) { + clang::QualType protoQualType = *it; + argsVec.push_back(CvtType(protoQualType)->GetTypeIndex()); + GenericAttrs genAttrs; + // collect storage class, access, and qual attributes + // ASTCompiler::GetSClassAttrs(SC_Auto, genAttrs); -- no-op + // ASTCompiler::GetAccessAttrs(genAttrs); -- no-op for params + GetCVRAttrs(protoQualType.getCVRQualifiers(), genAttrs); + if (IsOneElementVector(protoQualType)) { + genAttrs.SetAttr(GENATTR_oneelem_simd); + } + attrsVec.push_back(genAttrs.ConvertToTypeAttrs()); + } + } + MIRType *mirFuncType = GlobalTables::GetTypeTable().GetOrCreateFunctionType( + retType->GetTypeIndex(), argsVec, attrsVec); + return GlobalTables::GetTypeTable().GetOrCreatePointerType(*mirFuncType); +} + + +void LibAstFile::CollectBaseEltTypeAndSizesFromConstArrayDecl(const clang::QualType &currQualType, MIRType *&elemType, + TypeAttrs &elemAttr, std::vector &operands) { + const clang::Type *ptrType = currQualType.getTypePtrOrNull(); + ASSERT(ptrType != nullptr, "Null type", currQualType.getAsString().c_str()); + if (ptrType->isArrayType()) { + bool asFlag = ptrType->isConstantArrayType(); + ASSERT(asFlag, "Must be a ConstantArrayType", currQualType.getAsString().c_str()); + const auto *constArrayType = llvm::cast(ptrType); + ASSERT(constArrayType != nullptr, "ERROR : null pointer!"); + llvm::APInt size = constArrayType->getSize(); + asFlag = size.getSExtValue() >= 0; + ASSERT(asFlag, "Array Size must be positive or zero", currQualType.getAsString().c_str()); + operands.push_back(size.getSExtValue()); + CollectBaseEltTypeAndSizesFromConstArrayDecl(constArrayType->getElementType(), elemType, elemAttr, operands); + } else { + elemType = CvtType(currQualType); + // Get alignment from the element type + uint32 alignmentBits = astContext->getTypeAlignIfKnown(currQualType); + if (alignmentBits) { + if (alignmentBits > astContext->getTypeUnadjustedAlign(currQualType)) { + elemAttr.SetAlign(alignmentBits / 8); + } + } + if (IsOneElementVector(currQualType)) { + elemAttr.SetAttr(ATTR_oneelem_simd); + } + } +} + +void LibAstFile::CollectBaseEltTypeAndDimFromVariaArrayDecl(const clang::QualType &currQualType, MIRType *&elemType, + TypeAttrs &elemAttr, uint8_t &dim) { + const clang::Type *ptrType = currQualType.getTypePtrOrNull(); + ASSERT(ptrType != nullptr, "Null type", currQualType.getAsString().c_str()); + if (ptrType->isArrayType()) { + const auto *arrayType = llvm::cast(ptrType); + CollectBaseEltTypeAndDimFromVariaArrayDecl(arrayType->getElementType(), elemType, elemAttr, dim); + ++dim; + } else { + elemType = CvtType(currQualType); + // Get alignment from the element type + uint32 alignmentBits = astContext->getTypeAlignIfKnown(currQualType); + if (alignmentBits) { + if (alignmentBits > astContext->getTypeUnadjustedAlign(currQualType)) { + elemAttr.SetAlign(alignmentBits / 8); + } + } + if (IsOneElementVector(currQualType)) { + elemAttr.SetAttr(ATTR_oneelem_simd); + } + } +} + +void LibAstFile::CollectBaseEltTypeAndDimFromDependentSizedArrayDecl( + const clang::QualType currQualType, MIRType *&elemType, TypeAttrs &elemAttr, std::vector &operands) { + const clang::Type *ptrType = currQualType.getTypePtrOrNull(); + ASSERT(ptrType != nullptr, "ERROR:null pointer!"); + if (ptrType->isArrayType()) { + const auto *arrayType = llvm::dyn_cast(ptrType); + ASSERT(arrayType != nullptr, "ERROR:null pointer!"); + // variable sized + operands.push_back(0); + CollectBaseEltTypeAndDimFromDependentSizedArrayDecl(arrayType->getElementType(), elemType, elemAttr, operands); + } else { + elemType = CvtType(currQualType); + // Get alignment from the element type + uint32 alignmentBits = astContext->getTypeAlignIfKnown(currQualType); + if (alignmentBits) { + if (alignmentBits > astContext->getTypeUnadjustedAlign(currQualType)) { + elemAttr.SetAlign(alignmentBits / 8); + } + } + if (IsOneElementVector(currQualType)) { + elemAttr.SetAttr(ATTR_oneelem_simd); + } + } +} + +MIRType *LibAstFile::CvtVectorType(const clang::QualType srcType) { + const auto *vectorType = llvm::cast(srcType); + MIRType *elemType = CvtType(vectorType->getElementType()); + unsigned numElems = vectorType->getNumElements(); + MIRType *destType = nullptr; + switch (elemType->GetPrimType()) { + case PTY_i64: + if (numElems == 1) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_i64); + } else if (numElems == 2) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v2i64); + } else { + CHECK_FATAL(false, "Unsupported vector type"); + } + break; + case PTY_i32: + if (numElems == 1) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_i64); + } else if (numElems == 2) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v2i32); + } else if (numElems == 4) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v4i32); + } else if (numElems == 8) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v8i16); + } else if (numElems == 16) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v16i8); + } else { + CHECK_FATAL(false, "Unsupported vector type"); + } + break; + case PTY_i16: + if (numElems == 4) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v4i16); + } else if (numElems == 8) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v8i16); + } else { + CHECK_FATAL(false, "Unsupported vector type"); + } + break; + case PTY_i8: + if (numElems == 8) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v8i8); + } else if (numElems == 16) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v16i8); + } else { + CHECK_FATAL(false, "Unsupported vector type"); + } + break; + case PTY_u64: + if (numElems == 1) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_u64); + } else if (numElems == 2) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v2u64); + } else { + CHECK_FATAL(false, "Unsupported vector type"); + } + break; + case PTY_u32: + if (numElems == 2) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v2u32); + } else if (numElems == 4) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v4u32); + } else { + CHECK_FATAL(false, "Unsupported vector type"); + } + break; + case PTY_u16: + if (numElems == 4) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v4u16); + } else if (numElems == 8) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v8u16); + } else { + CHECK_FATAL(false, "Unsupported vector type"); + } + break; + case PTY_u8: + if (numElems == 8) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v8u8); + } else if (numElems == 16) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v16u8); + } else { + CHECK_FATAL(false, "Unsupported vector type"); + } + break; + case PTY_f64: + if (numElems == 1) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_f64); + } else if (numElems == 2) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v2f64); + } else { + CHECK_FATAL(false, "Unsupported vector type"); + } + break; + case PTY_f32: + if (numElems == 2) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v2f32); + } else if (numElems == 4) { + destType = GlobalTables::GetTypeTable().GetPrimType(PTY_v4f32); + } else { + CHECK_FATAL(false, "Unsupported vector type"); + } + break; + default: + CHECK_FATAL(false, "Unsupported vector type"); + break; + } + return destType; +} + +bool LibAstFile::IsOneElementVector(const clang::QualType &qualType) { + return IsOneElementVector(*qualType.getTypePtr()); +} + +bool LibAstFile::IsOneElementVector(const clang::Type &type) { + const clang::VectorType *vectorType = llvm::dyn_cast(type.getUnqualifiedDesugaredType()); + if (vectorType != nullptr && vectorType->getNumElements() == 1) { + return true; + } + return false; +} +} // namespace maple diff --git a/src/hir2mpl/ast_input/clang/lib/ast_util.cpp b/src/hir2mpl/ast_input/clang/lib/ast_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..007eab98cadbd9c4c7096f42a15a65bb0e9b99fb --- /dev/null +++ b/src/hir2mpl/ast_input/clang/lib/ast_util.cpp @@ -0,0 +1,342 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "ast_util.h" +#include "clang/AST/AST.h" +#include "clang/Serialization/ASTDeserializationListener.h" +#include "mir_nodes.h" +#include "mir_builder.h" +#include "ast_macros.h" +#include "fe_utils_ast.h" + +namespace maple { +int ast2mplDebug = 0; +int ast2mplDebugIndent = 0; +uint32_t ast2mplOption = kCheckAssertion; +const char *checkFuncName = nullptr; + +void ASTUtil::AdjIndent(int n) { + ast2mplDebugIndent += n; +} + +void ASTUtil::SetIndent(int n) { + ast2mplDebugIndent = n; +} + +bool ASTUtil::ValidInName(char c) { + return isalnum(c) || (c == '_' || c == '|' || c == ';' || c == '/' || c == '$'); +} + +bool ASTUtil::IsValidName(const std::string &name) { + for (size_t i = 0; i < name.length(); ++i) { + if (!ValidInName(name[i])) { + return false; + } + } + return true; +} + +bool ASTUtil::IsSignedType(const MIRType &type) { + PrimType primType = type.GetPrimType(); + if (primType == PTY_i8 || primType == PTY_i16 || primType == PTY_i32 || primType == PTY_i64) { + return true; + } + return false; +} + +void ASTUtil::AdjustName(std::string &name) { + for (size_t i = 0; name[i] != '\0'; ++i) { + char c = name[i]; + if (ASTUtil::ValidInName(c)) { + name[i] = c; + continue; + } + switch (c) { + case '(': + case ')': + case '<': + case '>': + case '-': + case ' ': + name[i] = '_'; + break; + case '[': + name[i] = 'A'; + break; + case ']': + name[i] = 'B'; + break; + default: + name[i] = '$'; + break; + } + } +} + +std::string ASTUtil::GetAdjustVarName(const std::string &name, uint32_t &num) { + std::stringstream ss; + ss << name << "." << num; + + DEBUGPRINT2(ss.str()); + ++num; + return ss.str(); +} + +std::string ASTUtil::GetNameWithSuffix(const std::string &origName, const std::string &suffix) { + std::stringstream ss; + ss << origName << suffix; + + return ss.str(); +} + +Opcode ASTUtil::CvtBinaryOpcode(uint32_t opcode, PrimType pty) { + switch (opcode) { + case clang::BO_Mul: + return OP_mul; // "*" + case clang::BO_Div: + return OP_div; // "/" + case clang::BO_Rem: + return OP_rem; // "%" + case clang::BO_Add: + return OP_add; // "+" + case clang::BO_Sub: + return OP_sub; // "-" + case clang::BO_Shl: + return OP_shl; // "<<" + case clang::BO_Shr: + return IsUnsignedInteger(pty) ? OP_lshr : OP_ashr; // ">>" + case clang::BO_LT: + return OP_lt; // "<" + case clang::BO_GT: + return OP_gt; // ">" + case clang::BO_LE: + return OP_le; // "<=" + case clang::BO_GE: + return OP_ge; // ">=" + case clang::BO_EQ: + return OP_eq; // "==" + case clang::BO_NE: + return OP_ne; // "!=" + case clang::BO_And: + return OP_band; // "&" + case clang::BO_Xor: + return OP_bxor; // "^" + case clang::BO_Or: + return OP_bior; // "|" + case clang::BO_LAnd: + return OP_cand; // "&&" + case clang::BO_LOr: + return OP_cior; // "||" + default: + return OP_undef; + } +} + +// these do not have equivalent opcode in mapleir +Opcode ASTUtil::CvtBinaryAssignOpcode(uint32_t opcode) { + switch (opcode) { + case clang::BO_Assign: + return OP_eq; // "=" + case clang::BO_MulAssign: + return OP_mul; // "*=" + case clang::BO_DivAssign: + return OP_div; // "/=" + case clang::BO_RemAssign: + return OP_rem; // "%=" + case clang::BO_AddAssign: + return OP_add; // "+=" + case clang::BO_SubAssign: + return OP_sub; // "-=" + case clang::BO_ShlAssign: + return OP_shl; // "<<=" + case clang::BO_ShrAssign: + return OP_lshr; // ">>=" + case clang::BO_AndAssign: + return OP_band; // "&=" + case clang::BO_XorAssign: + return OP_bxor; // "^=" + case clang::BO_OrAssign: + return OP_bior; // "|=" + case clang::BO_Comma: + return OP_undef; // "," + case clang::BO_PtrMemD: + return OP_undef; // ".*" + case clang::BO_PtrMemI: + return OP_undef; // "->*" + default: + return OP_undef; + } +} + +Opcode ASTUtil::CvtUnaryOpcode(uint32_t opcode) { + switch (opcode) { + case clang::UO_Minus: + return OP_neg; // "-" + case clang::UO_Not: + return OP_bnot; // "~" + case clang::UO_LNot: + return OP_lnot; // "!" + case clang::UO_PostInc: + return OP_add; // "++" + case clang::UO_PostDec: + return OP_sub; // "--" + case clang::UO_PreInc: + return OP_add; // "++" + case clang::UO_PreDec: + return OP_sub; // "--" + case clang::UO_AddrOf: + return OP_addrof; // "&" + case clang::UO_Deref: + return OP_undef; // "*" + case clang::UO_Plus: + return OP_undef; // "+" + case clang::UO_Real: + return OP_undef; // "__real" + case clang::UO_Imag: + return OP_undef; // "__imag" + case clang::UO_Extension: + return OP_undef; // "__extension__" + case clang::UO_Coawait: + return OP_undef; // "co_await" + default: + CHECK_FATAL(false, "NYI ASTUtil::CvtUnaryOpcode", opcode); + } +} + +uint32 ASTUtil::GetDim(MIRType &type) { + MIRType *ptrType = &type; + if (type.GetKind() == kTypePointer) { + auto *ptr = static_cast(&type); + ptrType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptr->GetPointedTyIdx()); + } + uint32 dim = 0; + while (ptrType->GetKind() == kTypeArray) { + auto *array = static_cast(ptrType); + ptrType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(array->GetElemTyIdx()); + if (ptrType->GetKind() == kTypePointer) { + auto *ptr = static_cast(ptrType); + ptrType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptr->GetPointedTyIdx()); + } + ++dim; + } + + DEBUGPRINT2(dim); + return dim; +} + +std::string ASTUtil::GetTypeString(MIRType &type) { + std::stringstream ss; + if (ast2mplDebug > kDebugLevelThree) { + type.Dump(1); + } + switch (type.GetKind()) { + case kTypeScalar: + ss << FEUtilAST::Type2Label(type.GetPrimType()); + break; + case kTypeStruct: + case kTypeClass: + case kTypeInterface: + case kTypeBitField: + case kTypeByName: + case kTypeParam: { + ss << GlobalTables::GetStrTable().GetStringFromStrIdx(type.GetNameStrIdx()).c_str() << ";"; + break; + } + case kTypeArray: { + auto &array = static_cast(type); + MIRType *elemType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(array.GetElemTyIdx()); + uint32 dim = GetDim(type); + for (size_t i = 0; i < dim; ++i) { + ss << 'A'; + } + ss << GetTypeString(*elemType); + break; + } + case kTypePointer: { + auto &ptr = static_cast(type); + MIRType *pType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptr.GetPointedTyIdx()); + ss << "P"; + std::string str = GetTypeString(*pType); + ss << str; + break; + } + default: + break; + } + + return ss.str(); +} + +void ASTUtil::DumpMplTypes() { + uint32 size = static_cast(GlobalTables::GetTypeTable().GetTypeTableSize()); + DEBUGPRINT(size); + DEBUGPRINT_S(" dump type table "); + for (uint32 i = 1; i < size; ++i) { + MIRType *type = GlobalTables::GetTypeTable().GetTypeTable()[i]; + std::string name = GlobalTables::GetStrTable().GetStringFromStrIdx(type->GetNameStrIdx()); + (void)printf("%-4u %4u %s\n", i, type->GetNameStrIdx().GetIdx(), name.c_str()); + } + DEBUGPRINT_S(" end dump type table "); +} + +void ASTUtil::DumpMplStrings() { + size_t size = GlobalTables::GetStrTable().StringTableSize(); + DEBUGPRINT(size); + DEBUGPRINT_S(" dump string table "); + for (size_t i = 1; i < size; ++i) { + MIRType *type = GlobalTables::GetTypeTable().GetTypeTable()[i]; + const std::string &str = GlobalTables::GetStrTable().GetStringFromStrIdx(type->GetNameStrIdx()); + (void)printf("%-4d %4d %s\n", static_cast(i), static_cast(str.length()), str.c_str()); + } + DEBUGPRINT_S(" end dump string table "); +} + +bool ASTUtil::IsVoidPointerType(const TyIdx &tyIdx) { + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + auto *ptr = static_cast(type); + type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptr->GetPointedTyIdx()); + if (type->GetPrimType() == PTY_void) { + return true; + } + return false; +} + +std::string ASTUtil::AdjustFuncName(std::string funcName) { + std::size_t found = funcName.find('\"'); + const std::size_t offsetByTwoChar = 2; // skip the replaced char + while (found != std::string::npos) { + (void)funcName.replace(found, 1, "\\\""); + found += offsetByTwoChar; + found = funcName.find('\"', found); + } + return funcName; +} + +bool ASTUtil::InsertFuncSet(const GStrIdx &idx) { + static std::set funcIdxSet; + return funcIdxSet.insert(idx).second; +} + +std::string ASTUtil::GetRecordLayoutString(const clang::ASTRecordLayout &recordLayout) { + std::string recordLayoutStr = ""; + unsigned int fieldCount = recordLayout.getFieldCount(); + uint64_t recordSize = static_cast(recordLayout.getSize().getQuantity()); + recordLayoutStr += (std::to_string(fieldCount) + std::to_string(recordSize)); + for (unsigned int i = 0; i < fieldCount; ++i) { + recordLayoutStr += std::to_string(recordLayout.getFieldOffset(i)); + } + return recordLayoutStr; +} +} // namespace maple diff --git a/src/hir2mpl/ast_input/clang/lib/ast_util.h b/src/hir2mpl/ast_input/clang/lib/ast_util.h new file mode 100644 index 0000000000000000000000000000000000000000..40d151685e565473691e3291f034043a7f246ab2 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/lib/ast_util.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef AST2MPL_INCLUDE_ASTUTIL_H +#define AST2MPL_INCLUDE_ASTUTIL_H +#include "clang/AST/AST.h" +#include "clang/AST/RecordLayout.h" +#include "mir_type.h" +#include "ast_macros.h" + +namespace maple { +extern int ast2mplDebug; +extern int ast2mplDebugIndent; +extern uint32_t ast2mplOption; +extern const char *checkFuncName; + +class ASTUtil { + public: + static const int opcodeNameLength = 228; + static const char *opcodeName[opcodeNameLength]; + static void AdjIndent(int n); + static void SetIndent(int n); + static bool ValidInName(char c); + static bool IsValidName(const std::string &name); + static bool IsSignedType(const MIRType &type); + static void AdjustName(std::string &name); + static std::string GetAdjustVarName(const std::string &name, uint32_t &num); + static std::string GetNameWithSuffix(const std::string &origName, const std::string &suffix); + + static void DumpMplStrings(); + static void DumpMplTypes(); + + static uint32 GetDim(MIRType &type); + static std::string GetTypeString(MIRType &type); + + static MIRType *CvtPrimType(const clang::QualType type); + static Opcode CvtUnaryOpcode(uint32_t opcode); + static Opcode CvtBinaryOpcode(uint32_t opcode, PrimType pty = PTY_begin); + static Opcode CvtBinaryAssignOpcode(uint32_t opcode); + + static bool IsVoidPointerType(const TyIdx &tyIdx); + static std::string AdjustFuncName(std::string funcName); + static bool InsertFuncSet(const GStrIdx &idx); + + template + static std::string Join(const Range &elements, const char *delimiter) { + std::ostringstream os; + auto b = begin(elements); + auto e = end(elements); + if (b != e) { + std::copy(b, prev(e), std::ostream_iterator(os, delimiter)); + b = prev(e); + } + if (b != e) { + os << *b; + } + return os.str(); + } + static std::string GetRecordLayoutString(const clang::ASTRecordLayout &recordLayout); +}; +} // namespace maple +#endif // AST2MPL_INCLUDE_ASTUTIL_H_ diff --git a/src/hir2mpl/ast_input/clang/lib/sys/arm_neon.h b/src/hir2mpl/ast_input/clang/lib/sys/arm_neon.h new file mode 100644 index 0000000000000000000000000000000000000000..4e213d0a4bff117e62b3b2ab47f4b83e12fef39d --- /dev/null +++ b/src/hir2mpl/ast_input/clang/lib/sys/arm_neon.h @@ -0,0 +1,1398 @@ +/*===---- arm_neon.h - ARM Neon intrinsics ---------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __ARM_NEON_H +#define __ARM_NEON_H + +#include + +typedef float float32_t; +#ifdef __aarch64__ +typedef double float64_t; +#endif + +typedef __attribute__((neon_vector_type(8))) int8_t int8x8_t; +typedef __attribute__((neon_vector_type(16))) int8_t int8x16_t; +typedef __attribute__((neon_vector_type(4))) int16_t int16x4_t; +typedef __attribute__((neon_vector_type(8))) int16_t int16x8_t; +typedef __attribute__((neon_vector_type(2))) int32_t int32x2_t; +typedef __attribute__((neon_vector_type(4))) int32_t int32x4_t; +typedef __attribute__((neon_vector_type(1))) int64_t int64x1_t; +typedef __attribute__((neon_vector_type(2))) int64_t int64x2_t; +typedef __attribute__((neon_vector_type(8))) uint8_t uint8x8_t; +typedef __attribute__((neon_vector_type(16))) uint8_t uint8x16_t; +typedef __attribute__((neon_vector_type(4))) uint16_t uint16x4_t; +typedef __attribute__((neon_vector_type(8))) uint16_t uint16x8_t; +typedef __attribute__((neon_vector_type(2))) uint32_t uint32x2_t; +typedef __attribute__((neon_vector_type(4))) uint32_t uint32x4_t; +typedef __attribute__((neon_vector_type(1))) uint64_t uint64x1_t; +typedef __attribute__((neon_vector_type(2))) uint64_t uint64x2_t; +typedef __attribute__((neon_vector_type(2))) float32_t float32x2_t; +typedef __attribute__((neon_vector_type(4))) float32_t float32x4_t; +#ifdef __aarch64__ +typedef __attribute__((neon_vector_type(1))) float64_t float64x1_t; +typedef __attribute__((neon_vector_type(2))) float64_t float64x2_t; +#endif + +typedef struct int8x8x2_t { + int8x8_t val[2]; +} int8x8x2_t; + +typedef struct int16x4x2_t { + int16x4_t val[2]; +} int16x4x2_t; + +typedef struct int32x2x2_t { + int32x2_t val[2]; +} int32x2x2_t; + +typedef struct uint8x8x2_t { + uint8x8_t val[2]; +} uint8x8x2_t; + +typedef struct uint16x4x2_t { + uint16x4_t val[2]; +} uint16x4x2_t; + +typedef struct uint32x2x2_t { + uint32x2_t val[2]; +} uint32x2x2_t; + +typedef struct float32x2x2_t { + float32x2_t val[2]; +} float32x2x2_t; + +// vecTy vector_abs(vecTy src) +// Create a vector by getting the absolute value of the elements in src. +int8x8_t __builtin_mpl_vector_abs_v8i8(int8x8_t); +int16x4_t __builtin_mpl_vector_abs_v4i16(int16x4_t); +int32x2_t __builtin_mpl_vector_abs_v2i32(int32x2_t); +int64x1_t __builtin_mpl_vector_abs_v1i64(int64x1_t); +float32x2_t __builtin_mpl_vector_abs_v2f32(float32x2_t); +float64x1_t __builtin_mpl_vector_abs_v1f64(float64x1_t); +int8x16_t __builtin_mpl_vector_abs_v16i8(int8x16_t); +int16x8_t __builtin_mpl_vector_abs_v8i16(int16x8_t); +int32x4_t __builtin_mpl_vector_abs_v4i32(int32x4_t); +int64x2_t __builtin_mpl_vector_abs_v2i64(int64x2_t); +float32x4_t __builtin_mpl_vector_abs_v4f32(float32x4_t); +float64x2_t __builtin_mpl_vector_abs_v2f64(float64x2_t); + +// vecTy vector_addl_low(vecTy src1, vecTy src2) +// Add each element of the source vector to second source +// widen the result into the destination vector. +int16x8_t __builtin_mpl_vector_addl_low_v8i8(int8x8_t, int8x8_t); +int32x4_t __builtin_mpl_vector_addl_low_v4i16(int16x4_t, int16x4_t); +int64x2_t __builtin_mpl_vector_addl_low_v2i32(int32x2_t, int32x2_t); +uint16x8_t __builtin_mpl_vector_addl_low_v8u8(uint8x8_t, uint8x8_t); +uint32x4_t __builtin_mpl_vector_addl_low_v4u16(uint16x4_t, uint16x4_t); +uint64x2_t __builtin_mpl_vector_addl_low_v2u32(uint32x2_t, uint32x2_t); + +// vecTy vector_addl_high(vecTy src1, vecTy src2) +// Add each element of the source vector to upper half of second source +// widen the result into the destination vector. +int16x8_t __builtin_mpl_vector_addl_high_v8i8(int8x16_t, int8x16_t); +int32x4_t __builtin_mpl_vector_addl_high_v4i16(int16x8_t, int16x8_t); +int64x2_t __builtin_mpl_vector_addl_high_v2i32(int32x4_t, int32x4_t); +uint16x8_t __builtin_mpl_vector_addl_high_v8u8(uint8x16_t, uint8x16_t); +uint32x4_t __builtin_mpl_vector_addl_high_v4u16(uint16x8_t, uint16x8_t); +uint64x2_t __builtin_mpl_vector_addl_high_v2u32(uint32x4_t, uint32x4_t); + +// vecTy vector_addw_low(vecTy src1, vecTy src2) +// Add each element of the source vector to second source +// widen the result into the destination vector. +int16x8_t __builtin_mpl_vector_addw_low_v8i8(int16x8_t, int8x8_t); +int32x4_t __builtin_mpl_vector_addw_low_v4i16(int32x4_t, int16x4_t); +int64x2_t __builtin_mpl_vector_addw_low_v2i32(int64x2_t, int32x2_t); +uint16x8_t __builtin_mpl_vector_addw_low_v8u8(uint16x8_t, uint8x8_t); +uint32x4_t __builtin_mpl_vector_addw_low_v4u16(uint32x4_t, uint16x4_t); +uint64x2_t __builtin_mpl_vector_addw_low_v2u32(uint64x2_t, uint32x2_t); + +// vecTy vector_addw_high(vecTy src1, vecTy src2) +// Add each element of the source vector to upper half of second source +// widen the result into the destination vector. +int16x8_t __builtin_mpl_vector_addw_high_v8i8(int16x8_t, int8x16_t); +int32x4_t __builtin_mpl_vector_addw_high_v4i16(int32x4_t, int16x8_t); +int64x2_t __builtin_mpl_vector_addw_high_v2i32(int64x2_t, int32x4_t); +uint16x8_t __builtin_mpl_vector_addw_high_v8u8(uint16x8_t, uint8x16_t); +uint32x4_t __builtin_mpl_vector_addw_high_v4u16(uint32x4_t, uint16x8_t); +uint64x2_t __builtin_mpl_vector_addw_high_v2u32(uint64x2_t, uint32x4_t); + +// vectTy vector_from_scalar(scalarTy val) +// Create a vector by replicating the scalar value to all elements of the +// vector. +int64x2_t __builtin_mpl_vector_from_scalar_v2i64(int64_t); +int32x4_t __builtin_mpl_vector_from_scalar_v4i32(int32_t); +int16x8_t __builtin_mpl_vector_from_scalar_v8i16(int16_t); +int8x16_t __builtin_mpl_vector_from_scalar_v16i8(int8_t); +uint64x2_t __builtin_mpl_vector_from_scalar_v2u64(uint64_t); +uint32x4_t __builtin_mpl_vector_from_scalar_v4u32(uint32_t); +uint16x8_t __builtin_mpl_vector_from_scalar_v8u16(uint16_t); +uint8x16_t __builtin_mpl_vector_from_scalar_v16u8(uint8_t); +float64x2_t __builtin_mpl_vector_from_scalar_v2f64(float64_t); +float32x4_t __builtin_mpl_vector_from_scalar_v4f32(float32_t); +int64x1_t __builtin_mpl_vector_from_scalar_v1i64(int64_t); +int32x2_t __builtin_mpl_vector_from_scalar_v2i32(int32_t); +int16x4_t __builtin_mpl_vector_from_scalar_v4i16(int16_t); +int8x8_t __builtin_mpl_vector_from_scalar_v8i8(int8_t); +uint64x1_t __builtin_mpl_vector_from_scalar_v1u64(uint64_t); +uint32x2_t __builtin_mpl_vector_from_scalar_v2u32(uint32_t); +uint16x4_t __builtin_mpl_vector_from_scalar_v4u16(uint16_t); +uint8x8_t __builtin_mpl_vector_from_scalar_v8u8(uint8_t); +float64x1_t __builtin_mpl_vector_from_scalar_v1f64(float64_t); +float32x2_t __builtin_mpl_vector_from_scalar_v2f32(float32_t); + +// vecTy2 vector_madd(vecTy2 accum, vecTy1 src1, vecTy1 src2) +// Multiply the elements of src1 and src2, then accumulate into accum. +// Elements of vecTy2 are twice as long as elements of vecTy1. +int64x2_t __builtin_mpl_vector_madd_v2i32(int64x2_t, int32x2_t, int32x2_t); +int32x4_t __builtin_mpl_vector_madd_v4i16(int32x4_t, int16x4_t, int16x4_t); +int16x8_t __builtin_mpl_vector_madd_v8i8(int16x8_t, int8x8_t, int8x8_t); +uint64x2_t __builtin_mpl_vector_madd_v2u32(uint64x2_t, uint32x2_t, uint32x2_t); +uint32x4_t __builtin_mpl_vector_madd_v4u16(uint32x4_t, uint16x4_t, uint16x4_t); +uint16x8_t __builtin_mpl_vector_madd_v8u8(uint16x8_t, uint8x8_t, uint8x8_t); + +// vecTy2 vector_mull_low(vecTy1 src1, vecTy1 src2) +// Multiply the elements of src1 and src2. Elements of vecTy2 are twice as +// long as elements of vecTy1. +int64x2_t __builtin_mpl_vector_mull_low_v2i32(int32x2_t, int32x2_t); +int32x4_t __builtin_mpl_vector_mull_low_v4i16(int16x4_t, int16x4_t); +int16x8_t __builtin_mpl_vector_mull_low_v8i8(int8x8_t, int8x8_t); +uint64x2_t __builtin_mpl_vector_mull_low_v2u32(uint32x2_t, uint32x2_t); +uint32x4_t __builtin_mpl_vector_mull_low_v4u16(uint16x4_t, uint16x4_t); +uint16x8_t __builtin_mpl_vector_mull_low_v8u8(uint8x8_t, uint8x8_t); + +// vecTy2 vector_mull_high(vecTy1 src1, vecTy1 src2) +// Multiply the upper elements of src1 and src2. Elements of vecTy2 are twice +// as long as elements of vecTy1. +int64x2_t __builtin_mpl_vector_mull_high_v2i32(int32x4_t, int32x4_t); +int32x4_t __builtin_mpl_vector_mull_high_v4i16(int16x8_t, int16x8_t); +int16x8_t __builtin_mpl_vector_mull_high_v8i8(int8x16_t, int8x16_t); +uint64x2_t __builtin_mpl_vector_mull_high_v2u32(uint32x4_t, uint32x4_t); +uint32x4_t __builtin_mpl_vector_mull_high_v4u16(uint16x8_t, uint16x8_t); +uint16x8_t __builtin_mpl_vector_mull_high_v8u8(uint8x16_t, uint8x16_t); + +// vecTy vector_merge(vecTy src1, vecTy src2, int n) +// Create a vector by concatenating the high elements of src1, starting +// with the nth element, followed by the low elements of src2. +int64x2_t __builtin_mpl_vector_merge_v2i64(int64x2_t, int64x2_t, int32_t); +int32x4_t __builtin_mpl_vector_merge_v4i32(int32x4_t, int32x4_t, int32_t); +int16x8_t __builtin_mpl_vector_merge_v8i16(int16x8_t, int16x8_t, int32_t); +int8x16_t __builtin_mpl_vector_merge_v16i8(int8x16_t, int8x16_t, int32_t); +uint64x2_t __builtin_mpl_vector_merge_v2u64(uint64x2_t, uint64x2_t, int32_t); +uint32x4_t __builtin_mpl_vector_merge_v4u32(uint32x4_t, uint32x4_t, int32_t); +uint16x8_t __builtin_mpl_vector_merge_v8u16(uint16x8_t, uint16x8_t, int32_t); +uint8x16_t __builtin_mpl_vector_merge_v16u8(uint8x16_t, uint8x16_t, int32_t); +float64x2_t __builtin_mpl_vector_merge_v2f64(float64x2_t, float64x2_t, int32_t); +float32x4_t __builtin_mpl_vector_merge_v4f32(float32x4_t, float32x4_t, int32_t); +int64x1_t __builtin_mpl_vector_merge_v1i64(int64x1_t, int64x1_t, int32_t); +int32x2_t __builtin_mpl_vector_merge_v2i32(int32x2_t, int32x2_t, int32_t); +int16x4_t __builtin_mpl_vector_merge_v4i16(int16x4_t, int16x4_t, int32_t); +int8x8_t __builtin_mpl_vector_merge_v8i8(int8x8_t, int8x8_t, int32_t); +uint64x1_t __builtin_mpl_vector_merge_v1u64(uint64x1_t, uint64x1_t, int32_t); +uint32x2_t __builtin_mpl_vector_merge_v2u32(uint32x2_t, uint32x2_t, int32_t); +uint16x4_t __builtin_mpl_vector_merge_v4u16(uint16x4_t, uint16x4_t, int32_t); +uint8x8_t __builtin_mpl_vector_merge_v8u8(uint8x8_t, uint8x8_t, int32_t); +float64x1_t __builtin_mpl_vector_merge_v1f64(float64x1_t, float64x1_t, int32_t); +float32x2_t __builtin_mpl_vector_merge_v2f32(float32x2_t, float32x2_t, int32_t); + +// vecTy2 vector_get_low(vecTy1 src) +// Create a vector from the low part of the source vector. +int64x1_t __builtin_mpl_vector_get_low_v2i64(int64x2_t); +int32x2_t __builtin_mpl_vector_get_low_v4i32(int32x4_t); +int16x4_t __builtin_mpl_vector_get_low_v8i16(int16x8_t); +int8x8_t __builtin_mpl_vector_get_low_v16i8(int8x16_t); +uint64x1_t __builtin_mpl_vector_get_low_v2u64(uint64x2_t); +uint32x2_t __builtin_mpl_vector_get_low_v4u32(uint32x4_t); +uint16x4_t __builtin_mpl_vector_get_low_v8u16(uint16x8_t); +uint8x8_t __builtin_mpl_vector_get_low_v16u8(uint8x16_t); +float64x1_t __builtin_mpl_vector_get_low_v2f64(float64x2_t); +float32x2_t __builtin_mpl_vector_get_low_v4f32(float32x4_t); + +// vecTy2 vector_get_high(vecTy1 src) +// Create a vector from the high part of the source vector. +int64x1_t __builtin_mpl_vector_get_high_v2i64(int64x2_t); +int32x2_t __builtin_mpl_vector_get_high_v4i32(int32x4_t); +int16x4_t __builtin_mpl_vector_get_high_v8i16(int16x8_t); +int8x8_t __builtin_mpl_vector_get_high_v16i8(int8x16_t); +uint64x1_t __builtin_mpl_vector_get_high_v2u64(uint64x2_t); +uint32x2_t __builtin_mpl_vector_get_high_v4u32(uint32x4_t); +uint16x4_t __builtin_mpl_vector_get_high_v8u16(uint16x8_t); +uint8x8_t __builtin_mpl_vector_get_high_v16u8(uint8x16_t); +float64x1_t __builtin_mpl_vector_get_high_v2f64(float64x2_t); +float32x2_t __builtin_mpl_vector_get_high_v4f32(float32x4_t); + +// scalarTy vector_get_element(vecTy src, int n) +// Get the nth element of the source vector. +int64_t __builtin_mpl_vector_get_element_v2i64(int64x2_t, int32_t); +int32_t __builtin_mpl_vector_get_element_v4i32(int32x4_t, int32_t); +int16_t __builtin_mpl_vector_get_element_v8i16(int16x8_t, int32_t); +int8_t __builtin_mpl_vector_get_element_v16i8(int8x16_t, int32_t); +uint64_t __builtin_mpl_vector_get_element_v2u64(uint64x2_t, int32_t); +uint32_t __builtin_mpl_vector_get_element_v4u32(uint32x4_t, int32_t); +uint16_t __builtin_mpl_vector_get_element_v8u16(uint16x8_t, int32_t); +uint8_t __builtin_mpl_vector_get_element_v16u8(uint8x16_t, int32_t); +float64_t __builtin_mpl_vector_get_element_v2f64(float64x2_t, int32_t); +float32_t __builtin_mpl_vector_get_element_v4f32(float32x4_t, int32_t); +int64_t __builtin_mpl_vector_get_element_v1i64(int64x1_t, int32_t); +int32_t __builtin_mpl_vector_get_element_v2i32(int32x2_t, int32_t); +int16_t __builtin_mpl_vector_get_element_v4i16(int16x4_t, int32_t); +int8_t __builtin_mpl_vector_get_element_v8i8(int8x8_t, int32_t); +uint64_t __builtin_mpl_vector_get_element_v1u64(uint64x1_t, int32_t); +uint32_t __builtin_mpl_vector_get_element_v2u32(uint32x2_t, int32_t); +uint16_t __builtin_mpl_vector_get_element_v4u16(uint16x4_t, int32_t); +uint8_t __builtin_mpl_vector_get_element_v8u8(uint8x8_t, int32_t); +float64_t __builtin_mpl_vector_get_element_v1f64(float64x1_t, int32_t); +float32_t __builtin_mpl_vector_get_element_v2f32(float32x2_t, int32_t); + +// vecTy vector_set_element(ScalarTy value, VecTy vec, int n) +// Set the nth element of the source vector to value. +int64x2_t __builtin_mpl_vector_set_element_v2i64(int64_t, int64x2_t, int32_t); +int32x4_t __builtin_mpl_vector_set_element_v4i32(int32_t, int32x4_t, int32_t); +int16x8_t __builtin_mpl_vector_set_element_v8i16(int16_t, int16x8_t, int32_t); +int8x16_t __builtin_mpl_vector_set_element_v16i8(int8_t, int8x16_t, int32_t); +uint64x2_t __builtin_mpl_vector_set_element_v2u64(uint64_t, uint64x2_t, + int32_t); +uint32x4_t __builtin_mpl_vector_set_element_v4u32(uint32_t, uint32x4_t, + int32_t); +uint16x8_t __builtin_mpl_vector_set_element_v8u16(uint16_t, uint16x8_t, + int32_t); +uint8x16_t __builtin_mpl_vector_set_element_v16u8(uint8_t, uint8x16_t, int32_t); +float64x2_t __builtin_mpl_vector_set_element_v2f64(float64_t, float64x2_t, + int32_t); +float32x4_t __builtin_mpl_vector_set_element_v4f32(float32_t, float32x4_t, + int32_t); +int64x1_t __builtin_mpl_vector_set_element_v1i64(int64_t, int64x1_t, int32_t); +int32x2_t __builtin_mpl_vector_set_element_v2i32(int32_t, int32x2_t, int32_t); +int16x4_t __builtin_mpl_vector_set_element_v4i16(int16_t, int16x4_t, int32_t); +int8x8_t __builtin_mpl_vector_set_element_v8i8(int8_t, int8x8_t, int32_t); +uint64x1_t __builtin_mpl_vector_set_element_v1u64(uint64_t, uint64x1_t, + int32_t); +uint32x2_t __builtin_mpl_vector_set_element_v2u32(uint32_t, uint32x2_t, + int32_t); +uint16x4_t __builtin_mpl_vector_set_element_v4u16(uint16_t, uint16x4_t, + int32_t); +uint8x8_t __builtin_mpl_vector_set_element_v8u8(uint8_t, uint8x8_t, int32_t); +float64x1_t __builtin_mpl_vector_set_element_v1f64(float64_t, float64x1_t, + int32_t); +float32x2_t __builtin_mpl_vector_set_element_v2f32(float32_t, float32x2_t, + int32_t); + +// vecTy2 vector_abdl(vectTy1 src2, vectTy2 src2) +// Create a widened vector by getting the abs value of subtracted arguments. +int16x8_t __builtin_mpl_vector_labssub_low_v8i8(int8x8_t, int8x8_t); +int32x4_t __builtin_mpl_vector_labssub_low_v4i16(int16x4_t, int16x4_t); +int64x2_t __builtin_mpl_vector_labssub_low_v2i32(int32x2_t, int32x2_t); +uint16x8_t __builtin_mpl_vector_labssub_low_v8u8(uint8x8_t, uint8x8_t); +uint32x4_t __builtin_mpl_vector_labssub_low_v4u16(uint16x4_t, uint16x4_t); +uint64x2_t __builtin_mpl_vector_labssub_low_v2u32(uint32x2_t, uint32x2_t); + +// vecTy2 vector_abdl_high(vectTy1 src2, vectTy2 src2) +// Create a widened vector by getting the abs value of subtracted high arguments. +int16x8_t __builtin_mpl_vector_labssub_high_v8i8(int8x16_t, int8x16_t); +int32x4_t __builtin_mpl_vector_labssub_high_v4i16(int16x8_t, int16x8_t); +int64x2_t __builtin_mpl_vector_labssub_high_v2i32(int32x4_t, int32x4_t); +uint16x8_t __builtin_mpl_vector_labssub_high_v8u8(uint8x16_t, uint8x16_t); +uint32x4_t __builtin_mpl_vector_labssub_high_v4u16(uint16x8_t, uint16x8_t); +uint64x2_t __builtin_mpl_vector_labssub_high_v2u32(uint32x4_t, uint32x4_t); + +// vecTy2 vector_narrow_low(vecTy1 src) +// Narrow each element of the source vector to half of the original width, +// writing the lower half into the destination vector. +int32x2_t __builtin_mpl_vector_narrow_low_v2i64(int64x2_t); +int16x4_t __builtin_mpl_vector_narrow_low_v4i32(int32x4_t); +int8x8_t __builtin_mpl_vector_narrow_low_v8i16(int16x8_t); +uint32x2_t __builtin_mpl_vector_narrow_low_v2u64(uint64x2_t); +uint16x4_t __builtin_mpl_vector_narrow_low_v4u32(uint32x4_t); +uint8x8_t __builtin_mpl_vector_narrow_low_v8u16(uint16x8_t); + +// vecTy2 vector_narrow_high(vecTy1 src1, vecTy2 src2) +// Narrow each element of the source vector to half of the original width, +// concatenate the upper half into the destination vector. +int32x4_t __builtin_mpl_vector_narrow_high_v2i64(int32x2_t, int64x2_t); +int16x8_t __builtin_mpl_vector_narrow_high_v4i32(int16x4_t, int32x4_t); +int8x16_t __builtin_mpl_vector_narrow_high_v8i16(int8x8_t, int16x8_t); +uint32x4_t __builtin_mpl_vector_narrow_high_v2u64(uint32x2_t, uint64x2_t); +uint16x8_t __builtin_mpl_vector_narrow_high_v4u32(uint16x4_t, uint32x4_t); +uint8x16_t __builtin_mpl_vector_narrow_high_v8u16(uint8x8_t, uint16x8_t); + +// vecTy1 vector_adapl(vecTy1 src1, vecTy2 src2) +// Vector pairwise addition and accumulate +int16x4_t __builtin_mpl_vector_pairwise_adalp_v8i8(int16x4_t, int8x8_t); +int32x2_t __builtin_mpl_vector_pairwise_adalp_v4i16(int32x2_t, int16x4_t); +int64x1_t __builtin_mpl_vector_pairwise_adalp_v2i32(int64x1_t, int32x2_t); +uint16x4_t __builtin_mpl_vector_pairwise_adalp_v8u8(uint16x4_t, uint8x8_t); +uint32x2_t __builtin_mpl_vector_pairwise_adalp_v4u16(uint32x2_t, uint16x4_t); +uint64x1_t __builtin_mpl_vector_pairwise_adalp_v2u32(uint64x1_t, uint32x2_t); +int16x8_t __builtin_mpl_vector_pairwise_adalp_v16i8(int16x8_t, int8x16_t); +int32x4_t __builtin_mpl_vector_pairwise_adalp_v8i16(int32x4_t, int16x8_t); +int64x2_t __builtin_mpl_vector_pairwise_adalp_v4i32(int64x2_t, int32x4_t); +uint16x8_t __builtin_mpl_vector_pairwise_adalp_v16u8(uint16x8_t, uint8x16_t); +uint32x4_t __builtin_mpl_vector_pairwise_adalp_v8u16(uint32x4_t, uint16x8_t); +uint64x2_t __builtin_mpl_vector_pairwise_adalp_v4u32(uint64x2_t, uint32x4_t); + +// vecTy2 vector_pairwise_add(vecTy1 src) +// Add pairs of elements from the source vector and put the result into the +// destination vector, whose element size is twice and the number of +// elements is half of the source vector type. +int64x2_t __builtin_mpl_vector_pairwise_add_v4i32(int32x4_t); +int32x4_t __builtin_mpl_vector_pairwise_add_v8i16(int16x8_t); +int16x8_t __builtin_mpl_vector_pairwise_add_v16i8(int8x16_t); +uint64x2_t __builtin_mpl_vector_pairwise_add_v4u32(uint32x4_t); +uint32x4_t __builtin_mpl_vector_pairwise_add_v8u16(uint16x8_t); +uint16x8_t __builtin_mpl_vector_pairwise_add_v16u8(uint8x16_t); +int64x1_t __builtin_mpl_vector_pairwise_add_v2i32(int32x2_t); +int32x2_t __builtin_mpl_vector_pairwise_add_v4i16(int16x4_t); +int16x4_t __builtin_mpl_vector_pairwise_add_v8i8(int8x8_t); +uint64x1_t __builtin_mpl_vector_pairwise_add_v2u32(uint32x2_t); +uint32x2_t __builtin_mpl_vector_pairwise_add_v4u16(uint16x4_t); +uint16x4_t __builtin_mpl_vector_pairwise_add_v8u8(uint8x8_t); + +// vecTy vector_reverse(vecTy src) +// Create a vector by reversing the order of the elements in src. +int64x2_t __builtin_mpl_vector_reverse_v2i64(int64x2_t); +int32x4_t __builtin_mpl_vector_reverse_v4i32(int32x4_t); +int16x8_t __builtin_mpl_vector_reverse_v8i16(int16x8_t); +int8x16_t __builtin_mpl_vector_reverse_v16i8(int8x16_t); +uint64x2_t __builtin_mpl_vector_reverse_v2u64(uint64x2_t); +uint32x4_t __builtin_mpl_vector_reverse_v4u32(uint32x4_t); +uint16x8_t __builtin_mpl_vector_reverse_v8u16(uint16x8_t); +uint8x16_t __builtin_mpl_vector_reverse_v16u8(uint8x16_t); +float64x2_t __builtin_mpl_vector_reverse_v2f64(float64x2_t); +float32x4_t __builtin_mpl_vector_reverse_v4f32(float32x4_t); +int64x1_t __builtin_mpl_vector_reverse_v1i64(int64x1_t); +int32x2_t __builtin_mpl_vector_reverse_v2i32(int32x2_t); +int16x4_t __builtin_mpl_vector_reverse_v4i16(int16x4_t); +int8x8_t __builtin_mpl_vector_reverse_v8i8(int8x8_t); +uint64x1_t __builtin_mpl_vector_reverse_v1u64(uint64x1_t); +uint32x2_t __builtin_mpl_vector_reverse_v2u32(uint32x2_t); +uint16x4_t __builtin_mpl_vector_reverse_v4u16(uint16x4_t); +uint8x8_t __builtin_mpl_vector_reverse_v8u8(uint8x8_t); +float64x1_t __builtin_mpl_vector_reverse_v1f64(float64x1_t); +float32x2_t __builtin_mpl_vector_reverse_v2f32(float32x2_t); + +// vecTy vector_shli(vecTy src, const int n) +// Shift each element in the vector left by n. +int64x2_t __builtin_mpl_vector_shli_v2i64(int64x2_t, const int); +int32x4_t __builtin_mpl_vector_shli_v4i32(int32x4_t, const int); +int16x8_t __builtin_mpl_vector_shli_v8i16(int16x8_t, const int); +int8x16_t __builtin_mpl_vector_shli_v16i8(int8x16_t, const int); +uint64x2_t __builtin_mpl_vector_shli_v2u64(uint64x2_t, const int); +uint32x4_t __builtin_mpl_vector_shli_v4u32(uint32x4_t, const int); +uint16x8_t __builtin_mpl_vector_shli_v8u16(uint16x8_t, const int); +uint8x16_t __builtin_mpl_vector_shli_v16u8(uint8x16_t, const int); +int64x1_t __builtin_mpl_vector_shli_v1i64(int64x1_t, const int); +int32x2_t __builtin_mpl_vector_shli_v2i32(int32x2_t, const int); +int16x4_t __builtin_mpl_vector_shli_v4i16(int16x4_t, const int); +int8x8_t __builtin_mpl_vector_shli_v8i8(int8x8_t, const int); +uint64x1_t __builtin_mpl_vector_shli_v1u64(uint64x1_t, const int); +uint32x2_t __builtin_mpl_vector_shli_v2u32(uint32x2_t, const int); +uint16x4_t __builtin_mpl_vector_shli_v4u16(uint16x4_t, const int); +uint8x8_t __builtin_mpl_vector_shli_v8u8(uint8x8_t, const int); + +// vecTy vector_shri(vecTy src, const int n) +// Shift each element in the vector right by n. +int64x2_t __builtin_mpl_vector_shri_v2i64(int64x2_t, const int); +int32x4_t __builtin_mpl_vector_shri_v4i32(int32x4_t, const int); +int16x8_t __builtin_mpl_vector_shri_v8i16(int16x8_t, const int); +int8x16_t __builtin_mpl_vector_shri_v16i8(int8x16_t, const int); +uint64x2_t __builtin_mpl_vector_shru_v2u64(uint64x2_t, const int); +uint32x4_t __builtin_mpl_vector_shru_v4u32(uint32x4_t, const int); +uint16x8_t __builtin_mpl_vector_shru_v8u16(uint16x8_t, const int); +uint8x16_t __builtin_mpl_vector_shru_v16u8(uint8x16_t, const int); +int64x1_t __builtin_mpl_vector_shri_v1i64(int64x1_t, const int); +int32x2_t __builtin_mpl_vector_shri_v2i32(int32x2_t, const int); +int16x4_t __builtin_mpl_vector_shri_v4i16(int16x4_t, const int); +int8x8_t __builtin_mpl_vector_shri_v8i8(int8x8_t, const int); +uint64x1_t __builtin_mpl_vector_shru_v1u64(uint64x1_t, const int); +uint32x2_t __builtin_mpl_vector_shru_v2u32(uint32x2_t, const int); +uint16x4_t __builtin_mpl_vector_shru_v4u16(uint16x4_t, const int); +uint8x8_t __builtin_mpl_vector_shru_v8u8(uint8x8_t, const int); + +// vecTy2 vector_shift_narrow_low(vecTy1 src, const int n) +// Shift each element in the vector right by n, narrow each element to half +// of the original width (truncating), then write the result to the lower +// half of the destination vector. +int32x2_t __builtin_mpl_vector_shr_narrow_low_v2i64(int64x2_t, const int); +int16x4_t __builtin_mpl_vector_shr_narrow_low_v4i32(int32x4_t, const int); +int8x8_t __builtin_mpl_vector_shr_narrow_low_v8i16(int16x8_t, const int); +uint32x2_t __builtin_mpl_vector_shr_narrow_low_v2u64(uint64x2_t, const int); +uint16x4_t __builtin_mpl_vector_shr_narrow_low_v4u32(uint32x4_t, const int); +uint8x8_t __builtin_mpl_vector_shr_narrow_low_v8u16(uint16x8_t, const int); + +// scalarTy vector_sum(vecTy src) +// Sum all of the elements in the vector into a scalar. +int64_t __builtin_mpl_vector_sum_v2i64(int64x2_t); +int32_t __builtin_mpl_vector_sum_v4i32(int32x4_t); +int16_t __builtin_mpl_vector_sum_v8i16(int16x8_t); +int8_t __builtin_mpl_vector_sum_v16i8(int8x16_t); +uint64_t __builtin_mpl_vector_sum_v2u64(uint64x2_t); +uint32_t __builtin_mpl_vector_sum_v4u32(uint32x4_t); +uint16_t __builtin_mpl_vector_sum_v8u16(uint16x8_t); +uint8_t __builtin_mpl_vector_sum_v16u8(uint8x16_t); +float64_t __builtin_mpl_vector_sum_v2f64(float64x2_t); +float32_t __builtin_mpl_vector_sum_v4f32(float32x4_t); +int32_t __builtin_mpl_vector_sum_v2i32(int32x2_t); +int16_t __builtin_mpl_vector_sum_v4i16(int16x4_t); +int8_t __builtin_mpl_vector_sum_v8i8(int8x8_t); +uint32_t __builtin_mpl_vector_sum_v2u32(uint32x2_t); +uint16_t __builtin_mpl_vector_sum_v4u16(uint16x4_t); +uint8_t __builtin_mpl_vector_sum_v8u8(uint8x8_t); +float32_t __builtin_mpl_vector_sum_v2f32(float32x2_t); + +// vecTy table_lookup(vecTy tbl, vecTy idx) +// Performs a table vector lookup. +int64x2_t __builtin_mpl_vector_table_lookup_v2i64(int64x2_t, int64x2_t); +int32x4_t __builtin_mpl_vector_table_lookup_v4i32(int32x4_t, int32x4_t); +int16x8_t __builtin_mpl_vector_table_lookup_v8i16(int16x8_t, int16x8_t); +int8x16_t __builtin_mpl_vector_table_lookup_v16i8(int8x16_t, int8x16_t); +uint64x2_t __builtin_mpl_vector_table_lookup_v2u64(uint64x2_t, uint64x2_t); +uint32x4_t __builtin_mpl_vector_table_lookup_v4u32(uint32x4_t, uint32x4_t); +uint16x8_t __builtin_mpl_vector_table_lookup_v8u16(uint16x8_t, uint16x8_t); +uint8x16_t __builtin_mpl_vector_table_lookup_v16u8(uint8x16_t, uint8x16_t); +float64x2_t __builtin_mpl_vector_table_lookup_v2f64(float64x2_t, float64x2_t); +float32x4_t __builtin_mpl_vector_table_lookup_v4f32(float32x4_t, float32x4_t); +int64x1_t __builtin_mpl_vector_table_lookup_v1i64(int64x1_t, int64x1_t); +int32x2_t __builtin_mpl_vector_table_lookup_v2i32(int32x2_t, int32x2_t); +int16x4_t __builtin_mpl_vector_table_lookup_v4i16(int16x4_t, int16x4_t); +int8x8_t __builtin_mpl_vector_table_lookup_v8i8(int8x8_t, int8x8_t); +uint64x1_t __builtin_mpl_vector_table_lookup_v1u64(uint64x1_t, uint64x1_t); +uint32x2_t __builtin_mpl_vector_table_lookup_v2u32(uint32x2_t, uint32x2_t); +uint16x4_t __builtin_mpl_vector_table_lookup_v4u16(uint16x4_t, uint16x4_t); +uint8x8_t __builtin_mpl_vector_table_lookup_v8u8(uint8x8_t, uint8x8_t); +float64x1_t __builtin_mpl_vector_table_lookup_v1f64(float64x1_t, float64x1_t); +float32x2_t __builtin_mpl_vector_table_lookup_v2f32(float32x2_t, float32x2_t); + +// vecTy2 vector_widen_low(vecTy1 src) +// Widen each element of the source vector to half of the original width, +// writing the lower half into the destination vector. +int64x2_t __builtin_mpl_vector_widen_low_v2i32(int32x2_t); +int32x4_t __builtin_mpl_vector_widen_low_v4i16(int16x4_t); +int16x8_t __builtin_mpl_vector_widen_low_v8i8(int8x8_t); +uint64x2_t __builtin_mpl_vector_widen_low_v2u32(uint32x2_t); +uint32x4_t __builtin_mpl_vector_widen_low_v4u16(uint16x4_t); +uint16x8_t __builtin_mpl_vector_widen_low_v8u8(uint8x8_t); + +// vecTy2 vector_widen_high(vecTy1 src) +// Widen each element of the source vector to half of the original width, +// writing the higher half into the destination vector. +int64x2_t __builtin_mpl_vector_widen_high_v2i32(int32x4_t); +int32x4_t __builtin_mpl_vector_widen_high_v4i16(int16x8_t); +int16x8_t __builtin_mpl_vector_widen_high_v8i8(int8x16_t); +uint64x2_t __builtin_mpl_vector_widen_high_v2u32(uint32x4_t); +uint32x4_t __builtin_mpl_vector_widen_high_v4u16(uint16x8_t); +uint16x8_t __builtin_mpl_vector_widen_high_v8u8(uint8x16_t); + +// vecArrTy vector_zip(vecTy a, vecTy b) +// Interleave the upper half of elements from a and b into the destination +// vector. +int32x2x2_t __builtin_mpl_vector_zip_v2i32(int32x2_t, int32x2_t); +int16x4x2_t __builtin_mpl_vector_zip_v4i16(int16x4_t, int16x4_t); +int8x8x2_t __builtin_mpl_vector_zip_v8i8(int8x8_t, int8x8_t); +uint32x2x2_t __builtin_mpl_vector_zip_v2u32(uint32x2_t, uint32x2_t); +uint16x4x2_t __builtin_mpl_vector_zip_v4u16(uint16x4_t, uint16x4_t); +uint8x8x2_t __builtin_mpl_vector_zip_v8u8(uint8x8_t, uint8x8_t); +float32x2x2_t __builtin_mpl_vector_zip_v2f32(float32x2_t, float32x2_t); + +// vecTy vector_load(scalarTy *ptr) +// Load the elements pointed to by ptr into a vector. +int64x2_t __builtin_mpl_vector_load_v2i64(int64_t *); +int32x4_t __builtin_mpl_vector_load_v4i32(int32_t *); +int16x8_t __builtin_mpl_vector_load_v8i16(int16_t *); +int8x16_t __builtin_mpl_vector_load_v16i8(int8_t *); +uint64x2_t __builtin_mpl_vector_load_v2u64(uint64_t *); +uint32x4_t __builtin_mpl_vector_load_v4u32(uint32_t *); +uint16x8_t __builtin_mpl_vector_load_v8u16(uint16_t *); +uint8x16_t __builtin_mpl_vector_load_v16u8(uint8_t *); +float64x2_t __builtin_mpl_vector_load_v2f64(float64_t *); +float32x4_t __builtin_mpl_vector_load_v4f32(float32_t *); +int64x1_t __builtin_mpl_vector_load_v1i64(int64_t *); +int32x2_t __builtin_mpl_vector_load_v2i32(int32_t *); +int16x4_t __builtin_mpl_vector_load_v4i16(int16_t *); +int8x8_t __builtin_mpl_vector_load_v8i8(int8_t *); +uint64x1_t __builtin_mpl_vector_load_v1u64(uint64_t *); +uint32x2_t __builtin_mpl_vector_load_v2u32(uint32_t *); +uint16x4_t __builtin_mpl_vector_load_v4u16(uint16_t *); +uint8x8_t __builtin_mpl_vector_load_v8u8(uint8_t *); +float64x1_t __builtin_mpl_vector_load_v1f64(float64_t *); +float32x2_t __builtin_mpl_vector_load_v2f32(float32_t *); + +// void vector_store(scalarTy *ptr, vecTy src) +// Store the elements from src into the memory pointed to by ptr. +void __builtin_mpl_vector_store_v2i64(int64_t *, int64x2_t); +void __builtin_mpl_vector_store_v4i32(int32_t *, int32x4_t); +void __builtin_mpl_vector_store_v8i16(int16_t *, int16x8_t); +void __builtin_mpl_vector_store_v16i8(int8_t *, int8x16_t); +void __builtin_mpl_vector_store_v2u64(uint64_t *, uint64x2_t); +void __builtin_mpl_vector_store_v4u32(uint32_t *, uint32x4_t); +void __builtin_mpl_vector_store_v8u16(uint16_t *, uint16x8_t); +void __builtin_mpl_vector_store_v16u8(uint8_t *, uint8x16_t); +void __builtin_mpl_vector_store_v2f64(float64_t *, float64x2_t); +void __builtin_mpl_vector_store_v4f32(float32_t *, float32x4_t); +void __builtin_mpl_vector_store_v1i64(int64_t *, int64x1_t); +void __builtin_mpl_vector_store_v2i32(int32_t *, int32x2_t); +void __builtin_mpl_vector_store_v4i16(int16_t *, int16x4_t); +void __builtin_mpl_vector_store_v8i8(int8_t *, int8x8_t); +void __builtin_mpl_vector_store_v1u64(uint64_t *, uint64x1_t); +void __builtin_mpl_vector_store_v2u32(uint32_t *, uint32x2_t); +void __builtin_mpl_vector_store_v4u16(uint16_t *, uint16x4_t); +void __builtin_mpl_vector_store_v8u8(uint8_t *, uint8x8_t); +void __builtin_mpl_vector_store_v1f64(float64_t *, float64x1_t); +void __builtin_mpl_vector_store_v2f32(float32_t *, float32x2_t); + +// vecTy vector_subl_low(vecTy src1, vecTy src2) +// Subtract each element of the source vector to second source +// widen the result into the destination vector. +int16x8_t __builtin_mpl_vector_subl_low_v8i8(int8x8_t, int8x8_t); +int32x4_t __builtin_mpl_vector_subl_low_v4i16(int16x4_t, int16x4_t); +int64x2_t __builtin_mpl_vector_subl_low_v2i32(int32x2_t, int32x2_t); +uint16x8_t __builtin_mpl_vector_subl_low_v8u8(uint8x8_t, uint8x8_t); +uint32x4_t __builtin_mpl_vector_subl_low_v4u16(uint16x4_t, uint16x4_t); +uint64x2_t __builtin_mpl_vector_subl_low_v2u32(uint32x2_t, uint32x2_t); + +// vecTy vector_subl_high(vecTy src1, vecTy src2) +// Subtract each element of the source vector to upper half of second source +// widen the result into the destination vector. +int16x8_t __builtin_mpl_vector_subl_high_v8i8(int8x16_t, int8x16_t); +int32x4_t __builtin_mpl_vector_subl_high_v4i16(int16x8_t, int16x8_t); +int64x2_t __builtin_mpl_vector_subl_high_v2i32(int32x4_t, int32x4_t); +uint16x8_t __builtin_mpl_vector_subl_high_v8u8(uint8x16_t, uint8x16_t); +uint32x4_t __builtin_mpl_vector_subl_high_v4u16(uint16x8_t, uint16x8_t); +uint64x2_t __builtin_mpl_vector_subl_high_v2u32(uint32x4_t, uint32x4_t); + +// vecTy vector_subw_low(vecTy src1, vecTy src2) +// Subtract each element of the source vector to second source +// widen the result into the destination vector. +int16x8_t __builtin_mpl_vector_subw_low_v8i8(int16x8_t, int8x8_t); +int32x4_t __builtin_mpl_vector_subw_low_v4i16(int32x4_t, int16x4_t); +int64x2_t __builtin_mpl_vector_subw_low_v2i32(int64x2_t, int32x2_t); +uint16x8_t __builtin_mpl_vector_subw_low_v8u8(uint16x8_t, uint8x8_t); +uint32x4_t __builtin_mpl_vector_subw_low_v4u16(uint32x4_t, uint16x4_t); +uint64x2_t __builtin_mpl_vector_subw_low_v2u32(uint64x2_t, uint32x2_t); + +// vecTy vector_subw_high(vecTy src1, vecTy src2) +// Subtract each element of the source vector to upper half of second source +// widen the result into the destination vector. +int16x8_t __builtin_mpl_vector_subw_high_v8i8(int16x8_t, int8x16_t); +int32x4_t __builtin_mpl_vector_subw_high_v4i16(int32x4_t, int16x8_t); +int64x2_t __builtin_mpl_vector_subw_high_v2i32(int64x2_t, int32x4_t); +uint16x8_t __builtin_mpl_vector_subw_high_v8u8(uint16x8_t, uint8x16_t); +uint32x4_t __builtin_mpl_vector_subw_high_v4u16(uint32x4_t, uint16x8_t); +uint64x2_t __builtin_mpl_vector_subw_high_v2u32(uint64x2_t, uint32x4_t); + +// ************************* +// Supported Neon Intrinsics +// ************************* + +// vabdl +#define vabdl_s8(a, b) __builtin_mpl_vector_labssub_low_v8i8(a, b); +#define vabdl_s16(a, b) __builtin_mpl_vector_labssub_low_v4i16(a, b); +#define vabdl_s32(a, b) __builtin_mpl_vector_labssub_low_v2i32(a, b); +#define vabdl_u8(a, b) __builtin_mpl_vector_labssub_low_v8u8(a, b); +#define vabdl_u16(a, b) __builtin_mpl_vector_labssub_low_v4u16(a, b); +#define vabdl_u32(a, b) __builtin_mpl_vector_labssub_low_v2u32(a, b); + +// vabdl_high +#define vabdl_high_s8(a, b) __builtin_mpl_vector_labssub_high_v8i8(a, b); +#define vabdl_high_s16(a, b) __builtin_mpl_vector_labssub_high_v4i16(a, b); +#define vabdl_high_s32(a, b) __builtin_mpl_vector_labssub_high_v2i32(a, b); +#define vabdl_high_u8(a, b) __builtin_mpl_vector_labssub_high_v8u8(a, b); +#define vabdl_high_u16(a, b) __builtin_mpl_vector_labssub_high_v4u16(a, b); +#define vabdl_high_u32(a, b) __builtin_mpl_vector_labssub_high_v2u32(a, b); + +// vabs +#define vabs_s8(a) __builtin_mpl_vector_abs_v8i8(a); +#define vabs_s16(a) __builtin_mpl_vector_abs_v4i16(a); +#define vabs_s32(a) __builtin_mpl_vector_abs_v2i32(a); +#define vabs_s64(a) __builtin_mpl_vector_abs_v1i64(a); +#define vabs_f32(a) __builtin_mpl_vector_abs_v2f32(a); +#define vabs_f64(a) __builtin_mpl_vector_abs_v1f64(a); +#define vabsq_s8(a) __builtin_mpl_vector_abs_v16i8(a); +#define vabsq_s16(a) __builtin_mpl_vector_abs_v8i16(a); +#define vabsq_s32(a) __builtin_mpl_vector_abs_v4i32(a); +#define vabsq_s64(a) __builtin_mpl_vector_abs_v2i64(a); +#define vabsq_f32(a) __builtin_mpl_vector_abs_v4f32(a); +#define vabsq_f64(a) __builtin_mpl_vector_abs_v2f64(a); + +// vaddv +#define vaddv_s8(a) __builtin_mpl_vector_sum_v8i8(a) +#define vaddv_s16(a) __builtin_mpl_vector_sum_v4i16(a) +#define vaddv_s32(a) __builtin_mpl_vector_sum_v2i32(a) +#define vaddv_u8 (a) __builtin_mpl_vector_sum_v8u8(a) +#define vaddv_u16(a) __builtin_mpl_vector_sum_v4u16(a) +#define vaddv_u32(a) __builtin_mpl_vector_sum_v2u32(a) +#define vaddv_f32(a) __builtin_mpl_vector_sum_v2f32(a) +#define vaddvq_s8(a) __builtin_mpl_vector_sum_v16i8(a) +#define vaddvq_s16(a) __builtin_mpl_vector_sum_v8i16(a) +#define vaddvq_s32(a) __builtin_mpl_vector_sum_v4i32(a) +#define vaddvq_s64(a) __builtin_mpl_vector_sum_v2i64(a) +#define vaddvq_u8(a) __builtin_mpl_vector_sum_v16u8(a) +#define vaddvq_u16(a) __builtin_mpl_vector_sum_v8u16(a) +#define vaddvq_u32(a) __builtin_mpl_vector_sum_v4u32(a) +#define vaddvq_u64(a) __builtin_mpl_vector_sum_v2u64(a) +#define vaddvq_f32(a) __builtin_mpl_vector_sum_v4f32(a) +#define vaddvq_f64(a) __builtin_mpl_vector_sum_v2f64(a) + +// vaddl +#define vaddl_s8(a, b) __builtin_mpl_vector_addl_low_v8i8(a, b) +#define vaddl_s16(a, b) __builtin_mpl_vector_addl_low_v4i16(a, b) +#define vaddl_s32(a, b) __builtin_mpl_vector_addl_low_v2i32(a, b) +#define vaddl_u8(a, b) __builtin_mpl_vector_addl_low_v8u8(a, b) +#define vaddl_u16(a, b) __builtin_mpl_vector_addl_low_v4u16(a, b) +#define vaddl_u32(a, b) __builtin_mpl_vector_addl_low_v2u32(a, b) + +// vaddl_high +#define vaddl_high_s8(a, b) __builtin_mpl_vector_addl_high_v8i8(a, b) +#define vaddl_high_s16(a, b) __builtin_mpl_vector_addl_high_v4i16(a, b) +#define vaddl_high_s32(a, b) __builtin_mpl_vector_addl_high_v2i32(a, b) +#define vaddl_high_u8(a, b) __builtin_mpl_vector_addl_high_v8u8(a, b) +#define vaddl_high_u16(a, b) __builtin_mpl_vector_addl_high_v4u16(a, b) +#define vaddl_high_u32(a, b) __builtin_mpl_vector_addl_high_v2u32(a, b) + +// vaddw +#define vaddw_s8(a, b) __builtin_mpl_vector_addw_low_v8i8(a, b) +#define vaddw_s16(a, b) __builtin_mpl_vector_addw_low_v4i16(a, b) +#define vaddw_s32(a, b) __builtin_mpl_vector_addw_low_v2i32(a, b) +#define vaddw_u8(a, b) __builtin_mpl_vector_addw_low_v8u8(a, b) +#define vaddw_u16(a, b) __builtin_mpl_vector_addw_low_v4u16(a, b) +#define vaddw_u32(a, b) __builtin_mpl_vector_addw_low_v2u32(a, b) + +// vaddw_high +#define vaddw_high_s8(a, b) __builtin_mpl_vector_addw_high_v8i8(a, b) +#define vaddw_high_s16(a, b) __builtin_mpl_vector_addw_high_v4i16(a, b) +#define vaddw_high_s32(a, b) __builtin_mpl_vector_addw_high_v2i32(a, b) +#define vaddw_high_u8(a, b) __builtin_mpl_vector_addw_high_v8u8(a, b) +#define vaddw_high_u16(a, b) __builtin_mpl_vector_addw_high_v4u16(a, b) +#define vaddw_high_u32(a, b) __builtin_mpl_vector_addw_high_v2u32(a, b) + +// vadd +#define vadd_s8(a, b) (a + b) +#define vadd_s16(a, b) (a + b) +#define vadd_s32(a, b) (a + b) +#define vadd_s64(a, b) (a + b) +#define vadd_u8(a, b) (a + b) +#define vadd_u16(a, b) (a + b) +#define vadd_u32(a, b) (a + b) +#define vadd_u64(a, b) (a + b) +#define vadd_f16(a, b) (a + b) +#define vadd_f32(a, b) (a + b) +#define vadd_f64(a, b) (a + b) +#define vaddq_s8(a, b) (a + b) +#define vaddq_s16(a, b) (a + b) +#define vaddq_s32(a, b) (a + b) +#define vaddq_s64(a, b) (a + b) +#define vaddq_u8(a, b) (a + b) +#define vaddq_u16(a, b) (a + b) +#define vaddq_u32(a, b) (a + b) +#define vaddq_u64(a, b) (a + b) +#define vaddq_f16(a, b) (a + b) +#define vaddq_f32(a, b) (a + b) +#define vaddq_f64(a, b) (a + b) + +// vand +#define vand_s8(a, b) (a & b) +#define vand_s16(a, b) (a & b) +#define vand_s32(a, b) (a & b) +#define vand_s64(a, b) (a & b) +#define vand_u8(a, b) (a & b) +#define vand_u16(a, b) (a & b) +#define vand_u32(a, b) (a & b) +#define vand_u64(a, b) (a & b) +#define vandq_s8(a, b) (a & b) +#define vandq_s16(a, b) (a & b) +#define vandq_s32(a, b) (a & b) +#define vandq_s64(a, b) (a & b) +#define vandq_u8(a, b) (a & b) +#define vandq_u16(a, b) (a & b) +#define vandq_u32(a, b) (a & b) +#define vandq_u64(a, b) (a & b) + +// vdup +#define vdup_n_s8(a) __builtin_mpl_vector_from_scalar_v8i8(a) +#define vdup_n_s16(a) __builtin_mpl_vector_from_scalar_v4i16(a) +#define vdup_n_s32(a) __builtin_mpl_vector_from_scalar_v2i32(a) +#define vdup_n_s64(a) __builtin_mpl_vector_from_scalar_v1i64(a) +#define vdup_n_u8(a) __builtin_mpl_vector_from_scalar_v8u8(a) +#define vdup_n_u16(a) __builtin_mpl_vector_from_scalar_v4u16(a) +#define vdup_n_u32(a) __builtin_mpl_vector_from_scalar_v2u32(a) +#define vdup_n_u64(a) __builtin_mpl_vector_from_scalar_v1u64(a) +#define vdup_n_f16(a) __builtin_mpl_vector_from_scalar_v4f16(a) +#define vdup_n_f32(a) __builtin_mpl_vector_from_scalar_v2f32(a) +#define vdup_n_f64(a) __builtin_mpl_vector_from_scalar_v1f64(a) +#define vdupq_n_s8(a) __builtin_mpl_vector_from_scalar_v16i8(a) +#define vdupq_n_s16(a) __builtin_mpl_vector_from_scalar_v8i16(a) +#define vdupq_n_s32(a) __builtin_mpl_vector_from_scalar_v4i32(a) +#define vdupq_n_s64(a) __builtin_mpl_vector_from_scalar_v2i64(a) +#define vdupq_n_u8(a) __builtin_mpl_vector_from_scalar_v16u8(a) +#define vdupq_n_u16(a) __builtin_mpl_vector_from_scalar_v8u16(a) +#define vdupq_n_u32(a) __builtin_mpl_vector_from_scalar_v4u32(a) +#define vdupq_n_u64(a) __builtin_mpl_vector_from_scalar_v2u64(a) +#define vdupq_n_f16(a) __builtin_mpl_vector_from_scalar_v8f16(a) +#define vdupq_n_f32(a) __builtin_mpl_vector_from_scalar_v4f32(a) +#define vdupq_n_f64(a) __builtin_mpl_vector_from_scalar_v2f64(a) + +// vceq +#define vceq_s8(a, b) (a == b) +#define vceq_s16(a, b) (a == b) +#define vceq_s32(a, b) (a == b) +#define vceq_s64(a, b) (a == b) +#define vceq_u8(a, b) (a == b) +#define vceq_u16(a, b) (a == b) +#define vceq_u32(a, b) (a == b) +#define vceq_u64(a, b) (a == b) +#define vceq_f16(a, b) (a == b) +#define vceq_f32(a, b) (a == b) +#define vceq_f64(a, b) (a == b) +#define vceqq_s8(a, b) (a == b) +#define vceqq_s16(a, b) (a == b) +#define vceqq_s32(a, b) (a == b) +#define vceqq_s64(a, b) (a == b) +#define vceqq_u8(a, b) (a == b) +#define vceqq_u16(a, b) (a == b) +#define vceqq_u32(a, b) (a == b) +#define vceqq_u64(a, b) (a == b) +#define vceqq_f16(a, b) (a == b) +#define vceqq_f32(a, b) (a == b) +#define vceqq_f64(a, b) (a == b) + +// vcgt +#define vcgt_s8(a, b) (a > b) +#define vcgt_s16(a, b) (a > b) +#define vcgt_s32(a, b) (a > b) +#define vcgt_s64(a, b) (a > b) +#define vcgt_u8(a, b) (a > b) +#define vcgt_u16(a, b) (a > b) +#define vcgt_u32(a, b) (a > b) +#define vcgt_u64(a, b) (a > b) +#define vcgt_f16(a, b) (a > b) +#define vcgt_f32(a, b) (a > b) +#define vcgt_f64(a, b) (a > b) +#define vcgtq_s8(a, b) (a > b) +#define vcgtq_s16(a, b) (a > b) +#define vcgtq_s32(a, b) (a > b) +#define vcgtq_s64(a, b) (a > b) +#define vcgtq_u8(a, b) (a > b) +#define vcgtq_u16(a, b) (a > b) +#define vcgtq_u32(a, b) (a > b) +#define vcgtq_u64(a, b) (a > b) +#define vcgtq_f16(a, b) (a > b) +#define vcgtq_f32(a, b) (a > b) +#define vcgtq_f64(a, b) (a > b) + +// vcge +#define vcge_s8(a, b) (a >= b) +#define vcge_s16(a, b) (a >= b) +#define vcge_s32(a, b) (a >= b) +#define vcge_s64(a, b) (a >= b) +#define vcge_u8(a, b) (a >= b) +#define vcge_u16(a, b) (a >= b) +#define vcge_u32(a, b) (a >= b) +#define vcge_u64(a, b) (a >= b) +#define vcge_f16(a, b) (a >= b) +#define vcge_f32(a, b) (a >= b) +#define vcge_f64(a, b) (a >= b) +#define vcgeq_s8(a, b) (a >= b) +#define vcgeq_s16(a, b) (a >= b) +#define vcgeq_s32(a, b) (a >= b) +#define vcgeq_s64(a, b) (a >= b) +#define vcgeq_u8(a, b) (a >= b) +#define vcgeq_u16(a, b) (a >= b) +#define vcgeq_u32(a, b) (a >= b) +#define vcgeq_u64(a, b) (a >= b) +#define vcgeq_f16(a, b) (a >= b) +#define vcgeq_f32(a, b) (a >= b) +#define vcgeq_f64(a, b) (a >= b) + +// vclt +#define vclt_s8(a, b) (a < b) +#define vclt_s16(a, b) (a < b) +#define vclt_s32(a, b) (a < b) +#define vclt_s64(a, b) (a < b) +#define vclt_u8(a, b) (a < b) +#define vclt_u16(a, b) (a < b) +#define vclt_u32(a, b) (a < b) +#define vclt_u64(a, b) (a < b) +#define vclt_f16(a, b) (a < b) +#define vclt_f32(a, b) (a < b) +#define vclt_f64(a, b) (a < b) +#define vcltq_s8(a, b) (a < b) +#define vcltq_s16(a, b) (a < b) +#define vcltq_s32(a, b) (a < b) +#define vcltq_s64(a, b) (a < b) +#define vcltq_u8(a, b) (a < b) +#define vcltq_u16(a, b) (a < b) +#define vcltq_u32(a, b) (a < b) +#define vcltq_u64(a, b) (a < b) +#define vcltq_f16(a, b) (a < b) +#define vcltq_f32(a, b) (a < b) +#define vcltq_f64(a, b) (a < b) + +// vcle +#define vcle_s8(a, b) (a <= b) +#define vcle_s16(a, b) (a <= b) +#define vcle_s32(a, b) (a <= b) +#define vcle_s64(a, b) (a <= b) +#define vcle_u8(a, b) (a <= b) +#define vcle_u16(a, b) (a <= b) +#define vcle_u32(a, b) (a <= b) +#define vcle_u64(a, b) (a <= b) +#define vcle_f16(a, b) (a <= b) +#define vcle_f32(a, b) (a <= b) +#define vcle_f64(a, b) (a <= b) +#define vcleq_s8(a, b) (a <= b) +#define vcleq_s16(a, b) (a <= b) +#define vcleq_s32(a, b) (a <= b) +#define vcleq_s64(a, b) (a <= b) +#define vcleq_u8(a, b) (a <= b) +#define vcleq_u16(a, b) (a <= b) +#define vcleq_u32(a, b) (a <= b) +#define vcleq_u64(a, b) (a <= b) +#define vcleq_f16(a, b) (a <= b) +#define vcleq_f32(a, b) (a <= b) +#define vcleq_f64(a, b) (a <= b) + +// veor +#define veor_s8(a, b) (a ^ b) +#define veor_s16(a, b) (a ^ b) +#define veor_s32(a, b) (a ^ b) +#define veor_s64(a, b) (a ^ b) +#define veor_u8(a, b) (a ^ b) +#define veor_u16(a, b) (a ^ b) +#define veor_u32(a, b) (a ^ b) +#define veor_u64(a, b) (a ^ b) +#define veorq_s8(a, b) (a ^ b) +#define veorq_s16(a, b) (a ^ b) +#define veorq_s32(a, b) (a ^ b) +#define veorq_s64(a, b) (a ^ b) +#define veorq_u8(a, b) (a ^ b) +#define veorq_u16(a, b) (a ^ b) +#define veorq_u32(a, b) (a ^ b) +#define veorq_u64(a, b) (a ^ b) + +// vext +#define vext_s8(a, b, n) __builtin_mpl_vector_merge_v8i8(a, b, n) +#define vext_s16(a, b, n) __builtin_mpl_vector_merge_v4i16(a, b, n) +#define vext_s32(a, b, n) __builtin_mpl_vector_merge_v2i32(a, b, n) +#define vext_s64(a, b, n) __builtin_mpl_vector_merge_v1i64(a, b, n) +#define vext_u8(a, b, n) __builtin_mpl_vector_merge_v8u8(a, b, n) +#define vext_u16(a, b, n) __builtin_mpl_vector_merge_v4u16(a, b, n) +#define vext_u32(a, b, n) __builtin_mpl_vector_merge_v2u32(a, b, n) +#define vext_u64(a, b, n) __builtin_mpl_vector_merge_v1u64(a, b, n) +#define vext_f16(a, b, n) __builtin_mpl_vector_merge_v4f16(a, b, n) +#define vext_f32(a, b, n) __builtin_mpl_vector_merge_v2f32(a, b, n) +#define vext_f64(a, b, n) __builtin_mpl_vector_merge_v1f64(a, b, n) +#define vextq_s8(a, b, n) __builtin_mpl_vector_merge_v16i8(a, b, n) +#define vextq_s16(a, b, n) __builtin_mpl_vector_merge_v8i16(a, b, n) +#define vextq_s32(a, b, n) __builtin_mpl_vector_merge_v4i32(a, b, n) +#define vextq_s64(a, b, n) __builtin_mpl_vector_merge_v2i64(a, b, n) +#define vextq_u8(a, b, n) __builtin_mpl_vector_merge_v16u8(a, b, n) +#define vextq_u16(a, b, n) __builtin_mpl_vector_merge_v8u16(a, b, n) +#define vextq_u32(a, b, n) __builtin_mpl_vector_merge_v4u32(a, b, n) +#define vextq_u64(a, b, n) __builtin_mpl_vector_merge_v2u64(a, b, n) +#define vextq_f16(a, b, n) __builtin_mpl_vector_merge_v8f16(a, b, n) +#define vextq_f32(a, b, n) __builtin_mpl_vector_merge_v4f32(a, b, n) +#define vextq_f64(a, b, n) __builtin_mpl_vector_merge_v2f64(a, b, n) + +// vget_high +#define vget_high_s8(a) __builtin_mpl_vector_get_high_v16i8(a) +#define vget_high_s16(a) __builtin_mpl_vector_get_high_v8i16(a) +#define vget_high_s32(a) __builtin_mpl_vector_get_high_v4i32(a) +#define vget_high_s64(a) __builtin_mpl_vector_get_high_v2i64(a) +#define vget_high_u8(a) __builtin_mpl_vector_get_high_v16u8(a) +#define vget_high_u16(a) __builtin_mpl_vector_get_high_v8u16(a) +#define vget_high_u32(a) __builtin_mpl_vector_get_high_v4u32(a) +#define vget_high_u64(a) __builtin_mpl_vector_get_high_v2u64(a) +#define vget_high_f16(a) __builtin_mpl_vector_get_high_v4f16(a) +#define vget_high_f32(a) __builtin_mpl_vector_get_high_v2f32(a) +#define vget_high_f64(a) __builtin_mpl_vector_get_high_v1f64(a) + +// vget_lane +#define vget_lane_s8(a, n) __builtin_mpl_vector_get_element_v8i8(a, n) +#define vget_lane_s16(a, n) __builtin_mpl_vector_get_element_v4i16(a, n) +#define vget_lane_s32(a, n) __builtin_mpl_vector_get_element_v2i32(a, n) +#define vget_lane_s64(a, n) __builtin_mpl_vector_get_element_v1i64(a, n) +#define vget_lane_u8(a, n) __builtin_mpl_vector_get_element_v8u8(a, n) +#define vget_lane_u16(a, n) __builtin_mpl_vector_get_element_v4u16(a, n) +#define vget_lane_u32(a, n) __builtin_mpl_vector_get_element_v2u32(a, n) +#define vget_lane_u64(a, n) __builtin_mpl_vector_get_element_v1u64(a, n) +#define vget_lane_f16(a, n) __builtin_mpl_vector_get_element_v4f16(a, n) +#define vget_lane_f32(a, n) __builtin_mpl_vector_get_element_v2f32(a, n) +#define vget_lane_f64(a, n) __builtin_mpl_vector_get_element_v1f64(a, n) +#define vgetq_lane_s8(a, n) __builtin_mpl_vector_get_element_v16i8(a, n) +#define vgetq_lane_s16(a, n) __builtin_mpl_vector_get_element_v8i16(a, n) +#define vgetq_lane_s32(a, n) __builtin_mpl_vector_get_element_v4i32(a, n) +#define vgetq_lane_s64(a, n) __builtin_mpl_vector_get_element_v2i64(a, n) +#define vgetq_lane_u8(a, n) __builtin_mpl_vector_get_element_v16u8(a, n) +#define vgetq_lane_u16(a, n) __builtin_mpl_vector_get_element_v8u16(a, n) +#define vgetq_lane_u32(a, n) __builtin_mpl_vector_get_element_v4u32(a, n) +#define vgetq_lane_u64(a, n) __builtin_mpl_vector_get_element_v2u64(a, n) +#define vgetq_lane_f16(a, n) __builtin_mpl_vector_get_element_v8f16(a, n) +#define vgetq_lane_f32(a, n) __builtin_mpl_vector_get_element_v4f32(a, n) +#define vgetq_lane_f64(a, n) __builtin_mpl_vector_get_element_v2f64(a, n) + +// vget_low +#define vget_low_s8(a) __builtin_mpl_vector_get_low_v16i8(a) +#define vget_low_s16(a) __builtin_mpl_vector_get_low_v8i16(a) +#define vget_low_s32(a) __builtin_mpl_vector_get_low_v4i32(a) +#define vget_low_s64(a) __builtin_mpl_vector_get_low_v2i64(a) +#define vget_low_u8(a) __builtin_mpl_vector_get_low_v16u8(a) +#define vget_low_u16(a) __builtin_mpl_vector_get_low_v8u16(a) +#define vget_low_u32(a) __builtin_mpl_vector_get_low_v4u32(a) +#define vget_low_u64(a) __builtin_mpl_vector_get_low_v2u64(a) +#define vget_low_f16(a) __builtin_mpl_vector_get_low_v4f16(a) +#define vget_low_f32(a) __builtin_mpl_vector_get_low_v2f32(a) +#define vget_low_f64(a) __builtin_mpl_vector_get_low_v1f64(a) + +// vld1 +#define vld1_s8(a) __builtin_mpl_vector_load_v8i8(a) +#define vld1_s16(a) __builtin_mpl_vector_load_v4i16(a) +#define vld1_s32(a) __builtin_mpl_vector_load_v2i32(a) +#define vld1_s64(a) __builtin_mpl_vector_load_v1i64(a) +#define vld1_u8(a) __builtin_mpl_vector_load_v8u8(a) +#define vld1_u16(a) __builtin_mpl_vector_load_v4u16(a) +#define vld1_u32(a) __builtin_mpl_vector_load_v2u32(a) +#define vld1_u64(a) __builtin_mpl_vector_load_v1u64(a) +#define vld1_f16(a) __builtin_mpl_vector_load_v4f16(a) +#define vld1_f32(a) __builtin_mpl_vector_load_v2f32(a) +#define vld1_f64(a) __builtin_mpl_vector_load_v1f64(a) +#define vld1q_s8(a) __builtin_mpl_vector_load_v16i8(a) +#define vld1q_s16(a) __builtin_mpl_vector_load_v8i16(a) +#define vld1q_s32(a) __builtin_mpl_vector_load_v4i32(a) +#define vld1q_s64(a) __builtin_mpl_vector_load_v2i64(a) +#define vld1q_u8(a) __builtin_mpl_vector_load_v16u8(a) +#define vld1q_u16(a) __builtin_mpl_vector_load_v8u16(a) +#define vld1q_u32(a) __builtin_mpl_vector_load_v4u32(a) +#define vld1q_u64(a) __builtin_mpl_vector_load_v2u64(a) +#define vld1q_f16(a) __builtin_mpl_vector_load_v8f16(a) +#define vld1q_f32(a) __builtin_mpl_vector_load_v4f32(a) +#define vld1q_f64(a) __builtin_mpl_vector_load_v2f64(a) + +// vmlal +#define vmlal_s8(acc, a, b) __builtin_mpl_vector_madd_v8i8(acc, a, b) +#define vmlal_s16(acc, a, b) __builtin_mpl_vector_madd_v4i16(acc, a, b) +#define vmlal_s32(acc, a, b) __builtin_mpl_vector_madd_v2i32(acc, a, b) +#define vmlal_u8(acc, a, b) __builtin_mpl_vector_madd_v8u8(acc, a, b) +#define vmlal_u16(acc, a, b) __builtin_mpl_vector_madd_v4u16(acc, a, b) +#define vmlal_u32(acc, a, b) __builtin_mpl_vector_madd_v2u32(acc, a, b) + +// vmovl +#define vmovl_s32(a) __builtin_mpl_vector_widen_low_v2i32(a) +#define vmovl_s16(a) __builtin_mpl_vector_widen_low_v4i16(a) +#define vmovl_s8(a) __builtin_mpl_vector_widen_low_v8i8(a) +#define vmovl_u32(a) __builtin_mpl_vector_widen_low_v2u32(a) +#define vmovl_u16(a) __builtin_mpl_vector_widen_low_v4u16(a) +#define vmovl_u8(a) __builtin_mpl_vector_widen_low_v8u8(a) + +// vmovl_high +#define vmovl_high_s32(a) __builtin_mpl_vector_widen_high_v2i32(a) +#define vmovl_high_s16(a) __builtin_mpl_vector_widen_high_v4i16(a) +#define vmovl_high_s8(a) __builtin_mpl_vector_widen_high_v8i8(a) +#define vmovl_high_u32(a) __builtin_mpl_vector_widen_high_v2u32(a) +#define vmovl_high_u16(a) __builtin_mpl_vector_widen_high_v4u16(a) +#define vmovl_high_u8(a) __builtin_mpl_vector_widen_high_v8u8(a) + +// vmovn +#define vmovn_s64(a) __builtin_mpl_vector_narrow_low_v2i64(a) +#define vmovn_s32(a) __builtin_mpl_vector_narrow_low_v4i32(a) +#define vmovn_s16(a) __builtin_mpl_vector_narrow_low_v8i16(a) +#define vmovn_u64(a) __builtin_mpl_vector_narrow_low_v2u64(a) +#define vmovn_u32(a) __builtin_mpl_vector_narrow_low_v4u32(a) +#define vmovn_u16(a) __builtin_mpl_vector_narrow_low_v8u16(a) + +// vmovn_high +#define vmovn_high_s64(a, b) __builtin_mpl_vector_narrow_high_v2i64(a, b) +#define vmovn_high_s32(a, b) __builtin_mpl_vector_narrow_high_v4i32(a, b) +#define vmovn_high_s16(a, b) __builtin_mpl_vector_narrow_high_v8i16(a, b) +#define vmovn_high_u64(a, b) __builtin_mpl_vector_narrow_high_v2u64(a, b) +#define vmovn_high_u32(a, b) __builtin_mpl_vector_narrow_high_v4u32(a, b) +#define vmovn_high_u16(a, b) __builtin_mpl_vector_narrow_high_v8u16(a, b) + +// vmull +#define vmull_s8(a, b) __builtin_mpl_vector_mull_low_v8i8(a, b) +#define vmull_s16(a, b) __builtin_mpl_vector_mull_low_v4i16(a, b) +#define vmull_s32(a, b) __builtin_mpl_vector_mull_low_v2i32(a, b) +#define vmull_u8(a, b) __builtin_mpl_vector_mull_low_v8u8(a, b) +#define vmull_u16(a, b) __builtin_mpl_vector_mull_low_v4u16(a, b) +#define vmull_u32(a, b) __builtin_mpl_vector_mull_low_v2u32(a, b) + +// vmull_high +#define vmull_high_s8(a, b) __builtin_mpl_vector_mull_high_v8i8(a, b) +#define vmull_high_s16(a, b) __builtin_mpl_vector_mull_high_v4i16(a, b) +#define vmull_high_s32(a, b) __builtin_mpl_vector_mull_high_v2i32(a, b) +#define vmull_high_u8(a, b) __builtin_mpl_vector_mull_high_v8u8(a, b) +#define vmull_high_u16(a, b) __builtin_mpl_vector_mull_high_v4u16(a, b) +#define vmull_high_u32(a, b) __builtin_mpl_vector_mull_high_v2u32(a, b) + +// vor +#define vor_s8(a, b) (a | b) +#define vor_s16(a, b) (a | b) +#define vor_s32(a, b) (a | b) +#define vor_s64(a, b) (a | b) +#define vor_u8(a, b) (a | b) +#define vor_u16(a, b) (a | b) +#define vor_u32(a, b) (a | b) +#define vor_u64(a, b) (a | b) +#define vorq_s8(a, b) (a | b) +#define vorq_s16(a, b) (a | b) +#define vorq_s32(a, b) (a | b) +#define vorq_s64(a, b) (a | b) +#define vorq_u8(a, b) (a | b) +#define vorq_u16(a, b) (a | b) +#define vorq_u32(a, b) (a | b) +#define vorq_u64(a, b) (a | b) + +// vpadal (add and accumulate long pairwise) +#define vpadal_s8(a,b) __builtin_mpl_vector_pairwise_adalp_v8i8(a, b) +#define vpadal_s16(a,b) __builtin_mpl_vector_pairwise_adalp_v4i16(a, b) +#define vpadal_s32(a,b) __builtin_mpl_vector_pairwise_adalp_v2i32(a, b) +#define vpadal_u8(a,b) __builtin_mpl_vector_pairwise_adalp_v8u8(a, b) +#define vpadal_u16(a,b) __builtin_mpl_vector_pairwise_adalp_v4u16(a, b) +#define vpadal_u32(a,b) __builtin_mpl_vector_pairwise_adalp_v2u32(a, b) +#define vpadalq_s8(a,b) __builtin_mpl_vector_pairwise_adalp_v16i8(a, b) +#define vpadalq_s16(a,b) __builtin_mpl_vector_pairwise_adalp_v8i16(a, b) +#define vpadalq_s32(a,b) __builtin_mpl_vector_pairwise_adalp_v4i32(a, b) +#define vpadalq_u8(a,b) __builtin_mpl_vector_pairwise_adalp_v16u8(a, b) +#define vpadalq_u16(a,b) __builtin_mpl_vector_pairwise_adalp_v8u16(a, b) +#define vpadalq_u32(a,b) __builtin_mpl_vector_pairwise_adalp_v4u32(a, b) + +// vpaddl +#define vpaddl_s8(a) __builtin_mpl_vector_pairwise_add_v8i8(a) +#define vpaddl_s16(a) __builtin_mpl_vector_pairwise_add_v4i16(a) +#define vpaddl_s32(a) __builtin_mpl_vector_pairwise_add_v2i32(a) +#define vpaddl_u8(a) __builtin_mpl_vector_pairwise_add_v8u8(a) +#define vpaddl_u16(a) __builtin_mpl_vector_pairwise_add_v4u16(a) +#define vpaddl_u32(a) __builtin_mpl_vector_pairwise_add_v2u32(a) +#define vpaddlq_s8(a) __builtin_mpl_vector_pairwise_add_v16i8(a) +#define vpaddlq_s16(a) __builtin_mpl_vector_pairwise_add_v8i16(a) +#define vpaddlq_s32(a) __builtin_mpl_vector_pairwise_add_v4i32(a) +#define vpaddlq_u8(a) __builtin_mpl_vector_pairwise_add_v16u8(a) +#define vpaddlq_u16(a) __builtin_mpl_vector_pairwise_add_v8u16(a) +#define vpaddlq_u32(a) __builtin_mpl_vector_pairwise_add_v4u32(a) + +// vqtbl1 +#define vqtbl1_s8(a, b) __builtin_mpl_vector_table_lookup_v8i8(a, b) +#define vqtbl1_u8(a, b) __builtin_mpl_vector_table_lookup_v8u8(a, b) +#define vqtbl1q_s8(a, b) __builtin_mpl_vector_table_lookup_v16i8(a, b) +#define vqtbl1q_u8(a, b) __builtin_mpl_vector_table_lookup_v16u8(a, b) + +// vreinterpret 8 +#define vreinterpret_s16_s8(a) ((int16x4_t)a) +#define vreinterpret_s32_s8(a) ((int32x2_t)a) +#define vreinterpret_s64_s8(a) ((int64x1_t)a) +#define vreinterpret_u16_u8(a) ((uint16x4_t)a) +#define vreinterpret_u32_u8(a) ((uint32x2_t)a) +#define vreinterpret_u64_u8(a) ((uint64x1_t)a) +#define vreinterpret_f16_s8(a) ((float16x4_t)a) +#define vreinterpret_f32_s8(a) ((float32x2_t)a) +#define vreinterpret_f64_s8(a) ((float64x1_t)a) +#define vreinterpret_f16_u8(a) ((float16x4_t)a) +#define vreinterpret_f32_u8(a) ((float32x2_t)a) +#define vreinterpret_f64_u8(a) ((float64x1_t)a) +#define vreinterpretq_s16_s8(a) ((int16x8_t)a) +#define vreinterpretq_s32_s8(a) ((int32x4_t)a) +#define vreinterpretq_s64_s8(a) ((int64x2_t)a) +#define vreinterpretq_u16_u8(a) ((uint16x8_t)a) +#define vreinterpretq_u32_u8(a) ((uint32x4_t)a) +#define vreinterpretq_u64_u8(a) ((uint64x2_t)a) +#define vreinterpretq_f16_s8(a) ((float16x8_t)a) +#define vreinterpretq_f32_s8(a) ((float32x4_t)a) +#define vreinterpretq_f64_s8(a) ((float64x2_t)a) +#define vreinterpretq_f16_u8(a) ((float16x8_t)a) +#define vreinterpretq_f32_u8(a) ((float32x4_t)a) +#define vreinterpretq_f64_u8(a) ((float64x2_t)a) + +// vreinterpret 16 +#define vreinterpret_s8_s16(a) ((int8x8_t)a) +#define vreinterpret_s32_s16(a) ((int32x2_t)a) +#define vreinterpret_s64_s16(a) ((int64x1_t)a) +#define vreinterpret_u8_u16(a) ((uint8x8_t)a) +#define vreinterpret_u32_u16(a) ((uint32x2_t)a) +#define vreinterpret_u64_u16(a) ((uint64x1_t)a) +#define vreinterpret_f16_s16(a) ((float16x4_t)a) +#define vreinterpret_f32_s16(a) ((float32x2_t)a) +#define vreinterpret_f64_s16(a) ((float64x1_t)a) +#define vreinterpret_f16_u16(a) ((float16x4_t)a) +#define vreinterpret_f32_u16(a) ((float32x2_t)a) +#define vreinterpret_f64_u16(a) ((float64x1_t)a) +#define vreinterpretq_s8_s16(a) ((int16x8_t)a) +#define vreinterpretq_s32_s16(a) ((int32x4_t)a) +#define vreinterpretq_s64_s16(a) ((int64x2_t)a) +#define vreinterpretq_u8_u16(a) ((uint16x8_t)a) +#define vreinterpretq_u32_u16(a) ((uint32x4_t)a) +#define vreinterpretq_u64_u16(a) ((uint64x2_t)a) +#define vreinterpretq_f16_s16(a) ((float16x8_t)a) +#define vreinterpretq_f32_s16(a) ((float32x4_t)a) +#define vreinterpretq_f64_s16(a) ((float64x2_t)a) +#define vreinterpretq_f16_u16(a) ((float16x8_t)a) +#define vreinterpretq_f32_u16(a) ((float32x4_t)a) +#define vreinterpretq_f64_u16(a) ((float64x2_t)a) + +// vreinterpret 32 +#define vreinterpret_s8_s32(a) ((int8x8_t)a) +#define vreinterpret_s16_s32(a) ((int16x4_t)a) +#define vreinterpret_s64_s32(a) ((int64x1_t)a) +#define vreinterpret_u8_u32(a) ((uint8x8_t)a) +#define vreinterpret_u16_u32(a) ((uint16x4_t)a) +#define vreinterpret_u64_u32(a) ((uint64x1_t)a) +#define vreinterpret_f16_s32(a) ((float16x4_t)a) +#define vreinterpret_f32_s32(a) ((float32x2_t)a) +#define vreinterpret_f64_s32(a) ((float64x1_t)a) +#define vreinterpret_f16_u32(a) ((float16x4_t)a) +#define vreinterpret_f32_u32(a) ((float32x2_t)a) +#define vreinterpret_f64_u32(a) ((float64x1_t)a) +#define vreinterpretq_s8_s32(a) ((int16x8_t)a) +#define vreinterpretq_s16_s32(a) ((int16x8_t)a) +#define vreinterpretq_s64_s32(a) ((int64x2_t)a) +#define vreinterpretq_u8_u32(a) ((uint16x8_t)a) +#define vreinterpretq_u16_u32(a) ((uint16x8_t)a) +#define vreinterpretq_u64_u32(a) ((uint64x2_t)a) +#define vreinterpretq_f16_s32(a) ((float16x8_t)a) +#define vreinterpretq_f32_s32(a) ((float32x4_t)a) +#define vreinterpretq_f64_s32(a) ((float64x2_t)a) +#define vreinterpretq_f16_u32(a) ((float16x8_t)a) +#define vreinterpretq_f32_u32(a) ((float32x4_t)a) +#define vreinterpretq_f64_u32(a) ((float64x2_t)a) + +// vreinterpret 64 +#define vreinterpret_s8_s64(a) ((int8x8_t)a) +#define vreinterpret_s16_s64(a) ((int16x4_t)a) +#define vreinterpret_s32_s64(a) ((int32x2_t)a) +#define vreinterpret_u8_u64(a) ((uint8x8_t)a) +#define vreinterpret_u16_u64(a) ((uint16x4_t)a) +#define vreinterpret_u32_u64(a) ((uint32x2_t)a) +#define vreinterpret_f16_s64(a) ((float16x4_t)a) +#define vreinterpret_f32_s64(a) ((float32x2_t)a) +#define vreinterpret_f64_s64(a) ((float64x1_t)a) +#define vreinterpret_f16_u64(a) ((float16x4_t)a) +#define vreinterpret_f32_u64(a) ((float32x2_t)a) +#define vreinterpret_f64_u64(a) ((float64x1_t)a) +#define vreinterpretq_s8_s64(a) ((int8x16_t)a) +#define vreinterpretq_s16_s64(a) ((int16x8_t)a) +#define vreinterpretq_s32_s64(a) ((int32x4_t)a) +#define vreinterpretq_u8_u64(a) ((uint8x16_t)a) +#define vreinterpretq_u16_u64(a) ((uint16x8_t)a) +#define vreinterpretq_u32_u64(a) ((uint32x4_t)a) +#define vreinterpretq_f16_s64(a) ((float16x8_t)a) +#define vreinterpretq_f32_s64(a) ((float32x4_t)a) +#define vreinterpretq_f64_s64(a) ((float64x2_t)a) +#define vreinterpretq_f16_u64(a) ((float16x8_t)a) +#define vreinterpretq_f32_u64(a) ((float32x4_t)a) +#define vreinterpretq_f64_u64(a) ((float64x2_t)a) + +// vrev32 +#define vrev32_s8(a) __builtin_mpl_vector_reverse_v8i8(a) +#define vrev32_s16(a) __builtin_mpl_vector_reverse_v4i16(a) +#define vrev32_u8(a) __builtin_mpl_vector_reverse_v8u8(a) +#define vrev32_u16(a) __builtin_mpl_vector_reverse_v4u16(a) +#define vrev32q_s8(a) __builtin_mpl_vector_reverse_v16i8(a) +#define vrev32q_s16(a) __builtin_mpl_vector_reverse_v8i16(a) +#define vrev32q_u8(a) __builtin_mpl_vector_reverse_v16u8(a) +#define vrev32q_u16(a) __builtin_mpl_vector_reverse_v8u16(a) + +// vset_lane +#define vset_lane_s8(v, a, n) __builtin_mpl_vector_set_element_v8i8(v, a, n) +#define vset_lane_s16(v, a, n) __builtin_mpl_vector_set_element_v4i16(v, a, n) +#define vset_lane_s32(v, a, n) __builtin_mpl_vector_set_element_v2i32(v, a, n) +#define vset_lane_s64(v, a, n) __builtin_mpl_vector_set_element_v1i64(v, a, n) +#define vset_lane_u8(v, a, n) __builtin_mpl_vector_set_element_v8u8(v, a, n) +#define vset_lane_u16(v, a, n) __builtin_mpl_vector_set_element_v4u16(v, a, n) +#define vset_lane_u32(v, a, n) __builtin_mpl_vector_set_element_v2u32(v, a, n) +#define vset_lane_u64(v, a, n) __builtin_mpl_vector_set_element_v1u64(v, a, n) +#define vset_lane_f16(v, a, n) __builtin_mpl_vector_set_element_v4f16(v, a, n) +#define vset_lane_f32(v, a, n) __builtin_mpl_vector_set_element_v2f32(v, a, n) +#define vset_lane_f64(v, a, n) __builtin_mpl_vector_set_element_v1f64(v, a, n) +#define vsetq_lane_s8(v, a, n) __builtin_mpl_vector_set_element_v16i8(v, a, n) +#define vsetq_lane_s16(v, a, n) __builtin_mpl_vector_set_element_v8i16(v, a, n) +#define vsetq_lane_s32(v, a, n) __builtin_mpl_vector_set_element_v4i32(v, a, n) +#define vsetq_lane_s64(v, a, n) __builtin_mpl_vector_set_element_v2i64(v, a, n) +#define vsetq_lane_u8(v, a, n) __builtin_mpl_vector_set_element_v16u8(v, a, n) +#define vsetq_lane_u16(v, a, n) __builtin_mpl_vector_set_element_v8u16(v, a, n) +#define vsetq_lane_u32(v, a, n) __builtin_mpl_vector_set_element_v4u32(v, a, n) +#define vsetq_lane_u64(v, a, n) __builtin_mpl_vector_set_element_v2u64(v, a, n) +#define vsetq_lane_f16(v, a, n) __builtin_mpl_vector_set_element_v8f16(v, a, n) +#define vsetq_lane_f32(v, a, n) __builtin_mpl_vector_set_element_v4f32(v, a, n) +#define vsetq_lane_f64(v, a, n) __builtin_mpl_vector_set_element_v2f64(v, a, n) + +// vshl +#define vshl_s8(a, b) (a << b) +#define vshl_s16(a, b) (a << b) +#define vshl_s32(a, b) (a << b) +#define vshl_s64(a, b) (a << b) +#define vshl_u8(a, b) (a << b) +#define vshl_u16(a, b) (a << b) +#define vshl_u32(a, b) (a << b) +#define vshl_u64(a, b) (a << b) +#define vshlq_s8(a, b) (a << b) +#define vshlq_s16(a, b) (a << b) +#define vshlq_s32(a, b) (a << b) +#define vshlq_s64(a, b) (a << b) +#define vshlq_u8(a, b) (a << b) +#define vshlq_u16(a, b) (a << b) +#define vshlq_u32(a, b) (a << b) +#define vshlq_u64(a, b) (a << b) + +// vshl_n +#define vshlq_n_s64(a, n) __builtin_mpl_vector_shli_v2i64(a, n); +#define vshlq_n_s32(a, n) __builtin_mpl_vector_shli_v4i32(a, n); +#define vshlq_n_s16(a, n) __builtin_mpl_vector_shli_v8i16(a, n); +#define vshlq_n_s8(a, n) __builtin_mpl_vector_shli_v16i8(a, n); +#define vshlq_n_u64(a, n) __builtin_mpl_vector_shli_v2u64(a, n); +#define vshlq_n_u32(a, n) __builtin_mpl_vector_shli_v4u32(a, n); +#define vshlq_n_u16(a, n) __builtin_mpl_vector_shli_v8u16(a, n); +#define vshlq_n_u8(a, n) __builtin_mpl_vector_shli_v16u8(a, n); +#define vshl_n_s64(a, n) __builtin_mpl_vector_shli_v1i64(a, n); +#define vshl_n_s32(a, n) __builtin_mpl_vector_shli_v2i32(a, n); +#define vshl_n_s16(a, n) __builtin_mpl_vector_shli_v4i16(a, n); +#define vshl_n_s8(a, n) __builtin_mpl_vector_shli_v8i8(a, n); +#define vshl_n_u64(a, n) __builtin_mpl_vector_shli_v1u64(a, n); +#define vshl_n_u32(a, n) __builtin_mpl_vector_shli_v2u32(a, n); +#define vshl_n_u16(a, n) __builtin_mpl_vector_shli_v4u16(a, n); +#define vshl_n_u8(a, n) __builtin_mpl_vector_shli_v8u8(a, n); + +// vshr +#define vshr_s8(a, b) (a >> b) +#define vshr_s16(a, b) (a >> b) +#define vshr_s32(a, b) (a >> b) +#define vshr_s64(a, b) (a >> b) +#define vshr_u8(a, b) (a >> b) +#define vshr_u16(a, b) (a >> b) +#define vshr_u32(a, b) (a >> b) +#define vshr_u64(a, b) (a >> b) +#define vshrq_s8(a, b) (a >> b) +#define vshrq_s16(a, b) (a >> b) +#define vshrq_s32(a, b) (a >> b) +#define vshrq_s64(a, b) (a >> b) +#define vshrq_u8(a, b) (a >> b) +#define vshrq_u16(a, b) (a >> b) +#define vshrq_u32(a, b) (a >> b) +#define vshrq_u64(a, b) (a >> b) + +// vshr_n +#define vshrq_n_s64(a, n) __builtin_mpl_vector_shri_v2i64(a, n); +#define vshrq_n_s32(a, n) __builtin_mpl_vector_shri_v4i32(a, n); +#define vshrq_n_s16(a, n) __builtin_mpl_vector_shri_v8i16(a, n); +#define vshrq_n_s8(a, n) __builtin_mpl_vector_shri_v16i8(a, n); +#define vshrq_n_u64(a, n) __builtin_mpl_vector_shru_v2u64(a, n); +#define vshrq_n_u32(a, n) __builtin_mpl_vector_shru_v4u32(a, n); +#define vshrq_n_u16(a, n) __builtin_mpl_vector_shru_v8u16(a, n); +#define vshrq_n_u8(a, n) __builtin_mpl_vector_shru_v16u8(a, n); +#define vshr_n_s64(a, n) __builtin_mpl_vector_shri_v1i64(a, n); +#define vshr_n_s32(a, n) __builtin_mpl_vector_shri_v2i32(a, n); +#define vshr_n_s16(a, n) __builtin_mpl_vector_shri_v4i16(a, n); +#define vshr_n_s8(a, n) __builtin_mpl_vector_shri_v8i8(a, n); +#define vshr_n_u64(a, n) __builtin_mpl_vector_shru_v1u64(a, n); +#define vshr_n_u32(a, n) __builtin_mpl_vector_shru_v2u32(a, n); +#define vshr_n_u16(a, n) __builtin_mpl_vector_shru_v4u16(a, n); +#define vshr_n_u8(a, n) __builtin_mpl_vector_shru_v8u8(a, n); + +// vshrn_n +#define vshrn_n_s16(a, n) __builtin_mpl_vector_shr_narrow_low_v8i16(a, n) +#define vshrn_n_s32(a, n) __builtin_mpl_vector_shr_narrow_low_v4i32(a, n) +#define vshrn_n_s64(a, n) __builtin_mpl_vector_shr_narrow_low_v2i64(a, n) +#define vshrn_n_u16(a, n) __builtin_mpl_vector_shr_narrow_low_v8u16(a, n) +#define vshrn_n_u32(a, n) __builtin_mpl_vector_shr_narrow_low_v4u32(a, n) +#define vshrn_n_u64(a, n) __builtin_mpl_vector_shr_narrow_low_v2u64(a, n) + +// vst1 +#define vst1_s8(p, v) __builtin_mpl_vector_store_v8i8(p, v) +#define vst1_s16(p, v) __builtin_mpl_vector_store_v4i16(p, v) +#define vst1_s32(p, v) __builtin_mpl_vector_store_v2i32(p, v) +#define vst1_s64(p, v) __builtin_mpl_vector_store_v1i64(p, v) +#define vst1_u8(p, v) __builtin_mpl_vector_store_v8u8(p, v) +#define vst1_u16(p, v) __builtin_mpl_vector_store_v4u16(p, v) +#define vst1_u32(p, v) __builtin_mpl_vector_store_v2u32(p, v) +#define vst1_u64(p, v) __builtin_mpl_vector_store_v1u64(p, v) +#define vst1_f16(p, v) __builtin_mpl_vector_store_v4f16(p, v) +#define vst1_f32(p, v) __builtin_mpl_vector_store_v2f32(p, v) +#define vst1_f64(p, v) __builtin_mpl_vector_store_v1f64(p, v) +#define vst1q_s8(p, v) __builtin_mpl_vector_store_v16i8(p, v) +#define vst1q_s16(p, v) __builtin_mpl_vector_store_v8i16(p, v) +#define vst1q_s32(p, v) __builtin_mpl_vector_store_v4i32(p, v) +#define vst1q_s64(p, v) __builtin_mpl_vector_store_v2i64(p, v) +#define vst1q_u8(p, v) __builtin_mpl_vector_store_v16u8(p, v) +#define vst1q_u16(p, v) __builtin_mpl_vector_store_v8u16(p, v) +#define vst1q_u32(p, v) __builtin_mpl_vector_store_v4u32(p, v) +#define vst1q_u64(p, v) __builtin_mpl_vector_store_v2u64(p, v) +#define vst1q_f16(p, v) __builtin_mpl_vector_store_v8f16(p, v) +#define vst1q_f32(p, v) __builtin_mpl_vector_store_v4f32(p, v) +#define vst1q_f64(p, v) __builtin_mpl_vector_store_v2f64(p, v) + +// vsub +#define vsub_s8(a, b) (a - b) +#define vsub_s16(a, b) (a - b) +#define vsub_s32(a, b) (a - b) +#define vsub_s64(a, b) (a - b) +#define vsub_u8(a, b) (a - b) +#define vsub_u16(a, b) (a - b) +#define vsub_u32(a, b) (a - b) +#define vsub_u64(a, b) (a - b) +#define vsub_f16(a, b) (a - b) +#define vsub_f32(a, b) (a - b) +#define vsub_f64(a, b) (a - b) +#define vsubq_s8(a, b) (a - b) +#define vsubq_s16(a, b) (a - b) +#define vsubq_s32(a, b) (a - b) +#define vsubq_s64(a, b) (a - b) +#define vsubq_u8(a, b) (a - b) +#define vsubq_u16(a, b) (a - b) +#define vsubq_u32(a, b) (a - b) +#define vsubq_u64(a, b) (a - b) +#define vsubq_f16(a, b) (a - b) +#define vsubq_f32(a, b) (a - b) +#define vsubq_f64(a, b) (a - b) + +// vsub[lw] +#define vsubl_s8(a, b) __builtin_mpl_vector_subl_low_v8i8(a, b) +#define vsubl_s16(a, b) __builtin_mpl_vector_subl_low_v4i16(a, b) +#define vsubl_s32(a, b) __builtin_mpl_vector_subl_low_v2i32(a, b) +#define vsubl_u8(a, b) __builtin_mpl_vector_subl_low_v8u8(a, b) +#define vsubl_u16(a, b) __builtin_mpl_vector_subl_low_v4u16(a, b) +#define vsubl_u32(a, b) __builtin_mpl_vector_subl_low_v2u32(a, b) +#define vsubl_high_s8(a, b) __builtin_mpl_vector_subl_high_v8i8(a, b) +#define vsubl_high_s16(a, b) __builtin_mpl_vector_subl_high_v4i16(a, b) +#define vsubl_high_s32(a, b) __builtin_mpl_vector_subl_high_v2i32(a, b) +#define vsubl_high_u8(a, b) __builtin_mpl_vector_subl_high_v8u8(a, b) +#define vsubl_high_u16(a, b) __builtin_mpl_vector_subl_high_v4u16(a, b) +#define vsubl_high_u32(a, b) __builtin_mpl_vector_subl_high_v2u32(a, b) +#define vsubw_s8(a, b) __builtin_mpl_vector_subw_low_v8i8(a, b) +#define vsubw_s16(a, b) __builtin_mpl_vector_subw_low_v4i16(a, b) +#define vsubw_s32(a, b) __builtin_mpl_vector_subw_low_v2i32(a, b) +#define vsubw_u8(a, b) __builtin_mpl_vector_subw_low_v8u8(a, b) +#define vsubw_u16(a, b) __builtin_mpl_vector_subw_low_v4u16(a, b) +#define vsubw_u32(a, b) __builtin_mpl_vector_subw_low_v2u32(a, b) +#define vsubw_high_s8(a, b) __builtin_mpl_vector_subw_high_v8i8(a, b) +#define vsubw_high_s16(a, b) __builtin_mpl_vector_subw_high_v4i16(a, b) +#define vsubw_high_s32(a, b) __builtin_mpl_vector_subw_high_v2i32(a, b) +#define vsubw_high_u8(a, b) __builtin_mpl_vector_subw_high_v8u8(a, b) +#define vsubw_high_u16(a, b) __builtin_mpl_vector_subw_high_v4u16(a, b) +#define vsubw_high_u32(a, b) __builtin_mpl_vector_subw_high_v2u32(a, b) + +// vzip +#define vzip_s8(a, b) __builtin_mpl_vector_zip_v8i8(a, b) +#define vzip_s16(a, b) __builtin_mpl_vector_zip_v4i16(a, b) +#define vzip_s32(a, b) __builtin_mpl_vector_zip_v2i32(a, b) +#define vzip_u8(a, b) __builtin_mpl_vector_zip_v8u8(a, b) +#define vzip_u16(a, b) __builtin_mpl_vector_zip_v4u16(a, b) +#define vzip_u32(a, b) __builtin_mpl_vector_zip_v2u32(a, b) +#define vzip_f32(a, b) __builtin_mpl_vector_zip_v2f32(a, b) + +#endif /* __ARM_NEON_H */ diff --git a/src/hir2mpl/ast_input/clang/src/ast_expr.cpp b/src/hir2mpl/ast_input/clang/src/ast_expr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..82acadec9519937c90afea5e800cc9da30a37653 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/src/ast_expr.cpp @@ -0,0 +1,2594 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ast_expr.h" +#include "ast_decl.h" +#include "ast_macros.h" +#include "mpl_logging.h" +#include "feir_stmt.h" +#include "feir_builder.h" +#include "fe_utils_ast.h" +#include "feir_type_helper.h" +#include "fe_manager.h" +#include "ast_stmt.h" +#include "ast_util.h" +#include "enhance_c_checker.h" +#include "ror.h" +#include "conditional_operator.h" + +namespace maple { +const uint32 kOneByte = 8; +// ---------- ASTValue ---------- +MIRConst *ASTValue::Translate2MIRConst() const { + switch (pty) { + case PTY_u1: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + val.u8, *GlobalTables::GetTypeTable().GetPrimType(PTY_u1)); + } + case PTY_u8: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + val.u8, *GlobalTables::GetTypeTable().GetPrimType(PTY_u8)); + } + case PTY_u16: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + val.u16, *GlobalTables::GetTypeTable().GetPrimType(PTY_u16)); + } + case PTY_u32: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + val.u32, *GlobalTables::GetTypeTable().GetPrimType(PTY_u32)); + } + case PTY_u64: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + val.u64, *GlobalTables::GetTypeTable().GetPrimType(PTY_u64)); + } + case PTY_i8: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + val.i8, *GlobalTables::GetTypeTable().GetPrimType(PTY_i8)); + } + case PTY_i16: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + val.i16, *GlobalTables::GetTypeTable().GetPrimType(PTY_i16)); + } + case PTY_i32: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + val.i32, *GlobalTables::GetTypeTable().GetPrimType(PTY_i32)); + } + case PTY_i64: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + val.i64, *GlobalTables::GetTypeTable().GetPrimType(PTY_i64)); + } + case PTY_f32: { + return FEManager::GetModule().GetMemPool()->New( + val.f32, *GlobalTables::GetTypeTable().GetPrimType(PTY_f32)); + } + case PTY_f64: { + return FEManager::GetModule().GetMemPool()->New( + val.f64, *GlobalTables::GetTypeTable().GetPrimType(PTY_f64)); + } + case PTY_a64: { + return FEManager::GetModule().GetMemPool()->New( + val.strIdx, *GlobalTables::GetTypeTable().GetPrimType(PTY_a64)); + } + default: { + CHECK_FATAL(false, "Unsupported Primitive type: %d", pty); + } + } +} + +// ---------- ASTExpr ---------- +UniqueFEIRExpr ASTExpr::Emit2FEExpr(std::list &stmts) const { + auto feirExpr = Emit2FEExprImpl(stmts); + for (auto &stmt : stmts) { + if (!stmt->HasSetLOCInfo()) { + stmt->SetSrcFileInfo(srcFileIdx, srcFileLineNum); + } + } + return feirExpr; +} + +UniqueFEIRExpr ASTExpr::ImplicitInitFieldValue(MIRType *type, std::list &stmts) const { + UniqueFEIRExpr implicitInitFieldExpr; + MIRTypeKind noInitExprKind = type->GetKind(); + if (noInitExprKind == kTypeStruct || noInitExprKind == kTypeUnion) { + auto *structType = static_cast(type); + std::string tmpName = FEUtils::GetSequentialName("implicitInitStruct_"); + UniqueFEIRVar tmpVar = FEIRBuilder::CreateVarNameForC(tmpName, *type); + for (size_t i = 0; i < structType->GetFieldsSize(); ++i) { + FieldID fieldID = 0; + FEUtils::TraverseToNamedField(*structType, structType->GetElemStrIdx(i), fieldID); + MIRType *fieldType = structType->GetFieldType(fieldID); + UniqueFEIRExpr fieldExpr = ImplicitInitFieldValue(fieldType, stmts); + UniqueFEIRStmt fieldStmt = std::make_unique(tmpVar->Clone(), std::move(fieldExpr), fieldID); + stmts.emplace_back(std::move(fieldStmt)); + } + implicitInitFieldExpr = FEIRBuilder::CreateExprDRead(std::move(tmpVar)); + } else if (noInitExprKind == kTypeArray) { + auto *arrayType = static_cast(type); + size_t elemSize = arrayType->GetElemType()->GetSize(); + CHECK_FATAL(elemSize != 0, "elemSize is 0"); + size_t numElems = arrayType->GetSize() / elemSize; + UniqueFEIRType typeNative = FEIRTypeHelper::CreateTypeNative(*type); + std::string tmpName = FEUtils::GetSequentialName("implicitInitArray_"); + UniqueFEIRVar tmpVar = FEIRBuilder::CreateVarNameForC(tmpName, *type); + UniqueFEIRExpr arrayExpr = FEIRBuilder::CreateExprDRead(tmpVar->Clone()); + for (uint32 i = 0; i < numElems; ++i) { + UniqueFEIRExpr exprIndex = FEIRBuilder::CreateExprConstI32(i); + MIRType *fieldType = arrayType->GetElemType(); + UniqueFEIRExpr exprElem = ImplicitInitFieldValue(fieldType, stmts); + UniqueFEIRType typeNativeTmp = typeNative->Clone(); + UniqueFEIRExpr arrayExprTmp = arrayExpr->Clone(); + auto stmt = FEIRBuilder::CreateStmtArrayStoreOneStmtForC(std::move(exprElem), std::move(arrayExprTmp), + std::move(exprIndex), std::move(typeNativeTmp), + tmpName); + stmts.emplace_back(std::move(stmt)); + } + implicitInitFieldExpr = FEIRBuilder::CreateExprDRead(std::move(tmpVar)); + } else if (noInitExprKind == kTypePointer) { + implicitInitFieldExpr = std::make_unique(static_cast(0), PTY_ptr); + } else { + CHECK_FATAL(noInitExprKind == kTypeScalar, "noInitExprKind isn't kTypeScalar"); + implicitInitFieldExpr = FEIRBuilder::CreateExprConstAnyScalar(type->GetPrimType(), 0); + } + return implicitInitFieldExpr; +} + +MIRConst *ASTExpr::GenerateMIRConstImpl() const { + CHECK_FATAL(isConstantFolded && value != nullptr, "Unsupported for ASTExpr: %d", op); + return value->Translate2MIRConst(); +} + +// ---------- ASTDeclRefExpr --------- +MIRConst *ASTDeclRefExpr::GenerateMIRConstImpl() const { + MIRType *mirType = refedDecl->GetTypeDesc().front(); + if (mirType->GetKind() == kTypePointer && + static_cast(mirType)->GetPointedType()->GetKind() == kTypeFunction) { + GStrIdx idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(refedDecl->GetName()); + MIRSymbol *funcSymbol = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(idx); + CHECK_FATAL(funcSymbol != nullptr, "Should process func decl before var decl"); + MIRFunction *mirFunc = funcSymbol->GetFunction(); + CHECK_FATAL(mirFunc != nullptr, "Same name symbol with function: %s", refedDecl->GetName().c_str()); + return FEManager::GetModule().GetMemPool()->New(mirFunc->GetPuidx(), *mirType); + } else if (!isConstantFolded) { + ASTDecl *var = refedDecl; + MIRSymbol *mirSymbol; + if (var->IsGlobal()) { + mirSymbol = FEManager::GetMIRBuilder().GetOrCreateGlobalDecl( + var->GenerateUniqueVarName(), *(var->GetTypeDesc().front())); + } else { + mirSymbol = FEManager::GetMIRBuilder().GetOrCreateLocalDecl( + var->GenerateUniqueVarName(), *(var->GetTypeDesc().front())); + } + return FEManager::GetModule().GetMemPool()->New( + mirSymbol->GetStIdx(), 0, *(var->GetTypeDesc().front())); + } else { + return GetConstantValue()->Translate2MIRConst(); + } +} + +UniqueFEIRExpr ASTDeclRefExpr::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + MIRType *mirType = refedDecl->GetTypeDesc().front(); + UniqueFEIRExpr feirRefExpr; + auto attrs = refedDecl->GetGenericAttrs(); + if (mirType->GetKind() == kTypePointer && + static_cast(mirType)->GetPointedType()->GetKind() == kTypeFunction) { + feirRefExpr = FEIRBuilder::CreateExprAddrofFunc(refedDecl->GetName()); + } else { + if (refedDecl->GetDeclKind() == kASTEnumConstant) { + return FEIRBuilder::CreateExprConstAnyScalar(refedDecl->GetTypeDesc().front()->GetPrimType(), + static_cast(refedDecl)->GetValue()); + } + UniqueFEIRVar feirVar = + FEIRBuilder::CreateVarNameForC(refedDecl->GenerateUniqueVarName(), *mirType, refedDecl->IsGlobal(), false); + feirVar->SetAttrs(attrs); + if (mirType->GetKind() == kTypeArray) { + feirRefExpr = FEIRBuilder::CreateExprAddrofVar(std::move(feirVar)); + } else { + feirRefExpr = FEIRBuilder::CreateExprDRead(std::move(feirVar)); + } + } + return feirRefExpr; +} + +// ---------- ASTCallExpr ---------- +std::string ASTCallExpr::CvtBuiltInFuncName(std::string builtInName) const { +#define BUILTIN_FUNC(funcName) \ + {"__builtin_"#funcName, #funcName}, + static std::map cvtMap = { +#include "ast_builtin_func.def" +#undef BUILTIN_FUNC + }; + auto it = cvtMap.find(builtInName); + if (it != cvtMap.end()) { + return cvtMap.find(builtInName)->second; + } else { + return builtInName; + } +} + +std::unordered_map ASTCallExpr::builtingFuncPtrMap = + ASTCallExpr::InitBuiltinFuncPtrMap(); + +void ASTCallExpr::AddArgsExpr(const std::unique_ptr &callStmt, std::list &stmts) const { + for (int32 i = (static_cast(args.size()) - 1); i >= 0; --i) { + UniqueFEIRExpr expr = args[i]->Emit2FEExpr(stmts); + callStmt->AddExprArgReverse(std::move(expr)); + } + if (IsFirstArgRet()) { + UniqueFEIRVar var = FEIRBuilder::CreateVarNameForC(varName, *retType, false, false); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprAddrofVar(var->Clone()); + callStmt->AddExprArgReverse(std::move(expr)); + } + if (isIcall) { + UniqueFEIRExpr expr = calleeExpr->Emit2FEExpr(stmts); + InsertNonnullCheckingForIcall(expr, stmts); + InsertBoundaryCheckingInArgsForICall(stmts, expr); + callStmt->AddExprArgReverse(std::move(expr)); + } + InsertBoundaryCheckingInArgs(stmts); + CheckNonnullFieldInStruct(); +} + +void ASTCallExpr::InsertNonnullCheckingForIcall(const UniqueFEIRExpr &expr, std::list &stmts) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || expr->GetPrimType() != PTY_ptr) { + return; + } + UniqueFEIRStmt stmt = std::make_unique(OP_assertnonnull, expr->Clone()); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); +} + +UniqueFEIRExpr ASTCallExpr::AddRetExpr(const std::unique_ptr &callStmt) const { + UniqueFEIRVar var = FEIRBuilder::CreateVarNameForC(varName, *retType, false, false); + UniqueFEIRVar dreadVar = var->Clone(); + if (!IsFirstArgRet()) { + callStmt->SetVar(var->Clone()); + } + return FEIRBuilder::CreateExprDRead(dreadVar->Clone()); +} + +std::unique_ptr ASTCallExpr::GenCallStmt() const { + MemPool *mp = FEManager::GetManager().GetStructElemMempool(); + std::unique_ptr callStmt; + if (isIcall) { + callStmt = std::make_unique(); + } else { + StructElemNameIdx *nameIdx = mp->New(funcName); + FEStructMethodInfo *info = static_cast( + FEManager::GetTypeManager().RegisterStructMethodInfo(*nameIdx, kSrcLangC, false)); + info->SetFuncAttrs(funcAttrs); + FEIRTypeNative *retTypeInfo = nullptr; + if (IsFirstArgRet()) { + retTypeInfo = mp->New(*GlobalTables::GetTypeTable().GetPrimType(PTY_void)); + } else { + retTypeInfo = mp->New(*retType); + } + info->SetReturnType(retTypeInfo); + Opcode op; + if (retTypeInfo->GetPrimType() != PTY_void) { + op = OP_callassigned; + } else { + op = OP_call; + } + callStmt = std::make_unique(*info, op, nullptr, false); + } + callStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + return callStmt; +} + +UniqueFEIRExpr ASTCallExpr::Emit2FEExprImpl(std::list &stmts) const { + if (!isIcall) { + bool isFinish = false; + UniqueFEIRExpr buitinExpr = ProcessBuiltinFunc(stmts, isFinish); + if (isFinish) { + return buitinExpr; + } + } + std::unique_ptr callStmt = GenCallStmt(); + AddArgsExpr(callStmt, stmts); + UniqueFEIRExpr retExpr = nullptr; + if (IsNeedRetExpr()) { + retExpr = AddRetExpr(callStmt); + } + stmts.emplace_back(std::move(callStmt)); + InsertBoundaryVarInRet(stmts); + return retExpr; +} + +// ---------- ASTCastExpr ---------- +MIRConst *ASTCastExpr::GenerateMIRConstImpl() const { + std::list stmts; + auto feExpr = child->Emit2FEExpr(stmts); + if (isArrayToPointerDecay && feExpr->GetKind() == FEIRNodeKind::kExprAddrof) { + return FEManager::GetModule().GetMemPool()->New( + GetConstantValue()->val.strIdx, *GlobalTables::GetTypeTable().GetPrimType(PTY_a64)); + } else if (isArrayToPointerDecay && child->GetASTOp() == kASTOpRef) { + ASTDecl *astDecl = static_cast(child)->GetASTDecl(); + CHECK_FATAL(astDecl->GetDeclKind() == kASTVar, "Invalid"); + MIRSymbol *mirSymbol = static_cast(astDecl)->Translate2MIRSymbol(); + return FEManager::GetModule().GetMemPool()->New(mirSymbol->GetStIdx(), 0, + *(astDecl->GetTypeDesc().front())); + } else if (isArrayToPointerDecay && child->GetASTOp() == kASTOpCompoundLiteralExpr) { + static_cast(child)->SetAddrof(true); + return child->GenerateMIRConst(); + } else if (isNeededCvt) { + if (dst->GetPrimType() == PTY_f64) { + return GenerateMIRDoubleConst(); + } else if (dst->GetPrimType() == PTY_f32) { + return GenerateMIRFloatConst(); + } else { + return GenerateMIRIntConst(); + } + } else { + return child->GenerateMIRConst(); + } +} + +MIRConst *ASTCastExpr::GenerateMIRDoubleConst() const { + MIRConst *childConst = child->GenerateMIRConst(); + if (childConst == nullptr) { + return nullptr; + } + switch (childConst->GetKind()) { + case kConstFloatConst: { + return FEManager::GetModule().GetMemPool()->New( + static_cast(static_cast(childConst)->GetValue()), + *GlobalTables::GetTypeTable().GetPrimType(PTY_f64)); + } + case kConstInt: { + return FEManager::GetModule().GetMemPool()->New( + static_cast(static_cast(childConst)->GetValue()), + *GlobalTables::GetTypeTable().GetPrimType(PTY_f64)); + } + case kConstDoubleConst: { + return FEManager::GetModule().GetMemPool()->New( + static_cast(static_cast(childConst)->GetValue()), + *GlobalTables::GetTypeTable().GetPrimType(PTY_f64)); + } + default: { + CHECK_FATAL(false, "Unsupported pty type: %d", GetConstantValue()->pty); + return nullptr; + } + } +} + +MIRConst *ASTCastExpr::GenerateMIRFloatConst() const { + MIRConst *childConst = child->GenerateMIRConst(); + if (childConst == nullptr) { + return nullptr; + } + switch (childConst->GetKind()) { + case kConstDoubleConst: { + return FEManager::GetModule().GetMemPool()->New( + static_cast(static_cast(childConst)->GetValue()), + *GlobalTables::GetTypeTable().GetPrimType(PTY_f32)); + } + case kConstInt: { + return FEManager::GetModule().GetMemPool()->New( + static_cast(static_cast(childConst)->GetValue()), + *GlobalTables::GetTypeTable().GetPrimType(PTY_f32)); + } + default: { + CHECK_FATAL(false, "Unsupported pty type: %d", GetConstantValue()->pty); + return nullptr; + } + } +} + +MIRConst *ASTCastExpr::GenerateMIRIntConst() const { + MIRConst *childConst = child->GenerateMIRConst(); + if (childConst == nullptr) { + return nullptr; + } + switch (childConst->GetKind()) { + case kConstDoubleConst: + case kConstInt: { + int64 val = childConst->GetKind() == kConstDoubleConst ? + static_cast(static_cast(childConst)->GetValue()) : + static_cast(childConst)->GetValue(); + + PrimType destPrimType = mirType->GetPrimType(); + switch (destPrimType) { + case PTY_i8: + val = static_cast(val); + break; + case PTY_i16: + val = static_cast(val); + break; + case PTY_i32: + val = static_cast(val); + break; + case PTY_i64: + val = static_cast(val); + break; + case PTY_u8: + val = static_cast(val); + break; + case PTY_u16: + val = static_cast(val); + break; + case PTY_u32: + val = static_cast(val); + break; + case PTY_u64: + val = static_cast(val); + break; + default: + break; + } + return FEManager::GetModule().GetMemPool()->New( + val, *GlobalTables::GetTypeTable().GetPrimType(PTY_i64)); + } + case kConstStrConst: { + return FEManager::GetModule().GetMemPool()->New( + static_cast(static_cast(childConst)->GetValue()), + *GlobalTables::GetTypeTable().GetPrimType(PTY_a64)); + } + case kConstAddrof: { + return FEManager::GetModule().GetMemPool()->New( + static_cast(static_cast(childConst)->GetOffset()), + *GlobalTables::GetTypeTable().GetPrimType(PTY_i64)); + } + case kConstLblConst: { + // init by initListExpr, Only MIRConst kind is set here. + return childConst; + } + default: { + CHECK_FATAL(false, "Unsupported pty type: %d", GetConstantValue()->pty); + return nullptr; + } + } +} + +UniqueFEIRExpr ASTCastExpr::Emit2FEExprForComplex(const UniqueFEIRExpr &subExpr, const UniqueFEIRType &srcType, + std::list &stmts) const { + std::string tmpName = FEUtils::GetSequentialName("Complex_"); + UniqueFEIRVar tmpVar = FEIRBuilder::CreateVarNameForC(tmpName, *complexType); + UniqueFEIRExpr dreadAgg; + if (imageZero) { + UniqueFEIRStmt realStmtNode = std::make_unique(tmpVar->Clone(), + subExpr->Clone(), kComplexRealID); + stmts.emplace_back(std::move(realStmtNode)); + UniqueFEIRExpr imagExpr = FEIRBuilder::CreateExprConstAnyScalar(src->GetPrimType(), 0); + UniqueFEIRStmt imagStmtNode = std::make_unique(tmpVar->Clone(), + imagExpr->Clone(), kComplexImagID); + stmts.emplace_back(std::move(imagStmtNode)); + dreadAgg = FEIRBuilder::CreateExprDRead(std::move(tmpVar)); + static_cast(dreadAgg.get())->SetFieldType(srcType->Clone()); + } else { + UniqueFEIRExpr realExpr; + UniqueFEIRExpr imagExpr; + FEIRNodeKind subNodeKind = subExpr->GetKind(); + UniqueFEIRExpr cloneSubExpr = subExpr->Clone(); + if (subNodeKind == kExprIRead) { + static_cast(subExpr.get())->SetFieldID(kComplexRealID); + static_cast(cloneSubExpr.get())->SetFieldID(kComplexImagID); + } else if (subNodeKind == kExprDRead) { + static_cast(subExpr.get())->SetFieldID(kComplexRealID); + static_cast(subExpr.get())->SetFieldType(srcType->Clone()); + static_cast(cloneSubExpr.get())->SetFieldID(kComplexImagID); + static_cast(cloneSubExpr.get())->SetFieldType(srcType->Clone()); + } + realExpr = FEIRBuilder::CreateExprCastPrim(subExpr->Clone(), dst->GetPrimType()); + imagExpr = FEIRBuilder::CreateExprCastPrim(std::move(cloneSubExpr), dst->GetPrimType()); + UniqueFEIRStmt realStmt = std::make_unique(tmpVar->Clone(), std::move(realExpr), kComplexRealID); + stmts.emplace_back(std::move(realStmt)); + UniqueFEIRStmt imagStmt = std::make_unique(tmpVar->Clone(), std::move(imagExpr), kComplexImagID); + stmts.emplace_back(std::move(imagStmt)); + dreadAgg = FEIRBuilder::CreateExprDRead(std::move(tmpVar)); + } + return dreadAgg; +} + +UniqueFEIRExpr ASTCastExpr::Emit2FEExprImpl(std::list &stmts) const { + const ASTExpr *childExpr = child; + CHECK_FATAL(childExpr != nullptr, "childExpr is nullptr"); + if (isArrayToPointerDecay) { + auto childFEExpr = childExpr->Emit2FEExpr(stmts); + if (childFEExpr->GetKind() == kExprDRead) { + return std::make_unique( + static_cast(childFEExpr.get())->GetVar()->Clone(), childFEExpr->GetFieldID()); + } else if (childFEExpr->GetKind() == kExprIRead) { + auto iread = static_cast(childFEExpr.get()); + if (iread->GetFieldID() == 0) { + auto addrOfExpr = iread->GetClonedOpnd(); + ENCChecker::ReduceBoundaryChecking(stmts, addrOfExpr); + return addrOfExpr; + } else { + return std::make_unique(iread->GetClonedPtrType(), iread->GetFieldID(), + iread->GetClonedOpnd()); + } + } else if (childFEExpr->GetKind() == kExprIAddrof || childFEExpr->GetKind() == kExprAddrofVar || + childFEExpr->GetKind() == kExprAddrofFunc || childFEExpr->GetKind() == kExprAddrof) { + return childFEExpr; + } else { + CHECK_FATAL(false, "unsupported expr kind %d", childFEExpr->GetKind()); + } + } + UniqueFEIRExpr subExpr = childExpr->Emit2FEExpr(stmts); + if (isUnoinCast && dst->GetKind() == kTypeUnion) { + return subExpr; + } + if (isBitCast) { + if (src->GetPrimType() == dst->GetPrimType() && src->IsScalarType()) { + // This case may show up when casting from a 1-element vector to its scalar type. + return subExpr; + } + UniqueFEIRType dstType = std::make_unique(*dst); + if (dst->GetKind() == kTypePointer) { + CheckNonnullFieldInStruct(); + return subExpr; + } else { + return std::make_unique(std::move(dstType), OP_retype, std::move(subExpr)); + } + } + if (isVectorSplat) { + return EmitExprVdupVector(dst->GetPrimType(), subExpr); + } + if (complexType != nullptr) { + UniqueFEIRType srcType = std::make_unique(*src); + return Emit2FEExprForComplex(subExpr, srcType, stmts); + } + if (!IsNeededCvt(subExpr)) { + return subExpr; + } + if (IsPrimitiveFloat(subExpr->GetPrimType()) && IsPrimitiveInteger(dst->GetPrimType()) && + dst->GetPrimType() != PTY_u1) { + return FEIRBuilder::CreateExprCvtPrim(OP_trunc, std::move(subExpr), dst->GetPrimType()); + } + return FEIRBuilder::CreateExprCastPrim(std::move(subExpr), dst->GetPrimType()); +} + +UniqueFEIRExpr ASTCastExpr::EmitExprVdupVector(PrimType primtype, UniqueFEIRExpr &subExpr) const { +MIRIntrinsicID intrinsic; + switch (primtype) { +#define SET_VDUP(TY) \ + case PTY_##TY: \ + intrinsic = INTRN_vector_from_scalar_##TY; \ + break; + + SET_VDUP(v2i64) + SET_VDUP(v4i32) + SET_VDUP(v8i16) + SET_VDUP(v16i8) + SET_VDUP(v2u64) + SET_VDUP(v4u32) + SET_VDUP(v8u16) + SET_VDUP(v16u8) + SET_VDUP(v2f64) + SET_VDUP(v4f32) + SET_VDUP(v2i32) + SET_VDUP(v4i16) + SET_VDUP(v8i8) + SET_VDUP(v2u32) + SET_VDUP(v4u16) + SET_VDUP(v8u8) + SET_VDUP(v2f32) + case PTY_i64: + intrinsic = INTRN_vector_from_scalar_v1i64; + break; + case PTY_u64: + intrinsic = INTRN_vector_from_scalar_v1f64; + break; + case PTY_f64: + intrinsic = INTRN_vector_from_scalar_v1f64; + break; + default: + CHECK_FATAL(false, "Unhandled vector type in CreateExprVdupAnyVector"); + } + UniqueFEIRType feType = FEIRTypeHelper::CreateTypeNative(*GlobalTables::GetTypeTable().GetPrimType(primtype)); + std::vector> argOpnds; + argOpnds.push_back(std::move(subExpr)); + return std::make_unique(std::move(feType), intrinsic, argOpnds); +} + +// ---------- ASTUnaryOperatorExpr ---------- +void ASTUnaryOperatorExpr::SetUOExpr(ASTExpr *astExpr) { + expr = astExpr; +} + +void ASTUnaryOperatorExpr::SetSubType(MIRType *type) { + subType = type; +} + +UniqueFEIRExpr ASTUOMinusExpr::Emit2FEExprImpl(std::list &stmts) const { + ASTExpr *childExpr = expr; + CHECK_FATAL(childExpr != nullptr, "childExpr is nullptr"); + UniqueFEIRExpr childFEIRExpr = childExpr->Emit2FEExpr(stmts); + PrimType dstType = uoType->GetPrimType(); + CHECK_NULL_FATAL(subType); + if (childFEIRExpr->GetPrimType() != dstType) { + UniqueFEIRExpr minusExpr = std::make_unique( + FEIRTypeHelper::CreateTypeNative(*subType), OP_neg, std::move(childFEIRExpr)); + return FEIRBuilder::CreateExprCastPrim(std::move(minusExpr), dstType); + } + return std::make_unique(FEIRTypeHelper::CreateTypeNative(*subType), OP_neg, std::move(childFEIRExpr)); +} + +UniqueFEIRExpr ASTUOPlusExpr::Emit2FEExprImpl(std::list &stmts) const { + ASTExpr *childExpr = expr; + CHECK_FATAL(childExpr != nullptr, "childExpr is nullptr"); + UniqueFEIRExpr plusExpr = childExpr->Emit2FEExpr(stmts); + return plusExpr; +} + +UniqueFEIRExpr ASTUONotExpr::Emit2FEExprImpl(std::list &stmts) const { + ASTExpr *childExpr = expr; + CHECK_FATAL(childExpr != nullptr, "childExpr is nullptr"); + UniqueFEIRExpr childFEIRExpr = childExpr->Emit2FEExpr(stmts); + PrimType dstType = uoType->GetPrimType(); + CHECK_NULL_FATAL(subType); + if (childFEIRExpr->GetPrimType() != dstType) { + UniqueFEIRExpr notExpr = std::make_unique( + FEIRTypeHelper::CreateTypeNative(*subType), OP_bnot, std::move(childFEIRExpr)); + return FEIRBuilder::CreateExprCastPrim(std::move(notExpr), dstType); + } + return std::make_unique(FEIRTypeHelper::CreateTypeNative(*subType), OP_bnot, std::move(childFEIRExpr)); +} + +UniqueFEIRExpr ASTUOLNotExpr::Emit2FEExprImpl(std::list &stmts) const { + ASTExpr *childExpr = expr; + CHECK_FATAL(childExpr != nullptr, "childExpr is nullptr"); + childExpr->SetShortCircuitIdx(falseIdx, trueIdx); + UniqueFEIRExpr childFEIRExpr = childExpr->Emit2FEExpr(stmts); + if (childFEIRExpr != nullptr) { + return FEIRBuilder::CreateExprZeroCompare(OP_eq, std::move(childFEIRExpr)); + } + return childFEIRExpr; +} + +UniqueFEIRExpr ASTUnaryOperatorExpr::ASTUOSideEffectExpr(Opcode op, std::list &stmts, + const std::string &varName, bool post) const { + ASTExpr *childExpr = expr; + CHECK_FATAL(childExpr != nullptr, "childExpr is nullptr"); + UniqueFEIRExpr childFEIRExpr = childExpr->Emit2FEExpr(stmts); + UniqueFEIRVar tempVar; + if (post) { + tempVar = FEIRBuilder::CreateVarNameForC(varName, *subType); + UniqueFEIRStmt readSelfstmt = FEIRBuilder::CreateStmtDAssign(tempVar->Clone(), childFEIRExpr->Clone()); + readSelfstmt->SetDummy(); + stmts.emplace_back(std::move(readSelfstmt)); + } + + PrimType subPrimType = subType->GetPrimType(); + UniqueFEIRExpr subExpr = (subPrimType == PTY_ptr) ? std::make_unique(pointeeLen, PTY_i32) : + FEIRBuilder::CreateExprConstAnyScalar(subPrimType, 1); + UniqueFEIRExpr sideEffectExpr = FEIRBuilder::CreateExprMathBinary(op, childFEIRExpr->Clone(), std::move(subExpr)); + UniqueFEIRStmt sideEffectStmt = FEIRBuilder::AssginStmtField(childFEIRExpr->Clone(), std::move(sideEffectExpr), 0); + stmts.emplace_back(std::move(sideEffectStmt)); + + if (post) { + return FEIRBuilder::CreateExprDRead(std::move(tempVar)); + } + return childFEIRExpr; +} + +UniqueFEIRExpr ASTUOPostIncExpr::Emit2FEExprImpl(std::list &stmts) const { + return ASTUOSideEffectExpr(OP_add, stmts, tempVarName, true); +} + +UniqueFEIRExpr ASTUOPostDecExpr::Emit2FEExprImpl(std::list &stmts) const { + return ASTUOSideEffectExpr(OP_sub, stmts, tempVarName, true); +} + +UniqueFEIRExpr ASTUOPreIncExpr::Emit2FEExprImpl(std::list &stmts) const { + return ASTUOSideEffectExpr(OP_add, stmts); +} + +UniqueFEIRExpr ASTUOPreDecExpr::Emit2FEExprImpl(std::list &stmts) const { + return ASTUOSideEffectExpr(OP_sub, stmts); +} + +MIRConst *ASTUOAddrOfExpr::GenerateMIRConstImpl() const { + switch (expr->GetASTOp()) { + case kASTOpCompoundLiteralExpr: { + static_cast(expr)->SetAddrof(true); + return expr->GenerateMIRConst(); + } + case kASTOpRef: + case kASTSubscriptExpr: + case kASTMemberExpr: { + return expr->GenerateMIRConst(); + } + case kASTStringLiteral: { + return FEManager::GetModule().GetMemPool()->New( + expr->GetConstantValue()->val.strIdx, *GlobalTables::GetTypeTable().GetPrimType(PTY_a64)); + } + default: { + CHECK_FATAL(false, "lValue in expr: %d NIY", expr->GetASTOp()); + } + } + return nullptr; +} + +UniqueFEIRExpr ASTUOAddrOfExpr::Emit2FEExprImpl(std::list &stmts) const { + ASTExpr *childExpr = expr; + UniqueFEIRExpr addrOfExpr; + CHECK_FATAL(childExpr != nullptr, "childExpr is nullptr"); + UniqueFEIRExpr childFEIRExpr = childExpr->Emit2FEExpr(stmts); + if (childFEIRExpr->GetKind() == kExprDRead) { + addrOfExpr = std::make_unique( + static_cast(childFEIRExpr.get())->GetVar()->Clone(), childFEIRExpr->GetFieldID()); + } else if (childFEIRExpr->GetKind() == kExprIRead) { + auto ireadExpr = static_cast(childFEIRExpr.get()); + if (ireadExpr->GetFieldID() == 0) { + addrOfExpr = ireadExpr->GetClonedOpnd(); + ENCChecker::ReduceBoundaryChecking(stmts, addrOfExpr); + } else { + addrOfExpr = std::make_unique(ireadExpr->GetClonedPtrType(), ireadExpr->GetFieldID(), + ireadExpr->GetClonedOpnd()); + } + } else if (childFEIRExpr->GetKind() == kExprIAddrof || childFEIRExpr->GetKind() == kExprAddrofVar || + childFEIRExpr->GetKind() == kExprAddrofFunc || childFEIRExpr->GetKind() == kExprAddrof) { + return childFEIRExpr; + } else { + CHECK_FATAL(false, "unsupported expr kind %d", childFEIRExpr->GetKind()); + } + return addrOfExpr; +} + +// ---------- ASTUOAddrOfLabelExpr --------- +MIRConst *ASTUOAddrOfLabelExpr::GenerateMIRConstImpl() const { + return FEManager::GetMIRBuilder().GetCurrentFuncCodeMp()->New( + FEManager::GetMIRBuilder().GetOrCreateMIRLabel(labelName), + FEManager::GetMIRBuilder().GetCurrentFunction()->GetPuidx(), // GetCurrentFunction need to be optimized + *GlobalTables::GetTypeTable().GetVoidPtr()); // when parallel features +} + +UniqueFEIRExpr ASTUOAddrOfLabelExpr::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + return FEIRBuilder::CreateExprAddrofLabel(labelName, std::make_unique(*uoType)); +} + +UniqueFEIRExpr ASTUODerefExpr::Emit2FEExprImpl(std::list &stmts) const { + ASTExpr *childExpr = expr; + CHECK_FATAL(childExpr != nullptr, "childExpr is nullptr"); + UniqueFEIRExpr childFEIRExpr = childExpr->Emit2FEExpr(stmts); + UniqueFEIRType retType = std::make_unique(*uoType); + UniqueFEIRType ptrType = std::make_unique(*subType); + if (uoType->GetKind() == kTypePointer && + static_cast(uoType)->GetPointedType()->GetKind() == kTypeFunction) { + return childFEIRExpr; + } + InsertNonnullChecking(stmts, childFEIRExpr->Clone()); + if (InsertBoundaryChecking(stmts, childFEIRExpr->Clone())) { + childFEIRExpr->SetIsBoundaryChecking(true); + } + UniqueFEIRExpr derefExpr = FEIRBuilder::CreateExprIRead(std::move(retType), std::move(ptrType), + std::move(childFEIRExpr)); + return derefExpr; +} + +void ASTUODerefExpr::InsertNonnullChecking(std::list &stmts, UniqueFEIRExpr baseExpr) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic()) { + return; + } + if (baseExpr->GetPrimType() == PTY_ptr) { + UniqueFEIRStmt stmt = std::make_unique(OP_assertnonnull, std::move(baseExpr)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } +} + +UniqueFEIRExpr ASTUORealExpr::Emit2FEExprImpl(std::list &stmts) const { + ASTExpr *childExpr = expr; + ASTOp astOP = childExpr->GetASTOp(); + UniqueFEIRExpr subFEIRExpr; + if (astOP == kASTStringLiteral || astOP == kASTIntegerLiteral || astOP == kASTFloatingLiteral || + astOP == kASTCharacterLiteral || astOP == kASTImaginaryLiteral) { + subFEIRExpr = childExpr->Emit2FEExpr(stmts); + } else { + subFEIRExpr = childExpr->Emit2FEExpr(stmts); + FEIRNodeKind subNodeKind = subFEIRExpr->GetKind(); + if (subNodeKind == kExprIRead) { + static_cast(subFEIRExpr.get())->SetFieldID(kComplexRealID); + } else if (subNodeKind == kExprDRead) { + static_cast(subFEIRExpr.get())->SetFieldID(kComplexRealID); + UniqueFEIRType elementFEType = std::make_unique(*elementType); + static_cast(subFEIRExpr.get())->SetFieldType(std::move(elementFEType)); + } else { + CHECK_FATAL(false, "NIY"); + } + } + return subFEIRExpr; +} + +UniqueFEIRExpr ASTUOImagExpr::Emit2FEExprImpl(std::list &stmts) const { + ASTExpr *childExpr = expr; + ASTOp astOP = childExpr->GetASTOp(); + UniqueFEIRExpr subFEIRExpr; + if (astOP == kASTStringLiteral || astOP == kASTIntegerLiteral || astOP == kASTFloatingLiteral || + astOP == kASTCharacterLiteral || astOP == kASTImaginaryLiteral) { + subFEIRExpr = childExpr->Emit2FEExpr(stmts); + } else { + subFEIRExpr = childExpr->Emit2FEExpr(stmts); + FEIRNodeKind subNodeKind = subFEIRExpr->GetKind(); + if (subNodeKind == kExprIRead) { + static_cast(subFEIRExpr.get())->SetFieldID(kComplexImagID); + } else if (subNodeKind == kExprDRead) { + static_cast(subFEIRExpr.get())->SetFieldID(kComplexImagID); + UniqueFEIRType elementFEType = std::make_unique(*elementType); + static_cast(subFEIRExpr.get())->SetFieldType(std::move(elementFEType)); + } else { + CHECK_FATAL(false, "NIY"); + } + } + return subFEIRExpr; +} + +UniqueFEIRExpr ASTUOExtensionExpr::Emit2FEExprImpl(std::list &stmts) const { + return expr->Emit2FEExpr(stmts); +} + +UniqueFEIRExpr ASTUOCoawaitExpr::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + CHECK_FATAL(false, "C++ feature"); + return nullptr; +} + +// ---------- ASTPredefinedExpr ---------- +UniqueFEIRExpr ASTPredefinedExpr::Emit2FEExprImpl(std::list &stmts) const { + return child->Emit2FEExpr(stmts); +} + +void ASTPredefinedExpr::SetASTExpr(ASTExpr *astExpr) { + child = astExpr; +} + +// ---------- ASTOpaqueValueExpr ---------- +UniqueFEIRExpr ASTOpaqueValueExpr::Emit2FEExprImpl(std::list &stmts) const { + return child->Emit2FEExpr(stmts); +} + +void ASTOpaqueValueExpr::SetASTExpr(ASTExpr *astExpr) { + child = astExpr; +} + +// ---------- ASTBinaryConditionalOperator ---------- +UniqueFEIRExpr ASTBinaryConditionalOperator::Emit2FEExprImpl(std::list &stmts) const { + UniqueFEIRExpr condFEIRExpr = condExpr->Emit2FEExpr(stmts); + UniqueFEIRExpr trueFEIRExpr; + CHECK_NULL_FATAL(mirType); + // if a conditional expr is noncomparative, e.g., b = a ?: c + // the conditional expr will be use for trueExpr before it will be converted to comparative expr + if (!(condFEIRExpr->GetKind() == kExprBinary && static_cast(condFEIRExpr.get())->IsComparative())) { + trueFEIRExpr = condFEIRExpr->Clone(); + condFEIRExpr = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(condFEIRExpr)); + } else { + // if a conditional expr already is comparative (only return u1 val 0 or 1), e.g., b = (a < 0) ?: c + // the conditional expr will be assigned var used for comparative expr and true expr meanwhile + MIRType *condType = condFEIRExpr->GetType()->GenerateMIRTypeAuto(); + ASSERT_NOT_NULL(condType); + UniqueFEIRVar condVar = FEIRBuilder::CreateVarNameForC(FEUtils::GetSequentialName("condVal_"), *condType); + UniqueFEIRVar condVarCloned = condVar->Clone(); + UniqueFEIRVar condVarCloned2 = condVar->Clone(); + UniqueFEIRStmt condStmt = FEIRBuilder::CreateStmtDAssign(std::move(condVar), std::move(condFEIRExpr)); + stmts.emplace_back(std::move(condStmt)); + condFEIRExpr = FEIRBuilder::CreateExprDRead(std::move(condVarCloned)); + if (condType->GetPrimType() != mirType->GetPrimType()) { + trueFEIRExpr = FEIRBuilder::CreateExprCvtPrim(std::move(condVarCloned2), mirType->GetPrimType()); + } else { + trueFEIRExpr = FEIRBuilder::CreateExprDRead(std::move(condVarCloned2)); + } + } + std::list falseStmts; + UniqueFEIRExpr falseFEIRExpr = falseExpr->Emit2FEExpr(falseStmts); + // There are no extra nested statements in false expressions, (e.g., a < 1 ?: 2), use ternary FEIRExpr + if (falseStmts.empty()) { + UniqueFEIRType type = std::make_unique(*mirType); + return FEIRBuilder::CreateExprTernary(OP_select, std::move(type), std::move(condFEIRExpr), + std::move(trueFEIRExpr), std::move(falseFEIRExpr)); + } + // Otherwise, (e.g., a < 1 ?: a++) create a temporary var to hold the return trueExpr or falseExpr value + CHECK_FATAL(falseFEIRExpr->GetPrimType() == mirType->GetPrimType(), "The type of falseFEIRExpr are inconsistent"); + UniqueFEIRVar tempVar = FEIRBuilder::CreateVarNameForC(FEUtils::GetSequentialName("levVar_"), *mirType); + UniqueFEIRVar tempVarCloned1 = tempVar->Clone(); + UniqueFEIRVar tempVarCloned2 = tempVar->Clone(); + UniqueFEIRStmt retTrueStmt = FEIRBuilder::CreateStmtDAssign(std::move(tempVar), std::move(trueFEIRExpr)); + std::list trueStmts; + trueStmts.emplace_back(std::move(retTrueStmt)); + UniqueFEIRStmt retFalseStmt = FEIRBuilder::CreateStmtDAssign(std::move(tempVarCloned1), std::move(falseFEIRExpr)); + falseStmts.emplace_back(std::move(retFalseStmt)); + UniqueFEIRStmt stmtIf = FEIRBuilder::CreateStmtIf(std::move(condFEIRExpr), trueStmts, falseStmts); + stmts.emplace_back(std::move(stmtIf)); + return FEIRBuilder::CreateExprDRead(std::move(tempVarCloned2)); +} + +void ASTBinaryConditionalOperator::SetCondExpr(ASTExpr *expr) { + condExpr = expr; +} + +void ASTBinaryConditionalOperator::SetFalseExpr(ASTExpr *expr) { + falseExpr = expr; +} + +// ---------- ASTNoInitExpr ---------- +UniqueFEIRExpr ASTNoInitExpr::Emit2FEExprImpl(std::list &stmts) const { + return ImplicitInitFieldValue(noInitType, stmts); +} + +void ASTNoInitExpr::SetNoInitType(MIRType *type) { + noInitType = type; +} + +// ---------- ASTCompoundLiteralExpr ---------- +UniqueFEIRExpr ASTCompoundLiteralExpr::Emit2FEExprImpl(std::list &stmts) const { + UniqueFEIRExpr feirExpr; + if (child->GetASTOp() == kASTOpInitListExpr) { // other potential expr should concern + std::string tmpName = FEUtils::GetSequentialName("clvar_"); + static_cast(child)->SetInitListVarName(tmpName); + child->Emit2FEExpr(stmts); + UniqueFEIRVar tmpVar = FEIRBuilder::CreateVarNameForC(tmpName, *compoundLiteralType); + feirExpr = FEIRBuilder::CreateExprDRead(std::move(tmpVar)); + } else { + feirExpr = child->Emit2FEExpr(stmts); + } + return feirExpr; +} + +MIRConst *ASTCompoundLiteralExpr::GenerateMIRPtrConst() const { + CHECK_NULL_FATAL(compoundLiteralType); + const std::string tmpName = FEUtils::GetSequentialName("cle."); + // If a var is pointer type, agg value cannot be directly assigned to it + // Create a temporary symbol for addrof agg value + MIRSymbol *cleSymbol = FEManager::GetMIRBuilder().GetOrCreateGlobalDecl( + tmpName, *compoundLiteralType); + auto mirConst = child->GenerateMIRConst(); // InitListExpr in CompoundLiteral gen struct + cleSymbol->SetKonst(mirConst); + MIRAddrofConst *mirAddrofConst = FEManager::GetModule().GetMemPool()->New( + cleSymbol->GetStIdx(), 0, *compoundLiteralType); + return mirAddrofConst; +} + +MIRConst *ASTCompoundLiteralExpr::GenerateMIRConstImpl() const { + if (isAddrof) { + return GenerateMIRPtrConst(); + } + return child->GenerateMIRConst(); +} + +void ASTCompoundLiteralExpr::SetCompoundLiteralType(MIRType *clType) { + compoundLiteralType = clType; +} + +void ASTCompoundLiteralExpr::SetASTExpr(ASTExpr *astExpr) { + child = astExpr; +} + +// ---------- ASTOffsetOfExpr ---------- +void ASTOffsetOfExpr::SetStructType(MIRType *stype) { + structType = stype; +} + +void ASTOffsetOfExpr::SetFieldName(const std::string &fName) { + fieldName = fName; +} + +UniqueFEIRExpr ASTOffsetOfExpr::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + return FEIRBuilder::CreateExprConstU64(static_cast(offset)); +} + +// ---------- ASTInitListExpr ---------- +MIRConst *ASTInitListExpr::GenerateMIRConstImpl() const { + if (initListType->GetKind() == kTypeArray) { + return GenerateMIRConstForArray(); + } else if (initListType->GetKind() == kTypeStruct || initListType->GetKind() == kTypeUnion) { + return GenerateMIRConstForStruct(); + } else if (isTransparent) { + return initExprs[0]->GenerateMIRConst(); + } else { + CHECK_FATAL(false, "not handle now"); + } +} + +MIRConst *ASTInitListExpr::GenerateMIRConstForArray() const { + if (initExprs.size() == 1 && initExprs[0]->GetASTOp() == kASTStringLiteral) { + return initExprs[0]->GenerateMIRConst(); + } + MIRAggConst *aggConst = FEManager::GetModule().GetMemPool()->New(FEManager::GetModule(), *initListType); + CHECK_FATAL(initListType->GetKind() == kTypeArray, "Must be array type"); + auto arrayMirType = static_cast(initListType); + CHECK_FATAL(initExprs.size() <= arrayMirType->GetSizeArrayItem(0), "InitExpr size must less or equal array size"); + for (size_t i = 0; i < initExprs.size(); ++i) { + auto konst = initExprs[i]->GenerateMIRConst(); + if (konst == nullptr) { + return nullptr; + } + aggConst->AddItem(konst, 0); + } + if (HasArrayFiller()) { + auto fillerConst = arrayFillerExpr->GenerateMIRConst(); + for (uint32 i = initExprs.size(); i < arrayMirType->GetSizeArrayItem(0); ++i) { + aggConst->AddItem(fillerConst, 0); + } + } + return aggConst; +} + +MIRConst *ASTInitListExpr::GenerateMIRConstForStruct() const { + if (initExprs.empty()) { + return nullptr; // No var constant generation + } + bool hasFiller = false; + for (auto e : initExprs) { + if (e != nullptr) { + hasFiller = true; + break; + } + } + if (!hasFiller) { + return nullptr; + } + MIRAggConst *aggConst = FEManager::GetModule().GetMemPool()->New(FEManager::GetModule(), *initListType); + CHECK_FATAL(initExprs.size() <= UINT_MAX, "Too large elem size"); + for (uint32 i = 0; i < static_cast(initExprs.size()); ++i) { + if (initExprs[i] == nullptr) { + continue; + } + auto konst = initExprs[i]->GenerateMIRConst(); + if (konst->GetKind() == kConstLblConst) { + // init by initListExpr, Only MIRConst kind is set here. + return konst; + } + aggConst->AddItem(konst, i + 1); + } + ENCChecker::CheckNullFieldInGlobalStruct(*initListType, *aggConst, initExprs); + return aggConst; +} + +UniqueFEIRExpr ASTInitListExpr::Emit2FEExprImpl(std::list &stmts) const { + UniqueFEIRVar feirVar = FEIRBuilder::CreateVarNameForC(varName, *initListType); + if (initListType->GetKind() == MIRTypeKind::kTypeArray) { + UniqueFEIRExpr arrayExpr = FEIRBuilder::CreateExprAddrofVar(feirVar->Clone()); + auto base = std::variant, UniqueFEIRExpr>(arrayExpr->Clone()); + ProcessInitList(base, const_cast(this), stmts); + } else if (initListType->IsStructType()) { + auto base = std::variant, UniqueFEIRExpr>(std::make_pair(feirVar->Clone(), 0)); + ProcessInitList(base, const_cast(this), stmts); + } else if (isTransparent) { + CHECK_FATAL(initExprs.size() == 1, "Transparent init list size must be 1"); + return initExprs[0]->Emit2FEExpr(stmts); + } else if (hasVectorType) { + auto base = std::variant, UniqueFEIRExpr>(std::make_pair(feirVar->Clone(), 0)); + ProcessInitList(base, const_cast(this), stmts); + } else { + CHECK_FATAL(true, "Unsupported init list type"); + } + return nullptr; +} + +void ASTInitListExpr::ProcessInitList(std::variant, UniqueFEIRExpr> &base, + ASTInitListExpr *initList, + std::list &stmts) const { + if (initList->initListType->GetKind() == kTypeArray) { + if (std::holds_alternative(base)) { + ProcessArrayInitList(std::get(base)->Clone(), initList, stmts); + } else { + auto addrExpr = std::make_unique( + std::get>(base).first->Clone()); + addrExpr->SetFieldID(std::get>(base).second); + ProcessArrayInitList(addrExpr->Clone(), initList, stmts); + } + } else if (initList->initListType->GetKind() == kTypeStruct || initList->initListType->GetKind() == kTypeUnion) { + ProcessStructInitList(base, initList, stmts); + } else if (initList->isTransparent) { + CHECK_FATAL(initList->initExprs.size() == 1, "Transparent init list size must be 1"); + auto feExpr = initList->initExprs[0]->Emit2FEExpr(stmts); + MIRType *retType = initList->initListType; + MIRType *retPtrType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*retType); + UniqueFEIRType fePtrType = std::make_unique(*retPtrType); + if (std::holds_alternative(base)) { + auto stmt = FEIRBuilder::CreateStmtIAssign(fePtrType->Clone(), std::get(base)->Clone(), + feExpr->Clone(), 0); + stmts.emplace_back(std::move(stmt)); + } else { + UniqueFEIRVar feirVar = std::get>(base).first->Clone(); + FieldID fieldID = std::get>(base).second; + auto stmt = FEIRBuilder::CreateStmtDAssignAggField(feirVar->Clone(), feExpr->Clone(), fieldID); + stmts.emplace_back(std::move(stmt)); + } + } else if (initList->HasVectorType()) { + ProcessVectorInitList(base, initList, stmts); + } +} + +void ASTInitListExpr::ProcessStringLiteralInitList(const UniqueFEIRExpr &addrOfCharArray, + const UniqueFEIRExpr &addrOfStringLiteral, + size_t stringLength, std::list &stmts) const { + std::unique_ptr> argExprList = std::make_unique>(); + argExprList->emplace_back(addrOfCharArray->Clone()); + argExprList->emplace_back(addrOfStringLiteral->Clone()); + CHECK_FATAL(stringLength <= INT_MAX, "Too large length range"); + argExprList->emplace_back(FEIRBuilder::CreateExprConstI32(static_cast(stringLength))); + std::unique_ptr memcpyStmt = std::make_unique( + INTRN_C_memcpy, nullptr, nullptr, std::move(argExprList)); + stmts.emplace_back(std::move(memcpyStmt)); + + // Handling Implicit Initialization When Incomplete Initialization + if (addrOfCharArray->GetKind() != kExprAddrofArray) { + return; + } + auto type = static_cast(addrOfCharArray.get())->GetTypeArray()->Clone(); + MIRType *mirType = type->GenerateMIRType(); + if (mirType->GetKind() == kTypeArray) { + MIRArrayType *arrayType = static_cast(mirType); + if (arrayType->GetDim() != 2) { // only processing two-dimensional arrays. + return; + } + uint32 dimSize = arrayType->GetSizeArrayItem(1); + uint32 elemSize = arrayType->GetElemType()->GetSize(); + ProcessImplicitInit(addrOfCharArray->Clone(), stringLength, dimSize, elemSize, stmts); + } +} + +void ASTInitListExpr::ProcessImplicitInit(const UniqueFEIRExpr &addrExpr, uint32 initSize, + uint32 total, uint32 elemSize, std::list &stmts) const { + if (initSize >= total) { + return; + } + std::unique_ptr> argExprList = std::make_unique>(); + UniqueFEIRExpr realAddr = addrExpr->Clone(); + CHECK_FATAL(elemSize <= INT_MAX, "Too large elem size"); + CHECK_FATAL(initSize <= INT_MAX, "Too large init size"); + UniqueFEIRExpr elemSizeExpr = FEIRBuilder::CreateExprConstI32(static_cast(elemSize)); + if (initSize != 0) { + UniqueFEIRExpr initSizeExpr = FEIRBuilder::CreateExprConstI32(static_cast(initSize)); + if (elemSize != 1) { + initSizeExpr = FEIRBuilder::CreateExprBinary(OP_mul, std::move(initSizeExpr), elemSizeExpr->Clone()); + } + realAddr = FEIRBuilder::CreateExprBinary(OP_add, std::move(realAddr), initSizeExpr->Clone()); + } + argExprList->emplace_back(std::move(realAddr)); + argExprList->emplace_back(FEIRBuilder::CreateExprConstI32(0)); + UniqueFEIRExpr cntExpr = FEIRBuilder::CreateExprConstI32(static_cast(total - initSize)); + if (elemSize != 1) { + cntExpr = FEIRBuilder::CreateExprBinary(OP_mul, std::move(cntExpr), elemSizeExpr->Clone()); + } + argExprList->emplace_back(std::move(cntExpr)); + std::unique_ptr memsetStmt = std::make_unique( + INTRN_C_memset, nullptr, nullptr, std::move(argExprList)); + stmts.emplace_back(std::move(memsetStmt)); +} + +void ASTInitListExpr::ProcessDesignatedInitUpdater( + std::variant, UniqueFEIRExpr> &base, + ASTExpr *expr, std::list &stmts) const { + auto designatedInitUpdateExpr = static_cast(expr); + ASTExpr *baseExpr = designatedInitUpdateExpr->GetBaseExpr(); + ASTExpr *updaterExpr = designatedInitUpdateExpr->GetUpdaterExpr(); + auto feExpr = baseExpr->Emit2FEExpr(stmts); + if (std::holds_alternative(base)) { + MIRType *mirType = designatedInitUpdateExpr->GetInitListType(); + MIRType *mirPtrType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*mirType); + UniqueFEIRType fePtrType = std::make_unique(*mirPtrType); + auto stmt = FEIRBuilder::CreateStmtIAssign(fePtrType->Clone(), std::get(base)->Clone(), + feExpr->Clone(), 0); + stmts.emplace_back(std::move(stmt)); + } else { + UniqueFEIRVar feirVar = std::get>(base).first->Clone(); + FieldID fieldID = std::get>(base).second; + auto stmt = FEIRBuilder::CreateStmtDAssignAggField(feirVar->Clone(), feExpr->Clone(), fieldID); + stmts.emplace_back(std::move(stmt)); + } + ProcessInitList(base, static_cast(updaterExpr), stmts); +} + +void ASTInitListExpr::ProcessStructInitList(std::variant, UniqueFEIRExpr> &base, + ASTInitListExpr *initList, + std::list &stmts) const { + MIRType *baseStructMirPtrType = nullptr; + MIRStructType *baseStructMirType = nullptr; + UniqueFEIRType baseStructFEType = nullptr; + UniqueFEIRType baseStructFEPtrType = nullptr; + MIRStructType *curStructMirType = static_cast(initList->initListType); + UniqueFEIRVar var; + if (std::holds_alternative(base)) { + var = std::get(base)->GetVarUses().front()->Clone(); + baseStructMirType = static_cast(initList->initListType); + baseStructMirPtrType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*baseStructMirType); + baseStructFEType = FEIRTypeHelper::CreateTypeNative(*baseStructMirType); + baseStructFEPtrType = std::make_unique(*baseStructMirPtrType); + } else { + var = std::get>(base).first->Clone(); + baseStructFEType = var->GetType()->Clone(); + baseStructMirType = static_cast(baseStructFEType->GenerateMIRTypeAuto()); + baseStructMirPtrType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*baseStructMirType); + baseStructFEPtrType = std::make_unique(*baseStructMirPtrType); + } + + FieldID baseFieldID = 0; + if (!std::holds_alternative(base)) { + baseFieldID = std::get>(base).second; + } + + if (initList->initExprs.size() == 0) { + UniqueFEIRExpr addrOfExpr = std::make_unique(var->Clone(), 0); + ProcessImplicitInit(addrOfExpr->Clone(), 0, curStructMirType->GetSize(), 1, stmts); + return; + } + + uint32 curFieldTypeSize = 0; + uint32 offset = 0; + for (size_t i = 0; i < initList->initExprs.size(); ++i) { + if (initList->initExprs[i] == nullptr) { + continue; // skip anonymous field + } + + FieldID curFieldID = 0; + uint32 fieldIdx = (curStructMirType->GetKind() == kTypeUnion) ? initList->GetUnionInitFieldIdx() : i; + FEUtils::TraverseToNamedField(*curStructMirType, curStructMirType->GetElemStrIdx(fieldIdx), curFieldID); + uint32 fieldID = static_cast(baseFieldID + curFieldID); + MIRType *fieldMirType = curStructMirType->GetFieldType(curFieldID); + curFieldTypeSize = static_cast(fieldMirType->GetSize()); + offset += curFieldTypeSize; + + if (initList->initExprs[i]->GetASTOp() == kASTImplicitValueInitExpr && fieldMirType->GetPrimType() == PTY_agg) { + UniqueFEIRExpr addrOfExpr; + if (std::holds_alternative(base)) { + UniqueFEIRExpr offsetExpr = FEIRBuilder::CreateExprConstU32(offset - curFieldTypeSize); + addrOfExpr = FEIRBuilder::CreateExprBinary(OP_add, std::get(base)->Clone(), + std::move(offsetExpr)); + } else { + addrOfExpr = std::make_unique(var->Clone(), fieldID); + } + ProcessImplicitInit(addrOfExpr->Clone(), 0, fieldMirType->GetSize(), 1, stmts); + continue; + } + + if (initList->initExprs[i]->GetASTOp() == kASTOpInitListExpr || + initList->initExprs[i]->GetASTOp() == kASTASTDesignatedInitUpdateExpr) { + std::variant, UniqueFEIRExpr> subBase; + if (std::holds_alternative(base)) { + auto addrOfElemExpr = std::make_unique(baseStructFEPtrType->Clone(), fieldID, + std::get(base)->Clone()); + subBase = std::variant, UniqueFEIRExpr>(addrOfElemExpr->Clone()); + } else { + auto subVar = std::get>(base).first->Clone(); + subBase = std::variant, UniqueFEIRExpr>( + std::make_pair(subVar->Clone(), fieldID)); + } + if (initList->initExprs[i]->GetASTOp() == kASTOpInitListExpr) { + ProcessInitList(subBase, static_cast(initList->initExprs[i]), stmts); + } else { + ProcessDesignatedInitUpdater(subBase, static_cast(initList->initExprs[i]), stmts); + } + } else { + auto elemExpr = initList->initExprs[i]->Emit2FEExpr(stmts); + if (std::holds_alternative(base)) { + if (fieldMirType->GetKind() == kTypeArray && initList->initExprs[i]->GetASTOp() == kASTStringLiteral) { + auto addrOfElement = std::make_unique(baseStructFEPtrType->Clone(), fieldID, + std::get(base)->Clone()); + ProcessStringLiteralInitList(addrOfElement->Clone(), elemExpr->Clone(), + static_cast(initList->initExprs[i])->GetLength(), stmts); + } else { + auto stmt = std::make_unique(baseStructFEPtrType->Clone(), + std::get(base)->Clone(), + elemExpr->Clone(), + fieldID); + stmt->SetSrcFileInfo(initList->initExprs[i]->GetSrcFileIdx(), initList->initExprs[i]->GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + } else { + auto subVar = std::get>(base).first->Clone(); + if (fieldMirType->GetKind() == kTypeArray && initList->initExprs[i]->GetASTOp() == kASTStringLiteral) { + auto addrOfElement = std::make_unique(subVar->Clone()); + addrOfElement->SetFieldID(static_cast(fieldID)); + ProcessStringLiteralInitList(addrOfElement->Clone(), elemExpr->Clone(), + static_cast(initList->initExprs[i])->GetLength(), stmts); + } else { + auto stmt = std::make_unique(subVar->Clone(), elemExpr->Clone(), fieldID); + stmt->SetSrcFileInfo(initList->initExprs[i]->GetSrcFileIdx(), initList->initExprs[i]->GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + } + } + } + + // Handling Incomplete Union Initialization + if (curStructMirType->GetKind() == kTypeUnion) { + UniqueFEIRExpr addrOfExpr = std::make_unique(var->Clone(), 0); + ProcessImplicitInit(addrOfExpr->Clone(), curFieldTypeSize, + curStructMirType->GetSize(), 1, stmts); + } +} + +void ASTInitListExpr::ProcessArrayInitList(const UniqueFEIRExpr &addrOfArray, ASTInitListExpr *initList, + std::list &stmts) const { + auto arrayMirType = static_cast(initList->initListType); + UniqueFEIRType arrayFEType = FEIRTypeHelper::CreateTypeNative(*arrayMirType); + MIRType *elementType; + if (arrayMirType->GetDim() > 1) { + uint32 subSizeArray[arrayMirType->GetDim()]; + for (int dim = 1; dim < arrayMirType->GetDim(); ++dim) { + subSizeArray[dim - 1] = arrayMirType->GetSizeArrayItem(static_cast(dim)); + } + elementType = GlobalTables::GetTypeTable().GetOrCreateArrayType(*arrayMirType->GetElemType(), + static_cast(arrayMirType->GetDim() - 1), subSizeArray); + } else { + elementType = arrayMirType->GetElemType(); + } + auto elementPtrType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*elementType); + auto elementPtrFEType = FEIRTypeHelper::CreateTypeNative(*elementPtrType); + CHECK_FATAL(initExprs.size() <= INT_MAX, "invalid index"); + for (size_t i = 0; i < initList->initExprs.size(); ++i) { + std::list indexExprs; + UniqueFEIRExpr indexExpr = FEIRBuilder::CreateExprConstI32(static_cast(i)); + indexExprs.emplace_back(std::move(indexExpr)); + auto addrOfElemExpr = FEIRBuilder::CreateExprAddrofArray(arrayFEType->Clone(), addrOfArray->Clone(), "", + indexExprs); + if (initList->initExprs[i]->GetASTOp() == kASTOpInitListExpr) { + auto base = std::variant, UniqueFEIRExpr>(addrOfElemExpr->Clone()); + ProcessInitList(base, static_cast(initList->initExprs[i]), stmts); + } else { + UniqueFEIRExpr elemExpr = initList->initExprs[i]->Emit2FEExpr(stmts); + if (elementType->GetKind() == kTypeArray && initList->initExprs[i]->GetASTOp() == kASTStringLiteral) { + ProcessStringLiteralInitList(addrOfElemExpr->Clone(), elemExpr->Clone(), + static_cast(initList->initExprs[i])->GetLength(), stmts); + } else { + auto stmt = FEIRBuilder::CreateStmtIAssign(elementPtrFEType->Clone(), addrOfElemExpr->Clone(), + elemExpr->Clone(), + 0); + stmts.emplace_back(std::move(stmt)); + } + } + } + + // handling implicit initialization sections + auto allSize = arrayMirType->GetSize(); + auto elemSize = elementType->GetSize(); + CHECK_FATAL(elemSize != 0, "elemSize should not 0"); + auto allElemCnt = allSize / elemSize; + ProcessImplicitInit(addrOfArray->Clone(), initList->initExprs.size(), allElemCnt, elemSize, stmts); +} + +void ASTInitListExpr::ProcessVectorInitList(std::variant, UniqueFEIRExpr> &base, + ASTInitListExpr *initList, std::list &stmts) const { + UniqueFEIRType srcType = FEIRTypeHelper::CreateTypeNative(*initList->initListType); + if (std::holds_alternative(base)) { + CHECK_FATAL(false, "unsupported case"); + } else { + UniqueFEIRVar srcVar = std::get>(base).first->Clone(); + FieldID fieldID = std::get>(base).second; + UniqueFEIRExpr dreadVar; + if (fieldID != 0) { + dreadVar = FEIRBuilder::CreateExprDReadAggField(srcVar->Clone(), fieldID, srcType->Clone()); + } else { + dreadVar = FEIRBuilder::CreateExprDRead(srcVar->Clone()); + } + for (size_t index = 0; index < initList->initExprs.size(); ++index) { + UniqueFEIRExpr indexExpr = FEIRBuilder::CreateExprConstI32(index); + UniqueFEIRExpr elemExpr = initList->initExprs[index]->Emit2FEExpr(stmts); + std::vector> argOpnds; + argOpnds.push_back(std::move(elemExpr)); + argOpnds.push_back(dreadVar->Clone()); + argOpnds.push_back(std::move(indexExpr)); + UniqueFEIRExpr intrinsicExpr = std::make_unique( + srcType->Clone(), SetVectorSetLane(*initList->initListType), argOpnds); + auto stmt = FEIRBuilder::CreateStmtDAssignAggField(srcVar->Clone(), std::move(intrinsicExpr), fieldID); + stmts.emplace_back(std::move(stmt)); + } + } +} + +MIRIntrinsicID ASTInitListExpr::SetVectorSetLane(const MIRType &type) const { + MIRIntrinsicID Intrinsic; + switch (type.GetPrimType()) { +#define SETQ_LANE(TY) \ + case PTY_##TY: \ + Intrinsic = INTRN_vector_set_element_##TY; \ + break; + + SETQ_LANE(v2i64) + SETQ_LANE(v4i32) + SETQ_LANE(v8i16) + SETQ_LANE(v16i8) + SETQ_LANE(v2u64) + SETQ_LANE(v4u32) + SETQ_LANE(v8u16) + SETQ_LANE(v16u8) + SETQ_LANE(v2f64) + SETQ_LANE(v4f32) + SETQ_LANE(v2i32) + SETQ_LANE(v4i16) + SETQ_LANE(v8i8) + SETQ_LANE(v2u32) + SETQ_LANE(v4u16) + SETQ_LANE(v8u8) + SETQ_LANE(v2f32) + case PTY_i64: + Intrinsic = INTRN_vector_set_element_v1i64; + break; + case PTY_u64: + Intrinsic = INTRN_vector_set_element_v1u64; + break; + case PTY_f64: + Intrinsic = INTRN_vector_set_element_v1f64; + break; + default: + CHECK_FATAL(false, "Unhandled vector type"); + return INTRN_UNDEFINED; + } + return Intrinsic; +} + +void ASTInitListExpr::SetInitExprs(ASTExpr *astExpr) { + initExprs.emplace_back(astExpr); +} + +void ASTInitListExpr::SetInitListType(MIRType *type) { + initListType = type; +} + +// ---------- ASTImplicitValueInitExpr ---------- +MIRConst *ASTImplicitValueInitExpr::GenerateMIRConstImpl() const { + return FEUtils::CreateImplicitConst(mirType); +} + +UniqueFEIRExpr ASTImplicitValueInitExpr::Emit2FEExprImpl(std::list &stmts) const { + return ImplicitInitFieldValue(mirType, stmts); +} + +MIRConst *ASTStringLiteral::GenerateMIRConstImpl() const { + auto *arrayType = static_cast(mirType); + uint32 arraySize = arrayType->GetSizeArrayItem(0); + auto elemType = arrayType->GetElemType(); + auto *val = FEManager::GetModule().GetMemPool()->New(FEManager::GetModule(), *arrayType); + for (uint32 i = 0; i < arraySize; ++i) { + MIRConst *cst; + if (i < codeUnits.size()) { + cst = FEManager::GetModule().GetMemPool()->New(codeUnits[i], *elemType); + } else { + cst = FEManager::GetModule().GetMemPool()->New(0, *elemType); + } + val->PushBack(cst); + } + return val; +} + +UniqueFEIRExpr ASTStringLiteral::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + MIRType *elemType = static_cast(mirType)->GetElemType(); + UniqueFEIRExpr expr = std::make_unique(codeUnits, elemType, str); + CHECK_NULL_FATAL(expr); + return expr; +} + +// ---------- ASTArraySubscriptExpr ---------- +size_t ASTArraySubscriptExpr::CalculateOffset() const { + size_t offset = 0; + CHECK_FATAL(idxExpr->GetConstantValue() != nullptr, "Not constant value for constant initializer"); + offset += mirType->GetSize() * static_cast(idxExpr->GetConstantValue()->val.i64); + return offset; +} + +ASTExpr *ASTArraySubscriptExpr::FindFinalBase() const { + if (baseExpr->GetASTOp() == kASTSubscriptExpr) { + return static_cast(baseExpr)->FindFinalBase(); + } + return baseExpr; +} + +MIRConst *ASTArraySubscriptExpr::GenerateMIRConstImpl() const { + size_t offset = CalculateOffset(); + const ASTExpr *base = FindFinalBase(); + MIRConst *baseConst = base->GenerateMIRConst(); + if (baseConst->GetKind() == kConstStrConst) { + MIRStrConst *strConst = static_cast(baseConst); + std::string str = GlobalTables::GetUStrTable().GetStringFromStrIdx(strConst->GetValue()); + CHECK_FATAL(str.length() >= offset, "Invalid operation"); + str = str.substr(offset); + UStrIdx strIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(str); + return FEManager::GetModule().GetMemPool()->New( + strIdx, *GlobalTables::GetTypeTable().GetPrimType(PTY_a64)); + } else if (baseConst->GetKind() == kConstAddrof) { + MIRAddrofConst *konst = static_cast(baseConst); + CHECK_FATAL(offset <= INT_MAX, "Invalid operation"); + return FEManager::GetModule().GetMemPool()->New(konst->GetSymbolIndex(), konst->GetFieldID(), + konst->GetType(), konst->GetOffset() + static_cast(offset)); + } else { + CHECK_FATAL(false, "Unsupported MIRConst: %d", baseConst->GetKind()); + } +} + +bool ASTArraySubscriptExpr::CheckFirstDimIfZero(const MIRType *arrayType) const { + auto tmpArrayType = static_cast(arrayType); + uint32 size = tmpArrayType->GetSizeArrayItem(0); + uint32 oriDim = tmpArrayType->GetDim(); + if (size == 0 && oriDim >= 2) { // 2 is the array dim + return true; + } + return false; +} + +void ASTArraySubscriptExpr::InsertNonnullChecking(std::list &stmts, const UniqueFEIRExpr &indexExpr, + const UniqueFEIRExpr &baseAddrExpr) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || indexExpr->GetKind() != kExprConst) { + return; + } + if (FEIRBuilder::IsZeroConstExpr(indexExpr)) { // insert nonnull checking when ptr[0] + UniqueFEIRStmt stmt = std::make_unique(OP_assertnonnull, baseAddrExpr->Clone()); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } +} + +UniqueFEIRExpr ASTArraySubscriptExpr::Emit2FEExprImpl(std::list &stmts) const { + auto baseAddrFEExpr = baseExpr->Emit2FEExpr(stmts); + auto retFEType = std::make_unique(*mirType); + MIRType *arrayTypeOpt = arrayType; + bool isArrayTypeOpt = false; + if (arrayTypeOpt->GetKind() == kTypePointer && !isVLA) { + MIRPtrType *ptrTy = static_cast(arrayTypeOpt); + MIRType *pointedTy = ptrTy->GetPointedType(); + if (pointedTy->GetKind() == kTypeArray) { + MIRArrayType *pointedArrTy = static_cast(pointedTy); + std::vector sizeArray{1}; + for (uint32 i = 0; i < pointedArrTy->GetDim(); ++i) { + sizeArray.push_back(pointedArrTy->GetSizeArrayItem(i)); + } + MIRArrayType newArrTy(pointedArrTy->GetElemTyIdx(), sizeArray); + arrayTypeOpt = static_cast(GlobalTables::GetTypeTable().GetOrCreateMIRTypeNode(newArrTy)); + } else { + arrayTypeOpt = GlobalTables::GetTypeTable().GetOrCreateArrayType(*pointedTy, 1); + } + isArrayTypeOpt = true; + } + UniqueFEIRType arrayFEType = std::make_unique(*arrayTypeOpt); + auto mirPtrType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*mirType); + auto fePtrType = std::make_unique(*mirPtrType); + UniqueFEIRExpr addrOfArray; + if (arrayTypeOpt->GetKind() == MIRTypeKind::kTypeArray && !isVLA) { + if(CheckFirstDimIfZero(arrayTypeOpt)) { + // return multi-dim array addr directly if its first dim size was 0. + return baseAddrFEExpr; + } + std::list feIdxExprs; + if (baseAddrFEExpr->GetKind() == kExprAddrofArray && !isArrayTypeOpt) { + auto baseArrayExpr = static_cast(baseAddrFEExpr.get()); + for (auto &e : baseArrayExpr->GetExprIndexs()) { + feIdxExprs.emplace_back(e->Clone()); + } + arrayFEType = baseArrayExpr->GetTypeArray()->Clone(); + baseAddrFEExpr = baseArrayExpr->GetExprArray()->Clone(); + } + auto feIdxExpr = idxExpr->Emit2FEExpr(stmts); + if (isArrayTypeOpt) { + InsertNonnullChecking(stmts, feIdxExpr, baseAddrFEExpr); + } + feIdxExprs.emplace_back(std::move(feIdxExpr)); + addrOfArray = FEIRBuilder::CreateExprAddrofArray(arrayFEType->Clone(), baseAddrFEExpr->Clone(), "", feIdxExprs); + } else { + std::vector offsetExprs; + UniqueFEIRExpr offsetExpr; + auto feIdxExpr = idxExpr->Emit2FEExpr(stmts); + PrimType indexPty = feIdxExpr->GetPrimType(); + UniqueFEIRType sizeType; + if (IsSignedInteger(indexPty)) { + sizeType = std::make_unique(*GlobalTables::GetTypeTable().GetPrimType(PTY_i64)); + feIdxExpr = FEIRBuilder::CreateExprCvtPrim(std::move(feIdxExpr), GetRegPrimType(indexPty), PTY_i64); + } else { + sizeType = std::make_unique(*GlobalTables::GetTypeTable().GetPrimType(PTY_ptr)); + feIdxExpr = FEIRBuilder::CreateExprCvtPrim(std::move(feIdxExpr), + GetRegPrimType(indexPty), PTY_ptr); + } + if (mirType->GetSize() != 1) { + auto typeSizeExpr = std::make_unique(mirType->GetSize(), sizeType->GetPrimType()); + feIdxExpr = FEIRBuilder::CreateExprBinary(sizeType->Clone(), OP_mul, std::move(feIdxExpr), + std::move(typeSizeExpr)); + } + offsetExprs.emplace_back(std::move(feIdxExpr)); + if (offsetExprs.size() == 1) { + offsetExpr = std::move(offsetExprs[0]); + } else if (offsetExprs.size() >= 2) { + offsetExpr = FEIRBuilder::CreateExprBinary(sizeType->Clone(), OP_add, std::move(offsetExprs[0]), + std::move(offsetExprs[1])); + if (offsetExprs.size() >= 3) { + for (size_t i = 2; i < offsetExprs.size(); i++) { + offsetExpr = FEIRBuilder::CreateExprBinary(sizeType->Clone(), OP_add, std::move(offsetExpr), + std::move(offsetExprs[i])); + } + } + } + if (isVLA) { + baseAddrFEExpr = FEIRBuilder::CreateExprDRead(baseAddrFEExpr->GetVarUses().front()->Clone()); + } + addrOfArray = FEIRBuilder::CreateExprBinary(std::move(sizeType), OP_add, baseAddrFEExpr->Clone(), + std::move(offsetExpr)); + } + if (InsertBoundaryChecking(stmts, addrOfArray->Clone(), std::move(baseAddrFEExpr))) { + addrOfArray->SetIsBoundaryChecking(true); + } + return FEIRBuilder::CreateExprIRead(std::move(retFEType), fePtrType->Clone(), addrOfArray->Clone()); +} + +UniqueFEIRExpr ASTExprUnaryExprOrTypeTraitExpr::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + CHECK_FATAL(false, "NIY"); + return nullptr; +} + +MIRConst *ASTMemberExpr::GenerateMIRConstImpl() const { + uint64 fieldOffset = fieldOffsetBits / kOneByte; + ASTExpr *base = baseExpr; + while (base->GetASTOp() == kASTMemberExpr) { // find final BaseExpr and calculate FieldOffsets + ASTMemberExpr *memberExpr = static_cast(base); + fieldOffset += memberExpr->GetFieldOffsetBits() / kOneByte; + base = memberExpr->GetBaseExpr(); + } + MIRConst *baseConst = base->GenerateMIRConst(); + MIRAddrofConst *konst = nullptr; + if (baseConst->GetKind() == kConstAddrof) { + konst = static_cast(baseConst); + } else if (baseConst->GetKind() == kConstInt) { + return FEManager::GetModule().GetMemPool()->New(static_cast(fieldOffset), + *GlobalTables::GetTypeTable().GetInt64()); + } else { + CHECK_FATAL(false, "base const kind NYI."); + } + MIRType *baseStructType = + base->GetType()->IsMIRPtrType() ? static_cast(base->GetType())->GetPointedType() : + base->GetType(); + CHECK_FATAL(baseStructType->IsMIRStructType() || baseStructType->GetKind() == kTypeUnion, "Invalid"); + return FEManager::GetModule().GetMemPool()->New(konst->GetSymbolIndex(), konst->GetFieldID(), + konst->GetType(), konst->GetOffset() + static_cast(fieldOffset)); +} + +const ASTMemberExpr *ASTMemberExpr::FindFinalMember(const ASTMemberExpr *startExpr, + std::list &memberNames) const { + memberNames.emplace_back(startExpr->memberName); + if (startExpr->isArrow || startExpr->baseExpr->GetASTOp() != kASTMemberExpr) { + return startExpr; + } + return FindFinalMember(static_cast(startExpr->baseExpr), memberNames); +} + +void ASTMemberExpr::InsertNonnullChecking(std::list &stmts, UniqueFEIRExpr baseFEExpr) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic()) { + return; + } + if (baseFEExpr->GetPrimType() == PTY_ptr) { + UniqueFEIRStmt stmt = std::make_unique(OP_assertnonnull, std::move(baseFEExpr)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } +} + +UniqueFEIRExpr ASTMemberExpr::Emit2FEExprImpl(std::list &stmts) const { + UniqueFEIRExpr baseFEExpr; + std::string fieldName = memberName; + bool tmpIsArrow = this->isArrow; + MIRType *tmpBaseType = this->baseType; + if (baseExpr->GetASTOp() == kASTMemberExpr) { + std::list memberNameList; + memberNameList.emplace_back(memberName); + const ASTMemberExpr *finalMember = FindFinalMember(static_cast(baseExpr), memberNameList); + baseFEExpr = finalMember->baseExpr->Emit2FEExpr(stmts); + tmpIsArrow = finalMember->isArrow; + tmpBaseType = finalMember->baseType; + fieldName = ASTUtil::Join(memberNameList, "."); + } else { + baseFEExpr = baseExpr->Emit2FEExpr(stmts); + } + UniqueFEIRType baseFEType = std::make_unique(*tmpBaseType); + if (tmpIsArrow) { + CHECK_FATAL(tmpBaseType->IsMIRPtrType(), "Must be ptr type!"); + MIRPtrType *mirPtrType = static_cast(tmpBaseType); + MIRType *pointedMirType = mirPtrType->GetPointedType(); + CHECK_FATAL(pointedMirType->IsStructType(), "pointedMirType must be StructType"); + MIRStructType *structType = static_cast(pointedMirType); + FieldID fieldID = FEUtils::GetStructFieldID(structType, fieldName); + MIRType *reType = FEUtils::GetStructFieldType(structType, fieldID); + CHECK_FATAL(reType->GetPrimType() == memberType->GetPrimType(), "traverse fieldID error, type is inconsistent"); + UniqueFEIRType retFEType = std::make_unique(*reType); + if (retFEType->IsArray()) { + return std::make_unique(std::move(baseFEType), fieldID, std::move(baseFEExpr)); + } else { + InsertNonnullChecking(stmts, baseFEExpr->Clone()); + return FEIRBuilder::CreateExprIRead(std::move(retFEType), std::move(baseFEType), std::move(baseFEExpr), fieldID); + } + } else { + CHECK_FATAL(tmpBaseType->IsStructType(), "basetype must be StructType"); + MIRStructType *structType = static_cast(tmpBaseType); + FieldID fieldID = FEUtils::GetStructFieldID(structType, fieldName); + MIRType *reType = FEUtils::GetStructFieldType(structType, fieldID); + CHECK_FATAL(reType->GetPrimType() == memberType->GetPrimType(), "traverse fieldID error, type is inconsistent"); + UniqueFEIRType reFEType = std::make_unique(*reType); + FieldID baseID = baseFEExpr->GetFieldID(); + if (baseFEExpr->GetKind() == FEIRNodeKind::kExprIRead) { + baseFEExpr->SetFieldID(baseID + fieldID); + baseFEExpr->SetType(std::move(reFEType)); + return baseFEExpr; + } + UniqueFEIRVar tmpVar = static_cast(baseFEExpr.get())->GetVar()->Clone(); + if (reFEType->IsArray()) { + auto addrofExpr = std::make_unique(std::move(tmpVar)); + addrofExpr->SetFieldID(baseID + fieldID); + return addrofExpr; + } else { + return FEIRBuilder::CreateExprDReadAggField(std::move(tmpVar), baseID + fieldID, std::move(reFEType)); + } + } +} + +// ---------- ASTDesignatedInitUpdateExpr ---------- +MIRConst *ASTDesignatedInitUpdateExpr::GenerateMIRConstImpl() const { + return FEManager::GetModule().GetMemPool()->New(FEManager::GetModule(), *initListType); +} + +UniqueFEIRExpr ASTDesignatedInitUpdateExpr::Emit2FEExprImpl(std::list &stmts) const { + UniqueFEIRVar feirVar = FEIRBuilder::CreateVarNameForC(initListVarName, *initListType); + UniqueFEIRExpr baseFEIRExpr = baseExpr->Emit2FEExpr(stmts); + UniqueFEIRStmt baseFEIRStmt = std::make_unique(std::move(feirVar), std::move(baseFEIRExpr), 0); + stmts.emplace_back(std::move(baseFEIRStmt)); + static_cast(updaterExpr)->SetInitListVarName(initListVarName); + updaterExpr->Emit2FEExpr(stmts); + return nullptr; +} + +MIRConst *ASTBinaryOperatorExpr::GenerateMIRConstImpl() const { + MIRConst *leftConst = leftExpr->GenerateMIRConst(); + MIRConst *rightConst = nullptr; + if (opcode == OP_lior || opcode == OP_cior) { + if (!leftConst->IsZero()) { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst(1, + *GlobalTables::GetTypeTable().GetPrimType(PTY_i32)); + } else { + rightConst = rightExpr->GenerateMIRConst(); + if (!rightConst->IsZero()) { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst(1, + *GlobalTables::GetTypeTable().GetPrimType(PTY_i32)); + } else { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst(0, + *GlobalTables::GetTypeTable().GetPrimType(PTY_i32)); + } + } + } + rightConst = rightExpr->GenerateMIRConst(); + if (leftConst->GetKind() == kConstLblConst || rightConst->GetKind() == kConstLblConst) { + // if left or right is label mirconst, not currently implemented + return nullptr; + } + if (opcode == OP_land || opcode == OP_cand) { + if (leftConst->IsZero()) { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst(0, + *GlobalTables::GetTypeTable().GetPrimType(PTY_i32)); + } else if (rightConst->IsZero()) { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst(0, + *GlobalTables::GetTypeTable().GetPrimType(PTY_i32)); + } else { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst(1, + *GlobalTables::GetTypeTable().GetPrimType(PTY_i32)); + } + } + if (leftConst->GetKind() == rightConst->GetKind()) { + if (isConstantFolded) { + return value->Translate2MIRConst(); + } + switch (leftConst->GetKind()) { + case kConstInt: { + return MIRConstGenerator(FEManager::GetModule().GetMemPool(), static_cast(leftConst), + static_cast(rightConst), opcode); + } + case kConstFloatConst: { + return MIRConstGenerator(FEManager::GetModule().GetMemPool(), static_cast(leftConst), + static_cast(rightConst), opcode); + } + case kConstDoubleConst: { + return MIRConstGenerator(FEManager::GetModule().GetMemPool(), static_cast(leftConst), + static_cast(rightConst), opcode); + } + default: { + CHECK_FATAL(false, "Unsupported yet"); + return nullptr; + } + } + } + if (opcode == OP_add) { + MIRIntConst *constInt = nullptr; + MIRConst *baseConst = nullptr; + if (leftConst->GetKind() == kConstInt) { + constInt = static_cast(leftConst); + baseConst = rightConst; + } else if (rightConst->GetKind() == kConstInt) { + constInt = static_cast(rightConst); + baseConst = leftConst; + } else { + CHECK_FATAL(false, "Unsupported yet"); + } + int64 value = constInt->GetValue(); + if (baseConst->GetKind() == kConstStrConst) { + std::string str = + GlobalTables::GetUStrTable().GetStringFromStrIdx(static_cast(baseConst)->GetValue()); + CHECK_FATAL(str.length() >= static_cast(value), "Invalid operation"); + str = str.substr(static_cast(value)); + UStrIdx strIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(str); + return FEManager::GetModule().GetMemPool()->New( + strIdx, *GlobalTables::GetTypeTable().GetPrimType(PTY_a64)); + } else if (baseConst->GetKind() == kConstAddrof) { + MIRAddrofConst *konst = static_cast(baseConst); + auto idx = konst->GetSymbolIndex(); + auto id = konst->GetFieldID(); + auto ty = konst->GetType(); + auto offset = konst->GetOffset(); + return FEManager::GetModule().GetMemPool()->New(idx, id, ty, offset + value); + } else { + CHECK_FATAL(false, "NIY"); + } + } else if (opcode == OP_sub) { + CHECK_FATAL(leftConst->GetKind() == kConstAddrof && rightConst->GetKind() == kConstInt, "Unsupported"); + MIRAddrofConst *konst = static_cast(leftConst); + auto idx = konst->GetSymbolIndex(); + auto id = konst->GetFieldID(); + auto ty = konst->GetType(); + auto offset = konst->GetOffset(); + int64 value = static_cast(rightConst)->GetValue(); + return FEManager::GetModule().GetMemPool()->New(idx, id, ty, offset - value); + } else { + CHECK_FATAL(false, "NIY"); + } + return nullptr; +} + +UniqueFEIRType ASTBinaryOperatorExpr::SelectBinaryOperatorType(UniqueFEIRExpr &left, UniqueFEIRExpr &right) const { + // For arithmetical calculation only + std::map binaryTypePriority = { + {PTY_u1, 0}, + {PTY_i8, 1}, + {PTY_u8, 2}, + {PTY_i16, 3}, + {PTY_u16, 4}, + {PTY_i32, 5}, + {PTY_u32, 6}, + {PTY_i64, 7}, + {PTY_u64, 8}, + {PTY_f32, 9}, + {PTY_f64, 10} + }; + UniqueFEIRType feirType = std::make_unique(*retType); + if (!cvtNeeded) { + return feirType; + } + if (binaryTypePriority.find(left->GetPrimType()) == binaryTypePriority.end() || + binaryTypePriority.find(right->GetPrimType()) == binaryTypePriority.end()) { + if (left->GetPrimType() != feirType->GetPrimType()) { + left = FEIRBuilder::CreateExprCastPrim(std::move(left), feirType->GetPrimType()); + } + if (right->GetPrimType() != feirType->GetPrimType()) { + right = FEIRBuilder::CreateExprCastPrim(std::move(right), feirType->GetPrimType()); + } + return feirType; + } + MIRType *dstType; + if (binaryTypePriority[left->GetPrimType()] > binaryTypePriority[right->GetPrimType()]) { + right = FEIRBuilder::CreateExprCastPrim(std::move(right), left->GetPrimType()); + dstType = left->GetType()->GenerateMIRTypeAuto(); + } else { + left = FEIRBuilder::CreateExprCastPrim(std::move(left), right->GetPrimType()); + dstType = right->GetType()->GenerateMIRTypeAuto(); + } + return std::make_unique(*dstType); +} + +UniqueFEIRExpr ASTBinaryOperatorExpr::Emit2FEExprComplexCalculations(std::list &stmts) const { + UniqueFEIRVar tempVar = FEIRBuilder::CreateVarNameForC(FEUtils::GetSequentialName("Complex_"), *retType); + auto complexElementFEType = std::make_unique(*complexElementType); + UniqueFEIRExpr realFEExpr = FEIRBuilder::CreateExprBinary(complexElementFEType->Clone(), opcode, + leftRealExpr->Emit2FEExpr(stmts), + rightRealExpr->Emit2FEExpr(stmts)); + UniqueFEIRExpr imagFEExpr = FEIRBuilder::CreateExprBinary(complexElementFEType->Clone(), opcode, + leftImagExpr->Emit2FEExpr(stmts), + rightImagExpr->Emit2FEExpr(stmts)); + auto realStmt = FEIRBuilder::CreateStmtDAssignAggField(tempVar->Clone(), std::move(realFEExpr), kComplexRealID); + auto imagStmt = FEIRBuilder::CreateStmtDAssignAggField(tempVar->Clone(), std::move(imagFEExpr), kComplexImagID); + stmts.emplace_back(std::move(realStmt)); + stmts.emplace_back(std::move(imagStmt)); + auto dread = FEIRBuilder::CreateExprDRead(std::move(tempVar)); + static_cast(dread.get())->SetFieldType(std::move(complexElementFEType)); + return dread; +} + +UniqueFEIRExpr ASTBinaryOperatorExpr::Emit2FEExprComplexCompare(std::list &stmts) const { + auto boolFEType = std::make_unique(*GlobalTables::GetTypeTable().GetPrimType(PTY_i32)); + UniqueFEIRExpr realFEExpr = FEIRBuilder::CreateExprBinary(boolFEType->Clone(), opcode, + leftRealExpr->Emit2FEExpr(stmts), + rightRealExpr->Emit2FEExpr(stmts)); + UniqueFEIRExpr imagFEExpr = FEIRBuilder::CreateExprBinary(boolFEType->Clone(), opcode, + leftImagExpr->Emit2FEExpr(stmts), + rightImagExpr->Emit2FEExpr(stmts)); + UniqueFEIRExpr finalExpr; + if (opcode == OP_eq) { + finalExpr = FEIRBuilder::CreateExprBinary(boolFEType->Clone(), OP_land, std::move(realFEExpr), + std::move(imagFEExpr)); + } else { + finalExpr = FEIRBuilder::CreateExprBinary(boolFEType->Clone(), OP_lior, std::move(realFEExpr), + std::move(imagFEExpr)); + } + return finalExpr; +} + +UniqueFEIRExpr ASTBinaryOperatorExpr::Emit2FEExprLogicOperate(std::list &stmts) const { + bool inShortCircuit = true; + uint32 trueLabelIdx = trueIdx; + uint32 falseLabelIdx = falseIdx; + uint32 fallthrouLabelIdx, jumpToLabelIdx; + uint32 rightCondLabelIdx = FEUtils::GetSequentialNumber(); + MIRType *tempVarType = GlobalTables::GetTypeTable().GetUInt32(); + UniqueFEIRVar shortCircuit = FEIRBuilder::CreateVarNameForC(varName, *tempVarType); + + // check short circuit boundary + if (trueLabelIdx == 0) { + trueLabelIdx = FEUtils::GetSequentialNumber(); + falseLabelIdx = FEUtils::GetSequentialNumber(); + inShortCircuit = false; + } + + Opcode op = opcode == OP_cior ? OP_brtrue : OP_brfalse; + if (op == OP_brtrue) { + fallthrouLabelIdx = falseLabelIdx; + jumpToLabelIdx = trueLabelIdx; + leftExpr->SetShortCircuitIdx(jumpToLabelIdx, rightCondLabelIdx); + } else { + fallthrouLabelIdx = trueLabelIdx; + jumpToLabelIdx = falseLabelIdx; + leftExpr->SetShortCircuitIdx(rightCondLabelIdx, jumpToLabelIdx); + } + rightExpr->SetShortCircuitIdx(trueLabelIdx, falseLabelIdx); + + std::string rightCondLabel = FEUtils::GetSequentialName0("shortCircuit_", rightCondLabelIdx); + std::string fallthrouLabel = FEUtils::GetSequentialName0("shortCircuit_", fallthrouLabelIdx); + std::string jumpToLabel = FEUtils::GetSequentialName0("shortCircuit_", jumpToLabelIdx); + + // brfalse/brtrue label (leftCond) + auto leftFEExpr = leftExpr->Emit2FEExpr(stmts); + if (leftFEExpr != nullptr) { + auto leftCond = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(leftFEExpr)); + UniqueFEIRStmt leftCondGoToExpr = std::make_unique(leftCond->Clone(), op, jumpToLabel); + stmts.emplace_back(std::move(leftCondGoToExpr)); + } + + auto rightCondlabelStmt = std::make_unique(rightCondLabel); + rightCondlabelStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(rightCondlabelStmt)); + + // brfalse/brtrue label (rightCond) + auto rightFEExpr = rightExpr->Emit2FEExpr(stmts); + if (rightFEExpr != nullptr) { + auto rightCond = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(rightFEExpr)); + UniqueFEIRStmt rightCondGoToExpr = std::make_unique(rightCond->Clone(), op, jumpToLabel); + UniqueFEIRStmt goStmt = FEIRBuilder::CreateStmtGoto(fallthrouLabel); + stmts.emplace_back(std::move(rightCondGoToExpr)); + stmts.emplace_back(std::move(goStmt)); + } + + UniqueFEIRExpr returnValue(nullptr); + // when reaching the outer layer of a short circuit, return explicit value for each branch + if (!inShortCircuit) { + std::string nextLabel = FEUtils::GetSequentialName("shortCircuit_"); + UniqueFEIRExpr trueConst = FEIRBuilder::CreateExprConstAnyScalar(PTY_u32, 1); + UniqueFEIRExpr falseConst = FEIRBuilder::CreateExprConstAnyScalar(PTY_u32, 0); + UniqueFEIRStmt goStmt = FEIRBuilder::CreateStmtGoto(nextLabel); + auto trueCircuit = std::make_unique(shortCircuit->Clone(), std::move(trueConst), 0); + auto falseCircuit = std::make_unique(shortCircuit->Clone(), std::move(falseConst), 0); + auto labelFallthrouStmt = std::make_unique(fallthrouLabel); + auto labelJumpToStmt = std::make_unique(jumpToLabel); + auto labelNextStmt = std::make_unique(nextLabel); + labelJumpToStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + labelNextStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(labelFallthrouStmt)); + stmts.emplace_back(op == OP_brtrue ? std::move(falseCircuit) : std::move(trueCircuit)); + stmts.emplace_back(std::move(goStmt)); + stmts.emplace_back(std::move(labelJumpToStmt)); + stmts.emplace_back(op == OP_brtrue ? std::move(trueCircuit) : std::move(falseCircuit)); + stmts.emplace_back(std::move(labelNextStmt)); + returnValue = FEIRBuilder::CreateExprDRead(shortCircuit->Clone()); + } + return returnValue; +} + +UniqueFEIRExpr ASTBinaryOperatorExpr::Emit2FEExprLogicOperateSimplify(std::list &stmts) const { + std::list lStmts; + std::list cStmts; + std::list rStmts; + Opcode op = opcode == OP_cior ? OP_brtrue : OP_brfalse; + MIRType *tempVarType = GlobalTables::GetTypeTable().GetInt32(); + UniqueFEIRType tempFeirType = std::make_unique(*tempVarType); + UniqueFEIRVar shortCircuit = FEIRBuilder::CreateVarNameForC(varName, *tempVarType); + std::string labelName = FEUtils::GetSequentialName("shortCircuit_label_"); + auto leftFEExpr = leftExpr->Emit2FEExpr(lStmts); + leftFEExpr = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(leftFEExpr)); + auto leftStmt = std::make_unique(shortCircuit->Clone(), leftFEExpr->Clone(), 0); + cStmts.emplace_back(std::move(leftStmt)); + auto dreadExpr = FEIRBuilder::CreateExprDRead(shortCircuit->Clone()); + UniqueFEIRStmt condGoToExpr = std::make_unique(dreadExpr->Clone(), op, labelName); + cStmts.emplace_back(std::move(condGoToExpr)); + auto rightFEExpr = rightExpr->Emit2FEExpr(rStmts); + rightFEExpr = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(rightFEExpr)); + if (rStmts.empty()) { + stmts.splice(stmts.end(), lStmts); + UniqueFEIRType feirType = SelectBinaryOperatorType(leftFEExpr, rightFEExpr); + return FEIRBuilder::CreateExprBinary(std::move(feirType), opcode, std::move(leftFEExpr), std::move(rightFEExpr)); + } + auto rightStmt = std::make_unique(shortCircuit->Clone(), rightFEExpr->Clone(), 0); + rStmts.emplace_back(std::move(rightStmt)); + auto labelStmt = std::make_unique(labelName); + labelStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + rStmts.emplace_back(std::move(labelStmt)); + stmts.splice(stmts.end(), lStmts); + stmts.splice(stmts.end(), cStmts); + stmts.splice(stmts.end(), rStmts); + return FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(dreadExpr)); +} + +UniqueFEIRExpr ASTBinaryOperatorExpr::Emit2FEExprImpl(std::list &stmts) const { + if (complexElementType != nullptr) { + if (opcode == OP_add || opcode == OP_sub) { + return Emit2FEExprComplexCalculations(stmts); + } else if (opcode == OP_eq || opcode == OP_ne) { + return Emit2FEExprComplexCompare(stmts); + } else { + CHECK_FATAL(false, "NIY"); + } + } else { + if (opcode == OP_cior || opcode == OP_cand) { + if (FEOptions::GetInstance().IsSimplifyShortCircuit()) { + return Emit2FEExprLogicOperateSimplify(stmts); + } else { + return Emit2FEExprLogicOperate(stmts); + } + } else { + auto leftFEExpr = leftExpr->Emit2FEExpr(stmts); + auto rightFEExpr = rightExpr->Emit2FEExpr(stmts); + if (FEOptions::GetInstance().IsO2()) { + Ror ror(opcode, leftFEExpr, rightFEExpr); + auto rorExpr = ror.Emit2FEExpr(); + if (rorExpr != nullptr) { + return rorExpr; + } + } + UniqueFEIRType feirType = SelectBinaryOperatorType(leftFEExpr, rightFEExpr); + return FEIRBuilder::CreateExprBinary(std::move(feirType), opcode, std::move(leftFEExpr), std::move(rightFEExpr)); + } + } +} + +void ASTAssignExpr::GetActualRightExpr(UniqueFEIRExpr &right, const UniqueFEIRExpr &left) const { + if (right->GetPrimType() != left->GetPrimType() && + right->GetPrimType() != PTY_void && + right->GetPrimType() != PTY_agg) { + PrimType dstType = left->GetPrimType(); + if (right->GetPrimType() == PTY_f32 || right->GetPrimType() == PTY_f64) { + if (left->GetPrimType() == PTY_u8 || left->GetPrimType() == PTY_u16) { + dstType = PTY_u32; + } + if (left->GetPrimType() == PTY_i8 || left->GetPrimType() == PTY_i16) { + dstType = PTY_i32; + } + } + right = FEIRBuilder::CreateExprCastPrim(std::move(right), dstType); + } +} + +UniqueFEIRExpr ASTAssignExpr::Emit2FEExprImpl(std::list &stmts) const { + UniqueFEIRExpr rightFEExpr = rightExpr->Emit2FEExpr(stmts); // parse the right expr to generate stmt first + UniqueFEIRExpr leftFEExpr; + if (isCompoundAssign) { + std::list dummyStmts; + leftFEExpr = leftExpr->Emit2FEExpr(dummyStmts); + } else { + leftFEExpr = leftExpr->Emit2FEExpr(stmts); + } + // C89 does not support lvalue casting, but cxx support, needs to improve here + if (leftFEExpr->GetKind() == FEIRNodeKind::kExprDRead && !leftFEExpr->GetType()->IsArray()) { + auto dreadFEExpr = static_cast(leftFEExpr.get()); + FieldID fieldID = dreadFEExpr->GetFieldID(); + UniqueFEIRVar var = dreadFEExpr->GetVar()->Clone(); + if (ConditionalOptimize::DeleteRedundantTmpVar(rightFEExpr, stmts, var, leftFEExpr->GetPrimType(), fieldID)) { + return leftFEExpr; + } + GetActualRightExpr(rightFEExpr, leftFEExpr); + auto preStmt = std::make_unique(std::move(var), rightFEExpr->Clone(), fieldID); + stmts.emplace_back(std::move(preStmt)); + return leftFEExpr; + } else if (leftFEExpr->GetKind() == FEIRNodeKind::kExprIRead) { + auto ireadFEExpr = static_cast(leftFEExpr.get()); + FieldID fieldID = ireadFEExpr->GetFieldID(); + GetActualRightExpr(rightFEExpr, leftFEExpr); + auto preStmt = std::make_unique(ireadFEExpr->GetClonedPtrType(), ireadFEExpr->GetClonedOpnd(), + rightFEExpr->Clone(), fieldID); + stmts.emplace_back(std::move(preStmt)); + return leftFEExpr; + } + return nullptr; +} + +bool ASTAssignExpr::IsInsertNonnullChecking(const UniqueFEIRExpr &rExpr) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic()) { + return false; + } + // The pointer assignment + if (retType == nullptr || !(retType->IsMIRPtrType())) { + return false; + } + // The Rvalue is a pointer type + if ((rExpr->GetKind() == kExprDRead && rExpr->GetPrimType() == PTY_ptr) || + (rExpr->GetKind() == kExprIRead && rExpr->GetFieldID() != 0 && rExpr->GetPrimType() == PTY_ptr)) { + return true; + } + // The Rvalue is NULL + if (ENCChecker::HasNullExpr(rExpr)) { + return true; + } + return false; +} + +UniqueFEIRExpr ASTBOComma::Emit2FEExprImpl(std::list &stmts) const { + (void)leftExpr->Emit2FEExpr(stmts); + return rightExpr->Emit2FEExpr(stmts); +} + +UniqueFEIRExpr ASTBOPtrMemExpr::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + CHECK_FATAL(false, "NYI"); + return nullptr; +} + +// ---------- ASTParenExpr ---------- +UniqueFEIRExpr ASTParenExpr::Emit2FEExprImpl(std::list &stmts) const { + ASTExpr *childExpr = child; + CHECK_FATAL(childExpr != nullptr, "childExpr is nullptr"); + childExpr->SetShortCircuitIdx(trueIdx, falseIdx); + return childExpr->Emit2FEExpr(stmts); +} + +// ---------- ASTIntegerLiteral ---------- +MIRConst *ASTIntegerLiteral::GenerateMIRConstImpl() const { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst(val, *GlobalTables::GetTypeTable().GetPrimType(PTY_i64)); +} + +UniqueFEIRExpr ASTIntegerLiteral::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + UniqueFEIRExpr constExpr = std::make_unique(val, mirType->GetPrimType()); + return constExpr; +} + +// ---------- ASTFloatingLiteral ---------- +MIRConst *ASTFloatingLiteral::GenerateMIRConstImpl() const { + MemPool *mp = FEManager::GetModule().GetMemPool(); + MIRConst *cst; + MIRType *type; + if (kind == F32) { + type = GlobalTables::GetTypeTable().GetPrimType(PTY_f32); + cst = mp->New(static_cast(val), *type); + } else { + type = GlobalTables::GetTypeTable().GetPrimType(PTY_f64); + cst = mp->New(val, *type); + } + return cst; +} + +UniqueFEIRExpr ASTFloatingLiteral::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + UniqueFEIRExpr expr; + if (kind == F32) { + expr = FEIRBuilder::CreateExprConstF32(static_cast(val)); + } else { + expr = FEIRBuilder::CreateExprConstF64(val); + } + CHECK_NULL_FATAL(expr); + return expr; +} + +// ---------- ASTCharacterLiteral ---------- +UniqueFEIRExpr ASTCharacterLiteral::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + UniqueFEIRExpr constExpr = FEIRBuilder::CreateExprConstAnyScalar(type, val); + return constExpr; +} + +// ---------- ASTConditionalOperator ---------- +UniqueFEIRExpr ASTConditionalOperator::Emit2FEExprImpl(std::list &stmts) const { + UniqueFEIRExpr condFEIRExpr = condExpr->Emit2FEExpr(stmts); + // a noncomparative conditional expr need to be converted a comparative conditional expr + if (!(condFEIRExpr->GetKind() == kExprBinary && static_cast(condFEIRExpr.get())->IsComparative())) { + condFEIRExpr = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(condFEIRExpr)); + } + std::list trueStmts; + UniqueFEIRExpr trueFEIRExpr = trueExpr->Emit2FEExpr(trueStmts); + std::list falseStmts; + UniqueFEIRExpr falseFEIRExpr = falseExpr->Emit2FEExpr(falseStmts); + // when subExpr is void + if (trueFEIRExpr == nullptr || falseFEIRExpr == nullptr || mirType->GetPrimType() == PTY_void) { + UniqueFEIRStmt stmtIf = FEIRBuilder::CreateStmtIf(std::move(condFEIRExpr), trueStmts, falseStmts); + stmts.emplace_back(std::move(stmtIf)); + return nullptr; + } + // Otherwise, (e.g., a < 1 ? 1 : a++) create a temporary var to hold the return trueExpr or falseExpr value + MIRType *retType = mirType; + if (retType->GetKind() == kTypeBitField) { + retType = GlobalTables::GetTypeTable().GetPrimType(retType->GetPrimType()); + } + UniqueFEIRVar tempVar = FEIRBuilder::CreateVarNameForC(varName, *retType); + UniqueFEIRVar tempVarCloned1 = tempVar->Clone(); + UniqueFEIRVar tempVarCloned2 = tempVar->Clone(); + UniqueFEIRStmt retTrueStmt = FEIRBuilder::CreateStmtDAssign(std::move(tempVar), std::move(trueFEIRExpr)); + retTrueStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + trueStmts.emplace_back(std::move(retTrueStmt)); + UniqueFEIRStmt retFalseStmt = FEIRBuilder::CreateStmtDAssign(std::move(tempVarCloned1), std::move(falseFEIRExpr)); + retFalseStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + falseStmts.emplace_back(std::move(retFalseStmt)); + UniqueFEIRStmt stmtIf = FEIRBuilder::CreateStmtIf(std::move(condFEIRExpr), trueStmts, falseStmts); + stmts.emplace_back(std::move(stmtIf)); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(tempVarCloned2)); + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || !FEOptions::GetInstance().IsBoundaryCheckDynamic()) { + expr->SetKind(kExprTernary); + } + return expr; +} + +// ---------- ASTConstantExpr ---------- +UniqueFEIRExpr ASTConstantExpr::Emit2FEExprImpl(std::list &stmts) const { + return child->Emit2FEExpr(stmts); +} + +MIRConst *ASTConstantExpr::GenerateMIRConstImpl() const { + if (child->GetConstantValue() == nullptr || child->GetConstantValue()->GetPrimType() == PTY_begin) { + return child->GenerateMIRConst(); + } else { + return child->GetConstantValue()->Translate2MIRConst(); + } +} + +// ---------- ASTImaginaryLiteral ---------- +UniqueFEIRExpr ASTImaginaryLiteral::Emit2FEExprImpl(std::list &stmts) const { + CHECK_NULL_FATAL(complexType); + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(FEUtils::GetSequentialName("Complex_")); + UniqueFEIRVar complexVar = FEIRBuilder::CreateVarNameForC(nameIdx, *complexType); + UniqueFEIRVar clonedComplexVar = complexVar->Clone(); + UniqueFEIRVar clonedComplexVar2 = complexVar->Clone(); + // real number + UniqueFEIRExpr zeroConstExpr = FEIRBuilder::CreateExprConstAnyScalar(elemType->GetPrimType(), 0); + UniqueFEIRStmt realStmt = std::make_unique(std::move(complexVar), std::move(zeroConstExpr), 1); + stmts.emplace_back(std::move(realStmt)); + // imaginary number + CHECK_FATAL(child != nullptr, "childExpr is nullptr"); + UniqueFEIRExpr childFEIRExpr = child->Emit2FEExpr(stmts); + UniqueFEIRStmt imagStmt = std::make_unique(std::move(clonedComplexVar), std::move(childFEIRExpr), 2); + stmts.emplace_back(std::move(imagStmt)); + // return expr to parent operation + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(clonedComplexVar2)); + return expr; +} + +// ---------- ASTVAArgExpr ---------- +UniqueFEIRExpr ASTVAArgExpr::Emit2FEExprImpl(std::list &stmts) const { + CHECK_NULL_FATAL(mirType); + VaArgInfo info = ProcessValistArgInfo(*mirType); + UniqueFEIRExpr readVaList = child->Emit2FEExpr(stmts); + // The va_arg_offset temp var is created and assigned from __gr_offs or __vr_offs of va_list + MIRType *int32Type = GlobalTables::GetTypeTable().GetInt32(); + UniqueFEIRType int32FETRType = std::make_unique(*int32Type); + UniqueFEIRVar offsetVar = FEIRBuilder::CreateVarNameForC(FEUtils::GetSequentialName("va_arg_offs_"), *int32Type); + UniqueFEIRExpr dreadVaListOffset = FEIRBuilder::ReadExprField( + readVaList->Clone(), info.isGPReg ? 4 : 5, int32FETRType->Clone()); + UniqueFEIRStmt dassignOffsetVar = FEIRBuilder::CreateStmtDAssign(offsetVar->Clone(), dreadVaListOffset->Clone()); + stmts.emplace_back(std::move(dassignOffsetVar)); + UniqueFEIRExpr dreadOffsetVar = FEIRBuilder::CreateExprDRead(offsetVar->Clone()); + // The va_arg temp var is created and assigned in tow following way: + // If the va_arg_offs is vaild, i.e., its value should be (0 - (8 - named_arg) * 8) ~ 0, + // the va_arg will be got from GP or FP/SIMD arg reg, otherwise va_arg will be got from stack. + // See https://developer.arm.com/documentation/ihi0055/latest/?lang=en#the-va-arg-macro for more info + const std::string onStackStr = FEUtils::GetSequentialName("va_on_stack_"); + UniqueFEIRExpr cond1 = FEIRBuilder::CreateExprBinary( // checking validity: regOffs >= 0, goto on_stack + OP_ge, dreadOffsetVar->Clone(), FEIRBuilder::CreateExprConstI32(0)); + UniqueFEIRStmt condGoTo1 = std::make_unique(cond1->Clone(), OP_brtrue, onStackStr); + stmts.emplace_back(std::move(condGoTo1)); + // The va_arg set next reg setoff + UniqueFEIRExpr ArgAUnitOffs = FEIRBuilder::CreateExprBinary( + OP_add, dreadOffsetVar->Clone(), FEIRBuilder::CreateExprConstI32(info.regOffset)); + UniqueFEIRStmt assignArgNextOffs = FEIRBuilder::AssginStmtField( + readVaList->Clone(), std::move(ArgAUnitOffs), info.isGPReg ? 4 : 5); + stmts.emplace_back(std::move(assignArgNextOffs)); + UniqueFEIRExpr cond2 = FEIRBuilder::CreateExprBinary( // checking validity: regOffs + next offset > 0, goto on_stack + OP_gt, dreadVaListOffset->Clone(), FEIRBuilder::CreateExprConstI32(0)); + UniqueFEIRStmt condGoTo2 = std::make_unique(cond2->Clone(), OP_brtrue, onStackStr); + stmts.emplace_back(std::move(condGoTo2)); + // The va_arg will be got from GP or FP/SIMD arg reg + MIRType *sizeType = GlobalTables::GetTypeTable().GetPtrType(); + UniqueFEIRType sizeFEIRType = std::make_unique(*sizeType); + MIRType *vaArgType = !info.isCopyedMem ? mirType : sizeType; + MIRType *ptrType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*vaArgType); + UniqueFEIRVar vaArgVar = FEIRBuilder::CreateVarNameForC(FEUtils::GetSequentialName("va_arg_"), *ptrType); + UniqueFEIRExpr dreadVaArgTop = FEIRBuilder::ReadExprField( + readVaList->Clone(), info.isGPReg ? 2 : 3, sizeFEIRType->Clone()); + ProcessBigEndianForReg(stmts, *vaArgType, offsetVar, info); // process big endian for reg + UniqueFEIRExpr cvtOffset = FEIRBuilder::CreateExprCastPrim(dreadOffsetVar->Clone(), PTY_i64); + UniqueFEIRExpr addTopAndOffs = FEIRBuilder::CreateExprBinary(OP_add, std::move(dreadVaArgTop), std::move(cvtOffset)); + UniqueFEIRStmt dassignVaArgFromReg = FEIRBuilder::CreateStmtDAssign(vaArgVar->Clone(), std::move(addTopAndOffs)); + stmts.emplace_back(std::move(dassignVaArgFromReg)); + if (info.HFAType != nullptr && !info.isCopyedMem) { + CvtHFA2Struct(*static_cast(mirType), *info.HFAType, vaArgVar->Clone(), stmts); + } + const std::string endStr = FEUtils::GetSequentialName("va_end_"); + UniqueFEIRStmt goToEnd = FEIRBuilder::CreateStmtGoto(endStr); + stmts.emplace_back(std::move(goToEnd)); + // Otherwise, the va_arg will be got from stack and set next stack setoff + UniqueFEIRStmt onStackLabelStmt = std::make_unique(onStackStr); + stmts.emplace_back(std::move(onStackLabelStmt)); + UniqueFEIRExpr dreadStackTop = FEIRBuilder::ReadExprField(readVaList->Clone(), 1, sizeFEIRType->Clone()); + UniqueFEIRStmt dassignVaArgFromStack = FEIRBuilder::CreateStmtDAssign(vaArgVar->Clone(), dreadStackTop->Clone()); + UniqueFEIRExpr stackAUnitOffs = FEIRBuilder::CreateExprBinary( + OP_add, dreadStackTop->Clone(), FEIRBuilder::CreateExprConstPtr(info.stackOffset)); + stmts.emplace_back(std::move(dassignVaArgFromStack)); + UniqueFEIRStmt dassignStackNextOffs = FEIRBuilder::AssginStmtField( + readVaList->Clone(), std::move(stackAUnitOffs), 1); + stmts.emplace_back(std::move(dassignStackNextOffs)); + ProcessBigEndianForStack(stmts, *vaArgType, vaArgVar); // process big endian for stack + // return va_arg + UniqueFEIRStmt endLabelStmt = std::make_unique(endStr); + stmts.emplace_back(std::move(endLabelStmt)); + UniqueFEIRExpr dreadRetVar = FEIRBuilder::CreateExprDRead(vaArgVar->Clone()); + if (info.isCopyedMem) { + UniqueFEIRType ptrPtrFEIRType = std::make_unique( + *GlobalTables::GetTypeTable().GetOrCreatePointerType(*ptrType)); + dreadRetVar = FEIRBuilder::CreateExprIRead( + std::move(sizeFEIRType), std::move(ptrPtrFEIRType), std::move(dreadRetVar)); + } + UniqueFEIRType baseFEIRType = std::make_unique(*mirType); + UniqueFEIRType ptrFEIRType = std::make_unique(*ptrType); + UniqueFEIRExpr retExpr = FEIRBuilder::CreateExprIRead( + std::move(baseFEIRType), std::move(ptrFEIRType), std::move(dreadRetVar)); + return retExpr; +} + +void ASTVAArgExpr::ProcessBigEndianForReg(std::list &stmts, MIRType &vaArgType, + const UniqueFEIRVar &offsetVar, const VaArgInfo &info) const { + if (!FEOptions::GetInstance().IsBigEndian()) { + return; + } + int offset = 0; + if (info.isGPReg && !vaArgType.IsStructType() && vaArgType.GetSize() < 8) { // general reg + offset = 8 - static_cast(vaArgType.GetSize()); + } else if (info.HFAType != nullptr) { // HFA + offset = 16 - static_cast(info.HFAType->GetSize()); + } else if (!info.isGPReg && !vaArgType.IsStructType() && vaArgType.GetSize() < 16) { // fp/simd reg + offset = 16 - static_cast(vaArgType.GetSize()); + } + if (offset == 0) { + return; + } + UniqueFEIRExpr addExpr = FEIRBuilder::CreateExprBinary( + OP_add, FEIRBuilder::CreateExprDRead(offsetVar->Clone()), FEIRBuilder::CreateExprConstI32(offset)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(offsetVar->Clone(), std::move(addExpr)); + stmts.emplace_back(std::move(stmt)); +} + +void ASTVAArgExpr::ProcessBigEndianForStack(std::list &stmts, MIRType &vaArgType, + const UniqueFEIRVar &vaArgVar) const { + if (!FEOptions::GetInstance().IsBigEndian()) { + return; + } + int offset = 0; + if (!vaArgType.IsStructType() && vaArgType.GetSize() < 8) { + offset = 8 - static_cast(vaArgType.GetSize()); + } + if (offset == 0) { + return; + } + UniqueFEIRExpr addExpr = FEIRBuilder::CreateExprBinary( + OP_add, FEIRBuilder::CreateExprDRead(vaArgVar->Clone()), FEIRBuilder::CreateExprConstU64(offset)); + UniqueFEIRExpr dreadRetVar = FEIRBuilder::CreateExprDRead(vaArgVar->Clone()); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(vaArgVar->Clone(), std::move(addExpr)); + stmts.emplace_back(std::move(stmt)); +} + +VaArgInfo ASTVAArgExpr::ProcessValistArgInfo(const MIRType &type) const { + VaArgInfo info; + if (type.IsScalarType()) { + switch (type.GetPrimType()) { + case PTY_f32: // float is automatically promoted to double when passed to va_arg + WARN(kLncWarn, "error: float is promoted to double when passed to va_arg"); + case PTY_f64: // double + info = { false, 16, 8, false, nullptr }; + break; + case PTY_i32: + case PTY_u32: + case PTY_i64: + case PTY_u64: + info = { true, 8, 8, false, nullptr }; + break; + default: // bool, char, short, and unscoped enumerations are converted to int or wider integer types + WARN(kLncWarn, "error: bool, char, short, and unscoped enumerations are promoted to int or "\ + "wider integer types when passed to va_arg"); + info = { true, 8, 8, false, nullptr }; + break; + } + } else if (type.IsMIRPtrType()) { + info = { true, 8, 8, false, nullptr }; + } else if (type.IsStructType()) { + MIRStructType structType = static_cast(type); + size_t size = structType.GetSize(); + size = (size + 7) & -8; // size round up 8 + if (size > 16) { + info = { true, 8, 8, true, nullptr }; + } else { + MIRType *hfa = IsHFAType(structType); + if (hfa != nullptr) { + int fieldsNum = static_cast(structType.GetSize() / hfa->GetSize()); + info = { false, fieldsNum * 16, static_cast(size), false, hfa }; + } else { + info = { true, static_cast(size), static_cast(size), false, nullptr }; + } + } + } else { + CHECK_FATAL(false, "unsupport mirtype"); + } + return info; +} + +// Homogeneous Floating-point Aggregate: +// A data type with 2 to 4 identical floating-point members, either floats or doubles. +// (including 1 members here, struct nested array) +MIRType *ASTVAArgExpr::IsHFAType(const MIRStructType &type) const { + uint32 size = static_cast(type.GetFieldsSize()); + if (size < 1 || size > 4) { + return nullptr; + } + MIRType *firstType = nullptr; + for (uint32 i = 0; i < size; ++i) { + MIRType *fieldType = type.GetElemType(i); + if (fieldType->GetKind() == kTypeArray) { + MIRArrayType *arrayType = static_cast(fieldType); + MIRType *elemType = arrayType->GetElemType(); + if (elemType->GetPrimType() != PTY_f32 && elemType->GetPrimType() != PTY_f64) { + return nullptr; + } + fieldType = elemType; + } else if (fieldType->GetPrimType() != PTY_f32 && fieldType->GetPrimType() != PTY_f64) { + return nullptr; + } + if (firstType == nullptr) { + firstType = fieldType; + } else if (fieldType != firstType) { + return nullptr; + } + } + return firstType; +} + +// When va_arg is HFA struct, +// if it is passed as parameter in register then each uniquely addressable field goes in its own register. +// So its fields in FP/SIMD arg reg are still 128 bit and should be converted float or double type fields. +void ASTVAArgExpr::CvtHFA2Struct(const MIRStructType &type, MIRType &fieldType, const UniqueFEIRVar &vaArgVar, + std::list &stmts) const { + UniqueFEIRVar copyedVar = FEIRBuilder::CreateVarNameForC(FEUtils::GetSequentialName("va_arg_struct_"), *mirType); + MIRType *ptrMirType = GlobalTables::GetTypeTable().GetOrCreatePointerType(fieldType); + UniqueFEIRType baseType = std::make_unique(fieldType); + UniqueFEIRType ptrType = std::make_unique(*ptrMirType); + size_t size = type.GetSize() / fieldType.GetSize(); // fieldType must be nonzero + for (size_t i = 0; i < size; ++i) { + UniqueFEIRExpr dreadVaArg = FEIRBuilder::CreateExprDRead(vaArgVar->Clone()); + if (i != 0) { + dreadVaArg = FEIRBuilder::CreateExprBinary( + OP_add, std::move(dreadVaArg), FEIRBuilder::CreateExprConstPtr(static_cast(16 * i))); + } + UniqueFEIRExpr ireadVaArg = FEIRBuilder::CreateExprIRead(baseType->Clone(), ptrType->Clone(), dreadVaArg->Clone()); + UniqueFEIRExpr addrofVar = FEIRBuilder::CreateExprAddrofVar(copyedVar->Clone()); + if(i != 0) { + addrofVar = FEIRBuilder::CreateExprBinary( + OP_add, std::move(addrofVar), FEIRBuilder::CreateExprConstPtr(static_cast(fieldType.GetSize() * i))); + } + MIRType *fieldPtrType = GlobalTables::GetTypeTable().GetOrCreatePointerType(fieldType); + UniqueFEIRType fieldFEIRType = std::make_unique(*fieldPtrType); + UniqueFEIRStmt iassignCopyedVar = FEIRBuilder::CreateStmtIAssign( + std::move(fieldFEIRType), std::move(addrofVar), std::move(ireadVaArg)); + stmts.emplace_back(std::move(iassignCopyedVar)); + } + UniqueFEIRExpr addrofCopyedVar = FEIRBuilder::CreateExprAddrofVar(copyedVar->Clone()); + UniqueFEIRStmt assignVar = FEIRBuilder::CreateStmtDAssign(vaArgVar->Clone(), std::move(addrofCopyedVar)); + stmts.emplace_back(std::move(assignVar)); +} + +// ---------- ASTArrayInitLoopExpr ---------- +UniqueFEIRExpr ASTArrayInitLoopExpr::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + CHECK_FATAL(false, "NIY"); + return nullptr; +} + +// ---------- ASTArrayInitIndexExpr ---------- +UniqueFEIRExpr ASTArrayInitIndexExpr::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + CHECK_FATAL(false, "NIY"); + return nullptr; +} + +// ---------- ASTExprWithCleanups ---------- +UniqueFEIRExpr ASTExprWithCleanups::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + CHECK_FATAL(false, "NIY"); + return nullptr; +} + +// ---------- ASTMaterializeTemporaryExpr ---------- +UniqueFEIRExpr ASTMaterializeTemporaryExpr::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + CHECK_FATAL(false, "NIY"); + return nullptr; +} + +// ---------- ASTSubstNonTypeTemplateParmExpr ---------- +UniqueFEIRExpr ASTSubstNonTypeTemplateParmExpr::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + CHECK_FATAL(false, "NIY"); + return nullptr; +} + +// ---------- ASTDependentScopeDeclRefExpr ---------- +UniqueFEIRExpr ASTDependentScopeDeclRefExpr::Emit2FEExprImpl(std::list &stmts) const { + (void)stmts; + CHECK_FATAL(false, "NIY"); + return nullptr; +} + +// ---------- ASTAtomicExpr ---------- +UniqueFEIRExpr ASTAtomicExpr::Emit2FEExprImpl(std::list &stmts) const { + auto atomicExpr = std::make_unique(mirType, refType, objExpr->Emit2FEExpr(stmts), atomicOp); + if (atomicOp != kAtomicOpLoadN) { + static_cast(atomicExpr.get())->SetVal1Expr(valExpr1->Emit2FEExpr(stmts)); + static_cast(atomicExpr.get())->SetVal1Type(val1Type); + } + if (atomicOp == kAtomicOpExchange) { + static_cast(atomicExpr.get())->SetVal2Expr(valExpr2->Emit2FEExpr(stmts)); + static_cast(atomicExpr.get())->SetVal2Type(val2Type); + } + static_cast(atomicExpr.get())->SetOrderExpr(orderExpr->Emit2FEExpr(stmts)); + auto var = FEIRBuilder::CreateVarNameForC(FEUtils::GetSequentialName("ret.var."), *refType, false, false); + atomicExpr->SetValVar(var->Clone()); + if (!isFromStmt) { + auto stmt = std::make_unique(std::move(atomicExpr)); + stmts.emplace_back(std::move(stmt)); + return FEIRBuilder::CreateExprDRead(var->Clone()); + } + return atomicExpr; +} + +// ---------- ASTExprStmtExpr ---------- +UniqueFEIRExpr ASTExprStmtExpr::Emit2FEExprImpl(std::list &stmts) const { + std::list stmts0 = cpdStmt->Emit2FEStmt(); + for (auto &stmt : stmts0) { + stmts.emplace_back(std::move(stmt)); + } + CHECK_FATAL(cpdStmt->GetASTStmtOp() == kASTStmtCompound, "Invalid in ASTExprStmtExpr"); + stmts0.clear(); + auto *lastCpdStmt = static_cast(cpdStmt); + while (lastCpdStmt->GetASTStmtList().back()->GetASTStmtOp() == kASTStmtStmtExpr) { + auto bodyStmt = static_cast(lastCpdStmt->GetASTStmtList().back())->GetBodyStmt(); + lastCpdStmt = static_cast(bodyStmt); + } + if (lastCpdStmt->GetASTStmtList().size() != 0 && lastCpdStmt->GetASTStmtList().back()->GetExprs().size() != 0) { + UniqueFEIRExpr feirExpr = lastCpdStmt->GetASTStmtList().back()->GetExprs().back()->Emit2FEExpr(stmts0); + for (size_t i = 0; i < stmts0.size(); ++i) { + if (!stmts.empty()) { + stmts.pop_back(); + } + } + for (auto &stmt : stmts0) { + stmts.emplace_back(std::move(stmt)); + } + return feirExpr; + } + return nullptr; +} +} diff --git a/src/hir2mpl/ast_input/clang/src/ast_function.cpp b/src/hir2mpl/ast_input/clang/src/ast_function.cpp new file mode 100644 index 0000000000000000000000000000000000000000..381afbef3ab1e913461cd612d60991316d695433 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/src/ast_function.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ast_function.h" +#include "fe_macros.h" +#include "fe_manager.h" + +namespace maple { +ASTFunction::ASTFunction(const ASTFunc2FEHelper &argMethodHelper, MIRFunction &mirFunc, + const std::unique_ptr &argPhaseResultTotal) + : FEFunction(mirFunc, argPhaseResultTotal), + funcHelper(argMethodHelper), + astFunc(funcHelper.GetMethod()) {} + +bool ASTFunction::GenerateArgVarList(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + argVarList = astFunc.GenArgVarList(); + // EnhanceC: Initialize and assign args boundary + std::list boundaryStmts = astFunc.InitArgsBoundaryVar(mirFunction); + AppendFEIRStmts(boundaryStmts); + return phaseResult.Finish(); +} + +bool ASTFunction::GenerateAliasVars(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + return phaseResult.Finish(true); +} + +bool ASTFunction::EmitToFEIRStmt(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + std::list feirStmts = astFunc.EmitASTStmtToFEIR(); + if ((astFunc.GetSize() <= FEOptions::GetInstance().GetFuncInlineSize() && + !astFunc.GetGenericAttrs().GetAttr(GENATTR_noinline)) || astFunc.GetGenericAttrs().GetAttr(GENATTR_static)) { + FEManager::GetModule().AddOptFuncs(&mirFunction); + } + AppendFEIRStmts(feirStmts); + return phaseResult.Finish(true); +} + +void ASTFunction::PreProcessImpl() { + CHECK_FATAL(false, "NIY"); +} + +void ASTFunction::SetMIRFunctionInfo() { + GStrIdx idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(astFunc.GetName()); + mirFunction.PushbackMIRInfo(MIRInfoPair(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("INFO_fullname"), idx)); + mirFunction.PushbackIsString(true); +} + +bool ASTFunction::ProcessImpl() { + FE_INFO_LEVEL(FEOptions::kDumpLevelInfoDetail, "ASTFunction::Process() for %s", astFunc.GetName().c_str()); + bool success = true; + mirFunction.NewBody(); + FEManager::GetMIRBuilder().SetCurrentFunction(mirFunction); + FEManager::SetCurrentFEFunction(*this); + SetMIRFunctionInfo(); + success = success && GenerateArgVarList("gen arg var list"); + success = success && EmitToFEIRStmt("emit to feir"); + return success; +} + +bool ASTFunction::ProcessFEIRFunction() { + CHECK_FATAL(false, "NIY"); + return false; +} + +void ASTFunction::FinishImpl() { + if (FEOptions::GetInstance().IsDumpFEIRBB()) { + (void)LowerFunc("low feir func"); + (void)DumpFEIRBBs("dump bb list"); + } + if (FEOptions::GetInstance().IsDumpFEIRCFGGraph(GetGeneralFuncName())) { + (void)LowerFunc("low feir func"); + (void)DumpFEIRCFGGraph("dump cfg graph"); + } + (void)EmitToMIR("finish/emit to mir"); + (void)GenerateAliasVars("finish/generate alias vars"); +} + +bool ASTFunction::EmitToMIR(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + EmitToMIRStmt(); + return phaseResult.Finish(); +} +} // namespace maple diff --git a/src/hir2mpl/ast_input/clang/src/ast_parser.cpp b/src/hir2mpl/ast_input/clang/src/ast_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5ee499c80c46d595d2649c920ac566cd0a7183f9 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/src/ast_parser.cpp @@ -0,0 +1,2748 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ast_parser.h" +#include "mpl_logging.h" +#include "mir_module.h" +#include "mpl_logging.h" +#include "ast_decl_builder.h" +#include "ast_interface.h" +#include "ast_decl.h" +#include "ast_macros.h" +#include "ast_util.h" +#include "ast_input.h" +#include "fe_manager.h" +#include "enhance_c_checker.h" + +namespace maple { +std::map ASTDeclsBuilder::declesTable; + +bool ASTParser::OpenFile() { + astFile = std::make_unique(recordDecles); + bool res = astFile->Open(fileName, 0, 0); + if (!res) { + return false; + } + astUnitDecl = astFile->GetAstUnitDecl(); + return true; +} + +bool ASTParser::Verify() const { + return true; +} + +ASTBinaryOperatorExpr *ASTParser::AllocBinaryOperatorExpr(MapleAllocator &allocator, const clang::BinaryOperator &bo) { + if (bo.isAssignmentOp() && !bo.isCompoundAssignmentOp()) { + return ASTDeclsBuilder::ASTExprBuilder(allocator); + } + if (bo.getOpcode() == clang::BO_Comma) { + return ASTDeclsBuilder::ASTExprBuilder(allocator); + } + // [C++ 5.5] Pointer-to-member operators. + if (bo.isPtrMemOp()) { + return ASTDeclsBuilder::ASTExprBuilder(allocator); + } + MIRType *lhTy = astFile->CvtType(bo.getLHS()->getType()); + auto opcode = bo.getOpcode(); + if (bo.isCompoundAssignmentOp()) { + opcode = clang::BinaryOperator::getOpForCompoundAssignment(bo.getOpcode()); + } + Opcode mirOpcode = ASTUtil::CvtBinaryOpcode(opcode, lhTy->GetPrimType()); + CHECK_FATAL(mirOpcode != OP_undef, "Opcode not support!"); + auto *expr = ASTDeclsBuilder::ASTExprBuilder(allocator); + expr->SetOpcode(mirOpcode); + return expr; +} + +ASTStmt *ASTParser::ProcessFunctionBody(MapleAllocator &allocator, const clang::CompoundStmt &compoundStmt) { + CHECK_FATAL(false, "NIY"); + return ProcessStmtCompoundStmt(allocator, compoundStmt); +} + +ASTStmt *ASTParser::ProcessStmtCompoundStmt(MapleAllocator &allocator, const clang::CompoundStmt &cpdStmt) { + ASTCompoundStmt *astCompoundStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astCompoundStmt != nullptr, "astCompoundStmt is nullptr"); + clang::CompoundStmt::const_body_iterator it; + ASTStmt *childStmt = nullptr; + for (it = cpdStmt.body_begin(); it != cpdStmt.body_end(); ++it) { + childStmt = ProcessStmt(allocator, **it); + if (childStmt != nullptr) { + astCompoundStmt->SetASTStmt(childStmt); + } else { + continue; + } + } + + if (FEOptions::GetInstance().IsEnableSafeRegion()) { + switch (cpdStmt.getSafeSpecifier()) { + case clang::SS_None: + astCompoundStmt->SetSafeSS(kNoneSS); + break; + case clang::SS_Unsafe: + astCompoundStmt->SetSafeSS(kUnsafeSS); + break; + case clang::SS_Safe: + astCompoundStmt->SetSafeSS(kSafeSS); + break; + default: break; + } + } + return astCompoundStmt; +} + +#define STMT_CASE(CLASS) \ + case clang::Stmt::CLASS##Class: { \ + ASTStmt *astStmt = ProcessStmt##CLASS(allocator, llvm::cast(stmt)); \ + Pos loc = astFile->GetStmtLOC(stmt); \ + astStmt->SetSrcLOC(loc.first, loc.second); \ + return astStmt; \ + } + +ASTStmt *ASTParser::ProcessStmt(MapleAllocator &allocator, const clang::Stmt &stmt) { + switch (stmt.getStmtClass()) { + STMT_CASE(UnaryOperator); + STMT_CASE(BinaryOperator); + STMT_CASE(CompoundAssignOperator); + STMT_CASE(ImplicitCastExpr); + STMT_CASE(ParenExpr); + STMT_CASE(IntegerLiteral); + STMT_CASE(FloatingLiteral); + STMT_CASE(VAArgExpr); + STMT_CASE(ConditionalOperator); + STMT_CASE(CharacterLiteral); + STMT_CASE(StmtExpr); + STMT_CASE(CallExpr); + STMT_CASE(ReturnStmt); + STMT_CASE(CompoundStmt); + STMT_CASE(IfStmt); + STMT_CASE(ForStmt); + STMT_CASE(WhileStmt); + STMT_CASE(DoStmt); + STMT_CASE(BreakStmt); + STMT_CASE(LabelStmt); + STMT_CASE(ContinueStmt); + STMT_CASE(GotoStmt); + STMT_CASE(IndirectGotoStmt); + STMT_CASE(SwitchStmt); + STMT_CASE(CaseStmt); + STMT_CASE(DefaultStmt); + STMT_CASE(CStyleCastExpr); + STMT_CASE(DeclStmt); + STMT_CASE(NullStmt); + STMT_CASE(AtomicExpr); + STMT_CASE(GCCAsmStmt); + STMT_CASE(OffsetOfExpr); + STMT_CASE(GenericSelectionExpr); + STMT_CASE(AttributedStmt); + default: { + CHECK_FATAL(false, "ASTStmt: %s NIY", stmt.getStmtClassName()); + return nullptr; + } + } +} + +ASTStmt *ASTParser::ProcessStmtAttributedStmt(MapleAllocator &allocator, const clang::AttributedStmt &AttrStmt) { + ASSERT(clang::hasSpecificAttr(AttrStmt.getAttrs()), "AttrStmt is not fallthrough"); + ASTAttributedStmt *astAttributedStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astAttributedStmt != nullptr, "astAttributedStmt is nullptr"); + return astAttributedStmt; +} + +ASTStmt *ASTParser::ProcessStmtOffsetOfExpr(MapleAllocator &allocator, const clang::OffsetOfExpr &expr) { + auto *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &expr); + if (astExpr == nullptr) { + return nullptr; + } + astStmt->SetASTExpr(astExpr); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtGenericSelectionExpr(MapleAllocator &allocator, + const clang::GenericSelectionExpr &expr) { + auto *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &expr); + if (astExpr == nullptr) { + return nullptr; + } + astStmt->SetASTExpr(astExpr); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtUnaryOperator(MapleAllocator &allocator, const clang::UnaryOperator &unaryOp) { + ASTUnaryOperatorStmt *astUOStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astUOStmt != nullptr, "astUOStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &unaryOp); + if (astExpr == nullptr) { + return nullptr; + } + astUOStmt->SetASTExpr(astExpr); + return astUOStmt; +} + +ASTStmt *ASTParser::ProcessStmtBinaryOperator(MapleAllocator &allocator, const clang::BinaryOperator &binaryOp) { + ASTBinaryOperatorStmt *astBOStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astBOStmt != nullptr, "astBOStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &binaryOp); + if (astExpr == nullptr) { + return nullptr; + } + astBOStmt->SetASTExpr(astExpr); + return astBOStmt; +} + +ASTStmt *ASTParser::ProcessStmtCallExpr(MapleAllocator &allocator, const clang::CallExpr &callExpr) { + ASTCallExprStmt *astCallExprStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astCallExprStmt != nullptr, "astCallExprStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &callExpr); + if (astExpr == nullptr) { + return nullptr; + } + astCallExprStmt->SetASTExpr(astExpr); + return astCallExprStmt; +} + +ASTStmt *ASTParser::ProcessStmtImplicitCastExpr(MapleAllocator &allocator, + const clang::ImplicitCastExpr &implicitCastExpr) { + ASTImplicitCastExprStmt *astImplicitCastExprStmt = + ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astImplicitCastExprStmt != nullptr, "astImplicitCastExprStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &implicitCastExpr); + if (astExpr == nullptr) { + return nullptr; + } + astImplicitCastExprStmt->SetASTExpr(astExpr); + return astImplicitCastExprStmt; +} + +ASTStmt *ASTParser::ProcessStmtParenExpr(MapleAllocator &allocator, const clang::ParenExpr &parenExpr) { + ASTParenExprStmt *astParenExprStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astParenExprStmt != nullptr, "astCallExprStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &parenExpr); + if (astExpr == nullptr) { + return nullptr; + } + astParenExprStmt->SetASTExpr(astExpr); + return astParenExprStmt; +} + +ASTStmt *ASTParser::ProcessStmtIntegerLiteral(MapleAllocator &allocator, const clang::IntegerLiteral &integerLiteral) { + ASTIntegerLiteralStmt *astIntegerLiteralStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astIntegerLiteralStmt != nullptr, "astIntegerLiteralStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &integerLiteral); + if (astExpr == nullptr) { + return nullptr; + } + astIntegerLiteralStmt->SetASTExpr(astExpr); + return astIntegerLiteralStmt; +} + +ASTStmt *ASTParser::ProcessStmtFloatingLiteral(MapleAllocator &allocator, + const clang::FloatingLiteral &floatingLiteral) { + ASTFloatingLiteralStmt *astFloatingLiteralStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astFloatingLiteralStmt != nullptr, "astFloatingLiteralStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &floatingLiteral); + if (astExpr == nullptr) { + return nullptr; + } + astFloatingLiteralStmt->SetASTExpr(astExpr); + return astFloatingLiteralStmt; +} + +ASTStmt *ASTParser::ProcessStmtVAArgExpr(MapleAllocator &allocator, const clang::VAArgExpr &vAArgExpr) { + ASTVAArgExprStmt *astVAArgExprStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astVAArgExprStmt != nullptr, "astVAArgExprStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &vAArgExpr); + if (astExpr == nullptr) { + return nullptr; + } + astVAArgExprStmt->SetASTExpr(astExpr); + return astVAArgExprStmt; +} + +ASTStmt *ASTParser::ProcessStmtConditionalOperator(MapleAllocator &allocator, + const clang::ConditionalOperator &conditionalOperator) { + ASTConditionalOperatorStmt *astConditionalOperatorStmt = + ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astConditionalOperatorStmt != nullptr, "astConditionalOperatorStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &conditionalOperator); + if (astExpr == nullptr) { + return nullptr; + } + astConditionalOperatorStmt->SetASTExpr(astExpr); + return astConditionalOperatorStmt; +} + +ASTStmt *ASTParser::ProcessStmtCharacterLiteral(MapleAllocator &allocator, + const clang::CharacterLiteral &characterLiteral) { + ASTCharacterLiteralStmt *astCharacterLiteralStmt = + ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astCharacterLiteralStmt != nullptr, "astCharacterLiteralStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &characterLiteral); + if (astExpr == nullptr) { + return nullptr; + } + astCharacterLiteralStmt->SetASTExpr(astExpr); + return astCharacterLiteralStmt; +} + +ASTStmt *ASTParser::ProcessStmtCStyleCastExpr(MapleAllocator &allocator, const clang::CStyleCastExpr &cStyleCastExpr) { + ASTCStyleCastExprStmt *astCStyleCastExprStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astCStyleCastExprStmt != nullptr, "astCStyleCastExprStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &cStyleCastExpr); + if (astExpr == nullptr) { + return nullptr; + } + astCStyleCastExprStmt->SetASTExpr(astExpr); + return astCStyleCastExprStmt; +} + +ASTStmt *ASTParser::ProcessStmtStmtExpr(MapleAllocator &allocator, const clang::StmtExpr &stmtExpr) { + ASTStmtExprStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + const clang::CompoundStmt *cpdStmt = stmtExpr.getSubStmt(); + ASTStmt *astCompoundStmt = ProcessStmt(allocator, *cpdStmt); + astStmt->SetBodyStmt(astCompoundStmt); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtCompoundAssignOperator(MapleAllocator &allocator, + const clang::CompoundAssignOperator &cpdAssignOp) { + ASTCompoundAssignOperatorStmt *astCAOStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astCAOStmt != nullptr, "astCAOStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &cpdAssignOp); + if (astExpr == nullptr) { + return nullptr; + } + astCAOStmt->SetASTExpr(astExpr); + return astCAOStmt; +} + +ASTStmt *ASTParser::ProcessStmtAtomicExpr(MapleAllocator &allocator, const clang::AtomicExpr &atomicExpr) { + ASTAtomicExprStmt *astAtomicExprStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astAtomicExprStmt != nullptr, "astAtomicExprStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, &atomicExpr); + if (astExpr == nullptr) { + return nullptr; + } + static_cast(astExpr)->SetFromStmt(true); + astAtomicExprStmt->SetASTExpr(astExpr); + return astAtomicExprStmt; +} + +ASTStmt *ASTParser::ProcessStmtReturnStmt(MapleAllocator &allocator, const clang::ReturnStmt &retStmt) { + ASTReturnStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, retStmt.getRetValue()); + astStmt->SetASTExpr(astExpr); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtIfStmt(MapleAllocator &allocator, const clang::IfStmt &ifStmt) { + auto *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, ifStmt.getCond()); + if (astExpr == nullptr) { + return nullptr; + } + astStmt->SetCondExpr(astExpr); + ASTStmt *astThenStmt = nullptr; + const clang::Stmt *thenStmt = ifStmt.getThen(); + if (thenStmt->getStmtClass() == clang::Stmt::CompoundStmtClass) { + astThenStmt = ProcessStmt(allocator, *llvm::cast(thenStmt)); + } else { + astThenStmt = ProcessStmt(allocator, *thenStmt); + } + astStmt->SetThenStmt(astThenStmt); + if (ifStmt.hasElseStorage()) { + ASTStmt *astElseStmt = nullptr; + const clang::Stmt *elseStmt = ifStmt.getElse(); + if (elseStmt->getStmtClass() == clang::Stmt::CompoundStmtClass) { + astElseStmt = ProcessStmt(allocator, *llvm::cast(elseStmt)); + } else { + astElseStmt = ProcessStmt(allocator, *elseStmt); + } + astStmt->SetElseStmt(astElseStmt); + } + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtForStmt(MapleAllocator &allocator, const clang::ForStmt &forStmt) { + auto *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + if (forStmt.getInit() != nullptr) { + ASTStmt *initStmt = ProcessStmt(allocator, *forStmt.getInit()); + if (initStmt == nullptr) { + return nullptr; + } + astStmt->SetInitStmt(initStmt); + } + if (forStmt.getCond() != nullptr) { + ASTExpr *condExpr = ProcessExpr(allocator, forStmt.getCond()); + if (condExpr == nullptr) { + return nullptr; + } + astStmt->SetCondExpr(condExpr); + } + if (forStmt.getInc() != nullptr) { + ASTExpr *incExpr = ProcessExpr(allocator, forStmt.getInc()); + if (incExpr == nullptr) { + return nullptr; + } + astStmt->SetIncExpr(incExpr); + } + ASTStmt *bodyStmt = nullptr; + if (forStmt.getBody()->getStmtClass() == clang::Stmt::CompoundStmtClass) { + const auto *tmpCpdStmt = llvm::cast(forStmt.getBody()); + bodyStmt = ProcessStmt(allocator, *tmpCpdStmt); + } else { + bodyStmt = ProcessStmt(allocator, *forStmt.getBody()); + } + astStmt->SetBodyStmt(bodyStmt); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtWhileStmt(MapleAllocator &allocator, const clang::WhileStmt &whileStmt) { + ASTWhileStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + ASTExpr *condExpr = ProcessExpr(allocator, whileStmt.getCond()); + if (condExpr == nullptr) { + return nullptr; + } + astStmt->SetCondExpr(condExpr); + ASTStmt *bodyStmt = ProcessStmt(allocator, *whileStmt.getBody()); + astStmt->SetBodyStmt(bodyStmt); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtGotoStmt(MapleAllocator &allocator, const clang::GotoStmt &gotoStmt) { + ASTGotoStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + std::string name; + if (gotoStmt.getLabel() != nullptr) { + ASTDecl *astDecl = ProcessDecl(allocator, *gotoStmt.getLabel()); + name = astDecl->GetName(); + } else { + name = gotoStmt.getLabel()->getStmt()->getName(); + } + astStmt->SetLabelName(name); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtIndirectGotoStmt(MapleAllocator &allocator, const clang::IndirectGotoStmt &iGotoStmt) { + ASTIndirectGotoStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + astStmt->SetASTExpr(ProcessExpr(allocator, iGotoStmt.getTarget())); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtGCCAsmStmt(MapleAllocator &allocator, const clang::GCCAsmStmt &asmStmt) { + ASTGCCAsmStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + astStmt->SetAsmStr(asmStmt.generateAsmString(*(astFile->GetAstContext()))); + // set output + for (unsigned i = 0; i < asmStmt.getNumOutputs(); ++i) { + bool isPlusConstraint = asmStmt.isOutputPlusConstraint(i); + astStmt->InsertOutput(std::make_tuple(asmStmt.getOutputName(i).str(), + asmStmt.getOutputConstraint(i).str(), isPlusConstraint)); + astStmt->SetASTExpr(ProcessExpr(allocator, asmStmt.getOutputExpr(i))); + } + // set input + for (unsigned i = 0; i < asmStmt.getNumInputs(); ++i) { + astStmt->InsertInput(std::make_pair(asmStmt.getInputName(i).str(), asmStmt.getInputConstraint(i).str())); + astStmt->SetASTExpr(ProcessExpr(allocator, asmStmt.getInputExpr(i))); + } + // set clobbers + for (unsigned i = 0; i < asmStmt.getNumClobbers(); ++i) { + astStmt->InsertClobber(asmStmt.getClobber(i).str()); + } + // set label + for (unsigned i = 0; i < asmStmt.getNumLabels(); ++i) { + astStmt->InsertLabel(asmStmt.getLabelName(i).str()); + } + // set goto/volatile flag + if (asmStmt.isVolatile()) { + astStmt->SetIsVolatile(true); + } + if (asmStmt.isAsmGoto()) { + astStmt->SetIsGoto(true); + } + return astStmt; +} + +bool ASTParser::HasDefault(const clang::Stmt &stmt) { + if (llvm::isa(stmt)) { + return true; + } else if (llvm::isa(stmt)) { + const auto *cpdStmt = llvm::cast(&stmt); + clang::CompoundStmt::const_body_iterator it; + for (it = cpdStmt->body_begin(); it != cpdStmt->body_end(); ++it) { + if (llvm::isa(*it)) { + return true; + } else if (llvm::isa(*it)) { + auto *caseStmt = llvm::cast(*it); + if (HasDefault(*caseStmt->getSubStmt())) { + return true; + } + } + } + } else if (llvm::isa(stmt)) { + const auto *caseStmt = llvm::cast(&stmt); + if (HasDefault(*caseStmt->getSubStmt())) { + return true; + } + } + return false; +} + +ASTStmt *ASTParser::ProcessStmtSwitchStmt(MapleAllocator &allocator, const clang::SwitchStmt &switchStmt) { + // if switch cond expr has var decl, we need to handle it. + ASTSwitchStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + ASTStmt *condStmt = switchStmt.getConditionVariableDeclStmt() == nullptr ? nullptr : + ProcessStmt(allocator, *switchStmt.getConditionVariableDeclStmt()); + astStmt->SetCondStmt(condStmt); + // switch cond expr + ASTExpr *condExpr = switchStmt.getCond() == nullptr ? nullptr : ProcessExpr(allocator, switchStmt.getCond()); + if (condExpr != nullptr) { + astStmt->SetCondType(astFile->CvtType(switchStmt.getCond()->getType())); + } + astStmt->SetCondExpr(condExpr); + // switch body stmt + ASTStmt *bodyStmt = switchStmt.getBody() == nullptr ? nullptr : + ProcessStmt(allocator, *switchStmt.getBody()); + astStmt->SetBodyStmt(bodyStmt); + astStmt->SetHasDefault(HasDefault(*switchStmt.getBody())); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtDoStmt(MapleAllocator &allocator, const clang::DoStmt &doStmt) { + ASTDoStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + ASTExpr *condExpr = ProcessExpr(allocator, doStmt.getCond()); + if (condExpr == nullptr) { + return nullptr; + } + astStmt->SetCondExpr(condExpr); + ASTStmt *bodyStmt = ProcessStmt(allocator, *doStmt.getBody()); + astStmt->SetBodyStmt(bodyStmt); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtBreakStmt(MapleAllocator &allocator, const clang::BreakStmt &breakStmt) { + (void)breakStmt; + auto *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtLabelStmt(MapleAllocator &allocator, const clang::LabelStmt &stmt) { + auto *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + std::string name; + ASTStmt *astSubStmt = ProcessStmt(allocator, *stmt.getSubStmt()); + if (stmt.getDecl() != nullptr) { + ASTDecl *astDecl = ProcessDecl(allocator, *stmt.getDecl()); + name = astDecl->GetName(); + } else { + name = stmt.getName(); + } + astStmt->SetLabelName(name); + astStmt->SetSubStmt(astSubStmt); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtCaseStmt(MapleAllocator &allocator, const clang::CaseStmt &caseStmt) { + ASTCaseStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + astStmt->SetLHS(ProcessExpr(allocator, caseStmt.getLHS())); + astStmt->SetRHS(ProcessExpr(allocator, caseStmt.getRHS())); + clang::Expr::EvalResult resL; + (void)caseStmt.getLHS()->EvaluateAsInt(resL, *astFile->GetAstContext()); + astStmt->SetLCaseTag(resL.Val.getInt().getExtValue()); + if (caseStmt.getRHS() != nullptr) { + clang::Expr::EvalResult resR; + (void)caseStmt.getLHS()->EvaluateAsInt(resR, *astFile->GetAstContext()); + astStmt->SetRCaseTag(resR.Val.getInt().getExtValue()); + } else { + astStmt->SetRCaseTag(resL.Val.getInt().getExtValue()); + } + ASTStmt* subStmt = caseStmt.getSubStmt() == nullptr ? nullptr : ProcessStmt(allocator, *caseStmt.getSubStmt()); + astStmt->SetSubStmt(subStmt); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtDefaultStmt(MapleAllocator &allocator, const clang::DefaultStmt &defaultStmt) { + ASTDefaultStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + auto *subStmt = defaultStmt.getSubStmt() == nullptr ? nullptr : ProcessStmt(allocator, *defaultStmt.getSubStmt()); + astStmt->SetChildStmt(subStmt); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtNullStmt(MapleAllocator &allocator, const clang::NullStmt &nullStmt) { + (void)nullStmt; + ASTNullStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtContinueStmt(MapleAllocator &allocator, const clang::ContinueStmt &continueStmt) { + (void)continueStmt; + auto *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + return astStmt; +} + +ASTStmt *ASTParser::ProcessStmtDeclStmt(MapleAllocator &allocator, const clang::DeclStmt &declStmt) { + ASTDeclStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + if (declStmt.isSingleDecl()) { + const clang::Decl *decl = declStmt.getSingleDecl(); + if (decl != nullptr) { + ASTDecl *ad = ProcessDecl(allocator, *decl); + if (decl->getKind() == clang::Decl::Var) { + const clang::VarDecl *varDecl = llvm::cast(decl); + ASTExpr *expr = ProcessExprInType(allocator, varDecl->getType()); + if (expr != nullptr) { + astStmt->SetASTExpr(expr); + } + } + // extern func decl in function + if (decl->getKind() == clang::Decl::Function) { + astFuncs.emplace_back(static_cast(ad)); + } + if (ad != nullptr) { + astStmt->SetSubDecl(ad); + } + } + } else { + // multiple decls + clang::DeclGroupRef declGroupRef = declStmt.getDeclGroup(); + clang::DeclGroupRef::const_iterator it; + for (it = declGroupRef.begin(); it != declGroupRef.end(); ++it) { + ASTDecl *ad = ProcessDecl(allocator, **it); + if ((*it)->getKind() == clang::Decl::Var) { + const clang::VarDecl *varDecl = llvm::cast(*it); + ASTExpr *expr = ProcessExprInType(allocator, varDecl->getType()); + if (expr != nullptr) { + astStmt->SetASTExpr(expr); + } + } + if (ad != nullptr) { + astStmt->SetSubDecl(ad); + } + } + } + return astStmt; +} + +ASTValue *ASTParser::TranslateConstantValue2ASTValue(MapleAllocator &allocator, const clang::Expr *expr) const { + ASTValue *astValue = nullptr; + clang::Expr::EvalResult result; + if (expr->getStmtClass() == clang::Stmt::StringLiteralClass && + expr->EvaluateAsLValue(result, *(astFile->GetContext()))) { + return TranslateLValue2ASTValue(allocator, result, expr); + } + if (expr->EvaluateAsRValue(result, *(astFile->GetContext()))) { + if (result.Val.isLValue()) { + return TranslateLValue2ASTValue(allocator, result, expr); + } + auto *constMirType = astFile->CvtType(expr->getType().getCanonicalType()); + if (result.Val.isInt()) { + astValue = AllocASTValue(allocator); + switch (constMirType->GetPrimType()) { + case PTY_i8: + astValue->val.i8 = static_cast(result.Val.getInt().getExtValue()); + astValue->pty = PTY_i8; + break; + case PTY_i16: + astValue->val.i16 = static_cast(result.Val.getInt().getExtValue()); + astValue->pty = PTY_i16; + break; + case PTY_i32: + if (expr->getStmtClass() == clang::Stmt::CharacterLiteralClass) { + if (FEOptions::GetInstance().IsUseSignedChar()) { + astValue->val.i8 = static_cast(llvm::cast(expr)->getValue()); + astValue->pty = PTY_i8; + } else { + astValue->val.u8 = static_cast(llvm::cast(expr)->getValue()); + astValue->pty = PTY_u8; + } + } else { + astValue->val.i32 = static_cast(result.Val.getInt().getExtValue()); + astValue->pty = PTY_i32; + } + break; + case PTY_i64: + if (result.Val.getInt().getBitWidth() > 64) { + astValue->val.i64 = static_cast(result.Val.getInt().getSExtValue()); + } else { + astValue->val.i64 = static_cast(result.Val.getInt().getExtValue()); + } + astValue->pty = PTY_i64; + break; + case PTY_i128: + astValue->val.i64 = static_cast(result.Val.getInt().getSExtValue()); + astValue->pty = PTY_i128; + break; + case PTY_u8: + astValue->val.u8 = static_cast(result.Val.getInt().getExtValue()); + astValue->pty = PTY_u8; + break; + case PTY_u16: + astValue->val.u16 = static_cast(result.Val.getInt().getExtValue()); + astValue->pty = PTY_u16; + break; + case PTY_u32: + astValue->val.u32 = static_cast(result.Val.getInt().getExtValue()); + astValue->pty = PTY_u32; + break; + case PTY_u64: + if (result.Val.getInt().getBitWidth() > 64) { + astValue->val.u64 = static_cast(result.Val.getInt().getZExtValue()); + } else { + astValue->val.u64 = static_cast(result.Val.getInt().getExtValue()); + } + astValue->pty = PTY_u64; + break; + case PTY_u128: + astValue->val.u64 = static_cast(result.Val.getInt().getZExtValue()); + astValue->pty = PTY_u128; + break; + case PTY_u1: + astValue->val.u8 = (result.Val.getInt().getExtValue() == 0 ? 0 : 1); + astValue->pty = PTY_u1; + break; + default: { + CHECK_FATAL(false, "Invalid"); + break; + } + } + } else if (result.Val.isFloat()) { + astValue = AllocASTValue(allocator); + llvm::APFloat fValue = result.Val.getFloat(); + llvm::APFloat::Semantics semantics = llvm::APFloatBase::SemanticsToEnum(fValue.getSemantics()); + switch (semantics) { + case llvm::APFloat::S_IEEEsingle: + astValue->val.f32 = fValue.convertToFloat(); + break; + case llvm::APFloat::S_IEEEdouble: + astValue->val.f64 = fValue.convertToDouble(); + break; + case llvm::APFloat::S_IEEEquad: + case llvm::APFloat::S_PPCDoubleDouble: + case llvm::APFloat::S_x87DoubleExtended: + bool LosesInfo; + if (constMirType->GetPrimType() == PTY_f64) { + (void)fValue.convert(llvm::APFloat::IEEEdouble(), + llvm::APFloatBase::rmNearestTiesToAway, + &LosesInfo); + astValue->val.f64 = fValue.convertToDouble(); + } else { + (void)fValue.convert(llvm::APFloat::IEEEsingle(), + llvm::APFloatBase::rmNearestTiesToAway, + &LosesInfo); + astValue->val.f32 = fValue.convertToFloat(); + } + break; + default: + CHECK_FATAL(false, "unsupported semantics"); + } + astValue->pty = constMirType->GetPrimType(); + } else if (result.Val.isComplexInt() || result.Val.isComplexFloat()) { + WARN(kLncWarn, "Unsupported complex value in MIR"); + } else if (result.Val.isVector()) { + // vector type var must be init by initListExpr + return nullptr; + } else if (result.Val.isMemberPointer()) { + CHECK_FATAL(false, "NIY"); + } + // Others: Agg const processed in `InitListExpr` + } + return astValue; +} + +ASTValue *ASTParser::TranslateLValue2ASTValue( + MapleAllocator &allocator, const clang::Expr::EvalResult &result, const clang::Expr *expr) const { + ASTValue *astValue = nullptr; + const clang::APValue::LValueBase &lvBase = result.Val.getLValueBase(); + if (lvBase.is()) { + const clang::Expr *lvExpr = lvBase.get(); + if (lvExpr == nullptr) { + return astValue; + } + if (expr->getStmtClass() == clang::Stmt::MemberExprClass) { + // meaningless, just for Initialization + astValue = AllocASTValue(allocator); + astValue->pty = PTY_i32; + astValue->val.i64 = 0; + return astValue; + } + switch (lvExpr->getStmtClass()) { + case clang::Stmt::StringLiteralClass: { + const clang::StringLiteral &strExpr = llvm::cast(*lvExpr); + std::string str = ""; + if (strExpr.isWide() || strExpr.isUTF16() || strExpr.isUTF32()) { + str = strExpr.getBytes().str(); + } else { + str = strExpr.getString().str(); + } + astValue = AllocASTValue(allocator); + UStrIdx strIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(str); + astValue->val.strIdx = strIdx; + astValue->pty = PTY_a64; + break; + } + case clang::Stmt::PredefinedExprClass: { + astValue = AllocASTValue(allocator); + std::string str = llvm::cast(*lvExpr).getFunctionName()->getString().str(); + UStrIdx strIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(str); + astValue->val.strIdx = strIdx; + astValue->pty = PTY_a64; + break; + } + case clang::Stmt::AddrLabelExprClass: + case clang::Stmt::CompoundLiteralExprClass: { + // Processing in corresponding expr, skipping + break; + } + default: { + CHECK_FATAL(false, "Unsupported expr :%s in LValue", lvExpr->getStmtClassName()); + } + } + } else { + // `valueDecl` processed in corresponding expr + bool isValueDeclInLValueBase = lvBase.is(); + CHECK_FATAL(isValueDeclInLValueBase, "Unsupported lValue base"); + } + + return astValue; +} + +ASTValue *ASTParser::TranslateExprEval(MapleAllocator &allocator, const clang::Expr *expr) const { + return TranslateConstantValue2ASTValue(allocator, expr); +} + +#define EXPR_CASE(CLASS) \ + case clang::Stmt::CLASS##Class: { \ + ASTExpr *astExpr = EvaluateExprAsConst(allocator, expr); \ + if (astExpr == nullptr) { \ + astExpr = ProcessExpr##CLASS(allocator, llvm::cast(*expr)); \ + if (astExpr == nullptr) { \ + return nullptr; \ + } \ + } \ + MIRType *exprType = astFile->CvtType(expr->getType()); \ + astExpr->SetType(exprType); \ + if (expr->isConstantInitializer(*astFile->GetNonConstAstContext(), false, nullptr)) { \ + astExpr->SetConstantValue(TranslateExprEval(allocator, expr)); \ + } \ + Pos loc = astFile->GetExprLOC(*expr); \ + astExpr->SetSrcLOC(loc.first, loc.second); \ + return astExpr; \ + } + +ASTExpr *ASTParser::EvaluateExprAsConst(MapleAllocator &allocator, const clang::Expr *expr) { + clang::Expr::EvalResult constResult; + if (!expr->EvaluateAsConstantExpr(constResult, *astFile->GetNonConstAstContext())) { + return nullptr; + } + + clang::APValue constVal = constResult.Val; + if (constVal.isInt()) { + ASTIntegerLiteral *intExpr = allocator.New(); + llvm::APSInt intVal = constVal.getInt(); + intExpr->SetVal(intVal.getExtValue()); + return intExpr; + } else if (constVal.isFloat()) { + ASTFloatingLiteral *floatExpr = allocator.New(); + llvm::APFloat floatVal = constVal.getFloat(); + const llvm::fltSemantics &fltSem = floatVal.getSemantics(); + double val = 0; + if (&fltSem == &llvm::APFloat::IEEEsingle()) { + val = static_cast(floatVal.convertToFloat()); + floatExpr->SetKind(F32); + floatExpr->SetVal(val); + } else if (&fltSem == &llvm::APFloat::IEEEdouble()) { + val = static_cast(floatVal.convertToDouble()); + floatExpr->SetKind(F64); + floatExpr->SetVal(val); + } else if (&fltSem == &llvm::APFloat::IEEEquad() || &fltSem == &llvm::APFloat::x87DoubleExtended()) { + bool losesInfo; + (void)floatVal.convert(llvm::APFloat::IEEEdouble(), + llvm::APFloatBase::rmNearestTiesToAway, + &losesInfo); + val = static_cast(floatVal.convertToDouble()); + floatExpr->SetKind(F64); + floatExpr->SetVal(val); + } else { + return nullptr; + } + return floatExpr; + } + + return nullptr; +} + +ASTExpr *ASTParser::ProcessExpr(MapleAllocator &allocator, const clang::Expr *expr) { + if (expr == nullptr) { + return nullptr; + } + switch (expr->getStmtClass()) { + EXPR_CASE(UnaryOperator); + EXPR_CASE(AddrLabelExpr); + EXPR_CASE(NoInitExpr); + EXPR_CASE(PredefinedExpr); + EXPR_CASE(OpaqueValueExpr); + EXPR_CASE(BinaryConditionalOperator); + EXPR_CASE(CompoundLiteralExpr); + EXPR_CASE(OffsetOfExpr); + EXPR_CASE(InitListExpr); + EXPR_CASE(BinaryOperator); + EXPR_CASE(ImplicitValueInitExpr); + EXPR_CASE(ArraySubscriptExpr); + EXPR_CASE(UnaryExprOrTypeTraitExpr); + EXPR_CASE(MemberExpr); + EXPR_CASE(DesignatedInitUpdateExpr); + EXPR_CASE(ImplicitCastExpr); + EXPR_CASE(DeclRefExpr); + EXPR_CASE(ParenExpr); + EXPR_CASE(IntegerLiteral); + EXPR_CASE(CharacterLiteral); + EXPR_CASE(StringLiteral); + EXPR_CASE(FloatingLiteral); + EXPR_CASE(ConditionalOperator); + EXPR_CASE(VAArgExpr); + EXPR_CASE(GNUNullExpr); + EXPR_CASE(SizeOfPackExpr); + EXPR_CASE(UserDefinedLiteral); + EXPR_CASE(ShuffleVectorExpr); + EXPR_CASE(TypeTraitExpr); + EXPR_CASE(ConstantExpr); + EXPR_CASE(ImaginaryLiteral); + EXPR_CASE(CallExpr); + EXPR_CASE(CompoundAssignOperator); + EXPR_CASE(StmtExpr); + EXPR_CASE(CStyleCastExpr); + EXPR_CASE(ArrayInitLoopExpr); + EXPR_CASE(ArrayInitIndexExpr); + EXPR_CASE(ExprWithCleanups); + EXPR_CASE(MaterializeTemporaryExpr); + EXPR_CASE(SubstNonTypeTemplateParmExpr); + EXPR_CASE(DependentScopeDeclRefExpr); + EXPR_CASE(AtomicExpr); + EXPR_CASE(ChooseExpr); + EXPR_CASE(GenericSelectionExpr); + default: + CHECK_FATAL(false, "ASTExpr %s NIY", expr->getStmtClassName()); + return nullptr; + } +} + +ASTExpr *ASTParser::ProcessExprInType(MapleAllocator &allocator, const clang::QualType &qualType) { + const clang::Type *type = qualType.getCanonicalType().getTypePtr(); + if (type->isVariableArrayType()) { + const clang::VariableArrayType *vAType = llvm::cast(type); + return ProcessExpr(allocator, vAType->getSizeExpr()); + } + return nullptr; +} + +ASTUnaryOperatorExpr *ASTParser::AllocUnaryOperatorExpr(MapleAllocator &allocator, const clang::UnaryOperator &expr) { + clang::UnaryOperator::Opcode clangOpCode = expr.getOpcode(); + switch (clangOpCode) { + case clang::UO_Minus: // "-" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_Not: // "~" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_LNot: // "!" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_PostInc: // "++" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_PostDec: // "--" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_PreInc: // "++" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_PreDec: // "--" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_AddrOf: // "&" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_Deref: // "*" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_Plus: // "+" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_Real: // "__real" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_Imag: // "__imag" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_Extension: // "__extension__" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + case clang::UO_Coawait: // "co_await" + return ASTDeclsBuilder::ASTExprBuilder(allocator); + default: + CHECK_FATAL(false, "NYI"); + } +} + +ASTValue *ASTParser::AllocASTValue(const MapleAllocator &allocator) const { + return allocator.GetMemPool()->New(); +} + +const clang::Expr *ASTParser::PeelParen(const clang::Expr &expr) { + const clang::Expr *exprPtr = &expr; + while (llvm::isa(exprPtr) || + (llvm::isa(exprPtr) && + llvm::cast(exprPtr)->getOpcode() == clang::UO_Extension) || + (llvm::isa(exprPtr) && + llvm::cast(exprPtr)->getCastKind() == clang::CK_LValueToRValue)) { + if (llvm::isa(exprPtr)) { + exprPtr = llvm::cast(exprPtr)->getSubExpr(); + } else if (llvm::isa(exprPtr)) { + exprPtr = llvm::cast(exprPtr)->getSubExpr(); + } else { + exprPtr = llvm::cast(exprPtr)->getSubExpr(); + } + } + return exprPtr; +} + +const clang::Expr *ASTParser::PeelParen2(const clang::Expr &expr) { + const clang::Expr *exprPtr = &expr; + while (llvm::isa(exprPtr) || + (llvm::isa(exprPtr) && + llvm::cast(exprPtr)->getOpcode() == clang::UO_Extension)) { + if (llvm::isa(exprPtr)) { + exprPtr = llvm::cast(exprPtr)->getSubExpr(); + } else { + exprPtr = llvm::cast(exprPtr)->getSubExpr(); + } + } + return exprPtr; +} + +ASTExpr *ASTParser::ProcessExprUnaryOperator(MapleAllocator &allocator, const clang::UnaryOperator &uo) { + ASTUnaryOperatorExpr *astUOExpr = AllocUnaryOperatorExpr(allocator, uo); + CHECK_FATAL(astUOExpr != nullptr, "astUOExpr is nullptr"); + const clang::Expr *subExpr = PeelParen(*uo.getSubExpr()); + clang::UnaryOperator::Opcode clangOpCode = uo.getOpcode(); + MIRType *subType = astFile->CvtType(subExpr->getType()); + astUOExpr->SetSubType(subType); + MIRType *uoType = astFile->CvtType(uo.getType()); + astUOExpr->SetUOType(uoType); + if (clangOpCode == clang::UO_PostInc || clangOpCode == clang::UO_PostDec || + clangOpCode == clang::UO_PreInc || clangOpCode == clang::UO_PreDec) { + const auto *declRefExpr = llvm::dyn_cast(subExpr); + if (declRefExpr != nullptr && declRefExpr->getDecl()->getKind() == clang::Decl::Var) { + const auto *varDecl = llvm::cast(declRefExpr->getDecl()->getCanonicalDecl()); + astUOExpr->SetGlobal(!varDecl->isLocalVarDeclOrParm()); + } + if (subType->GetPrimType() == PTY_ptr) { + int64 len; + const clang::QualType qualType = subExpr->getType()->getPointeeType(); + if (astFile->CvtType(qualType)->GetPrimType() == PTY_ptr) { + MIRType *pointeeType = GlobalTables::GetTypeTable().GetPtr(); + len = static_cast(pointeeType->GetSize()); + } else { + const clang::QualType desugaredType = qualType.getDesugaredType(*(astFile->GetContext())); + len = astFile->GetContext()->getTypeSizeInChars(desugaredType).getQuantity(); + } + astUOExpr->SetPointeeLen(len); + } + } + if (clangOpCode == clang::UO_Imag || clangOpCode == clang::UO_Real) { + clang::QualType elementType = llvm::cast( + uo.getSubExpr()->getType().getCanonicalType())->getElementType(); + MIRType *elementMirType = astFile->CvtType(elementType); + if (clangOpCode == clang::UO_Real) { + static_cast(astUOExpr)->SetElementType(elementMirType); + } else { + static_cast(astUOExpr)->SetElementType(elementMirType); + } + } + ASTExpr *astExpr = ProcessExpr(allocator, subExpr); + if (astExpr == nullptr) { + return nullptr; + } + astUOExpr->SetASTDecl(astExpr->GetASTDecl()); + astUOExpr->SetUOExpr(astExpr); + return astUOExpr; +} + +ASTExpr *ASTParser::ProcessExprAddrLabelExpr(MapleAllocator &allocator, const clang::AddrLabelExpr &expr) { + ASTUOAddrOfLabelExpr *astAddrOfLabelExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + const clang::LabelDecl *lbDecl = expr.getLabel(); + CHECK_NULL_FATAL(lbDecl); + ASTDecl *astDecl = ProcessDecl(allocator, *lbDecl); + astAddrOfLabelExpr->SetLabelName(astDecl->GetName()); + astAddrOfLabelExpr->SetUOType(GlobalTables::GetTypeTable().GetPrimType(PTY_ptr)); + return astAddrOfLabelExpr; +} + +ASTExpr *ASTParser::ProcessExprNoInitExpr(MapleAllocator &allocator, const clang::NoInitExpr &expr) { + ASTNoInitExpr *astNoInitExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astNoInitExpr != nullptr, "astNoInitExpr is nullptr"); + clang::QualType qualType = expr.getType(); + MIRType *noInitType = astFile->CvtType(qualType); + astNoInitExpr->SetNoInitType(noInitType); + return astNoInitExpr; +} + +ASTExpr *ASTParser::ProcessExprPredefinedExpr(MapleAllocator &allocator, const clang::PredefinedExpr &expr) { + ASTPredefinedExpr *astPredefinedExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astPredefinedExpr != nullptr, "astPredefinedExpr is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, expr.getFunctionName()); + if (astExpr == nullptr) { + return nullptr; + } + astPredefinedExpr->SetASTExpr(astExpr); + return astPredefinedExpr; +} + +ASTExpr *ASTParser::ProcessExprOpaqueValueExpr(MapleAllocator &allocator, const clang::OpaqueValueExpr &expr) { + ASTOpaqueValueExpr *astOpaqueValueExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astOpaqueValueExpr != nullptr, "astOpaqueValueExpr is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, expr.getSourceExpr()); + if (astExpr == nullptr) { + return nullptr; + } + astOpaqueValueExpr->SetASTExpr(astExpr); + return astOpaqueValueExpr; +} + +ASTExpr *ASTParser::ProcessExprBinaryConditionalOperator(MapleAllocator &allocator, + const clang::BinaryConditionalOperator &expr) { + ASTBinaryConditionalOperator *astBinaryConditionalOperator = + ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astBinaryConditionalOperator != nullptr, "astBinaryConditionalOperator is nullptr"); + ASTExpr *condExpr = ProcessExpr(allocator, expr.getCond()); + if (condExpr == nullptr) { + return nullptr; + } + astBinaryConditionalOperator->SetCondExpr(condExpr); + ASTExpr *falseExpr = ProcessExpr(allocator, expr.getFalseExpr()); + if (falseExpr == nullptr) { + return nullptr; + } + astBinaryConditionalOperator->SetFalseExpr(falseExpr); + astBinaryConditionalOperator->SetType(astFile->CvtType(expr.getType())); + return astBinaryConditionalOperator; +} + +ASTExpr *ASTParser::ProcessExprCompoundLiteralExpr(MapleAllocator &allocator, + const clang::CompoundLiteralExpr &expr) { + ASTCompoundLiteralExpr *astCompoundLiteralExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astCompoundLiteralExpr != nullptr, "astCompoundLiteralExpr is nullptr"); + const clang::Expr *initExpr = expr.getInitializer(); + CHECK_FATAL(initExpr != nullptr, "initExpr is nullptr"); + clang::QualType qualType = initExpr->getType(); + astCompoundLiteralExpr->SetCompoundLiteralType(astFile->CvtType(qualType)); + ASTExpr *astExpr = ProcessExpr(allocator, initExpr); + if (astExpr == nullptr) { + return nullptr; + } + astCompoundLiteralExpr->SetASTExpr(astExpr); + return astCompoundLiteralExpr; +} + +ASTExpr *ASTParser::ProcessExprInitListExpr(MapleAllocator &allocator, const clang::InitListExpr &expr) { + ASTInitListExpr *astInitListExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astInitListExpr != nullptr, "ASTInitListExpr is nullptr"); + MIRType *initListType = astFile->CvtType(expr.getType()); + clang::QualType aggType = expr.getType().getCanonicalType(); + astInitListExpr->SetInitListType(initListType); + const clang::FieldDecl *fieldDecl = expr.getInitializedFieldInUnion(); + if (fieldDecl != nullptr) { + astInitListExpr->SetUnionInitFieldIdx(fieldDecl->getFieldIndex()); + } + uint32 n = expr.getNumInits(); + clang::Expr * const *le = expr.getInits(); + if (aggType->isRecordType()) { + const auto *recordType = llvm::cast(aggType); + clang::RecordDecl *recordDecl = recordType->getDecl(); + ASTDecl *astDecl = ProcessDecl(allocator, *recordDecl); + CHECK_FATAL(astDecl != nullptr && astDecl->GetDeclKind() == kASTStruct, "Undefined record type"); + uint i = 0; + for (const auto field : static_cast(astDecl)->GetFields()) { + if (field->IsAnonymousField() && fieldDecl == nullptr && + n != static_cast(astDecl)->GetFields().size()) { + astInitListExpr->SetInitExprs(nullptr); + } else { + if (i < n) { + const clang::Expr *eExpr = le[i]; + ASTExpr *astExpr = ProcessExpr(allocator, eExpr); + CHECK_FATAL(astExpr != nullptr, "Invalid InitListExpr"); + astInitListExpr->SetInitExprs(astExpr); + i++; + } + } + } + } else { + if (expr.hasArrayFiller()) { + auto *astFilterExpr = ProcessExpr(allocator, expr.getArrayFiller()); + astInitListExpr->SetArrayFiller(astFilterExpr); + astInitListExpr->SetHasArrayFiller(true); + } + if (expr.isTransparent()) { + astInitListExpr->SetTransparent(true); + } + if (aggType->isVectorType()) { + astInitListExpr->SetHasVectorType(true); + // for one elem vector type + if (LibAstFile::IsOneElementVector(aggType)) { + astInitListExpr->SetTransparent(true); + } + } + for (uint32 i = 0; i < n; ++i) { + const clang::Expr *eExpr = le[i]; + ASTExpr *astExpr = ProcessExpr(allocator, eExpr); + if (astExpr == nullptr) { + return nullptr; + } + astInitListExpr->SetInitExprs(astExpr); + } + } + return astInitListExpr; +} + +ASTExpr *ASTParser::ProcessExprOffsetOfExpr(MapleAllocator &allocator, const clang::OffsetOfExpr &expr) { + if (expr.isEvaluatable(*astFile->GetContext())) { + clang::Expr::EvalResult result; + bool success = expr.EvaluateAsInt(result, *astFile->GetContext()); + if (success) { + auto astExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + astExpr->SetVal(result.Val.getInt().getExtValue()); + astExpr->SetType(GlobalTables::GetTypeTable().GetUInt64()); + return astExpr; + } + } + int64_t offset = 0; + std::vector vlaOffsetExprs; + for (unsigned i = 0; i < expr.getNumComponents(); i++) { + auto comp = expr.getComponent(i); + if (comp.getKind() == clang::OffsetOfNode::Kind::Field) { + uint filedIdx = comp.getField()->getFieldIndex(); + offset += static_cast(astFile->GetContext()->getASTRecordLayout( + comp.getField()->getParent()).getFieldOffset(filedIdx) >> kBitToByteShift); + } else if (comp.getKind() == clang::OffsetOfNode::Kind::Array) { + uint32 idx = comp.getArrayExprIndex(); + auto idxExpr = expr.getIndexExpr(idx); + auto leftExpr = ProcessExpr(allocator, idxExpr); + auto arrayType = expr.getComponent(i - 1).getField()->getType(); + auto elementType = llvm::cast(arrayType)->getElementType(); + uint32 elementSize = GetSizeFromQualType(elementType); + if (elementSize == 1) { + vlaOffsetExprs.emplace_back(leftExpr); + } else { + auto astSizeExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + astSizeExpr->SetVal(elementSize); + astSizeExpr->SetType(GlobalTables::GetTypeTable().GetUInt64()); + auto astExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + astExpr->SetOpcode(OP_mul); + astExpr->SetLeftExpr(leftExpr); + astExpr->SetRightExpr(astSizeExpr); + astExpr->SetRetType(GlobalTables::GetTypeTable().GetPrimType(PTY_u64)); + vlaOffsetExprs.emplace_back(astExpr); + } + } else { + CHECK_FATAL(false, "NIY"); + } + } + ASTExpr *vlaOffsetExpr = nullptr; + if (vlaOffsetExprs.size() == 1) { + vlaOffsetExpr = vlaOffsetExprs[0]; + } else if (vlaOffsetExprs.size() >= 2) { + auto astExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + astExpr->SetRetType(GlobalTables::GetTypeTable().GetPrimType(PTY_u64)); + astExpr->SetLeftExpr(vlaOffsetExprs[0]); + astExpr->SetRightExpr(vlaOffsetExprs[1]); + if (vlaOffsetExprs.size() >= 3) { + for (size_t i = 2; i < vlaOffsetExprs.size(); i++) { + auto astSubExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + astSubExpr->SetRetType(GlobalTables::GetTypeTable().GetPrimType(PTY_u64)); + astSubExpr->SetLeftExpr(astExpr); + astSubExpr->SetRightExpr(vlaOffsetExprs[i]); + astExpr = astSubExpr; + } + } + vlaOffsetExpr = astExpr; + } + auto astSizeExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + astSizeExpr->SetVal(offset); + astSizeExpr->SetType(GlobalTables::GetTypeTable().GetUInt64()); + auto astExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + astExpr->SetOpcode(OP_add); + astExpr->SetLeftExpr(astSizeExpr); + astExpr->SetRightExpr(vlaOffsetExpr); + astExpr->SetRetType(GlobalTables::GetTypeTable().GetPrimType(PTY_u64)); + return astExpr; +} + +ASTExpr *ASTParser::ProcessExprVAArgExpr(MapleAllocator &allocator, const clang::VAArgExpr &expr) { + ASTVAArgExpr *astVAArgExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + ASSERT(astVAArgExpr != nullptr, "astVAArgExpr is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, expr.getSubExpr()); + if (astExpr == nullptr) { + return nullptr; + } + astVAArgExpr->SetASTExpr(astExpr); + astVAArgExpr->SetType(astFile->CvtType(expr.getType())); + return astVAArgExpr; +} + +ASTExpr *ASTParser::ProcessExprImplicitValueInitExpr(MapleAllocator &allocator, + const clang::ImplicitValueInitExpr &expr) { + auto *astImplicitValueInitExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astImplicitValueInitExpr != nullptr, "astImplicitValueInitExpr is nullptr"); + astImplicitValueInitExpr->SetType(astFile->CvtType(expr.getType())); + return astImplicitValueInitExpr; +} + +ASTExpr *ASTParser::ProcessExprStringLiteral(MapleAllocator &allocator, const clang::StringLiteral &expr) { + auto *astStringLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astStringLiteral != nullptr, "astStringLiteral is nullptr"); + astStringLiteral->SetType(astFile->CvtType(expr.getType())); + astStringLiteral->SetLength(expr.getLength()); + std::vector codeUnits; + for (size_t i = 0; i < expr.getLength(); ++i) { + codeUnits.emplace_back(expr.getCodeUnit(i)); + } + astStringLiteral->SetCodeUnits(codeUnits); + if (expr.isAscii()) { + astStringLiteral->SetStr(expr.getString().str()); + } + return astStringLiteral; +} + +ASTExpr *ASTParser::ProcessExprArraySubscriptExpr(MapleAllocator &allocator, const clang::ArraySubscriptExpr &expr) { + auto *astArraySubscriptExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astArraySubscriptExpr != nullptr, "astArraySubscriptExpr is nullptr"); + auto base = expr.getBase(); + + base = PeelParen2(*base); + ASTExpr *idxExpr = ProcessExpr(allocator, expr.getIdx()); + astArraySubscriptExpr->SetIdxExpr(idxExpr); + + clang::QualType arrayQualType = base->getType().getCanonicalType(); + if (base->getStmtClass() == clang::Stmt::ImplicitCastExprClass && + !static_cast(base)->isPartOfExplicitCast()) { + arrayQualType = static_cast(base)->getSubExpr()->getType().getCanonicalType(); + } + auto arrayMirType = astFile->CvtType(arrayQualType); + astArraySubscriptExpr->SetArrayType(arrayMirType); + + clang::QualType exprType = expr.getType().getCanonicalType(); + if (llvm::isa(arrayQualType)) { + CHECK_FATAL(FEOptions::GetInstance().IsEnableVariableArray(), + "Intercepts variable arrays, because the backend does not yet support."); + astArraySubscriptExpr->SetIsVLA(true); + } + ASTExpr *astBaseExpr = ProcessExpr(allocator, base); + astArraySubscriptExpr->SetBaseExpr(astBaseExpr); + auto *mirType = astFile->CvtType(exprType); + astArraySubscriptExpr->SetType(mirType); + return astArraySubscriptExpr; +} + +uint32 ASTParser::GetSizeFromQualType(const clang::QualType qualType) { + const clang::QualType desugaredType = qualType.getDesugaredType(*astFile->GetContext()); + return astFile->GetContext()->getTypeSizeInChars(desugaredType).getQuantity(); +} + +ASTExpr *ASTParser::GetTypeSizeFromQualType(MapleAllocator &allocator, const clang::QualType qualType) { + const clang::QualType desugaredType = qualType.getDesugaredType(*astFile->GetContext()); + if (llvm::isa(desugaredType)) { + ASTExpr *vlaSizeExpr = ProcessExpr(allocator, llvm::cast(desugaredType)->getSizeExpr()); + ASTExpr *vlaElemTypeSizeExpr = + GetTypeSizeFromQualType(allocator, llvm::cast(desugaredType)->getElementType()); + ASTBinaryOperatorExpr *sizeExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + sizeExpr->SetRetType(GlobalTables::GetTypeTable().GetPrimType(PTY_i64)); + sizeExpr->SetOpcode(OP_mul); + sizeExpr->SetLeftExpr(vlaSizeExpr); + sizeExpr->SetRightExpr(vlaElemTypeSizeExpr); + return sizeExpr; + } else { + ASTIntegerLiteral *sizeExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + sizeExpr->SetVal(astFile->GetContext()->getTypeSizeInChars(desugaredType).getQuantity()); + sizeExpr->SetType(GlobalTables::GetTypeTable().GetInt32()); + return sizeExpr; + } +} + +uint32_t ASTParser::GetAlignOfType(const clang::QualType currQualType, clang::UnaryExprOrTypeTrait exprKind) { + clang::QualType qualType = currQualType; + clang::CharUnits alignInCharUnits = clang::CharUnits::Zero(); + if (const auto *ref = currQualType->getAs()) { + qualType = ref->getPointeeType(); + } + if (qualType.getQualifiers().hasUnaligned()) { + alignInCharUnits = clang::CharUnits::One(); + } + if (exprKind == clang::UETT_AlignOf) { + alignInCharUnits = astFile->GetContext()->getTypeAlignInChars(qualType.getTypePtr()); + } else if (exprKind == clang::UETT_PreferredAlignOf) { + alignInCharUnits = astFile->GetContext()->toCharUnitsFromBits( + astFile->GetContext()->getPreferredTypeAlign(qualType.getTypePtr())); + } else { + CHECK_FATAL(false, "NIY"); + } + return static_cast(alignInCharUnits.getQuantity()); +} + +uint32_t ASTParser::GetAlignOfExpr(const clang::Expr &expr, clang::UnaryExprOrTypeTrait exprKind) { + clang::CharUnits alignInCharUnits = clang::CharUnits::Zero(); + const clang::Expr *exprNoParens = expr.IgnoreParens(); + if (const auto *declRefExpr = clang::dyn_cast(exprNoParens)) { + alignInCharUnits = astFile->GetContext()->getDeclAlign(declRefExpr->getDecl(), true); + } else if (const auto *memberExpr = clang::dyn_cast(exprNoParens)) { + alignInCharUnits = astFile->GetContext()->getDeclAlign(memberExpr->getMemberDecl(), true); + } else { + return GetAlignOfType(exprNoParens->getType(), exprKind); + } + return static_cast(alignInCharUnits.getQuantity()); +} + +ASTExpr *ASTParser::GetAddrShiftExpr(MapleAllocator &allocator, ASTExpr *expr, uint32 typeSize) { + MIRType *retType = nullptr; + if (IsSignedInteger(expr->GetType()->GetPrimType())) { + retType = GlobalTables::GetTypeTable().GetInt64(); + } else { + retType = GlobalTables::GetTypeTable().GetPtr(); + } + if (expr->GetASTOp() == kASTIntegerLiteral) { + auto intExpr = static_cast(expr); + auto retExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + retExpr->SetVal(intExpr->GetVal() * typeSize); + retExpr->SetType(retType); + return retExpr; + } + auto ptrSizeExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + ptrSizeExpr->SetVal(typeSize); + ptrSizeExpr->SetType(retType); + auto shiftExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + shiftExpr->SetLeftExpr(expr); + shiftExpr->SetRightExpr(ptrSizeExpr); + shiftExpr->SetOpcode(OP_mul); + shiftExpr->SetRetType(retType); + shiftExpr->SetCvtNeeded(true); + return shiftExpr; +} + +ASTExpr *ASTParser::BuildExprToComputeSizeFromVLA(MapleAllocator &allocator, const clang::QualType &qualType) { + if (llvm::isa(qualType)) { + ASTExpr *lhs = BuildExprToComputeSizeFromVLA(allocator, llvm::cast(qualType)->getElementType()); + ASTExpr *rhs = nullptr; + CHECK_FATAL(llvm::isa(qualType), "the type must be array type"); + if (llvm::isa(qualType)) { + clang::Expr *sizeExpr = llvm::cast(qualType)->getSizeExpr(); + rhs = ProcessExpr(allocator, sizeExpr); + CHECK_FATAL(sizeExpr->getType()->isIntegerType(), "the type should be integer"); + } else if (llvm::isa(qualType)) { + uint32 size = static_cast(llvm::cast(qualType)->getSize().getSExtValue()); + if (size == 1) { + return lhs; + } + auto astExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + astExpr->SetVal(size); + astExpr->SetType(GlobalTables::GetTypeTable().GetInt32()); + rhs = astExpr; + } else { + CHECK_FATAL(false, "NIY"); + } + auto *astBOExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + astBOExpr->SetRetType(GlobalTables::GetTypeTable().GetPrimType(PTY_u64)); + astBOExpr->SetOpcode(OP_mul); + astBOExpr->SetLeftExpr(lhs); + astBOExpr->SetRightExpr(rhs); + return astBOExpr; + } + uint32 size = GetSizeFromQualType(qualType); + auto integerExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + integerExpr->SetType(GlobalTables::GetTypeTable().GetUInt64()); + integerExpr->SetVal(size); + return integerExpr; +} + +ASTExpr *ASTParser::ProcessExprUnaryExprOrTypeTraitExpr(MapleAllocator &allocator, + const clang::UnaryExprOrTypeTraitExpr &expr) { + auto *astExprUnaryExprOrTypeTraitExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astExprUnaryExprOrTypeTraitExpr != nullptr, "astExprUnaryExprOrTypeTraitExpr is nullptr"); + switch (expr.getKind()) { + case clang::UETT_SizeOf: { + clang::QualType qualType = expr.isArgumentType() ? expr.getArgumentType().getCanonicalType() + : expr.getArgumentExpr()->getType().getCanonicalType(); + if (llvm::isa(qualType)) { + return BuildExprToComputeSizeFromVLA(allocator, qualType); + } + uint32 size = GetSizeFromQualType(qualType); + auto integerExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + integerExpr->SetType(GlobalTables::GetTypeTable().GetUInt64()); + integerExpr->SetVal(size); + return integerExpr; + } + case clang::UETT_PreferredAlignOf: + case clang::UETT_AlignOf: { + // C11 specification: ISO/IEC 9899:201x + uint32_t align; + if (expr.isArgumentType()) { + align = GetAlignOfType(expr.getArgumentType(), expr.getKind()); + } else { + align = GetAlignOfExpr(*expr.getArgumentExpr(), expr.getKind()); + } + auto integerExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + integerExpr->SetType(GlobalTables::GetTypeTable().GetUInt64()); + integerExpr->SetVal(align); + return integerExpr; + } + case clang::UETT_VecStep: + CHECK_FATAL(false, "NIY"); + break; + case clang::UETT_OpenMPRequiredSimdAlign: + CHECK_FATAL(false, "NIY"); + break; + } + return astExprUnaryExprOrTypeTraitExpr; +} + +ASTExpr *ASTParser::ProcessExprMemberExpr(MapleAllocator &allocator, const clang::MemberExpr &expr) { + auto *astMemberExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astMemberExpr != nullptr, "astMemberExpr is nullptr"); + ASTExpr *baseExpr = ProcessExpr(allocator, expr.getBase()); + if (baseExpr == nullptr) { + return nullptr; + } + astMemberExpr->SetBaseExpr(baseExpr); + astMemberExpr->SetBaseType(astFile->CvtType(expr.getBase()->getType())); + auto memberName = expr.getMemberDecl()->getNameAsString(); + if (memberName.empty()) { + uint32 id = expr.getMemberDecl()->getLocation().getRawEncoding(); + memberName = astFile->GetOrCreateMappedUnnamedName(id); + } + astMemberExpr->SetMemberName(memberName); + astMemberExpr->SetMemberType(astFile->CvtType(expr.getMemberDecl()->getType())); + astMemberExpr->SetIsArrow(expr.isArrow()); + uint64_t offsetBits = astFile->GetContext()->getFieldOffset(expr.getMemberDecl()); + astMemberExpr->SetFiledOffsetBits(offsetBits); + return astMemberExpr; +} + +ASTExpr *ASTParser::ProcessExprDesignatedInitUpdateExpr(MapleAllocator &allocator, + const clang::DesignatedInitUpdateExpr &expr) { + auto *astDesignatedInitUpdateExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astDesignatedInitUpdateExpr != nullptr, "astDesignatedInitUpdateExpr is nullptr"); + ASTExpr *baseExpr = ProcessExpr(allocator, expr.getBase()); + if (baseExpr == nullptr) { + return nullptr; + } + astDesignatedInitUpdateExpr->SetBaseExpr(baseExpr); + clang::InitListExpr *initListExpr = expr.getUpdater(); + MIRType *initListType = astFile->CvtType(expr.getType()); + astDesignatedInitUpdateExpr->SetInitListType(initListType); + ASTExpr *updaterExpr = ProcessExpr(allocator, initListExpr); + if (updaterExpr == nullptr) { + return nullptr; + } + astDesignatedInitUpdateExpr->SetUpdaterExpr(updaterExpr); + return astDesignatedInitUpdateExpr; +} + +ASTExpr *ASTParser::ProcessExprStmtExpr(MapleAllocator &allocator, const clang::StmtExpr &expr) { + ASTExprStmtExpr *astExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + ASTStmt *compoundStmt = ProcessStmt(allocator, *expr.getSubStmt()); + astExpr->SetCompoundStmt(compoundStmt); + return astExpr; +} + +ASTExpr *ASTParser::ProcessExprConditionalOperator(MapleAllocator &allocator, const clang::ConditionalOperator &expr) { + ASTConditionalOperator *astConditionalOperator = ASTDeclsBuilder::ASTExprBuilder(allocator); + ASSERT(astConditionalOperator != nullptr, "astConditionalOperator is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, expr.getCond()); + if (astExpr == nullptr) { + return nullptr; + } + astConditionalOperator->SetCondExpr(astExpr); + ASTExpr *astTrueExpr = ProcessExpr(allocator, expr.getTrueExpr()); + if (astTrueExpr == nullptr) { + return nullptr; + } + astConditionalOperator->SetTrueExpr(astTrueExpr); + ASTExpr *astFalseExpr = ProcessExpr(allocator, expr.getFalseExpr()); + if (astFalseExpr == nullptr) { + return nullptr; + } + astConditionalOperator->SetFalseExpr(astFalseExpr); + astConditionalOperator->SetType(astFile->CvtType(expr.getType())); + return astConditionalOperator; +} + +ASTExpr *ASTParser::ProcessExprCompoundAssignOperator(MapleAllocator &allocator, + const clang::CompoundAssignOperator &expr) { + return ProcessExprBinaryOperator(allocator, expr); +} + +ASTExpr *ASTParser::ProcessExprSizeOfPackExpr(MapleAllocator &allocator, const clang::SizeOfPackExpr &expr) { + // CXX feature + (void)allocator; + (void)expr; + return nullptr; +} + +ASTExpr *ASTParser::ProcessExprUserDefinedLiteral(MapleAllocator &allocator, const clang::UserDefinedLiteral &expr) { + // CXX feature + (void)allocator; + (void)expr; + return nullptr; +} + +ASTExpr *ASTParser::ProcessExprTypeTraitExpr(MapleAllocator &allocator, const clang::TypeTraitExpr &expr) { + ASTIntegerLiteral *astIntegerLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + if (expr.getValue()) { + astIntegerLiteral->SetVal(1); + } else { + astIntegerLiteral->SetVal(0); + } + astIntegerLiteral->SetType(astFile->CvtType(expr.getType())); + return astIntegerLiteral; +} + +ASTExpr *ASTParser::ProcessExprShuffleVectorExpr(MapleAllocator &allocator, const clang::ShuffleVectorExpr &expr) { + (void)allocator; + (void)expr; + CHECK_FATAL(false, "NIY"); + return nullptr; +} + +ASTExpr *ASTParser::ProcessExprGNUNullExpr(MapleAllocator &allocator, const clang::GNUNullExpr &expr) { + (void)allocator; + (void)expr; + CHECK_FATAL(false, "NIY"); + return nullptr; +} + +ASTExpr *ASTParser::ProcessExprConstantExpr(MapleAllocator &allocator, const clang::ConstantExpr &expr) { + ASTConstantExpr *astConstantExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + ASSERT(astConstantExpr != nullptr, "astConstantExpr is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, expr.getSubExpr()); + if (astExpr == nullptr) { + return nullptr; + } + astConstantExpr->SetASTExpr(astExpr); + return astConstantExpr; +} + +ASTExpr *ASTParser::ProcessExprImaginaryLiteral(MapleAllocator &allocator, const clang::ImaginaryLiteral &expr) { + clang::QualType complexQualType = expr.getType().getCanonicalType(); + MIRType *complexType = astFile->CvtType(complexQualType); + CHECK_NULL_FATAL(complexType); + clang::QualType elemQualType = llvm::cast(complexQualType)->getElementType(); + MIRType *elemType = astFile->CvtType(elemQualType); + CHECK_NULL_FATAL(elemType); + ASTImaginaryLiteral *astImaginaryLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + astImaginaryLiteral->SetComplexType(complexType); + astImaginaryLiteral->SetElemType(elemType); + ASTExpr *astExpr = ProcessExpr(allocator, expr.getSubExpr()); + if (astExpr == nullptr) { + return nullptr; + } + astImaginaryLiteral->SetASTExpr(astExpr); + return astImaginaryLiteral; +} + +std::map ASTParser::builtingFuncPtrMap = + ASTParser::InitBuiltinFuncPtrMap(); + +ASTExpr *ASTParser::ProcessExprCallExpr(MapleAllocator &allocator, const clang::CallExpr &expr) { + ASTCallExpr *astCallExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + ASSERT(astCallExpr != nullptr, "astCallExpr is nullptr"); + // callee + ASTExpr *astCallee = ProcessExpr(allocator, expr.getCallee()); + if (astCallee == nullptr) { + return nullptr; + } + astCallExpr->SetCalleeExpr(astCallee); + // return + MIRType *retType = astFile->CvtType(expr.getCallReturnType(*astFile->GetAstContext())); + astCallExpr->SetRetType(retType); + // args + std::vector args; + for (uint32_t i = 0; i < expr.getNumArgs(); ++i) { + const clang::Expr *subExpr = expr.getArg(i); + ASTExpr *arg = ProcessExpr(allocator, subExpr); + arg->SetType(astFile->CvtType(subExpr->getType())); + args.push_back(arg); + } + astCallExpr->SetArgs(args); + // Obtain the function name directly + const clang::FunctionDecl *funcDecl = expr.getDirectCallee(); + if (funcDecl != nullptr) { + std::string funcName = astFile->GetMangledName(*funcDecl); + funcName = astCallExpr->CvtBuiltInFuncName(funcName); + if (!ASTUtil::IsValidName(funcName)) { + ASTUtil::AdjustName(funcName); + } + + if (builtingFuncPtrMap.find(funcName) != builtingFuncPtrMap.end()) { + static std::stringstream ss; + ss.clear(); + ss.str(std::string()); + ss << funcName; + ASTExpr *builtinFuncExpr = ParseBuiltinFunc(allocator, expr, ss); + if (builtinFuncExpr != nullptr) { + return builtinFuncExpr; + } + funcName = ss.str(); + } + + GenericAttrs attrs; + astFile->CollectFuncAttrs(*funcDecl, attrs, kPublic); + // for inline optimize + if (attrs.GetAttr(GENATTR_static) && FEOptions::GetInstance().GetFuncInlineSize() != 0) { + funcName = funcName + astFile->GetAstFileNameHashStr(); + } + astCallExpr->SetFuncName(funcName); + astCallExpr->SetFuncAttrs(attrs.ConvertToFuncAttrs()); + ASTFunc *astFunc = static_cast(ASTDeclsBuilder::GetASTDecl(funcDecl->getID())); + if (astFunc != nullptr) { + astCallExpr->SetFuncDecl(astFunc); + } + } else { + astCallExpr->SetIcall(true); + } + astCallExpr->SetType(astFile->CvtType(expr.getType())); + return astCallExpr; +} + +ASTExpr *ASTParser::ProcessExprParenExpr(MapleAllocator &allocator, const clang::ParenExpr &expr) { + ASTParenExpr *astParenExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + ASSERT(astParenExpr != nullptr, "astParenExpr is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, expr.getSubExpr()); + if (astExpr == nullptr) { + return nullptr; + } + astParenExpr->SetASTExpr(astExpr); + return astParenExpr; +} + +ASTExpr *ASTParser::ProcessExprCharacterLiteral(MapleAllocator &allocator, const clang::CharacterLiteral &expr) { + ASTCharacterLiteral *astCharacterLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + ASSERT(astCharacterLiteral != nullptr, "astCharacterLiteral is nullptr"); + const clang::QualType qualType = expr.getType(); + const auto *type = llvm::cast(qualType.getTypePtr()); + clang::BuiltinType::Kind kind = type->getKind(); + if (qualType->isPromotableIntegerType()) { + kind = clang::BuiltinType::Int; + } + PrimType primType = PTY_i32; + switch (kind) { + case clang::BuiltinType::UInt: + primType = PTY_u32; + break; + case clang::BuiltinType::Int: + primType = PTY_i32; + break; + case clang::BuiltinType::ULong: + case clang::BuiltinType::ULongLong: + primType = PTY_u64; + break; + case clang::BuiltinType::Long: + case clang::BuiltinType::LongLong: + primType = PTY_i64; + break; + default: + break; + } + astCharacterLiteral->SetVal(expr.getValue()); + astCharacterLiteral->SetPrimType(primType); + return astCharacterLiteral; +} + +ASTExpr *ASTParser::ProcessExprIntegerLiteral(MapleAllocator &allocator, const clang::IntegerLiteral &expr) { + ASTIntegerLiteral *astIntegerLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + ASSERT(astIntegerLiteral != nullptr, "astIntegerLiteral is nullptr"); + MIRType *type = nullptr; + llvm::APInt api = expr.getValue(); + int64 val = api.getSExtValue(); + if (api.getBitWidth() > kInt32Width) { + type = expr.getType()->isSignedIntegerOrEnumerationType() ? + GlobalTables::GetTypeTable().GetInt64() : GlobalTables::GetTypeTable().GetUInt64(); + } else { + type = expr.getType()->isSignedIntegerOrEnumerationType() ? + GlobalTables::GetTypeTable().GetInt32() : GlobalTables::GetTypeTable().GetUInt32(); + } + astIntegerLiteral->SetVal(val); + astIntegerLiteral->SetType(type); + return astIntegerLiteral; +} + +ASTExpr *ASTParser::ProcessExprFloatingLiteral(MapleAllocator &allocator, const clang::FloatingLiteral &expr) { + ASTFloatingLiteral *astFloatingLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + ASSERT(astFloatingLiteral != nullptr, "astFloatingLiteral is nullptr"); + llvm::APFloat apf = expr.getValue(); + const llvm::fltSemantics &fltSem = expr.getSemantics(); + double val = 0; + if (&fltSem == &llvm::APFloat::IEEEdouble()) { + val = static_cast(apf.convertToDouble()); + astFloatingLiteral->SetKind(F64); + astFloatingLiteral->SetVal(val); + } else if (&fltSem == &llvm::APFloat::IEEEsingle()) { + val = static_cast(apf.convertToFloat()); + astFloatingLiteral->SetKind(F32); + astFloatingLiteral->SetVal(val); + } else if (&fltSem == &llvm::APFloat::IEEEquad() || &fltSem == &llvm::APFloat::x87DoubleExtended()) { + bool losesInfo; + (void)apf.convert(llvm::APFloat::IEEEdouble(), + llvm::APFloatBase::rmNearestTiesToAway, + &losesInfo); + val = static_cast(apf.convertToDouble()); + astFloatingLiteral->SetKind(F64); + astFloatingLiteral->SetVal(val); + } else { + CHECK_FATAL(false, "unsupported floating literal"); + } + return astFloatingLiteral; +} + +ASTExpr *ASTParser::ProcessExprCastExpr(MapleAllocator &allocator, const clang::CastExpr &expr) { + ASTCastExpr *astCastExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astCastExpr != nullptr, "astCastExpr is nullptr"); + MIRType *srcType = astFile->CvtType(expr.getSubExpr()->getType()); + MIRType *toType = astFile->CvtType(expr.getType()); + astCastExpr->SetSrcType(srcType); + astCastExpr->SetDstType(toType); + + switch (expr.getCastKind()) { + case clang::CK_NoOp: + case clang::CK_ToVoid: + case clang::CK_FunctionToPointerDecay: + case clang::CK_LValueToRValue: + break; + case clang::CK_BitCast: + astCastExpr->SetBitCast(true); + break; + case clang::CK_ArrayToPointerDecay: + astCastExpr->SetIsArrayToPointerDecay(true); + break; + case clang::CK_BuiltinFnToFnPtr: + astCastExpr->SetBuilinFunc(true); + break; + case clang::CK_VectorSplat: + astCastExpr->SetVectorSplat(true); + CHECK_FATAL(expr.getType()->isVectorType(), "dst type must be vector type in VectorSplat"); + break; + case clang::CK_NullToPointer: + case clang::CK_IntegralToPointer: + case clang::CK_FloatingToIntegral: + case clang::CK_IntegralToFloating: + case clang::CK_FloatingCast: + case clang::CK_IntegralCast: + case clang::CK_IntegralToBoolean: + case clang::CK_PointerToBoolean: + case clang::CK_FloatingToBoolean: + case clang::CK_PointerToIntegral: + astCastExpr->SetNeededCvt(true); + break; + case clang::CK_ToUnion: + astCastExpr->SetUnionCast(true); + break; + case clang::CK_IntegralRealToComplex: + case clang::CK_FloatingRealToComplex: + case clang::CK_IntegralComplexCast: + case clang::CK_FloatingComplexCast: + case clang::CK_IntegralComplexToFloatingComplex: + case clang::CK_FloatingComplexToIntegralComplex: + case clang::CK_FloatingComplexToReal: + case clang::CK_IntegralComplexToReal: + case clang::CK_FloatingComplexToBoolean: + case clang::CK_IntegralComplexToBoolean: { + clang::QualType qualType = expr.getType().getCanonicalType(); + astCastExpr->SetComplexType(astFile->CvtType(qualType)); + clang::QualType dstQualType = llvm::cast(qualType)->getElementType(); + astCastExpr->SetDstType(astFile->CvtType(dstQualType)); + astCastExpr->SetNeededCvt(true); + if (expr.getCastKind() == clang::CK_IntegralRealToComplex || + expr.getCastKind() == clang::CK_FloatingRealToComplex) { + astCastExpr->SetComplexCastKind(true); + astCastExpr->SetSrcType(astFile->CvtType(expr.getSubExpr()->getType().getCanonicalType())); + } else { + clang::QualType subQualType = expr.getSubExpr()->getType().getCanonicalType(); + clang::QualType srcQualType = llvm::cast(subQualType)->getElementType(); + astCastExpr->SetSrcType(astFile->CvtType(srcQualType)); + } + break; + } + default: + CHECK_FATAL(false, "NIY"); + return nullptr; + } + ASTExpr *astExpr = ProcessExpr(allocator, expr.getSubExpr()); + if (astExpr == nullptr) { + return nullptr; + } + astCastExpr->SetASTExpr(astExpr); + return astCastExpr; +} + +ASTExpr *ASTParser::ProcessExprImplicitCastExpr(MapleAllocator &allocator, const clang::ImplicitCastExpr &expr) { + return ProcessExprCastExpr(allocator, expr); +} + +ASTExpr *ASTParser::ProcessExprDeclRefExpr(MapleAllocator &allocator, const clang::DeclRefExpr &expr) { + ASTDeclRefExpr *astRefExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astRefExpr != nullptr, "astRefExpr is nullptr"); + if (auto enumConst = llvm::dyn_cast(expr.getDecl())) { + const llvm::APSInt value = enumConst->getInitVal(); + ASTIntegerLiteral *astIntegerLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + astIntegerLiteral->SetVal(value.getExtValue()); + astIntegerLiteral->SetType(astFile->CvtType(expr.getType())); + return astIntegerLiteral; + } + switch (expr.getStmtClass()) { + case clang::Stmt::DeclRefExprClass: { + ASTDecl *astDecl = ASTDeclsBuilder::GetASTDecl(expr.getDecl()->getCanonicalDecl()->getID()); + if (astDecl == nullptr) { + astDecl = ProcessDecl(allocator, *(expr.getDecl()->getCanonicalDecl())); + } + astRefExpr->SetASTDecl(astDecl); + astRefExpr->SetType(astDecl->GetTypeDesc().front()); + return astRefExpr; + } + default: + CHECK_FATAL(false, "NIY"); + return nullptr; + } + return nullptr; +} + +ASTExpr *ASTParser::ProcessExprBinaryOperatorComplex(MapleAllocator &allocator, const clang::BinaryOperator &bo) { + ASTBinaryOperatorExpr *astBinOpExpr = AllocBinaryOperatorExpr(allocator, bo); + CHECK_FATAL(astBinOpExpr != nullptr, "astBinOpExpr is nullptr"); + clang::QualType qualType = bo.getType(); + astBinOpExpr->SetRetType(astFile->CvtType(qualType)); + ASTExpr *astRExpr = ProcessExpr(allocator, bo.getRHS()); + ASTExpr *astLExpr = ProcessExpr(allocator, bo.getLHS()); + clang::QualType elementType = llvm::cast( + bo.getLHS()->getType().getCanonicalType())->getElementType(); + MIRType *elementMirType = astFile->CvtType(elementType); + astBinOpExpr->SetComplexElementType(elementMirType); + auto *leftImage = ASTDeclsBuilder::ASTExprBuilder(allocator); + leftImage->SetUOExpr(astLExpr); + leftImage->SetElementType(elementMirType); + astBinOpExpr->SetComplexLeftImagExpr(leftImage); + auto *leftReal = ASTDeclsBuilder::ASTExprBuilder(allocator); + leftReal->SetUOExpr(astLExpr); + leftReal->SetElementType(elementMirType); + astBinOpExpr->SetComplexLeftRealExpr(leftReal); + auto *rightImage = ASTDeclsBuilder::ASTExprBuilder(allocator); + rightImage->SetUOExpr(astRExpr); + rightImage->SetElementType(elementMirType); + astBinOpExpr->SetComplexRightImagExpr(rightImage); + auto *rightReal = ASTDeclsBuilder::ASTExprBuilder(allocator); + rightReal->SetUOExpr(astRExpr); + rightReal->SetElementType(elementMirType); + astBinOpExpr->SetComplexRightRealExpr(rightReal); + return astBinOpExpr; +} + +ASTExpr *ASTParser::ProcessExprBinaryOperator(MapleAllocator &allocator, const clang::BinaryOperator &bo) { + ASTBinaryOperatorExpr *astBinOpExpr = AllocBinaryOperatorExpr(allocator, bo); + CHECK_FATAL(astBinOpExpr != nullptr, "astBinOpExpr is nullptr"); + auto boType = bo.getType().getCanonicalType(); + auto lhsType = bo.getLHS()->getType().getCanonicalType(); + auto rhsType = bo.getRHS()->getType().getCanonicalType(); + auto leftMirType = astFile->CvtType(lhsType); + auto rightMirType = astFile->CvtType(rhsType); + auto clangOpCode = bo.getOpcode(); + astBinOpExpr->SetRetType(astFile->CvtType(boType)); + if (bo.isCompoundAssignmentOp()) { + clangOpCode = clang::BinaryOperator::getOpForCompoundAssignment(clangOpCode); + } + if ((boType->isAnyComplexType() && + (clang::BinaryOperator::isAdditiveOp(clangOpCode) || clang::BinaryOperator::isMultiplicativeOp(clangOpCode))) || + (clang::BinaryOperator::isEqualityOp(clangOpCode) && lhsType->isAnyComplexType() && + rhsType->isAnyComplexType())) { + return ProcessExprBinaryOperatorComplex(allocator, bo); + } + ASTExpr *astRExpr = ProcessExpr(allocator, bo.getRHS()); + ASTExpr *astLExpr = ProcessExpr(allocator, bo.getLHS()); + if (clangOpCode == clang::BO_Div || clangOpCode == clang::BO_Mul || + clangOpCode == clang::BO_DivAssign || clangOpCode == clang::BO_MulAssign) { + if (astBinOpExpr->GetRetType()->GetPrimType() == PTY_u16 || astBinOpExpr->GetRetType()->GetPrimType() == PTY_u8) { + astBinOpExpr->SetRetType(GlobalTables::GetTypeTable().GetPrimType(PTY_u32)); + } + if (astBinOpExpr->GetRetType()->GetPrimType() == PTY_i16 || astBinOpExpr->GetRetType()->GetPrimType() == PTY_i8) { + astBinOpExpr->SetRetType(GlobalTables::GetTypeTable().GetPrimType(PTY_i32)); + } + } + if ((leftMirType->GetPrimType() != astBinOpExpr->GetRetType()->GetPrimType() || + rightMirType->GetPrimType() != astBinOpExpr->GetRetType()->GetPrimType()) + && (clang::BinaryOperator::isAdditiveOp(clangOpCode) || clang::BinaryOperator::isMultiplicativeOp(clangOpCode))) { + astBinOpExpr->SetCvtNeeded(true); + } + // ptr +/- + if (boType->isPointerType() && clang::BinaryOperator::isAdditiveOp(clangOpCode) && + ((lhsType->isPointerType() && rhsType->isIntegerType()) || + (lhsType->isIntegerType() && rhsType->isPointerType())) && + !boType->isVoidPointerType() && GetSizeFromQualType(boType->getPointeeType()) != 1) { + auto boMirType = astFile->CvtType(boType); + auto typeSize = GetSizeFromQualType(boType->getPointeeType()); + MIRType *pointedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx( + static_cast(boMirType)->GetPointedTyIdx()); + if (pointedType->GetPrimType() == PTY_f64) { + typeSize = 8; // 8 is f64 byte num, because now f128 also cvt to f64 + } + if (lhsType->isPointerType()) { + astRExpr = GetAddrShiftExpr(allocator, astRExpr, typeSize); + } else if (rhsType->isPointerType()) { + astLExpr = GetAddrShiftExpr(allocator, astLExpr, typeSize); + } + astBinOpExpr->SetCvtNeeded(false); // the type cannot be cvt. + } + astBinOpExpr->SetLeftExpr(astLExpr); + astBinOpExpr->SetRightExpr(astRExpr); + // ptr - ptr + if (clangOpCode == clang::BO_Sub && rhsType->isPointerType() && + lhsType->isPointerType() && !rhsType->isVoidPointerType() && + GetSizeFromQualType(rhsType->getPointeeType()) != 1) { + auto ptrSizeExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + ptrSizeExpr->SetType(astBinOpExpr->GetRetType()); + ptrSizeExpr->SetVal(GetSizeFromQualType(rhsType->getPointeeType())); + auto retASTExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + retASTExpr->SetLeftExpr(astBinOpExpr); + retASTExpr->SetRightExpr(ptrSizeExpr); + retASTExpr->SetOpcode(OP_div); + retASTExpr->SetRetType(astBinOpExpr->GetRetType()); + astBinOpExpr = retASTExpr; + } + if (bo.isCompoundAssignmentOp()) { + auto assignExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + assignExpr->SetLeftExpr(astLExpr); + assignExpr->SetRightExpr(astBinOpExpr); + assignExpr->SetRetType(astBinOpExpr->GetRetType()); + assignExpr->SetIsCompoundAssign(true); + return assignExpr; + } + return astBinOpExpr; +} + +ASTDecl *ASTParser::GetAstDeclOfDeclRefExpr(MapleAllocator &allocator, const clang::Expr &expr) { + switch (expr.getStmtClass()) { + case clang::Stmt::DeclRefExprClass: + return static_cast(ProcessExpr(allocator, &expr))->GetASTDecl(); + case clang::Stmt::ImplicitCastExprClass: + case clang::Stmt::CXXStaticCastExprClass: + case clang::Stmt::CXXReinterpretCastExprClass: + case clang::Stmt::CStyleCastExprClass: + return GetAstDeclOfDeclRefExpr(allocator, *llvm::cast(expr).getSubExpr()); + case clang::Stmt::ParenExprClass: + return GetAstDeclOfDeclRefExpr(allocator, *llvm::cast(expr).getSubExpr()); + case clang::Stmt::UnaryOperatorClass: + return GetAstDeclOfDeclRefExpr(allocator, *llvm::cast(expr).getSubExpr()); + case clang::Stmt::ConstantExprClass: + return GetAstDeclOfDeclRefExpr(allocator, *llvm::cast(expr).getSubExpr()); + default: + break; + } + return nullptr; +} + +ASTExpr *ASTParser::ProcessExprCStyleCastExpr(MapleAllocator &allocator, const clang::CStyleCastExpr &castExpr) { + return ProcessExprCastExpr(allocator, castExpr); +} + +ASTExpr *ASTParser::ProcessExprArrayInitLoopExpr(MapleAllocator &allocator, + const clang::ArrayInitLoopExpr &arrInitLoopExpr) { + ASTArrayInitLoopExpr *astExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astExpr != nullptr, "astCastExpr is nullptr"); + ASTExpr *common = arrInitLoopExpr.getCommonExpr() == nullptr ? nullptr : + ProcessExpr(allocator, arrInitLoopExpr.getCommonExpr()); + astExpr->SetCommonExpr(common); + return astExpr; +} + +ASTExpr *ASTParser::ProcessExprArrayInitIndexExpr(MapleAllocator &allocator, + const clang::ArrayInitIndexExpr &arrInitIndexExpr) { + ASTArrayInitIndexExpr *astExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astExpr != nullptr, "astCastExpr is nullptr"); + astExpr->SetPrimType(astFile->CvtType(arrInitIndexExpr.getType())); + astExpr->SetValueStr("0"); + return astExpr; +} + +ASTExpr *ASTParser::ProcessExprAtomicExpr(MapleAllocator &allocator, + const clang::AtomicExpr &atomicExpr) { + ASTAtomicExpr *astExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astExpr != nullptr, "astCastExpr is nullptr"); + astExpr->SetObjExpr(ProcessExpr(allocator, atomicExpr.getPtr())); + astExpr->SetType(astFile->CvtType(atomicExpr.getPtr()->getType())); + astExpr->SetRefType(astFile->CvtType(atomicExpr.getPtr()->getType()->getPointeeType())); + if (atomicExpr.getOp() != clang::AtomicExpr::AO__atomic_load_n) { + astExpr->SetValExpr1(ProcessExpr(allocator, atomicExpr.getVal1())); + astExpr->SetVal1Type(astFile->CvtType(atomicExpr.getVal1()->getType())); + } + if (atomicExpr.getOp() == clang::AtomicExpr::AO__atomic_exchange) { + astExpr->SetValExpr2(ProcessExpr(allocator, atomicExpr.getVal2())); + astExpr->SetVal2Type(astFile->CvtType(atomicExpr.getVal2()->getType())); + } + astExpr->SetOrderExpr(ProcessExpr(allocator, atomicExpr.getOrder())); + + static std::unordered_map astOpMap = { + {clang::AtomicExpr::AO__atomic_load_n, kAtomicOpLoadN}, + {clang::AtomicExpr::AO__atomic_load, kAtomicOpLoad}, + {clang::AtomicExpr::AO__atomic_store_n, kAtomicOpStoreN}, + {clang::AtomicExpr::AO__atomic_store, kAtomicOpStore}, + {clang::AtomicExpr::AO__atomic_exchange, kAtomicOpExchange}, + {clang::AtomicExpr::AO__atomic_exchange_n, kAtomicOpExchangeN}, + {clang::AtomicExpr::AO__atomic_add_fetch, kAtomicOpAddFetch}, + {clang::AtomicExpr::AO__atomic_sub_fetch, kAtomicOpSubFetch}, + {clang::AtomicExpr::AO__atomic_and_fetch, kAtomicOpAndFetch}, + {clang::AtomicExpr::AO__atomic_xor_fetch, kAtomicOpXorFetch}, + {clang::AtomicExpr::AO__atomic_or_fetch, kAtomicOpOrFetch}, + {clang::AtomicExpr::AO__atomic_nand_fetch, kAtomicOpNandFetch}, + {clang::AtomicExpr::AO__atomic_fetch_add, kAtomicOpFetchAdd}, + {clang::AtomicExpr::AO__atomic_fetch_sub, kAtomicOpFetchSub}, + {clang::AtomicExpr::AO__atomic_fetch_and, kAtomicOpFetchAnd}, + {clang::AtomicExpr::AO__atomic_fetch_xor, kAtomicOpFetchXor}, + {clang::AtomicExpr::AO__atomic_fetch_or, kAtomicOpFetchOr}, + {clang::AtomicExpr::AO__atomic_fetch_nand, kAtomicOpFetchNand}, + }; + CHECK(astOpMap.find(atomicExpr.getOp()) != astOpMap.end(), "atomic expr op not supported!"); + astExpr->SetAtomicOp(astOpMap[atomicExpr.getOp()]); + return astExpr; +} + +ASTExpr *ASTParser::ProcessExprExprWithCleanups(MapleAllocator &allocator, + const clang::ExprWithCleanups &cleanupsExpr) { + ASTExprWithCleanups *astExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astExpr != nullptr, "astCastExpr is nullptr"); + ASTExpr *sub = cleanupsExpr.getSubExpr() == nullptr ? nullptr : ProcessExpr(allocator, cleanupsExpr.getSubExpr()); + astExpr->SetSubExpr(sub); + return astExpr; +} + +ASTExpr *ASTParser::ProcessExprMaterializeTemporaryExpr(MapleAllocator &allocator, + const clang::MaterializeTemporaryExpr &matTempExpr) { + // cxx feature + (void)allocator; + (void)matTempExpr; + return nullptr; +} + +ASTExpr *ASTParser::ProcessExprSubstNonTypeTemplateParmExpr(MapleAllocator &allocator, + const clang::SubstNonTypeTemplateParmExpr &subTempExpr) { + // cxx feature + (void)allocator; + (void)subTempExpr; + return nullptr; +} + +ASTExpr *ASTParser::ProcessExprDependentScopeDeclRefExpr(MapleAllocator &allocator, + const clang::DependentScopeDeclRefExpr &depScopeExpr) { + // cxx feature + (void)allocator; + (void)depScopeExpr; + return nullptr; +} + +ASTExpr *ASTParser::ProcessExprChooseExpr(MapleAllocator &allocator, const clang::ChooseExpr &chs) { + return ProcessExpr(allocator, chs.getChosenSubExpr()); +} + +ASTExpr *ASTParser::ProcessExprGenericSelectionExpr(MapleAllocator &allocator, const clang::GenericSelectionExpr &gse) { + return ProcessExpr(allocator, gse.getResultExpr()); +} + +bool ASTParser::PreProcessAST() { + TraverseDecl(astUnitDecl, [&](clang::Decl *child) { + switch (child->getKind()) { + case clang::Decl::Var: { + globalVarDecles.emplace_back(child); + break; + } + case clang::Decl::Function: { + funcDecles.emplace_back(child); + break; + } + case clang::Decl::Record: { + recordDecles.emplace_back(child); + break; + } + case clang::Decl::Typedef: + globalTypeDefDecles.emplace_back(child); + break; + case clang::Decl::Enum: + globalEnumDecles.emplace_back(child); + break; + case clang::Decl::FileScopeAsm: + globalFileScopeAsm.emplace_back(child); + break; + case clang::Decl::Empty: + case clang::Decl::StaticAssert: + break; + default: { + WARN(kLncWarn, "Unsupported decl kind: %u", child->getKind()); + } + } + }); + return true; +} + +#define DECL_CASE(CLASS) \ + case clang::Decl::CLASS: { \ + ASTDecl *astDeclaration = ProcessDecl##CLASS##Decl(allocator, llvm::cast(decl)); \ + if (astDeclaration != nullptr) { \ + astDeclaration->SetDeclPos(astFile->GetDeclPosInfo(decl)); \ + astDeclaration->SetGlobal(decl.isDefinedOutsideFunctionOrMethod()); \ + Pos loc = astFile->GetLOC(decl.getLocation()); \ + astDeclaration->SetSrcLOC(loc.first, loc.second); \ + } \ + return astDeclaration; \ + } +ASTDecl *ASTParser::ProcessDecl(MapleAllocator &allocator, const clang::Decl &decl) { + ASTDecl *astDecl = ASTDeclsBuilder::GetASTDecl(decl.getID()); + if (astDecl != nullptr) { + return astDecl; + } + switch (decl.getKind()) { + DECL_CASE(Function); + DECL_CASE(Field); + DECL_CASE(Record); + DECL_CASE(Var); + DECL_CASE(ParmVar); + DECL_CASE(Enum); + DECL_CASE(Typedef); + DECL_CASE(EnumConstant); + DECL_CASE(Label); + DECL_CASE(StaticAssert); + DECL_CASE(FileScopeAsm); + default: + CHECK_FATAL(false, "ASTDecl: %s NIY", decl.getDeclKindName()); + return nullptr; + } + return nullptr; +} + +ASTDecl *ASTParser::ProcessDeclStaticAssertDecl(MapleAllocator &allocator, const clang::StaticAssertDecl &assertDecl) { + (void)allocator; + (void)assertDecl; + return nullptr; +} + +ASTDecl *ASTParser::ProcessDeclRecordDecl(MapleAllocator &allocator, const clang::RecordDecl &recDecl) { + ASTStruct *curStructOrUnion = static_cast(ASTDeclsBuilder::GetASTDecl(recDecl.getID())); + if (curStructOrUnion != nullptr) { + return curStructOrUnion; + } + std::stringstream recName; + clang::QualType qType = recDecl.getTypeForDecl()->getCanonicalTypeInternal(); + astFile->EmitTypeName(*qType->getAs(), recName); + MIRType *recType = astFile->CvtType(qType); + if (recType == nullptr) { + return nullptr; + } + GenericAttrs attrs; + astFile->CollectRecordAttrs(recDecl, attrs, kNone); + std::string structName = recName.str(); + if (structName.empty() || !ASTUtil::IsValidName(structName)) { + structName = astFile->GetTypedefNameFromUnnamedStruct(recDecl); + if (structName.empty()) { + uint32 id = qType->getAs()->getDecl()->getLocation().getRawEncoding(); + structName = astFile->GetOrCreateMappedUnnamedName(id); + } + } else if (FEOptions::GetInstance().GetFuncInlineSize() != 0) { + std::string recordLayoutStr = recDecl.getDefinition() == nullptr ? "" : + ASTUtil::GetRecordLayoutString(astFile->GetContext()->getASTRecordLayout(recDecl.getDefinition())); + std::string filename = astFile->GetContext()->getSourceManager().getFilename(recDecl.getLocation()).str(); + structName = structName + FEUtils::GetFileNameHashStr(filename + recordLayoutStr); + } + curStructOrUnion = ASTDeclsBuilder::ASTStructBuilder( + allocator, fileName, structName, std::vector{recType}, attrs, recDecl.getID()); + if (recDecl.isUnion()) { + curStructOrUnion->SetIsUnion(); + } + const auto *declContext = llvm::dyn_cast(&recDecl); + if (declContext == nullptr) { + return nullptr; + } + for (auto *loadDecl : declContext->decls()) { + if (loadDecl == nullptr) { + return nullptr; + } + auto *fieldDecl = llvm::dyn_cast(loadDecl); + if (llvm::isa(loadDecl)) { + clang::RecordDecl *subRecordDecl = llvm::cast(loadDecl->getCanonicalDecl()); + ASTStruct *sub = static_cast(ProcessDecl(allocator, *subRecordDecl)); + if (sub == nullptr) { + return nullptr; + } + } + + if (llvm::isa(loadDecl)) { + ASTField *af = static_cast(ProcessDecl(allocator, *fieldDecl)); + if (af == nullptr) { + return nullptr; + } + curStructOrUnion->SetField(af); + } + } + if (!recDecl.isDefinedOutsideFunctionOrMethod()) { + // Record function scope type decl in global with unique suffix identified + auto itor = std::find(astStructs.begin(), astStructs.end(), curStructOrUnion); + if (itor == astStructs.end()) { + astStructs.emplace_back(curStructOrUnion); + } + } + ProcessBoundaryFieldAttrs(allocator, *curStructOrUnion, recDecl); + return curStructOrUnion; +} + +ASTDecl *ASTParser::ProcessDeclFunctionDecl(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl) { + ASTFunc *astFunc = static_cast(ASTDeclsBuilder::GetASTDecl(funcDecl.getID())); + if (astFunc != nullptr) { + return astFunc; + } + std::string funcName = astFile->GetMangledName(funcDecl); + if (funcName.empty()) { + return nullptr; + } + if (!ASTUtil::IsValidName(funcName)) { + ASTUtil::AdjustName(funcName); + } + std::vector typeDescIn; + clang::QualType funcQualType = funcDecl.getType(); + MIRType *mirFuncType = astFile->CvtType(funcQualType); + typeDescIn.push_back(mirFuncType); + clang::QualType qualType = funcDecl.getReturnType(); + MIRType *retType = astFile->CvtType(qualType); + if (retType == nullptr) { + return nullptr; + } + std::vector paramDecls; + typeDescIn.push_back(retType); + unsigned int numParam = funcDecl.getNumParams(); + std::list implicitStmts; + for (uint32_t i = 0; i < numParam; ++i) { + const clang::ParmVarDecl *parmDecl = funcDecl.getParamDecl(i); + ASTExpr *expr = ProcessExprInType(allocator, parmDecl->getOriginalType()); + if (expr != nullptr) { + ASTStmtDummy *stmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + stmt->SetASTExpr(expr); + implicitStmts.emplace_back(stmt); + } + ASTDecl *parmVarDecl = ProcessDecl(allocator, *parmDecl); + paramDecls.push_back(parmVarDecl); + typeDescIn.push_back(parmVarDecl->GetTypeDesc().front()); + } + GenericAttrs attrs; + astFile->CollectFuncAttrs(funcDecl, attrs, kPublic); + // for inline optimize + if (attrs.GetAttr(GENATTR_static) && FEOptions::GetInstance().GetFuncInlineSize() != 0) { + funcName = funcName + astFile->GetAstFileNameHashStr(); + } + // one element vector type in rettype + if (LibAstFile::IsOneElementVector(qualType)) { + attrs.SetAttr(GENATTR_oneelem_simd); + } + if (FEOptions::GetInstance().IsEnableSafeRegion()) { + if (funcDecl.getSafeSpecifier() == clang::SS_Unsafe) { + attrs.SetAttr(GENATTR_unsafed); + } else if (funcDecl.getSafeSpecifier() == clang::SS_Safe) { + attrs.SetAttr(GENATTR_safed); + } + } + astFunc = ASTDeclsBuilder::ASTFuncBuilder( + allocator, fileName, funcName, typeDescIn, attrs, paramDecls, funcDecl.getID()); + CHECK_FATAL(astFunc != nullptr, "astFunc is nullptr"); + clang::SectionAttr *sa = funcDecl.getAttr(); + if (sa != nullptr && !sa->isImplicit()) { + astFunc->SetSectionAttr(sa->getName().str()); + } + // collect EnhanceC func attr + ProcessNonnullFuncAttrs(funcDecl, *astFunc); + ProcessBoundaryFuncAttrs(allocator, funcDecl, *astFunc); + ProcessBoundaryParamAttrs(allocator, funcDecl, *astFunc); + clang::WeakRefAttr *weakrefAttr = funcDecl.getAttr(); + if (weakrefAttr != nullptr) { + astFunc->SetWeakrefAttr(std::pair { true, weakrefAttr->getAliasee().str() }); + } + if (funcDecl.hasBody()) { + ASTStmt *astCompoundStmt = ProcessStmt(allocator, *llvm::cast(funcDecl.getBody())); + if (astCompoundStmt != nullptr) { + astFunc->SetCompoundStmt(astCompoundStmt); + astFunc->InsertStmtsIntoCompoundStmtAtFront(implicitStmts); + } else { + return nullptr; + } +#ifndef STMTS_AS_BODY_SIZE + Pos startLoc = astFile->GetLOC(llvm::cast(funcDecl.getBody())->getBeginLoc()); + Pos endLoc = astFile->GetLOC(llvm::cast(funcDecl.getBody())->getEndLoc()); + astFunc->SetSize(static_cast(endLoc.second - startLoc.second)); +#else + astFunc->SetSize(static_cast(static_cast(astCompoundStmt)->GetASTStmtList().size())); +#endif + } + return astFunc; +} + +void ASTParser::ProcessNonnullFuncAttrs(const clang::FunctionDecl &funcDecl, ASTFunc &astFunc) { + if (funcDecl.hasAttr()) { + astFunc.SetAttr(GENATTR_nonnull); + } + for (const auto *nonNull : funcDecl.specific_attrs()) { + if (!nonNull->args_size()) { + // Lack of attribute parameters means that all of the pointer parameters are + // implicitly marked as nonnull. + for (auto paramDecl : astFunc.GetParamDecls()) { + if (paramDecl->GetTypeDesc().front()->IsMIRPtrType()) { + paramDecl->SetAttr(GENATTR_nonnull); + } + } + break; + } + for (const clang::ParamIdx ¶mIdx : nonNull->args()) { + // The clang ensures that nonnull attribute only applies to pointer parameter + unsigned int idx = paramIdx.getASTIndex(); + if (idx >= astFunc.GetParamDecls().size()) { + continue; + } + astFunc.GetParamDecls()[idx]->SetAttr(GENATTR_nonnull); + } + } +} + +ASTDecl *ASTParser::ProcessDeclFieldDecl(MapleAllocator &allocator, const clang::FieldDecl &decl) { + ASTField *astField = static_cast(ASTDeclsBuilder::GetASTDecl(decl.getID())); + if (astField != nullptr) { + return astField; + } + clang::QualType qualType = decl.getType(); + std::string fieldName = astFile->GetMangledName(decl); + bool isAnonymousField = false; + if (fieldName.empty()) { + isAnonymousField = true; + uint32 id = decl.getLocation().getRawEncoding(); + fieldName = astFile->GetOrCreateMappedUnnamedName(id); + } + CHECK_FATAL(!fieldName.empty(), "fieldName is empty"); + MIRType *fieldType = astFile->CvtType(qualType); + if (fieldType == nullptr) { + return nullptr; + } + if (decl.isBitField()) { + unsigned bitSize = decl.getBitWidthValue(*(astFile->GetContext())); + MIRBitFieldType mirBFType(static_cast(bitSize), fieldType->GetPrimType()); + auto bfTypeIdx = GlobalTables::GetTypeTable().GetOrCreateMIRType(&mirBFType); + fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(bfTypeIdx); + } + GenericAttrs attrs; + astFile->CollectFieldAttrs(decl, attrs, kNone); + // one elem vector type + if (LibAstFile::IsOneElementVector(qualType)) { + attrs.SetAttr(GENATTR_oneelem_simd); + } + auto fieldDecl = ASTDeclsBuilder::ASTFieldBuilder( + allocator, fileName, fieldName, std::vector{fieldType}, attrs, decl.getID(), isAnonymousField); + clang::CharUnits alignment = astFile->GetContext()->getDeclAlign(&decl); + clang::CharUnits unadjust = astFile->GetContext()->toCharUnitsFromBits( + astFile->GetContext()->getTypeUnadjustedAlign(qualType)); + uint32 maxAlign = std::max(alignment.getQuantity(), unadjust.getQuantity()); + fieldDecl->SetAlign(maxAlign); + const auto *valueDecl = llvm::dyn_cast(&decl); + if (valueDecl != nullptr) { + ProcessNonnullFuncPtrAttrs(*valueDecl, *fieldDecl); + ProcessBoundaryFuncPtrAttrs(allocator, *valueDecl, *fieldDecl); + } + return fieldDecl; +} + +ASTDecl *ASTParser::ProcessDeclVarDecl(MapleAllocator &allocator, const clang::VarDecl &varDecl) { + ASTVar *astVar = static_cast(ASTDeclsBuilder::GetASTDecl(varDecl.getID())); + if (astVar != nullptr) { + return astVar; + } + std::string varName = astFile->GetMangledName(varDecl); + if (varName.empty()) { + return nullptr; + } + clang::QualType qualType = varDecl.getType(); + MIRType *varType = astFile->CvtType(qualType); + if (varType == nullptr) { + return nullptr; + } + GenericAttrs attrs; + astFile->CollectVarAttrs(varDecl, attrs, kNone); + // for inline optimize + if (attrs.GetAttr(GENATTR_static) && FEOptions::GetInstance().GetFuncInlineSize() != 0) { + varName = varName + astFile->GetAstFileNameHashStr(); + } + + if (llvm::isa(varDecl.getType())) { + CHECK_FATAL(FEOptions::GetInstance().IsEnableVariableArray(), + "Intercepts variable arrays, because the backend does not yet support."); + MIRType *elementType = static_cast(varType)->GetElemType(); + varType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*elementType); + } + astVar = ASTDeclsBuilder::ASTVarBuilder( + allocator, fileName, varName, std::vector{varType}, attrs, varDecl.getID()); + astVar->SetIsMacro(varDecl.getLocation().isMacroID()); + clang::SectionAttr *sa = varDecl.getAttr(); + if (sa != nullptr && !sa->isImplicit()) { + astVar->SetSectionAttr(sa->getName().str()); + } + clang::AsmLabelAttr *ala = varDecl.getAttr(); + if (ala != nullptr) { + astVar->SetAsmAttr(ala->getLabel().str()); + } + if (varDecl.hasInit()) { + astVar->SetDeclPos(astFile->GetDeclPosInfo(varDecl)); + auto initExpr = varDecl.getInit(); + auto astInitExpr = ProcessExpr(allocator, initExpr); + if (initExpr->getStmtClass() == clang::Stmt::InitListExprClass && astInitExpr->GetASTOp() == kASTOpInitListExpr) { + static_cast(astInitExpr)->SetInitListVarName(astVar->GenerateUniqueVarName()); + } + astVar->SetInitExpr(astInitExpr); + } + if (llvm::isa(varDecl.getType())) { + CHECK_FATAL(FEOptions::GetInstance().IsEnableVariableArray(), + "Intercepts variable arrays, because the backend does not yet support."); + astVar->SetVariableArrayExpr(GetTypeSizeFromQualType(allocator, varDecl.getType())); + } + if (!varDecl.getType()->isIncompleteType()) { + int64 naturalAlignment = astFile->GetContext()->toCharUnitsFromBits( + astFile->GetContext()->getTypeUnadjustedAlign(varDecl.getType())).getQuantity(); + + // Get alignment from the decl + if (uint32 alignmentBits = varDecl.getMaxAlignment()) { + uint32 alignment = alignmentBits / 8; + if (alignment > naturalAlignment) { + astVar->SetAlign(alignment); + } + } + + // Get alignment from the type + if (uint32 alignmentBits = astFile->GetContext()->getTypeAlignIfKnown(varDecl.getType())) { + uint32 alignment = alignmentBits / 8; + if (alignment > astVar->GetAlign() && alignment > naturalAlignment) { + astVar->SetAlign(alignment); + } + } + } + const auto *valueDecl = llvm::dyn_cast(&varDecl); + if (valueDecl != nullptr) { + ProcessNonnullFuncPtrAttrs(*valueDecl, *astVar); + ProcessBoundaryFuncPtrAttrs(allocator, *valueDecl, *astVar); + } + ProcessBoundaryVarAttrs(allocator, varDecl, *astVar); + return astVar; +} + +ASTDecl *ASTParser::ProcessDeclParmVarDecl(MapleAllocator &allocator, const clang::ParmVarDecl &parmVarDecl) { + ASTVar *parmVar = static_cast(ASTDeclsBuilder::GetASTDecl(parmVarDecl.getID())); + if (parmVar != nullptr) { + return parmVar; + } + const clang::QualType parmQualType = parmVarDecl.getType(); + std::string parmName = parmVarDecl.getNameAsString(); + if (parmName.length() == 0) { + parmName = FEUtils::GetSequentialName("arg|"); + } + MIRType *paramType = astFile->CvtType(parmQualType); + if (paramType == nullptr) { + return nullptr; + } + GenericAttrs attrs; + astFile->CollectAttrs(parmVarDecl, attrs, kNone); + if (LibAstFile::IsOneElementVector(parmQualType)) { + attrs.SetAttr(GENATTR_oneelem_simd); + } + parmVar = ASTDeclsBuilder::ASTVarBuilder( + allocator, fileName, parmName, std::vector{paramType}, attrs, parmVarDecl.getID()); + parmVar->SetIsParam(true); + const auto *valueDecl = llvm::dyn_cast(&parmVarDecl); + if (valueDecl != nullptr) { + ProcessNonnullFuncPtrAttrs(*valueDecl, *parmVar); + ProcessBoundaryFuncPtrAttrs(allocator, *valueDecl, *parmVar); + } + return parmVar; +} + +ASTDecl *ASTParser::ProcessDeclFileScopeAsmDecl(MapleAllocator &allocator, const clang::FileScopeAsmDecl &asmDecl) { + ASTFileScopeAsm *astAsmDecl = allocator.GetMemPool()->New(fileName); + astAsmDecl->SetAsmStr(asmDecl.getAsmString()->getString().str()); + return astAsmDecl; +} + +ASTDecl *ASTParser::ProcessDeclEnumDecl(MapleAllocator &allocator, const clang::EnumDecl &enumDecl) { + ASTEnumDecl *localEnumDecl = static_cast(ASTDeclsBuilder::GetASTDecl(enumDecl.getID())); + if (localEnumDecl != nullptr) { + return localEnumDecl; + } + GenericAttrs attrs; + astFile->CollectAttrs(*clang::dyn_cast(&enumDecl), attrs, kNone); + const std::string &enumName = clang::dyn_cast(&enumDecl)->getNameAsString(); + localEnumDecl = ASTDeclsBuilder::ASTLocalEnumDeclBuilder(allocator, fileName, enumName, + std::vector{}, attrs, enumDecl.getID()); + TraverseDecl(&enumDecl, [&](clang::Decl *child) { + CHECK_FATAL(child->getKind() == clang::Decl::EnumConstant, "Unsupported decl kind: %u", child->getKind()); + localEnumDecl->PushConstant(static_cast(ProcessDecl(allocator, *child))); + }); + return localEnumDecl; +} + +ASTDecl *ASTParser::ProcessDeclTypedefDecl(MapleAllocator &allocator, const clang::TypedefDecl &typeDefDecl) { + clang::QualType underlyCanonicalTy = typeDefDecl.getCanonicalDecl()->getUnderlyingType().getCanonicalType(); + // For used type completeness + // Only process implicit record type here + if (underlyCanonicalTy->isRecordType()) { + const auto *recordType = llvm::cast(underlyCanonicalTy); + clang::RecordDecl *recordDecl = recordType->getDecl(); + if (recordDecl->isImplicit()) { + return ProcessDecl(allocator, *recordDecl); + } + } + return nullptr; // skip primitive type and explicit declared type +} + +ASTDecl *ASTParser::ProcessDeclEnumConstantDecl(MapleAllocator &allocator, const clang::EnumConstantDecl &decl) { + ASTEnumConstant *astConst = static_cast(ASTDeclsBuilder::GetASTDecl(decl.getID())); + if (astConst != nullptr) { + return astConst; + } + GenericAttrs attrs; + astFile->CollectAttrs(*clang::dyn_cast(&decl), attrs, kNone); + const std::string &varName = clang::dyn_cast(&decl)->getNameAsString(); + MIRType *mirType = astFile->CvtType(clang::dyn_cast(&decl)->getType()); + astConst = ASTDeclsBuilder::ASTEnumConstBuilder( + allocator, fileName, varName, std::vector{mirType}, attrs, decl.getID()); + + astConst->SetValue(static_cast(clang::dyn_cast(&decl)->getInitVal().getExtValue())); + return astConst; +} + +ASTDecl *ASTParser::ProcessDeclLabelDecl(MapleAllocator &allocator, const clang::LabelDecl &decl) { + ASTDecl *astDecl= static_cast(ASTDeclsBuilder::GetASTDecl(decl.getID())); + if (astDecl != nullptr) { + return astDecl; + } + std::string varName = astFile->GetMangledName(decl); + CHECK_FATAL(!varName.empty(), "label string is null"); + varName = FEUtils::GetSequentialName0(varName + "@", FEUtils::GetSequentialNumber()); + astDecl = ASTDeclsBuilder::ASTDeclBuilder(allocator, fileName, varName, std::vector{}, decl.getID()); + return astDecl; +} + +bool ASTParser::RetrieveStructs(MapleAllocator &allocator) { + for (auto &decl : recordDecles) { + clang::RecordDecl *recDecl = llvm::cast(decl->getCanonicalDecl()); + if (!recDecl->isCompleteDefinition()) { + clang::RecordDecl *recDeclDef = recDecl->getDefinition(); + if (recDeclDef == nullptr) { + continue; + } else { + recDecl = recDeclDef; + } + } + ASTStruct *curStructOrUnion = static_cast(ProcessDecl(allocator, *recDecl)); + if (curStructOrUnion == nullptr) { + return false; + } + curStructOrUnion->SetGlobal(true); + auto itor = std::find(astStructs.begin(), astStructs.end(), curStructOrUnion); + if (itor != astStructs.end()) { + } else { + astStructs.emplace_back(curStructOrUnion); + } + } + return true; +} + +bool ASTParser::RetrieveFuncs(MapleAllocator &allocator) { + for (auto &func : funcDecles) { + clang::FunctionDecl *funcDecl = llvm::cast(func); + if (funcDecl->isDefined()) { + clang::SafeScopeSpecifier spec = funcDecl->getSafeSpecifier(); + funcDecl = funcDecl->getDefinition(); + if (funcDecl->getSafeSpecifier() != spec) { + if (funcDecl->getSafeSpecifier() != clang::SS_None && spec != clang::SS_None) { + std::string funcName = astFile->GetMangledName(*funcDecl); + Pos loc = astFile->GetLOC(funcDecl->getLocation()); + FE_ERR(kLncWarn, "%s:%d error: The function %s declaration and definition security attributes " + "are inconsistent.", FEManager::GetModule().GetFileNameFromFileNum(loc.first).c_str(), loc.second, + funcName.c_str()); + } else { + if (funcDecl->getSafeSpecifier() == clang::SS_None) { + funcDecl->setSafeSpecifier(spec); + } + } + } + } + ASTFunc *af = static_cast(ProcessDecl(allocator, *funcDecl)); + if (af == nullptr) { + return false; + } + af->SetGlobal(true); + astFuncs.emplace_back(af); + } + return true; +} + +// seperate MP with astparser +bool ASTParser::RetrieveGlobalVars(MapleAllocator &allocator) { + for (auto &decl : globalVarDecles) { + clang::VarDecl *varDecl = llvm::cast(decl); + ASTVar *val = static_cast(ProcessDecl(allocator, *varDecl)); + if (val == nullptr) { + return false; + } + astVars.emplace_back(val); + } + return true; +} + +bool ASTParser::RetrieveFileScopeAsms(MapleAllocator &allocator) { + for (auto &decl : globalFileScopeAsm) { + clang::FileScopeAsmDecl *fileScopeAsmDecl = llvm::cast(decl); + ASTFileScopeAsm *asmDecl = static_cast(ProcessDecl(allocator, *fileScopeAsmDecl)); + if (asmDecl == nullptr) { + return false; + } + astFileScopeAsms.emplace_back(asmDecl); + } + return true; +} + +bool ASTParser::ProcessGlobalTypeDef(MapleAllocator &allocator) { + for (auto gTypeDefDecl : globalTypeDefDecles) { + (void)ProcessDecl(allocator, *gTypeDefDecl); + } + return true; +} + +const std::string &ASTParser::GetSourceFileName() const { + return fileName; +} + +const uint32 ASTParser::GetFileIdx() const { + return fileIdx; +} + +void ASTParser::TraverseDecl(const clang::Decl *decl, std::function const &functor) { + if (decl == nullptr) { + return; + } + for (auto *child : clang::dyn_cast(decl)->decls()) { + functor(child); + } +} +} // namespace maple diff --git a/src/hir2mpl/ast_input/clang/src/ast_parser_builting_func.cpp b/src/hir2mpl/ast_input/clang/src/ast_parser_builting_func.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d01637c527c9444544e05039c13a43d79e88e6ee --- /dev/null +++ b/src/hir2mpl/ast_input/clang/src/ast_parser_builting_func.cpp @@ -0,0 +1,720 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ast_expr.h" +#include "ast_decl.h" +#include "ast_decl_builder.h" +#include "ast_interface.h" +#include "ast_util.h" +#include "ast_input.h" +#include "ast_stmt.h" +#include "ast_parser.h" +#include "feir_stmt.h" +#include "feir_builder.h" +#include "fe_utils_ast.h" +#include "feir_type_helper.h" +#include "fe_manager.h" +#include "mir_module.h" +#include "mpl_logging.h" + +namespace maple { +std::unordered_map ASTCallExpr::InitBuiltinFuncPtrMap() { + std::unordered_map ans; +#define BUILTIN_FUNC_EMIT(funcName, FuncPtrBuiltinFunc) \ + ans[funcName] = FuncPtrBuiltinFunc; +#include "builtin_func_emit.def" +#undef BUILTIN_FUNC_EMIT + // vector builtinfunc +#define DEF_MIR_INTRINSIC(STR, NAME, INTRN_CLASS, RETURN_TYPE, ...) \ + ans["__builtin_mpl_"#STR] = &ASTCallExpr::EmitBuiltin##STR; +#include "intrinsic_vector.def" +#undef DEF_MIR_INTRINSIC + + return ans; +} + +UniqueFEIRExpr ASTCallExpr::CreateIntrinsicCallForC(std::list &stmts, + MIRIntrinsicID argIntrinsicID) const { + auto feTy = std::make_unique(*mirType); + auto exprArgList = std::make_unique>(); + for (auto arg : args) { + UniqueFEIRExpr expr = arg->Emit2FEExpr(stmts); + exprArgList->emplace_back(std::move(expr)); + } + std::string retName = FEUtils::GetSequentialName("intrincall_res_var_"); + UniqueFEIRVar retVar = FEIRBuilder::CreateVarNameForC(retName, *retType); + std::unique_ptr stmt = std::make_unique( + argIntrinsicID, std::move(feTy), retVar->Clone(), std::move(exprArgList)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + auto dread = FEIRBuilder::CreateExprDRead(retVar->Clone()); + return dread; +} + +UniqueFEIRExpr ASTCallExpr::CreateIntrinsicopForC(std::list &stmts, + MIRIntrinsicID argIntrinsicID, bool genTempVar) const { + auto feTy = std::make_unique(*mirType); + std::vector> argOpnds; + for (auto arg : args) { + argOpnds.push_back(arg->Emit2FEExpr(stmts)); + } + auto feExpr = std::make_unique(std::move(feTy), argIntrinsicID, argOpnds); + if (mirType->GetPrimType() == PTY_void) { + std::list feExprs; + feExprs.emplace_back(std::move(feExpr)); + UniqueFEIRStmt evalStmt = std::make_unique(OP_eval, std::move(feExprs)); + evalStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(evalStmt)); + return nullptr; + } else { + if (!genTempVar) { + return feExpr; + } + std::string tmpName = FEUtils::GetSequentialName("intrinsicop_var_"); + UniqueFEIRVar tmpVar = FEIRBuilder::CreateVarNameForC(tmpName, *mirType); + UniqueFEIRStmt dAssign = std::make_unique(tmpVar->Clone(), std::move(feExpr), 0); + dAssign->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(dAssign)); + auto dread = FEIRBuilder::CreateExprDRead(tmpVar->Clone()); + return dread; + } +} + +UniqueFEIRExpr ASTCallExpr::CreateBinaryExpr(std::list &stmts, Opcode op) const { + auto feTy = std::make_unique(*mirType); + auto arg1 = args[0]->Emit2FEExpr(stmts); + auto arg2 = args[1]->Emit2FEExpr(stmts); + return std::make_unique(std::move(feTy), op, std::move(arg1), std::move(arg2)); +} + +UniqueFEIRExpr ASTCallExpr::ProcessBuiltinFunc(std::list &stmts, bool &isFinish) const { + // process a kind of builtinFunc + std::string prefix = "__builtin_mpl_vector_load"; + if (funcName.compare(0, prefix.size(), prefix) == 0) { + auto argExpr = args[0]->Emit2FEExpr(stmts); + UniqueFEIRType type = FEIRTypeHelper::CreateTypeNative(*mirType); + UniqueFEIRType ptrType = FEIRTypeHelper::CreateTypeNative( + *GlobalTables::GetTypeTable().GetOrCreatePointerType(*mirType)); + isFinish = true; + return FEIRBuilder::CreateExprIRead(std::move(type), std::move(ptrType), std::move(argExpr)); + } + prefix = "__builtin_mpl_vector_store"; + if (funcName.compare(0, prefix.size(), prefix) == 0) { + auto arg1Expr = args[0]->Emit2FEExpr(stmts); + auto arg2Expr = args[1]->Emit2FEExpr(stmts); + UniqueFEIRType type = FEIRTypeHelper::CreateTypeNative( + *GlobalTables::GetTypeTable().GetOrCreatePointerType(*args[1]->GetType())); + auto stmt = FEIRBuilder::CreateStmtIAssign(std::move(type), std::move(arg1Expr), std::move(arg2Expr)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + isFinish = true; + return nullptr; + } + prefix = "__builtin_mpl_vector_zip"; + if (funcName.compare(0, prefix.size(), prefix) == 0) { + return EmitBuiltinVectorZip(stmts, isFinish); + } + prefix = "__builtin_mpl_vector_shli"; + if (funcName.compare(0, prefix.size(), prefix) == 0) { + isFinish = true; + UniqueFEIRType type = FEIRTypeHelper::CreateTypeNative(*args[0]->GetType()); + auto arg1Expr = args[0]->Emit2FEExpr(stmts); + auto arg2Expr = args[1]->Emit2FEExpr(stmts); + return FEIRBuilder::CreateExprBinary(std::move(type), OP_shl, std::move(arg1Expr), std::move(arg2Expr)); + } + prefix = "__builtin_mpl_vector_shri"; + if (funcName.compare(0, prefix.size(), prefix) == 0) { + isFinish = true; + UniqueFEIRType type = FEIRTypeHelper::CreateTypeNative(*args[0]->GetType()); + auto arg1Expr = args[0]->Emit2FEExpr(stmts); + auto arg2Expr = args[1]->Emit2FEExpr(stmts); + return FEIRBuilder::CreateExprBinary(std::move(type), OP_ashr, std::move(arg1Expr), std::move(arg2Expr)); + } + prefix = "__builtin_mpl_vector_shru"; + if (funcName.compare(0, prefix.size(), prefix) == 0) { + isFinish = true; + UniqueFEIRType type = FEIRTypeHelper::CreateTypeNative(*args[0]->GetType()); + auto arg1Expr = args[0]->Emit2FEExpr(stmts); + auto arg2Expr = args[1]->Emit2FEExpr(stmts); + return FEIRBuilder::CreateExprBinary(std::move(type), OP_lshr, std::move(arg1Expr), std::move(arg2Expr)); + } + // process a single builtinFunc + auto ptrFunc = builtingFuncPtrMap.find(funcName); + if (ptrFunc != builtingFuncPtrMap.end()) { + isFinish = true; + return EmitBuiltinFunc(stmts); + } + isFinish = false; + if (FEOptions::GetInstance().GetDumpLevel() >= FEOptions::kDumpLevelInfo) { + prefix = "__builtin"; + if (funcName.compare(0, prefix.size(), prefix) == 0) { + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "%s:%d BuiltinFunc (%s) has not been implemented", + FEManager::GetModule().GetFileNameFromFileNum(GetSrcFileIdx()).c_str(), GetSrcFileLineNum(), + funcName.c_str()); + } + } + return nullptr; +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinFunc(std::list &stmts) const { + return (this->*(builtingFuncPtrMap[funcName]))(stmts); +} + +#define DEF_MIR_INTRINSIC(STR, NAME, INTRN_CLASS, RETURN_TYPE, ...) \ +UniqueFEIRExpr ASTCallExpr::EmitBuiltin##STR(std::list &stmts) const { \ + auto feType = FEIRTypeHelper::CreateTypeNative(*mirType); \ + std::vector> argOpnds; \ + for (auto arg : args) { \ + argOpnds.push_back(arg->Emit2FEExpr(stmts)); \ + } \ + return std::make_unique(std::move(feType), INTRN_##STR, argOpnds); \ +} +#include "intrinsic_vector.def" +#undef DEF_MIR_INTRINSIC + +#define DEF_INTRIN_C_CALL(NAME, INTRIN_NAME) \ +UniqueFEIRExpr ASTCallExpr::EmitBuiltin##NAME(std::list &stmts) const { \ + return CreateIntrinsicCallForC(stmts, INTRN_C_##INTRIN_NAME); \ +} + +#define DEF_INTRIN_C_OP(NAME, INTRIN_NAME) \ +UniqueFEIRExpr ASTCallExpr::EmitBuiltin##NAME(std::list &stmts) const { \ + return CreateIntrinsicopForC(stmts, INTRN_C_##INTRIN_NAME); \ +} + +//libc intrin calls as calls (side effects) +DEF_INTRIN_C_CALL(Memcpy, memcpy); +DEF_INTRIN_C_CALL(Memmove, memmove); +DEF_INTRIN_C_CALL(Memset, memset); +DEF_INTRIN_C_CALL(Strcpy, strcpy); +DEF_INTRIN_C_CALL(Strncpy, strncpy); + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinVectorZip(std::list &stmts, bool &isFinish) const { + std::unique_ptr> argExprList = std::make_unique>(); + for (auto arg : args) { + UniqueFEIRExpr expr = arg->Emit2FEExpr(stmts); + argExprList->emplace_back(std::move(expr)); + } + CHECK_NULL_FATAL(retType); + std::string retName = FEUtils::GetSequentialName("vector_zip_retvar_"); + UniqueFEIRVar retVar = FEIRBuilder::CreateVarNameForC(retName, *retType); + +#define VECTOR_INTRINSICCALL_TYPE(OP_NAME, VECTY) \ + if (FEUtils::EndsWith(funcName, #VECTY)) { \ + stmt = std::make_unique( \ + INTRN_vector_##OP_NAME##_##VECTY, nullptr, retVar->Clone(), std::move(argExprList)); \ + } + UniqueFEIRStmt stmt; + + VECTOR_INTRINSICCALL_TYPE(zip, v2i32) + else VECTOR_INTRINSICCALL_TYPE(zip, v4i16) + else VECTOR_INTRINSICCALL_TYPE(zip, v8i8) + else VECTOR_INTRINSICCALL_TYPE(zip, v2u32) + else VECTOR_INTRINSICCALL_TYPE(zip, v4u16) + else VECTOR_INTRINSICCALL_TYPE(zip, v8u8) + else VECTOR_INTRINSICCALL_TYPE(zip, v2f32) + + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + isFinish = true; + return FEIRBuilder::CreateExprDRead(std::move(retVar)); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinVaStart(std::list &stmts) const { + // args + auto exprArgList = std::make_unique>(); + for (auto arg : args) { + UniqueFEIRExpr expr = arg->Emit2FEExpr(stmts); + exprArgList->emplace_back(std::move(expr)); + } + // addrof va_list instead of dread va_list + exprArgList->front()->SetAddrof(true); + std::unique_ptr stmt = std::make_unique( + INTRN_C_va_start, nullptr /* type */, nullptr /* retVar */, std::move(exprArgList)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + return nullptr; +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinVaEnd(std::list &stmts) const { + // args + ASSERT(args.size() == 1, "va_end expects 1 arguments"); + std::list exprArgList; + for (auto arg : args) { + UniqueFEIRExpr expr = arg->Emit2FEExpr(stmts); + // addrof va_list instead of dread va_list + expr->SetAddrof(true); + exprArgList.emplace_back(std::move(expr)); + } + auto stmt = std::make_unique(OP_eval, std::move(exprArgList)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + return nullptr; +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinVaCopy(std::list &stmts) const { + // args + auto exprArgList = std::make_unique>(); + UniqueFEIRType vaListType; + for (auto arg : args) { + UniqueFEIRExpr expr = arg->Emit2FEExpr(stmts); + // addrof va_list instead of dread va_list + expr->SetAddrof(true); + vaListType = expr->GetType()->Clone(); + exprArgList->emplace_back(std::move(expr)); + } + // Add the size of the va_list structure as the size to memcpy. + size_t elemSizes = vaListType->GenerateMIRTypeAuto()->GetSize(); + CHECK_FATAL(elemSizes <= INT_MAX, "Too large elem size"); + UniqueFEIRExpr sizeExpr = FEIRBuilder::CreateExprConstI32(static_cast(elemSizes)); + exprArgList->emplace_back(std::move(sizeExpr)); + std::unique_ptr stmt = std::make_unique( + INTRN_C_memcpy, nullptr /* type */, nullptr /* retVar */, std::move(exprArgList)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + return nullptr; +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinPrefetch(std::list &stmts) const { + // __builtin_prefetch is not supported, only parsing args including stmts + for (size_t i = 0; i <= args.size() - 1; ++i) { + (void)args[i]->Emit2FEExpr(stmts); + } + return nullptr; +} +//libc mem* and str* intrin calls as emitted operations (no side effects) +DEF_INTRIN_C_OP(Memcmp, memcmp); +DEF_INTRIN_C_OP(Strlen, strlen); +DEF_INTRIN_C_OP(Strcmp, strcmp); +DEF_INTRIN_C_OP(Strncmp, strncmp); +DEF_INTRIN_C_OP(Strchr, strchr); +DEF_INTRIN_C_OP(Strrchr, strrchr); + +DEF_INTRIN_C_OP(Ctz, ctz32); +DEF_INTRIN_C_OP(Ctzl, ctz64); +DEF_INTRIN_C_OP(Clz, clz32); +DEF_INTRIN_C_OP(Clzl, clz64); +DEF_INTRIN_C_OP(Popcount, popcount32); +DEF_INTRIN_C_OP(Popcountl, popcount64); +DEF_INTRIN_C_OP(Popcountll, popcount64); +DEF_INTRIN_C_OP(Parity, parity32); +DEF_INTRIN_C_OP(Parityl, parity64); +DEF_INTRIN_C_OP(Parityll, parity64); +DEF_INTRIN_C_OP(Clrsb, clrsb32); +DEF_INTRIN_C_OP(Clrsbl, clrsb64); +DEF_INTRIN_C_OP(Clrsbll, clrsb64); +DEF_INTRIN_C_OP(Ffs, ffs); +DEF_INTRIN_C_OP(Ffsl, ffs); +DEF_INTRIN_C_OP(Ffsll, ffs); +DEF_INTRIN_C_OP(IsAligned, isaligned); +DEF_INTRIN_C_OP(AlignUp, alignup); +DEF_INTRIN_C_OP(AlignDown, aligndown); +DEF_INTRIN_C_OP(SyncAddAndFetch8, __sync_add_and_fetch_8); +DEF_INTRIN_C_OP(SyncAddAndFetch4, __sync_add_and_fetch_4); +DEF_INTRIN_C_OP(SyncAddAndFetch2, __sync_add_and_fetch_2); +DEF_INTRIN_C_OP(SyncAddAndFetch1, __sync_add_and_fetch_1); +DEF_INTRIN_C_OP(SyncSubAndFetch8, __sync_sub_and_fetch_8); +DEF_INTRIN_C_OP(SyncSubAndFetch4, __sync_sub_and_fetch_4); +DEF_INTRIN_C_OP(SyncSubAndFetch2, __sync_sub_and_fetch_2); +DEF_INTRIN_C_OP(SyncSubAndFetch1, __sync_sub_and_fetch_1); +DEF_INTRIN_C_OP(SyncFetchAndSub8, __sync_fetch_and_sub_8); +DEF_INTRIN_C_OP(SyncFetchAndSub4, __sync_fetch_and_sub_4); +DEF_INTRIN_C_OP(SyncFetchAndSub2, __sync_fetch_and_sub_2); +DEF_INTRIN_C_OP(SyncFetchAndSub1, __sync_fetch_and_sub_1); +DEF_INTRIN_C_OP(SyncFetchAndAdd8, __sync_fetch_and_add_8); +DEF_INTRIN_C_OP(SyncFetchAndAdd4, __sync_fetch_and_add_4); +DEF_INTRIN_C_OP(SyncFetchAndAdd2, __sync_fetch_and_add_2); +DEF_INTRIN_C_OP(SyncFetchAndAdd1, __sync_fetch_and_add_1); +DEF_INTRIN_C_OP(SyncValCompareAndSwap8, __sync_val_compare_and_swap_8); +DEF_INTRIN_C_OP(SyncValCompareAndSwap4, __sync_val_compare_and_swap_4); +DEF_INTRIN_C_OP(SyncValCompareAndSwap2, __sync_val_compare_and_swap_2); +DEF_INTRIN_C_OP(SyncValCompareAndSwap1, __sync_val_compare_and_swap_1); +DEF_INTRIN_C_OP(SyncLockRelease8, __sync_lock_release_8); +DEF_INTRIN_C_OP(SyncLockRelease4, __sync_lock_release_4); +DEF_INTRIN_C_OP(SyncLockRelease2, __sync_lock_release_2); +DEF_INTRIN_C_OP(SyncLockRelease1, __sync_lock_release_1); +DEF_INTRIN_C_OP(SyncBoolCompareAndSwap8, __sync_bool_compare_and_swap_8); +DEF_INTRIN_C_OP(SyncBoolCompareAndSwap4, __sync_bool_compare_and_swap_4); +DEF_INTRIN_C_OP(SyncBoolCompareAndSwap2, __sync_bool_compare_and_swap_2); +DEF_INTRIN_C_OP(SyncBoolCompareAndSwap1, __sync_bool_compare_and_swap_1); +DEF_INTRIN_C_OP(SyncLockTestAndSet8, __sync_lock_test_and_set_8); +DEF_INTRIN_C_OP(SyncLockTestAndSet4, __sync_lock_test_and_set_4); +DEF_INTRIN_C_OP(SyncLockTestAndSet2, __sync_lock_test_and_set_2); +DEF_INTRIN_C_OP(SyncLockTestAndSet1, __sync_lock_test_and_set_1); +DEF_INTRIN_C_OP(SyncFetchAndAnd8, __sync_fetch_and_and_8); +DEF_INTRIN_C_OP(SyncFetchAndAnd4, __sync_fetch_and_and_4); +DEF_INTRIN_C_OP(SyncFetchAndAnd2, __sync_fetch_and_and_2); +DEF_INTRIN_C_OP(SyncFetchAndAnd1, __sync_fetch_and_and_1); +DEF_INTRIN_C_OP(SyncFetchAndOr8, __sync_fetch_and_or_8); +DEF_INTRIN_C_OP(SyncFetchAndOr4, __sync_fetch_and_or_4); +DEF_INTRIN_C_OP(SyncFetchAndOr2, __sync_fetch_and_or_2); +DEF_INTRIN_C_OP(SyncFetchAndOr1, __sync_fetch_and_or_1); +DEF_INTRIN_C_OP(SyncFetchAndXor8, __sync_fetch_and_xor_8); +DEF_INTRIN_C_OP(SyncFetchAndXor4, __sync_fetch_and_xor_4); +DEF_INTRIN_C_OP(SyncFetchAndXor2, __sync_fetch_and_xor_2); +DEF_INTRIN_C_OP(SyncFetchAndXor1, __sync_fetch_and_xor_1); +DEF_INTRIN_C_OP(SyncFetchAndNand8, __sync_fetch_and_nand_8); +DEF_INTRIN_C_OP(SyncFetchAndNand4, __sync_fetch_and_nand_4); +DEF_INTRIN_C_OP(SyncFetchAndNand2, __sync_fetch_and_nand_2); +DEF_INTRIN_C_OP(SyncFetchAndNand1, __sync_fetch_and_nand_1); +DEF_INTRIN_C_OP(SyncAndAndFetch8, __sync_and_and_fetch_8); +DEF_INTRIN_C_OP(SyncAndAndFetch4, __sync_and_and_fetch_4); +DEF_INTRIN_C_OP(SyncAndAndFetch2, __sync_and_and_fetch_2); +DEF_INTRIN_C_OP(SyncAndAndFetch1, __sync_and_and_fetch_1); +DEF_INTRIN_C_OP(SyncOrAndFetch8, __sync_or_and_fetch_8); +DEF_INTRIN_C_OP(SyncOrAndFetch4, __sync_or_and_fetch_4); +DEF_INTRIN_C_OP(SyncOrAndFetch2, __sync_or_and_fetch_2); +DEF_INTRIN_C_OP(SyncOrAndFetch1, __sync_or_and_fetch_1); +DEF_INTRIN_C_OP(SyncXorAndFetch8, __sync_xor_and_fetch_8); +DEF_INTRIN_C_OP(SyncXorAndFetch4, __sync_xor_and_fetch_4); +DEF_INTRIN_C_OP(SyncXorAndFetch2, __sync_xor_and_fetch_2); +DEF_INTRIN_C_OP(SyncXorAndFetch1, __sync_xor_and_fetch_1); +DEF_INTRIN_C_OP(SyncNandAndFetch8, __sync_nand_and_fetch_8); +DEF_INTRIN_C_OP(SyncNandAndFetch4, __sync_nand_and_fetch_4); +DEF_INTRIN_C_OP(SyncNandAndFetch2, __sync_nand_and_fetch_2); +DEF_INTRIN_C_OP(SyncNandAndFetch1, __sync_nand_and_fetch_1); +DEF_INTRIN_C_OP(SyncSynchronize, __sync_synchronize); + +DEF_INTRIN_C_OP(ReturnAddress, _builtin_return_address); +DEF_INTRIN_C_OP(ExtractReturnAddr, _builtin_extract_return_addr); + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinAlloca(std::list &stmts) const { + auto arg = args[0]->Emit2FEExpr(stmts); + CHECK_NULL_FATAL(mirType); + auto alloca = std::make_unique(FEIRTypeHelper::CreateTypeNative(*mirType), OP_alloca, std::move(arg)); + return alloca; +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinExpect(std::list &stmts) const { + ASSERT(args.size() == 2, "__builtin_expect requires two arguments"); + return CreateIntrinsicopForC(stmts, INTRN_C___builtin_expect, false); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinUnreachable(std::list &stmts) const { + UniqueFEIRExpr feExpr = nullptr; + UniqueFEIRStmt stmt = std::make_unique(std::move(feExpr)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + return nullptr; +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinAbs(std::list &stmts) const { + auto arg = args[0]->Emit2FEExpr(stmts); + CHECK_NULL_FATAL(mirType); + auto abs = std::make_unique(FEIRTypeHelper::CreateTypeNative(*mirType), OP_abs, std::move(arg)); + auto feType = std::make_unique(*mirType); + abs->SetType(std::move(feType)); + return abs; +} + +DEF_INTRIN_C_OP(ACos, acos); +DEF_INTRIN_C_OP(ACosf, acosf); +DEF_INTRIN_C_OP(ASin, asin); +DEF_INTRIN_C_OP(ASinf, asinf); +DEF_INTRIN_C_OP(ATan, atan); +DEF_INTRIN_C_OP(ATanf, atanf); +DEF_INTRIN_C_OP(Cos, cos); +DEF_INTRIN_C_OP(Cosf, cosf); +DEF_INTRIN_C_OP(Cosh, cosh); +DEF_INTRIN_C_OP(Coshf, coshf); +DEF_INTRIN_C_OP(Sin, sin); +DEF_INTRIN_C_OP(Sinf, sinf); +DEF_INTRIN_C_OP(Sinh, sinh); +DEF_INTRIN_C_OP(Sinhf, sinhf); +DEF_INTRIN_C_OP(Exp, exp); +DEF_INTRIN_C_OP(Expf, expf); +DEF_INTRIN_C_OP(Log, log); +DEF_INTRIN_C_OP(Logf, logf); +DEF_INTRIN_C_OP(Log10, log10); +DEF_INTRIN_C_OP(Log10f, log10f); + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinFmax(std::list &stmts) const { + return CreateBinaryExpr(stmts, OP_max); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinFmin(std::list &stmts) const { + return CreateBinaryExpr(stmts, OP_min); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinIsunordered(std::list &stmts) const { + auto feTy = std::make_unique(*mirType); + auto arg1 = args[0]->Emit2FEExpr(stmts); + auto arg2 = args[1]->Emit2FEExpr(stmts); + auto nan1 = std::make_unique(feTy->Clone(), OP_ne, arg1->Clone(), arg1->Clone()); + auto nan2 = std::make_unique(feTy->Clone(), OP_ne, arg2->Clone(), arg2->Clone()); + auto res = std::make_unique(feTy->Clone(), OP_lior, std::move(nan1), std::move(nan2)); + return res; +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinIsless(std::list &stmts) const { + return CreateBinaryExpr(stmts, OP_lt); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinIslessequal(std::list &stmts) const { + return CreateBinaryExpr(stmts, OP_le); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinIsgreater (std::list &stmts) const { + return CreateBinaryExpr(stmts, OP_gt); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinIsgreaterequal(std::list &stmts) const { + return CreateBinaryExpr(stmts, OP_ge); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinIslessgreater(std::list &stmts) const { + auto feTy = std::make_unique(*mirType); + auto arg1 = args[0]->Emit2FEExpr(stmts); + auto arg2 = args[1]->Emit2FEExpr(stmts); + auto cond1 = std::make_unique(feTy->Clone(), OP_lt, arg1->Clone(), arg2->Clone()); + auto cond2 = std::make_unique(feTy->Clone(), OP_gt, arg1->Clone(), arg2->Clone()); + auto res = std::make_unique(feTy->Clone(), OP_lior, std::move(cond1), std::move(cond2)); + return res; +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinWarnMemsetZeroLen(std::list &stmts) const { + (void)stmts; + return nullptr; +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinRotateLeft8(std::list &stmts) const { + return EmitBuiltinRotate(stmts, PTY_u8, true); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinRotateLeft16(std::list &stmts) const { + return EmitBuiltinRotate(stmts, PTY_u16, true); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinRotateLeft32(std::list &stmts) const { + return EmitBuiltinRotate(stmts, PTY_u32, true); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinRotateLeft64(std::list &stmts) const { + return EmitBuiltinRotate(stmts, PTY_u64, true); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinRotateRight8(std::list &stmts) const { + return EmitBuiltinRotate(stmts, PTY_u8, false); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinRotateRight16(std::list &stmts) const { + return EmitBuiltinRotate(stmts, PTY_u16, false); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinRotateRight32(std::list &stmts) const { + return EmitBuiltinRotate(stmts, PTY_u32, false); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinRotateRight64(std::list &stmts) const { + return EmitBuiltinRotate(stmts, PTY_u64, false); +} + +UniqueFEIRExpr ASTCallExpr::EmitBuiltinRotate(std::list &stmts, PrimType rotType, bool isLeft) const { + const int mask = FEUtils::GetWidth(rotType) - 1; + UniqueFEIRExpr maskExpr = FEIRBuilder::CreateExprConstAnyScalar(rotType, mask); + UniqueFEIRExpr valExpr = args[0]->Emit2FEExpr(stmts); + UniqueFEIRExpr bitExpr = args[1]->Emit2FEExpr(stmts); + bitExpr = FEIRBuilder::CreateExprBinary(OP_band, bitExpr->Clone(), maskExpr->Clone()); + // RotateLeft: (val >> bit) | (val << ((-bit) & mask)) + // RotateRight: (val << bit) | (val >> ((-bit) & mask)) + return FEIRBuilder::CreateExprBinary(OP_bior, + FEIRBuilder::CreateExprBinary((isLeft ? OP_shl : OP_lshr), valExpr->Clone(), bitExpr->Clone()), + FEIRBuilder::CreateExprBinary((isLeft ? OP_lshr : OP_shl), + valExpr->Clone(), + FEIRBuilder::CreateExprBinary(OP_band, + FEIRBuilder::CreateExprMathUnary(OP_neg, bitExpr->Clone()), + maskExpr->Clone()))); +} + +std::map ASTParser::InitBuiltinFuncPtrMap() { + std::map ans; +#define BUILTIN_FUNC_PARSE(funcName, FuncPtrBuiltinFunc) \ + ans[funcName] = FuncPtrBuiltinFunc; +#include "builtin_func_parse.def" +#undef BUILTIN_FUNC_PARSE + return ans; +} + +ASTExpr *ASTParser::ParseBuiltinFunc(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + return (this->*(builtingFuncPtrMap[ss.str()]))(allocator, expr, ss); +} + +ASTExpr *ASTParser::ProcessBuiltinFuncByName(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss, const std::string &name) const { + (void)allocator; + (void)expr; + ss.clear(); + ss.str(std::string()); + ss << name; + return nullptr; +} + +ASTExpr *ASTParser::ParseBuiltinClassifyType(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + (void)ss; + clang::Expr::EvalResult res; + bool success = expr.EvaluateAsInt(res, *(astFile->GetContext())); + CHECK_FATAL(success, "Failed to evaluate __builtin_classify_type"); + llvm::APSInt apVal = res.Val.getInt(); + ASTIntegerLiteral *astIntegerLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + astIntegerLiteral->SetVal(apVal.getExtValue()); + astIntegerLiteral->SetType(GlobalTables::GetTypeTable().GetInt32()); + return astIntegerLiteral; +} + +ASTExpr *ASTParser::ParseBuiltinConstantP(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + (void)ss; + int64 constP = expr.getArg(0)->isConstantInitializer(*astFile->GetNonConstAstContext(), false) ? 1 : 0; + // Pointers are not considered constant + if (expr.getArg(0)->getType()->isPointerType() && + !llvm::isa(expr.getArg(0)->IgnoreParenCasts())) { + constP = 0; + } + ASTIntegerLiteral *astIntegerLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + astIntegerLiteral->SetVal(constP); + astIntegerLiteral->SetType(astFile->CvtType(expr.getType())); + return astIntegerLiteral; +} + +ASTExpr *ASTParser::ParseBuiltinSignbit(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + return ProcessBuiltinFuncByName(allocator, expr, ss, "__signbit"); +} + +ASTExpr *ASTParser::ParseBuiltinIsinfsign(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + (void)allocator; + (void)expr; + ss.clear(); + ss.str(std::string()); + if (astFile->CvtType(expr.getArg(0)->getType())->GetPrimType() == PTY_f64) { + ss << "__isinf"; + } else if (astFile->CvtType(expr.getArg(0)->getType())->GetPrimType() == PTY_f32) { + ss << "__isinff"; + } else { + ASSERT(false, "Unsupported type passed to isinf"); + } + return nullptr; +} + +ASTExpr *ASTParser::ParseBuiltinHugeVal(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + (void)expr; + (void)ss; + ASTFloatingLiteral *astFloatingLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + astFloatingLiteral->SetKind(F64); + astFloatingLiteral->SetVal(std::numeric_limits::infinity()); + return astFloatingLiteral; +} + +ASTExpr *ASTParser::ParseBuiltinHugeValf(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + (void)expr; + (void)ss; + ASTFloatingLiteral *astFloatingLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + astFloatingLiteral->SetKind(F32); + astFloatingLiteral->SetVal(std::numeric_limits::infinity()); + return astFloatingLiteral; +} + +ASTExpr *ASTParser::ParseBuiltinInf(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + (void)expr; + (void)ss; + ASTFloatingLiteral *astFloatingLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + astFloatingLiteral->SetKind(F64); + astFloatingLiteral->SetVal(std::numeric_limits::infinity()); + return astFloatingLiteral; +} + +ASTExpr *ASTParser::ParseBuiltinInff(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + (void)expr; + (void)ss; + ASTFloatingLiteral *astFloatingLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + astFloatingLiteral->SetKind(F32); + astFloatingLiteral->SetVal(std::numeric_limits::infinity()); + return astFloatingLiteral; +} + +ASTExpr *ASTParser::ParseBuiltinNan(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + (void)expr; + (void)ss; + ASTFloatingLiteral *astFloatingLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + astFloatingLiteral->SetKind(F64); + astFloatingLiteral->SetVal(nan("")); + return astFloatingLiteral; +} + +ASTExpr *ASTParser::ParseBuiltinNanf(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + (void)expr; + (void)ss; + ASTFloatingLiteral *astFloatingLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + astFloatingLiteral->SetKind(F32); + astFloatingLiteral->SetVal(nanf("")); + return astFloatingLiteral; +} + +ASTExpr *ASTParser::ParseBuiltinSignBitf(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + return ProcessBuiltinFuncByName(allocator, expr, ss, "__signbitf"); +} + +ASTExpr *ASTParser::ParseBuiltinSignBitl(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + return ProcessBuiltinFuncByName(allocator, expr, ss, "__signbitl"); +} + +ASTExpr *ASTParser::ParseBuiltinTrap(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + return ProcessBuiltinFuncByName(allocator, expr, ss, "abort"); +} + +ASTExpr *ASTParser::ParseBuiltinCopysignf(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + return ProcessBuiltinFuncByName(allocator, expr, ss, "copysignf"); +} + +ASTExpr *ASTParser::ParseBuiltinCopysign(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + return ProcessBuiltinFuncByName(allocator, expr, ss, "copysign"); +} + +ASTExpr *ASTParser::ParseBuiltinCopysignl(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + return ProcessBuiltinFuncByName(allocator, expr, ss, "copysignl"); +} + +ASTExpr *ASTParser::ParseBuiltinObjectsize(MapleAllocator &allocator, const clang::CallExpr &expr, + std::stringstream &ss) const { + (void)ss; + uint32 objSizeType = expr.getArg(1)->EvaluateKnownConstInt(*astFile->GetContext()).getZExtValue(); + // GCC size_t __builtin_object_size(void *ptr, int type) type range is 0 ~ 3 + ASSERT(objSizeType <= 3, "unexpected type"); + uint64 objSize; + bool canEval = expr.getArg(0)->tryEvaluateObjectSize(objSize, *astFile->GetNonConstAstContext(), objSizeType); + if (!canEval) { + // type 0 and 1 need return -1, type 2 and 3 need return 0 + objSize = objSizeType & 2 ? 0 : -1; + } + ASTIntegerLiteral *astIntegerLiteral = ASTDeclsBuilder::ASTExprBuilder(allocator); + astIntegerLiteral->SetVal(static_cast(objSize)); + astIntegerLiteral->SetType(astFile->CvtType(expr.getType())); + return astIntegerLiteral; +} +} // namespace maple diff --git a/src/hir2mpl/ast_input/clang/src/ast_stmt.cpp b/src/hir2mpl/ast_input/clang/src/ast_stmt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4184cc0e7379fb4c0a807c3feee68ee724f28c71 --- /dev/null +++ b/src/hir2mpl/ast_input/clang/src/ast_stmt.cpp @@ -0,0 +1,584 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ast_stmt.h" +#include "ast_decl.h" +#include "ast_util.h" +#include "mpl_logging.h" +#include "feir_stmt.h" +#include "feir_builder.h" +#include "fe_utils_ast.h" +#include "fe_manager.h" +#include "ast_util.h" +#include "enhance_c_checker.h" +#include "conditional_operator.h" + +namespace maple { +// ---------- ASTStmt ---------- +void ASTStmt::SetASTExpr(ASTExpr *astExpr) { + exprs.emplace_back(astExpr); +} + +// ---------- ASTStmtDummy ---------- +std::list ASTStmtDummy::Emit2FEStmtImpl() const { + std::list stmts; + for (auto expr : exprs) { + (void)expr->Emit2FEExpr(stmts); + } + return stmts; +} + +// ---------- ASTCompoundStmt ---------- +void ASTCompoundStmt::SetASTStmt(ASTStmt *astStmt) { + astStmts.emplace_back(astStmt); +} + +void ASTCompoundStmt::InsertASTStmtsAtFront(const std::list &stmts) { + astStmts.insert(astStmts.begin(), stmts.begin(), stmts.end()); +} + +const std::list &ASTCompoundStmt::GetASTStmtList() const { + return astStmts; +} + +std::list ASTCompoundStmt::Emit2FEStmtImpl() const { + std::list stmts; + auto insertStmt = [&](bool flag) { + if (!FEOptions::GetInstance().IsEnableSafeRegion()) { + return; + } + if (safeSS == kSafeSS) { + stmts.emplace_back(std::make_unique(flag)); + } else if (safeSS == kUnsafeSS) { + stmts.emplace_back(std::make_unique(flag)); + } + }; + insertStmt(false); + for (auto it : astStmts) { + stmts.splice(stmts.end(), it->Emit2FEStmt()); + } + insertStmt(true); + return stmts; +} + +// ---------- ASTReturnStmt ---------- +std::list ASTReturnStmt::Emit2FEStmtImpl() const { + std::list stmts; + auto astExpr = exprs.front(); + UniqueFEIRExpr feExpr = (astExpr != nullptr) ? astExpr->Emit2FEExpr(stmts) : nullptr; + if (astExpr != nullptr && ConditionalOptimize::DeleteRedundantTmpVar(feExpr, stmts)) { + return stmts; + } + UniqueFEIRStmt stmt = std::make_unique(std::move(feExpr)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ---------- ASTIfStmt ---------- +std::list ASTIfStmt::Emit2FEStmtImpl() const { + std::list stmts; + std::list thenStmts; + std::list elseStmts; + if (thenStmt != nullptr) { + thenStmts = thenStmt->Emit2FEStmt(); + } + if (elseStmt != nullptr) { + elseStmts = elseStmt->Emit2FEStmt(); + } + UniqueFEIRExpr condFEExpr = condExpr->Emit2FEExpr(stmts); + condFEExpr = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(condFEExpr)); + UniqueFEIRStmt ifStmt; + ifStmt = FEIRBuilder::CreateStmtIf(std::move(condFEExpr), thenStmts, elseStmts); + ifStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(ifStmt)); + return stmts; +} + +std::list ASTForStmt::Emit2FEStmtImpl() const { + std::list stmts; + std::string loopBodyEndLabelName = FEUtils::GetSequentialName("dowhile_body_end_"); + std::string loopEndLabelName = FEUtils::GetSequentialName("dowhile_end_"); + AstLoopUtil::Instance().PushContinue(loopBodyEndLabelName); + AstLoopUtil::Instance().PushBreak(loopEndLabelName); + auto labelBodyEndStmt = std::make_unique(loopBodyEndLabelName); + auto labelLoopEndStmt = std::make_unique(loopEndLabelName); + if (initStmt != nullptr) { + std::list feStmts = initStmt->Emit2FEStmt(); + stmts.splice(stmts.cend(), feStmts); + } + std::list bodyFEStmts = bodyStmt->Emit2FEStmt(); + if (AstLoopUtil::Instance().IsCurrentContinueLabelUsed()) { + bodyFEStmts.emplace_back(std::move(labelBodyEndStmt)); + } + UniqueFEIRExpr condFEExpr; + if (condExpr != nullptr) { + (void)condExpr->Emit2FEExpr(stmts); + } else { + condFEExpr = std::make_unique(static_cast(1), PTY_i32); + } + if (incExpr != nullptr) { + std::list incStmts; + UniqueFEIRExpr incFEExpr = incExpr->Emit2FEExpr(incStmts); + if (incFEExpr != nullptr && incStmts.size() == 2 && incStmts.front()->IsDummy()) { + incStmts.pop_front(); + } + bodyFEStmts.splice(bodyFEStmts.cend(), incStmts); + } + if (condExpr != nullptr) { + std::list condStmts; + condFEExpr = condExpr->Emit2FEExpr(condStmts); + bodyFEStmts.splice(bodyFEStmts.cend(), condStmts); + } + condFEExpr = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(condFEExpr)); + UniqueFEIRStmt whileStmt = std::make_unique(OP_while, std::move(condFEExpr), std::move(bodyFEStmts)); + whileStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(whileStmt)); + if (AstLoopUtil::Instance().IsCurrentBreakLabelUsed()) { + stmts.emplace_back(std::move(labelLoopEndStmt)); + } + AstLoopUtil::Instance().PopCurrentBreak(); + AstLoopUtil::Instance().PopCurrentContinue(); + return stmts; +} + +std::list ASTWhileStmt::Emit2FEStmtImpl() const { + std::list stmts; + std::string loopBodyEndLabelName = FEUtils::GetSequentialName("dowhile_body_end_"); + std::string loopEndLabelName = FEUtils::GetSequentialName("dowhile_end_"); + AstLoopUtil::Instance().PushBreak(loopEndLabelName); + AstLoopUtil::Instance().PushContinue(loopBodyEndLabelName); + auto labelBodyEndStmt = std::make_unique(loopBodyEndLabelName); + auto labelLoopEndStmt = std::make_unique(loopEndLabelName); + std::list bodyFEStmts = bodyStmt->Emit2FEStmt(); + std::list condStmts; + std::list condPreStmts; + UniqueFEIRExpr condFEExpr = condExpr->Emit2FEExpr(condStmts); + (void)condExpr->Emit2FEExpr(condPreStmts); + if (AstLoopUtil::Instance().IsCurrentContinueLabelUsed()) { + bodyFEStmts.emplace_back(std::move(labelBodyEndStmt)); + } + bodyFEStmts.splice(bodyFEStmts.end(), condPreStmts); + condFEExpr = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(condFEExpr)); + auto whileStmt = std::make_unique(OP_while, std::move(condFEExpr), std::move(bodyFEStmts)); + whileStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.splice(stmts.end(), condStmts); + stmts.emplace_back(std::move(whileStmt)); + if (AstLoopUtil::Instance().IsCurrentBreakLabelUsed()) { + stmts.emplace_back(std::move(labelLoopEndStmt)); + } + AstLoopUtil::Instance().PopCurrentBreak(); + AstLoopUtil::Instance().PopCurrentContinue(); + return stmts; +} + +std::list ASTDoStmt::Emit2FEStmtImpl() const { + std::list stmts; + std::string loopBodyEndLabelName = FEUtils::GetSequentialName("dowhile_body_end_"); + std::string loopEndLabelName = FEUtils::GetSequentialName("dowhile_end_"); + AstLoopUtil::Instance().PushBreak(loopEndLabelName); + AstLoopUtil::Instance().PushContinue(loopBodyEndLabelName); + auto labelBodyEndStmt = std::make_unique(loopBodyEndLabelName); + auto labelLoopEndStmt = std::make_unique(loopEndLabelName); + std::list bodyFEStmts; + if (bodyStmt != nullptr) { + bodyFEStmts = bodyStmt->Emit2FEStmt(); + } + if (AstLoopUtil::Instance().IsCurrentContinueLabelUsed()) { + bodyFEStmts.emplace_back(std::move(labelBodyEndStmt)); + } + std::list condStmts; + UniqueFEIRExpr condFEExpr = condExpr->Emit2FEExpr(condStmts); + bodyFEStmts.splice(bodyFEStmts.end(), condStmts); + condFEExpr = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(condFEExpr)); + UniqueFEIRStmt whileStmt = std::make_unique(OP_dowhile, std::move(condFEExpr), + std::move(bodyFEStmts)); + whileStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(whileStmt)); + if (AstLoopUtil::Instance().IsCurrentBreakLabelUsed()) { + stmts.emplace_back(std::move(labelLoopEndStmt)); + } + AstLoopUtil::Instance().PopCurrentBreak(); + AstLoopUtil::Instance().PopCurrentContinue(); + return stmts; +} + +std::list ASTBreakStmt::Emit2FEStmtImpl() const { + std::list stmts; + auto stmt = std::make_unique(); + if (!AstLoopUtil::Instance().IsBreakLabelsEmpty()) { + stmt->SetBreakLabelName(AstLoopUtil::Instance().GetCurrentBreak()); + } + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +std::list ASTLabelStmt::Emit2FEStmtImpl() const { + std::list stmts; + auto feStmt = std::make_unique(labelName); + feStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(feStmt)); + stmts.splice(stmts.end(), subStmt->Emit2FEStmt()); + return stmts; +} + +std::list ASTContinueStmt::Emit2FEStmtImpl() const { + std::list stmts; + auto stmt = std::make_unique(); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmt->SetLabelName(AstLoopUtil::Instance().GetCurrentContinue()); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ---------- ASTUnaryOperatorStmt ---------- +std::list ASTUnaryOperatorStmt::Emit2FEStmtImpl() const { + std::list stmts; + std::list feExprs; + auto feExpr = exprs.front()->Emit2FEExpr(stmts); + if (feExpr != nullptr) { + if (stmts.size() == 2 && stmts.front()->IsDummy()) { + stmts.pop_front(); + return stmts; + } + feExprs.emplace_back(std::move(feExpr)); + auto stmt = std::make_unique(OP_eval, std::move(feExprs)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + return stmts; +} + +// ---------- ASTGotoStmt ---------- +std::list ASTGotoStmt::Emit2FEStmtImpl() const { + std::list stmts; + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtGoto(labelName); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ---------- ASTIndirectGotoStmt ---------- +std::list ASTIndirectGotoStmt::Emit2FEStmtImpl() const { + std::list stmts; + UniqueFEIRExpr targetExpr = exprs.front()->Emit2FEExpr(stmts); + stmts.emplace_back(FEIRBuilder::CreateStmtIGoto(std::move(targetExpr))); + return stmts; +} + +// ---------- ASTSwitchStmt ---------- +std::list ASTSwitchStmt::Emit2FEStmtImpl() const { + std::list stmts; + UniqueFEIRExpr expr = condExpr->Emit2FEExpr(stmts); + std::string exitName = AstSwitchUtil::Instance().CreateEndOrExitLabelName(); + AstLoopUtil::Instance().PushBreak(exitName); + std::string tmpName = FEUtils::GetSequentialName("switch_cond"); + UniqueFEIRVar tmpVar = FEIRBuilder::CreateVarNameForC(tmpName, *condType); + UniqueFEIRStmt condFEStmt = FEIRBuilder::CreateStmtDAssign(tmpVar->Clone(), std::move(expr)); + stmts.emplace_back(std::move(condFEStmt)); + auto dread = FEIRBuilder::CreateExprDRead(tmpVar->Clone()); + auto switchStmt = std::make_unique(std::move(dread), hasDefualt); + switchStmt->SetBreakLabelName(exitName); + switchStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + for (auto &s : bodyStmt->Emit2FEStmt()) { + switchStmt.get()->AddFeirStmt(std::move(s)); + } + stmts.emplace_back(std::move(switchStmt)); + AstLoopUtil::Instance().PopCurrentBreak(); + return stmts; +} + +// ---------- ASTCaseStmt ---------- +std::list ASTCaseStmt::Emit2FEStmtImpl() const { + std::list stmts; + auto caseStmt = std::make_unique(lCaseTag); + caseStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + caseStmt.get()->AddCaseTag2CaseVec(lCaseTag, rCaseTag); + for (auto &s : subStmt->Emit2FEStmt()) { + caseStmt.get()->AddFeirStmt(std::move(s)); + } + stmts.emplace_back(std::move(caseStmt)); + return stmts; +} + +// ---------- ASTDefaultStmt ---------- +std::list ASTDefaultStmt::Emit2FEStmtImpl() const { + std::list stmts; + auto defaultStmt = std::make_unique(); + defaultStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + for (auto &s : child->Emit2FEStmt()) { + defaultStmt.get()->AddFeirStmt(std::move(s)); + } + stmts.emplace_back(std::move(defaultStmt)); + return stmts; +} + +// ---------- ASTNullStmt ---------- +std::list ASTNullStmt::Emit2FEStmtImpl() const { + // there is no need to process this stmt + std::list stmts; + return stmts; +} + +// ---------- ASTDeclStmt ---------- +std::list ASTDeclStmt::Emit2FEStmtImpl() const { + std::list stmts; + for (auto expr : exprs) { + (void)expr->Emit2FEExpr(stmts); + } + for (auto decl : subDecls) { + InsertBoundaryVar(decl, stmts); + decl->GenerateInitStmt(stmts); + } + return stmts; +} + +void ASTDeclStmt::InsertBoundaryVar(ASTDecl *ptrDecl, std::list &stmts) const { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || + ptrDecl == nullptr || ptrDecl->GetBoundaryLenExpr() == nullptr) { + return; + } + // GetCurrentFunction need to be optimized when parallel features + MIRFunction *curFunction = FEManager::GetMIRBuilder().GetCurrentFunctionNotNull(); + UniqueFEIRExpr lenFEExpr = ptrDecl->GetBoundaryLenExpr()->Emit2FEExpr(stmts); + ENCChecker::InitBoundaryVar(*curFunction, *ptrDecl, std::move(lenFEExpr), stmts); +} + +// ---------- ASTCallExprStmt ---------- +std::list ASTCallExprStmt::Emit2FEStmtImpl() const { + std::list stmts; + ASTCallExpr *callExpr = static_cast(exprs.front()); + if (!callExpr->IsIcall()) { + bool isFinish = false; + (void)callExpr->ProcessBuiltinFunc(stmts, isFinish); + if (isFinish) { + return stmts; + } + } + std::unique_ptr callStmt = callExpr->GenCallStmt(); + callStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + callExpr->AddArgsExpr(callStmt, stmts); + if (callExpr->IsNeedRetExpr()) { + UniqueFEIRVar var = FEIRBuilder::CreateVarNameForC(varName, *callExpr->GetRetType(), false, false); + callStmt->SetVar(std::move(var)); + } + stmts.emplace_back(std::move(callStmt)); + return stmts; +} + +// ---------- ASTImplicitCastExprStmt ---------- +std::list ASTImplicitCastExprStmt::Emit2FEStmtImpl() const { + CHECK_FATAL(exprs.size() == 1, "Only one sub expr supported!"); + std::list stmts; + UniqueFEIRExpr feirExpr = exprs.front()->Emit2FEExpr(stmts); + if (feirExpr != nullptr) { + std::list feirExprs; + feirExprs.emplace_back(std::move(feirExpr)); + auto stmt = std::make_unique(OP_eval, std::move(feirExprs)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + return stmts; +} + +// ---------- ASTParenExprStmt ---------- +std::list ASTParenExprStmt::Emit2FEStmtImpl() const { + std::list stmts; + exprs.front()->Emit2FEExpr(stmts); + return stmts; +} + +// ---------- ASTIntegerLiteralStmt ---------- +std::list ASTIntegerLiteralStmt::Emit2FEStmtImpl() const { + std::list stmts; + std::list feExprs; + auto feExpr = exprs.front()->Emit2FEExpr(stmts); + if (feExpr != nullptr) { + feExprs.emplace_back(std::move(feExpr)); + auto stmt = std::make_unique(OP_eval, std::move(feExprs)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + return stmts; +} + +// ---------- ASTFloatingLiteralStmt ---------- +std::list ASTFloatingLiteralStmt::Emit2FEStmtImpl() const { + std::list stmts; + std::list feExprs; + auto feExpr = exprs.front()->Emit2FEExpr(stmts); + if (feExpr != nullptr) { + feExprs.emplace_back(std::move(feExpr)); + auto stmt = std::make_unique(OP_eval, std::move(feExprs)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + return stmts; +} + +// ---------- ASTVAArgExprStmt ---------- +std::list ASTVAArgExprStmt::Emit2FEStmtImpl() const { + std::list stmts; + exprs.front()->Emit2FEExpr(stmts); + return stmts; +} + +// ---------- ASTConditionalOperatorStmt ---------- +std::list ASTConditionalOperatorStmt::Emit2FEStmtImpl() const { + std::list stmts; + std::list feExprs; + auto feExpr = exprs.front()->Emit2FEExpr(stmts); + if (feExpr != nullptr) { + feExprs.emplace_back(std::move(feExpr)); + auto stmt = std::make_unique(OP_eval, std::move(feExprs)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + return stmts; +} + +// ---------- ASTCharacterLiteralStmt ---------- +std::list ASTCharacterLiteralStmt::Emit2FEStmtImpl() const { + std::list stmts; + std::list feExprs; + auto feExpr = exprs.front()->Emit2FEExpr(stmts); + if (feExpr != nullptr) { + feExprs.emplace_back(std::move(feExpr)); + auto stmt = std::make_unique(OP_eval, std::move(feExprs)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + return stmts; +} + +// ---------- ASTStmtExprStmt ---------- +std::list ASTStmtExprStmt::Emit2FEStmtImpl() const { + return cpdStmt->Emit2FEStmt(); +} + +// ---------- ASTCStyleCastExprStmt ---------- +std::list ASTCStyleCastExprStmt::Emit2FEStmtImpl() const { + CHECK_FATAL(exprs.front() != nullptr, "child expr must not be nullptr!"); + std::list stmts; + std::list feExprs; + auto feExpr = exprs.front()->Emit2FEExpr(stmts); + if (feExpr != nullptr) { + feExprs.emplace_back(std::move(feExpr)); + auto stmt = std::make_unique(OP_eval, std::move(feExprs)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + return stmts; +} + +// ---------- ASTCompoundAssignOperatorStmt ---------- +std::list ASTCompoundAssignOperatorStmt::Emit2FEStmtImpl() const { + CHECK_FATAL(exprs.size() == 1, "ASTCompoundAssignOperatorStmt must contain only one bo expr!"); + std::list stmts; + CHECK_FATAL(static_cast(exprs.front()) != nullptr, "Child expr must be ASTCompoundAssignOperator!"); + exprs.front()->Emit2FEExpr(stmts); + return stmts; +} + +std::list ASTBinaryOperatorStmt::Emit2FEStmtImpl() const { + CHECK_FATAL(exprs.size() == 1, "ASTBinaryOperatorStmt must contain only one bo expr!"); + std::list stmts; + auto boExpr = static_cast(exprs.front()); + if (boExpr->GetASTOp() == kASTOpBO) { + UniqueFEIRExpr boFEExpr = boExpr->Emit2FEExpr(stmts); + if (boFEExpr != nullptr) { + std::list exprs; + exprs.emplace_back(std::move(boFEExpr)); + auto stmt = std::make_unique(OP_eval, std::move(exprs)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + } else { + // has been processed by child expr emit, skip here + UniqueFEIRExpr boFEExpr = boExpr->Emit2FEExpr(stmts); + return stmts; + } + return stmts; +} + +// ---------- ASTAtomicExprStmt ---------- +std::list ASTAtomicExprStmt::Emit2FEStmtImpl() const { + std::list stmts; + auto astExpr = exprs.front(); + UniqueFEIRExpr feExpr = astExpr->Emit2FEExpr(stmts); + auto stmt = std::make_unique(std::move(feExpr)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ---------- ASTGCCAsmStmt ---------- +std::list ASTGCCAsmStmt::Emit2FEStmtImpl() const { + std::list stmts; + std::vector outputsExprs; + std::vector inputsExprs; + std::unique_ptr stmt = std::make_unique(asmStr, isGoto, isVolatile); + stmt->SetOutputs(outputs); + for (uint32 i = 0; i < outputs.size(); ++i) { + outputsExprs.emplace_back(exprs[i]->Emit2FEExpr(stmts)); + } + stmt->SetOutputsExpr(outputsExprs); + stmt->SetInputs(inputs); + for (uint32 i = 0; i < inputs.size(); ++i) { + UniqueFEIRExpr expr; + if (inputs[i].second == "m") { + std::unique_ptr addrOf = std::make_unique(); + addrOf->SetUOExpr(exprs[i + outputs.size()]); + expr = addrOf->Emit2FEExpr(stmts); + } else { + expr = exprs[i + outputs.size()]->Emit2FEExpr(stmts); + } + inputsExprs.emplace_back(std::move(expr)); + } + stmt->SetInputsExpr(inputsExprs); + stmt->SetClobbers(clobbers); + stmt->SetLabels(labels); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +std::list ASTOffsetOfStmt::Emit2FEStmtImpl() const { + CHECK_FATAL(exprs.front() != nullptr, "child expr must not be nullptr!"); + std::list stmts; + std::list feExprs; + auto feExpr = exprs.front()->Emit2FEExpr(stmts); + if (feExpr != nullptr) { + feExprs.emplace_back(std::move(feExpr)); + auto stmt = std::make_unique(OP_eval, std::move(feExprs)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + return stmts; +} + +std::list ASTGenericSelectionExprStmt::Emit2FEStmtImpl() const { + CHECK_FATAL(exprs.front() != nullptr, "child expr must not be nullptr!"); + std::list stmts; + std::list feExprs; + auto feExpr = exprs.front()->Emit2FEExpr(stmts); + if (feExpr != nullptr) { + feExprs.emplace_back(std::move(feExpr)); + auto stmt = std::make_unique(OP_eval, std::move(feExprs)); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } + return stmts; +} +} // namespace maple diff --git a/src/hir2mpl/ast_input/clang/src/ast_struct2fe_helper.cpp b/src/hir2mpl/ast_input/clang/src/ast_struct2fe_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6493eef946328e427f9a281227b8d06d8b0c9aaa --- /dev/null +++ b/src/hir2mpl/ast_input/clang/src/ast_struct2fe_helper.cpp @@ -0,0 +1,340 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ast_struct2fe_helper.h" +#include "fe_manager.h" +#include "feir_builder.h" +#include "fe_utils_ast.h" +#include "ast_util.h" +#include "ast_decl_builder.h" +#include "enhance_c_checker.h" + +namespace maple { +// ---------- ASTStruct2FEHelper ---------- +bool ASTStruct2FEHelper::ProcessDeclImpl() { + if (isSkipped) { + return true; + } + if (mirStructType == nullptr) { + return false; + } + mirStructType->SetTypeAttrs(GetStructAttributeFromInput()); + // Process Fields + InitFieldHelpers(); + ProcessFieldDef(); + // Process Methods + InitMethodHelpers(); + ProcessMethodDef(); + return true; +} + +void ASTStruct2FEHelper::InitFieldHelpersImpl() { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mem pool is nullptr"); + for (const ASTField *field : astStruct.GetFields()) { + ASSERT(field != nullptr, "field is nullptr"); + ASTStructField2FEHelper *fieldHelper = mp->New( + allocator, *field, *astStruct.GetTypeDesc().front()); + fieldHelpers.push_back(fieldHelper); + } +} + +void ASTStruct2FEHelper::InitMethodHelpersImpl() { +} + +TypeAttrs ASTStruct2FEHelper::GetStructAttributeFromInputImpl() const { + GenericAttrs attrs = astStruct.GetGenericAttrs(); + return attrs.ConvertToTypeAttrs(); +} + +ASTStruct2FEHelper::ASTStruct2FEHelper(MapleAllocator &allocator, const ASTStruct &structIn) + : FEInputStructHelper(allocator), astStruct(structIn) { + srcLang = kSrcLangC; +} + +std::string ASTStruct2FEHelper::GetStructNameOrinImpl() const { + return astStruct.GetStructName(false); +} + +std::string ASTStruct2FEHelper::GetStructNameMplImpl() const { + return astStruct.GetStructName(true); +} + +std::list ASTStruct2FEHelper::GetSuperClassNamesImpl() const { + CHECK_FATAL(false, "NIY"); + return std::list {}; +} + +std::vector ASTStruct2FEHelper::GetInterfaceNamesImpl() const { + CHECK_FATAL(false, "NIY"); + return std::vector {}; +} + +std::string ASTStruct2FEHelper::GetSourceFileNameImpl() const { + return astStruct.GetSrcFileName(); +} + +std::string ASTStruct2FEHelper::GetSrcFileNameImpl() const { + return astStruct.GetSrcFileName(); +} + +MIRStructType *ASTStruct2FEHelper::CreateMIRStructTypeImpl(bool &error) const { + std::string name = GetStructNameOrinImpl(); + if (name.empty()) { + error = true; + ERR(kLncErr, "class name is empty"); + return nullptr; + } + MIRStructType *type = FEManager::GetTypeManager().GetOrCreateStructType(name); + error = false; + if (astStruct.IsUnion()) { + type->SetMIRTypeKind(kTypeUnion); + } else { + type->SetMIRTypeKind(kTypeStruct); + } + return type; +} + +uint64 ASTStruct2FEHelper::GetRawAccessFlagsImpl() const { + CHECK_FATAL(false, "NIY"); + return 0; +} + +GStrIdx ASTStruct2FEHelper::GetIRSrcFileSigIdxImpl() const { + // Not implemented, just return a invalid value + return GStrIdx(0); +} + +bool ASTStruct2FEHelper::IsMultiDefImpl() const { + // Not implemented, alway return false + return false; +} + +// ---------- ASTGlobalVar2FEHelper --------- +bool ASTStructField2FEHelper::ProcessDeclImpl(MapleAllocator &allocator) { + (void)allocator; + CHECK_FATAL(false, "should not run here"); + return false; +} + +bool ASTStructField2FEHelper::ProcessDeclWithContainerImpl(MapleAllocator &allocator) { + (void)allocator; + std::string fieldName = field.GetName(); + GStrIdx idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fieldName); + FieldAttrs attrs = field.GetGenericAttrs().ConvertToFieldAttrs(); + attrs.SetAlign(field.GetAlign()); + MIRType *fieldType = field.GetTypeDesc().front(); + ASSERT(fieldType != nullptr, "nullptr check for fieldType"); + ENCChecker::InsertBoundaryInAtts(attrs, field.GetBoundaryInfo()); + if (attrs.GetAttr(FLDATTR_nonnull) || + FEManager::GetTypeManager().IsOwnedNonnullFieldStructSet(fieldType->GetTypeIndex())) { // nested struct + FEManager::GetTypeManager().InsertOwnedNonnullFieldStructSet(structType.GetTypeIndex()); + } + mirFieldPair.first = idx; + mirFieldPair.second.first = fieldType->GetTypeIndex(); + mirFieldPair.second.second = attrs; + return true; +} + +// ---------- ASTGlobalVar2FEHelper --------- +bool ASTGlobalVar2FEHelper::ProcessDeclImpl(MapleAllocator &allocator) { + (void)allocator; + const std::string varName = astVar.GetName(); + MIRType *type = astVar.GetTypeDesc().front(); + MIRSymbol *mirSymbol = FEManager::GetMIRBuilder().GetOrCreateGlobalDecl(varName, *type); + if (mirSymbol == nullptr) { + return false; + } + // Set the type here in case a previous declaration had an incomplete + // array type and the definition has the complete type. + if (mirSymbol->GetType()->GetTypeIndex() != type->GetTypeIndex()) { + mirSymbol->SetTyIdx(type->GetTypeIndex()); + } + mirSymbol->GetSrcPosition().SetFileNum(static_cast(astVar.GetSrcFileIdx())); + mirSymbol->GetSrcPosition().SetLineNum(astVar.GetSrcFileLineNum()); + auto typeAttrs = astVar.GetGenericAttrs().ConvertToTypeAttrs(); + ENCChecker::InsertBoundaryInAtts(typeAttrs, astVar.GetBoundaryInfo()); + // do not allow extern var override global var + if (mirSymbol->GetAttrs().GetAttrFlag() != 0 && typeAttrs.GetAttr(ATTR_extern)) { + ASTExpr *initExpr = astVar.GetInitExpr(); + if (initExpr == nullptr) { + return true; + } + MIRConst *cst = initExpr->GenerateMIRConst(); + mirSymbol->SetKonst(cst); + return true; + } + if (typeAttrs.GetAttr(ATTR_extern)) { + mirSymbol->SetStorageClass(MIRStorageClass::kScExtern); + typeAttrs.ResetAttr(AttrKind::ATTR_extern); + } else if (typeAttrs.GetAttr(ATTR_static)) { + mirSymbol->SetStorageClass(MIRStorageClass::kScFstatic); + } else { + mirSymbol->SetStorageClass(MIRStorageClass::kScGlobal); + } + typeAttrs.SetAlign(astVar.GetAlign()); + mirSymbol->SetAttrs(typeAttrs); + if (!astVar.GetSectionAttr().empty()) { + mirSymbol->sectionAttr = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(astVar.GetSectionAttr()); + } + if (!astVar.GetAsmAttr().empty()) { + mirSymbol->SetAsmAttr(GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(astVar.GetAsmAttr())); + } + ASTExpr *initExpr = astVar.GetInitExpr(); + MIRConst *cst = nullptr; + if (initExpr != nullptr) { + cst = initExpr->GenerateMIRConst(); + mirSymbol->SetKonst(cst); + } + ENCChecker::CheckNonnullGlobalVarInit(*mirSymbol, cst); + return true; +} + +bool ASTFileScopeAsm2FEHelper::ProcessDeclImpl(MapleAllocator &allocator) { + MapleString asmDecl(astAsm.GetAsmStr().c_str(), allocator.GetMemPool()); + FEManager::GetModule().GetAsmDecls().emplace_back(asmDecl); + return true; +} + +// ---------- ASTFunc2FEHelper ---------- +bool ASTFunc2FEHelper::ProcessDeclImpl(MapleAllocator &allocator) { + HIR2MPL_PARALLEL_FORBIDDEN(); + ASSERT(srcLang != kSrcLangUnknown, "src lang not set"); + std::string methodShortName = GetMethodName(false, false); + CHECK_FATAL(!methodShortName.empty(), "error: method name is empty"); + if (methodShortName.compare("main") == 0) { + FEManager::GetMIRBuilder().GetMirModule().SetEntryFuncName(methodShortName); + } + methodNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(methodShortName); + if (!ASTUtil::InsertFuncSet(methodNameIdx)) { + return true; + } + SolveReturnAndArgTypes(allocator); + FuncAttrs attrs = GetAttrs(); + if (firstArgRet) { + attrs.SetAttr(FUNCATTR_firstarg_return); + } + bool isStatic = IsStatic(); + bool isVarg = IsVarg(); + CHECK_FATAL(retMIRType != nullptr, "function must have return type"); + std::vector argsTypeIdx; + for (auto *type : argMIRTypes) { + argsTypeIdx.push_back(type->GetTypeIndex()); + } + mirFunc = FEManager::GetTypeManager().CreateFunction(methodNameIdx, retMIRType->GetTypeIndex(), + argsTypeIdx, isVarg, isStatic); + mirFunc->GetSrcPosition().SetFileNum(static_cast(func.GetSrcFileIdx())); + mirFunc->GetSrcPosition().SetLineNum(func.GetSrcFileLineNum()); + MIRSymbol *funSym = mirFunc->GetFuncSymbol(); + if (!func.GetSectionAttr().empty()) { + funSym->sectionAttr = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(func.GetSectionAttr()); + } + if (func.GetWeakrefAttr().first) { + std::string attrStr = func.GetWeakrefAttr().second; + UStrIdx idx { 0 }; + if (!attrStr.empty()) { + idx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(attrStr); + } + funSym->SetWeakrefAttr(std::pair { true, idx }); + } + std::vector paramDecls = func.GetParamDecls(); + if (firstArgRet) { + ASTDecl *returnParamVar = ASTDeclsBuilder::ASTVarBuilder( + allocator, "", "first_arg_return", std::vector{}, GenericAttrs()); + returnParamVar->SetIsParam(true); + paramDecls.insert(paramDecls.begin(), returnParamVar); + } + for (uint32 i = 0; i < paramDecls.size(); ++i) { + MIRSymbol *sym = FEManager::GetMIRBuilder().GetOrCreateDeclInFunc( + paramDecls[i]->GetName(), *argMIRTypes[i], *mirFunc); + sym->SetStorageClass(kScFormal); + sym->SetSKind(kStVar); + TypeAttrs typeAttrs = paramDecls[i]->GetGenericAttrs().ConvertToTypeAttrs(); + ENCChecker::InsertBoundaryInAtts(typeAttrs, paramDecls[i]->GetBoundaryInfo()); + sym->AddAttrs(typeAttrs); + mirFunc->AddArgument(sym); + } + mirMethodPair.first = mirFunc->GetStIdx(); + mirMethodPair.second.first = mirFunc->GetMIRFuncType()->GetTypeIndex(); + ENCChecker::InsertBoundaryInAtts(attrs, func.GetBoundaryInfo()); + mirMethodPair.second.second = attrs; + mirFunc->SetFuncAttrs(attrs); + return true; +} + +const std::string &ASTFunc2FEHelper::GetSrcFileName() const { + return func.GetSrcFileName(); +} + +void ASTFunc2FEHelper::SolveReturnAndArgTypesImpl(MapleAllocator &allocator) { + (void)allocator; + const std::vector &returnAndArgTypeNames = func.GetTypeDesc(); + retMIRType = returnAndArgTypeNames[1]; + // skip funcType and returnType + argMIRTypes.insert(argMIRTypes.begin(), returnAndArgTypeNames.begin() + 2, returnAndArgTypeNames.end()); + if (retMIRType->GetPrimType() == PTY_agg && retMIRType->GetSize() > 16) { + firstArgRet = true; + MIRType *retPointerType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*retMIRType); + argMIRTypes.insert(argMIRTypes.begin(), retPointerType); + retMIRType = GlobalTables::GetTypeTable().GetPrimType(PTY_void); + } +} + +std::string ASTFunc2FEHelper::GetMethodNameImpl(bool inMpl, bool full) const { + std::string funcName = func.GetName(); + if (!full) { + return inMpl ? namemangler::EncodeName(funcName) : funcName; + } + // fullName not implemented yet + return funcName; +} + +bool ASTFunc2FEHelper::IsVargImpl() const { + return false; +} + +bool ASTFunc2FEHelper::HasThisImpl() const { + CHECK_FATAL(false, "NIY"); + return false; +} + +MIRType *ASTFunc2FEHelper::GetTypeForThisImpl() const { + CHECK_FATAL(false, "NIY"); + return nullptr; +} + +FuncAttrs ASTFunc2FEHelper::GetAttrsImpl() const { + return func.GetGenericAttrs().ConvertToFuncAttrs(); +} + +bool ASTFunc2FEHelper::IsStaticImpl() const { + return false; +} + +bool ASTFunc2FEHelper::IsVirtualImpl() const { + CHECK_FATAL(false, "NIY"); + return false; +} +bool ASTFunc2FEHelper::IsNativeImpl() const { + CHECK_FATAL(false, "NIY"); + return false; +} + +bool ASTFunc2FEHelper::HasCodeImpl() const { + if (func.GetCompoundStmt() == nullptr) { + return false; + } + return true; +} +} // namespace maple diff --git a/src/hir2mpl/ast_input/common/include/ast_compiler_component-inl.h b/src/hir2mpl/ast_input/common/include/ast_compiler_component-inl.h new file mode 100644 index 0000000000000000000000000000000000000000..d0996cad26c6dff6b477adb6e382805654c0b594 --- /dev/null +++ b/src/hir2mpl/ast_input/common/include/ast_compiler_component-inl.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ast_compiler_component.h" +#include "ast_struct2fe_helper.h" +#include "ast_function.h" +#include "fe_timer.h" +#include "fe_manager.h" + +namespace maple { +template +ASTCompilerComponent::ASTCompilerComponent(MIRModule &module) + : HIR2MPLCompilerComponent(module, kSrcLangC), + mp(FEUtils::NewMempool("MemPool for ASTCompilerComponent", false /* isLcalPool */)), + allocator(mp), + astInput(module, allocator) {} + +template +ASTCompilerComponent::~ASTCompilerComponent() { + mp = nullptr; +} + +template +bool ASTCompilerComponent::ParseInputImpl() { + FETimer timer; + bool success = true; + timer.StartAndDump("ASTCompilerComponent::ParseInput()"); + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process ASTCompilerComponent::ParseInput() ====="); + std::vector inputNames; + if (typeid(T) == typeid(ASTParser)) { + inputNames = FEOptions::GetInstance().GetInputASTFiles(); +#ifdef ENABLE_MAST + } else if (typeid(T) == typeid(MapleASTParser)) { + inputNames = FEOptions::GetInstance().GetInputMASTFiles(); +#endif + } + success = success && astInput.ReadASTFiles(allocator, inputNames); + CHECK_FATAL(success, "ASTCompilerComponent::ParseInput failed. Exit."); + for (auto &astStruct : astInput.GetASTStructs()) { + FEInputStructHelper *structHelper = allocator.GetMemPool()->New(allocator, *astStruct); + structHelpers.emplace_back(structHelper); + } + + for (auto &astFunc : astInput.GetASTFuncs()) { + FEInputMethodHelper *funcHelper = allocator.GetMemPool()->New(allocator, *astFunc); + for (auto &e : globalFuncHelpers) { + if (funcHelper->GetMethodName(false) == e->GetMethodName(false)) { + globalFuncHelpers.remove(e); + break; + } + } + globalFuncHelpers.emplace_back(funcHelper); + } + + for (auto &astVar : astInput.GetASTVars()) { + FEInputGlobalVarHelper *varHelper = allocator.GetMemPool()->New(allocator, *astVar); + globalVarHelpers.emplace_back(varHelper); + } + + for (auto &astFileScopeAsm : astInput.GetASTFileScopeAsms()) { + FEInputFileScopeAsmHelper *asmHelper = allocator.GetMemPool()->New( + allocator, *astFileScopeAsm); + globalFileScopeAsmHelpers.emplace_back(asmHelper); + } + timer.StopAndDumpTimeMS("ASTCompilerComponent::ParseInput()"); + return success; +} + +template +bool ASTCompilerComponent::PreProcessDeclImpl() { + FETimer timer; + timer.StartAndDump("ASTCompilerComponent::PreProcessDecl()"); + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process ASTCompilerComponent::PreProcessDecl() ====="); + bool success = true; + for (FEInputStructHelper *helper : structHelpers) { + ASSERT_NOT_NULL(helper); + success = helper->PreProcessDecl() ? success : false; + } + timer.StopAndDumpTimeMS("ASTCompilerComponent::PreProcessDecl()"); + return success; +} + +template +std::unique_ptr ASTCompilerComponent::CreatFEFunctionImpl(FEInputMethodHelper *methodHelper) { + ASTFunc2FEHelper *astFuncHelper = static_cast(methodHelper); + GStrIdx methodNameIdx = methodHelper->GetMethodNameIdx(); + bool isStatic = methodHelper->IsStatic(); + MIRFunction *mirFunc = FEManager::GetTypeManager().GetMIRFunction(methodNameIdx, isStatic); + CHECK_NULL_FATAL(mirFunc); + module.AddFunction(mirFunc); + std::unique_ptr feFunction = std::make_unique(*astFuncHelper, *mirFunc, phaseResultTotal); + feFunction->Init(); + return feFunction; +} + +template +bool ASTCompilerComponent::ProcessFunctionSerialImpl() { + std::stringstream ss; + ss << GetComponentName() << "::ProcessFunctionSerial()"; + FETimer timer; + timer.StartAndDump(ss.str()); + bool success = true; + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process %s =====", ss.str().c_str()); + for (FEInputMethodHelper *methodHelper : globalFuncHelpers) { + ASSERT_NOT_NULL(methodHelper); + if (methodHelper->HasCode()) { + ASTFunc2FEHelper *astFuncHelper = static_cast(methodHelper); + std::unique_ptr feFunction = CreatFEFunction(methodHelper); + feFunction->SetSrcFileName(astFuncHelper->GetSrcFileName()); + bool processResult = feFunction->Process(); + if (!processResult) { + (void)compileFailedFEFunctions.insert(feFunction.get()); + } + success = success && processResult; + feFunction->Finish(); + } + funcSize++; + } + timer.StopAndDumpTimeMS(ss.str()); + return success; +} +} // namespace maple diff --git a/src/hir2mpl/ast_input/common/include/ast_compiler_component.h b/src/hir2mpl/ast_input/common/include/ast_compiler_component.h new file mode 100644 index 0000000000000000000000000000000000000000..07e6dadc6eaed90b6bf1d3e09b7bde58c0339164 --- /dev/null +++ b/src/hir2mpl/ast_input/common/include/ast_compiler_component.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_AST_INPUT_INCLUDE_AST_COMPILER_COMPONENT_H +#define HIR2MPL_AST_INPUT_INCLUDE_AST_COMPILER_COMPONENT_H +#include "fe_macros.h" +#include "hir2mpl_compiler_component.h" +#include "ast_input.h" + +namespace maple { +template +class ASTCompilerComponent : public HIR2MPLCompilerComponent { + public: + explicit ASTCompilerComponent(MIRModule &module); + ~ASTCompilerComponent(); + + protected: + bool ParseInputImpl() override; + bool PreProcessDeclImpl() override; + std::unique_ptr CreatFEFunctionImpl(FEInputMethodHelper *methodHelper) override; + bool ProcessFunctionSerialImpl() override; + std::string GetComponentNameImpl() const override { + return "ASTCompilerComponent"; + } + bool ParallelableImpl() const override { + return true; + } + void DumpPhaseTimeTotalImpl() const override { + INFO(kLncInfo, "[PhaseTime] ASTCompilerComponent"); + HIR2MPLCompilerComponent::DumpPhaseTimeTotalImpl(); + } + void ReleaseMemPoolImpl() override { + FEUtils::DeleteMempoolPtr(mp); + } + + private: + MemPool *mp; + MapleAllocator allocator; + ASTInput astInput; +}; // class ASTCompilerComponent +} // namespace maple +#include "ast_compiler_component-inl.h" +#endif // HIR2MPL_AST_INPUT_INCLUDE_AST_COMPILER_COMPONENT_H diff --git a/src/hir2mpl/ast_input/common/include/ast_decl.h b/src/hir2mpl/ast_input/common/include/ast_decl.h new file mode 100644 index 0000000000000000000000000000000000000000..ca523c8b795d01c3c0531cd5c9b830ce11630946 --- /dev/null +++ b/src/hir2mpl/ast_input/common/include/ast_decl.h @@ -0,0 +1,385 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_AST_INPUT_INCLUDE_AST_DECL_H +#define HIR2MPL_AST_INPUT_INCLUDE_AST_DECL_H +#include +#include +#include +#include "types_def.h" +#include "ast_stmt.h" +#include "feir_var.h" +#include "fe_function.h" +#include "generic_attrs.h" + +namespace maple { +using Pos = std::pair; +enum DeclKind { + kUnknownDecl = 0, + kASTDecl, + kASTField, + kASTFunc, + kASTStruct, + kASTVar, + kASTEnumConstant, + kASTEnumDecl, + kASTFileScopeAsm, +}; + +struct BoundaryInfo { + ASTExpr *lenExpr = nullptr; + int8 lenParamIdx = -1; // -1 means not on the parameter + bool isBytedLen = false; +}; + +class ASTDecl { + public: + ASTDecl(const std::string &srcFile, const std::string &nameIn, const std::vector &typeDescIn) + : isGlobalDecl(false), srcFileName(srcFile), name(nameIn), typeDesc(typeDescIn) {} + virtual ~ASTDecl() = default; + const std::string &GetSrcFileName() const; + const std::string &GetName() const; + const std::vector &GetTypeDesc() const; + void SetTypeDesc(const std::vector &typeVecIn); + GenericAttrs GetGenericAttrs() const { + return genAttrs; + } + + void SetGlobal(bool isGlobal) { + isGlobalDecl = isGlobal; + } + + bool IsGlobal() const { + return isGlobalDecl; + } + + void SetIsParam(bool flag) { + isParam = flag; + } + + bool IsParam() const { + return isParam; + } + + void SetIsMacro(bool flag) { + if (flag) { + isMacroID = FEUtils::GetSequentialNumber(); + } else { + isMacroID = flag; + } + } + + uint32 IsMacroID() const { + return isMacroID; + } + + void SetAlign(uint32 n) { + if (n > align) { + align = n; + } + } + + uint32 GetAlign() const { + return align; + } + + void SetAttr(GenericAttrKind attrKind) { + genAttrs.SetAttr(attrKind); + } + + void SetSectionAttr(const std::string &str) { + sectionAttr = str; + } + + const std::string &GetSectionAttr() const { + return sectionAttr; + } + + void GenerateInitStmt(std::list &stmts) { + return GenerateInitStmtImpl(stmts); + } + + void SetDeclPos(const Pos &p) { + pos = p; + } + + void SetSrcLOC(uint32 fileIdx, uint32 lineNum) { + srcFileIdx = fileIdx; + srcFileLineNum = lineNum; + } + + uint32 GetSrcFileIdx() const { + return srcFileIdx; + } + + uint32 GetSrcFileLineNum() const { + return srcFileLineNum; + } + + DeclKind GetDeclKind() const { + return declKind; + } + + MIRConst *Translate2MIRConst() const; + + std::string GenerateUniqueVarName() const; + + void SetBoundaryLenExpr(ASTExpr *expr) { + boundary.lenExpr = expr; + } + + const BoundaryInfo &GetBoundaryInfo() const { + return boundary; + } + + ASTExpr *GetBoundaryLenExpr() const { + return boundary.lenExpr; + } + + void SetBoundaryLenParamIdx(int8 idx) { + boundary.lenParamIdx = idx; + } + + int8 GetBoundaryLenParamIdx() const { + return boundary.lenParamIdx; + } + + void SetIsBytedLen(bool flag) { + boundary.isBytedLen = flag; + } + + bool IsBytedLen() const { + return boundary.isBytedLen; + } + + protected: + virtual MIRConst *Translate2MIRConstImpl() const { + CHECK_FATAL(false, "Maybe implemented for other ASTDecls"); + return nullptr; + } + virtual void GenerateInitStmtImpl(std::list &stmts) {} + bool isGlobalDecl; + bool isParam = false; + uint32 align = 1; // in byte + const std::string srcFileName; + std::string name; + std::vector typeDesc; + GenericAttrs genAttrs; + Pos pos = { 0, 0 }; + uint32 srcFileIdx = 0; + uint32 srcFileLineNum = 0; + uint32 isMacroID = false; + DeclKind declKind = kASTDecl; + BoundaryInfo boundary; + std::string sectionAttr; +}; + +class ASTField : public ASTDecl { + public: + ASTField(const std::string &srcFile, const std::string &nameIn, const std::vector &typeDescIn, + const GenericAttrs &genAttrsIn, bool isAnonymous = false) + : ASTDecl(srcFile, nameIn, typeDescIn), isAnonymousField(isAnonymous) { + genAttrs = genAttrsIn; + declKind = kASTField; + } + ~ASTField() = default; + bool IsAnonymousField() const { + return isAnonymousField; + } + + private: + bool isAnonymousField = false; +}; + +class ASTFunc : public ASTDecl { + public: + ASTFunc(const std::string &srcFile, const std::string &nameIn, const std::vector &typeDescIn, + const GenericAttrs &genAttrsIn, const std::vector ¶mDeclsIn) + : ASTDecl(srcFile, nameIn, typeDescIn), compound(nullptr), paramDecls(paramDeclsIn) { + genAttrs = genAttrsIn; + declKind = kASTFunc; + } + ~ASTFunc() { + compound = nullptr; + } + void SetCompoundStmt(ASTStmt*); + void InsertStmtsIntoCompoundStmtAtFront(const std::list &stmts); + const ASTStmt *GetCompoundStmt() const; + const std::vector &GetParamDecls() const { + return paramDecls; + } + std::vector> GenArgVarList() const; + std::list EmitASTStmtToFEIR() const; + std::list InitArgsBoundaryVar(MIRFunction &mirFunc) const; + void InsertBoundaryCheckingInRet(std::list &stmts) const; + + void SetWeakrefAttr(const std::pair &attr) { + weakrefAttr = attr; + } + + const std::pair &GetWeakrefAttr() const { + return weakrefAttr; + } + + uint32 GetSize() const { + return bodySize; + } + + void SetSize(uint32 size) { + bodySize = size; + } + + private: + // typeDesc format: [funcType, retType, arg0, arg1 ... argN] + ASTStmt *compound = nullptr; // func body + std::vector paramDecls; + std::pair weakrefAttr; + uint32 bodySize = 0; +}; + +class ASTStruct : public ASTDecl { + public: + ASTStruct(const std::string &srcFile, const std::string &nameIn, const std::vector &typeDescIn, + const GenericAttrs &genAttrsIn) + : ASTDecl(srcFile, nameIn, typeDescIn), isUnion(false) { + genAttrs = genAttrsIn; + declKind = kASTStruct; + } + ~ASTStruct() = default; + + std::string GetStructName(bool mapled) const; + + void SetField(ASTField *f) { + fields.emplace_back(f); + } + + const std::list &GetFields() const { + return fields; + } + + void SetIsUnion() { + isUnion = true; + } + + bool IsUnion() const { + return isUnion; + } + + private: + bool isUnion = false; + std::list fields; + std::list methods; +}; + +class ASTVar : public ASTDecl { + public: + ASTVar(const std::string &srcFile, const std::string &nameIn, const std::vector &typeDescIn, + const GenericAttrs &genAttrsIn) + : ASTDecl(srcFile, nameIn, typeDescIn) { + genAttrs = genAttrsIn; + declKind = kASTVar; + } + virtual ~ASTVar() = default; + + void SetInitExpr(ASTExpr *init) { + initExpr = init; + } + + ASTExpr *GetInitExpr() const { + return initExpr; + } + + void SetAsmAttr(const std::string &str) { + asmAttr = str; + } + + const std::string &GetAsmAttr() const { + return asmAttr; + } + + void SetVariableArrayExpr(ASTExpr *expr) { + variableArrayExpr = expr; + } + + std::unique_ptr Translate2FEIRVar() const; + MIRSymbol *Translate2MIRSymbol() const; + + private: + MIRConst *Translate2MIRConstImpl() const override; + void GenerateInitStmtImpl(std::list &stmts) override; + void GenerateInitStmt4StringLiteral(ASTExpr *initASTExpr, const UniqueFEIRVar &feirVar, + const UniqueFEIRExpr &initFeirExpr, std::list &stmts); + ASTExpr *initExpr = nullptr; + std::string asmAttr; + ASTExpr *variableArrayExpr = nullptr; +}; + +class ASTFileScopeAsm : public ASTDecl { + public: + ASTFileScopeAsm(const std::string &srcFile) + : ASTDecl(srcFile, "", std::vector{}) { + declKind = kASTFileScopeAsm; + } + ~ASTFileScopeAsm() = default; + + void SetAsmStr(const std::string &str) { + asmStr = str; + } + + const std::string &GetAsmStr() const { + return asmStr; + } + + private: + std::string asmStr; +}; + +class ASTEnumConstant : public ASTDecl { + public: + ASTEnumConstant(const std::string &srcFile, const std::string &nameIn, const std::vector &typeDescIn, + const GenericAttrs &genAttrsIn) + : ASTDecl(srcFile, nameIn, typeDescIn) { + genAttrs = genAttrsIn; + declKind = kASTEnumConstant; + } + ~ASTEnumConstant() = default; + + void SetValue(int32 val); + int32 GetValue() const; + + private: + MIRConst *Translate2MIRConstImpl() const override; + int32 value = 0; +}; + +// only process local `EnumDecl` here +class ASTEnumDecl : public ASTDecl { + public: + ASTEnumDecl(const std::string &srcFile, const std::string &nameIn, const std::vector &typeDescIn, + const GenericAttrs &genAttrsIn) + : ASTDecl(srcFile, nameIn, typeDescIn) { + genAttrs = genAttrsIn; + declKind = kASTEnumDecl; + } + ~ASTEnumDecl() = default; + + void PushConstant(ASTEnumConstant *c) { + consts.emplace_back(c); + } + + private: + std::list consts; +}; +} // namespace maple +#endif // HIR2MPL_AST_INPUT_INCLUDE_AST_DECL_H diff --git a/src/hir2mpl/ast_input/common/include/ast_decl_builder.h b/src/hir2mpl/ast_input/common/include/ast_decl_builder.h new file mode 100644 index 0000000000000000000000000000000000000000..45aaf4fdc795954cee5e8652e711f5f6e6fd054e --- /dev/null +++ b/src/hir2mpl/ast_input/common/include/ast_decl_builder.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_AST_INPUT_INCLUDE_AST_DECL_BUILDER_H +#define HIR2MPL_AST_INPUT_INCLUDE_AST_DECL_BUILDER_H +#include "ast_decl.h" +#include "mempool_allocator.h" + +namespace maple { +class ASTDeclsBuilder { + public: + static ASTDecl *GetASTDecl(int64 id) { + ASTDecl *decl = declesTable[id]; + return decl; + } + + static ASTDecl *ASTDeclBuilder(const MapleAllocator &allocator, const std::string &srcFile, + const std::string &nameIn, const std::vector &typeDescIn, int64 id = INT64_MAX) { + if (id == INT64_MAX) { + return allocator.GetMemPool()->New(srcFile, nameIn, typeDescIn); // for temp decl + } else if (declesTable[id] == nullptr) { + declesTable[id] = allocator.GetMemPool()->New(srcFile, nameIn, typeDescIn); + } + return declesTable[id]; + } + + static ASTVar *ASTVarBuilder(const MapleAllocator &allocator, const std::string &srcFile, const std::string &varName, + const std::vector &desc, const GenericAttrs &genAttrsIn, int64 id = INT64_MAX) { + if (id == INT64_MAX) { + return allocator.GetMemPool()->New(srcFile, varName, desc, genAttrsIn); + } else if (declesTable[id] == nullptr) { + declesTable[id] = allocator.GetMemPool()->New(srcFile, varName, desc, genAttrsIn); + } + return static_cast(declesTable[id]); + } + + static ASTEnumConstant *ASTEnumConstBuilder(const MapleAllocator &allocator, const std::string &srcFile, + const std::string &varName, const std::vector &desc, + const GenericAttrs &genAttrsIn, int64 id = INT64_MAX) { + if (id == INT64_MAX) { + return allocator.GetMemPool()->New(srcFile, varName, desc, genAttrsIn); + } else if (declesTable[id] == nullptr) { + declesTable[id] = allocator.GetMemPool()->New(srcFile, varName, desc, genAttrsIn); + } + return static_cast(declesTable[id]); + } + + static ASTEnumDecl *ASTLocalEnumDeclBuilder(const MapleAllocator &allocator, const std::string &srcFile, + const std::string &varName, const std::vector &desc, const GenericAttrs &genAttrsIn, + int64 id = INT64_MAX) { + if (id == INT64_MAX) { + return allocator.GetMemPool()->New(srcFile, varName, desc, genAttrsIn); + } else if (declesTable[id] == nullptr) { + declesTable[id] = allocator.GetMemPool()->New(srcFile, varName, desc, genAttrsIn); + } + return static_cast(declesTable[id]); + } + + static ASTFunc *ASTFuncBuilder(const MapleAllocator &allocator, const std::string &srcFile, const std::string &nameIn, + const std::vector &typeDescIn, const GenericAttrs &genAttrsIn, + const std::vector ¶mDeclsIn, int64 id = INT64_MAX) { + if (id == INT64_MAX) { + return allocator.GetMemPool()->New(srcFile, nameIn, typeDescIn, genAttrsIn, paramDeclsIn); + } else if (declesTable[id] == nullptr) { + declesTable[id] = allocator.GetMemPool()->New(srcFile, nameIn, typeDescIn, genAttrsIn, paramDeclsIn); + } + return static_cast(declesTable[id]); + } + + template + static T *ASTStmtBuilder(const MapleAllocator &allocator) { + return allocator.GetMemPool()->New(); + } + + template + static T *ASTExprBuilder(const MapleAllocator &allocator) { + return allocator.GetMemPool()->New(); + } + + static ASTStruct *ASTStructBuilder(const MapleAllocator &allocator, const std::string &srcFile, const std::string &nameIn, + const std::vector &typeDescIn, const GenericAttrs &genAttrsIn, int64 id = INT64_MAX) { + if (id == INT64_MAX) { + return allocator.GetMemPool()->New(srcFile, nameIn, typeDescIn, genAttrsIn); + } else if (declesTable[id] == nullptr) { + declesTable[id] = allocator.GetMemPool()->New(srcFile, nameIn, typeDescIn, genAttrsIn); + } + return static_cast(declesTable[id]); + } + + static ASTField *ASTFieldBuilder(const MapleAllocator &allocator, const std::string &srcFile, const std::string &varName, + const std::vector &desc, const GenericAttrs &genAttrsIn, int64 id = INT64_MAX, + bool isAnonymous = false) { + if (id == INT64_MAX) { + return allocator.GetMemPool()->New(srcFile, varName, desc, genAttrsIn, isAnonymous); + } else if (declesTable[id] == nullptr) { + declesTable[id] = allocator.GetMemPool()->New(srcFile, varName, desc, genAttrsIn, isAnonymous); + } + return static_cast(declesTable[id]); + } + + private: + static std::map declesTable; +}; +} // namespace maple +#endif // HIR2MPL_AST_INPUT_INCLUDE_AST_DECL_BUILDER_H diff --git a/src/hir2mpl/ast_input/common/include/ast_input-inl.h b/src/hir2mpl/ast_input/common/include/ast_input-inl.h new file mode 100644 index 0000000000000000000000000000000000000000..ed577ba5862eaca799c6456b1dadd5ee8ca5607a --- /dev/null +++ b/src/hir2mpl/ast_input/common/include/ast_input-inl.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ast_input.h" +#include "global_tables.h" +#include "fe_macros.h" + +namespace maple { +template +ASTInput::ASTInput(MIRModule &moduleIn, MapleAllocator &allocatorIn) + : module(moduleIn), allocator(allocatorIn), parserMap(allocatorIn.Adapter()), + astStructs(allocatorIn.Adapter()), astFuncs(allocatorIn.Adapter()), astVars(allocatorIn.Adapter()), + astFileScopeAsms(allocatorIn.Adapter()) {} + +template +bool ASTInput::ReadASTFile(MapleAllocator &allocatorIn, uint32 index, const std::string &fileName) { + T *parser = allocator.GetMemPool()->New(allocator, index, fileName, + astStructs, astFuncs, astVars, astFileScopeAsms); + TRY_DO(parser->OpenFile()); + TRY_DO(parser->Verify()); + TRY_DO(parser->PreProcessAST()); + // Some implicit record decl would be retrieved in func body at use, + // so we put `RetrieveFuncs` before `RetrieveStructs` + TRY_DO(parser->RetrieveFuncs(allocatorIn)); + TRY_DO(parser->RetrieveStructs(allocatorIn)); + TRY_DO(parser->RetrieveGlobalVars(allocatorIn)); + TRY_DO(parser->RetrieveFileScopeAsms(allocatorIn)); + parserMap.emplace(fileName, parser); + return true; +} + +template +bool ASTInput::ReadASTFiles(MapleAllocator &mapleAllocator, const std::vector &fileNames) { + bool res = true; + for (uint32 i = 0; res && i < fileNames.size(); ++i) { + res = res && ReadASTFile(mapleAllocator, i, fileNames[i]); + RegisterFileInfo(fileNames[i]); + } + return res; +} + +template +void ASTInput::RegisterFileInfo(const std::string &fileName) { + GStrIdx fileNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fileName); + GStrIdx fileInfoIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("INFO_filename"); + module.PushFileInfoPair(MIRInfoPair(fileInfoIdx, fileNameIdx)); + module.PushFileInfoIsString(true); +} +} \ No newline at end of file diff --git a/src/hir2mpl/ast_input/common/include/ast_input.h b/src/hir2mpl/ast_input/common/include/ast_input.h new file mode 100644 index 0000000000000000000000000000000000000000..0352be5790db830d89fe4894cca934ebea947f5d --- /dev/null +++ b/src/hir2mpl/ast_input/common/include/ast_input.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_AST_INPUT_INCLUDE_AST_INPUT_H +#define HIR2MPL_AST_INPUT_INCLUDE_AST_INPUT_H +#include +#include "mir_module.h" +#include "ast_decl.h" +#include "ast_parser.h" +#ifdef ENABLE_MAST +#include "maple_ast_parser.h" +#endif + +namespace maple { +template +class ASTInput { + public: + ASTInput(MIRModule &moduleIn, MapleAllocator &allocatorIn); + ~ASTInput() = default; + bool ReadASTFile(MapleAllocator &allocatorIn, uint32 index, const std::string &fileName); + bool ReadASTFiles(MapleAllocator &allocatorIn, const std::vector &fileNames); + const MIRModule &GetModule() const { + return module; + } + + void RegisterFileInfo(const std::string &fileName); + const MapleList &GetASTStructs() const { + return astStructs; + } + + void AddASTStruct(ASTStruct *astStruct) { + auto itor = std::find(astStructs.begin(), astStructs.end(), astStruct); + if (itor == astStructs.end()) { + astStructs.emplace_back(astStruct); + } + } + + const MapleList &GetASTFuncs() const { + return astFuncs; + } + + void AddASTFunc(ASTFunc *astFunc) { + astFuncs.emplace_back(astFunc); + } + + const MapleList &GetASTVars() const { + return astVars; + } + + void AddASTVar(ASTVar *astVar) { + astVars.emplace_back(astVar); + } + + const MapleList &GetASTFileScopeAsms() const { + return astFileScopeAsms; + } + + void AddASTFileScopeAsm(ASTFileScopeAsm *fileScopeAsm) { + astFileScopeAsms.emplace_back(fileScopeAsm); + } + + private: + MIRModule &module; + MapleAllocator &allocator; + MapleMap parserMap; + + MapleList astStructs; + MapleList astFuncs; + MapleList astVars; + MapleList astFileScopeAsms; +}; +} +#include "ast_input-inl.h" +#endif // HIR2MPL_AST_INPUT_INCLUDE_AST_INPUT_H \ No newline at end of file diff --git a/src/hir2mpl/ast_input/common/src/ast_decl.cpp b/src/hir2mpl/ast_input/common/src/ast_decl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87ec49a13aa46c0767567d2020ffd3a40fc86b16 --- /dev/null +++ b/src/hir2mpl/ast_input/common/src/ast_decl.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ast_decl.h" +#include "ast_parser.h" +#include "global_tables.h" +#include "ast_stmt.h" +#include "feir_var_name.h" +#include "feir_builder.h" +#include "fe_manager.h" +#include "enhance_c_checker.h" +#include "conditional_operator.h" + +namespace maple { +// ---------- ASTDecl --------- +const std::string &ASTDecl::GetSrcFileName() const { + return srcFileName; +} + +const std::string &ASTDecl::GetName() const { + return name; +} + +const std::vector &ASTDecl::GetTypeDesc() const { + return typeDesc; +} + +void ASTDecl::SetTypeDesc(const std::vector &typeVecIn) { + typeDesc = typeVecIn; +} + +MIRConst *ASTDecl::Translate2MIRConst() const { + return Translate2MIRConstImpl(); +} + +std::string ASTDecl::GenerateUniqueVarName() const { + // add `_line_column` suffix for avoiding local var name conflict + if (isGlobalDecl || isParam) { + return name; + } else { + std::stringstream os; + os << name; + if (isMacroID) { + // for macro expansion, variable names of same location need to be unique + os << "_" << std::to_string(isMacroID); + } else { + os << "_" << std::to_string(pos.first) << "_" << std::to_string(pos.second); + } + return os.str(); + } +} + +// ---------- ASTVar ---------- +std::unique_ptr ASTVar::Translate2FEIRVar() const { + CHECK_FATAL(typeDesc.size() == 1, "Invalid ASTVar"); + auto feirVar = + std::make_unique(GenerateUniqueVarName(), std::make_unique(*(typeDesc[0]))); + feirVar->SetGlobal(isGlobalDecl); + feirVar->SetAttrs(const_cast(genAttrs)); + feirVar->SetSrcLOC(srcFileIdx, srcFileLineNum); + feirVar->SetSectionAttr(sectionAttr); + if (boundary.lenExpr != nullptr) { + std::list nullStmts; + UniqueFEIRExpr lenExpr = boundary.lenExpr->Emit2FEExpr(nullStmts); + feirVar->SetBoundaryLenExpr(std::move(lenExpr)); + } + return feirVar; +} + +MIRConst *ASTVar::Translate2MIRConstImpl() const { + return initExpr->GenerateMIRConst(); +} + +void ASTVar::GenerateInitStmt4StringLiteral(ASTExpr *initASTExpr, const UniqueFEIRVar &feirVar, + const UniqueFEIRExpr &initFeirExpr, std::list &stmts) { + if (!static_cast(initASTExpr)->IsArrayToPointerDecay()) { + std::unique_ptr> argExprList = std::make_unique>(); + UniqueFEIRExpr dstExpr = FEIRBuilder::CreateExprAddrofVar(feirVar->Clone()); + uint32 stringLiteralSize = static_cast(initFeirExpr.get())->GetStringLiteralSize(); + auto uDstExpr = dstExpr->Clone(); + auto uSrcExpr = initFeirExpr->Clone(); + argExprList->emplace_back(std::move(uDstExpr)); + argExprList->emplace_back(std::move(uSrcExpr)); + MIRType *mirArrayType = feirVar->GetType()->GenerateMIRTypeAuto(); + UniqueFEIRExpr sizeExpr; + if (mirArrayType->GetKind() == kTypeArray && + static_cast(mirArrayType)->GetElemType()->GetSize() != 1) { + UniqueFEIRExpr leftExpr = FEIRBuilder::CreateExprConstI32(stringLiteralSize); + size_t elemSizes = static_cast(mirArrayType)->GetElemType()->GetSize(); + CHECK_FATAL(elemSizes <= INT_MAX, "Too large elem size"); + UniqueFEIRExpr rightExpr = FEIRBuilder::CreateExprConstI32(static_cast(elemSizes)); + sizeExpr = FEIRBuilder::CreateExprBinary(OP_mul, std::move(leftExpr), std::move(rightExpr)); + } else { + sizeExpr = FEIRBuilder::CreateExprConstI32(stringLiteralSize); + } + argExprList->emplace_back(sizeExpr->Clone()); + std::unique_ptr memcpyStmt = std::make_unique( + INTRN_C_memcpy, nullptr, nullptr, std::move(argExprList)); + stmts.emplace_back(std::move(memcpyStmt)); + if (mirArrayType->GetKind() != kTypeArray) { + return; + } + auto allSize = static_cast(mirArrayType)->GetSize(); + auto elemSize = static_cast(mirArrayType)->GetElemType()->GetSize(); + CHECK_FATAL(elemSize != 0, "elemSize should not 0"); + auto allElemCnt = allSize / elemSize; + uint32 needInitFurtherCnt = static_cast(allElemCnt - stringLiteralSize); + if (needInitFurtherCnt > 0) { + argExprList = std::make_unique>(); + auto addExpr = FEIRBuilder::CreateExprBinary(OP_add, std::move(dstExpr), sizeExpr->Clone()); + argExprList->emplace_back(std::move(addExpr)); + argExprList->emplace_back(FEIRBuilder::CreateExprConstI32(0)); + argExprList->emplace_back(FEIRBuilder::CreateExprConstI32(needInitFurtherCnt * elemSize)); + std::unique_ptr memsetStmt = std::make_unique( + INTRN_C_memset, nullptr, nullptr, std::move(argExprList)); + stmts.emplace_back(std::move(memsetStmt)); + } + return; + } +} + +void ASTVar::GenerateInitStmtImpl(std::list &stmts) { + MIRSymbol *sym = Translate2MIRSymbol(); + ENCChecker::CheckNonnullLocalVarInit(*sym, initExpr); + UniqueFEIRVar feirVar = Translate2FEIRVar(); + if (variableArrayExpr != nullptr) { + // free, Currently, the back-end are not supported. + // alloca + UniqueFEIRExpr variableArrayFEIRExpr = variableArrayExpr->Emit2FEExpr(stmts); + MIRType *mirType = GlobalTables::GetTypeTable().GetPrimType(PTY_a64); + UniqueFEIRType feType = std::make_unique(*mirType); + UniqueFEIRExpr allocaExpr = std::make_unique(std::move(feType), OP_alloca, + std::move(variableArrayFEIRExpr)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(feirVar->Clone(), std::move(allocaExpr)); + stmts.emplace_back(std::move(stmt)); + return; + } + if (initExpr == nullptr) { + return; + } + if (genAttrs.GetAttr(GENATTR_static) && sym->GetKonst() != nullptr) { + return; + } + UniqueFEIRExpr initFeirExpr = initExpr->Emit2FEExpr(stmts); + if (initFeirExpr == nullptr) { + return; + } + ENCChecker::CheckNonnullLocalVarInit(*sym, initFeirExpr, stmts); + if (initExpr->GetASTOp() == kASTStringLiteral) { // init for StringLiteral + return GenerateInitStmt4StringLiteral(initExpr, feirVar, initFeirExpr, stmts); + } + + if (ConditionalOptimize::DeleteRedundantTmpVar(initFeirExpr, stmts, feirVar, feirVar->GetType()->GetPrimType())) { + return; + } + + PrimType srcPrimType = initFeirExpr->GetPrimType(); + UniqueFEIRStmt stmt; + if (srcPrimType != feirVar->GetType()->GetPrimType() && srcPrimType != PTY_agg && srcPrimType != PTY_void) { + auto castExpr = FEIRBuilder::CreateExprCastPrim(std::move(initFeirExpr), feirVar->GetType()->GetPrimType()); + stmt = FEIRBuilder::CreateStmtDAssign(std::move(feirVar), std::move(castExpr)); + } else { + stmt = FEIRBuilder::CreateStmtDAssign(std::move(feirVar), std::move(initFeirExpr)); + } + stmt->SetSrcFileInfo(initExpr->GetSrcFileIdx(), initExpr->GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); +} + +MIRSymbol *ASTVar::Translate2MIRSymbol() const { + UniqueFEIRVar feirVar = Translate2FEIRVar(); + MIRSymbol *mirSymbol = feirVar->GenerateMIRSymbol(FEManager::GetMIRBuilder()); + if (initExpr != nullptr && genAttrs.GetAttr(GENATTR_static)) { + MIRConst *cst = initExpr->GenerateMIRConst(); + if (cst != nullptr && cst->GetKind() != kConstInvalid) { + mirSymbol->SetKonst(cst); + } + } + if (!sectionAttr.empty()) { + mirSymbol->sectionAttr = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(sectionAttr); + } + if (!asmAttr.empty()) { + mirSymbol->SetAsmAttr(GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(asmAttr)); + } + return mirSymbol; +} + +// ---------- ASTEnumConstant ---------- +void ASTEnumConstant::SetValue(int32 val) { + value = val; +} + +int32 ASTEnumConstant::GetValue() const { + return value; +} + +MIRConst *ASTEnumConstant::Translate2MIRConstImpl() const { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + value, *GlobalTables::GetTypeTable().GetPrimType(PTY_i32)); +} + +// ---------- ASTFunc --------- +void ASTFunc::SetCompoundStmt(ASTStmt *astCompoundStmt) { + compound = astCompoundStmt; +} + +void ASTFunc::InsertStmtsIntoCompoundStmtAtFront(const std::list &stmts) { + static_cast(compound)->InsertASTStmtsAtFront(stmts); +} + +const ASTStmt *ASTFunc::GetCompoundStmt() const { + return compound; +} + +std::vector> ASTFunc::GenArgVarList() const { + std::vector> args; + return args; +} + +std::list ASTFunc::EmitASTStmtToFEIR() const { + std::list stmts; + const ASTStmt *astStmt = GetCompoundStmt(); + if (astStmt == nullptr) { + return stmts; + } + const ASTCompoundStmt *astCpdStmt = static_cast(astStmt); + const std::list &astStmtList = astCpdStmt->GetASTStmtList(); + for (auto stmtNode : astStmtList) { + std::list childStmts = stmtNode->Emit2FEStmt(); + for (auto &stmt : childStmts) { + // Link jump stmt not implemented yet + stmts.emplace_back(std::move(stmt)); + } + } + // fix int main() no return 0 and void func() no return. there are multiple branches, insert return at the end. + if (stmts.size() == 0 || stmts.back()->GetKind() != kStmtReturn) { + UniqueFEIRExpr retExpr = nullptr; + PrimType retType = typeDesc[1]->GetPrimType(); + if (retType != PTY_void) { + if (!typeDesc[1]->IsScalarType()) { + retType = PTY_i32; + } + retExpr = FEIRBuilder::CreateExprConstAnyScalar(retType, static_cast(0)); + } + UniqueFEIRStmt retStmt = std::make_unique(std::move(retExpr)); + stmts.emplace_back(std::move(retStmt)); + } + InsertBoundaryCheckingInRet(stmts); + return stmts; +} + +// ---------- ASTStruct ---------- +std::string ASTStruct::GetStructName(bool mapled) const { + return mapled ? namemangler::EncodeName(name) : name; +} +} // namespace maple diff --git a/src/hir2mpl/ast_input/maple/include/maple_ast_parser.h b/src/hir2mpl/ast_input/maple/include/maple_ast_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..f38e3c3ba222b5e2f8ba40bce3e26ab8fd131f88 --- /dev/null +++ b/src/hir2mpl/ast_input/maple/include/maple_ast_parser.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_AST_PARSER_H +#define MAPLE_AST_PARSER_H +#include +#include +#include "mempool_allocator.h" +#include "ast_decl.h" +#include "maple_ast_interface.h" +#include "ast.h" + +namespace maple { +class MapleASTParser { + public: + MapleASTParser(MapleAllocator &allocatorIn, uint32 fileIdxIn, const std::string &fileNameIn, + MapleList &astStructsIn, MapleList &astFuncsIn, MapleList &astVarsIn, + MapleList &astFileScopeAsmsIn) + : fileIdx(fileIdxIn), fileName(fileNameIn), + globalVarDecles(allocatorIn.Adapter()), funcDecles(allocatorIn.Adapter()), + astStructs(astStructsIn), astFuncs(astFuncsIn), + astVars(astVarsIn), astFileScopeAsms(astFileScopeAsmsIn), + astFuncMap(allocatorIn.Adapter()) {} + virtual ~MapleASTParser() = default; + bool OpenFile(); + const uint32 GetFileIdx() const; + bool Verify() const; + bool PreProcessAST(); + + std::list ProcessDeclNode(MapleAllocator &allocator, maplefe::DeclNode *decl); + ASTDecl *ProcessDecl(MapleAllocator &allocator, maplefe::TreeNode *decl); +#define MAPLE_PROCESS_DECL(CLASS) ProcessDecl##CLASS##Node(MapleAllocator &allocator, maplefe::CLASS##Node*) + ASTDecl *MAPLE_PROCESS_DECL(Function); + ASTDecl *MAPLE_PROCESS_DECL(Identifier); + + ASTStmt *ProcessStmt(MapleAllocator &allocator, maplefe::TreeNode *stmt); +#define MAPLE_PROCESS_STMT(CLASS) ProcessStmt##CLASS##Node(MapleAllocator&, maplefe::CLASS##Node*) + ASTStmt *MAPLE_PROCESS_STMT(Block); + ASTStmt *MAPLE_PROCESS_STMT(Decl); + ASTStmt *MAPLE_PROCESS_STMT(Return); + + ASTExpr *ProcessExpr(MapleAllocator &allocator, maplefe::TreeNode *expr); +#define MAPLE_PROCESS_EXPR(CLASS) ProcessExpr##CLASS##Node(MapleAllocator&, maplefe::CLASS##Node*) + ASTExpr *MAPLE_PROCESS_EXPR(Literal); + ASTExpr *MAPLE_PROCESS_EXPR(Call); + ASTExpr *MAPLE_PROCESS_EXPR(Identifier); + + bool RetrieveStructs(MapleAllocator &allocator); + bool RetrieveFuncs(MapleAllocator &allocator); + bool RetrieveGlobalVars(MapleAllocator &allocator); + bool RetrieveFileScopeAsms(MapleAllocator &allocator); + + private: + uint32 fileIdx; + const std::string fileName; + std::unique_ptr astFile; + MapleList globalVarDecles; + MapleList funcDecles; + MapleList &astStructs; + MapleList &astFuncs; + MapleList &astVars; + MapleList &astFileScopeAsms; + MapleMap astFuncMap; +}; +} // namespace maple +#endif // MAPLE_AST_PARSER_H diff --git a/src/hir2mpl/ast_input/maple/lib/maple_ast_interface.cpp b/src/hir2mpl/ast_input/maple/lib/maple_ast_interface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..614abb630c74c8a40c351cfe821c7f6d361bb573 --- /dev/null +++ b/src/hir2mpl/ast_input/maple/lib/maple_ast_interface.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "maple_ast_interface.h" +#include +#include +#include "gen_aststore.h" +#include "gen_astload.h" +#include "global_tables.h" + +namespace maple { +bool LibMapleAstFile::Open(const std::string &fileName) { + std::ifstream input(fileName, std::ifstream::binary); + input >> std::noskipws; + std::istream_iterator s(input), e; + maplefe::AstBuffer vec(s, e); + maplefe::AstLoad loadAst; + maplefe::ModuleNode *mod = loadAst.LoadFromAstBuf(vec); + // add mod to the vector + while(mod) { + handler.AddModule(mod); + mod = loadAst.Next(); + } + return true; +} + +PrimType LibMapleAstFile::MapPrim(maplefe::TypeId id) { + PrimType prim; + switch (id) { + case maplefe::TY_Boolean: + prim = PTY_u1; + break; + case maplefe::TY_Byte: + prim = PTY_u8; + break; + case maplefe::TY_Short: + prim = PTY_i16; + break; + case maplefe::TY_Int: + prim = PTY_i32; + break; + case maplefe::TY_Long: + prim = PTY_i64; + break; + case maplefe::TY_Char: + prim = PTY_u16; + break; + case maplefe::TY_Float: + prim = PTY_f32; + break; + case maplefe::TY_Double: + prim = PTY_f64; + break; + case maplefe::TY_Void: + prim = PTY_void; + break; + case maplefe::TY_Null: + prim = PTY_void; + break; + default: + CHECK_FATAL(false, "Unsupported PrimType"); + break; + } + return prim; +} + +MIRType *LibMapleAstFile::MapPrimType(maplefe::TypeId id) { + PrimType prim = MapPrim(id); + TyIdx tid(prim); + return GlobalTables::GetTypeTable().GetTypeFromTyIdx(tid); +} + +MIRType *LibMapleAstFile::MapPrimType(maplefe::PrimTypeNode *ptnode) { + return MapPrimType(ptnode->GetPrimType()); +} + +MIRType *LibMapleAstFile::MapType(maplefe::TreeNode *type) { + if (type == nullptr) { + return GlobalTables::GetTypeTable().GetVoid(); + } + + MIRType *mirType = nullptr; + if (type->IsPrimType()) { + maplefe::PrimTypeNode *ptnode = static_cast(type); + mirType = MapPrimType(ptnode); + } else if (type->IsUserType()) { + if (type->IsIdentifier()) { + maplefe::IdentifierNode *inode = static_cast(type); + mirType = MapType(inode->GetType()); + } else { + CHECK_FATAL(false, "MapType IsUserType"); + } + } else { + CHECK_FATAL(false, "MapType unknown type"); + } + + return mirType; +} +} \ No newline at end of file diff --git a/src/hir2mpl/ast_input/maple/lib/maple_ast_interface.h b/src/hir2mpl/ast_input/maple/lib/maple_ast_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..77d8b4f9e7559d578790d3c81760062938b5f4ca --- /dev/null +++ b/src/hir2mpl/ast_input/maple/lib/maple_ast_interface.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_AST_INTERFACE_H +#define MAPLE_AST_INTERFACE_H +#include +#include "ast_handler.h" +#include "mir_type.h" + +namespace maple { +class LibMapleAstFile { + public: + LibMapleAstFile() : handler(maplefe::FLG_trace) {} + ~LibMapleAstFile() = default; + + bool Open(const std::string &fileName); + + maplefe::AST_Handler &GetASTHandler() { + return handler; + } + + PrimType MapPrim(maplefe::TypeId id); + MIRType *MapPrimType(maplefe::TypeId id); + MIRType *MapPrimType(maplefe::PrimTypeNode *ptnode); + MIRType *MapType(maplefe::TreeNode *type); + + private: + maplefe::AST_Handler handler; +}; +} // namespace maple +#endif // MAPLE_AST_INTERFACE_H \ No newline at end of file diff --git a/src/hir2mpl/ast_input/maple/src/maple_ast_parser.cpp b/src/hir2mpl/ast_input/maple/src/maple_ast_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01765dc2d6ba18de8a7a18985e4ce35779c2773f --- /dev/null +++ b/src/hir2mpl/ast_input/maple/src/maple_ast_parser.cpp @@ -0,0 +1,345 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "maple_ast_parser.h" +#include "ast_decl_builder.h" + +namespace maple { +bool MapleASTParser::OpenFile() { + (void)astStructs; + (void)astFileScopeAsms; + astFile = std::make_unique(); + bool res = astFile->Open(fileName); + if (!res) { + return false; + } + return true; +} + +const uint32 MapleASTParser::GetFileIdx() const { + return fileIdx; +} + +bool MapleASTParser::Verify() const { + return true; +} + +bool MapleASTParser::PreProcessAST() { + for (uint32 i = 0; i < astFile->GetASTHandler().GetSize(); ++i) { + maplefe::Module_Handler *handler = astFile->GetASTHandler().GetModuleHandler(i); + maplefe::ModuleNode *module = handler->GetASTModule(); + for (uint32 i = 0; i < module->GetTreesNum(); ++i) { + maplefe::TreeNode *node = module->GetTree(i); + switch (node->GetKind()) { + case maplefe::NK_Decl: + globalVarDecles.emplace_back(node); + break; + case maplefe::NK_Function: + funcDecles.emplace_back(node); + break; + default: break; + } + } + } + return true; +} + + +#define MAPLE_DECL_CASE(CLASS) \ + case maplefe::NK_##CLASS: { \ + ASTDecl *astDecl = ProcessDecl##CLASS##Node(allocator, static_cast(decl)); \ + if (astDecl != nullptr) { \ + } \ + return astDecl; \ + } + +ASTDecl *MapleASTParser::ProcessDecl(MapleAllocator &allocator, maplefe::TreeNode *decl) { + ASTDecl *astDecl = ASTDeclsBuilder::GetASTDecl(decl->GetNodeId()); + if (astDecl != nullptr) { + return astDecl; + } + + switch (decl->GetKind()) { + MAPLE_DECL_CASE(Function) + MAPLE_DECL_CASE(Identifier) + default: + decl->Dump(0); + CHECK_FATAL(false, "ASTDecl NIY"); + return nullptr; + } + return nullptr; +} + +ASTDecl *MapleASTParser::ProcessDeclIdentifierNode(MapleAllocator &allocator, maplefe::IdentifierNode *identifierDecl) { + ASTVar *astVar = static_cast(ASTDeclsBuilder::GetASTDecl(identifierDecl->GetNodeId())); + if (astVar != nullptr) { + return astVar; + } + + std::string varName = identifierDecl->GetName(); + if (varName.empty()) { + return nullptr; + } + MIRType *varType = astFile->MapType(identifierDecl->GetType()); + if (varType == nullptr) { + return nullptr; + } + GenericAttrs attrs; + astVar = ASTDeclsBuilder::ASTVarBuilder( + allocator, fileName, varName, std::vector{varType}, attrs, identifierDecl->GetNodeId()); + + if (identifierDecl->GetInit() != nullptr) { + auto astInitExpr = ProcessExpr(allocator, identifierDecl->GetInit()); + astVar->SetInitExpr(astInitExpr); + } + + return astVar; +} + +std::list MapleASTParser::ProcessDeclNode(MapleAllocator &allocator, maplefe::DeclNode *varDecl) { + maplefe::VarListNode *varList = static_cast(varDecl->GetVar()); + std::list astVars; + for (uint32 i = 0; i < varList->GetVarsNum(); ++i) { + maplefe::IdentifierNode *iNode = varList->GetVarAtIndex(i); + ASTVar *astVar = static_cast(ProcessDecl(allocator, iNode)); + astVars.emplace_back(astVar); + } + return astVars; +} + +ASTDecl *MapleASTParser::ProcessDeclFunctionNode(MapleAllocator &allocator, maplefe::FunctionNode *funcDecl) { + ASTFunc *astFunc = static_cast(ASTDeclsBuilder::GetASTDecl(funcDecl->GetNodeId())); + if (astFunc != nullptr) { + return astFunc; + } + + std::string funcName = funcDecl->GetName(); + if (funcName.empty()) { + return nullptr; + } + + std::vector typeDescIn; + typeDescIn.push_back(nullptr); // mirFuncType + MIRType *retType = astFile->MapType(funcDecl->GetType()); + if (retType == nullptr) { + return nullptr; + } + typeDescIn.push_back(retType); + + std::vector paramDecls; + uint32 numParam = funcDecl->GetParamsNum(); + for (uint32 i = 0; i < numParam; ++i) { + maplefe::TreeNode *param = funcDecl->GetParam(i); + ASTDecl *parmVarDecl = nullptr; + if (param->IsIdentifier()) { + parmVarDecl = ProcessDecl(allocator, param); + } else { + continue; + } + paramDecls.push_back(parmVarDecl); + typeDescIn.push_back(parmVarDecl->GetTypeDesc().front()); + } + + GenericAttrs attrs; + astFunc = ASTDeclsBuilder::ASTFuncBuilder( + allocator, fileName, funcName, typeDescIn, attrs, paramDecls, funcDecl->GetNodeId()); + CHECK_FATAL(astFunc != nullptr, "astFunc is nullptr"); + + maplefe::BlockNode *astBody = funcDecl->GetBody(); + if (astBody != nullptr) { + ASTStmt *astCompoundStmt = ProcessStmt(allocator, astBody); + if (astCompoundStmt != nullptr) { + astFunc->SetCompoundStmt(astCompoundStmt); + } + } + astFuncMap[funcDecl->GetStrIdx()] = astFunc; + return astFunc; +} + + +#define MAPLE_STMT_CASE(CLASS) \ + case maplefe::NK_##CLASS: { \ + ASTStmt *astStmt = ProcessStmt##CLASS##Node(allocator, static_cast(stmt)); \ + return astStmt; \ + } + +ASTStmt *MapleASTParser::ProcessStmt(MapleAllocator &allocator, maplefe::TreeNode *stmt) { + switch (stmt->GetKind()) { + MAPLE_STMT_CASE(Block); + MAPLE_STMT_CASE(Decl); + MAPLE_STMT_CASE(Return); + default: { + stmt->Dump(0); + CHECK_FATAL(false, "ASTStmt NIY"); + return nullptr; + } + } +} + +ASTStmt *MapleASTParser::ProcessStmtBlockNode(MapleAllocator &allocator, maplefe::BlockNode *stmt) { + ASTCompoundStmt *astCompoundStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astCompoundStmt != nullptr, "astCompoundStmt is nullptr"); + ASTStmt *childStmt = nullptr; + for (uint32 i = 0; i < stmt->GetChildrenNum(); ++i) { + maplefe::TreeNode *child = stmt->GetChildAtIndex(i); + childStmt = ProcessStmt(allocator, child); + if (childStmt != nullptr) { + astCompoundStmt->SetASTStmt(childStmt); + } else { + continue; + } + } + return astCompoundStmt; +} + +ASTStmt *MapleASTParser::ProcessStmtDeclNode(MapleAllocator &allocator, maplefe::DeclNode *stmt) { + ASTDeclStmt *declStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + std::list astVars = ProcessDeclNode(allocator, stmt); + for (auto &var : astVars) { + declStmt->SetSubDecl(var); + } + return declStmt; +} + +ASTStmt *MapleASTParser::ProcessStmtReturnNode(MapleAllocator &allocator, maplefe::ReturnNode *stmt) { + ASTReturnStmt *astStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + CHECK_FATAL(astStmt != nullptr, "astStmt is nullptr"); + ASTExpr *astExpr = ProcessExpr(allocator, stmt->GetResult()); + astStmt->SetASTExpr(astExpr); + return astStmt; +} + +#define MAPLE_EXPR_CASE(CLASS) \ + case maplefe::NK_##CLASS: { \ + ASTExpr *astExpr = ProcessExpr##CLASS##Node(allocator, static_cast(expr)); \ + if (astExpr == nullptr) { \ + return nullptr; \ + } \ + return astExpr; \ + } + +ASTExpr *MapleASTParser::ProcessExpr(MapleAllocator &allocator, maplefe::TreeNode *expr) { + if (expr == nullptr) { + return nullptr; + } + + switch (expr->GetKind()) { + MAPLE_EXPR_CASE(Literal); + MAPLE_EXPR_CASE(Call); + MAPLE_EXPR_CASE(Identifier); + default: + expr->Dump(0); + CHECK_FATAL(false, "ASTExpr NIY"); + return nullptr; + } +} + +ASTExpr *MapleASTParser::ProcessExprLiteralNode(MapleAllocator &allocator, maplefe::LiteralNode *expr) { + ASTExpr *literalExpr = nullptr; + switch (expr->GetData().mType) { + case maplefe::LT_IntegerLiteral: + literalExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + literalExpr->SetType(GlobalTables::GetTypeTable().GetInt64()); + static_cast(literalExpr)->SetVal(expr->GetData().mData.mInt64); + break; + case maplefe::LT_FPLiteral: + literalExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + literalExpr->SetType(GlobalTables::GetTypeTable().GetFloat()); + static_cast(literalExpr)->SetVal(expr->GetData().mData.mFloat); + break; + case maplefe::LT_DoubleLiteral: + literalExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + literalExpr->SetType(GlobalTables::GetTypeTable().GetDouble()); + static_cast(literalExpr)->SetVal(expr->GetData().mData.mDouble); + break; + default: + CHECK_FATAL(false, "NYI"); + break; + } + return literalExpr; +} + +ASTExpr *MapleASTParser::ProcessExprIdentifierNode(MapleAllocator &allocator, maplefe::IdentifierNode *expr) { + ASTDeclRefExpr *astRefExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + CHECK_FATAL(astRefExpr != nullptr, "astRefExpr is nullptr"); + ASTDecl *astDecl = ASTDeclsBuilder::GetASTDecl(expr->GetNodeId()); + if (astDecl == nullptr) { + astDecl = ProcessDecl(allocator, expr); + } + astRefExpr->SetASTDecl(astDecl); + astRefExpr->SetType(astDecl->GetTypeDesc().front()); + return astRefExpr; +} + +ASTExpr *MapleASTParser::ProcessExprCallNode(MapleAllocator &allocator, maplefe::CallNode *expr) { + ASTCallExpr *astCallExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + ASSERT(astCallExpr != nullptr, "astCallExpr is nullptr"); + // callee + ASTExpr *astCallee = ProcessExpr(allocator, expr->GetMethod()); + if (astCallee == nullptr) { + return nullptr; + } + astCallExpr->SetCalleeExpr(astCallee); + // return + // C language function names can be used as unique identifiers + MIRType *retType = astFuncMap[expr->GetMethod()->GetStrIdx()]->GetTypeDesc()[1]; + astCallExpr->SetRetType(retType); + // args + std::vector args; + for (uint32_t i = 0; i < expr->GetArgsNum(); ++i) { + maplefe::TreeNode *subExpr = expr->GetArg(i); + ASTExpr *arg = ProcessExpr(allocator, subExpr); + args.push_back(arg); + } + astCallExpr->SetArgs(args); + if (expr->GetMethod() != nullptr) { + GenericAttrs attrs; + astCallExpr->SetFuncName(astCallee->GetASTDecl()->GetName()); + astCallExpr->SetFuncAttrs(attrs.ConvertToFuncAttrs()); + } else { + astCallExpr->SetIcall(true); + } + return astCallExpr; +} + +bool MapleASTParser::RetrieveStructs(MapleAllocator &allocator) { + return true; +} + +bool MapleASTParser::RetrieveFuncs(MapleAllocator &allocator) { + for (auto &decl : funcDecles) { + ASTFunc *funcDecl = static_cast(ProcessDecl(allocator, decl)); + if (funcDecl == nullptr) { + return false; + } + funcDecl->SetGlobal(true); + astFuncs.emplace_back(funcDecl); + } + return true; +} + +bool MapleASTParser::RetrieveGlobalVars(MapleAllocator &allocator) { + for (auto &decl : globalVarDecles) { + std::list astVarList = ProcessDeclNode(allocator, static_cast(decl)); + for (auto &astVar : astVarList) { + astVars.emplace_back(static_cast(astVar)); + } + } + return true; +} + +bool MapleASTParser::RetrieveFileScopeAsms(MapleAllocator &allocator) { + return true; +} +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_attr.def b/src/hir2mpl/bytecode_input/class/include/jbc_attr.def new file mode 100644 index 0000000000000000000000000000000000000000..4fe4da2e62a49bb97ac696d9897181e4a2eb36bf --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_attr.def @@ -0,0 +1,37 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +JBC_ATTR("ConstantValue", ConstantValue) +JBC_ATTR("Code", Code) +JBC_ATTR("StackMapTable", StackMapTable) +JBC_ATTR("Exceptions", Exception) +JBC_ATTR("InnerClasses", InnerClass) +JBC_ATTR("EnclosingMethod", EnclosingMethod) +JBC_ATTR("Synthetic", Synthetic) +JBC_ATTR("Signature", Signature) +JBC_ATTR("SourceFile", SourceFile) +JBC_ATTR("SourceDebugExtension", SourceDebugEx) +JBC_ATTR("LineNumberTable", LineNumberTable) +JBC_ATTR("LocalVariableTable", LocalVariableTable) +JBC_ATTR("LocalVariableTypeTable", LocalVariableTypeTable) +JBC_ATTR("Deprecated", Deprecated) +JBC_ATTR("RuntimeVisibleAnnotations", RTVisAnnotations) +JBC_ATTR("RuntimeInvisibleAnnotations", RTInvisAnnotations) +JBC_ATTR("RuntimeVisibleParameterAnnotations", RTVisParamAnnotations) +JBC_ATTR("RuntimeInvisibleParameterAnnotations", RTInvisParamAnnotations) +JBC_ATTR("RuntimeVisibleTypeAnnotations", RTVisTypeAnnotations) +JBC_ATTR("RuntimeInvisibleTypeAnnotations", RTInvisTypeAnnotations) +JBC_ATTR("AnnotationDefault", AnnotationDefault) +JBC_ATTR("BootstrapMethods", BootstrapMethods) +JBC_ATTR("MethodParameters", MethodParameters) \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_attr.h b/src/hir2mpl/bytecode_input/class/include/jbc_attr.h new file mode 100644 index 0000000000000000000000000000000000000000..59024ee5acae7647254de9a0cb83a172f10fee0f --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_attr.h @@ -0,0 +1,583 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_ATTR_H +#define HIR2MPL_INCLUDE_JBC_ATTR_H +#include "mempool_allocator.h" +#include "types_def.h" +#include "fe_configs.h" +#include "basic_io.h" +#include "jbc_class_const_pool.h" +#include "jbc_attr_item.h" +#include "jbc_opcode.h" + +namespace maple { +namespace jbc { +const static uint32 kInvalidPC = UINT32_MAX; +const static uint16 kInvalidPC16 = UINT16_MAX; +const static uint32 kMaxPC32 = 0x0000FFFF; + +enum JBCAttrKind : uint8 { + kAttrUnknown, + kAttrRaw, +#undef JBC_ATTR +#define JBC_ATTR(name, type) kAttr##type, +#include "jbc_attr.def" +#undef JBC_ATTR +}; + +class JBCAttr { + public: + JBCAttr(JBCAttrKind kindIn, uint16 nameIdxIn, uint32 lengthIn); + virtual ~JBCAttr() = default; + static JBCAttr *InAttr(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool); + static JBCAttrKind AttrKind(const std::string &str); + JBCAttrKind GetKind() const { + return kind; + } + + bool ParseFile(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + return ParseFileImpl(allocator, io, constPool); + } + + bool PreProcess(const JBCConstPool &constPool) { + return PreProcessImpl(constPool); + } + + SimpleXMLElem *GenXmlElem(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const { + return GenXmlElemImpl(allocator, constPool, idx); + } + + protected: + virtual bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) = 0; + virtual bool PreProcessImpl(const JBCConstPool &constPool) = 0; + virtual SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const = 0; + + JBCAttrKind kind; + uint16 nameIdx; + uint32 length; +}; + +class JBCAttrMap { + public: + explicit JBCAttrMap(MapleAllocator &allocatorIn); + ~JBCAttrMap() = default; + void RegisterAttr(JBCAttr &attr); + std::list GetAttrs(JBCAttrKind kind) const; + const JBCAttr *GetAttr(JBCAttrKind kind) const; + bool PreProcess(const JBCConstPool &constPool); + + private: + MapleAllocator &allocator; + MapleMap*> mapAttrs; +}; + +class JBCAttrRaw : public JBCAttr { + public: + JBCAttrRaw(const MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrRaw(); + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint8 *rawData; +}; + +struct JavaAttrLocalVariableInfoItem { + JavaAttrLocalVariableInfoItem() + : slotIdx(0), + start(0), + length(0), + nameIdx(0), + feirType(nullptr), + signatureNameIdx(0) {} + + uint16 slotIdx; + uint16 start; + uint16 length; + GStrIdx nameIdx; // in java format + const FEIRType *feirType; + GStrIdx signatureNameIdx; // in java format +}; + +class JBCAttrLocalVariableInfo { + public: + explicit JBCAttrLocalVariableInfo(MapleAllocator &argAllocator); + ~JBCAttrLocalVariableInfo() = default; + void RegisterItem(const attr::LocalVariableTableItem &itemAttr); + void RegisterTypeItem(const attr::LocalVariableTypeTableItem &itemAttr); + const JavaAttrLocalVariableInfoItem &GetItemByStart(uint16 slotIdx, uint16 start) const; + uint16 GetStart(uint16 slotIdx, uint16 pc) const; + std::list EmitToStrings() const; + static bool IsInvalidLocalVariableInfoItem(const JavaAttrLocalVariableInfoItem &item); + + private: + void AddSlotStartMap(uint16 slotIdx, uint16 startPC); + void CheckItemAvaiable(uint16 slotIdx, uint16 start) const; + JavaAttrLocalVariableInfoItem *GetItemByStartInternal(uint16 slotIdx, uint16 start); + + MapleAllocator &allocator; + MapleMap> slotStartMap; // map> + MapleMap, JavaAttrLocalVariableInfoItem> itemMap; + static JavaAttrLocalVariableInfoItem kInvalidInfoItem; +}; + +// ConstantValue Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.2 +class JBCAttrConstantValue : public JBCAttr { + public: + JBCAttrConstantValue(const MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrConstantValue(); + const JBCConst *GetConstValue() const { + return constValue; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 constIdx; + JBCConst *constValue; +}; + +// Code Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.3 +class JBCAttrLocalVariableInfo; +class JBCOp; +class JBCAttrCode : public JBCAttr { + public: + JBCAttrCode(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrCode(); + void InitLocalVarInfo(); + void SetLoadStoreType() const; + const MapleMap &GetInstMap() const { + return instructions; + } + + uint16 GetMaxStack() const { + return maxStack; + } + + uint16 GetMaxLocals() const { + return maxLocals; + } + + uint32 GetCodeLength() const { + return codeLength; + } + + LLT_MOCK_TARGET const MapleVector &GetExceptionInfos() const { + return exceptions; + } + + const JBCAttr *GetAttr(JBCAttrKind kind) const { + return attrMap.GetAttr(kind); + } + + const std::list GetAttrs(JBCAttrKind kind) const { + return attrMap.GetAttrs(kind); + } + + std::list GetLocalVarInfoByString() const { + return localVarInfo.EmitToStrings(); + } + + const JBCAttrLocalVariableInfo &GetLocalVarInfo() const { + return localVarInfo; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + bool ParseOpcodes(MapleAllocator &allocator); + + uint16 maxStack; + uint16 maxLocals; + uint32 codeLength; + uint8 *code; + uint16 nException; + MapleVector exceptions; + uint16 nAttr; + MapleVector attrs; + MapleMap instructions; + JBCAttrMap attrMap; + JBCAttrLocalVariableInfo localVarInfo; +}; + +// StackMapTable Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4 +class JBCAttrStackMapTable : public JBCAttr { + public: + JBCAttrStackMapTable(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrStackMapTable() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 count; + MapleVector entries; +}; + +// Exceptions Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.5 +class JBCAttrException : public JBCAttr { + public: + JBCAttrException(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrException() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 count; + MapleVector tbExceptionIdx; +}; + +// InnerClass Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.6 +class JBCAttrInnerClass : public JBCAttr { + public: + JBCAttrInnerClass(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrInnerClass() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 count; + MapleVector tbClasses; +}; + +// EnclosingMethod Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.7 +class JBCAttrEnclosingMethod : public JBCAttr { + public: + JBCAttrEnclosingMethod(const MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrEnclosingMethod(); + const JBCConstClass *GetConstClass() const { + return constClass; + } + + const JBCConstNameAndType *GetConstNameAndType() const { + return constNameAndType; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 classIdx; + uint16 methodIdx; + JBCConstClass *constClass; + JBCConstNameAndType *constNameAndType; +}; + +// Synthetic Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.8 +class JBCAttrSynthetic : public JBCAttr { + public: + JBCAttrSynthetic(const MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrSynthetic() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; +}; + +// Signature Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.9 +class JBCAttrSignature : public JBCAttr { + public: + JBCAttrSignature(const MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrSignature(); + const JBCConstUTF8 *GetConstSignatureName() const { + return constSignatureName; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 signatureIdx; + JBCConstUTF8 *constSignatureName; +}; + +// SourceFile Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.10 +class JBCAttrSourceFile : public JBCAttr { + public: + JBCAttrSourceFile(const MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrSourceFile(); + const JBCConstUTF8 *GetConstFileName() const { + return constFileName; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 sourceFileIdx; + const JBCConstUTF8 *constFileName; +}; + +// SourceDebugExtension Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.11 +class JBCAttrSourceDebugEx : public JBCAttr { + public: + JBCAttrSourceDebugEx(const MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrSourceDebugEx(); + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + char *data; +}; + +// LineNumberTable Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.12 +class JBCAttrLineNumberTable : public JBCAttr { + public: + JBCAttrLineNumberTable(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrLineNumberTable() = default; + const MapleVector &GetLineNums() const { + return lineNums; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 size; + MapleVector lineNums; +}; + +// LocalVariableTable Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.13 +class JBCAttrLocalVariableTable : public JBCAttr { + public: + JBCAttrLocalVariableTable(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrLocalVariableTable() = default; + const MapleVector &GetLocalVarInfos() const { + return localVarInfos; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 size; + MapleVector localVarInfos; +}; + +// LocalVariableTypeTable Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.14 +class JBCAttrLocalVariableTypeTable : public JBCAttr { + public: + JBCAttrLocalVariableTypeTable(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrLocalVariableTypeTable() = default; + const MapleVector &GetLocalVarTypeInfos() const { + return localVarTypeInfos; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 size; + MapleVector localVarTypeInfos; +}; + +// Deprecated Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.15 +class JBCAttrDeprecated : public JBCAttr { + public: + JBCAttrDeprecated(const MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrDeprecated() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; +}; + +// RuntimeAnnoations Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16 +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.17 +class JBCAttrRTAnnotations : public JBCAttr { + public: + JBCAttrRTAnnotations(MapleAllocator &allocator, JBCAttrKind kindIn, uint16 nameIdx, uint32 length); + virtual ~JBCAttrRTAnnotations() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + uint16 size; + MapleVector annotations; +}; + +class JBCAttrRTVisAnnotations : public JBCAttrRTAnnotations { + public: + JBCAttrRTVisAnnotations(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrRTVisAnnotations() = default; +}; + +class JBCAttrRTInvisAnnotations : public JBCAttrRTAnnotations { + public: + JBCAttrRTInvisAnnotations(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrRTInvisAnnotations() = default; +}; + +// RuntimeParamAnnoations Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.18 +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.19 +class JBCAttrRTParamAnnotations : public JBCAttr { + public: + JBCAttrRTParamAnnotations(MapleAllocator &allocator, JBCAttrKind kindIn, uint16 nameIdx, uint32 length); + virtual ~JBCAttrRTParamAnnotations() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + uint8 size; + MapleVector annotations; +}; + +class JBCAttrRTVisParamAnnotations : public JBCAttrRTParamAnnotations { + public: + JBCAttrRTVisParamAnnotations(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrRTVisParamAnnotations() {} +}; + +class JBCAttrRTInvisParamAnnotations : public JBCAttrRTParamAnnotations { + public: + JBCAttrRTInvisParamAnnotations(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrRTInvisParamAnnotations() {} +}; + +// RuntimeVisibleTypeAnnotations Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20 +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.21 +class JBCAttrRTTypeAnnotations : public JBCAttr { + public: + JBCAttrRTTypeAnnotations(MapleAllocator &allocator, JBCAttrKind kindIn, uint16 nameIdx, uint32 length); + virtual ~JBCAttrRTTypeAnnotations() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + uint16 size; + MapleVector annotations; +}; + +class JBCAttrRTVisTypeAnnotations : public JBCAttrRTTypeAnnotations { + public: + JBCAttrRTVisTypeAnnotations(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrRTVisTypeAnnotations() = default; +}; + +class JBCAttrRTInvisTypeAnnotations : public JBCAttrRTTypeAnnotations { + public: + JBCAttrRTInvisTypeAnnotations(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrRTInvisTypeAnnotations() = default; +}; + +// AnnotationDefault Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.22 +class JBCAttrAnnotationDefault : public JBCAttr { + public: + JBCAttrAnnotationDefault(const MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrAnnotationDefault(); + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + attr::ElementValue *value; +}; + +// BootstrapMethods Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23 +class JBCAttrBootstrapMethods : public JBCAttr { + public: + JBCAttrBootstrapMethods(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrBootstrapMethods() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 size; + MapleVector methods; +}; + +// MethodParameters Attribute +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24 +class JBCAttrMethodParameters : public JBCAttr { + public: + JBCAttrMethodParameters(MapleAllocator &allocator, uint16 nameIdx, uint32 length); + ~JBCAttrMethodParameters() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint8 size; + MapleVector params; +}; +} // namespace jbc +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_ATTR_H diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_attr_item.h b/src/hir2mpl/bytecode_input/class/include/jbc_attr_item.h new file mode 100644 index 0000000000000000000000000000000000000000..32ef975dd2573b3191d8637ff39791d3d9de1d8c --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_attr_item.h @@ -0,0 +1,912 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_ATTR_ITEM_H +#define HIR2MPL_INCLUDE_JBC_ATTR_ITEM_H +#include +#include +#include "mempool_allocator.h" +#include "types_def.h" +#include "jbc_class_const_pool.h" + +namespace maple { +namespace jbc { +namespace attr { +// ElementValueItem +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16 +enum ElementValueKind : uint8 { + kElementValueDefault = 0, + kElementValueConst, + kElementValueEnum, + kElementValueClassInfo, + kElementValueAnnotation, + kElementValueArray +}; + +class JBCAttrItem { + public: + JBCAttrItem() = default; + virtual ~JBCAttrItem() = default; + bool ParseFile(MapleAllocator &allocator, BasicIORead &io) { + return ParseFileImpl(allocator, io); + } + + bool PreProcess(const JBCConstPool &constPool) { + return PreProcessImpl(constPool); + } + + SimpleXMLElem *GenXmlElem(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const { + return GenXmlElemImpl(allocator, constPool, idx); + } + + protected: + virtual bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) = 0; + virtual bool PreProcessImpl(const JBCConstPool &constPool) = 0; + virtual SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const = 0; +}; + +// ExceptiionTableItem in Code Attr +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.3 +class ExceptionTableItem : public JBCAttrItem { + public: + ExceptionTableItem(); + ~ExceptionTableItem(); + uint16 GetStartPC() const { + return startPC; + } + + uint16 GetEndPC() const { + return endPC; + } + + uint16 GetHandlerPC() const { + return handlerPC; + } + + const JBCConstClass *GetCatchType() const { + return catchType; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 startPC; + uint16 endPC; + uint16 handlerPC; + uint16 catchTypeIdx; + const JBCConstClass *catchType; +}; + +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.4 +enum VerificationTypeInfoTag : uint8 { + kVerTypeInfoItemTop = 0, + kVerTypeInfoItemInteger = 1, + kVerTypeInfoItemFloat = 2, + kVerTypeInfoItemDouble = 3, + kVerTypeInfoItemLong = 4, + kVerTypeInfoItemNull = 5, + kVerTypeInfoItemUninitializedThis = 6, + kVerTypeInfoItemObject = 7, + kVerTypeInfoItemUninitialized = 8, + kVerTypeInfoItemUnknown = 0xFF, +}; + +class VerificationTypeInfo : public JBCAttrItem { + public: + VerificationTypeInfo(); + ~VerificationTypeInfo(); + static std::map InitTagNameMap(); + static std::string TagName(VerificationTypeInfoTag t); + const JBCConstClass &GetClassInfoRef() const { + CHECK_NULL_FATAL(classInfo); + return *classInfo; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + VerificationTypeInfoTag tag; + union { + uint16 cpoolIdx; + uint16 offset; + uint16 raw; + } data; + JBCConstClass *classInfo; + static std::map tagNameMap; +}; + +enum StackMapFrameItemTag : uint8 { + kStackSame, + kStackSameLocals1StackItem, + kStackSameLocals1StackItemEx, + kStackChop, + kStackSameFrameEx, + kStackAppend, + kStackFullFrame, + kStackReserved, +}; + +class StackMapFrameItem : public JBCAttrItem { + public: + StackMapFrameItem(uint8 frameTypeIn, StackMapFrameItemTag tagIn); + virtual ~StackMapFrameItem() = default; + static std::map InitTagName(); + static std::string TagName(StackMapFrameItemTag tag); + static StackMapFrameItemTag FrameType2Tag(uint8 frameType); + static StackMapFrameItem *NewItem(MapleAllocator &allocator, BasicIORead &io, uint8 frameType); + + protected: + StackMapFrameItemTag tag; + uint8 frameType; + static std::map tagNameMap; +}; + +class StackMapFrameItemSame : public StackMapFrameItem { + public: + explicit StackMapFrameItemSame(uint8 frameType); + ~StackMapFrameItemSame() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; +}; + +class StackMapFrameItemSameLocals1 : public StackMapFrameItem { + public: + explicit StackMapFrameItemSameLocals1(uint8 frameType); + ~StackMapFrameItemSameLocals1(); + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + VerificationTypeInfo *stack; +}; + +class StackMapFrameItemSameLocals1Ex : public StackMapFrameItem { + public: + explicit StackMapFrameItemSameLocals1Ex(uint8 frameType); + ~StackMapFrameItemSameLocals1Ex(); + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 offsetDelta; + VerificationTypeInfo *stack; +}; + +class StackMapFrameItemChop : public StackMapFrameItem { + public: + explicit StackMapFrameItemChop(uint8 frameType); + ~StackMapFrameItemChop() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 offsetDelta; +}; + +class StackMapFrameItemSameEx : public StackMapFrameItem { + public: + explicit StackMapFrameItemSameEx(uint8 frameType); + ~StackMapFrameItemSameEx() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 offsetDelta; +}; + +class StackMapFrameItemAppend : public StackMapFrameItem { + public: + StackMapFrameItemAppend(MapleAllocator &allocator, uint8 frameType); + ~StackMapFrameItemAppend() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 offsetDelta; + MapleVector locals; +}; + +class StackMapFrameItemFull : public StackMapFrameItem { + public: + StackMapFrameItemFull(MapleAllocator &allocator, uint8 frameType); + ~StackMapFrameItemFull() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 offsetDelta; + uint16 nLocals; + MapleVector locals; + uint16 nStacks; + MapleVector stacks; +}; + +// InnerClassItem in Attr InnerClass +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.6 +class InnerClassItem : public JBCAttrItem { + public: + InnerClassItem(); + ~InnerClassItem(); + const JBCConstClass *GetConstClassInnerRef() const { + return constClassInner; + } + + const JBCConstClass *GetConstClassOuter() const { + return constClassOuter; + } + + const JBCConstUTF8 *GetConstNameInner() const { + return constNameInner; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 innerClassInfoIdx; + uint16 outerClassInfoIdx; + uint16 innerNameIdx; + uint16 innerClassAccessFlag; + JBCConstClass *constClassInner; + JBCConstClass *constClassOuter; + JBCConstUTF8 *constNameInner; +}; + +// LineNumberTableItem in Attr LineNumberTable +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.12 +class LineNumberTableItem : public JBCAttrItem { + public: + LineNumberTableItem(); + ~LineNumberTableItem() = default; + uint16 GetStartPC() const { + return startPC; + } + + uint16 GetLineNumber() const { + return lineNumber; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 startPC; + uint16 lineNumber; +}; + +// LocalVariableTableItem in Attr LocalVariableTable +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.13 +class LocalVariableTableItem : public JBCAttrItem { + public: + LocalVariableTableItem(); + ~LocalVariableTableItem(); + const JBCConstUTF8 *GetConstName() const { + return constName; + } + + const JBCConstUTF8 *GetConstDesc() const { + return constDesc; + } + + uint16 GetStartPC() const { + return startPC; + } + + uint16 GetLength() const { + return length; + } + + uint16 GetIndex() const { + return index; + } + + GStrIdx GetNameStrIdx() const { + CHECK_NULL_FATAL(constName); + return constName->GetStrIdx(); + } + + const FEIRType *GetFEIRType() const { + return feirType; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 startPC; + uint16 length; + uint16 nameIdx; + uint16 descIdx; + uint16 index; + const JBCConstUTF8 *constName; + const JBCConstUTF8 *constDesc; + GStrIdx nameIdxMpl; + const FEIRType *feirType; +}; + +// LocalVariableTypeTableItem in Attr LocalVariableTypeTable +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.14 +class LocalVariableTypeTableItem : public JBCAttrItem { + public: + LocalVariableTypeTableItem(); + ~LocalVariableTypeTableItem(); + const JBCConstUTF8 *GetConstName() const { + return constName; + } + + const JBCConstUTF8 *GetConstSignature() const { + return constSignature; + } + + uint16 GetStartPC() const { + return startPC; + } + + uint16 GetLength() const { + return length; + } + + uint16 GetIndex() const { + return index; + } + + GStrIdx GetNameStrIdx() const { + CHECK_NULL_FATAL(constName); + return constName->GetStrIdx(); + } + + GStrIdx GetSignatureStrIdx() const { + CHECK_NULL_FATAL(constSignature); + return constSignature->GetStrIdx(); + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 startPC; + uint16 length; + uint16 nameIdx; + uint16 signatureIdx; + uint16 index; + const JBCConstUTF8 *constName; + const JBCConstUTF8 *constSignature; + GStrIdx nameIdxMpl; +}; + +class ElementValueItem : public JBCAttrItem { + public: + ElementValueItem(ElementValueKind kindIn, char tagIn); + virtual ~ElementValueItem() = default; + static std::map InitTagKindMap(); + static std::map InitKindNameMap(); + static std::string KindName(ElementValueKind kind); + static ElementValueKind TagToKind(char tag); + static ElementValueItem *NewItem(MapleAllocator &allocator, BasicIORead &io, char tag); + + protected: + ElementValueKind kind; + char tag; + static std::map tagKindMap; + static std::map kindNameMap; +}; + +class ElementValue : public JBCAttrItem { + public: + ElementValue(); + ~ElementValue(); + ElementValueKind GetKind() const { + return kind; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + char tag; + ElementValueKind kind; + ElementValueItem *value; +}; + +class ElementValuePair : public JBCAttrItem { + public: + ElementValuePair(); + ~ElementValuePair(); + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 nameIdx; + ElementValue *value; +}; + +// Annotation +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.16 +class Annotation : public JBCAttrItem { + public: + explicit Annotation(MapleAllocator &allocator); + ~Annotation(); + const JBCConstUTF8 *GetConstTypeName() const { + return constTypeName; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 typeIdx; + uint16 nElemPairs; + MapleVector tbElemPairs; + JBCConstUTF8 *constTypeName; +}; + +// ParamAnnotationItem in Attr ParamAnnotation +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.18 +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.19 +class ParamAnnotationItem : public JBCAttrItem { + public: + explicit ParamAnnotationItem(MapleAllocator &allocator); + ~ParamAnnotationItem() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 count; + MapleVector annotations; +}; + +// BootstrapMethodItem in Attr BootstrapMethod +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.23 +class BootstrapMethodItem : public JBCAttrItem { + public: + explicit BootstrapMethodItem(MapleAllocator &allocator); + ~BootstrapMethodItem(); + const JBCConstMethodHandleInfo *GetConstMethodHandleInfo() const { + return methodHandle; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 methodRefIdx; + uint16 nArgs; + MapleVector argsIdx; + JBCConstMethodHandleInfo *methodHandle; + MapleVector args; +}; + +// MethodParamItem in Attr MethodParam +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24 +class MethodParamItem : public JBCAttrItem { + public: + MethodParamItem(); + ~MethodParamItem(); + const JBCConstUTF8 *GetConstName() const { + return constName; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 nameIdx; + uint16 accessFlag; + JBCConstUTF8 *constName; +}; + +class ElementValuePair; + +class ElementValueConst : public ElementValueItem { + public: + explicit ElementValueConst(uint8 t); + ~ElementValueConst(); + const JBCConst *GetConstValue() const { + return constValue; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 constValueIdx; + JBCConst *constValue; +}; + +class ElementValueEnum : public ElementValueItem { + public: + ElementValueEnum(); + ~ElementValueEnum(); + const JBCConstUTF8 *GetConstTypeName() const { + return constTypeName; + } + + const JBCConstUTF8 *GetConstName() const { + return constName; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 typeNameIdx; + uint16 constNameIdx; + JBCConstUTF8 *constTypeName; + JBCConstUTF8 *constName; +}; + +class ElementValueClassInfo : public ElementValueItem { + public: + ElementValueClassInfo(); + ~ElementValueClassInfo(); + const JBCConstUTF8 *GetConstClassInfo() const { + return constClassInfo; + } + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 classInfoIdx; + JBCConstUTF8 *constClassInfo; +}; + +class ElementValueAnnotation : public ElementValueItem { + public: + ElementValueAnnotation(); + ~ElementValueAnnotation(); + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + Annotation *annotation; +}; + +class ElementValueArray : public ElementValueItem { + public: + explicit ElementValueArray(MapleAllocator &allocator); + ~ElementValueArray() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 size; + MapleVector values; +}; + +// TargetInfo +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.1 +enum TargetInfoItemTag : uint8 { + kTargetTagUndefine, + kTargetTagTypeParam, + kTargetTagSuperType, + kTargetTagTypeParamBound, + kTargetTagEmpty, + kTargetTagFormalParam, + kTargetTagThrows, + kTargetTagLocalVar, + kTargetTagCatch, + kTargetTagOffset, + kTargetTagTypeArg, +}; + +enum TargetInfoItemType : uint8 { + kTargetTypeParamClass = 0x00, + kTargetTypeParamMethod = 0x01, + kTargetTypeHierarchy = 0x10, + kTargetTypeBoundClass = 0x11, + kTargetTypeBoundMethod = 0x12, + kTargetTypeFieldDecl = 0x13, + kTargetTypeReturn = 0x14, + kTargetTypeReceiver = 0x15, + kTargetTypeFormal = 0x16, + kTargetTypeThrows = 0x17, + kTargetTypeLocalVar = 0x40, + kTargetTypeResourceVar = 0x41, + kTargetTypeExpectionParam = 0x42, + kTargetTypeInstanceof = 0x43, + kTargetTypeNew = 0x44, + kTargetTypeMethodRefNew = 0x45, + kTargetTypeMethodRefIdentifier = 0x46, + kTargetTypeCast = 0x47, + kTargetTypeConstructorInvoke = 0x48, + kTargetTypeMethodInvoke = 0x49, + kTargetTypeConstructorNew = 0x4A, + kTargetTypeConstructorIdentifier = 0x4B, +}; + +class TargetInfoItem : public JBCAttrItem { + public: + explicit TargetInfoItem(TargetInfoItemTag tagIn); + virtual ~TargetInfoItem() = default; + static std::map InitTypeTagMap(); + static TargetInfoItemTag TargetType2Tag(TargetInfoItemType type); + static TargetInfoItem *NewItem(MapleAllocator &allocator, BasicIORead &io, TargetInfoItemType targetType); + + protected: + TargetInfoItemTag tag; + static std::map typeTagMap; +}; + +class TargetTypeParam : public TargetInfoItem { + public: + TargetTypeParam(); + ~TargetTypeParam() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint8 paramIdx; +}; + +class TargetSuperType : public TargetInfoItem { + public: + TargetSuperType(); + ~TargetSuperType() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 index; +}; + +class TargetTypeParamBound : public TargetInfoItem { + public: + TargetTypeParamBound(); + ~TargetTypeParamBound() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint8 paramIdx; + uint8 boundIdx; +}; + +class TargetEmpty : public TargetInfoItem { + public: + TargetEmpty(); + ~TargetEmpty() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; +}; + +class TargetFormalParam : public TargetInfoItem { + public: + TargetFormalParam(); + ~TargetFormalParam() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint8 paramIdx; +}; + +class TargetThrows : public TargetInfoItem { + public: + TargetThrows(); + ~TargetThrows() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 typeIdx; +}; + +class TargetLocalVarItem : public TargetInfoItem { + public: + TargetLocalVarItem(); + ~TargetLocalVarItem() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 startPC; + uint16 length; + uint16 index; +}; + +class TargetLocalVar : public TargetInfoItem { + public: + explicit TargetLocalVar(MapleAllocator &allocator); + ~TargetLocalVar() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 size; + MapleVector table; +}; + +class TargetCatch : public TargetInfoItem { + public: + TargetCatch(); + ~TargetCatch() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 exTableIdx; +}; + +class TargetOffset : public TargetInfoItem { + public: + TargetOffset(); + ~TargetOffset() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 offset; +}; + +class TargetTypeArg : public TargetInfoItem { + public: + TargetTypeArg(); + ~TargetTypeArg() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint16 offset; + uint8 typeArgIdx; +}; + +class TypePathItem : public JBCAttrItem { + public: + TypePathItem(); + ~TypePathItem() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint8 typePathKind; + uint8 typeArgIdx; +}; + +// TypePath +// ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.20.2 +class TypePath : public JBCAttrItem { + public: + explicit TypePath(MapleAllocator &allocator); + ~TypePath() = default; + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + uint8 pathLength; + MapleVector tbPath; +}; + +class TypeAnnotationItem : public JBCAttrItem { + public: + explicit TypeAnnotationItem(MapleAllocator &allocator); + ~TypeAnnotationItem(); + + protected: + bool ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const override; + + private: + TargetInfoItemType targetType; + TargetInfoItem *targetInfo; + TypePath *targetPath; + uint16 typeIdx; + uint16 nElemPairs; + MapleVector elemPairs; +}; +} // namespace attr +} // namespace jbc +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_ATTR_ITEM_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_bb.h b/src/hir2mpl/bytecode_input/class/include/jbc_bb.h new file mode 100644 index 0000000000000000000000000000000000000000..f3a3985cbc2670008ccdd91bf9da91a69c3dc19f --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_bb.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_BB_H +#define HIR2MPL_INCLUDE_JBC_BB_H +#include +#include "feir_bb.h" +#include "jbc_stack_helper.h" + +namespace maple { +class JBCBB : public FEIRBB { + public: + JBCBB(const jbc::JBCConstPool &argConstPool); + JBCBB(uint8 argBBKind, const jbc::JBCConstPool &argConstPool); + ~JBCBB() = default; + bool InitForFuncHeader(); + bool InitForCatch(); + bool UpdateStack(); + bool UpdateStackByPredBB(const JBCBB &bb); + bool UpdateStackByPredBBEnd() const; + bool CheckStack(); + uint32 GetSwapSize() const; + bool GetStackError() const { + return stackError; + } + + const JBCStackHelper &GetMinStackIn() const { + return minStackIn; + } + + const JBCStackHelper &GetMinStackOut() const { + return minStackOut; + } + + protected: + void Dump() const override; + + private: + const jbc::JBCConstPool &constPool; + bool stackError : 1; + bool stackInUpdated : 1; + bool stackOutUpdated : 1; + bool updatePredEnd : 1; + JBCStackHelper minStackIn; + JBCStackHelper minStackOut; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_BB_H diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_class.h b/src/hir2mpl/bytecode_input/class/include/jbc_class.h new file mode 100644 index 0000000000000000000000000000000000000000..39e20721cab501ead4c94a95fe9072a88112108f --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_class.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_CLASS_H +#define HIR2MPL_INCLUDE_JBC_CLASS_H +#include "mempool_allocator.h" +#include "fe_configs.h" +#include "jbc_class_access.h" +#include "jbc_class_header.h" +#include "jbc_class_const_pool.h" +#include "jbc_attr.h" + +namespace maple { +namespace jbc { +class JBCClass; +class JBCClassElem { + public: + JBCClassElem(MapleAllocator &allocator, const JBCClass &argKlass); + virtual ~JBCClassElem() = default; + bool ParseFile(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool); + const JBCConstPool &GetConstPool() const; + std::string GetFullName() const; + LLT_MOCK_TARGET uint16 GetAccessFlag() const { + return accessFlag; + } + + LLT_MOCK_TARGET bool IsStatic() const { + return (accessFlag & kAccFieldStatic) != 0; + } + + LLT_MOCK_TARGET std::string GetClassName() const; + + LLT_MOCK_TARGET std::string GetName(const JBCConstPool &constPool) const { + return constPool.GetStringByConstUTF8(nameIdx); + } + + LLT_MOCK_TARGET std::string GetName() const { + return GetConstPool().GetStringByConstUTF8(nameIdx); + } + + LLT_MOCK_TARGET std::string GetDescription(const JBCConstPool &constPool) const { + return constPool.GetStringByConstUTF8(descIdx); + } + + LLT_MOCK_TARGET std::string GetDescription() const { + return GetConstPool().GetStringByConstUTF8(descIdx); + } + + uint16 GetNameIdx() const { + return nameIdx; + } + + uint16 GetDescriptionIdx() const { + return descIdx; + } + + const JBCClass &GetClass() const { + return klass; + } + + const JBCAttr *GetAttr(JBCAttrKind kind) const { + return attrMap.GetAttr(kind); + } + + const std::list GetAttrs(JBCAttrKind kind) const { + return attrMap.GetAttrs(kind); + } + + SimpleXMLElem *GenXmlElem(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) { + return GenXmlElemImpl(allocator, constPool, idx); + } + + protected: + virtual SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) = 0; + + const JBCClass &klass; + uint16 accessFlag; + uint16 nameIdx; + uint16 descIdx; + uint16 nAttr; + MapleVector attrs; + JBCAttrMap attrMap; +}; + +class JBCClassField : public JBCClassElem { + public: + JBCClassField(MapleAllocator &allocator, const JBCClass &argKlass); + ~JBCClassField() = default; + + protected: + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) override; +}; + +class JBCClassMethod : public JBCClassElem { + public: + JBCClassMethod(MapleAllocator &allocator, const JBCClass &argKlass); + ~JBCClassMethod() = default; + bool PreProcess(); + const JBCAttrCode *GetCode() const; + bool IsVirtual() const; + bool IsNative() const; + bool HasCode() const; + + protected: + SimpleXMLElem *GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) override; +}; + +class JBCClass { + public: + JBCClass(MapleAllocator &allocatorIn); + LLT_MOCK_TARGET ~JBCClass() = default; + + bool ParseFile(BasicIORead &io); + bool PreProcess(); + GStrIdx GetClassNameIdxOrin() const; + GStrIdx GetClassNameIdxMpl() const; + LLT_MOCK_TARGET std::string GetClassNameOrin() const; + LLT_MOCK_TARGET std::string GetClassNameMpl() const; + LLT_MOCK_TARGET std::string GetSourceFileName() const; + LLT_MOCK_TARGET std::string GetSuperClassName() const; + LLT_MOCK_TARGET std::vector GetInterfaceNames() const; + static JBCClass *InClass(MapleAllocator &allocator, BasicIORead &io); + + uint16 GetAccessFlag() const { + return header.accessFlag; + } + + const JBCConstPool &GetConstPool() const { + return constPool; + } + + uint16 GetConstPoolCount() const { + return header.constPoolCount; + } + + uint16 GetFieldCount() const { + return header.fieldsCount; + } + + uint16 GetMethodCount() const { + return header.methodsCount; + } + + uint16 GetAttrCount() const { + return header.attrsCount; + } + + bool IsInterface() const { + return (header.accessFlag & JBCClassAccessFlag::kAccClassInterface) != 0; + } + + const MapleVector &GetFields() const { + return tbFields; + } + + const MapleVector &GetMethods() const { + return tbMethods; + } + + void SetFilePathName(const std::string &name) { + filePathName = name; + } + + const std::string GetFilePathName() const { + return filePathName.length() == 0 ? "" : std::string(filePathName.c_str()); + } + + const std::string GetFileName() const { + return fileName.length() == 0 ? "" : std::string(fileName.c_str()); + } + + void SetSrcFileInfoIdx(uint32 idx) { + srcFileInfoIdx = idx; + } + + uint32 GetSrcFileInfoIdx() const { + return srcFileInfoIdx; + } + + const JBCAttr *GetAttr(JBCAttrKind kind) const { + return attrMap.GetAttr(kind); + } + + std::list GetAttrs(JBCAttrKind kind) const { + return attrMap.GetAttrs(kind); + } + + LLT_PRIVATE: + void InitHeader(); + bool ParseFileForConstPool(BasicIORead &io); + bool ParseFileForFields(BasicIORead &io); + bool ParseFileForMethods(BasicIORead &io); + bool ParseFileForAttrs(BasicIORead &io); + + struct { + uint32 magic; + uint16 minorVersion; + uint16 majorVersion; + uint16 constPoolCount; + uint16 accessFlag; + uint16 thisClass; + uint16 superClass; + uint16 interfacesCount; + uint16 fieldsCount; + uint16 methodsCount; + uint16 attrsCount; + } header; + MapleAllocator &allocator; + JBCConstPool constPool; + MapleVector tbInterfaces; + MapleVector tbFields; + MapleVector tbMethods; + MapleVector tbAttrs; + JBCAttrMap attrMap; + MapleString filePathName; + MapleString fileName; + uint32 srcFileInfoIdx = 0; +}; +} // namespace jbc +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_CLASS_H diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_class2fe_helper.h b/src/hir2mpl/bytecode_input/class/include/jbc_class2fe_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..eb73f924090a3193cf8c741d9612a1f690d99f9c --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_class2fe_helper.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC2FE_INPUT_HELPER_STRUCT_H +#define HIR2MPL_INCLUDE_JBC2FE_INPUT_HELPER_STRUCT_H +#include "fe_configs.h" +#include "jbc_class.h" +#include "jbc_input.h" +#include "fe_input_helper.h" + +namespace maple { +class JBCClass2FEHelper : public FEInputStructHelper { + public: + JBCClass2FEHelper(MapleAllocator &allocator, const jbc::JBCClass &klassIn); + ~JBCClass2FEHelper() = default; + const jbc::JBCConstPool &GetConstPool() const { + return klass.GetConstPool(); + } + + LLT_MOCK_TARGET bool IsStaticFieldProguard() const { + return isStaticFieldProguard; + } + + protected: + std::string GetStructNameOrinImpl() const override; + std::string GetStructNameMplImpl() const override; + std::list GetSuperClassNamesImpl() const override; + std::vector GetInterfaceNamesImpl() const override; + std::string GetSourceFileNameImpl() const override; + MIRStructType *CreateMIRStructTypeImpl(bool &error) const override; + TypeAttrs GetStructAttributeFromInputImpl() const override; + uint64 GetRawAccessFlagsImpl() const override; + GStrIdx GetIRSrcFileSigIdxImpl() const override; + bool IsMultiDefImpl() const override; + void InitFieldHelpersImpl() override; + void InitMethodHelpersImpl() override; + std::string GetSrcFileNameImpl() const override; + + private: + const jbc::JBCClass &klass; + bool isStaticFieldProguard; +}; + +class JBCClassField2FEHelper : public FEInputFieldHelper { + public: + JBCClassField2FEHelper(MapleAllocator &allocator, const jbc::JBCClassField &fieldIn) + : FEInputFieldHelper(allocator), + field(fieldIn) {} + ~JBCClassField2FEHelper() = default; + static FieldAttrs AccessFlag2Attribute(uint16 accessFlag); + + protected: + bool ProcessDeclImpl(MapleAllocator &allocator) override; + bool ProcessDeclWithContainerImpl(MapleAllocator &allocator) override; + + private: + const jbc::JBCClassField &field; +}; + +class JBCClassMethod2FEHelper : public FEInputMethodHelper { + public: + JBCClassMethod2FEHelper(MapleAllocator &allocator, const jbc::JBCClassMethod &methodIn); + ~JBCClassMethod2FEHelper() = default; + const jbc::JBCClassMethod &GetMethod() const { + return method; + } + + protected: + bool ProcessDeclImpl(MapleAllocator &allocator) override; + void SolveReturnAndArgTypesImpl(MapleAllocator &allocator) override; + std::string GetMethodNameImpl(bool inMpl, bool full) const override; + FuncAttrs GetAttrsImpl() const override; + bool IsStaticImpl() const override; + bool IsVargImpl() const override; + bool HasThisImpl() const override; + MIRType *GetTypeForThisImpl() const override; + bool IsVirtualImpl() const override; + bool IsNativeImpl() const override; + bool HasCodeImpl() const override; + + private: + bool IsClinit() const; + bool IsInit() const; + + const jbc::JBCClassMethod &method; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC2FE_INPUT_HELPER_STRUCT_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_class_access.h b/src/hir2mpl/bytecode_input/class/include/jbc_class_access.h new file mode 100644 index 0000000000000000000000000000000000000000..7868663856560b99b799a43ffd2446c0ff11df28 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_class_access.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_CLASS_ACCESS_H +#define HIR2MPL_INCLUDE_JBC_CLASS_ACCESS_H + +namespace maple { +namespace jbc { +enum JBCClassAccessFlag { + kAccClassPublic = 0x0001, + kAccClassFinal = 0x0010, + kAccClassSuper = 0x0020, + kAccClassInterface = 0x0200, + kAccClassAbstract = 0x0400, + kAccClassSynthetic = 0x1000, + kAccClassAnnotation = 0x2000, + kAccClassEnum = 0x4000, +}; + +enum JBCClassFieldAccessFlag { + kAccFieldPublic = 0x0001, + kAccFieldPrivate = 0x0002, + kAccFieldProtected = 0x0004, + kAccFieldStatic = 0x0008, + kAccFieldFinal = 0x0010, + kAccFieldVolatile = 0x0040, + kAccFieldTransient = 0x0080, + kAccFieldSynthetic = 0x1000, + kAccFieldEnum = 0x4000, +}; + +enum JBCClassMethodAccessFlag { + kAccMethodPublic = 0x0001, + kAccMethodPrivate = 0x0002, + kAccMethodProtected = 0x0004, + kAccMethodStatic = 0x0008, + kAccMethodFinal = 0x0010, + kAccMethodSynchronized = 0x0020, + kAccMethodBridge = 0x0040, + kAccMethodVarargs = 0x0080, + kAccMethodNative = 0x0100, + kAccMethodAbstract = 0x0400, + kAccMethodStrict = 0x0800, + kAccMethodSynthetic = 0x1000, +}; + +enum JBCAccessFlag { + kAccPublic = 0x0001, + kAccPrivate = 0x0002, + kAccProtected = 0x0004, + kAccStatic = 0x0008, + kAccFinal = 0x0010, + kAccSuperOrSynchronized = 0x0020, + kAccBridgeOrVolatile = 0x0040, + kAccVarargsOrTransient = 0x0080, + kAccNative = 0x0100, + kAccInterface = 0x0200, + kAccAbstract = 0x0400, + kAccStrict = 0x0800, + kAccSynthetic = 0x1000, + kAccAnnotation = 0x2000, + kAccEnum = 0x4000, +}; +} // namespace jbc +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_CLASS_ACCESS_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_class_builder.h b/src/hir2mpl/bytecode_input/class/include/jbc_class_builder.h new file mode 100644 index 0000000000000000000000000000000000000000..99760fc2965b16a31a7142f21e63ca409e2f8287 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_class_builder.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_CLASS_BUILDER_H +#define HIR2MPL_INCLUDE_JBC_CLASS_BUILDER_H +#include "jbc_class.h" + +namespace maple { +namespace jbc { +class JBCClassBuilder { + public: + JBCClassBuilder() = default; + ~JBCClassBuilder() = default; + + public: +}; +} // namespace jbc +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_CLASS_BUILDER_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_class_const.def b/src/hir2mpl/bytecode_input/class/include/jbc_class_const.def new file mode 100644 index 0000000000000000000000000000000000000000..49ef783b5ef68f320d45bf65488ca09cf4864f13 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_class_const.def @@ -0,0 +1,29 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +// JBC_CONST(tag, tagName, className) +JBC_CONST(kConstUTF8, "ConstUTF8", JBCConstUTF8) +JBC_CONST(kConstInteger, "ConstInteger", JBCConst4Byte) +JBC_CONST(kConstFloat, "ConstFloat", JBCConst4Byte) +JBC_CONST(kConstLong, "ConstLong", JBCConst8Byte) +JBC_CONST(kConstDouble, "ConstDouble", JBCConst8Byte) +JBC_CONST(kConstClass, "ConstClass", JBCConstClass) +JBC_CONST(kConstString, "ConstString", JBCConstString) +JBC_CONST(kConstFieldRef, "ConstFieldRef", JBCConstRef) +JBC_CONST(kConstMethodRef, "ConstMethodRef", JBCConstRef) +JBC_CONST(kConstInterfaceMethodRef, "ConstInterfaceMethodRef", JBCConstRef) +JBC_CONST(kConstNameAndType, "ConstNameAndType", JBCConstNameAndType) +JBC_CONST(kConstMethodHandleInfo, "ConstMethodHandleInfo", JBCConstMethodHandleInfo) +JBC_CONST(kConstMethodType, "ConstMethodType", JBCConstMethodType) +JBC_CONST(kConstInvokeDynamic, "ConstInvokeDynamic", JBCConstInvokeDynamic) \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_class_const.h b/src/hir2mpl/bytecode_input/class/include/jbc_class_const.h new file mode 100644 index 0000000000000000000000000000000000000000..e65d6af34dd530c0f78d7dffac85ec82046793b1 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_class_const.h @@ -0,0 +1,425 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_CLASS_CONST_H +#define HIR2MPL_INCLUDE_JBC_CLASS_CONST_H +#include +#include +#include "mempool_allocator.h" +#include "maple_string.h" +#include "global_tables.h" +#include "types_def.h" +#include "simple_xml.h" +#include "basic_io.h" +#include "fe_struct_elem_info.h" +#include "feir_type.h" + +namespace maple { +namespace jbc { +// Const Kind +enum JBCConstTag : uint8 { + kConstUnknown = 0, + kConstUTF8 = 1, + kConstInteger = 3, + kConstFloat = 4, + kConstLong = 5, + kConstDouble = 6, + kConstClass = 7, + kConstString = 8, + kConstFieldRef = 9, + kConstMethodRef = 10, + kConstInterfaceMethodRef = 11, + kConstNameAndType = 12, + kConstMethodHandleInfo = 15, + kConstMethodType = 16, + kConstInvokeDynamic = 18, +}; + +enum JavaRefKind : uint8 { + kRefGetField = 1, + kRefGetStatic = 2, + kRefPutField = 3, + kRefPutStatic = 4, + kRefInvokeVirtual = 5, + kRefInvokeStatic = 6, + kRefInvokeSpecial = 7, + kRefNewInvokeSpecial = 8, + kRefInvokeInterface = 9, +}; + +class JBCConstTagName { + public: + JBCConstTagName() = default; + ~JBCConstTagName() = default; + static std::map InitTagNameMap(); + static std::string GetTagName(JBCConstTag tag); + + private: + static std::map tagNameMap; +}; + +class JBCConstPool; +class JBCConst { + public: + JBCConst(MapleAllocator &allocIn, JBCConstTag t) : alloc(allocIn), tag(t) {} + virtual ~JBCConst() = default; + static JBCConst *InConst(MapleAllocator &alloc, BasicIORead &io); + static std::string InternalNameToFullName(const std::string &name); + static std::string FullNameToInternalName(const std::string &name); + JBCConstTag GetTag() const { + return tag; + } + + bool IsWide() const { + return (tag == kConstLong || tag == kConstDouble); + } + + bool IsValue() const { + return (tag == kConstInteger || tag == kConstLong || tag == kConstFloat || tag == kConstDouble); + } + + bool IsValue4Byte() const { + return (tag == kConstInteger || tag == kConstFloat); + } + + bool IsValue8Byte() const { + return (tag == kConstLong || tag == kConstDouble); + } + + bool ParseFile(BasicIORead &io) { + return ParseFileImpl(io); + } + + bool PreProcess(const JBCConstPool &constPool) { + return PreProcessImpl(constPool); + } + + SimpleXMLElem *GenXMLElem(MapleAllocator &allocIn, uint32 id) { + return GenXMLElemImpl(allocIn, id); + } + + protected: + virtual bool ParseFileImpl(BasicIORead &io) = 0; + virtual bool PreProcessImpl(const JBCConstPool &constPool) = 0; + virtual SimpleXMLElem *GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const; + const std::string MapleStringToStd(const MapleString &mapleStr) const { + return mapleStr.length() == 0 ? "" : std::string(mapleStr.c_str()); + } + + MapleAllocator &alloc; + JBCConstTag tag; +}; + +using JBCConstPoolIdx = uint16; + +class JBCConstUTF8 : public JBCConst { + public: + JBCConstUTF8(MapleAllocator &alloc, JBCConstTag t); + JBCConstUTF8(MapleAllocator &alloc, JBCConstTag t, const std::string &argStr); + ~JBCConstUTF8() = default; + + const std::string GetString() const { + return MapleStringToStd(str); + } + + GStrIdx GetStrIdx() const { + return strIdx; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const override; + + private: + uint16 length; + GStrIdx strIdx; + MapleString str; +}; + +class JBCConst4Byte : public JBCConst { + public: + JBCConst4Byte(MapleAllocator &alloc, JBCConstTag t); + JBCConst4Byte(MapleAllocator &alloc, JBCConstTag t, int32 arg); + JBCConst4Byte(MapleAllocator &alloc, JBCConstTag t, float arg); + ~JBCConst4Byte() = default; + int32 GetInt32() const { + return value.ivalue; + } + + float GetFloat() const { + return value.fvalue; + } + + uint32 GetRaw() const { + return value.raw; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const override; + + private: + union { + int32 ivalue; + float fvalue; + uint32 raw; + } value; +}; + +class JBCConst8Byte : public JBCConst { + public: + JBCConst8Byte(MapleAllocator &alloc, JBCConstTag t); + JBCConst8Byte(MapleAllocator &alloc, JBCConstTag t, int64 arg); + JBCConst8Byte(MapleAllocator &alloc, JBCConstTag t, double arg); + ~JBCConst8Byte() = default; + + int64 GetInt64() const { + return value.lvalue; + } + + double GetDouble() const { + return value.dvalue; + } + + uint64 GetRaw() const { + return value.raw; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const override; + + private: + union { + int64 lvalue; + double dvalue; + uint64 raw; + } value; +}; + +class JBCConstClass : public JBCConst { + public: + JBCConstClass(MapleAllocator &alloc, JBCConstTag t); + JBCConstClass(MapleAllocator &alloc, JBCConstTag t, JBCConstPoolIdx argNameIdx); + ~JBCConstClass(); + + GStrIdx GetClassNameIdxOrin() const { + return strIdxOrin; + } + + GStrIdx GetClassNameIdxMpl() const { + return strIdxMpl; + } + + const std::string GetClassNameOrin() const { + return MapleStringToStd(nameOrin); + } + + const std::string GetClassNameMpl() const { + return MapleStringToStd(nameMpl); + } + + const FEIRType *GetFEIRType() const { + return feType; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const override; + + private: + struct { + JBCConstPoolIdx nameIdx; + } rawData; + const JBCConstUTF8 *constUTF8; + GStrIdx strIdxOrin; + GStrIdx strIdxMpl; + MapleString nameOrin; + MapleString nameMpl; + FEIRType *feType = nullptr; +}; + +class JBCConstString : public JBCConst { + public: + JBCConstString(MapleAllocator &alloc, JBCConstTag t); + JBCConstString(MapleAllocator &alloc, JBCConstTag t, JBCConstPoolIdx argStringIdx); + ~JBCConstString() = default; + void SetValue(const GStrIdx &argStrIdx) { + strIdx = argStrIdx; + str = GlobalTables::GetStrTable().GetStringFromStrIdx(strIdx); + } + + GStrIdx GetStrIdx() const { + return strIdx; + } + + const std::string GetString() const { + return MapleStringToStd(str); + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const override; + + private: + struct { + JBCConstPoolIdx stringIdx; + } rawData; + GStrIdx strIdx; + MapleString str; +}; + +class JBCConstNameAndType : public JBCConst { + public: + JBCConstNameAndType(MapleAllocator &alloc, JBCConstTag t); + JBCConstNameAndType(MapleAllocator &alloc, JBCConstTag t, JBCConstPoolIdx argNameIdx, JBCConstPoolIdx argDescIdx); + ~JBCConstNameAndType(); + + const std::string GetName() const { + CHECK_FATAL(constName != nullptr, "invalid const index"); + return constName->GetString(); + } + + const std::string GetDesc() const { + CHECK_FATAL(constDesc != nullptr, "invalid const index"); + return constDesc->GetString(); + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const override; + + private: + struct { + JBCConstPoolIdx nameIdx; + JBCConstPoolIdx descIdx; + } rawData; + const JBCConstUTF8 *constName; + const JBCConstUTF8 *constDesc; +}; + +class JBCConstRef : public JBCConst { + public: + JBCConstRef(MapleAllocator &alloc, JBCConstTag t); + JBCConstRef(MapleAllocator &alloc, JBCConstTag t, JBCConstPoolIdx argClassIdx, + JBCConstPoolIdx argClassNameAndTypeIdx); + ~JBCConstRef(); + bool PrepareFEStructElemInfo(); + const std::string GetName() const; + const std::string GetDesc() const; + + const JBCConstClass *GetConstClass() const { + return constClass; + } + + FEStructElemInfo *GetFEStructElemInfo() const { + CHECK_NULL_FATAL(feStructElemInfo); + return feStructElemInfo; + } + + const FEIRType *GetOwnerFEIRType() const { + CHECK_NULL_FATAL(constClass); + return constClass->GetFEIRType(); + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const override; + + private: + struct { + JBCConstPoolIdx classIdx; + JBCConstPoolIdx nameAndTypeIdx; + } rawData; + const JBCConstClass *constClass; + const JBCConstNameAndType *constNameAndType; + FEStructElemInfo *feStructElemInfo; +}; + +class JBCConstMethodHandleInfo : public JBCConst { + public: + JBCConstMethodHandleInfo(MapleAllocator &alloc, JBCConstTag t); + ~JBCConstMethodHandleInfo(); + + protected: + bool ParseFileImpl(BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const override; + + private: + struct { + JBCConstPoolIdx refKind; + JBCConstPoolIdx refIdx; + } rawData; + const JBCConstRef *constRef; +}; + +class JBCConstMethodType : public JBCConst { + public: + JBCConstMethodType(MapleAllocator &alloc, JBCConstTag t); + ~JBCConstMethodType(); + + protected: + bool ParseFileImpl(BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const override; + + private: + struct { + JBCConstPoolIdx descIdx; + } rawData; + const JBCConstUTF8 *constDesc; +}; + +class JBCConstInvokeDynamic : public JBCConst { + public: + JBCConstInvokeDynamic(MapleAllocator &alloc, JBCConstTag t); + ~JBCConstInvokeDynamic(); + bool PrepareFEStructElemInfo(const std::string &ownerClassName); + JBCConstPoolIdx GetBSMAttrIdx() const { + return rawData.bsmAttrIdx; + } + + const JBCConstNameAndType *GetConstNameAndType() const { + return constNameAndType; + } + + FEStructElemInfo *GetFEStructElemInfo() const { + CHECK_NULL_FATAL(feStructElemInfo); + return feStructElemInfo; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + bool PreProcessImpl(const JBCConstPool &constPool) override; + SimpleXMLElem *GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const override; + + private: + struct { + JBCConstPoolIdx bsmAttrIdx; + JBCConstPoolIdx nameAndTypeIdx; + } rawData; + const JBCConstNameAndType *constNameAndType; + FEStructElemInfo *feStructElemInfo; +}; +} // namespace jbc +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_CLASS_CONST_H diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_class_const_pool.h b/src/hir2mpl/bytecode_input/class/include/jbc_class_const_pool.h new file mode 100644 index 0000000000000000000000000000000000000000..0acdb08a6e2c2b8292631939b4f0204206626b66 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_class_const_pool.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_CLASS_CONST_POOL_H +#define HIR2MPL_INCLUDE_JBC_CLASS_CONST_POOL_H +#include "jbc_class_const.h" + +namespace maple { +namespace jbc { +class JBCConstPool { + public: + JBCConstPool(MapleAllocator &alloc); + ~JBCConstPool() = default; + uint16 InsertConst(JBCConst &objConst); + void InsertConstDummyForWide(); + + /* + * GetConstByIdx + * GetConstXXXByIdx + * If safe is true, the return value must be not nullptr or fatal and exit. + * If safe is false, the return value may be nullptr with error printed. + */ + const JBCConst *GetConstByIdx(uint16 idx, bool safed = false) const; + const JBCConst *GetConstByIdxWithTag(uint16 idx, JBCConstTag tag, bool safed = false) const; + const JBCConst *GetConstValueByIdx(uint16 idx, bool safed = false) const; + const JBCConst *GetConstValue4ByteByIdx(uint16 idx, bool safed = false) const; + const JBCConst *GetConstValue8ByteByIdx(uint16 idx, bool safed = false) const; + std::string GetNameByClassInfoIdx(uint16 idx, bool safed = false) const; + bool PreProcess(uint16 argMajorVersion); + bool PrepareFEStructElemInfo(const std::string &ownerClassName); + JBCConstUTF8 *NewConstUTF8(uint16 &idx, const std::string &str); + JBCConst4Byte *NewConst4Byte(uint16 &idx, int32 value); + JBCConst4Byte *NewConst4Byte(uint16 &idx, float value); + JBCConst8Byte *NewConst8Byte(uint16 &idx, int64 value); + JBCConst8Byte *NewConst8Byte(uint16 &idx, double value); + JBCConstClass *NewConstClass(uint16 &idx, const std::string &className); + JBCConstString *NewConstString(uint16 &idx, const std::string &str); + JBCConstRef *NewConstRef(uint16 &idx, JBCConstTag tag, const std::string &className, const std::string &name, + const std::string &desc); + JBCConstNameAndType *NewConstNameAndType(uint16 &idx, const std::string &name, const std::string &desc); + + uint16 GetMajorVersion() const { + return majorVersion; + } + + std::string GetStringByConstUTF8(uint16 idx, bool safed = false) const { + const JBCConst *constUTF8 = GetConstByIdxWithTag(idx, JBCConstTag::kConstUTF8, safed); + return constUTF8 == nullptr ? "" : static_cast(constUTF8)->GetString(); + } + + private: + MapleAllocator &allocator; + MapleVector pool; + uint16 majorVersion; +}; +} // namespace jbc +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_CLASS_CONST_POOL_H diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_class_header.h b/src/hir2mpl/bytecode_input/class/include/jbc_class_header.h new file mode 100644 index 0000000000000000000000000000000000000000..c2605537ca5c43af54fc665c4714d87cfee631fd --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_class_header.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_CLASS_HEADER_H +#define HIR2MPL_INCLUDE_JBC_CLASS_HEADER_H +#include "types_def.h" +#include "basic_io.h" + +namespace maple { +namespace jbc { +class JBCClassHeader { + public: + JBCClassHeader(); + ~JBCClassHeader() = default; + bool ParseClassFile(BasicIORead &io) const; + + private: + uint32 magic; + uint16 minorVersion; + uint16 majorVersion; + uint16 constPoolCount; + uint16 accessFlag; + uint16 thisClass; + uint16 superClass; + uint16 interfacesCount; + uint16 fieldsCount; + uint16 methodsCount; + uint16 attrsCount; +}; +} // namespace jbc +} // namespace maple +#endif \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_compiler_component.h b/src/hir2mpl/bytecode_input/class/include/jbc_compiler_component.h new file mode 100644 index 0000000000000000000000000000000000000000..b4ef3d71d0ea12281e1e39583813070382f1d71a --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_compiler_component.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_COMPILER_COMPONENT_H +#define HIR2MPL_INCLUDE_JBC_COMPILER_COMPONENT_H +#include "fe_macros.h" +#include "hir2mpl_compiler_component.h" +#include "jbc_input.h" +#include "fe_function_phase_result.h" + +namespace maple { +class JBCCompilerComponent : public HIR2MPLCompilerComponent { + public: + JBCCompilerComponent(MIRModule &module); + ~JBCCompilerComponent(); + + protected: + bool ParseInputImpl() override; + bool LoadOnDemandTypeImpl() override; + void ProcessPragmaImpl() override; + std::unique_ptr CreatFEFunctionImpl(FEInputMethodHelper *methodHelper) override; + std::string GetComponentNameImpl() const override; + bool ParallelableImpl() const override; + void DumpPhaseTimeTotalImpl() const override; + void ReleaseMemPoolImpl() override; + + private: + MemPool *mp; + MapleAllocator allocator; + jbc::JBCInput jbcInput; +}; // class JBCCompilerComponent +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_COMPILER_COMPONENT_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_function.h b/src/hir2mpl/bytecode_input/class/include/jbc_function.h new file mode 100644 index 0000000000000000000000000000000000000000..7feb231ccb87819c727e18f443b2dc9d2f4df778 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_function.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_JBC_FUNCTION_H +#define HIR2MPL_INCLUDE_COMMON_JBC_FUNCTION_H +#include +#include +#include +#include +#include +#include "fe_configs.h" +#include "fe_function.h" +#include "jbc_class.h" +#include "jbc_attr.h" +#include "jbc_stmt.h" +#include "jbc_bb.h" +#include "jbc_class2fe_helper.h" +#include "jbc_stack2fe_helper.h" +#include "jbc_function_context.h" + +namespace maple { +class JBCBBPesudoCatchPred : public FEIRBB { + public: + static const uint8 kBBKindPesudoCatchPred = FEIRBBKind::kBBKindExt + 1; + JBCBBPesudoCatchPred() + : FEIRBB(kBBKindPesudoCatchPred) {} + ~JBCBBPesudoCatchPred() = default; +}; // class JBCBBPesudoCatchPred + +class JBCFunction : public FEFunction { + public: + JBCFunction(const JBCClassMethod2FEHelper &argMethodHelper, MIRFunction &mirFunc, + const std::unique_ptr &argPhaseResultTotal); + ~JBCFunction(); + + LLT_PROTECTED: + // run phase routines + bool GenerateGeneralStmt(const std::string &phaseName) override; + bool LabelLabelIdx(const std::string &phaseName); + bool CheckJVMStack(const std::string &phaseName); + bool GenerateArgVarList(const std::string &phaseName) override; + bool GenerateAliasVars(const std::string &phaseName) override; + bool ProcessFunctionArgs(const std::string &phaseName); + bool EmitLocalVarInfo(const std::string &phaseName); + bool EmitToFEIRStmt(const std::string &phaseName) override; + + // interface implement + void InitImpl() override; + void PreProcessImpl() override; + bool ProcessImpl() override; + void FinishImpl() override; + bool PreProcessTypeNameIdx() override; + void GenerateGeneralStmtFailCallBack() override; + void GenerateGeneralDebugInfo() override; + bool VerifyGeneral() override; + void VerifyGeneralFailCallBack() override; + std::string GetGeneralFuncName() const override; + + bool HasThis() override { + return methodHelper.HasThis(); + } + + bool IsNative() override { + return methodHelper.IsNative(); + } + + void EmitToFEIRStmt(const JBCBB &bb); + + LLT_PRIVATE: + const JBCClassMethod2FEHelper &methodHelper; + const jbc::JBCClassMethod &method; + JBCStack2FEHelper stack2feHelper; + JBCFunctionContext context; + bool error = false; + FEIRBB *pesudoBBCatchPred = nullptr; + + bool PreBuildJsrInfo(const jbc::JBCAttrCode &code); + bool BuildStmtFromInstruction(const jbc::JBCAttrCode &code); + FEIRStmt *BuildStmtFromInstructionForBranch(const jbc::JBCOp &op); + FEIRStmt *BuildStmtFromInstructionForGoto(const jbc::JBCOp &op); + FEIRStmt *BuildStmtFromInstructionForSwitch(const jbc::JBCOp &op); + FEIRStmt *BuildStmtFromInstructionForJsr(const jbc::JBCOp &op); + FEIRStmt *BuildStmtFromInstructionForRet(const jbc::JBCOp &op); + void BuildStmtForCatch(const jbc::JBCAttrCode &code); + void BuildStmtForTry(const jbc::JBCAttrCode &code); + void BuildTryInfo(const std::map, std::vector> &rawInfo, + std::map &outMapStartEnd, + std::map> &outMapStartCatch); + void BuildTryInfoCatch(const std::map, std::vector> &rawInfo, + const std::deque> &blockQueue, + uint32 startPos, + std::map> &outMapStartCatch); + void BuildStmtForLOC(const jbc::JBCAttrCode &code); + void BuildStmtForInstComment(const jbc::JBCAttrCode &code); + FEIRStmt *BuildAndUpdateLabel(uint32 dstPC, const std::unique_ptr &srcStmt); + void ArrangeStmts(); + bool CheckJVMStackResult(); + void InitStack2FEHelper(); + uint32 CalculateMaxSwapSize() const; + bool NeedConvertToInt32(const std::unique_ptr &var); +}; // class JBCFunction +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_JBC_FUNCTION_H diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_function_context.h b/src/hir2mpl/bytecode_input/class/include/jbc_function_context.h new file mode 100644 index 0000000000000000000000000000000000000000..01ec6454e850c09cc861fb58cdc9cc35041a9d09 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_function_context.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_INPUT_JBC_FUNCTION_CONTEXT_H +#define HIR2MPL_INCLUDE_JBC_INPUT_JBC_FUNCTION_CONTEXT_H +#include "mir_type.h" +#include "jbc_class_const_pool.h" +#include "jbc_attr.h" +#include "jbc_stack2fe_helper.h" +#include "jbc_stmt.h" + +namespace maple { +class JBCFunctionContext { + public: + JBCFunctionContext(const jbc::JBCConstPool &argConstPool, + JBCStack2FEHelper &argStack2feHelper, + const jbc::JBCAttrCode *argCode) + : constPool(argConstPool), + stack2feHelper(argStack2feHelper), + code(argCode) {} + + ~JBCFunctionContext() { + code = nullptr; + } + + int32 RegisterJsrSlotRetAddr(uint16 slotIdx, uint32 nextPC); + void ArrangeStmts(); + const FEIRType *GetSlotType(uint16 slotIdx, uint32 pc) const; + const FEIRType *GetSlotType(uint16 slotIdx) const; + + JBCStack2FEHelper &GetStack2FEHelper() { + return stack2feHelper; + } + + const jbc::JBCConstPool &GetConstPool() const { + return constPool; + } + + const jbc::JBCAttrCode *GetCode() const { + return code; + } + + const std::map &GetMapPCStmtInst() const { + return mapPCStmtInst; + } + + const std::map &GetMapPCTryStmt() const { + return mapPCTryStmt; + } + + const std::map &GetMapPCEndTryStmt() const { + return mapPCEndTryStmt; + } + + const std::map &GetMapPCCatchStmt() const { + return mapPCCatchStmt; + } + + const std::map &GetMapPCLabelStmt() const { + return mapPCLabelStmt; + } + + const std::map &GetMapPCStmtLOC() const { + return mapPCStmtLOC; + } + + const std::map &GetMapPCCommentStmt() const { + return mapPCCommentStmt; + } + + const std::map> &GetMapJsrSlotRetAddr() const { + return mapJsrSlotRetAddr; + } + + void UpdateMapPCStmtInst(uint32 pc, FEIRStmt *stmt) { + mapPCStmtInst[pc] = stmt; + } + + void UpdateMapPCTryStmt(uint32 pc, JBCStmtPesudoTry *stmt) { + mapPCTryStmt[pc] = stmt; + } + + void UpdateMapPCEndTryStmt(uint32 pc, JBCStmtPesudoEndTry *stmt) { + mapPCEndTryStmt[pc] = stmt; + } + + void UpdateMapPCCatchStmt(uint32 pc, JBCStmtPesudoCatch *stmt) { + mapPCCatchStmt[pc] = stmt; + } + + void UpdateMapPCLabelStmt(uint32 pc, JBCStmtPesudoLabel *stmt) { + mapPCLabelStmt[pc] = stmt; + } + + void UpdateMapPCStmtLOC(uint32 pc, JBCStmtPesudoLOC *stmt) { + mapPCStmtLOC[pc] = stmt; + } + + void UpdateMapPCCommentStmt(uint32 pc, JBCStmtPesudoComment *stmt) { + mapPCCommentStmt[pc] = stmt; + } + + const jbc::JBCAttrLocalVariableInfo &GetLocalVarInfo() const { + CHECK_NULL_FATAL(code); + return code->GetLocalVarInfo(); + } + + void SetCurrPC(uint32 pc) { + currPC = pc; + } + + uint32 GetCurrPC() const { + return currPC; + } + + private: + const jbc::JBCConstPool &constPool; + JBCStack2FEHelper &stack2feHelper; + const jbc::JBCAttrCode *code; + std::map mapPCStmtInst; + std::map mapPCTryStmt; // key: tryStartPC, value: stmt + std::map mapPCEndTryStmt; // key: tryEndPC, value: stmt + std::map mapPCCatchStmt; // key: handlePC, value: stmt + std::map mapPCLabelStmt; // key: labelPC, value: stmt + std::map mapPCStmtLOC; // key: locPC, value: stmt + std::map mapPCCommentStmt; // key: commentPC, value: stmt + std::map> mapJsrSlotRetAddr; // key: slotIdx, value: map + uint32 currPC = 0; +}; // class JBCFunctionContext +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_INPUT_JBC_FUNCTION_CONTEXT_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_input.h b/src/hir2mpl/bytecode_input/class/include/jbc_input.h new file mode 100644 index 0000000000000000000000000000000000000000..ce211d00c68451bdf9d2c5338be491c964418f37 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_input.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_INPUT_H +#define HIR2MPL_INCLUDE_JBC_INPUT_H +#include +#include +#include "mempool_allocator.h" +#include "jbc_class.h" + +namespace maple { +namespace jbc { +class JBCInput { + public: + explicit JBCInput(MIRModule &moduleIn); + ~JBCInput(); + void ReleaseMemPool(); + bool ReadClassFile(const std::string &fileName); + bool ReadClassFiles(const std::list &fileNames); + bool ReadJarFile(const std::string &fileName); + bool ReadJarFiles(const std::list &fileNames); + const JBCClass *GetFirstClass(); + const JBCClass *GetNextClass(); + void RegisterSrcFileInfo(JBCClass &klass); + + const MIRModule &GetModule() const { + return module; + } + + protected: + MIRModule &module; + MemPool *mp; + MapleAllocator allocator; + MapleList klassList; + + private: + MapleList::const_iterator itKlass; +}; +} // namespace jbc +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_INPUT_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_opcode.def b/src/hir2mpl/bytecode_input/class/include/jbc_opcode.def new file mode 100644 index 0000000000000000000000000000000000000000..ede7d7eb28cd409b1e2d44dfb52a4fa5e63e2e11 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_opcode.def @@ -0,0 +1,271 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +// JBC_OP(opcode, value, type, name, flags) +JBC_OP(Nop, 0x00, Default, "nop", (kOpFlagFallThru)) +JBC_OP(AConstNull, 0x01, Const, "aconst_null", (kOpFlagFallThru)) +JBC_OP(IConstM1, 0x02, Const, "iconst_m1", (kOpFlagFallThru)) +JBC_OP(IConst0, 0x03, Const, "iconst_0", (kOpFlagFallThru)) +JBC_OP(IConst1, 0x04, Const, "iconst_1", (kOpFlagFallThru)) +JBC_OP(IConst2, 0x05, Const, "iconst_2", (kOpFlagFallThru)) +JBC_OP(IConst3, 0x06, Const, "iconst_3", (kOpFlagFallThru)) +JBC_OP(IConst4, 0x07, Const, "iconst_4", (kOpFlagFallThru)) +JBC_OP(IConst5, 0x08, Const, "iconst_5", (kOpFlagFallThru)) +JBC_OP(LConst0, 0x09, Const, "lconst_0", (kOpFlagFallThru)) +JBC_OP(LConst1, 0x0A, Const, "lconst_1", (kOpFlagFallThru)) +JBC_OP(FConst0, 0x0B, Const, "fconst_0", (kOpFlagFallThru)) +JBC_OP(FConst1, 0x0C, Const, "fconst_1", (kOpFlagFallThru)) +JBC_OP(FConst2, 0x0D, Const, "fconst_2", (kOpFlagFallThru)) +JBC_OP(DConst0, 0x0E, Const, "dconst_0", (kOpFlagFallThru)) +JBC_OP(DConst1, 0x0F, Const, "dconst_1", (kOpFlagFallThru)) +JBC_OP(BiPush, 0x10, Const, "bipush", (kOpFlagFallThru)) +JBC_OP(SiPush, 0x11, Const, "sipush", (kOpFlagFallThru)) +JBC_OP(Ldc, 0x12, Const, "ldc", (kOpFlagFallThru)) +JBC_OP(LdcW, 0x13, Const, "ldc_w", (kOpFlagFallThru)) +JBC_OP(Ldc2W, 0x14, Const, "ldc2_w", (kOpFlagFallThru)) +JBC_OP(ILoad, 0x15, Load, "iload", (kOpFlagFallThru)) +JBC_OP(LLoad, 0x16, Load, "lload", (kOpFlagFallThru)) +JBC_OP(FLoad, 0x17, Load, "fload", (kOpFlagFallThru)) +JBC_OP(DLoad, 0x18, Load, "dload", (kOpFlagFallThru)) +JBC_OP(ALoad, 0x19, Load, "aload", (kOpFlagFallThru)) +JBC_OP(ILoad0, 0x1A, Load, "iload_0", (kOpFlagFallThru)) +JBC_OP(ILoad1, 0x1B, Load, "iload_1", (kOpFlagFallThru)) +JBC_OP(ILoad2, 0x1C, Load, "iload_2", (kOpFlagFallThru)) +JBC_OP(ILoad3, 0x1D, Load, "iload_3", (kOpFlagFallThru)) +JBC_OP(LLoad0, 0x1E, Load, "lload_0", (kOpFlagFallThru)) +JBC_OP(LLoad1, 0x1F, Load, "lload_1", (kOpFlagFallThru)) +JBC_OP(LLoad2, 0x20, Load, "lload_2", (kOpFlagFallThru)) +JBC_OP(LLoad3, 0x21, Load, "lload_3", (kOpFlagFallThru)) +JBC_OP(FLoad0, 0x22, Load, "fload_0", (kOpFlagFallThru)) +JBC_OP(FLoad1, 0x23, Load, "fload_1", (kOpFlagFallThru)) +JBC_OP(FLoad2, 0x24, Load, "fload_2", (kOpFlagFallThru)) +JBC_OP(FLoad3, 0x25, Load, "fload_3", (kOpFlagFallThru)) +JBC_OP(DLoad0, 0x26, Load, "dload_0", (kOpFlagFallThru)) +JBC_OP(DLoad1, 0x27, Load, "dload_1", (kOpFlagFallThru)) +JBC_OP(DLoad2, 0x28, Load, "dload_2", (kOpFlagFallThru)) +JBC_OP(DLoad3, 0x29, Load, "dload_3", (kOpFlagFallThru)) +JBC_OP(ALoad0, 0x2A, Load, "aload_0", (kOpFlagFallThru)) +JBC_OP(ALoad1, 0x2B, Load, "aload_1", (kOpFlagFallThru)) +JBC_OP(ALoad2, 0x2C, Load, "aload_2", (kOpFlagFallThru)) +JBC_OP(ALoad3, 0x2D, Load, "aload_3", (kOpFlagFallThru)) +JBC_OP(IALoad, 0x2E, ArrayLoad, "iaload", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(LALoad, 0x2F, ArrayLoad, "laload", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(FALoad, 0x30, ArrayLoad, "faload", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(DALoad, 0x31, ArrayLoad, "daload", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(AALoad, 0x32, ArrayLoad, "aaload", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(BALoad, 0x33, ArrayLoad, "baload", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(CALoad, 0x34, ArrayLoad, "caload", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(SALoad, 0x35, ArrayLoad, "saload", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(IStore, 0x36, Store, "istore", (kOpFlagFallThru)) +JBC_OP(LStore, 0x37, Store, "lstore", (kOpFlagFallThru)) +JBC_OP(FStore, 0x38, Store, "fstore", (kOpFlagFallThru)) +JBC_OP(DStore, 0x39, Store, "dstore", (kOpFlagFallThru)) +JBC_OP(AStore, 0x3A, Store, "astore", (kOpFlagFallThru)) +JBC_OP(IStore0, 0x3B, Store, "istore_0", (kOpFlagFallThru)) +JBC_OP(IStore1, 0x3C, Store, "istore_1", (kOpFlagFallThru)) +JBC_OP(IStore2, 0x3D, Store, "istore_2", (kOpFlagFallThru)) +JBC_OP(IStore3, 0x3E, Store, "istore_3", (kOpFlagFallThru)) +JBC_OP(LStore0, 0x3F, Store, "lstore_0", (kOpFlagFallThru)) +JBC_OP(LStore1, 0x40, Store, "lstore_1", (kOpFlagFallThru)) +JBC_OP(LStore2, 0x41, Store, "lstore_2", (kOpFlagFallThru)) +JBC_OP(LStore3, 0x42, Store, "lstore_3", (kOpFlagFallThru)) +JBC_OP(FStore0, 0x43, Store, "fstore_0", (kOpFlagFallThru)) +JBC_OP(FStore1, 0x44, Store, "fstore_1", (kOpFlagFallThru)) +JBC_OP(FStore2, 0x45, Store, "fstore_2", (kOpFlagFallThru)) +JBC_OP(FStore3, 0x46, Store, "fstore_3", (kOpFlagFallThru)) +JBC_OP(DStore0, 0x47, Store, "dstore_0", (kOpFlagFallThru)) +JBC_OP(DStore1, 0x48, Store, "dstore_1", (kOpFlagFallThru)) +JBC_OP(DStore2, 0x49, Store, "dstore_2", (kOpFlagFallThru)) +JBC_OP(DStore3, 0x4A, Store, "dstore_3", (kOpFlagFallThru)) +JBC_OP(AStore0, 0x4B, Store, "astore_0", (kOpFlagFallThru)) +JBC_OP(AStore1, 0x4C, Store, "astore_1", (kOpFlagFallThru)) +JBC_OP(AStore2, 0x4D, Store, "astore_2", (kOpFlagFallThru)) +JBC_OP(AStore3, 0x4E, Store, "astore_3", (kOpFlagFallThru)) +JBC_OP(IAStore, 0x4F, ArrayStore, "iastore", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(LAStore, 0x50, ArrayStore, "lastore", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(FAStore, 0x51, ArrayStore, "fastore", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(DAStore, 0x52, ArrayStore, "dastore", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(AAStore, 0x53, ArrayStore, "aastore", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(BAStore, 0x54, ArrayStore, "bastore", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(CAStore, 0x55, ArrayStore, "castore", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(SAStore, 0x56, ArrayStore, "sastore", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(Pop, 0x57, Pop, "pop", (kOpFlagFallThru)) +JBC_OP(Pop2, 0x58, Pop, "pop2", (kOpFlagFallThru)) +JBC_OP(Dup, 0x59, Dup, "dup", (kOpFlagFallThru)) +JBC_OP(DupX1, 0x5A, Dup, "dup_x1", (kOpFlagFallThru)) +JBC_OP(DupX2, 0x5B, Dup, "dup_x2", (kOpFlagFallThru)) +JBC_OP(Dup2, 0x5C, Dup, "dup2", (kOpFlagFallThru)) +JBC_OP(Dup2X1, 0x5D, Dup, "dup2_x1", (kOpFlagFallThru)) +JBC_OP(Dup2X2, 0x5E, Dup, "dup2_x2", (kOpFlagFallThru)) +JBC_OP(Swap, 0x5F, Swap, "swap", (kOpFlagFallThru)) +JBC_OP(IAdd, 0x60, MathBinop, "iadd", (kOpFlagFallThru)) +JBC_OP(LAdd, 0x61, MathBinop, "ladd", (kOpFlagFallThru)) +JBC_OP(FAdd, 0x62, MathBinop, "fadd", (kOpFlagFallThru)) +JBC_OP(DAdd, 0x63, MathBinop, "dadd", (kOpFlagFallThru)) +JBC_OP(ISub, 0x64, MathBinop, "isub", (kOpFlagFallThru)) +JBC_OP(LSub, 0x65, MathBinop, "lsub", (kOpFlagFallThru)) +JBC_OP(FSub, 0x66, MathBinop, "fsub", (kOpFlagFallThru)) +JBC_OP(DSub, 0x67, MathBinop, "dsub", (kOpFlagFallThru)) +JBC_OP(IMul, 0x68, MathBinop, "imul", (kOpFlagFallThru)) +JBC_OP(LMul, 0x69, MathBinop, "lmul", (kOpFlagFallThru)) +JBC_OP(FMul, 0x6A, MathBinop, "fmul", (kOpFlagFallThru)) +JBC_OP(DMul, 0x6B, MathBinop, "dmul", (kOpFlagFallThru)) +JBC_OP(IDiv, 0x6C, MathBinop, "idiv", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(LDiv, 0x6D, MathBinop, "ldiv", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(FDiv, 0x6E, MathBinop, "fdiv", (kOpFlagFallThru)) +JBC_OP(DDiv, 0x6F, MathBinop, "ddiv", (kOpFlagFallThru)) +JBC_OP(IRem, 0x70, MathBinop, "irem", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(LRem, 0x71, MathBinop, "lrem", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(FRem, 0x72, MathBinop, "frem", (kOpFlagFallThru)) +JBC_OP(DRem, 0x73, MathBinop, "drem", (kOpFlagFallThru)) +JBC_OP(INeg, 0x74, MathUnop, "ineg", (kOpFlagFallThru)) +JBC_OP(LNeg, 0x75, MathUnop, "lneg", (kOpFlagFallThru)) +JBC_OP(FNeg, 0x76, MathUnop, "fneg", (kOpFlagFallThru)) +JBC_OP(DNeg, 0x77, MathUnop, "dneg", (kOpFlagFallThru)) +JBC_OP(IShl, 0x78, MathBinop, "ishl", (kOpFlagFallThru)) +JBC_OP(LShl, 0x79, MathBinop, "lshl", (kOpFlagFallThru)) +JBC_OP(IShr, 0x7A, MathBinop, "ishr", (kOpFlagFallThru)) +JBC_OP(LShr, 0x7B, MathBinop, "lshr", (kOpFlagFallThru)) +JBC_OP(IUShr, 0x7C, MathBinop, "iushr", (kOpFlagFallThru)) +JBC_OP(LUShr, 0x7D, MathBinop, "lushr", (kOpFlagFallThru)) +JBC_OP(IAnd, 0x7E, MathBinop, "iand", (kOpFlagFallThru)) +JBC_OP(LAnd, 0x7F, MathBinop, "land", (kOpFlagFallThru)) +JBC_OP(IOr, 0x80, MathBinop, "ior", (kOpFlagFallThru)) +JBC_OP(LOr, 0x81, MathBinop, "lor", (kOpFlagFallThru)) +JBC_OP(IXor, 0x82, MathBinop, "ixor", (kOpFlagFallThru)) +JBC_OP(LXor, 0x83, MathBinop, "lxor", (kOpFlagFallThru)) +JBC_OP(IInc, 0x84, MathInc, "iinc", (kOpFlagFallThru)) +JBC_OP(I2L, 0x85, Convert, "i2l", (kOpFlagFallThru)) +JBC_OP(I2F, 0x86, Convert, "i2f", (kOpFlagFallThru)) +JBC_OP(I2D, 0x87, Convert, "i2d", (kOpFlagFallThru)) +JBC_OP(L2I, 0x88, Convert, "l2i", (kOpFlagFallThru)) +JBC_OP(L2F, 0x89, Convert, "l2f", (kOpFlagFallThru)) +JBC_OP(L2D, 0x8A, Convert, "l2d", (kOpFlagFallThru)) +JBC_OP(F2I, 0x8B, Convert, "f2i", (kOpFlagFallThru)) +JBC_OP(F2L, 0x8C, Convert, "f2l", (kOpFlagFallThru)) +JBC_OP(F2D, 0x8D, Convert, "f2d", (kOpFlagFallThru)) +JBC_OP(D2I, 0x8E, Convert, "d2i", (kOpFlagFallThru)) +JBC_OP(D2L, 0x8F, Convert, "d2l", (kOpFlagFallThru)) +JBC_OP(D2F, 0x90, Convert, "d2f", (kOpFlagFallThru)) +JBC_OP(I2B, 0x91, Convert, "i2b", (kOpFlagFallThru)) +JBC_OP(I2C, 0x92, Convert, "i2c", (kOpFlagFallThru)) +JBC_OP(I2S, 0x93, Convert, "i2s", (kOpFlagFallThru)) +JBC_OP(LCmp, 0x94, Compare, "lcmp", (kOpFlagFallThru)) +JBC_OP(FCmpl, 0x95, Compare, "fcmpl", (kOpFlagFallThru)) +JBC_OP(FCmpg, 0x96, Compare, "fcmpg", (kOpFlagFallThru)) +JBC_OP(DCmpl, 0x97, Compare, "dcmpl", (kOpFlagFallThru)) +JBC_OP(DCmpg, 0x98, Compare, "dcmpg", (kOpFlagFallThru)) +JBC_OP(Ifeq, 0x99, Branch, "ifeq", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(Ifne, 0x9A, Branch, "ifne", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(Iflt, 0x9B, Branch, "iflt", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(Ifge, 0x9C, Branch, "ifge", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(Ifgt, 0x9D, Branch, "ifgt", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(Ifle, 0x9E, Branch, "ifle", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(IfICmpeq, 0x9F, Branch, "if_icmpeq", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(IfICmpne, 0xA0, Branch, "if_icmpne", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(IfICmplt, 0xA1, Branch, "if_icmplt", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(IfICmpge, 0xA2, Branch, "if_icmpge", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(IfICmpgt, 0xA3, Branch, "if_icmpgt", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(IfICmple, 0xA4, Branch, "if_icmple", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(IfACmpeq, 0xA5, Branch, "if_acmpeq", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(IfACmpne, 0xA6, Branch, "if_acmpne", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(Goto, 0xA7, Goto, "goto", (kOpFlagBranch)) +JBC_OP(Jsr, 0xA8, Jsr, "jsr", (kOpFlagBranch)) +JBC_OP(Ret, 0xA9, Ret, "ret", (kOpFlagBranch)) +JBC_OP(TableSwitch, 0xAA, Switch, "tableswitch", (kOpFlagBranch)) +JBC_OP(LookupSwitch, 0xAB, Switch, "lookupswitch", (kOpFlagBranch)) +JBC_OP(IReturn, 0xAC, Return, "ireturn", (kOpFlagThrowable)) +JBC_OP(LReturn, 0xAD, Return, "lreturn", (kOpFlagThrowable)) +JBC_OP(FReturn, 0xAE, Return, "freturn", (kOpFlagThrowable)) +JBC_OP(DReturn, 0xAF, Return, "dreturn", (kOpFlagThrowable)) +JBC_OP(AReturn, 0xB0, Return, "areturn", (kOpFlagThrowable)) +JBC_OP(Return, 0xB1, Return, "return", (kOpFlagThrowable)) +JBC_OP(GetStatic, 0xB2, StaticFieldOpr, "getstatic", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(PutStatic, 0xB3, StaticFieldOpr, "putstatic", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(GetField, 0xB4, FieldOpr, "getfield", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(PutField, 0xB5, FieldOpr, "putfield", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(InvokeVirtual, 0xB6, Invoke, "invokevirtual", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(InvokeSpecial, 0xB7, Invoke, "invokespecial", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(InvokeStatic, 0xB8, Invoke, "invokestatic", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(InvokeInterface, 0xB9, Invoke, "invokeinterface", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(InvokeDynamic, 0xBA, Invoke, "invokedynamic", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(New, 0xBB, New, "new", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(NewArray, 0xBC, New, "newarray", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(ANewArray, 0xBD, New, "anewarray", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(ArrayLength, 0xBE, ArrayLength, "arraylength", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(AThrow, 0xBF, Throw, "athrow", (kOpFlagThrowable)) +JBC_OP(CheckCast, 0xC0, TypeCheck, "checkcast", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(InstanceOf, 0xC1, TypeCheck, "instanceof", (kOpFlagFallThru)) +JBC_OP(MonitorEnter, 0xC2, Monitor, "monitorenter", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(MonitorExit, 0xC3, Monitor, "monitorexit", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(Wide, 0xC4, Default, "wide", (kOpFlagFallThru)) +JBC_OP(MultiANewArray, 0xC5, MultiANewArray, "multianewarray", (kOpFlagFallThru | kOpFlagThrowable)) +JBC_OP(IfNull, 0xC6, Branch, "ifnull", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(IfNonNull, 0xC7, Branch, "ifnonnull", (kOpFlagFallThru | kOpFlagBranch)) +JBC_OP(GotoW, 0xC8, Goto, "goto_w", (kOpFlagBranch)) +JBC_OP(JsrW, 0xC9, Jsr, "jsr_w", (kOpFlagBranch)) +JBC_OP(BreakPoint, 0xCA, Reversed, "breakpoint", (kOpFlagFallThru)) +JBC_OP(UnusedCB, 0xCB, Unused, "unused_cb", (kOpFlagFallThru)) +JBC_OP(UnusedCC, 0xCC, Unused, "unused_cc", (kOpFlagFallThru)) +JBC_OP(UnusedCD, 0xCD, Unused, "unused_cd", (kOpFlagFallThru)) +JBC_OP(UnusedCE, 0xCE, Unused, "unused_ce", (kOpFlagFallThru)) +JBC_OP(UnusedCF, 0xCF, Unused, "unused_cf", (kOpFlagFallThru)) +JBC_OP(UnusedD0, 0xD0, Unused, "unused_d0", (kOpFlagFallThru)) +JBC_OP(UnusedD1, 0xD1, Unused, "unused_d1", (kOpFlagFallThru)) +JBC_OP(UnusedD2, 0xD2, Unused, "unused_d2", (kOpFlagFallThru)) +JBC_OP(UnusedD3, 0xD3, Unused, "unused_d3", (kOpFlagFallThru)) +JBC_OP(UnusedD4, 0xD4, Unused, "unused_d4", (kOpFlagFallThru)) +JBC_OP(UnusedD5, 0xD5, Unused, "unused_d5", (kOpFlagFallThru)) +JBC_OP(UnusedD6, 0xD6, Unused, "unused_d6", (kOpFlagFallThru)) +JBC_OP(UnusedD7, 0xD7, Unused, "unused_d7", (kOpFlagFallThru)) +JBC_OP(UnusedD8, 0xD8, Unused, "unused_d8", (kOpFlagFallThru)) +JBC_OP(UnusedD9, 0xD9, Unused, "unused_d9", (kOpFlagFallThru)) +JBC_OP(UnusedDA, 0xDA, Unused, "unused_da", (kOpFlagFallThru)) +JBC_OP(UnusedDB, 0xDB, Unused, "unused_db", (kOpFlagFallThru)) +JBC_OP(UnusedDC, 0xDC, Unused, "unused_dc", (kOpFlagFallThru)) +JBC_OP(UnusedDD, 0xDD, Unused, "unused_dd", (kOpFlagFallThru)) +JBC_OP(UnusedDE, 0xDE, Unused, "unused_de", (kOpFlagFallThru)) +JBC_OP(UnusedDF, 0xDF, Unused, "unused_df", (kOpFlagFallThru)) +JBC_OP(UnusedE0, 0xE0, Unused, "unused_e0", (kOpFlagFallThru)) +JBC_OP(UnusedE1, 0xE1, Unused, "unused_e1", (kOpFlagFallThru)) +JBC_OP(UnusedE2, 0xE2, Unused, "unused_e2", (kOpFlagFallThru)) +JBC_OP(UnusedE3, 0xE3, Unused, "unused_e3", (kOpFlagFallThru)) +JBC_OP(UnusedE4, 0xE4, Unused, "unused_e4", (kOpFlagFallThru)) +JBC_OP(UnusedE5, 0xE5, Unused, "unused_e5", (kOpFlagFallThru)) +JBC_OP(UnusedE6, 0xE6, Unused, "unused_e6", (kOpFlagFallThru)) +JBC_OP(UnusedE7, 0xE7, Unused, "unused_e7", (kOpFlagFallThru)) +JBC_OP(UnusedE8, 0xE8, Unused, "unused_e8", (kOpFlagFallThru)) +JBC_OP(UnusedE9, 0xE9, Unused, "unused_e9", (kOpFlagFallThru)) +JBC_OP(UnusedEA, 0xEA, Unused, "unused_ea", (kOpFlagFallThru)) +JBC_OP(UnusedEB, 0xEB, Unused, "unused_eb", (kOpFlagFallThru)) +JBC_OP(UnusedEC, 0xEC, Unused, "unused_ec", (kOpFlagFallThru)) +JBC_OP(UnusedED, 0xED, Unused, "unused_ed", (kOpFlagFallThru)) +JBC_OP(UnusedEE, 0xEE, Unused, "unused_ee", (kOpFlagFallThru)) +JBC_OP(UnusedEF, 0xEF, Unused, "unused_ef", (kOpFlagFallThru)) +JBC_OP(UnusedF0, 0xF0, Unused, "unused_f0", (kOpFlagFallThru)) +JBC_OP(UnusedF1, 0xF1, Unused, "unused_f1", (kOpFlagFallThru)) +JBC_OP(UnusedF2, 0xF2, Unused, "unused_f2", (kOpFlagFallThru)) +JBC_OP(UnusedF3, 0xF3, Unused, "unused_f3", (kOpFlagFallThru)) +JBC_OP(UnusedF4, 0xF4, Unused, "unused_f4", (kOpFlagFallThru)) +JBC_OP(UnusedF5, 0xF5, Unused, "unused_f5", (kOpFlagFallThru)) +JBC_OP(UnusedF6, 0xF6, Unused, "unused_f6", (kOpFlagFallThru)) +JBC_OP(UnusedF7, 0xF7, Unused, "unused_f7", (kOpFlagFallThru)) +JBC_OP(UnusedF8, 0xF8, Unused, "unused_f8", (kOpFlagFallThru)) +JBC_OP(UnusedF9, 0xF9, Unused, "unused_f9", (kOpFlagFallThru)) +JBC_OP(UnusedFA, 0xFA, Unused, "unused_fa", (kOpFlagFallThru)) +JBC_OP(UnusedFB, 0xFB, Unused, "unused_fb", (kOpFlagFallThru)) +JBC_OP(UnusedFC, 0xFC, Unused, "unused_fc", (kOpFlagFallThru)) +JBC_OP(UnusedFD, 0xFD, Unused, "unused_fd", (kOpFlagFallThru)) +JBC_OP(ImpDep1, 0xFE, Reversed, "impdep1", (kOpFlagFallThru)) +JBC_OP(ImpDep2, 0xFF, Reversed, "impdep2", (kOpFlagFallThru)) \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_opcode.h b/src/hir2mpl/bytecode_input/class/include/jbc_opcode.h new file mode 100644 index 0000000000000000000000000000000000000000..d10e5e43654ea7ce48b5836809027bc27c1f8888 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_opcode.h @@ -0,0 +1,691 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef HIR2MPL_INCLUDE_JBC_OPCODE_H +#define HIR2MPL_INCLUDE_JBC_OPCODE_H +#include +#include +#include +#include +#include "types_def.h" +#include "mempool_allocator.h" +#include "factory.h" +#include "basic_io.h" +#include "feir_type.h" + +namespace maple { +namespace jbc { +enum JBCOpcode : uint8 { +#define JBC_OP(op, value, type, name, flag) \ + kOp##op = value, +#include "jbc_opcode.def" +#undef JBC_OP +}; + +enum JBCOpcodeKind : uint8 { + kOpKindDefault = 0, +#define JBC_OP_KIND(kind, name) \ + kOpKind##kind, +#include "jbc_opcode_kind.def" +#undef JBC_OP_KIND + kOpKindSize +}; + +enum JBCPrimType : uint8 { + kTypeDefault = 0, + kTypeInt, + kTypeLong, + kTypeFloat, + kTypeDouble, + kTypeByteOrBoolean, + kTypeChar, + kTypeShort, + kTypeRef, + kTypeAddress, + kTypeLongDummy, + kTypeDoubleDummy, + kTypeSize +}; + +enum JBCOpcodeFlag : uint8 { + kOpFlagNone = 0, + kOpFlagFallThru = 1, + kOpFlagBranch = 1 << 1, + kOpFlagThrowable = 1 << 2 +}; + +struct JBCOpcodeDesc { + JBCOpcodeKind kind; + std::string name; + uint8 flags; +}; + +class JBCOpcodeInfo { + public: + static const uint32 kOpSize = 0x100; + JBCOpcodeInfo(); + ~JBCOpcodeInfo() = default; + + JBCOpcodeKind GetOpcodeKind(JBCOpcode op) const { + return table[static_cast(op)].kind; + } + + const std::string &GetOpcodeName(JBCOpcode op) const { + return table[static_cast(op)].name; + } + + bool IsFallThru(JBCOpcode op) const { + return (table[static_cast(op)].flags & kOpFlagFallThru) != 0; + } + + bool IsBranch(JBCOpcode op) const { + return (table[static_cast(op)].flags & kOpFlagBranch) != 0; + } + + bool IsThrowable(JBCOpcode op) const { + return (table[static_cast(op)].flags & kOpFlagThrowable) != 0; + } + + private: + JBCOpcodeDesc table[kOpSize]; +}; + +class JBCConstPool; +class JBCOp { + public: + JBCOp(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + virtual ~JBCOp() = default; + bool CheckNotWide(const BasicIORead &io) const; + bool ParseFile(BasicIORead &io) { + return ParseFileImpl(io); + } + + std::string Dump(const JBCConstPool &constPool) const { + return DumpImpl(constPool); + } + + const std::vector &GetInputTypesFromStack() const { + return GetInputTypesFromStackImpl(); + } + + std::vector GetInputTypesFromStack(const JBCConstPool &constPool) const { + return GetInputTypesFromStackImpl(constPool); + } + + JBCPrimType GetOutputTypesToStack() const { + return GetOutputTypesToStackImpl(); + } + + JBCPrimType GetOutputTypesToStack(const JBCConstPool &constPool) const { + return GetOutputTypesToStackImpl(constPool); + } + + JBCOpcode GetOpcode() const { + return op; + } + + JBCOpcodeKind GetOpcodeKind() const { + return kind; + } + + bool IsWide() const { + return wide; + } + + const std::string &GetOpcodeName() const { + return opcodeInfo.GetOpcodeName(op); + } + + bool IsFallThru() const { + return opcodeInfo.IsFallThru(op); + } + + bool IsBranch() const { + return opcodeInfo.IsBranch(op); + } + + bool IsThrowable() const { + return opcodeInfo.IsThrowable(op); + } + + static JBCOpcodeInfo &GetOpcodeInfo() { + return opcodeInfo; + } + + static uint32 GetTargetbyInt64(int64 pc) { + if (pc < 0 || pc > UINT16_MAX) { + CHECK_FATAL(false, "invalid PC: %ld", pc); + return 0; + } else { + return static_cast(pc); + } + } + + protected: + virtual bool ParseFileImpl(BasicIORead &io) = 0; + virtual const std::vector &GetInputTypesFromStackImpl() const; + virtual std::vector GetInputTypesFromStackImpl(const JBCConstPool &constPool) const; + virtual JBCPrimType GetOutputTypesToStackImpl() const; + virtual JBCPrimType GetOutputTypesToStackImpl(const JBCConstPool &constPool) const; + virtual std::string DumpImpl(const JBCConstPool &constPool) const; + + MapleAllocator &alloc; + JBCOpcode op : 8; + JBCOpcodeKind kind : 7; + bool wide : 1; + static JBCOpcodeInfo opcodeInfo; + static std::vector emptyPrimTypes; +}; + +class JBCOpUnused : public JBCOp { + public: + JBCOpUnused(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpUnused() = default; + + protected: + bool ParseFileImpl(BasicIORead &io) override; +}; + +class JBCOpReversed : public JBCOp { + public: + JBCOpReversed(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpReversed() = default; + + protected: + bool ParseFileImpl(BasicIORead &io) override; +}; + +class JBCOpDefault : public JBCOp { + public: + JBCOpDefault(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpDefault() = default; + + protected: + bool ParseFileImpl(BasicIORead &io) override; + const std::vector &GetInputTypesFromStackImpl() const override; + JBCPrimType GetOutputTypesToStackImpl() const override; + + private: + static std::map> mapOpInputTypes; + static std::map> InitMapOpInputTypes(); + static std::map mapOpOutputType; + static std::map InitMapOpOutputType(); + static void InitMapOpInputTypesForArrayLoad(std::map> &ans); + static void InitMapOpOutputTypesForArrayLoad(std::map &ans); + static void InitMapOpInputTypesForArrayStore(std::map> &ans); + static void InitMapOpOutputTypesForArrayStore(std::map &ans); + static void InitMapOpInputTypesForMathBinop(std::map> &ans); + static void InitMapOpOutputTypesForMathBinop(std::map &ans); + static void InitMapOpInputTypesForMathUnop(std::map> &ans); + static void InitMapOpOutputTypesForMathUnop(std::map &ans); + static void InitMapOpInputTypesForConvert(std::map> &ans); + static void InitMapOpOutputTypesForConvert(std::map &ans); + static void InitMapOpInputTypesForCompare(std::map> &ans); + static void InitMapOpOutputTypesForCompare(std::map &ans); + static void InitMapOpInputTypesForReturn(std::map> &ans); + static void InitMapOpOutputTypesForReturn(std::map &ans); + static void InitMapOpInputTypesForThrow(std::map> &ans); + static void InitMapOpOutputTypesForThrow(std::map &ans); + static void InitMapOpInputTypesForMonitor(std::map> &ans); + static void InitMapOpOutputTypesForMonitor(std::map &ans); + static void InitMapOpInputTypesForArrayLength(std::map> &ans); + static void InitMapOpOutputTypesForArrayLength(std::map &ans); +}; + +class JBCOpConst : public JBCOp { + public: + JBCOpConst(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpConst() = default; + std::string DumpBiPush() const; + std::string DumpSiPush() const; + std::string DumpLdc(const JBCConstPool &constPool) const; + int32 GetValueInt() const; + int64 GetValueLong() const; + float GetValueFloat() const; + double GetValueDouble() const; + int8 GetValueByte() const; + int16 GetValueShort() const; + uint16 GetIndex() const { + return u.index; + } + + void SetValue(int8 value) { + u.bvalue = value; + } + + void SetValue(int16 value) { + u.svalue = value; + } + + void SetIndex(uint16 argIdx) { + u.index = argIdx; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + JBCPrimType GetOutputTypesToStackImpl(const JBCConstPool &constPool) const override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + + private: + union { + int8 bvalue; + int16 svalue; + uint16 index; + uint16 raw; + } u; + + static std::map InitValueMapI(); + static std::map InitValueMapJ(); + static std::map InitValueMapF(); + static std::map InitValueMapD(); + + static std::map valueMapI; + static std::map valueMapJ; + static std::map valueMapF; + static std::map valueMapD; +}; + +class JBCOpSlotOpr : public JBCOp { + public: + JBCOpSlotOpr(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpSlotOpr() = default; + bool IsAStore() const; + uint16 GetSlotIdx() const { + return slotIdx; + } + + void SetSlotIdx(uint16 argSlotIdx) { + slotIdx = argSlotIdx; + } + + bool IsAddressOpr() const { + return isAddressOpr; + } + + void SetAddressOpr() { + isAddressOpr = true; + } + + void UnsetAddressOpr() { + isAddressOpr = false; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + const std::vector &GetInputTypesFromStackImpl() const override; + JBCPrimType GetOutputTypesToStackImpl() const override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + + private: + static std::map> InitMapSlotIdxAndType(); + static std::map> InitMapOpInputTypes(); + static std::map InitMapOpOutputType(); + + uint16 slotIdx; + bool isAddressOpr; + static std::map> mapSlotIdxAndType; + static std::map> mapOpInputTypes; + static std::map mapOpOutputType; + static std::vector inputTypesAddressOpr; +}; + +class JBCOpMathInc : public JBCOp { + public: + JBCOpMathInc(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpMathInc() = default; + uint16 GetIndex() const { + return index; + } + + void SetIndex(uint16 argIndex) { + index = argIndex; + } + + int16 GetIncr() const { + return incr; + } + + void SetIncr(int16 argIncr) { + incr = argIncr; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + + private: + static std::map> InitMapOpInputTypes(); + static std::map InitMapOpOutputType(); + + uint16 index; + int16 incr; + static std::map> mapOpInputTypes; + static std::map mapOpOutputType; +}; + +class JBCOpBranch : public JBCOp { + public: + JBCOpBranch(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpBranch() = default; + uint32 GetTarget() const { + return target; + } + + void SetTarget(uint32 argTarget) { + target = argTarget; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + const std::vector &GetInputTypesFromStackImpl() const override; + + private: + static std::map> InitMapOpInputTypes(); + + uint32 target; + static std::map> mapOpInputTypes; +}; + +class JBCOpGoto : public JBCOp { + public: + JBCOpGoto(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpGoto() = default; + uint32 GetTarget() const { + return target; + } + + void SetTarget(uint32 argTarget) { + target = argTarget; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + + private: + uint32 target; +}; + +class JBCOpSwitch : public JBCOp { + public: + JBCOpSwitch(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpSwitch() = default; + const MapleMap &GetTargets() const { + return targets; + } + + void ClearTargets() { + targets.clear(); + } + + void AddOrSetTarget(int32 value, uint32 targetPC) { + targets[value] = targetPC; + } + + uint32 GetDefaultTarget() const { + return targetDefault; + } + + void SetDefaultTarget(uint32 targetPC) { + targetDefault = targetPC; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + const std::vector &GetInputTypesFromStackImpl() const override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + + private: + static std::map> InitMapOpInputTypes(); + + MapleMap targets; + uint32 targetDefault; + static std::map> mapOpInputTypes; +}; + +class JBCOpFieldOpr : public JBCOp { + public: + JBCOpFieldOpr(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpFieldOpr() = default; + std::string GetFieldType(const JBCConstPool &constPool) const; + uint16 GetFieldIdx() const { + return fieldIdx; + } + + void SetFieldIdx(uint16 idx) { + fieldIdx = idx; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + const std::vector &GetInputTypesFromStackImpl() const override; + std::vector GetInputTypesFromStackImpl(const JBCConstPool &constPool) const override; + JBCPrimType GetOutputTypesToStackImpl() const override; + JBCPrimType GetOutputTypesToStackImpl(const JBCConstPool &constPool) const override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + + private: + std::vector GetInputTypesFromStackForGet(const JBCConstPool &constPool) const; + std::vector GetInputTypesFromStackForPut(const JBCConstPool &constPool) const; + + uint16 fieldIdx; +}; + +class JBCOpInvoke : public JBCOp { + public: + JBCOpInvoke(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpInvoke() = default; + std::string GetMethodDescription(const JBCConstPool &constPool) const; + uint16 GetMethodIdx() const { + return methodIdx; + } + + void SetMethodIdx(uint16 idx) { + methodIdx = idx; + } + + uint8 GetCount() const { + return count; + } + + void SetCount(uint8 argCount) { + count = argCount; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + const std::vector &GetInputTypesFromStackImpl() const override; + std::vector GetInputTypesFromStackImpl(const JBCConstPool &constPool) const override; + JBCPrimType GetOutputTypesToStackImpl() const override; + JBCPrimType GetOutputTypesToStackImpl(const JBCConstPool &constPool) const override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + + private: + uint16 methodIdx; + uint8 count; +}; + +class JBCOpJsr : public JBCOp { + public: + JBCOpJsr(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpJsr() = default; + uint32 GetTarget() const { + return target; + } + + void SetTarget(uint32 argTarget) { + target = argTarget; + } + + uint16 GetSlotIdx() const { + return slotIdx; + } + + void SetSlotIdx(uint32 argSlotIdx) { + slotIdx = static_cast(argSlotIdx); + } + + int32 GetJsrID() const { + return jsrID; + } + + void SetJsrID(int32 argJsrID) { + jsrID = argJsrID; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + JBCPrimType GetOutputTypesToStackImpl() const override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + + private: + uint32 target; + uint16 slotIdx; + int32 jsrID; +}; + +class JBCOpRet : public JBCOp { + public: + JBCOpRet(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpRet() = default; + uint16 GetIndex() const { + return index; + } + + void SetIndex(uint16 argIndex) { + index = argIndex; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + + private: + uint16 index; +}; + +class JBCOpNew : public JBCOp { + public: + enum PrimType : uint8 { + kPrimNone = 0, + kPrimBoolean = 4, + kPrimChar = 5, + kPrimFloat = 6, + kPrimDouble = 7, + kPrimByte = 8, + kPrimShort = 9, + kPrimInt = 10, + kPrimLong = 11 + }; + + JBCOpNew(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpNew() = default; + + GStrIdx GetTypeNameIdx(const JBCConstPool &constPool) const; + std::string GetTypeName(const JBCConstPool &constPool) const; + const FEIRType *GetFEIRType(const JBCConstPool &constPool) const; + uint16 GetRefTypeIdx() const { + return refTypeIdx; + } + + void SetRefTypeIdx(uint16 idx) { + refTypeIdx = idx; + } + + uint8 GetPrimType() const { + return primType; + } + + void SetPrimType(uint8 type) { + primType = type; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + const std::vector &GetInputTypesFromStackImpl() const override; + JBCPrimType GetOutputTypesToStackImpl() const override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + + private: + static std::map> InitMapOpInputTypes(); + std::string GetPrimTypeName() const; + const UniqueFEIRType &GetPrimFEIRType() const; + + uint16 refTypeIdx; + uint8 primType; + static std::map> mapOpInputTypes; +}; + +class JBCOpMultiANewArray : public JBCOp { + public: + JBCOpMultiANewArray(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpMultiANewArray() = default; + uint16 GetRefTypeIdx() const { + return refTypeIdx; + } + + void SetRefTypeIdx(uint16 idx) { + refTypeIdx = idx; + } + + uint8 GetDim() const { + return dim; + } + + void SetDim(uint8 argDim) { + dim = argDim; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + const std::vector &GetInputTypesFromStackImpl() const override; + std::vector GetInputTypesFromStackImpl(const JBCConstPool &constPool) const override; + JBCPrimType GetOutputTypesToStackImpl() const override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + + private: + uint16 refTypeIdx; + uint8 dim; +}; + +class JBCOpTypeCheck : public JBCOp { + public: + JBCOpTypeCheck(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn); + ~JBCOpTypeCheck() = default; + uint16 GetTypeIdx() const { + return typeIdx; + } + + void SetTypeIdx(uint16 idx) { + typeIdx = idx; + } + + protected: + bool ParseFileImpl(BasicIORead &io) override; + const std::vector &GetInputTypesFromStackImpl() const override; + JBCPrimType GetOutputTypesToStackImpl() const override; + std::string DumpImpl(const JBCConstPool &constPool) const override; + + private: + static std::map> InitMapOpInputTypes(); + static std::map InitMapOpOutputType(); + + uint16 typeIdx; + static std::map> mapOpInputTypes; + static std::map mapOpOutputType; +}; +} // namespace jbc +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_OPCODE_H diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_opcode_helper.h b/src/hir2mpl/bytecode_input/class/include/jbc_opcode_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..b20b3f7d7f79b45e67214e0e468033bca05c18fe --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_opcode_helper.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_JBC_OPCODE_HELPER_H +#define HIR2MPL_INCLUDE_COMMON_JBC_OPCODE_HELPER_H +#include +#include +#include +#include +#include "mpl_logging.h" +#include "jbc_opcode.h" +#include "jbc_class.h" + +namespace maple { +class JBCOpcodeHelper { + public: + JBCOpcodeHelper(const jbc::JBCClassMethod &argMethod); + ~JBCOpcodeHelper() = default; + std::string GetLastErorr() const { + return ssLastError.str(); + } + std::vector GetBaseTypeNamesForOP(const jbc::JBCOp &op, bool &success); + static std::vector GetInputPrimTypeForOP(const jbc::JBCOp &op, const jbc::JBCConstPool &constPool); + static jbc::JBCPrimType GetOutputPrimTypeForOP(const jbc::JBCOp &op, const jbc::JBCConstPool &constPool); + + LLT_PRIVATE: + using FuncPtrGetBaseTypeName = std::vector (JBCOpcodeHelper::*)(const jbc::JBCOp &op, bool &success); + std::vector GetBaseTypeNamesForOPDefault(bool &success) const; + std::vector GetBaseTypeNamesForOPConst(const jbc::JBCOp &op, bool &success); + std::vector GetBaseTypeNamesForOPFieldOpr(const jbc::JBCOp &op, bool &success); + std::vector GetBaseTypeNamesForOPInvoke(const jbc::JBCOp &op, bool &success); + std::vector GetBaseTypeNamesForOPNew(const jbc::JBCOp &op, bool &success); + std::vector GetBaseTypeNamesForOPMultiANewArray(const jbc::JBCOp &op, bool &success); + std::vector GetBaseTypeNamesForOPTypeCheck(const jbc::JBCOp &op, bool &success); + static std::map> InitMapOpInputPrimTypes(); + static std::map InitFuncPtrMapGetBaseTypeName(); + static void InitMapOpInputPrimTypesForConst(std::map> &ans); + static void InitMapOpInputPrimTypesForLoad(); + + const jbc::JBCClassMethod &method; + std::stringstream ssLastError; + static std::map> mapOpInputPrimTypes; + static std::map funcPtrMapGetBaseTypeName; +}; // class JBCOpcodeHelper +} // namespace maple +#endif diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_opcode_kind.def b/src/hir2mpl/bytecode_input/class/include/jbc_opcode_kind.def new file mode 100644 index 0000000000000000000000000000000000000000..5e0bda7e42f79799cf0b12bf04eb74c4cb4bc7d7 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_opcode_kind.def @@ -0,0 +1,47 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +// JBC_OP_KIND(kind, name) +JBC_OP_KIND(Unused, "Unused") +JBC_OP_KIND(Reversed, "Reversed") +JBC_OP_KIND(Const, "Const") +JBC_OP_KIND(SlotOpr, "SlotOpr") +JBC_OP_KIND(Load, "Load") +JBC_OP_KIND(Store, "Store") +JBC_OP_KIND(ArrayLoad, "ArrayLoad") +JBC_OP_KIND(ArrayStore, "ArrayStore") +JBC_OP_KIND(Pop, "Pop") +JBC_OP_KIND(Dup, "Dup") +JBC_OP_KIND(Swap, "Swap") +JBC_OP_KIND(Stack, "Stack") +JBC_OP_KIND(MathBinop, "MathBinop") +JBC_OP_KIND(MathUnop, "MathUnop") +JBC_OP_KIND(MathInc, "MathInc") +JBC_OP_KIND(Convert, "Convert") +JBC_OP_KIND(Compare, "Compare") +JBC_OP_KIND(Branch, "Branch") +JBC_OP_KIND(Goto, "Goto") +JBC_OP_KIND(Switch, "Switch") +JBC_OP_KIND(Return, "Return") +JBC_OP_KIND(StaticFieldOpr, "StaticFieldOpr") +JBC_OP_KIND(FieldOpr, "FieldOpr") +JBC_OP_KIND(Invoke, "Invoke") +JBC_OP_KIND(Jsr, "Jsr") +JBC_OP_KIND(Ret, "Ret") +JBC_OP_KIND(New, "New") +JBC_OP_KIND(MultiANewArray, "MultiANewArray") +JBC_OP_KIND(Throw, "Throw") +JBC_OP_KIND(TypeCheck, "TypeCheck") +JBC_OP_KIND(Monitor, "Monitor") +JBC_OP_KIND(ArrayLength, "ArrayLength") \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_stack2fe_helper.h b/src/hir2mpl/bytecode_input/class/include/jbc_stack2fe_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..9df0dac9a35313e2e77ae0d17dab6a6b49dd6d3b --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_stack2fe_helper.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_STACK2FE_HELPER_H +#define HIR2MPL_INCLUDE_JBC_STACK2FE_HELPER_H +#include +#include +#include +#include +#include "mempool_allocator.h" +#include "jbc_stack_helper.h" +#include "feir_builder.h" +#include "feir_var_reg.h" + +namespace maple { +class JBCStack2FEHelper { + public: + static const uint8 kRegNumOff = 1; + static const uint8 kRegNumOffWide = 2; + explicit JBCStack2FEHelper(bool argUseNestExpr = false); + ~JBCStack2FEHelper() = default; + uint32 GetRegNumForSlot(uint32 slotNum) const; + uint32 GetRegNumForStack() const; + bool PushItem(UniqueFEIRVar var, PrimType pty); + UniqueFEIRVar PushItem(PrimType pty); + UniqueFEIRStmt PushItem(UniqueFEIRExpr expr, PrimType pty, bool hasException = false); + UniqueFEIRStmt PushItem(UniqueFEIRExpr expr, UniqueFEIRType type, bool hasException = false); + UniqueFEIRVar PopItem(PrimType pty); + UniqueFEIRVar PopItem(UniqueFEIRType type); + UniqueFEIRVar PopItem(bool isWide, PrimType &pty); + UniqueFEIRVar PopItemAuto(PrimType &pty); + bool Swap(); + bool Pop(jbc::JBCOpcode opcode); + bool Dup(jbc::JBCOpcode opcode); + std::list GenerateSwapStmts(); + std::list LoadSwapStack(const JBCStackHelper &stackHelper, bool &success); + std::string DumpStackInJavaFormat() const; + std::string DumpStackInInternalFormat() const; + void ClearStack() { + stack.clear(); + } + + void SetNStacks(uint32 argNStacks) { + nStacks = argNStacks; + regNumForStacks.clear(); + for (uint32 i = 0; i < argNStacks; i++) { + CHECK_FATAL(regNumForStacks.insert(i).second, "regNumForStacks insert failed"); + } + } + + uint32 GetNStacks() const { + return nStacks; + } + + void SetNSwaps(uint32 argNSwaps) { + nSwaps = argNSwaps; + } + + uint32 GetNSwaps() const { + return nSwaps; + } + + void SetNLocals(uint32 argNLocals) { + nLocals = argNLocals; + } + + uint32 GetNLocals() const { + return nLocals; + } + + void SetNArgs(uint32 argNArgs) { + nArgs = argNArgs; + } + + uint32 GetNArgs() const { + return nArgs; + } + + static PrimType JBCStackItemTypeToPrimType(jbc::JBCPrimType itemType); + static PrimType SimplifyPrimType(PrimType pty); + + protected: + bool useNestExpr; + uint32 nStacks = 0; + uint32 nSwaps = 0; + uint32 nLocals = 0; + uint32 nArgs = 0; + using StackItem = std::pair; + std::vector stack; // list> + std::set regNumForStacks; + bool Pop(); + bool Pop2(); + bool Dup(); + bool DupX1(); + bool DupX2(); + bool Dup2(); + bool Dup2X1(); + bool Dup2X2(); + std::vector JBCStackItemTypesToPrimTypes(const std::vector itemTypes); + bool CheckSwapValid(const std::vector items) const; + std::vector> GeneralSwapRegNum(const std::vector items); + StackItem MakeStackItem(UniqueFEIRVar var, PrimType pty) const { + return std::make_pair(std::move(var), pty); + } + + bool IsItemDummy(const StackItem &item) const { + return item.first == nullptr && IsPrimTypeWide(item.second); + } + + bool IsItemNormal(const StackItem &item) const { + return item.first != nullptr && IsPrimTypeNormal(item.second); + } + + bool IsItemWide(const StackItem &item) const { + return item.first != nullptr && IsPrimTypeWide(item.second); + } + + bool IsPrimTypeNormal(PrimType pty) const { + return pty == PTY_i32 || pty == PTY_f32 || pty == PTY_ref || pty == PTY_a32; + } + + bool IsPrimTypeWide(PrimType pty) const { + return pty == PTY_i64 || pty == PTY_f64; + } +}; // class JBCStack2FEHelper +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_STACK2FE_HELPER_H diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_stack_helper.h b/src/hir2mpl/bytecode_input/class/include/jbc_stack_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..f34936f9d094d19b05ec923c23b40665a6f022aa --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_stack_helper.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_STACK_HELPER_H +#define HIR2MPL_INCLUDE_JBC_STACK_HELPER_H +#include "fe_configs.h" +#include "jbc_opcode.h" +#include "jbc_class_const_pool.h" + +namespace maple { +class JBCStackHelper { + public: + JBCStackHelper() = default; + ~JBCStackHelper() = default; + void Reset(); + bool StackChange(const jbc::JBCOp &op, const jbc::JBCConstPool &constPool); + void PushItem(jbc::JBCPrimType type); + void PushItems(const std::vector &types); + bool PopItem(jbc::JBCPrimType type); + bool PopItems(const std::vector &types); + void CopyFrom(const JBCStackHelper &src); + bool EqualTo(const JBCStackHelper &src); + bool Contains(const JBCStackHelper &src); + void Dump() const; + static std::string GetTypeName(jbc::JBCPrimType type); + std::vector GetStackItems() const; + uint32 GetStackSize() const { + size_t stackSize = stack.size(); + CHECK_FATAL(stackSize < UINT32_MAX, "stack size is too large"); + return static_cast(stackSize); + } + + LLT_PRIVATE: + std::vector stack; + bool Pop(jbc::JBCOpcode opcode); + bool Dup(jbc::JBCOpcode opcode); + bool Dup(); + bool DupX1(); + bool DupX2(); + bool Dup2(); + bool Dup2X1(); + bool Dup2X2(); + bool Swap(); + bool IsType1(jbc::JBCPrimType type) const; + bool IsType2(jbc::JBCPrimType type) const; + bool IsType2Dummy(jbc::JBCPrimType type) const; + jbc::JBCPrimType GetGeneralType(jbc::JBCPrimType type) const; +}; // class JBCStack +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_STACK_HELPER_H diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_stmt.h b/src/hir2mpl/bytecode_input/class/include/jbc_stmt.h new file mode 100644 index 0000000000000000000000000000000000000000..127a08b2037c66e64695ce9b677166d242e5254e --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_stmt.h @@ -0,0 +1,372 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_STMT_H +#define HIR2MPL_INCLUDE_JBC_STMT_H +#include +#include +#include "jbc_opcode.h" +#include "jbc_stack2fe_helper.h" + +namespace maple { +enum JBCStmtKind : uint8 { + kJBCStmtDefault = 0, + kJBCStmtFuncBeing, + kJBCStmtFuncEnd, + kJBCStmtInst, + kJBCStmtInstBranch, + kJBCStmtInstBranchRet, + kJBCStmtPesudoComment, + kJBCStmtPesudoLOC, + kJBCStmtPesudoLabel, + kJBCStmtPesudoTry, + kJBCStmtPesudoEndTry, + kJBCStmtPesudoCatch +}; + +class JBCFunctionContext; +class JBCStmtKindHelper { + public: + static std::string JBCStmtKindName(JBCStmtKind kind); + + private: + JBCStmtKindHelper() = default; + ~JBCStmtKindHelper() = default; +}; // class JBCStmtKindHelper + +class JBCStmt : public FEIRStmt { + public: + explicit JBCStmt(JBCStmtKind argKind) + : FEIRStmt(kStmt), JBCkind(argKind), + pc(UINT32_MAX) {} + + JBCStmt(FEIRNodeKind argGenKind, JBCStmtKind argKind) + : FEIRStmt(argGenKind), + JBCkind(argKind), + pc(UINT32_MAX) {} + + virtual ~JBCStmt() = default; + std::list EmitToFEIR(JBCFunctionContext &context, bool &success) const { + std::list feirStmts = EmitToFEIRImpl(context, success); + return feirStmts; + } + + JBCStmtKind GetJBCKind() const { + return JBCkind; + } + + void SetJBCKind(JBCStmtKind argKind) { + JBCkind = argKind; + } + + void SetPC(uint32 argPC) { + pc = argPC; + } + + uint32 GetPC() const { + return pc; + } + + bool IsJBCBranch() const { + return JBCkind == JBCStmtKind::kJBCStmtInstBranch || JBCkind == JBCStmtKind::kJBCStmtInstBranchRet; + } + + protected: + virtual std::list EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const = 0; + + JBCStmtKind JBCkind; + uint32 pc; +}; + +class JBCStmtInst : public JBCStmt { + public: + explicit JBCStmtInst(const jbc::JBCOp &argOp); + ~JBCStmtInst() = default; + const jbc::JBCOp &GetOp() const { + return op; + } + + protected: + bool IsStmtInstImpl() const override; + void DumpImpl(const std::string &prefix) const override; + std::string DumpDotStringImpl() const override; + std::list EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const override; + + private: + const jbc::JBCOp &op; + using FuncPtrEmitToFEIR = + std::list (JBCStmtInst::*)(JBCFunctionContext &context, bool &success) const; + static std::map funcPtrMapForEmitToFEIR; + static std::map InitFuncPtrMapForEmitToFEIR(); + static std::map opcodeMapForMathBinop; + static std::map InitOpcodeMapForMathBinop(); + static std::map opcodeMapForMathUnop; + static std::map InitOpcodeMapForMathUnop(); + static std::map opcodeMapForMonitor; + static std::map InitOpcodeMapForMonitor(); + std::list EmitToFEIRForOpConst(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpConstCommon(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpAConstNull(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpIConst(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpLConst(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpFConst(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpDConst(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpBiPush(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpSiPush(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpLdc(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpLoad(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpStore(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpArrayLoad(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpArrayStore(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpPop(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpDup(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpSwap(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpMathBinop(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpMathUnop(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpMathInc(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpConvert(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpCompare(const JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpReturn(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpStaticFieldOpr(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpFieldOpr(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpInvoke(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpInvokeVirtual(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpInvokeStatic(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpInvokeInterface(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpInvokeSpecial(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpInvokeDynamic(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpNew(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpMultiANewArray(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpThrow(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpTypeCheck(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpMonitor(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpArrayLength(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRCommon(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRCommon2(JBCFunctionContext &context, bool &success) const; + UniqueFEIRStmt GenerateStmtForConstI32(JBCStack2FEHelper &stack2feHelper, int32 val, bool &success) const; + UniqueFEIRStmt GenerateStmtForConstI64(JBCStack2FEHelper &stack2feHelper, int64 val, bool &success) const; + UniqueFEIRStmt GenerateStmtForConstF32(JBCStack2FEHelper &stack2feHelper, float val, bool &success) const; + UniqueFEIRStmt GenerateStmtForConstF64(JBCStack2FEHelper &stack2feHelper, double val, bool &success) const; + void PrepareInvokeParametersAndReturn(JBCStack2FEHelper &stack2feHelper, const FEStructMethodInfo &info, + FEIRStmtCallAssign &callStmt, bool isStatic) const; +}; + +class JBCStmtPesudoLabel; + +class JBCStmtInstBranch : public JBCStmt { + public: + explicit JBCStmtInstBranch(const jbc::JBCOp &argOp); + ~JBCStmtInstBranch() = default; + const jbc::JBCOp &GetOp() const { + return op; + } + + protected: + bool IsStmtInstImpl() const override; + void DumpImpl(const std::string &prefix) const override; + std::string DumpDotStringImpl() const override; + std::list EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const override; + JBCStmtPesudoLabel *GetTarget(const std::map &mapPCStmtLabel, uint32 pc) const; + virtual std::list EmitToFEIRForOpRetImpl(JBCFunctionContext &context, bool &success) const { + (void) context; + (void) success; + return std::list(); + } + + const jbc::JBCOp &op; + + private: + // bitwise mode + enum { + kModeDefault = 0, // for int32 using normal opnd + kModeUseRef = 0x1, // bit0: 1 for ref, 0 for int32 + kModeUseZeroAsSecondOpnd = 0x2 // bit1: 1 for using 0 for 2nd opnd, 0 for using normal opnd + }; + + using FuncPtrEmitToFEIR = + std::list (JBCStmtInstBranch::*)(JBCFunctionContext &context, bool &success) const; + static std::map funcPtrMapForEmitToFEIR; + static std::map InitFuncPtrMapForEmitToFEIR(); + static std::map> opcodeMapForCondGoto; + static std::map> InitOpcodeMapForCondGoto(); + std::list EmitToFEIRForOpGoto(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpBranch(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpSwitch(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpJsr(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRForOpRet(JBCFunctionContext &context, bool &success) const; + std::list EmitToFEIRCommon(JBCFunctionContext &context, bool &success) const; +}; + +class JBCStmtInstBranchRet : public JBCStmtInstBranch { + public: + JBCStmtInstBranchRet(const jbc::JBCOp &argOp); + ~JBCStmtInstBranchRet() = default; + + protected: + std::list EmitToFEIRForOpRetImpl(JBCFunctionContext &context, bool &success) const override; +}; + +class JBCStmtPesudoLabel : public JBCStmt { + public: + JBCStmtPesudoLabel() + : JBCStmt(kStmtPesudo, kJBCStmtPesudoLabel), + labelIdx(0) {} + + ~JBCStmtPesudoLabel() = default; + void SetLabelIdx(uint32 arg) { + labelIdx = arg; + } + + uint32 GetLabelIdx() const { + return labelIdx; + } + + protected: + void DumpImpl(const std::string &prefix) const override; + std::string DumpDotStringImpl() const override; + std::list EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const override; + + uint32 labelIdx; +}; + +class JBCStmtPesudoCatch : public JBCStmtPesudoLabel { + public: + JBCStmtPesudoCatch() + : JBCStmtPesudoLabel() { + JBCkind = kJBCStmtPesudoCatch; + } + ~JBCStmtPesudoCatch() = default; + void AddCatchTypeName(const GStrIdx &nameIdx) { + if (catchTypeNames.find(nameIdx) == catchTypeNames.end()) { + CHECK_FATAL(catchTypeNames.insert(nameIdx).second, "catchTypeNames insert failed"); + } + } + + protected: + void DumpImpl(const std::string &prefix) const override; + std::string DumpDotStringImpl() const override; + std::list EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const override; + + private: + std::set catchTypeNames; +}; + +class JBCStmtPesudoTry : public JBCStmt { + public: + JBCStmtPesudoTry() + : JBCStmt(kJBCStmtPesudoTry) {} + + ~JBCStmtPesudoTry() = default; + void AddCatchStmt(JBCStmtPesudoCatch &stmt) { + catchStmts.push_back(&stmt); + } + + size_t GetCatchCount() const { + return catchStmts.size(); + } + + JBCStmtPesudoCatch *GetCatchStmt(uint32 idx) { + ASSERT(idx < catchStmts.size(), "index out of range"); + return static_cast(catchStmts[idx]); + } + + protected: + void DumpImpl(const std::string &prefix) const override; + std::string DumpDotStringImpl() const override; + std::list EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const override; + + private: + std::vector catchStmts; +}; + +class JBCStmtPesudoEndTry : public JBCStmt { + public: + JBCStmtPesudoEndTry() : JBCStmt(kJBCStmtPesudoEndTry) { + isAuxPost = true; + } + + ~JBCStmtPesudoEndTry() = default; + + protected: + void DumpImpl(const std::string &prefix) const override; + std::string DumpDotStringImpl() const override; + std::list EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const override; +}; + +class JBCStmtPesudoComment : public JBCStmt { + public: + explicit JBCStmtPesudoComment(const std::string &argContent) + : JBCStmt(kJBCStmtPesudoComment), + content(argContent) { + isAuxPre = true; + } + + ~JBCStmtPesudoComment() = default; + void SetContent(const std::string &argContent) { + content = argContent; + } + + protected: + void DumpImpl(const std::string &prefix) const override; + std::string DumpDotStringImpl() const override; + std::list EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const override; + + private: + std::string content = ""; +}; // class JBCStmtPesudoComment + +class JBCStmtPesudoLOC : public JBCStmt { + public: + JBCStmtPesudoLOC() + : JBCStmt(kJBCStmtPesudoLOC), + srcFileIdx(0), + lineNumber(0) { + isAuxPre = true; + } + + JBCStmtPesudoLOC(uint32 argSrcFileIdx, uint32 argLineNumber) + : JBCStmt(kJBCStmtPesudoLOC), + srcFileIdx(argSrcFileIdx), + lineNumber(argLineNumber) { + isAuxPre = true; + } + + ~JBCStmtPesudoLOC() = default; + void SetSrcFileIdx(uint32 idx) { + srcFileIdx = idx; + } + + uint32 GetPesudoLOCSrcFileIdx() const { + return srcFileIdx; + } + + void SetLineNumber(uint32 line) { + lineNumber = line; + } + + uint32 GetLineNumber() const { + return lineNumber; + } + + protected: + void DumpImpl(const std::string &prefix) const override; + std::string DumpDotStringImpl() const override; + std::list EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const override; + + private: + uint32 srcFileIdx; + uint32 lineNumber; +}; +} +#endif // HIR2MPL_INCLUDE_JBC_STMT_H diff --git a/src/hir2mpl/bytecode_input/class/include/jbc_util.h b/src/hir2mpl/bytecode_input/class/include/jbc_util.h new file mode 100644 index 0000000000000000000000000000000000000000..3626e891300248c201a001f97dff9d087325e91f --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/include/jbc_util.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_JBC_UTIL_H +#define HIR2MPL_INCLUDE_JBC_UTIL_H +#include +#include +#include "jbc_opcode.h" + +namespace maple { +namespace jbc { +class JBCUtil { + public: + static std::string ClassInternalNameToFullName(const std::string &name); + static std::vector SolveMethodSignature(const std::string &signature); + static std::string SolveParamName(const std::string &signature); + static JBCPrimType GetPrimTypeForName(const std::string &name); + + private: + JBCUtil() = default; + ~JBCUtil() = default; +}; +} // namespace jbc +} // namespace maple +#endif // HIR2MPL_INCLUDE_JBC_UTIL_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_attr.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_attr.cpp new file mode 100644 index 0000000000000000000000000000000000000000..40f7a215ee4e405c5a985086cb251e610ef6cb7d --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_attr.cpp @@ -0,0 +1,1144 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_attr.h" +#include "jbc_attr_item.h" + +namespace maple { +namespace jbc { +// ---------- JBCAttr ---------- +JBCAttr::JBCAttr(JBCAttrKind kindIn, uint16 nameIdxIn, uint32 lengthIn) + : kind(kindIn), nameIdx(nameIdxIn), length(lengthIn) {} + +JBCAttr* JBCAttr::InAttr(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + JBCAttr *attrInfo = nullptr; + uint16 nameIdx = io.ReadUInt16(); + uint32 length = io.ReadUInt32(); + uint32 posStart = io.GetPos(); + const JBCConst *constNameRaw = constPool.GetConstByIdxWithTag(nameIdx, kConstUTF8); + if (constNameRaw == nullptr) { + ERR(kLncErr, "invalid nameIdx %d for attr name.", nameIdx); + return nullptr; + } + const JBCConstUTF8 *constName = static_cast(constNameRaw); + std::string strName = constName->GetString(); + if (strName.empty()) { + ERR(kLncErr, "AttrInfo@0x%x parse error: empty attr name.", posStart); +#define JBC_ATTR(name, Type) \ + } else if (strName.compare(name) == 0) { \ + attrInfo = mp->New(allocator, nameIdx, length); \ + if (!attrInfo->ParseFile(allocator, io, constPool)) { \ + CHECK_FATAL(false, "failed to parse attr info"); \ + } +#include "jbc_attr.def" +#undef JBC_ATTR + } else { + attrInfo = mp->New(allocator, nameIdx, length); + if (!attrInfo->ParseFile(allocator, io, constPool)) { + CHECK_FATAL(false, "failed to parse attr info"); + } + } + if (io.GetPos() - posStart != length) { + ERR(kLncErr, "AttrInfo@0x%x parse error: incorrect data length.", posStart); + io.SetPos(posStart + length); + } + return attrInfo; +} + +JBCAttrKind JBCAttr::AttrKind(const std::string &str) { +#define JBC_ATTR(name, type) \ + if (str.compare(name) == 0) { \ + return kAttr##type; \ + } +#include "jbc_attr.def" +#undef JBC_ATTR + return kAttrUnknown; +} + +// ---------- JBCAttrMap ---------- +JBCAttrMap::JBCAttrMap(MapleAllocator &allocatorIn) + : allocator(allocatorIn), mapAttrs(std::less(), allocator.Adapter()) {} + +void JBCAttrMap::RegisterAttr(JBCAttr &attr) { + JBCAttrKind kind = attr.GetKind(); + MapleMap*>::const_iterator it = mapAttrs.find(kind); + if (it == mapAttrs.end()) { + MemPool *mp = allocator.GetMemPool(); + MapleList *attrList = mp->New>(allocator.Adapter()); + attrList->push_back(&attr); + CHECK_FATAL(mapAttrs.insert(std::make_pair(kind, attrList)).second, "mapAttrs insert error"); + } else { + it->second->push_back(&attr); + } +} + +std::list JBCAttrMap::GetAttrs(JBCAttrKind kind) const { + auto it = mapAttrs.find(kind); + if (it == mapAttrs.end()) { + return std::list(); + } else { + std::list ans; + for (JBCAttr *attr : *(it->second)) { + ans.push_back(attr); + } + return ans; + } +} + +const JBCAttr *JBCAttrMap::GetAttr(JBCAttrKind kind) const { + auto it = mapAttrs.find(kind); + if (it == mapAttrs.end()) { + return nullptr; + } else { + CHECK_FATAL(it->second->size() == 1, "more than one attrs"); + return *(it->second->begin()); + } +} + +bool JBCAttrMap::PreProcess(const JBCConstPool &constPool) { + bool success = true; + for (auto itList : mapAttrs) { + for (JBCAttr *attr : *(itList.second)) { + switch (attr->GetKind()) { + case kAttrLocalVariableTable: + case kAttrLocalVariableTypeTable: + success = success && attr->PreProcess(constPool); + break; + default: + break; + } + } + } + return success; +} + +// ---------- JBCAttrRaw ---------- +JBCAttrRaw::JBCAttrRaw(const MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrRaw, nameIdx, length), + rawData(nullptr) { + (void) allocator; +} + +JBCAttrRaw::~JBCAttrRaw() { + rawData = nullptr; +} + +bool JBCAttrRaw::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + rawData = static_cast(mp->Malloc(length)); + CHECK_NULL_FATAL(rawData); + io.ReadBufferUInt8(rawData, length, success); + return success; +} + +bool JBCAttrRaw::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *JBCAttrRaw::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrLocalVariableInfo ---------- +JavaAttrLocalVariableInfoItem JBCAttrLocalVariableInfo::kInvalidInfoItem; + +JBCAttrLocalVariableInfo::JBCAttrLocalVariableInfo(MapleAllocator &argAllocator) + : allocator(argAllocator), + slotStartMap(allocator.Adapter()), + itemMap(allocator.Adapter()) {} + +void JBCAttrLocalVariableInfo::RegisterItem(const attr::LocalVariableTableItem &itemAttr) { + uint16 slotIdx = itemAttr.GetIndex(); + uint16 startPC = itemAttr.GetStartPC(); + uint16 length = itemAttr.GetLength(); + JavaAttrLocalVariableInfoItem *item = GetItemByStartInternal(slotIdx, startPC); + if (item == nullptr) { + CheckItemAvaiable(slotIdx, startPC); + AddSlotStartMap(slotIdx, startPC); + JavaAttrLocalVariableInfoItem &itemRef = itemMap[std::make_pair(slotIdx, startPC)]; + itemRef.slotIdx = slotIdx; + itemRef.start = startPC; + itemRef.length = length; + itemRef.nameIdx = itemAttr.GetNameStrIdx(); + itemRef.feirType = itemAttr.GetFEIRType(); + } else { + if (item->start == startPC && item->length == length && item->nameIdx == itemAttr.GetNameStrIdx()) { + CHECK_FATAL(item->feirType == nullptr, "Item already defined"); + item->feirType = itemAttr.GetFEIRType(); + } else { + CHECK_FATAL(false, "Item mismatch in RegisterItem()"); + } + } +} + +void JBCAttrLocalVariableInfo::RegisterTypeItem(const attr::LocalVariableTypeTableItem &itemAttr) { + uint16 slotIdx = itemAttr.GetIndex(); + uint16 startPC = itemAttr.GetStartPC(); + uint16 length = itemAttr.GetLength(); + JavaAttrLocalVariableInfoItem *item = GetItemByStartInternal(slotIdx, startPC); + if (item == nullptr) { + CheckItemAvaiable(slotIdx, startPC); + AddSlotStartMap(slotIdx, startPC); + JavaAttrLocalVariableInfoItem &itemRef = itemMap[std::make_pair(slotIdx, startPC)]; + itemRef.slotIdx = slotIdx; + itemRef.start = startPC; + itemRef.length = length; + itemRef.nameIdx = itemAttr.GetNameStrIdx(); + itemRef.signatureNameIdx = itemAttr.GetSignatureStrIdx(); + } else { + if (item->start == startPC && item->length == length && item->nameIdx == itemAttr.GetNameStrIdx()) { + CHECK_FATAL(item->signatureNameIdx == 0, "Item already defined"); + item->signatureNameIdx = itemAttr.GetSignatureStrIdx(); + } else { + CHECK_FATAL(false, "Item mismatch in RegisterItem()"); + } + } +} + +const JavaAttrLocalVariableInfoItem &JBCAttrLocalVariableInfo::GetItemByStart(uint16 slotIdx, uint16 start) const { + uint32 itemPCStart = GetStart(slotIdx, start); + if (itemPCStart != start) { + return kInvalidInfoItem; + } + std::map, JavaAttrLocalVariableInfoItem>::const_iterator it = + itemMap.find(std::make_pair(slotIdx, itemPCStart)); + if (it != itemMap.end()) { + return it->second; + } else { + return kInvalidInfoItem; + } +} + +JavaAttrLocalVariableInfoItem *JBCAttrLocalVariableInfo::GetItemByStartInternal(uint16 slotIdx, uint16 start) { + uint32 itemPCStart = GetStart(slotIdx, start); + if (itemPCStart != start) { + return nullptr; + } + std::map, JavaAttrLocalVariableInfoItem>::iterator it = + itemMap.find(std::make_pair(slotIdx, itemPCStart)); + CHECK_FATAL(it != itemMap.end(), "Item@%d not found", start); + return &(it->second); +} + +uint16 JBCAttrLocalVariableInfo::GetStart(uint16 slotIdx, uint16 pc) const { + MapleMap>::const_iterator it = slotStartMap.find(slotIdx); + if (it == slotStartMap.end()) { + return jbc::kInvalidPC16; + } + uint16 startLast = jbc::kInvalidPC16; + for (uint16 start : it->second) { + if (pc == start) { + return start; + } else if (pc < start) { + return startLast; + } + startLast = start; + } + return startLast; +} + +std::list JBCAttrLocalVariableInfo::EmitToStrings() const { + std::list ans; + std::stringstream ss; + ans.emplace_back("===== Local Variable Info ====="); + for (const std::pair, JavaAttrLocalVariableInfoItem> &itemPair : itemMap) { + const JavaAttrLocalVariableInfoItem &item = itemPair.second; + ss.str(""); + ss << "slot[" << item.slotIdx << "]: "; + ss << "start=" << item.start << ", "; + ss << "lenght=" << item.length << ", "; + ss << "name=\'" << GlobalTables::GetStrTable().GetStringFromStrIdx(item.nameIdx) << "\', "; + ss << "type=\'" << item.feirType->GetTypeName() << "\', "; + ss << "signature=\'" << GlobalTables::GetStrTable().GetStringFromStrIdx(item.signatureNameIdx) << "\'"; + ans.push_back(ss.str()); + } + ans.emplace_back("==============================="); + return ans; +} + +bool JBCAttrLocalVariableInfo::IsInvalidLocalVariableInfoItem(const JavaAttrLocalVariableInfoItem &item) { + return (item.nameIdx == 0 && item.feirType == nullptr && item.signatureNameIdx == 0); +} + +void JBCAttrLocalVariableInfo::AddSlotStartMap(uint16 slotIdx, uint16 startPC) { + auto it = slotStartMap.find(slotIdx); + if (it == slotStartMap.end()) { + MapleSet startSet(allocator.Adapter()); + CHECK_FATAL(startSet.insert(startPC).second, "insert failed"); + CHECK_FATAL(slotStartMap.insert(std::make_pair(slotIdx, startSet)).second, "insert failed"); + } else { + CHECK_FATAL(it->second.insert(startPC).second, "insert failed"); + } +} + +void JBCAttrLocalVariableInfo::CheckItemAvaiable(uint16 slotIdx, uint16 start) const { + uint32 itemPCStart = GetStart(slotIdx, start); + if (itemPCStart == jbc::kInvalidPC16) { + return; + } + CHECK_FATAL(itemPCStart <= jbc::kMaxPC32, "Invalid PC"); + uint16 itemPCStart16 = static_cast(itemPCStart); + const JavaAttrLocalVariableInfoItem &item = GetItemByStart(slotIdx, itemPCStart16); + CHECK_FATAL(!JBCAttrLocalVariableInfo::IsInvalidLocalVariableInfoItem(item), "Item@%d not found", itemPCStart16); + CHECK_FATAL(start >= item.start + item.length, "PC range overlapped"); +} + +// ---------- JBCAttrConstantValue ---------- +JBCAttrConstantValue::JBCAttrConstantValue(const MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrConstantValue, nameIdx, length), + constIdx(0), + constValue(nullptr) { + (void) allocator; +} + +JBCAttrConstantValue::~JBCAttrConstantValue() { + constValue = nullptr; +} + +bool JBCAttrConstantValue::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) allocator; + (void) constPool; + bool success = false; + constIdx = io.ReadUInt16(success); + return success; +} + +bool JBCAttrConstantValue::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *JBCAttrConstantValue::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrCode ---------- +JBCAttrCode::JBCAttrCode(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrCode, nameIdx, length), + maxStack(0), + maxLocals(0), + codeLength(0), + code(nullptr), + nException(0), + exceptions(allocator.Adapter()), + nAttr(0), + attrs(allocator.Adapter()), + instructions(allocator.Adapter()), + attrMap(allocator), + localVarInfo(allocator) {} + +JBCAttrCode::~JBCAttrCode() { + code = nullptr; +} + +bool JBCAttrCode::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + CHECK_FATAL(mp, "mempool is nullptr"); + maxStack = io.ReadUInt16(success); + maxLocals = io.ReadUInt16(success); + codeLength = io.ReadUInt32(success); + code = static_cast(mp->Malloc(codeLength)); + CHECK_NULL_FATAL(code); + io.ReadBufferUInt8(code, codeLength, success); + nException = io.ReadUInt16(success); + for (uint16 i = 0; i < nException; i++) { + attr::ExceptionTableItem *item = mp->New(); + success = item->ParseFile(allocator, io); + exceptions.push_back(item); + } + nAttr = io.ReadUInt16(success); + for (uint16 i = 0; i < nAttr; i++) { + JBCAttr *attr = nullptr; + attr = JBCAttr::InAttr(allocator, io, constPool); + if (attr == nullptr) { + return false; + } + attrs.push_back(attr); + attrMap.RegisterAttr(*attr); + } + // ParseOpcode + success = ParseOpcodes(allocator); + return success; +} + +bool JBCAttrCode::PreProcessImpl(const JBCConstPool &constPool) { + bool success = true; + for (attr::ExceptionTableItem *item : exceptions) { + success = success && item->PreProcess(constPool); + } + success = success && attrMap.PreProcess(constPool); + InitLocalVarInfo(); + return success; +} + +SimpleXMLElem *JBCAttrCode::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// Remove const when implemented +void JBCAttrCode::InitLocalVarInfo() { + // LocalVariableTable + std::list localVars = attrMap.GetAttrs(jbc::kAttrLocalVariableTable); + for (JBCAttr *attrRaw : localVars) { + CHECK_NULL_FATAL(attrRaw); + JBCAttrLocalVariableTable *attr = static_cast(attrRaw); + for (attr::LocalVariableTableItem *itemAttr : attr->GetLocalVarInfos()) { + localVarInfo.RegisterItem(*itemAttr); + } + } + // LocalVariableTypeTable + std::list localVarTypes = attrMap.GetAttrs(jbc::kAttrLocalVariableTypeTable); + for (JBCAttr *attrRaw : localVarTypes) { + CHECK_NULL_FATAL(attrRaw); + JBCAttrLocalVariableTypeTable *attr = static_cast(attrRaw); + for (attr::LocalVariableTypeTableItem *itemAttr : attr->GetLocalVarTypeInfos()) { + localVarInfo.RegisterTypeItem(*itemAttr); + } + } +} + +// Remove const when implemented +void JBCAttrCode::SetLoadStoreType() const { +} + +bool JBCAttrCode::ParseOpcodes(MapleAllocator &allocator) { + BasicIOMapFile file("code", code, codeLength); + BasicIORead io(file, true); + bool success = true; + bool wide = false; + JBCOp *objOP = nullptr; + uint32 pc = 0; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + while (io.GetPos() < codeLength && success) { + if (wide == false) { + pc = io.GetPos(); + } + JBCOpcode opcode = static_cast(io.ReadUInt8(success)); + if (opcode == kOpWide) { + wide = true; + continue; + } + JBCOpcodeKind kind = JBCOp::GetOpcodeInfo().GetOpcodeKind(opcode); + switch (kind) { + case kOpKindArrayLoad: + case kOpKindArrayStore: + case kOpKindPop: + case kOpKindDup: + case kOpKindSwap: + case kOpKindStack: + case kOpKindMathBinop: + case kOpKindMathUnop: + case kOpKindConvert: + case kOpKindCompare: + case kOpKindReturn: + case kOpKindThrow: + case kOpKindMonitor: + case kOpKindArrayLength: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindUnused: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindReversed: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindConst: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindLoad: + case kOpKindStore: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindMathInc: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindBranch: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindGoto: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindSwitch: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindStaticFieldOpr: + case kOpKindFieldOpr: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindInvoke: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindJsr: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindRet: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindNew: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindMultiANewArray: + objOP = mp->New(allocator, opcode, kind, wide); + break; + case kOpKindTypeCheck: + objOP = mp->New(allocator, opcode, kind, wide); + break; + default: + CHECK_NULL_FATAL(objOP); + break; + } + wide = false; + success = objOP->ParseFile(io); + if (success) { + instructions[pc] = objOP; + } + } + return success; +} + +// ---------- JBCAttrStackMapTable ---------- +JBCAttrStackMapTable::JBCAttrStackMapTable(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrStackMapTable, nameIdx, length), + count(0), + entries(allocator.Adapter()) {} + +bool JBCAttrStackMapTable::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + count = io.ReadUInt16(success); + for (uint16 i = 0; i < count; i++) { + uint8 frameType = io.ReadUInt8(); + attr::StackMapFrameItem *item = attr::StackMapFrameItem::NewItem(allocator, io, frameType); + if (item == nullptr) { + return false; + } + entries.push_back(item); + } + return success; +} + +bool JBCAttrStackMapTable::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *JBCAttrStackMapTable::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrException ---------- +JBCAttrException::JBCAttrException(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrException, nameIdx, length), + count(0), + tbExceptionIdx(allocator.Adapter()) {} + +bool JBCAttrException::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) allocator; + (void) constPool; + bool success = false; + count = io.ReadUInt16(success); + for (uint16 i = 0; i < count; i++) { + uint16 idx = io.ReadUInt16(success); + tbExceptionIdx.push_back(idx); + } + return success; +} + +bool JBCAttrException::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *JBCAttrException::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrInnerClass ---------- +JBCAttrInnerClass::JBCAttrInnerClass(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrInnerClass, nameIdx, length), + count(0), + tbClasses(allocator.Adapter()) {} + +bool JBCAttrInnerClass::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + count = io.ReadUInt16(success); + for (uint16 i = 0; i < count; i++) { + attr::InnerClassItem *item = mp->New(); + success = item->ParseFile(allocator, io); + tbClasses.push_back(item); + } + return success; +} + +bool JBCAttrInnerClass::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *JBCAttrInnerClass::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrEnclosingMethod ---------- +JBCAttrEnclosingMethod::JBCAttrEnclosingMethod(const MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrEnclosingMethod, nameIdx, length), + classIdx(0), + methodIdx(0), + constClass(nullptr), + constNameAndType(nullptr) { + (void) allocator; +} + +JBCAttrEnclosingMethod::~JBCAttrEnclosingMethod() { + constClass = nullptr; + constNameAndType = nullptr; +} + +bool JBCAttrEnclosingMethod::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) allocator; + (void) constPool; + bool success = false; + classIdx = io.ReadUInt16(success); + methodIdx = io.ReadUInt16(success); + return success; +} + +bool JBCAttrEnclosingMethod::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *JBCAttrEnclosingMethod::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrSynthetic ---------- +JBCAttrSynthetic::JBCAttrSynthetic(const MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrSynthetic, nameIdx, length) { + (void) allocator; +} + +bool JBCAttrSynthetic::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) allocator; + (void) io; + (void) constPool; + return true; +} + +bool JBCAttrSynthetic::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *JBCAttrSynthetic::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrSignature ---------- +JBCAttrSignature::JBCAttrSignature(const MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrSignature, nameIdx, length), + signatureIdx(0), + constSignatureName(nullptr) { + (void) allocator; +} + +JBCAttrSignature::~JBCAttrSignature() { + constSignatureName = nullptr; +} + +bool JBCAttrSignature::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) allocator; + (void) constPool; + bool success = false; + signatureIdx = io.ReadUInt16(success); + return success; +} + +bool JBCAttrSignature::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *JBCAttrSignature::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrSourceFile ---------- +JBCAttrSourceFile::JBCAttrSourceFile(const MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrSourceFile, nameIdx, length), + sourceFileIdx(0), + constFileName(nullptr) { + (void) allocator; +} + +JBCAttrSourceFile::~JBCAttrSourceFile() { + constFileName = nullptr; +} + +bool JBCAttrSourceFile::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) allocator; + (void) constPool; + bool success = false; + sourceFileIdx = io.ReadUInt16(success); + return success; +} + +bool JBCAttrSourceFile::PreProcessImpl(const JBCConstPool &constPool) { + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(sourceFileIdx, JBCConstTag::kConstUTF8); + if (constRaw == nullptr) { + return false; + } + constFileName = static_cast(constRaw); + return true; +} + +SimpleXMLElem *JBCAttrSourceFile::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrSourceDebugEx ---------- +JBCAttrSourceDebugEx::JBCAttrSourceDebugEx(const MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrSourceDebugEx, nameIdx, length), + data(nullptr) { + (void) allocator; +} + +JBCAttrSourceDebugEx::~JBCAttrSourceDebugEx() { + data = nullptr; +} + +bool JBCAttrSourceDebugEx::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + bool success = false; + (void) constPool; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + if (length > 0) { + data = static_cast(mp->Malloc(length + 1)); + CHECK_NULL_FATAL(data); + io.ReadBufferChar(data, length, success); + data[length] = 0; + } + return success; +} + +bool JBCAttrSourceDebugEx::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *JBCAttrSourceDebugEx::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrLineNumberTable ---------- +JBCAttrLineNumberTable::JBCAttrLineNumberTable(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrLineNumberTable, nameIdx, length), + size(0), + lineNums(allocator.Adapter()) {} + +bool JBCAttrLineNumberTable::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + size = io.ReadUInt16(success); + for (uint16 i = 0; i < size && success; i++) { + attr::LineNumberTableItem *item = mp->New(); + success = item->ParseFile(allocator, io); + lineNums.push_back(item); + } + return success; +} + +bool JBCAttrLineNumberTable::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *JBCAttrLineNumberTable::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrLocalVariableTable ---------- +JBCAttrLocalVariableTable::JBCAttrLocalVariableTable(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrLocalVariableTable, nameIdx, length), size(0), localVarInfos(allocator.Adapter()) {} + +bool JBCAttrLocalVariableTable::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, + const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + size = io.ReadUInt16(success); + for (uint16 i = 0; i < size && success; i++) { + attr::LocalVariableTableItem *item = mp->New(); + success = item->ParseFile(allocator, io); + localVarInfos.push_back(item); + } + return success; +} + +bool JBCAttrLocalVariableTable::PreProcessImpl(const JBCConstPool &constPool) { + bool success = true; + for (attr::LocalVariableTableItem *info : localVarInfos) { + success = success && info->PreProcess(constPool); + } + return success; +} + +SimpleXMLElem *JBCAttrLocalVariableTable::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrLocalVariableTypeTable ---------- +JBCAttrLocalVariableTypeTable::JBCAttrLocalVariableTypeTable(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrLocalVariableTypeTable, nameIdx, length), size(0), localVarTypeInfos(allocator.Adapter()) {} + +bool JBCAttrLocalVariableTypeTable::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, + const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + size = io.ReadUInt16(success); + for (uint16 i = 0; i < size && success; i++) { + attr::LocalVariableTypeTableItem *item = mp->New(); + success = item->ParseFile(allocator, io); + localVarTypeInfos.push_back(item); + } + return success; +} + +bool JBCAttrLocalVariableTypeTable::PreProcessImpl(const JBCConstPool &constPool) { + bool success = true; + for (attr::LocalVariableTypeTableItem *info : localVarTypeInfos) { + success = success && info->PreProcess(constPool); + } + return success; +} + +SimpleXMLElem *JBCAttrLocalVariableTypeTable::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrDeprecated ---------- +JBCAttrDeprecated::JBCAttrDeprecated(const MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrDeprecated, nameIdx, length) { + (void) allocator; +} + +bool JBCAttrDeprecated::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) allocator; + (void) io; + (void) constPool; + return true; +} + +bool JBCAttrDeprecated::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *JBCAttrDeprecated::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrRTAnnotations ---------- +JBCAttrRTAnnotations::JBCAttrRTAnnotations(MapleAllocator &allocator, JBCAttrKind kindIn, uint16 nameIdx, uint32 length) + : JBCAttr(kindIn, nameIdx, length), size(0), annotations(allocator.Adapter()) {} + +bool JBCAttrRTAnnotations::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + size = io.ReadUInt16(success); + for (uint16 i = 0; i < size && success; i++) { + attr::Annotation *item = mp->New(allocator); + success = item->ParseFile(allocator, io); + annotations.push_back(item); + } + return success; +} + +bool JBCAttrRTAnnotations::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *JBCAttrRTAnnotations::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrRTVisAnnotations ---------- +JBCAttrRTVisAnnotations::JBCAttrRTVisAnnotations(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttrRTAnnotations(allocator, kAttrRTVisAnnotations, nameIdx, length) {} + +// ---------- JBCAttrRTInvisAnnotations ---------- +JBCAttrRTInvisAnnotations::JBCAttrRTInvisAnnotations(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttrRTAnnotations(allocator, kAttrRTInvisAnnotations, nameIdx, length) {} + +// ---------- JBCAttrRTParamAnnotations ---------- +JBCAttrRTParamAnnotations::JBCAttrRTParamAnnotations(MapleAllocator &allocator, JBCAttrKind kindIn, uint16 nameIdx, + uint32 length) + : JBCAttr(kindIn, nameIdx, length), size(0), annotations(allocator.Adapter()) {} + +bool JBCAttrRTParamAnnotations::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, + const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + size = io.ReadUInt8(success); + for (uint16 i = 0; i < size && success; i++) { + attr::ParamAnnotationItem *item = mp->New(allocator); + success = item->ParseFile(allocator, io); + annotations.push_back(item); + } + return success; +} + +bool JBCAttrRTParamAnnotations::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *JBCAttrRTParamAnnotations::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrRTVisParamAnnotations ---------- +JBCAttrRTVisParamAnnotations::JBCAttrRTVisParamAnnotations(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttrRTParamAnnotations(allocator, kAttrRTVisParamAnnotations, nameIdx, length) {} + +// ---------- JBCAttrRTInvisParamAnnotations ---------- +JBCAttrRTInvisParamAnnotations::JBCAttrRTInvisParamAnnotations(MapleAllocator &allocator, uint16 nameIdx, + uint32 length) + : JBCAttrRTParamAnnotations(allocator, kAttrRTInvisParamAnnotations, nameIdx, length) {} + +// ---------- JBCAttrRTTypeAnnotations ---------- +JBCAttrRTTypeAnnotations::JBCAttrRTTypeAnnotations(MapleAllocator &allocator, JBCAttrKind kindIn, uint16 nameIdx, + uint32 length) + : JBCAttr(kindIn, nameIdx, length), size(0), annotations(allocator.Adapter()) {} + +bool JBCAttrRTTypeAnnotations::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, + const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + size = io.ReadUInt16(success); + for (uint16 i = 0; i < size && success; i++) { + attr::TypeAnnotationItem *item = mp->New(allocator); + success = item->ParseFile(allocator, io); + annotations.push_back(item); + } + return success; +} + +bool JBCAttrRTTypeAnnotations::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *JBCAttrRTTypeAnnotations::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrRTVisTypeAnnotations ---------- +JBCAttrRTVisTypeAnnotations::JBCAttrRTVisTypeAnnotations(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttrRTTypeAnnotations(allocator, kAttrRTVisTypeAnnotations, nameIdx, length) {} + +// ---------- JBCAttrRTInvisTypeAnnotations ---------- +JBCAttrRTInvisTypeAnnotations::JBCAttrRTInvisTypeAnnotations(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttrRTTypeAnnotations(allocator, kAttrRTInvisTypeAnnotations, nameIdx, length) {} + +// ---------- JBCAttrAnnotationDefault ---------- +JBCAttrAnnotationDefault::JBCAttrAnnotationDefault(const MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrAnnotationDefault, nameIdx, length), value(nullptr) { + (void) allocator; +} + +JBCAttrAnnotationDefault::~JBCAttrAnnotationDefault() { + value = nullptr; +} + +bool JBCAttrAnnotationDefault::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, + const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + value = mp->New(); + success = value->ParseFile(allocator, io); + return success; +} + +bool JBCAttrAnnotationDefault::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *JBCAttrAnnotationDefault::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrBootstrapMethods ---------- +JBCAttrBootstrapMethods::JBCAttrBootstrapMethods(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrBootstrapMethods, nameIdx, length), size(0), methods(allocator.Adapter()) {} + +bool JBCAttrBootstrapMethods::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + size = io.ReadUInt16(success); + for (uint16 i = 0; i < size && success; i++) { + attr::BootstrapMethodItem *item = mp->New(allocator); + success = item->ParseFile(allocator, io); + methods.push_back(item); + } + return success; +} + +bool JBCAttrBootstrapMethods::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *JBCAttrBootstrapMethods::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCAttrMethodParameters ---------- +JBCAttrMethodParameters::JBCAttrMethodParameters(MapleAllocator &allocator, uint16 nameIdx, uint32 length) + : JBCAttr(kAttrMethodParameters, nameIdx, length), size(0), params(allocator.Adapter()) {} + +bool JBCAttrMethodParameters::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + (void) constPool; + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + size = io.ReadUInt8(success); + for (uint8 i = 0; i < size && success; i++) { + attr::MethodParamItem *item = mp->New(); + success = item->ParseFile(allocator, io); + params.push_back(item); + } + return success; +} + +bool JBCAttrMethodParameters::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *JBCAttrMethodParameters::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} +} // namespace jbc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_attr_item.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_attr_item.cpp new file mode 100644 index 0000000000000000000000000000000000000000..045b3bce202e3e24e8e0e51fc872cf73f23f35f3 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_attr_item.cpp @@ -0,0 +1,1457 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_attr_item.h" +#include "fe_manager.h" + +namespace maple { +namespace jbc { +namespace attr { +inline GStrIdx GetOrCreateGStrIdx(const std::string &str) { + return GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(str); +} + +inline GStrIdx GetOrCreateGStrIdxWithMangler(const std::string &str) { + return GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(str)); +} + +// ---------- ExceptionTableItem ---------- +ExceptionTableItem::ExceptionTableItem() : startPC(0), endPC(0), handlerPC(0), catchTypeIdx(0), catchType(nullptr) {} + +ExceptionTableItem::~ExceptionTableItem() { + catchType = nullptr; +} + +bool ExceptionTableItem::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + startPC = io.ReadUInt16(success); + endPC = io.ReadUInt16(success); + handlerPC = io.ReadUInt16(success); + catchTypeIdx = io.ReadUInt16(success); + return success; +} + +bool ExceptionTableItem::PreProcessImpl(const JBCConstPool &constPool) { + if (catchTypeIdx == 0) { + return true; + } + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(catchTypeIdx, kConstClass); + if (constRaw == nullptr) { + catchType = nullptr; + return false; + } else { + catchType = static_cast(constRaw); + return true; + } +} + +SimpleXMLElem *ExceptionTableItem::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- VerificationTypeInfo ---------- +std::map VerificationTypeInfo::tagNameMap = + VerificationTypeInfo::InitTagNameMap(); + +VerificationTypeInfo::VerificationTypeInfo() + : tag(kVerTypeInfoItemUnknown), + classInfo(nullptr) { + data.raw = 0; +} + +VerificationTypeInfo::~VerificationTypeInfo() { + classInfo = nullptr; +} + +bool VerificationTypeInfo::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + uint8 t = io.ReadUInt8(success); + tag = static_cast(t); + switch (t) { + case kVerTypeInfoItemTop: + case kVerTypeInfoItemInteger: + case kVerTypeInfoItemFloat: + case kVerTypeInfoItemDouble: + case kVerTypeInfoItemLong: + case kVerTypeInfoItemNull: + case kVerTypeInfoItemUninitializedThis: + break; + case kVerTypeInfoItemObject: + data.cpoolIdx = io.ReadUInt16(success); + break; + case kVerTypeInfoItemUninitialized: + data.offset = io.ReadUInt16(success); + break; + default: + ERR(kLncErr, "undefined tag %d for verification_type_info", tag); + return false; + } + return success; +} + +bool VerificationTypeInfo::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *VerificationTypeInfo::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +std::map VerificationTypeInfo::InitTagNameMap() { + std::map result; + result[kVerTypeInfoItemTop] = "ITEM_Top"; + result[kVerTypeInfoItemInteger] = "ITEM_Integer"; + result[kVerTypeInfoItemFloat] = "ITEM_Float"; + result[kVerTypeInfoItemDouble] = "ITEM_Double"; + result[kVerTypeInfoItemLong] = "ITEM_Long"; + result[kVerTypeInfoItemNull] = "ITEM_Null"; + result[kVerTypeInfoItemUninitializedThis] = "ITEM_UninitializedThis"; + result[kVerTypeInfoItemObject] = "ITEM_Object"; + result[kVerTypeInfoItemUninitialized] = "ITEM_Uninitialized"; + return result; +} + +std::string VerificationTypeInfo::TagName(VerificationTypeInfoTag t) { + std::map::const_iterator it = tagNameMap.find(t); + if (it != tagNameMap.end()) { + return it->second; + } + return "ITEM_Unknown"; +} + +// ---------- StackMapFrameItem ---------- +std::map StackMapFrameItem::tagNameMap = StackMapFrameItem::InitTagName(); + +StackMapFrameItem::StackMapFrameItem(uint8 frameTypeIn, StackMapFrameItemTag tagIn) + : tag(tagIn), frameType(frameTypeIn) {} + +std::map StackMapFrameItem::InitTagName() { + std::map result; + result[kStackSame] = "SAME"; + result[kStackSameLocals1StackItem] = "SAME_LOCALS_1_STACK_ITEM"; + result[kStackSameLocals1StackItemEx] = "SAME_LOCALS_1_STACK_ITEM_EXTENDED"; + result[kStackChop] = "CHOP"; + result[kStackSameFrameEx] = "SAME_FRAME_EXTENDED"; + result[kStackAppend] = "APPEND"; + result[kStackFullFrame] = "FULL_FRAME"; + result[kStackReserved] = "RESERVED"; + return result; +} + +std::string StackMapFrameItem::TagName(StackMapFrameItemTag tag) { + std::map::const_iterator it = tagNameMap.find(tag); + if (it != tagNameMap.end()) { + return it->second; + } + return "UNKNOWN"; +} + +StackMapFrameItemTag StackMapFrameItem::FrameType2Tag(uint8 frameType) { + // frame type tag : 64, 128, 247, 251, 255 + if (frameType < 64) { + return kStackSame; + } else if (frameType < 128) { + return kStackSameLocals1StackItem; + } else if (frameType < 247) { + ERR(kLncErr, "Reserved frametype %d for stack_map_frame", frameType); + return kStackReserved; + } else if (frameType == 247) { + return kStackSameLocals1StackItemEx; + } else if (frameType < 251) { + return kStackChop; + } else if (frameType < 255) { + return kStackAppend; + } else { + return kStackFullFrame; + } +} + +StackMapFrameItem *StackMapFrameItem::NewItem(MapleAllocator &allocator, BasicIORead &io, uint8 frameType) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + StackMapFrameItem *item = nullptr; + StackMapFrameItemTag tag = StackMapFrameItem::FrameType2Tag(frameType); + switch (tag) { + case kStackSame: + item = mp->New(frameType); + break; + case kStackSameLocals1StackItem: + item = mp->New(frameType); + break; + case kStackSameLocals1StackItemEx: + item = mp->New(frameType); + break; + case kStackChop: + item = mp->New(frameType); + break; + case kStackSameFrameEx: + item = mp->New(frameType); + break; + case kStackAppend: + item = mp->New(allocator, frameType); + break; + case kStackFullFrame: + item = mp->New(allocator, frameType); + break; + default: + CHECK_FATAL(false, "Should not run here"); + } + if (!item->ParseFile(allocator, io)) { + CHECK_FATAL(false, "Failed to new StackMapFrame item"); + return nullptr; + } + return item; +} + +// ---------- StackMapFrameItemSame ---------- +StackMapFrameItemSame::StackMapFrameItemSame(uint8 frameType) : StackMapFrameItem(frameType, kStackSame) {} + +bool StackMapFrameItemSame::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + (void) io; + return true; +} + +bool StackMapFrameItemSame::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *StackMapFrameItemSame::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- StackMapFrameItemSameLocals1 ---------- +StackMapFrameItemSameLocals1::StackMapFrameItemSameLocals1(uint8 frameType) + : StackMapFrameItem(frameType, kStackSameLocals1StackItem), + stack(nullptr) {} + +StackMapFrameItemSameLocals1::~StackMapFrameItemSameLocals1() { + stack = nullptr; +} + +bool StackMapFrameItemSameLocals1::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + stack = mp->New(); + return stack->ParseFile(allocator, io); +} + +bool StackMapFrameItemSameLocals1::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *StackMapFrameItemSameLocals1::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- StackMapFrameItemSameLocals1Ex ---------- +StackMapFrameItemSameLocals1Ex::StackMapFrameItemSameLocals1Ex(uint8 frameType) + : StackMapFrameItem(frameType, kStackSameLocals1StackItemEx), + offsetDelta(0), + stack(nullptr) {} + +StackMapFrameItemSameLocals1Ex::~StackMapFrameItemSameLocals1Ex() { + stack = nullptr; +} + +bool StackMapFrameItemSameLocals1Ex::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + offsetDelta = io.ReadUInt16(success); + stack = mp->New(); + success = stack->ParseFile(allocator, io); + return success; +} + +bool StackMapFrameItemSameLocals1Ex::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *StackMapFrameItemSameLocals1Ex::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- StackMapFrameItemChop ---------- +StackMapFrameItemChop::StackMapFrameItemChop(uint8 frameType) + : StackMapFrameItem(frameType, kStackChop), + offsetDelta(0) {} + +bool StackMapFrameItemChop::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + offsetDelta = io.ReadUInt16(success); + return success; +} + +bool StackMapFrameItemChop::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *StackMapFrameItemChop::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- StackMapFrameItemSameEx ---------- +StackMapFrameItemSameEx::StackMapFrameItemSameEx(uint8 frameType) + : StackMapFrameItem(frameType, kStackSameFrameEx), + offsetDelta(0) {} + +bool StackMapFrameItemSameEx::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + offsetDelta = io.ReadUInt16(success); + return success; +} + +bool StackMapFrameItemSameEx::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *StackMapFrameItemSameEx::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- StackMapFrameItemAppend ---------- +StackMapFrameItemAppend::StackMapFrameItemAppend(MapleAllocator &allocator, uint8 frameType) + : StackMapFrameItem(frameType, kStackAppend), + offsetDelta(0), + locals(allocator.Adapter()) {} + +bool StackMapFrameItemAppend::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + offsetDelta = io.ReadUInt16(success); + for (uint8 i = 0; i < frameType - 251; i++) { // 251 : frame type tag + VerificationTypeInfo *local = mp->New(); + success = local->ParseFile(allocator, io); + locals.push_back(local); + } + return success; +} + +bool StackMapFrameItemAppend::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *StackMapFrameItemAppend::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- StackMapFrameItemFull ---------- +StackMapFrameItemFull::StackMapFrameItemFull(MapleAllocator &allocator, uint8 frameType) + : StackMapFrameItem(frameType, kStackFullFrame), + offsetDelta(0), + nLocals(0), + locals(allocator.Adapter()), + nStacks(0), + stacks(allocator.Adapter()) {} + +bool StackMapFrameItemFull::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + offsetDelta = io.ReadUInt16(success); + nLocals = io.ReadUInt16(success); + for (uint32 i = 0; i < nLocals; i++) { + VerificationTypeInfo *local = mp->New(); + success = local->ParseFile(allocator, io); + locals.push_back(local); + } + nStacks = io.ReadUInt16(success); + for (uint32 i = 0; i < nStacks; i++) { + VerificationTypeInfo *stack = mp->New(); + success = stack->ParseFile(allocator, io); + stacks.push_back(stack); + } + return success; +} + +bool StackMapFrameItemFull::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *StackMapFrameItemFull::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- InnerClassItem ---------- +InnerClassItem::InnerClassItem() + : innerClassInfoIdx(0), + outerClassInfoIdx(0), + innerNameIdx(0), + innerClassAccessFlag(0), + constClassInner(nullptr), + constClassOuter(nullptr), + constNameInner(nullptr) {} + +InnerClassItem::~InnerClassItem() { + constClassInner = nullptr; + constClassOuter = nullptr; + constNameInner = nullptr; +} + +bool InnerClassItem::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + innerClassInfoIdx = io.ReadUInt16(success); + outerClassInfoIdx = io.ReadUInt16(success); + innerNameIdx = io.ReadUInt16(success); + innerClassAccessFlag = io.ReadUInt16(success); + return success; +} + +bool InnerClassItem::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *InnerClassItem::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- LineNumberTableItem ---------- +LineNumberTableItem::LineNumberTableItem() : startPC(0), lineNumber(0) {} + +bool LineNumberTableItem::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + startPC = io.ReadUInt16(success); + lineNumber = io.ReadUInt16(success); + return success; +} + +bool LineNumberTableItem::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *LineNumberTableItem::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- LocalVariableTableItem ---------- +LocalVariableTableItem::LocalVariableTableItem() + : startPC(0), + length(0), + nameIdx(0), + descIdx(0), + index(0), + constName(nullptr), + constDesc(nullptr), + nameIdxMpl(0), + feirType(nullptr) {} + +LocalVariableTableItem::~LocalVariableTableItem() { + constName = nullptr; + constDesc = nullptr; + feirType = nullptr; +} + +bool LocalVariableTableItem::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + startPC = io.ReadUInt16(success); + length = io.ReadUInt16(success); + nameIdx = io.ReadUInt16(success); + descIdx = io.ReadUInt16(success); + index = io.ReadUInt16(success); + return success; +} + +bool LocalVariableTableItem::PreProcessImpl(const JBCConstPool &constPool) { + constName = static_cast(constPool.GetConstByIdxWithTag(nameIdx, JBCConstTag::kConstUTF8)); + constDesc = static_cast(constPool.GetConstByIdxWithTag(descIdx, JBCConstTag::kConstUTF8)); + if (constName == nullptr || constDesc == nullptr) { + return false; + } + nameIdxMpl = GetOrCreateGStrIdx(constName->GetString()); + feirType = FEManager::GetTypeManager().GetOrCreateFEIRTypeByName(namemangler::EncodeName(constDesc->GetString()), + GStrIdx(0), kSrcLangJava); + return true; +} + +SimpleXMLElem *LocalVariableTableItem::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- LocalVariableTypeTableItem ---------- +LocalVariableTypeTableItem::LocalVariableTypeTableItem() + : startPC(0), + length(0), + nameIdx(0), + signatureIdx(0), + index(0), + constName(nullptr), + constSignature(nullptr), + nameIdxMpl(0) {} + +LocalVariableTypeTableItem::~LocalVariableTypeTableItem() { + constName = nullptr; + constSignature = nullptr; +} + +bool LocalVariableTypeTableItem::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + startPC = io.ReadUInt16(success); + length = io.ReadUInt16(success); + nameIdx = io.ReadUInt16(success); + signatureIdx = io.ReadUInt16(success); + index = io.ReadUInt16(success); + return success; +} + +bool LocalVariableTypeTableItem::PreProcessImpl(const JBCConstPool &constPool) { + constName = static_cast(constPool.GetConstByIdxWithTag(nameIdx, JBCConstTag::kConstUTF8)); + constSignature = + static_cast(constPool.GetConstByIdxWithTag(signatureIdx, JBCConstTag::kConstUTF8)); + if (constName == nullptr || constSignature == nullptr) { + return false; + } + nameIdxMpl = GetOrCreateGStrIdx(constName->GetString()); + return true; +} + +SimpleXMLElem *LocalVariableTypeTableItem::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- ParamAnnotationItem ---------- +ParamAnnotationItem::ParamAnnotationItem(MapleAllocator &allocator) + : count(0), annotations(allocator.Adapter()) {} + +bool ParamAnnotationItem::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + count = io.ReadUInt16(success); + for (uint16 i = 0; i < count; i++) { + Annotation *anno = mp->New(allocator); + success = anno->ParseFile(allocator, io); + annotations.push_back(anno); + } + return success; +} + +bool ParamAnnotationItem::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *ParamAnnotationItem::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- BootstrapMethodItem ---------- +BootstrapMethodItem::BootstrapMethodItem(MapleAllocator &allocator) + : methodRefIdx(0), + nArgs(0), + argsIdx(allocator.Adapter()), + methodHandle(nullptr), + args(allocator.Adapter()) {} + +BootstrapMethodItem::~BootstrapMethodItem() { + methodHandle = nullptr; +} + +bool BootstrapMethodItem::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + methodRefIdx = io.ReadUInt16(success); + nArgs = io.ReadUInt16(success); + for (uint16 i = 0; i < nArgs; i++) { + uint16 idx = io.ReadUInt16(success); + argsIdx.push_back(idx); + } + return success; +} + +bool BootstrapMethodItem::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *BootstrapMethodItem::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- MethodParamItem ---------- +MethodParamItem::MethodParamItem() + : nameIdx(0), accessFlag(0), constName(nullptr) {} + +MethodParamItem::~MethodParamItem() { + constName = nullptr; +} + +bool MethodParamItem::MethodParamItem::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + nameIdx = io.ReadUInt16(success); + accessFlag = io.ReadUInt16(success); + return success; +} + +bool MethodParamItem::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *MethodParamItem::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- Annotation ---------- +Annotation::Annotation(MapleAllocator &allocator) + : typeIdx(0), nElemPairs(0), tbElemPairs(allocator.Adapter()), constTypeName(nullptr) {} + +Annotation::~Annotation() { + constTypeName = nullptr; +} + +bool Annotation::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + typeIdx = io.ReadUInt16(success); + nElemPairs = io.ReadUInt16(success); + for (uint16 i = 0; i < nElemPairs; i++) { + ElementValuePair *pair = mp->New(); + success = pair->ParseFile(allocator, io); + tbElemPairs.push_back(pair); + } + return success; +} + +bool Annotation::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *Annotation::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- ElementValueItem ---------- +std::map ElementValueItem::tagKindMap = ElementValueItem::InitTagKindMap(); +std::map ElementValueItem::kindNameMap = ElementValueItem::InitKindNameMap(); + +ElementValueItem::ElementValueItem(ElementValueKind kindIn, char tagIn) : kind(kindIn), tag(tagIn) {} + +std::map ElementValueItem::InitTagKindMap() { + std::map result; + result['B'] = kElementValueConst; + result['C'] = kElementValueConst; + result['D'] = kElementValueConst; + result['F'] = kElementValueConst; + result['I'] = kElementValueConst; + result['J'] = kElementValueConst; + result['S'] = kElementValueConst; + result['Z'] = kElementValueConst; + result['s'] = kElementValueConst; + result['e'] = kElementValueEnum; + result['c'] = kElementValueClassInfo; + result['@'] = kElementValueAnnotation; + result['['] = kElementValueArray; + return result; +} + +std::map ElementValueItem::InitKindNameMap() { + std::map result; + result[kElementValueConst] = "ElementValueConst"; + result[kElementValueEnum] = "ElementValueEnum"; + result[kElementValueClassInfo] = "ElementValueClassInfo"; + result[kElementValueAnnotation] = "ElementValueAnnotation"; + result[kElementValueArray] = "ElementValueArray"; + return result; +} + +std::string ElementValueItem::KindName(ElementValueKind kind) { + std::map::const_iterator it = kindNameMap.find(kind); + if (it != kindNameMap.end()) { + return it->second; + } + return "Unknown"; +} + +ElementValueKind ElementValueItem::TagToKind(char tag) { + std::map::const_iterator it = tagKindMap.find(tag); + if (it != tagKindMap.end()) { + return it->second; + } + return kElementValueDefault; +} + +ElementValueItem *ElementValueItem::NewItem(MapleAllocator &allocator, BasicIORead &io, char tag) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + ElementValueKind kind = ElementValueItem::TagToKind(tag); + ElementValueItem *item = nullptr; + switch (kind) { + case kElementValueConst: + item = mp->New(tag); + break; + case kElementValueEnum: + item = mp->New(); + break; + case kElementValueClassInfo: + item = mp->New(); + break; + case kElementValueAnnotation: + item = mp->New(); + break; + case kElementValueArray: + item = mp->New(allocator); + break; + default: + ERR(kLncErr, "unsupported kind"); + return nullptr; + } + if (item->ParseFile(allocator, io) == false) { + return nullptr; + } + return item; +} + +// ---------- ElementValueConst ---------- +ElementValueConst::ElementValueConst(uint8 t) + : ElementValueItem(kElementValueConst, t), constValueIdx(0), constValue(nullptr) {} + +ElementValueConst::~ElementValueConst() { + constValue = nullptr; +} + +bool ElementValueConst::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + constValueIdx = io.ReadUInt16(success); + return success; +} + +bool ElementValueConst::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *ElementValueConst::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- ElementValueEnum ---------- +ElementValueEnum::ElementValueEnum() + : ElementValueItem(kElementValueEnum, 'e'), + typeNameIdx(0), + constNameIdx(0), + constTypeName(nullptr), + constName(nullptr) {} + +ElementValueEnum::~ElementValueEnum() { + constTypeName = nullptr; + constName = nullptr; +} + +bool ElementValueEnum::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + typeNameIdx = io.ReadUInt16(success); + constNameIdx = io.ReadUInt16(success); + return success; +} + +bool ElementValueEnum::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *ElementValueEnum::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- ElementValueClassInfo ---------- +ElementValueClassInfo::ElementValueClassInfo() + : ElementValueItem(kElementValueClassInfo, 'c'), + classInfoIdx(0), + constClassInfo(nullptr) {} + +ElementValueClassInfo::~ElementValueClassInfo() { + constClassInfo = nullptr; +} + +bool ElementValueClassInfo::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + classInfoIdx = io.ReadUInt16(success); + return success; +} + +bool ElementValueClassInfo::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *ElementValueClassInfo::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- ElementValueAnnotation ---------- +ElementValueAnnotation::ElementValueAnnotation() + : ElementValueItem(kElementValueAnnotation, '@'), annotation(nullptr) {} + +ElementValueAnnotation::~ElementValueAnnotation() { + annotation = nullptr; +} + +bool ElementValueAnnotation::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + annotation = mp->New(allocator); + return annotation->ParseFile(allocator, io); +} + +bool ElementValueAnnotation::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *ElementValueAnnotation::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- ElementValueArray ---------- +ElementValueArray::ElementValueArray(MapleAllocator &allocator) + : ElementValueItem(kElementValueArray, '['), size(0), values(allocator.Adapter()) {} + +bool ElementValueArray::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + size = io.ReadUInt16(success); + for (uint16 i = 0; i < size; i++) { + ElementValue *elem = mp->New(); + success = elem->ParseFile(allocator, io); + values.push_back(elem); + } + return success; +} + +bool ElementValueArray::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *ElementValueArray::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- ElementValue ---------- +ElementValue::ElementValue() + : tag('\0'), kind(kElementValueDefault), value(nullptr) {} + +ElementValue::~ElementValue() { + value = nullptr; +} + +bool ElementValue::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + bool success = false; + tag = io.ReadChar(success); + value = ElementValueItem::NewItem(allocator, io, tag); + return success && value != nullptr; +} + +bool ElementValue::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return false; +} + +SimpleXMLElem *ElementValue::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- ElementValuePair ---------- +ElementValuePair::ElementValuePair() + : nameIdx(0), value(nullptr) {} + +ElementValuePair::~ElementValuePair() { + value = nullptr; +} + +bool ElementValuePair::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + nameIdx = io.ReadUInt16(success); + value = mp->New(); + return (success && value->ParseFile(allocator, io)); +} + +bool ElementValuePair::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *ElementValuePair::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TargetInfoItem ---------- +std::map TargetInfoItem::typeTagMap = TargetInfoItem::InitTypeTagMap(); + +TargetInfoItem::TargetInfoItem(TargetInfoItemTag tagIn) : tag(tagIn) {} + +std::map TargetInfoItem::InitTypeTagMap() { + std::map result; + result[kTargetTypeParamClass] = kTargetTagTypeParam; + result[kTargetTypeParamMethod] = kTargetTagTypeParam; + result[kTargetTypeHierarchy] = kTargetTagSuperType; + result[kTargetTypeBoundClass] = kTargetTagTypeParamBound; + result[kTargetTypeBoundMethod] = kTargetTagTypeParamBound; + result[kTargetTypeFieldDecl] = kTargetTagEmpty; + result[kTargetTypeReturn] = kTargetTagEmpty; + result[kTargetTypeReceiver] = kTargetTagEmpty; + result[kTargetTypeFormal] = kTargetTagFormalParam; + result[kTargetTypeThrows] = kTargetTagThrows; + result[kTargetTypeLocalVar] = kTargetTagLocalVar; + result[kTargetTypeResourceVar] = kTargetTagLocalVar; + result[kTargetTypeExpectionParam] = kTargetTagCatch; + result[kTargetTypeInstanceof] = kTargetTagOffset; + result[kTargetTypeNew] = kTargetTagOffset; + result[kTargetTypeMethodRefNew] = kTargetTagOffset; + result[kTargetTypeMethodRefIdentifier] = kTargetTagOffset; + result[kTargetTypeCast] = kTargetTagTypeArg; + result[kTargetTypeConstructorInvoke] = kTargetTagTypeArg; + result[kTargetTypeMethodInvoke] = kTargetTagTypeArg; + result[kTargetTypeConstructorNew] = kTargetTagTypeArg; + result[kTargetTypeConstructorIdentifier] = kTargetTagTypeArg; + return result; +} + +TargetInfoItemTag TargetInfoItem::TargetType2Tag(TargetInfoItemType type) { + std::map::const_iterator it = typeTagMap.find(type); + if (it != typeTagMap.end()) { + return it->second; + } + return kTargetTagUndefine; +} + +TargetInfoItem *TargetInfoItem::NewItem(MapleAllocator &allocator, BasicIORead &io, TargetInfoItemType targetType) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + TargetInfoItemTag tag = TargetInfoItem::TargetType2Tag(targetType); + TargetInfoItem *item = nullptr; + switch (tag) { + case kTargetTagTypeParam: + item = mp->New(); + break; + case kTargetTagSuperType: + item = mp->New(); + break; + case kTargetTagTypeParamBound: + item = mp->New(); + break; + case kTargetTagEmpty: + item = mp->New(); + break; + case kTargetTagFormalParam: + item = mp->New(); + break; + case kTargetTagThrows: + item = mp->New(); + break; + case kTargetTagLocalVar: + item = mp->New(allocator); + break; + case kTargetTagCatch: + item = mp->New(); + break; + case kTargetTagOffset: + item = mp->New(); + break; + case kTargetTagTypeArg: + item = mp->New(); + break; + default: + ERR(kLncErr, "TargetInfoItem::NewItem(): undefined tag"); + return nullptr; + } + if (item->ParseFile(allocator, io) == false) { + return nullptr; + } + return item; +} + +// ---------- TargetTypeParam ---------- +TargetTypeParam::TargetTypeParam() : TargetInfoItem(kTargetTagTypeParam), paramIdx(0) {} + +bool TargetTypeParam::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + paramIdx = io.ReadUInt8(success); + return success; +} + +bool TargetTypeParam::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TargetTypeParam::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TargetSuperType ---------- +TargetSuperType::TargetSuperType() : TargetInfoItem(kTargetTagSuperType), index(0) {} + +bool TargetSuperType::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + index = io.ReadUInt16(success); + return success; +} + +bool TargetSuperType::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TargetSuperType::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TargetTypeParamBound ---------- +TargetTypeParamBound::TargetTypeParamBound() : TargetInfoItem(kTargetTagTypeParamBound), paramIdx(0), boundIdx(0) {} + +bool TargetTypeParamBound::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + paramIdx = io.ReadUInt8(success); + boundIdx = io.ReadUInt8(success); + return success; +} + +bool TargetTypeParamBound::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TargetTypeParamBound::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TargetEmpty ---------- +TargetEmpty::TargetEmpty() : TargetInfoItem(kTargetTagEmpty) {} + +bool TargetEmpty::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + (void) io; + return true; +} + +bool TargetEmpty::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TargetEmpty::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TargetFormalParam ---------- +TargetFormalParam::TargetFormalParam() : TargetInfoItem(kTargetTagFormalParam), paramIdx(0) {} + +bool TargetFormalParam::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + paramIdx = io.ReadUInt8(success); + return success; +} + +bool TargetFormalParam::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TargetFormalParam::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TargetThrows ---------- +TargetThrows::TargetThrows() : TargetInfoItem(kTargetTagThrows), typeIdx(0) {} + +bool TargetThrows::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + typeIdx = io.ReadUInt16(success); + return success; +} + +bool TargetThrows::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TargetThrows::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TargetLocalVarItem ---------- +TargetLocalVarItem::TargetLocalVarItem() : TargetInfoItem(kTargetTagLocalVar), startPC(0), length(0), index(0) {} + +bool TargetLocalVarItem::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + startPC = io.ReadUInt16(success); + length = io.ReadUInt16(success); + index = io.ReadUInt16(success); + return success; +} +bool TargetLocalVarItem::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TargetLocalVarItem::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TargetLocalVar ---------- +TargetLocalVar::TargetLocalVar(MapleAllocator &allocator) + : TargetInfoItem(kTargetTagLocalVar), size(0), table(allocator.Adapter()) {} + +bool TargetLocalVar::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + size = io.ReadUInt16(success); + for (uint16 i = 0; i < size; i++) { + TargetLocalVarItem *item = mp->New(); + success = item->ParseFile(allocator, io); + table.push_back(item); + } + return success; +} + +bool TargetLocalVar::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TargetLocalVar::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TargetCatch ---------- +TargetCatch::TargetCatch() : TargetInfoItem(kTargetTagCatch), exTableIdx(0) {} + +bool TargetCatch::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + exTableIdx = io.ReadUInt16(success); + return true; +} + +bool TargetCatch::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TargetCatch::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TargetOffset ---------- +TargetOffset::TargetOffset() : TargetInfoItem(kTargetTagOffset), offset(0) {} + +bool TargetOffset::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + offset = io.ReadUInt16(success); + return success; +} + +bool TargetOffset::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TargetOffset::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TargetTypeArg ---------- +TargetTypeArg::TargetTypeArg() : TargetInfoItem(kTargetTagTypeArg), offset(0), typeArgIdx(0) {} + +bool TargetTypeArg::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + offset = io.ReadUInt16(success); + typeArgIdx = io.ReadUInt8(success); + return success; +} + +bool TargetTypeArg::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TargetTypeArg::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TypeAnnotationItem ---------- +TypeAnnotationItem::TypeAnnotationItem(MapleAllocator &allocator) + : targetType(kTargetTypeParamClass), + targetInfo(nullptr), + targetPath(nullptr), + typeIdx(0), + nElemPairs(0), + elemPairs(allocator.Adapter()) {} + +TypeAnnotationItem::~TypeAnnotationItem() { + targetInfo = nullptr; + targetPath = nullptr; +} + +bool TypeAnnotationItem::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + targetType = static_cast(io.ReadUInt8(success)); + targetInfo = TargetInfoItem::NewItem(allocator, io, targetType); + targetPath = mp->New(allocator); + success = targetPath->ParseFile(allocator, io); + typeIdx = io.ReadUInt16(success); + nElemPairs = io.ReadUInt16(success); + for (uint16 i = 0; i < nElemPairs; i++) { + ElementValuePair *e = mp->New(); + success = e->ParseFile(allocator, io); + elemPairs.push_back(e); + } + return success; +} + +bool TypeAnnotationItem::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TypeAnnotationItem::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TypePathItem ---------- +TypePathItem::TypePathItem() : typePathKind(0), typeArgIdx(0) {} + +bool TypePathItem::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + (void) allocator; + bool success = false; + typePathKind = io.ReadUInt8(success); + typeArgIdx = io.ReadUInt8(success); + return success; +} + +bool TypePathItem::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TypePathItem::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, + uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- TypePath ---------- +TypePath::TypePath(MapleAllocator &allocator) : pathLength(0), tbPath(allocator.Adapter()) {} + +bool TypePath::ParseFileImpl(MapleAllocator &allocator, BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + pathLength = io.ReadUInt8(success); + for (uint8 i = 0; i < pathLength; i++) { + TypePathItem *path = mp->New(); + success = path->ParseFile(allocator, io); + tbPath.push_back(path); + } + return success; +} + +bool TypePath::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *TypePath::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) const { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} +} // namespace attr +} // namespace jbc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_bb.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_bb.cpp new file mode 100644 index 0000000000000000000000000000000000000000..784431e2fd4faf77679857b5b972a936572b53db --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_bb.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_bb.h" +#include "jbc_stmt.h" +#include "jbc_function.h" + +namespace maple { +JBCBB::JBCBB(const jbc::JBCConstPool &argConstPool) + : JBCBB(FEIRBBKind::kBBKindDefault, argConstPool) {} + +JBCBB::JBCBB(uint8 argBBKind, const jbc::JBCConstPool &argConstPool) + : FEIRBB(argBBKind), + constPool(argConstPool), + stackError(false), + stackInUpdated(false), + stackOutUpdated(false), + updatePredEnd(false) {} + +bool JBCBB::InitForFuncHeader() { + updatePredEnd = true; + stackInUpdated = true; + return UpdateStack(); +} + +bool JBCBB::InitForCatch() { + updatePredEnd = true; + stackInUpdated = true; + minStackIn.PushItem(jbc::JBCPrimType::kTypeRef); + return UpdateStack(); +} + +bool JBCBB::UpdateStack() { + minStackOut.CopyFrom(minStackIn); + const JBCStmt *stmt = static_cast(stmtHead); + while (stmt != nullptr) { + JBCStmtKind kind = stmt->GetJBCKind(); + if (kind == JBCStmtKind::kJBCStmtInst) { + const JBCStmtInst *stmtInst = static_cast(stmt); + const jbc::JBCOp &op = stmtInst->GetOp(); + stackError = stackError || (!minStackOut.StackChange(op, constPool)); + } else if (kind == JBCStmtKind::kJBCStmtInstBranch) { + const JBCStmtInstBranch *stmtInstBranch = static_cast(stmt); + const jbc::JBCOp &op = stmtInstBranch->GetOp(); + stackError = stackError || (!minStackOut.StackChange(op, constPool)); + } + if (stackError) { + return false; + } + if (stmt == stmtTail) { + break; + } + const FELinkListNode *node = stmt->GetNext(); + stmt = static_cast(node); + } + stackOutUpdated = true; + return true; +} + +bool JBCBB::UpdateStackByPredBB(const JBCBB &bb) { + if (bb.stackError) { + return false; + } + if (!bb.stackOutUpdated) { + return true; + } + if (!stackInUpdated) { + minStackIn.CopyFrom(bb.minStackOut); + stackInUpdated = true; + return UpdateStack(); + } + if (!minStackIn.EqualTo(bb.minStackOut)) { + stackError = true; + return false; + } + return true; +} + +bool JBCBB::UpdateStackByPredBBEnd() const { + return updatePredEnd; +} + +bool JBCBB::CheckStack() { + if (!stackInUpdated || !stackOutUpdated) { + return false; + } + if (stackError) { + return false; + } + for (FEIRBB *bb : GetPredBBs()) { + if (bb->GetBBKind() == FEIRBBKind::kBBKindPesudoHead) { + continue; + } + if (bb->GetBBKind() == JBCBBPesudoCatchPred::kBBKindPesudoCatchPred) { + continue; + } + JBCBB *jbcBB = static_cast(bb); + if (!minStackIn.EqualTo(jbcBB->minStackOut)) { + return false; + } + } + return true; +} + +void JBCBB::Dump() const { + std::cout << "FEIRBB (id=" << GetID() << ", kind=" << GetBBKindName() << + ", preds={"; + for (FEIRBB *bb : GetPredBBs()) { + if (bb->GetBBKind() == FEIRBBKind::kBBKindPesudoHead) { + std::cout << "FuncHead "; + } else if (bb->GetBBKind() == JBCBBPesudoCatchPred::kBBKindPesudoCatchPred) { + std::cout << "CatchPred "; + } else { + std::cout << bb->GetID() << " "; + } + } + std::cout << "}, succs={"; + for (FEIRBB *bb : GetSuccBBs()) { + std::cout << bb->GetID() << " "; + } + std::cout << "})" << std::endl; + std::cout << " StackIn (" << (stackInUpdated ? "updated" : "") << "): "; + minStackIn.Dump(); + std::cout << std::endl; + const FELinkListNode *nodeStmt = GetStmtHead(); + while (nodeStmt != nullptr) { + const FEIRStmt *stmt = static_cast(nodeStmt); + stmt->Dump(" "); + if (nodeStmt == stmtTail) { + break; + } + nodeStmt = nodeStmt->GetNext(); + } + std::cout << " StackOut (" << (stackOutUpdated ? "updated" : "") << "): "; + minStackOut.Dump(); + std::cout << std::endl; +} + +uint32 JBCBB::GetSwapSize() const { + uint32 sizeIn = minStackIn.GetStackSize(); + uint32 sizeOut = minStackOut.GetStackSize(); + return sizeIn > sizeOut ? sizeIn : sizeOut; +} +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_class.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_class.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7bf92f7d9e63e5890ea95d85cd9a132be4dce755 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_class.cpp @@ -0,0 +1,351 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_class.h" +#include + +namespace maple { +namespace { +const uint32 kMagicJVMClass = 0xCAFEBABE; +const uint32 kJavaClassNoIndex = 0; +} + +namespace jbc { +// ---------- JBCClassElem ---------- +JBCClassElem::JBCClassElem(MapleAllocator &allocator, const JBCClass &argKlass) + : klass(argKlass), + accessFlag(0), + nameIdx(0), + descIdx(0), + nAttr(0), + attrs(allocator.Adapter()), + attrMap(allocator) {} + +bool JBCClassElem::ParseFile(MapleAllocator &allocator, BasicIORead &io, const JBCConstPool &constPool) { + bool success = false; + accessFlag = io.ReadUInt16(success); + nameIdx = io.ReadUInt16(success); + descIdx = io.ReadUInt16(success); + nAttr = io.ReadUInt16(success); + for (uint16 i = 0; i < nAttr; i++) { + JBCAttr *attr = JBCAttr::InAttr(allocator, io, constPool); + if (attr == nullptr) { + return false; + } + attrs.push_back(attr); + attrMap.RegisterAttr(*attr); + } + return true; +} + +std::string JBCClassElem::GetClassName() const { + return klass.GetClassNameOrin(); +} + +const JBCConstPool &JBCClassElem::GetConstPool() const { + return klass.GetConstPool(); +} + +std::string JBCClassElem::GetFullName() const { + std::stringstream ss; + ss << GetClassName() << "|" << GetName() << "|" << GetDescription(); + return ss.str(); +} + +// ---------- JBCClassField ---------- +JBCClassField::JBCClassField(MapleAllocator &allocator, const JBCClass &argKlass) + : JBCClassElem(allocator, argKlass) {} + +SimpleXMLElem *JBCClassField::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +// ---------- JBCClassMethod ---------- +JBCClassMethod::JBCClassMethod(MapleAllocator &allocator, const JBCClass &argKlass) + : JBCClassElem(allocator, argKlass) {} + +SimpleXMLElem *JBCClassMethod::GenXmlElemImpl(MapleAllocator &allocator, const JBCConstPool &constPool, uint32 idx) { + (void) allocator; + (void) constPool; + (void) idx; + return nullptr; +} + +bool JBCClassMethod::PreProcess() { + bool success = true; + for (JBCAttr *attr : attrs) { + switch (attr->GetKind()) { + case kAttrCode: + case kAttrLocalVariableTable: + case kAttrLocalVariableTypeTable: + success = success && attr->PreProcess(klass.GetConstPool()); + break; + default: + break; + } + } + return success; +} + +const JBCAttrCode *JBCClassMethod::GetCode() const { + return static_cast(attrMap.GetAttr(jbc::JBCAttrKind::kAttrCode)); +} + +bool JBCClassMethod::IsVirtual() const { + std::string classNameOrg = GetClass().GetClassNameOrin(); + CHECK_FATAL(classNameOrg.length() > 2, "Invalid calss name: %s", classNameOrg.c_str()); // LclassName; + std::string className = classNameOrg.substr(1, classNameOrg.length() - 2); + return (accessFlag & kAccMethodFinal) == 0 && (accessFlag & kAccMethodPrivate) == 0 && + (accessFlag & kAccMethodProtected) == 0 && (accessFlag & kAccMethodStatic) == 0 && + GetName().compare(className) != 0 && GetName().compare("") != 0 && GetName().compare("") != 0; +} + +bool JBCClassMethod::HasCode() const { + uint16 flag = GetAccessFlag(); + return ((flag & kAccMethodAbstract) == 0) && ((flag & kAccMethodNative) == 0); +} + +bool JBCClassMethod::IsNative() const { + uint16 flag = GetAccessFlag(); + return flag & kAccMethodNative; +} + +// ---------- JBCClass ---------- +JBCClass::JBCClass(MapleAllocator &allocatorIn) + : allocator(allocatorIn), + constPool(allocator), + tbInterfaces(allocator.Adapter()), + tbFields(allocator.Adapter()), + tbMethods(allocator.Adapter()), + tbAttrs(allocator.Adapter()), + attrMap(allocator), + filePathName("", allocator.GetMemPool()), + fileName("", allocator.GetMemPool()) { + InitHeader(); +} + +bool JBCClass::ParseFile(BasicIORead &io) { + // begin parsing + bool success = false; + header.magic = io.ReadUInt32(success); + if (header.magic != kMagicJVMClass) { + ERR(kLncErr, "JBCClass::ParseFile() failed: invalid java class file (wrong magic number)."); + return false; + } + header.minorVersion = io.ReadUInt16(success); + header.majorVersion = io.ReadUInt16(success); + if (!ParseFileForConstPool(io)) { + return false; + } + header.accessFlag = io.ReadUInt16(success); + header.thisClass = io.ReadUInt16(success); + header.superClass = io.ReadUInt16(success); + header.interfacesCount = io.ReadUInt16(success); + for (uint16 i = 0; i < header.interfacesCount && success; i++) { + uint16 idx = io.ReadUInt16(success); + tbInterfaces.push_back(idx); + } + if (!success) { + return success; + } + if (!ParseFileForFields(io)) { + return false; + } + if (!ParseFileForMethods(io)) { + return false; + } + if (!ParseFileForAttrs(io)) { + return false; + } + return true; +} + +bool JBCClass::ParseFileForConstPool(BasicIORead &io) { + bool success = false; + bool wide = false; + const uint8 kIdxOff = 1; + const uint8 kIdxOffWide = 2; + header.constPoolCount = io.ReadUInt16(success); + for (uint16_t i = 1; i < header.constPoolCount && success; i += (wide ? kIdxOffWide : kIdxOff)) { + JBCConst *objConst = JBCConst::InConst(allocator, io); + if (objConst != nullptr) { + (void)constPool.InsertConst(*objConst); + wide = objConst->IsWide(); + if (wide) { + constPool.InsertConstDummyForWide(); + } + } else { + ERR(kLncErr, "JBCClass::ParseFile() failed: invalid const @idx=%d", i); + success = false; + } + } + return success; +} + +bool JBCClass::ParseFileForFields(BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + header.fieldsCount = io.ReadUInt16(success); + for (uint16 i = 0; i < header.fieldsCount && success; i++) { + JBCClassField *field = mp->New(allocator, *this); + success = field->ParseFile(allocator, io, constPool); + tbFields.push_back(field); + } + return success; +} + +bool JBCClass::ParseFileForMethods(BasicIORead &io) { + bool success = false; + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + header.methodsCount = io.ReadUInt16(success); + for (uint16 i = 0; i < header.methodsCount && success; i++) { + JBCClassMethod *method = mp->New(allocator, *this); + success = method->ParseFile(allocator, io, constPool); + tbMethods.push_back(method); + } + return success; +} + +bool JBCClass::ParseFileForAttrs(BasicIORead &io) { + bool success = false; + header.attrsCount = io.ReadUInt16(success); + for (uint16 i = 0; i < header.attrsCount && success; i++) { + JBCAttr *attr = JBCAttr::InAttr(allocator, io, constPool); + if (attr == nullptr) { + return false; + } + tbAttrs.push_back(attr); + attrMap.RegisterAttr(*attr); + } + return success; +} + +bool JBCClass::PreProcess() { + bool success = true; + success = success && constPool.PreProcess(header.majorVersion); + success = success && constPool.PrepareFEStructElemInfo(GetClassNameOrin()); + for (JBCClassMethod *method : tbMethods) { + success = success && method->PreProcess(); + } + for (JBCAttr *attr : tbAttrs) { + if (attr->GetKind() == JBCAttrKind::kAttrSourceFile) { + success = success && attr->PreProcess(constPool); + } + } + return success; +} + +GStrIdx JBCClass::GetClassNameIdxOrin() const { + const JBCConstClass *constClass = + static_cast(constPool.GetConstByIdxWithTag(header.thisClass, kConstClass)); + if (constClass != nullptr) { + return constClass->GetClassNameIdxOrin(); + } else { + return GStrIdx(0); + } +} + +GStrIdx JBCClass::GetClassNameIdxMpl() const { + const JBCConstClass *constClass = + static_cast(constPool.GetConstByIdxWithTag(header.thisClass, kConstClass)); + if (constClass != nullptr) { + return constClass->GetClassNameIdxMpl(); + } else { + return GStrIdx(0); + } +} + +std::string JBCClass::GetClassNameOrin() const { + GStrIdx idx = GetClassNameIdxOrin(); + if (idx.GetIdx() == 0) { + return ""; + } else { + return GlobalTables::GetStrTable().GetStringFromStrIdx(idx); + } +} + +std::string JBCClass::GetClassNameMpl() const { + GStrIdx idx = GetClassNameIdxMpl(); + if (idx.GetIdx() == 0) { + return ""; + } else { + return GlobalTables::GetStrTable().GetStringFromStrIdx(idx); + } +} + +std::string JBCClass::GetSourceFileName() const { + return ""; +} + +std::string JBCClass::GetSuperClassName() const { + if (header.superClass == kJavaClassNoIndex) { + return ""; + } else { + return constPool.GetNameByClassInfoIdx(header.superClass); + } +} + +std::vector JBCClass::GetInterfaceNames() const { + std::vector results; + for (uint16 idx : tbInterfaces) { + if (idx != kJavaClassNoIndex) { + std::string name = constPool.GetNameByClassInfoIdx(idx); + results.push_back(name); + } + } + return results; +} + +JBCClass *JBCClass::InClass(MapleAllocator &allocator, BasicIORead &io) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp, "mempool is nullptr"); + JBCClass *klass = mp->New(allocator); + if (klass->ParseFile(io) == false) { + return nullptr; + } + if (klass->PreProcess() == false) { + return nullptr; + } + // update fileName + const JBCAttr *attrRaw = klass->attrMap.GetAttr(JBCAttrKind::kAttrSourceFile); + if (attrRaw == nullptr) { + klass->fileName = "unknown"; + } else { + const JBCAttrSourceFile *attrSourceFile = static_cast(attrRaw); + const JBCConstUTF8 *constName = attrSourceFile->GetConstFileName(); + klass->fileName = constName->GetString(); + } + return klass; +} + +void JBCClass::InitHeader() { + header.magic = 0; + header.minorVersion = 0; + header.majorVersion = 0; + header.constPoolCount = 0; + header.accessFlag = 0; + header.thisClass = 0; + header.superClass = 0; + header.interfacesCount = 0; + header.fieldsCount = 0; + header.methodsCount = 0; + header.attrsCount = 0; +} +} // namespace jbc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_class2fe_helper.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_class2fe_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d4e09cf5b65e8efaeff801864291a80fbdc752e --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_class2fe_helper.cpp @@ -0,0 +1,382 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_class2fe_helper.h" +#include "fe_configs.h" +#include "fe_options.h" +#include "fe_macros.h" +#include "fe_manager.h" +#include "fe_utils_java.h" + +namespace maple { +// ---------- JBCClass2FEHelper ---------- +JBCClass2FEHelper::JBCClass2FEHelper(MapleAllocator &allocator, const jbc::JBCClass &klassIn) + : FEInputStructHelper(allocator), + klass(klassIn), + isStaticFieldProguard(false) { + srcLang = kSrcLangJava; +} + +// interface implements +std::string JBCClass2FEHelper::GetStructNameOrinImpl() const { + return klass.GetClassNameOrin(); +} + +std::string JBCClass2FEHelper::GetStructNameMplImpl() const { + return klass.GetClassNameMpl(); +} + +std::list JBCClass2FEHelper::GetSuperClassNamesImpl() const { + std::string superName = klass.GetSuperClassName(); + return std::list({ superName }); +} + +std::vector JBCClass2FEHelper::GetInterfaceNamesImpl() const { + return klass.GetInterfaceNames(); +} + +std::string JBCClass2FEHelper::GetSourceFileNameImpl() const { + return klass.GetSourceFileName(); +} + +MIRStructType *JBCClass2FEHelper::CreateMIRStructTypeImpl(bool &error) const { + std::string classNameOrin = klass.GetClassNameOrin(); + std::string classNameMpl = klass.GetClassNameMpl(); + if (classNameMpl.empty()) { + error = true; + ERR(kLncErr, "class name is empty"); + return nullptr; + } + FE_INFO_LEVEL(FEOptions::kDumpLevelInfoDetail, "CreateMIRStrucType for %s", classNameOrin.c_str()); + bool isCreate = false; + MIRStructType *type = FEManager::GetTypeManager().GetOrCreateClassOrInterfaceType(classNameMpl, klass.IsInterface(), + FETypeFlag::kSrcInput, isCreate); + error = false; + // fill global type name table + GStrIdx typeNameIdx = type->GetNameStrIdx(); + TyIdx prevTyIdx = GlobalTables::GetTypeNameTable().GetTyIdxFromGStrIdx(typeNameIdx); + if (prevTyIdx == TyIdx(0)) { + GlobalTables::GetTypeNameTable().SetGStrIdxToTyIdx(typeNameIdx, type->GetTypeIndex()); + } + return isCreate ? type : nullptr; +} + +TypeAttrs JBCClass2FEHelper::GetStructAttributeFromInputImpl() const { + const uint8 bitOfUInt16 = 16; + TypeAttrs attrs; + uint16 klassAccessFlag = klass.GetAccessFlag(); + for (uint8 bit = 0; bit < bitOfUInt16; bit++) { + uint16 flag = static_cast(klassAccessFlag & (1u << bit)); + switch (flag) { + case jbc::kAccClassPublic: + attrs.SetAttr(ATTR_public); + break; + case jbc::kAccClassFinal: + attrs.SetAttr(ATTR_final); + break; + case jbc::kAccClassSuper: + case jbc::kAccClassInterface: + break; + case jbc::kAccClassAbstract: + attrs.SetAttr(ATTR_abstract); + break; + case jbc::kAccClassSynthetic: + attrs.SetAttr(ATTR_synthetic); + break; + case jbc::kAccClassAnnotation: + attrs.SetAttr(ATTR_annotation); + break; + case jbc::kAccClassEnum: + attrs.SetAttr(ATTR_enum); + break; + default: + break; + } + } + return attrs; +} + +uint64 JBCClass2FEHelper::GetRawAccessFlagsImpl() const { + return uint64{ klass.GetAccessFlag() }; +} + +GStrIdx JBCClass2FEHelper::GetIRSrcFileSigIdxImpl() const { + // Not implemented, just return a invalid value + return GStrIdx(0); +} + +bool JBCClass2FEHelper::IsMultiDefImpl() const { + // Not implemented, alway return false + return false; +} + +void JBCClass2FEHelper::InitFieldHelpersImpl() { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mem pool is nullptr"); + for (jbc::JBCClassField *field : klass.GetFields()) { + ASSERT(field != nullptr, "field is nullptr"); + JBCClassField2FEHelper *fieldHelper = mp->New(allocator, *field); + fieldHelpers.push_back(fieldHelper); + } +} + +void JBCClass2FEHelper::InitMethodHelpersImpl() { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mem pool is nullptr"); + for (jbc::JBCClassMethod *method : klass.GetMethods()) { + ASSERT(method != nullptr, "method is nullptr"); + JBCClassMethod2FEHelper *methodHelper = mp->New(allocator, *method); + methodHelpers.push_back(methodHelper); + } +} + +std::string JBCClass2FEHelper::GetSrcFileNameImpl() const { + return klass.GetFileName(); +} + +// ---------- JBCClassField2FEHelper ---------- +bool JBCClassField2FEHelper::ProcessDeclImpl(MapleAllocator &allocator) { + (void) allocator; + CHECK_FATAL(false, "should not run here"); + return false; +} + +bool JBCClassField2FEHelper::ProcessDeclWithContainerImpl(MapleAllocator &allocator) { + std::string klassName = field.GetClassName(); + std::string fieldName = field.GetName(); + std::string typeName = field.GetDescription(); + if (fieldName.empty()) { + ERR(kLncErr, "invalid name_index(%d) for field in class %s", field.GetNameIdx(), klassName.c_str()); + return false; + } + if (typeName.empty()) { + ERR(kLncErr, "invalid descriptor_index(%d) for field in class %s", field.GetDescriptionIdx(), klassName.c_str()); + return false; + } + FEOptions::ModeJavaStaticFieldName modeStaticField = FEOptions::GetInstance().GetModeJavaStaticFieldName(); + bool withType = (modeStaticField == FEOptions::kAllType) || + (modeStaticField == FEOptions::kSmart && field.IsStatic()); + std::string name = field.IsStatic() ? (klassName + "|") : ""; + name += fieldName; + name += withType ? ("|" + typeName) : ""; + GStrIdx idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(name)); + StructElemNameIdx *structElemNameIdx = allocator.GetMemPool()->New(klassName, fieldName, typeName); + FEStructElemInfo *elemInfo = FEManager::GetTypeManager().RegisterStructFieldInfo( + *structElemNameIdx, kSrcLangJava, field.IsStatic()); + elemInfo->SetDefined(); + elemInfo->SetFromDex(); + FieldAttrs attrs = AccessFlag2Attribute(field.GetAccessFlag()); + std::string typeNameMpl = namemangler::EncodeName(typeName); + MIRType *fieldType = FEManager::GetTypeManager().GetOrCreateTypeFromName(typeNameMpl, FETypeFlag::kSrcUnknown, true); + ASSERT(fieldType != nullptr, "nullptr check for fieldType"); + mirFieldPair.first = idx; + mirFieldPair.second.first = fieldType->GetTypeIndex(); + mirFieldPair.second.second = attrs; + return true; +} + +FieldAttrs JBCClassField2FEHelper::AccessFlag2Attribute(uint16 accessFlag) { + const uint32 bitOfUInt16 = 16; + FieldAttrs attrs; + for (uint32 bit = 0; bit < bitOfUInt16; bit++) { + uint16 flag = static_cast(accessFlag & (1u << bit)); + switch (flag) { + case jbc::JBCClassFieldAccessFlag::kAccFieldPublic: + attrs.SetAttr(FLDATTR_public); + break; + case jbc::JBCClassFieldAccessFlag::kAccFieldPrivate: + attrs.SetAttr(FLDATTR_private); + break; + case jbc::JBCClassFieldAccessFlag::kAccFieldProtected: + attrs.SetAttr(FLDATTR_protected); + break; + case jbc::JBCClassFieldAccessFlag::kAccFieldStatic: + attrs.SetAttr(FLDATTR_static); + break; + case jbc::JBCClassFieldAccessFlag::kAccFieldFinal: + attrs.SetAttr(FLDATTR_final); + break; + case jbc::JBCClassFieldAccessFlag::kAccFieldVolatile: + attrs.SetAttr(FLDATTR_volatile); + break; + case jbc::JBCClassFieldAccessFlag::kAccFieldTransient: + attrs.SetAttr(FLDATTR_transient); + break; + case jbc::JBCClassFieldAccessFlag::kAccFieldSynthetic: + attrs.SetAttr(FLDATTR_synthetic); + break; + case jbc::JBCClassFieldAccessFlag::kAccFieldEnum: + attrs.SetAttr(FLDATTR_enum); + break; + default: + break; + } + } + return attrs; +} + +// ---------- JBCClassMethod2FEHelper ---------- +JBCClassMethod2FEHelper::JBCClassMethod2FEHelper(MapleAllocator &allocator, const jbc::JBCClassMethod &methodIn) + : FEInputMethodHelper(allocator), + method(methodIn) { + srcLang = kSrcLangJava; +} + +bool JBCClassMethod2FEHelper::ProcessDeclImpl(MapleAllocator &allocator) { + StructElemNameIdx *structElemNameIdx = allocator.GetMemPool()->New( + method.GetClassName(), method.GetName(), method.GetDescription()); + FEStructElemInfo *elemInfo = FEManager::GetTypeManager().RegisterStructMethodInfo( + *structElemNameIdx, kSrcLangJava, IsStatic()); + elemInfo->SetDefined(); + elemInfo->SetFromDex(); + return FEInputMethodHelper::ProcessDeclImpl(allocator); +} + +void JBCClassMethod2FEHelper::SolveReturnAndArgTypesImpl(MapleAllocator &allocator) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + std::string klassName = method.GetClassName(); + std::string methodName = GetMethodName(false); + if (HasThis()) { + FEIRTypeDefault *type = mp->New(); + type->LoadFromJavaTypeName(klassName, false); + argTypes.push_back(type); + } + std::vector returnAndArgTypeNames = FEUtilJava::SolveMethodSignature(methodName); + bool first = true; + for (const std::string &typeName : returnAndArgTypeNames) { + FEIRTypeDefault *type = mp->New(); + type->LoadFromJavaTypeName(typeName, false); + if (first) { + retType = type; + first = false; + } else { + argTypes.push_back(type); + } + } +} + +std::string JBCClassMethod2FEHelper::GetMethodNameImpl(bool inMpl, bool full) const { + const jbc::JBCConstPool &constPool = method.GetConstPool(); + std::string klassName = method.GetClassName(); + std::string methodName = method.GetName(constPool); + if (!full) { + return inMpl ? namemangler::EncodeName(methodName) : methodName; + } + std::string descName = method.GetDescription(constPool); + std::string fullName = klassName + "|" + methodName + "|" + descName; + return inMpl ? namemangler::EncodeName(fullName) : fullName; +} + +FuncAttrs JBCClassMethod2FEHelper::GetAttrsImpl() const { + FuncAttrs attrs; + const uint32 bitOfUInt16 = 16; + uint16 accessFlag = method.GetAccessFlag(); + for (uint32 bit = 0; bit < bitOfUInt16; bit++) { + uint16 flag = static_cast(accessFlag & (1u << bit)); + switch (flag) { + case jbc::JBCClassMethodAccessFlag::kAccMethodPublic: + attrs.SetAttr(FUNCATTR_public); + break; + case jbc::JBCClassMethodAccessFlag::kAccMethodPrivate: + attrs.SetAttr(FUNCATTR_private); + break; + case jbc::JBCClassMethodAccessFlag::kAccMethodProtected: + attrs.SetAttr(FUNCATTR_protected); + break; + case jbc::JBCClassMethodAccessFlag::kAccMethodStatic: + attrs.SetAttr(FUNCATTR_static); + break; + case jbc::JBCClassMethodAccessFlag::kAccMethodFinal: + attrs.SetAttr(FUNCATTR_final); + break; + case jbc::JBCClassMethodAccessFlag::kAccMethodSynchronized: + attrs.SetAttr(FUNCATTR_synchronized); + break; + case jbc::JBCClassMethodAccessFlag::kAccMethodBridge: + attrs.SetAttr(FUNCATTR_bridge); + break; + case jbc::JBCClassMethodAccessFlag::kAccMethodVarargs: + attrs.SetAttr(FUNCATTR_varargs); + break; + case jbc::JBCClassMethodAccessFlag::kAccMethodNative: + attrs.SetAttr(FUNCATTR_native); + break; + case jbc::JBCClassMethodAccessFlag::kAccMethodAbstract: + attrs.SetAttr(FUNCATTR_abstract); + break; + case jbc::JBCClassMethodAccessFlag::kAccMethodStrict: + attrs.SetAttr(FUNCATTR_strict); + break; + case jbc::JBCClassMethodAccessFlag::kAccMethodSynthetic: + attrs.SetAttr(FUNCATTR_synthetic); + break; + default: + break; + } + attrs.SetAttr(IsVirtual() ? FUNCATTR_virtual : static_cast(0)); + } + return attrs; +} + +bool JBCClassMethod2FEHelper::IsStaticImpl() const { + uint16 accessFlag = method.GetAccessFlag(); + if ((accessFlag & jbc::JBCClassMethodAccessFlag::kAccMethodStatic) != 0) { + return true; + } + if (IsClinit()) { + return true; + } + return false; +} + +bool JBCClassMethod2FEHelper::IsVargImpl() const { + return false; +} + +bool JBCClassMethod2FEHelper::HasThisImpl() const { + return !IsStatic(); +} + +bool JBCClassMethod2FEHelper::IsClinit() const { + const jbc::JBCConstPool &constPool = method.GetConstPool(); + std::string methodName = method.GetName(constPool); + return methodName.compare("") == 0; +} + +bool JBCClassMethod2FEHelper::IsInit() const { + const jbc::JBCConstPool &constPool = method.GetConstPool(); + std::string methodName = method.GetName(constPool); + return methodName.compare("") == 0; +} + +bool JBCClassMethod2FEHelper::IsVirtualImpl() const { + return method.IsVirtual(); +} + +bool JBCClassMethod2FEHelper::IsNativeImpl() const { + return method.IsNative(); +} + +MIRType *JBCClassMethod2FEHelper::GetTypeForThisImpl() const { + FEIRTypeDefault type; + std::string klassName = method.GetClassName(); + type.LoadFromJavaTypeName(klassName, false); + return type.GenerateMIRType(true); +} + +bool JBCClassMethod2FEHelper::HasCodeImpl() const { + return method.HasCode(); +} +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_class_const.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_class_const.cpp new file mode 100644 index 0000000000000000000000000000000000000000..029e965631c6b145af5b46a4c0cd1bd44f72152e --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_class_const.cpp @@ -0,0 +1,519 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_class_const.h" +#include +#include "mpl_logging.h" +#include "jbc_class.h" +#include "jbc_util.h" +#include "fe_manager.h" + +namespace maple { +namespace jbc { +// ---------- JBCConstTagName ---------- +std::map JBCConstTagName::tagNameMap = JBCConstTagName::InitTagNameMap(); +std::map JBCConstTagName::InitTagNameMap() { + std::map ret; + ret[kConstUnknown] = "ConstUnknown"; +#undef JBC_CONST +#define JBC_CONST(tag, tagName, className) \ + ret[tag] = tagName; +#include "jbc_class_const.def" +#undef JBC_CONST + return ret; +} + +std::string JBCConstTagName::GetTagName(JBCConstTag tag) { + std::map::const_iterator it = tagNameMap.find(tag); + if (it != tagNameMap.end()) { + return it->second; + } + std::stringstream ss; + ss << "unknown tag (" << static_cast(tag) << ")"; + return ss.str(); +} + +// ---------- JBCConst ---------- +SimpleXMLElem *JBCConst::GenXMLElemImpl(MapleAllocator &allocIn, uint32 id) const { + (void) allocIn; + (void) id; + return nullptr; +} + +JBCConst *JBCConst::InConst(MapleAllocator &alloc, BasicIORead &io) { + MemPool *mp = alloc.GetMemPool(); + ASSERT(mp, "mp is nullptr"); + JBCConst *constObj = nullptr; + uint8 t = io.ReadUInt8(); + switch (t) { +#undef JBC_CONST +#define JBC_CONST(tag, tagName, ConstClassType) \ + case tag: \ + constObj = mp->New(alloc, static_cast(t)); \ + if (constObj->ParseFile(io) == false) { \ + return nullptr; \ + } \ + break; +#include "jbc_class_const.def" +#undef JBC_CONST + default: + break; + } + return constObj; +} + +std::string JBCConst::InternalNameToFullName(const std::string &name) { + // ref: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.4.1 + if (name[0] == '[') { + return name; + } else { + return "L" + name + ";"; + } +} + +std::string JBCConst::FullNameToInternalName(const std::string &name) { + if (name[0] == '[') { + return name; + } else { + return name.substr(1, name.length() - 2); // 1 : start pos, name.length() - 2 : substr length + } +} + +// ---------- JBCConstUTF8 ---------- +JBCConstUTF8::JBCConstUTF8(MapleAllocator &alloc, JBCConstTag t) + : JBCConst(alloc, t), length(0), strIdx(0), str("", alloc.GetMemPool()) {} + +JBCConstUTF8::JBCConstUTF8(MapleAllocator &alloc, JBCConstTag t, const std::string &argStr) + : JBCConst(alloc, t), str(argStr, alloc.GetMemPool()) { + CHECK_FATAL(t == kConstUTF8, "invalid tag"); + size_t rawLength = str.length(); + CHECK_FATAL(rawLength < UINT16_MAX, "input string is too long"); + length = static_cast(rawLength); + strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(MapleStringToStd(str)); +} + +bool JBCConstUTF8::ParseFileImpl(BasicIORead &io) { + bool success = false; + length = io.ReadUInt16(success); + str = io.ReadString(length, success); + strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(MapleStringToStd(str)); + return success; +} + +bool JBCConstUTF8::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *JBCConstUTF8::GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const { + (void) alloc; + (void) id; + return nullptr; +} + +// ---------- JBCConst4Byte ---------- +JBCConst4Byte::JBCConst4Byte(MapleAllocator &alloc, JBCConstTag t) : JBCConst(alloc, t) { + value.raw = 0; +} + +JBCConst4Byte::JBCConst4Byte(MapleAllocator &alloc, JBCConstTag t, int32 arg) : JBCConst(alloc, t) { + CHECK_FATAL(t == kConstInteger, "invalid tag"); + value.ivalue = arg; +} + +JBCConst4Byte::JBCConst4Byte(MapleAllocator &alloc, JBCConstTag t, float arg) : JBCConst(alloc, t) { + CHECK_FATAL(t == kConstFloat, "invalid tag"); + value.fvalue = arg; +} + +bool JBCConst4Byte::ParseFileImpl(BasicIORead &io) { + bool success = false; + value.raw = io.ReadUInt32(success); + return success; +} + +bool JBCConst4Byte::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *JBCConst4Byte::GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const { + (void) alloc; + (void) id; + return nullptr; +} + +// ---------- JBCConst8Byte ---------- +JBCConst8Byte::JBCConst8Byte(MapleAllocator &alloc, JBCConstTag t) : JBCConst(alloc, t) { + value.raw = 0; +} + +JBCConst8Byte::JBCConst8Byte(MapleAllocator &alloc, JBCConstTag t, int64 arg) : JBCConst(alloc, t) { + CHECK_FATAL(t == kConstLong, "invalid tag"); + value.lvalue = arg; +} + +JBCConst8Byte::JBCConst8Byte(MapleAllocator &alloc, JBCConstTag t, double arg) : JBCConst(alloc, t) { + CHECK_FATAL(t == kConstDouble, "invalid tag"); + value.dvalue = arg; +} + +bool JBCConst8Byte::ParseFileImpl(BasicIORead &io) { + bool success = false; + value.raw = io.ReadUInt64(success); + return success; +} + +bool JBCConst8Byte::PreProcessImpl(const JBCConstPool &constPool) { + (void) constPool; + return true; +} + +SimpleXMLElem *JBCConst8Byte::GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const { + (void) alloc; + (void) id; + return nullptr; +} + +// ---------- JBCConstClass ---------- +JBCConstClass::JBCConstClass(MapleAllocator &alloc, JBCConstTag t) + : JBCConst(alloc, t), + constUTF8(nullptr), + strIdxOrin(0), + strIdxMpl(0), + nameOrin("", alloc.GetMemPool()), + nameMpl("", alloc.GetMemPool()) { + rawData.nameIdx = 0; + feType = alloc.GetMemPool()->New(PTY_ref); +} + +JBCConstClass::JBCConstClass(MapleAllocator &alloc, JBCConstTag t, JBCConstPoolIdx argNameIdx) + : JBCConst(alloc, t), + constUTF8(nullptr), + strIdxOrin(0), + strIdxMpl(0), + nameOrin("", alloc.GetMemPool()), + nameMpl("", alloc.GetMemPool()) { + CHECK_FATAL(t == kConstClass, "invalid tag"); + rawData.nameIdx = argNameIdx; + feType = alloc.GetMemPool()->New(PTY_ref); +} + +JBCConstClass::~JBCConstClass() { + constUTF8 = nullptr; + feType = nullptr; +} + +bool JBCConstClass::ParseFileImpl(BasicIORead &io) { + bool success = false; + rawData.nameIdx = io.ReadUInt16(success); + return success; +} + +bool JBCConstClass::PreProcessImpl(const JBCConstPool &constPool) { + constUTF8 = static_cast(constPool.GetConstByIdxWithTag(rawData.nameIdx, kConstUTF8)); + if (constUTF8 == nullptr) { + return false; + } + const std::string &classNameInternal = constUTF8->GetString(); + nameOrin = JBCUtil::ClassInternalNameToFullName(classNameInternal); + strIdxOrin = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(MapleStringToStd(nameOrin)); + nameMpl = namemangler::EncodeName(nameOrin.c_str()); + strIdxMpl = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(MapleStringToStd(nameMpl)); + static_cast(feType)->LoadFromJavaTypeName(MapleStringToStd(nameMpl), true); + return true; +} + +SimpleXMLElem *JBCConstClass::GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const { + (void) alloc; + (void) id; + return nullptr; +} + +// ---------- JBCConstString ---------- +JBCConstString::JBCConstString(MapleAllocator &alloc, JBCConstTag t) + : JBCConst(alloc, t), strIdx(0), str("", alloc.GetMemPool()) { + rawData.stringIdx = 0; +} + +JBCConstString::JBCConstString(MapleAllocator &alloc, JBCConstTag t, JBCConstPoolIdx argStringIdx) + : JBCConst(alloc, t), strIdx(0), str("", alloc.GetMemPool()) { + CHECK_FATAL(t == kConstString, "invalid tag"); + rawData.stringIdx = argStringIdx; +} + +bool JBCConstString::ParseFileImpl(BasicIORead &io) { + bool success = false; + rawData.stringIdx = io.ReadUInt16(success); + return success; +} + +bool JBCConstString::PreProcessImpl(const JBCConstPool &constPool) { + const JBCConstUTF8 *constUTF8 = + static_cast(constPool.GetConstByIdxWithTag(rawData.stringIdx, kConstUTF8)); + if (constUTF8 == nullptr) { + return false; + } + strIdx = constUTF8->GetStrIdx(); + str = constUTF8->GetString(); + return true; +} + +SimpleXMLElem *JBCConstString::GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const { + (void) alloc; + (void) id; + return nullptr; +} + +// ---------- JBCConstRef ---------- +JBCConstRef::JBCConstRef(MapleAllocator &alloc, JBCConstTag t) + : JBCConst(alloc, t), constClass(nullptr), constNameAndType(nullptr), feStructElemInfo(nullptr) { + rawData.classIdx = 0; + rawData.nameAndTypeIdx = 0; +} + +JBCConstRef::JBCConstRef(MapleAllocator &alloc, JBCConstTag t, JBCConstPoolIdx argClassIdx, + JBCConstPoolIdx argClassNameAndTypeIdx) + : JBCConst(alloc, t), constClass(nullptr), constNameAndType(nullptr), feStructElemInfo(nullptr) { + rawData.classIdx = argClassIdx; + rawData.nameAndTypeIdx = argClassNameAndTypeIdx; +} + +JBCConstRef::~JBCConstRef() { + constClass = nullptr; + constNameAndType = nullptr; + feStructElemInfo = nullptr; +} + +bool JBCConstRef::ParseFileImpl(BasicIORead &io) { + bool success = false; + rawData.classIdx = io.ReadUInt16(success); + rawData.nameAndTypeIdx = io.ReadUInt16(success); + return success; +} + +bool JBCConstRef::PreProcessImpl(const JBCConstPool &constPool) { + constClass = static_cast(constPool.GetConstByIdxWithTag(rawData.classIdx, kConstClass)); + constNameAndType = static_cast(constPool.GetConstByIdxWithTag(rawData.nameAndTypeIdx, + kConstNameAndType)); + return (constClass != nullptr) && (constNameAndType != nullptr); +} + +bool JBCConstRef::PrepareFEStructElemInfo() { + CHECK_NULL_FATAL(constClass); + CHECK_NULL_FATAL(constNameAndType); + const std::string &className = constClass->GetClassNameOrin(); + const std::string &elemName = constNameAndType->GetName(); + const std::string &descName = constNameAndType->GetDesc(); + StructElemNameIdx *structElemNameIdx = alloc.GetMemPool()->New(className, elemName, descName); + if (tag == kConstFieldRef) { + feStructElemInfo = FEManager::GetTypeManager().RegisterStructFieldInfo( + *structElemNameIdx, kSrcLangJava, false); + } else { + feStructElemInfo = FEManager::GetTypeManager().RegisterStructMethodInfo( + *structElemNameIdx, kSrcLangJava, false); + } + return feStructElemInfo != nullptr; +} + +SimpleXMLElem *JBCConstRef::GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const { + (void) alloc; + (void) id; + return nullptr; +} + +const std::string JBCConstRef::GetName() const { + CHECK_FATAL(constNameAndType != nullptr, "invalid const index"); + return constNameAndType->GetName(); +} + +const std::string JBCConstRef::GetDesc() const { + CHECK_FATAL(constNameAndType != nullptr, "invalid const index"); + return constNameAndType->GetDesc(); +} + +// ---------- JBCConstNameAndType ---------- +JBCConstNameAndType::JBCConstNameAndType(MapleAllocator &alloc, JBCConstTag t) + : JBCConst(alloc, t), constName(nullptr), constDesc(nullptr) { + rawData.nameIdx = 0; + rawData.descIdx = 0; +} + +JBCConstNameAndType::JBCConstNameAndType(MapleAllocator &alloc, JBCConstTag t, JBCConstPoolIdx argNameIdx, + JBCConstPoolIdx argDescIdx) + : JBCConst(alloc, t), constName(nullptr), constDesc(nullptr) { + rawData.nameIdx = argNameIdx; + rawData.descIdx = argDescIdx; +} + +JBCConstNameAndType::~JBCConstNameAndType() { + constName = nullptr; + constDesc = nullptr; +} + +bool JBCConstNameAndType::ParseFileImpl(BasicIORead &io) { + bool success = false; + rawData.nameIdx = io.ReadUInt16(success); + rawData.descIdx = io.ReadUInt16(success); + return success; +} + +bool JBCConstNameAndType::PreProcessImpl(const JBCConstPool &constPool) { + constName = static_cast(constPool.GetConstByIdxWithTag(rawData.nameIdx, kConstUTF8)); + constDesc = static_cast(constPool.GetConstByIdxWithTag(rawData.descIdx, kConstUTF8)); + return (constName != nullptr) && (constDesc != nullptr); +} + +SimpleXMLElem *JBCConstNameAndType::GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const { + (void) alloc; + (void) id; + return nullptr; +} + +// ---------- JBCConstMethodHandleInfo ---------- +JBCConstMethodHandleInfo::JBCConstMethodHandleInfo(MapleAllocator &alloc, JBCConstTag t) + : JBCConst(alloc, t), constRef(nullptr) { + rawData.refKind = 0; + rawData.refIdx = 0; +} + +JBCConstMethodHandleInfo::~JBCConstMethodHandleInfo() { + constRef = nullptr; +} + +bool JBCConstMethodHandleInfo::ParseFileImpl(BasicIORead &io) { + bool success = false; + rawData.refKind = io.ReadUInt8(success); + rawData.refIdx = io.ReadUInt16(success); + return success; +} + +bool JBCConstMethodHandleInfo::PreProcessImpl(const JBCConstPool &constPool) { + constRef = nullptr; + switch (rawData.refKind) { + case kRefGetField: + case kRefGetStatic: + case kRefPutField: + case kRefPutStatic: + constRef = static_cast(constPool.GetConstByIdxWithTag(rawData.refIdx, kConstFieldRef)); + break; + case jbc::kRefInvokeVirtual: + case jbc::kRefNewInvokeSpecial: + constRef = static_cast(constPool.GetConstByIdxWithTag(rawData.refIdx, kConstMethodRef)); + break; + case jbc::kRefInvokeStatic: + case jbc::kRefInvokeSpecial: + if (constPool.GetMajorVersion() < 52) { // 52 : class file version number + constRef = static_cast(constPool.GetConstByIdxWithTag(rawData.refIdx, kConstMethodRef)); + } else { + constRef = static_cast(constPool.GetConstByIdx(rawData.refIdx)); + CHECK_NULL_FATAL(constRef); + if (constRef->GetTag() != kConstMethodRef && constRef->GetTag() != kConstInterfaceMethodRef) { + ERR(kLncErr, "Unexpected tag (%s) for const MethodHandle info. Expected %s or %s", + JBCConstTagName::GetTagName(constRef->GetTag()).c_str(), + JBCConstTagName::GetTagName(kConstMethodRef).c_str(), + JBCConstTagName::GetTagName(kConstInterfaceMethodRef).c_str()); + return false; + } + } + break; + case jbc::kRefInvokeInterface: + constRef = static_cast(constPool.GetConstByIdxWithTag(rawData.refIdx, + kConstInterfaceMethodRef)); + break; + default: + CHECK_FATAL(false, "Unsupported ref kind (%d)", rawData.refKind); + break; + } + return constRef != nullptr; +} + +SimpleXMLElem *JBCConstMethodHandleInfo::GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const { + (void) alloc; + (void) id; + return nullptr; +} + +// ---------- JBCConstMethodType ---------- +JBCConstMethodType::JBCConstMethodType(MapleAllocator &alloc, JBCConstTag t) + : JBCConst(alloc, t), constDesc(nullptr) { + rawData.descIdx = 0; +} + +JBCConstMethodType::~JBCConstMethodType() { + constDesc = nullptr; +} + +bool JBCConstMethodType::ParseFileImpl(BasicIORead &io) { + bool success = false; + rawData.descIdx = io.ReadUInt16(success); + return success; +} + +bool JBCConstMethodType::PreProcessImpl(const JBCConstPool &constPool) { + constDesc = static_cast(constPool.GetConstByIdxWithTag(rawData.descIdx, kConstUTF8)); + return constDesc != nullptr; +} + +SimpleXMLElem *JBCConstMethodType::GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const { + (void) alloc; + (void) id; + return nullptr; +} + +// ---------- JBCConstInvokeDynamic ---------- +JBCConstInvokeDynamic::JBCConstInvokeDynamic(MapleAllocator &alloc, JBCConstTag t) + : JBCConst(alloc, t), constNameAndType(nullptr), feStructElemInfo(nullptr) { + rawData.bsmAttrIdx = 0; + rawData.nameAndTypeIdx = 0; +} + +JBCConstInvokeDynamic::~JBCConstInvokeDynamic() { + constNameAndType = nullptr; + feStructElemInfo = nullptr; +} + +bool JBCConstInvokeDynamic::PrepareFEStructElemInfo(const std::string &ownerClassName) { + CHECK_NULL_FATAL(constNameAndType); + const std::string &className = ownerClassName + "$DynamicCall$"; + const std::string &elemName = constNameAndType->GetName(); + const std::string &descName = constNameAndType->GetDesc(); + StructElemNameIdx *structElemNameIdx = alloc.GetMemPool()->New(className, elemName, descName); + feStructElemInfo = FEManager::GetTypeManager().RegisterStructMethodInfo( + *structElemNameIdx, kSrcLangJava, false); + static_cast(feStructElemInfo)->SetJavaDyamicCall(); + return feStructElemInfo != nullptr; +} + +bool JBCConstInvokeDynamic::ParseFileImpl(BasicIORead &io) { + bool success = false; + rawData.bsmAttrIdx = io.ReadUInt16(success); + rawData.nameAndTypeIdx = io.ReadUInt16(success); + return success; +} + +bool JBCConstInvokeDynamic::PreProcessImpl(const JBCConstPool &constPool) { + constNameAndType = + static_cast(constPool.GetConstByIdxWithTag(rawData.nameAndTypeIdx, + kConstNameAndType)); + return constNameAndType != nullptr; +} + +SimpleXMLElem *JBCConstInvokeDynamic::GenXMLElemImpl(MapleAllocator &alloc, uint32 id) const { + (void) alloc; + (void) id; + return nullptr; +} +} // namespace jbc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_class_const_pool.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_class_const_pool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49703d94fbe329f927371864e79e78665792f72e --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_class_const_pool.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_class_const_pool.h" +#include + +namespace maple { +namespace jbc { +JBCConstPool::JBCConstPool(MapleAllocator &alloc) + : allocator(alloc), + pool(allocator.Adapter()), + majorVersion(0) { + pool.push_back(nullptr); +} + +uint16 JBCConstPool::InsertConst(JBCConst &objConst) { + size_t ans = pool.size(); + pool.push_back(&objConst); + CHECK_FATAL(ans < 0xFFFF, "const pool is full"); + return static_cast(ans); +} + +void JBCConstPool::InsertConstDummyForWide() { + size_t ans = pool.size(); + pool.push_back(nullptr); + CHECK_FATAL(ans < 0xFFFF, "const pool is full"); +} + +const JBCConst *JBCConstPool::GetConstByIdx(uint16 idx, bool safed) const { + if (idx == 0 || idx >= pool.size()) { + std::stringstream ss; + ss << "invalid const pool idx " << static_cast(idx) << "."; + CHECK_FATAL(!safed, "%s", ss.str().c_str()); + ERR(kLncErr, "%s", ss.str().c_str()); + return nullptr; + } + return pool[idx]; +} + +const JBCConst *JBCConstPool::GetConstByIdxWithTag(uint16 idx, JBCConstTag tag, bool safed) const { + const JBCConst *obj = GetConstByIdx(idx, safed); + if (obj != nullptr && obj->GetTag() != tag) { + std::stringstream ss; + ss << "invalid const pool idx " << static_cast(idx) << " (tag=" << + JBCConstTagName::GetTagName(obj->GetTag()).c_str() << ", expect " << + JBCConstTagName::GetTagName(tag).c_str() << ")."; + CHECK_FATAL(!safed, "%s Exit.", ss.str().c_str()); + ERR(kLncErr, "%s", ss.str().c_str()); + return nullptr; + } + return obj; +} + +const JBCConst *JBCConstPool::GetConstValueByIdx(uint16 idx, bool safed) const { + const JBCConst *obj = GetConstByIdx(idx, safed); + if (obj != nullptr && obj->IsValue() == false) { + std::stringstream ss; + ss << "invalid const pool idx " << static_cast(idx) << " (not value const)."; + CHECK_FATAL(!safed, "%s Exit.", ss.str().c_str()); + ERR(kLncErr, "%s", ss.str().c_str()); + return nullptr; + } + return obj; +} + +const JBCConst *JBCConstPool::GetConstValue4ByteByIdx(uint16 idx, bool safed) const { + const JBCConst *obj = GetConstByIdx(idx, safed); + if (obj != nullptr && obj->IsValue4Byte() == false) { + std::stringstream ss; + ss << "invalid const pool idx " << static_cast(idx) << " (not 4-byte value const)."; + CHECK_FATAL(!safed, "%s Exit.", ss.str().c_str()); + ERR(kLncErr, "%s", ss.str().c_str()); + return nullptr; + } + return obj; +} + +const JBCConst *JBCConstPool::GetConstValue8ByteByIdx(uint16 idx, bool safed) const { + const JBCConst *obj = GetConstByIdx(idx, safed); + if (obj != nullptr && obj->IsValue8Byte() == false) { + std::stringstream ss; + ss << "invalid const pool idx " << static_cast(idx) << " (not 8-byte value const)."; + CHECK_FATAL(!safed, "%s Exit.", ss.str().c_str()); + ERR(kLncErr, "%s", ss.str().c_str()); + return nullptr; + } + return obj; +} + +std::string JBCConstPool::GetNameByClassInfoIdx(uint16 idx, bool safed) const { + const JBCConstClass *constClass = static_cast(GetConstByIdxWithTag(idx, kConstClass, safed)); + if (constClass == nullptr) { + return ""; + } else { + return constClass->GetClassNameOrin(); + } +} + +bool JBCConstPool::PreProcess(uint16 argMajorVersion) { + majorVersion = argMajorVersion; + for (JBCConst *c : pool) { + if (c != nullptr && !c->PreProcess(*this)) { + return false; + } + } + return true; +} + +bool JBCConstPool::PrepareFEStructElemInfo(const std::string &ownerClassName) { + bool success = true; + for (JBCConst *c : pool) { + if (c == nullptr) { + continue; + } + JBCConstTag tag = c->GetTag(); + if (tag == JBCConstTag::kConstFieldRef || tag == JBCConstTag::kConstMethodRef || + tag == JBCConstTag::kConstInterfaceMethodRef) { + JBCConstRef *constRef = static_cast(c); + success = success && constRef->PrepareFEStructElemInfo(); + } + if (tag == JBCConstTag::kConstInvokeDynamic) { + JBCConstInvokeDynamic *constRef = static_cast(c); + success = success && constRef->PrepareFEStructElemInfo(ownerClassName); + } + } + return success; +} + +JBCConstUTF8 *JBCConstPool::NewConstUTF8(uint16 &idx, const std::string &str) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + JBCConstUTF8 *constItem = mp->New(allocator, kConstUTF8, str); + idx = InsertConst(*constItem); + return constItem; +} + +JBCConst4Byte *JBCConstPool::NewConst4Byte(uint16 &idx, int32 value) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + JBCConst4Byte *constItem = mp->New(allocator, kConstInteger, value); + idx = InsertConst(*constItem); + return constItem; +} + +JBCConst4Byte *JBCConstPool::NewConst4Byte(uint16 &idx, float value) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + JBCConst4Byte *constItem = mp->New(allocator, kConstFloat, value); + idx = InsertConst(*constItem); + return constItem; +} + +JBCConst8Byte *JBCConstPool::NewConst8Byte(uint16 &idx, int64 value) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + JBCConst8Byte *constItem = mp->New(allocator, kConstLong, value); + idx = InsertConst(*constItem); + return constItem; +} + +JBCConst8Byte *JBCConstPool::NewConst8Byte(uint16 &idx, double value) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + JBCConst8Byte *constItem = mp->New(allocator, kConstDouble, value); + idx = InsertConst(*constItem); + return constItem; +} + +JBCConstClass *JBCConstPool::NewConstClass(uint16 &idx, const std::string &className) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + std::string classNameInternal = JBCConst::FullNameToInternalName(className); + JBCConstUTF8 *constUTF8 = mp->New(allocator, kConstUTF8, classNameInternal); + uint16 idxTmp = InsertConst(*constUTF8); + CHECK_FATAL(idxTmp != UINT16_MAX, "constpool insert failed"); + JBCConstClass *constClass = mp->New(allocator, kConstClass, idxTmp); + CHECK_FATAL(constClass->PreProcess(*this), "New ConstClass failed"); + idx = InsertConst(*constClass); + return constClass; +} + +JBCConstString *JBCConstPool::NewConstString(uint16 &idx, const std::string &str) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + JBCConstUTF8 *constUTF8 = mp->New(allocator, kConstUTF8, str); + uint16 idxTmp = InsertConst(*constUTF8); + CHECK_FATAL(idxTmp != UINT16_MAX, "constpool insert failed"); + JBCConstString *constString = mp->New(allocator, kConstString, idxTmp); + CHECK_FATAL(constString->PreProcess(*this), "New ConstClass failed"); + idx = InsertConst(*constString); + return constString; +} + +JBCConstRef *JBCConstPool::NewConstRef(uint16 &idx, JBCConstTag tag, const std::string &className, + const std::string &name, const std::string &desc) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + uint16 idxConstClass; + uint16 idxConstNameAndType; + JBCConstClass *constClass = NewConstClass(idxConstClass, className); + CHECK_FATAL(idxConstClass != UINT16_MAX, "constpool insert failed"); + CHECK_NULL_FATAL(constClass); + JBCConstNameAndType *constNameAndType = NewConstNameAndType(idxConstNameAndType, name, desc); + CHECK_FATAL(idxConstNameAndType != UINT16_MAX, "constpool insert failed"); + CHECK_NULL_FATAL(constNameAndType); + JBCConstRef *constRef = mp->New(allocator, tag, idxConstClass, idxConstNameAndType); + CHECK_FATAL(constRef->PreProcess(*this), "New ConstClass failed"); + idx = InsertConst(*constRef); + return constRef; +} + +JBCConstNameAndType *JBCConstPool::NewConstNameAndType(uint16 &idx, const std::string &name, const std::string &desc) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + uint16 idxConstName; + uint16 idxConstDesc; + JBCConstUTF8 *constName = NewConstUTF8(idxConstName, name); + CHECK_FATAL(idxConstName != UINT16_MAX, "constpool insert failed"); + CHECK_NULL_FATAL(constName); + JBCConstUTF8 *constDesc = NewConstUTF8(idxConstDesc, desc); + CHECK_FATAL(idxConstDesc != UINT16_MAX, "constpool insert failed"); + CHECK_NULL_FATAL(constDesc); + JBCConstNameAndType *constNameAndType = mp->New(allocator, kConstNameAndType, idxConstName, + idxConstDesc); + CHECK_FATAL(constNameAndType->PreProcess(*this), "New ConstClass failed"); + idx = InsertConst(*constNameAndType); + return constNameAndType; +} +} // namespace jbc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_compiler_component.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_compiler_component.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bc5be8e8fb76aaa26242151328dcd5606a61a4d8 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_compiler_component.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_compiler_component.h" +#include "jbc_class2fe_helper.h" +#include "fe_timer.h" +#include "fe_manager.h" +#include "jbc_function.h" + +namespace maple { +JBCCompilerComponent::JBCCompilerComponent(MIRModule &module) + : HIR2MPLCompilerComponent(module, kSrcLangJava), + mp(FEUtils::NewMempool("MemPool for JBCCompilerComponent", false /* isLocalPool */)), + allocator(mp), + jbcInput(module) {} + +JBCCompilerComponent::~JBCCompilerComponent() { + mp = nullptr; +} + +void JBCCompilerComponent::ReleaseMemPoolImpl() { + FEUtils::DeleteMempoolPtr(mp); +} + +bool JBCCompilerComponent::ParseInputImpl() { + FETimer timer; + bool success = true; + timer.StartAndDump("JBCCompilerComponent::ParseInput()"); + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process JBCCompilerComponent::ParseInput() ====="); + const std::list &inputClassNames = FEOptions::GetInstance().GetInputClassFiles(); + const std::list &inputJarNames = FEOptions::GetInstance().GetInputJarFiles(); + success = success && jbcInput.ReadClassFiles(inputClassNames); + success = success && jbcInput.ReadJarFiles(inputJarNames); + CHECK_FATAL(success, "JBCCompilerComponent::ParseInput failed. Exit."); + const jbc::JBCClass *klass = jbcInput.GetFirstClass(); + while (klass != nullptr) { + FEInputStructHelper *structHelper = allocator.GetMemPool()->New(allocator, *klass); + structHelpers.push_back(structHelper); + klass = jbcInput.GetNextClass(); + } + timer.StopAndDumpTimeMS("JBCCompilerComponent::ParseInput()"); + return success; +} + +bool JBCCompilerComponent::LoadOnDemandTypeImpl() { + return false; +} + +void JBCCompilerComponent::ProcessPragmaImpl() {} + +std::unique_ptr JBCCompilerComponent::CreatFEFunctionImpl(FEInputMethodHelper *methodHelper) { + JBCClassMethod2FEHelper *jbcMethodHelper = static_cast(methodHelper); + GStrIdx methodNameIdx = methodHelper->GetMethodNameIdx(); + bool isStatic = methodHelper->IsStatic(); + MIRFunction *mirFunc = FEManager::GetTypeManager().GetMIRFunction(methodNameIdx, isStatic); + CHECK_NULL_FATAL(mirFunc); + std::unique_ptr feFunction = std::make_unique(*jbcMethodHelper, *mirFunc, phaseResultTotal); + module.AddFunction(mirFunc); + feFunction->Init(); + return feFunction; +} + +std::string JBCCompilerComponent::GetComponentNameImpl() const { + return "JBCCompilerComponent"; +} + +bool JBCCompilerComponent::ParallelableImpl() const { + return true; +} + +void JBCCompilerComponent::DumpPhaseTimeTotalImpl() const { + INFO(kLncInfo, "[PhaseTime] JBCCompilerComponent"); + HIR2MPLCompilerComponent::DumpPhaseTimeTotalImpl(); +} +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_function.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_function.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55b4bd740b80f87aa66d24c3929f9ea8dfc4f683 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_function.cpp @@ -0,0 +1,743 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_function.h" +#include "unistd.h" +#include "fe_macros.h" +#include "fe_algorithm.h" +#include "feir_var_reg.h" +#include "jbc_attr.h" +#include "fe_timer.h" + +namespace maple { +JBCFunction::JBCFunction(const JBCClassMethod2FEHelper &argMethodHelper, MIRFunction &mirFunc, + const std::unique_ptr &argPhaseResultTotal) + : FEFunction(mirFunc, argPhaseResultTotal), + methodHelper(argMethodHelper), + method(methodHelper.GetMethod()), + context(method.GetConstPool(), stack2feHelper, method.GetCode()) { + srcLang = MIRSrcLang::kSrcLangJava; +} + +JBCFunction::~JBCFunction() { + pesudoBBCatchPred = nullptr; +} + +void JBCFunction::InitImpl() { + FEFunction::InitImpl(); + feirCFG = std::make_unique(feirStmtHead, feirStmtHead); + feirCFG->Init(); + pesudoBBCatchPred = RegisterFEIRBB(std::make_unique()); +} + +void JBCFunction::PreProcessImpl() { +} + +bool JBCFunction::ProcessImpl() { + FE_INFO_LEVEL(FEOptions::kDumpLevelInfoDetail, "JBCFunction::Process() for %s", method.GetFullName().c_str()); + bool success = true; + if (!methodHelper.HasCode()) { + return success; // Skip abstract and native method, not emit it to mpl but mplts. + } + success = success && GenerateGeneralStmt("create general stmt"); + success = success && LabelGeneralStmts("label general stmt"); + success = success && LabelFEIRBBs("label general bb"); + success = success && LabelLabelIdx("label label idx"); + success = success && CheckJVMStack("check jvm stack"); + success = success && GenerateArgVarList("gen arg var list"); + success = success && ProcessFunctionArgs("process func args"); + if (FEOptions::GetInstance().IsEmitJBCLocalVarInfo()) { + success = success && EmitLocalVarInfo("emit localvar info"); + } + success = success && EmitToFEIRStmt("emit to feir"); + success = success && ProcessFEIRFunction(); + if (!success) { + error = true; + ERR(kLncErr, "JBCFunction::Process() failed for %s", method.GetFullName().c_str()); + } + return success; +} + +void JBCFunction::FinishImpl() { + bool dumpFunc = true; + dumpFunc = (FEOptions::GetInstance().IsDumpJBCErrorOnly() && error) || + FEOptions::GetInstance().IsDumpJBCAll() || + FEOptions::GetInstance().IsDumpJBCFuncName(method.GetFullName()); + if (dumpFunc) { + (void)BuildGeneralStmtBBMap("gen stmt_bb_map"); + } + if (FEOptions::GetInstance().IsDumpJBCStmt() && dumpFunc) { + DumpGeneralStmts(); + } + if (FEOptions::GetInstance().IsDumpFEIRBB() && dumpFunc) { + INFO(kLncInfo, "not implemented"); + } + if (FEOptions::GetInstance().IsDumpFEIRCFGGraph(method.GetFullName())) { + (void)DumpFEIRCFGGraph("dump cfg graph"); + } + (void)UpdateFormal("finish/update formal"); + // Not gen func body for abstract method + if (methodHelper.HasCode() || methodHelper.IsNative()) { + (void)EmitToMIR("finish/emit to mir"); + } + bool recordTime = FEOptions::GetInstance().IsDumpPhaseTime() || FEOptions::GetInstance().IsDumpPhaseTimeDetail(); + if (phaseResultTotal != nullptr && recordTime) { + phaseResultTotal->Combine(phaseResult); + } + if (FEOptions::GetInstance().IsDumpPhaseTimeDetail()) { + INFO(kLncInfo, "[PhaseTime] function: %s", method.GetFullName().c_str()); + phaseResult.Dump(); + } +} + +bool JBCFunction::PreProcessTypeNameIdx() { + return false; +} + +bool JBCFunction::GenerateGeneralStmt(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + const jbc::JBCAttrCode *code = method.GetCode(); + if (phaseResult.IsSuccess() && code != nullptr) { + if (!PreBuildJsrInfo(*code)) { + return phaseResult.Finish(false); + } + if (!BuildStmtFromInstruction(*code)) { + return phaseResult.Finish(false); + } + BuildStmtForCatch(*code); + BuildStmtForTry(*code); + BuildStmtForLOC(*code); + if (FEOptions::GetInstance().IsDumpInstComment()) { + BuildStmtForInstComment(*code); + } + ArrangeStmts(); + } + return phaseResult.Finish(true); +} + +void JBCFunction::GenerateGeneralStmtFailCallBack() { +} + +void JBCFunction::GenerateGeneralDebugInfo() { +} + +bool JBCFunction::VerifyGeneral() { + return false; +} + +void JBCFunction::VerifyGeneralFailCallBack() { +} + +bool JBCFunction::GenerateAliasVars(const std::string &phaseName) { + (void) phaseName; + return true; +} + +bool JBCFunction::GenerateArgVarList(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + InitStack2FEHelper(); + uint32 slotIdx = 0; + for (FEIRType *type : methodHelper.GetArgTypes()) { + PrimType pt = type->GetPrimType(); + std::unique_ptr var = std::make_unique(stack2feHelper.GetRegNumForSlot(slotIdx), + type->Clone()); + argVarList.push_back(std::move(var)); + if (type->IsScalar() && (pt == PTY_i64 || pt == PTY_f64)) { + slotIdx += JBCStack2FEHelper::kRegNumOffWide; + } else { + slotIdx += JBCStack2FEHelper::kRegNumOff; + } + } + return phaseResult.Finish(); +} + +bool JBCFunction::ProcessFunctionArgs(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + for (const UniqueFEIRVar &argVar : argVarList) { + ASSERT(argVar != nullptr, "nullptr check for argVar"); + const UniqueFEIRType &type = argVar->GetType(); + ASSERT(type != nullptr, "nullptr check for type"); + if (!type->IsScalar()) { + continue; + } + PrimType pty = type->GetPrimType(); + bool useZExt = (pty == PTY_u1 || pty == PTY_u16); + bool useSExt = (pty == PTY_i8 || pty == PTY_i16); + if (useZExt || useSExt) { + UniqueFEIRVar dstVar = argVar->Clone(); + dstVar->GetType()->SetPrimType(PTY_i32); + UniqueFEIRExpr exprExt = useZExt ? FEIRBuilder::CreateExprZExt(argVar->Clone()) : + FEIRBuilder::CreateExprSExt(argVar->Clone()); + UniqueFEIRStmt stmtExt = FEIRBuilder::CreateStmtDAssign(std::move(dstVar), std::move(exprExt)); + FEIRStmt *ptrFEIRStmt = RegisterFEIRStmt(std::move(stmtExt)); + feirStmtTail->InsertBefore(ptrFEIRStmt); + } + } + return phaseResult.Finish(); +} + +bool JBCFunction::EmitLocalVarInfo(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + const jbc::JBCAttrCode *code = method.GetCode(); + if (code == nullptr) { + return phaseResult.Finish(); + } + FEIRStmt *insPos = feirStmtHead; + std::list listInfo = code->GetLocalVarInfoByString(); + for (const std::string &infoStr : listInfo) { + UniqueFEIRStmt stmt = std::make_unique(infoStr); + FEIRStmt *ptrFEIRStmt = RegisterFEIRStmt(std::move(stmt)); + insPos->InsertAfter(ptrFEIRStmt); + insPos = ptrFEIRStmt; + } + return phaseResult.Finish(); +} + +bool JBCFunction::EmitToFEIRStmt(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + const FELinkListNode *bbNode = genBBHead->GetNext(); + while (bbNode != nullptr && bbNode != genBBTail) { + const JBCBB *bb = static_cast(bbNode); + EmitToFEIRStmt(*bb); + bbNode = bbNode->GetNext(); + } + return phaseResult.Finish(); +} + +void JBCFunction::EmitToFEIRStmt(const JBCBB &bb) { + bool success = false; + std::list feirStmts = stack2feHelper.LoadSwapStack(bb.GetMinStackIn(), success); + if (success == false) { + ERR(kLncErr, "LoadSwapStack Error for %s", method.GetFullName().c_str()); + return; + } + AppendFEIRStmts(feirStmts); + const FELinkListNode *stmtNode = bb.GetStmtHead(); + while (stmtNode != nullptr && success) { + const JBCStmt *stmt = static_cast(stmtNode); + feirStmts = stmt->EmitToFEIR(context, success); + AppendFEIRStmts(feirStmts); + if (stmtNode == bb.GetStmtTail()) { + break; + } + stmtNode = stmtNode->GetNext(); + } +} + +std::string JBCFunction::GetGeneralFuncName() const { + return method.GetFullName(); +} + +bool JBCFunction::CheckJVMStack(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + bool success = phaseResult.IsSuccess(); + FELinkListNode *nodeBB = genBBHead->GetNext(); + if (nodeBB == genBBTail) { + // empty function + return phaseResult.Finish(success); + } + // initialize function head + JBCBB *jbcBB = static_cast(nodeBB); + success = success && jbcBB->InitForFuncHeader(); + // initialize catch + for (FEIRBB *bbCatch : pesudoBBCatchPred->GetSuccBBs()) { + JBCBB *jbcBBCatch = static_cast(bbCatch); + success = success && jbcBBCatch->InitForCatch(); + } + // process + if (!success) { + return phaseResult.Finish(false); + } + std::map> correlation; + while (nodeBB != genBBTail) { + jbcBB = static_cast(nodeBB); + for (FEIRBB *bb : jbcBB->GetPredBBs()) { + if (bb != genBBHead && bb != pesudoBBCatchPred) { + CHECK_FATAL(correlation[jbcBB].insert(static_cast(bb)).second, "correlation map insert failed"); + } + } + nodeBB = nodeBB->GetNext(); + } + CorrelativeMerge stackUpdater(correlation, &JBCBB::UpdateStackByPredBB, &JBCBB::UpdateStackByPredBBEnd); + stackUpdater.ProcessAll(); + success = !stackUpdater.GetError(); + success = success && CheckJVMStackResult(); + return phaseResult.Finish(success); +} + +bool JBCFunction::CheckJVMStackResult() { + FELinkListNode *nodeBB = genBBHead->GetNext(); + while (nodeBB != nullptr && nodeBB != genBBTail) { + JBCBB *jbcBB = static_cast(nodeBB); + if (!jbcBB->CheckStack()) { + return false; + } + nodeBB = nodeBB->GetNext(); + } + return true; +} + +bool JBCFunction::PreBuildJsrInfo(const jbc::JBCAttrCode &code) { + const MapleMap &instMap = code.GetInstMap(); + for (const std::pair &it : instMap) { + uint32 pc = it.first; + jbc::JBCOp *op = it.second; + ASSERT_NOT_NULL(op); + jbc::JBCOpcode opcode = op->GetOpcode(); + jbc::JBCOpcodeKind kind = op->GetOpcodeKind(); + if (kind != jbc::kOpKindJsr) { + continue;; + } + uint32 width = (opcode == jbc::kOpJsr ? 3 : 5); // instruction width for jsr is 3, and for jsr_w is 5 + uint32 nextPC = pc + width; + jbc::JBCOpJsr *opJsr = static_cast(op); + auto itTarget = instMap.find(opJsr->GetTarget()); + if (itTarget == instMap.end()) { + ERR(kLncErr, "invalid target %u for jsr @pc=%u", opJsr->GetTarget(), pc); + return false; + } + jbc::JBCOp *opTarget = itTarget->second; + if (opTarget->GetOpcodeKind() != jbc::kOpKindStore) { + ERR(kLncErr, "invalid target (without astore) for jsr @pc=%u", pc); + return false; + } + jbc::JBCOpSlotOpr *opSlotOpr = static_cast(opTarget); + uint16 slotIdx = opSlotOpr->GetSlotIdx(); + opSlotOpr->SetAddressOpr(); + opJsr->SetSlotIdx(slotIdx); + int32 jsrID = context.RegisterJsrSlotRetAddr(slotIdx, nextPC); + opJsr->SetJsrID(jsrID); + } + return true; +} + +bool JBCFunction::BuildStmtFromInstruction(const jbc::JBCAttrCode &code) { + FEIRStmt *stmt = nullptr; + const MapleMap &instMap = code.GetInstMap(); + for (const std::pair &it : instMap) { + uint32 pc = it.first; + const jbc::JBCOp *op = it.second; + ASSERT(op != nullptr, "null ptr check"); + switch (op->GetOpcodeKind()) { + case jbc::kOpKindBranch: + stmt = BuildStmtFromInstructionForBranch(*op); + break; + case jbc::kOpKindGoto: + stmt = BuildStmtFromInstructionForGoto(*op); + break; + case jbc::kOpKindSwitch: + stmt = BuildStmtFromInstructionForSwitch(*op); + break; + case jbc::kOpKindJsr: + stmt = BuildStmtFromInstructionForJsr(*op); + break; + case jbc::kOpKindRet: + stmt = BuildStmtFromInstructionForRet(*op); + if (stmt == nullptr) { + return false; + } + break; + default: + stmt = RegisterFEIRStmt(std::make_unique(*op)); + break; + } + stmt->SetThrowable(op->IsThrowable()); + static_cast(stmt)->SetPC(pc); + genStmtTail->InsertBefore(stmt); + context.UpdateMapPCStmtInst(pc, stmt); + } + context.UpdateMapPCStmtInst(code.GetCodeLength(), genStmtTail); + return true; +} + +FEIRStmt *JBCFunction::BuildStmtFromInstructionForBranch(const jbc::JBCOp &op) { + const std::unique_ptr &uniStmt = + RegisterGeneralStmtUniqueReturn(std::make_unique(op)); + FEIRStmt *stmt = uniStmt.get(); + const jbc::JBCOpBranch &opBranch = static_cast(op); + FEIRStmt *target = BuildAndUpdateLabel(opBranch.GetTarget(), uniStmt); + static_cast(stmt)->AddExtraSucc(*target); + return stmt; +} + +FEIRStmt *JBCFunction::BuildStmtFromInstructionForGoto(const jbc::JBCOp &op) { + const std::unique_ptr &uniStmt = + RegisterGeneralStmtUniqueReturn(std::make_unique(op)); + FEIRStmt *stmt = uniStmt.get(); + stmt->SetFallThru(false); + const jbc::JBCOpGoto &opGoto = static_cast(op); + FEIRStmt *target = BuildAndUpdateLabel(opGoto.GetTarget(), uniStmt); + static_cast(stmt)->AddExtraSucc(*target); + return stmt; +} + +FEIRStmt *JBCFunction::BuildStmtFromInstructionForSwitch(const jbc::JBCOp &op) { + const std::unique_ptr &uniStmt = + RegisterGeneralStmtUniqueReturn(std::make_unique(op)); + FEIRStmt *stmt = uniStmt.get(); + stmt->SetFallThru(false); + const jbc::JBCOpSwitch &opSwitch = static_cast(op); + for (const std::pair &targetInfo : opSwitch.GetTargets()) { + FEIRStmt *target = BuildAndUpdateLabel(targetInfo.second, uniStmt); + static_cast(stmt)->AddExtraSucc(*target); + } + FEIRStmt *target = BuildAndUpdateLabel(opSwitch.GetDefaultTarget(), uniStmt); + static_cast(stmt)->AddExtraSucc(*target); + return stmt; +} + +FEIRStmt *JBCFunction::BuildStmtFromInstructionForJsr(const jbc::JBCOp &op) { + const std::unique_ptr &uniStmt = + RegisterGeneralStmtUniqueReturn(std::make_unique(op)); + FEIRStmt *stmt = uniStmt.get(); + stmt->SetFallThru(false); + const jbc::JBCOpJsr &opJsr = static_cast(op); + FEIRStmt *target = BuildAndUpdateLabel(opJsr.GetTarget(), uniStmt); + static_cast(stmt)->AddExtraSucc(*target); + return stmt; +} + +FEIRStmt *JBCFunction::BuildStmtFromInstructionForRet(const jbc::JBCOp &op) { + const std::map> &mapJsrSlotRetAddr = context.GetMapJsrSlotRetAddr(); + const std::unique_ptr &uniStmt = + RegisterGeneralStmtUniqueReturn(std::make_unique(op)); + FEIRStmt *stmt = uniStmt.get(); + stmt->SetFallThru(false); + const jbc::JBCOpRet &opRet = static_cast(op); + auto itJsrInfo = mapJsrSlotRetAddr.find(opRet.GetIndex()); + if (itJsrInfo == mapJsrSlotRetAddr.end()) { + ERR(kLncWarn, "invalid slotIdx for ret instruction"); + return nullptr; + } + for (auto itTarget : itJsrInfo->second) { + uint32 pc = itTarget.second; + FEIRStmt *target = BuildAndUpdateLabel(pc, uniStmt); + static_cast(stmt)->AddExtraSucc(*target); + } + return stmt; +} + +void JBCFunction::BuildStmtForCatch(const jbc::JBCAttrCode &code) { + const std::map &mapPCCatchStmt = context.GetMapPCCatchStmt(); + const MapleVector &exceptionInfo = code.GetExceptionInfos(); + for (const jbc::attr::ExceptionTableItem *item : exceptionInfo) { + uint16 handlerPC = item->GetHandlerPC(); + JBCStmtPesudoCatch *stmtCatch = nullptr; + auto it = mapPCCatchStmt.find(handlerPC); + if (it == mapPCCatchStmt.end()) { + stmtCatch = static_cast(RegisterFEIRStmt(std::make_unique())); + context.UpdateMapPCCatchStmt(handlerPC, stmtCatch); + } else { + stmtCatch = static_cast(it->second); + } + const jbc::JBCConstClass *catchType = item->GetCatchType(); + if (catchType != nullptr) { + stmtCatch->AddCatchTypeName(catchType->GetClassNameIdxMpl()); + } else { + stmtCatch->AddCatchTypeName(GStrIdx(0)); + } + } +} + +void JBCFunction::BuildStmtForTry(const jbc::JBCAttrCode &code) { + std::map, std::vector> rawInfo; + std::map outMapStartEnd; + std::map> outMapStartCatch; + const std::map &mapPCCatchStmt = context.GetMapPCCatchStmt(); + const MapleVector &exceptionInfo = code.GetExceptionInfos(); + for (const jbc::attr::ExceptionTableItem *item : exceptionInfo) { + uint32 start = item->GetStartPC(); + uint32 end = item->GetEndPC(); + uint32 handlerPC = item->GetHandlerPC(); + rawInfo[std::make_pair(start, end)].push_back(handlerPC); + } + BuildTryInfo(rawInfo, outMapStartEnd, outMapStartCatch); + for (const std::pair &startEnd : outMapStartEnd) { + // Try + JBCStmtPesudoTry *stmtTry = + static_cast(RegisterFEIRStmt(std::make_unique())); + auto it = outMapStartCatch.find(startEnd.first); + CHECK_FATAL(it != outMapStartCatch.end(), "catch info not exist"); + for (uint32 handlerPC : it->second) { + auto itHandler = mapPCCatchStmt.find(handlerPC); + CHECK_FATAL(itHandler != mapPCCatchStmt.end(), "catch stmt not exist"); + stmtTry->AddCatchStmt(*(itHandler->second)); + } + context.UpdateMapPCTryStmt(startEnd.first, stmtTry); + // EndTry + JBCStmtPesudoEndTry *stmtEndTry = + static_cast(RegisterFEIRStmt(std::make_unique())); + context.UpdateMapPCEndTryStmt(startEnd.second, stmtEndTry); + } +} + +void JBCFunction::BuildTryInfo(const std::map, std::vector> &rawInfo, + std::map &outMapStartEnd, + std::map> &outMapStartCatch) { + const uint8 flagStart = 0x1; + const uint8 flagEnd = 0x2; + const uint8 flagCatch = 0x4; + std::map keyPoints; + std::map> mapStartEnds; + std::map> mapEndStarts; + for (auto info : rawInfo) { + keyPoints[info.first.first] |= flagStart; + keyPoints[info.first.second] |= flagEnd; + for (uint32 handlerPC : info.second) { + keyPoints[handlerPC] |= flagCatch; + } + CHECK_FATAL(mapStartEnds[info.first.first].insert(info.first.second).second, "mapStartEnds insert failed"); + CHECK_FATAL(mapEndStarts[info.first.second].insert(info.first.first).second, "mapEndStarts insert failed"); + } + std::deque> blockQueue; + const uint32 posInvalid = 0xFFFFFFFF; + uint32 startPos = posInvalid; + for (auto keyPoint : keyPoints) { + uint32 curPos = keyPoint.first; + uint8 flag = keyPoint.second; + // set try block + if (startPos != posInvalid) { + outMapStartEnd[startPos] = curPos; + BuildTryInfoCatch(rawInfo, blockQueue, startPos, outMapStartCatch); + startPos = curPos; + } + // process end + if ((flag & flagEnd) != 0) { + blockQueue.push_back(std::make_pair(posInvalid, posInvalid)); + std::pair top; + do { + top = blockQueue.front(); + blockQueue.pop_front(); + bool deleted = false; + if (top.second == curPos) { + ASSERT(mapEndStarts.find(curPos) != mapEndStarts.end(), "try end not found"); + if (mapEndStarts[curPos].find(top.first) != mapEndStarts[curPos].end()) { + deleted = true; + } + } + if (!deleted && top.first != posInvalid) { + blockQueue.push_back(top); + } + } while (top.first != posInvalid); + if (blockQueue.size() == 0) { + startPos = posInvalid; + } + } + // process start + if ((flag & flagStart) != 0) { + startPos = curPos; + for (uint32 endPos : mapStartEnds[curPos]) { + blockQueue.push_back(std::make_pair(curPos, endPos)); + } + } + } +} + +void JBCFunction::BuildTryInfoCatch(const std::map, std::vector> &rawInfo, + const std::deque> &blockQueue, + uint32 startPos, + std::map> &outMapStartCatch) { + std::set catchSet; + for (const std::pair &block : blockQueue) { + auto it = rawInfo.find(block); + CHECK_FATAL(it != rawInfo.end(), "block not found"); + for (uint32 handlerPC : it->second) { + if (catchSet.find(handlerPC) == catchSet.end()) { + outMapStartCatch[startPos].push_back(handlerPC); + CHECK_FATAL(catchSet.insert(handlerPC).second, "catchSet insert failed"); + } + } + } +} + +void JBCFunction::BuildStmtForLOC(const jbc::JBCAttrCode &code) { + const jbc::JBCAttr *attrRaw = code.GetAttr(jbc::JBCAttrKind::kAttrLineNumberTable); + if (attrRaw == nullptr) { + return; + } + const jbc::JBCAttrLineNumberTable *attrLineNumTab = static_cast(attrRaw); + uint32 srcFileIdx = method.GetClass().GetSrcFileInfoIdx(); + const MapleVector &lineNums = attrLineNumTab->GetLineNums(); + for (const jbc::attr::LineNumberTableItem *item : lineNums) { + JBCStmtPesudoLOC *stmtLOC = + static_cast(RegisterFEIRStmt(std::make_unique())); + stmtLOC->SetSrcFileIdx(srcFileIdx); + stmtLOC->SetLineNumber(item->GetLineNumber()); + context.UpdateMapPCStmtLOC(item->GetStartPC(), stmtLOC); + } +} + +void JBCFunction::BuildStmtForInstComment(const jbc::JBCAttrCode &code) { + const jbc::JBCAttr *attrRaw = code.GetAttr(jbc::JBCAttrKind::kAttrLineNumberTable); + std::map mapPCLineNum; + if (attrRaw != nullptr) { + const jbc::JBCAttrLineNumberTable *attrLineNumTab = static_cast(attrRaw); + const MapleVector &lineNums = attrLineNumTab->GetLineNums(); + for (const jbc::attr::LineNumberTableItem *item : lineNums) { + ASSERT_NOT_NULL(item); + mapPCLineNum[item->GetStartPC()] = item->GetLineNumber(); + } + } + uint16 currLineNum = 0xFFFF; // use 0xFFFF as invalid line number + std::stringstream ss; + const jbc::JBCConstPool &constPool = method.GetConstPool(); + const MapleMap &instMap = code.GetInstMap(); + for (const std::pair &it : instMap) { + uint32 pc = it.first; + jbc::JBCOp *op = it.second; + if (mapPCLineNum.find(pc) != mapPCLineNum.end()) { + currLineNum = mapPCLineNum[pc]; + } + ASSERT(pc < 0x10000, "invalid pc"); // pc use 16bit in java bytecode (less than 0x10000) + ss << "LINE " << srcFileName << " : "; + if (currLineNum != 0xFFFF) { // use 0xFFFF as invalid line number + ss << std::dec << currLineNum; + } else { + ss << "unknown"; + } + ss << ", PC : " << std::setfill(' ') << std::setw(5) << pc << "||" << + std::setfill('0') << std::setw(4) << std::hex << pc << " : " << + op->Dump(constPool); + std::unique_ptr stmt = std::make_unique(ss.str()); + JBCStmtPesudoComment *ptrStmt = static_cast(RegisterFEIRStmt(std::move(stmt))); + context.UpdateMapPCCommentStmt(pc, ptrStmt); + ss.str(""); + } +} + +FEIRStmt *JBCFunction::BuildAndUpdateLabel(uint32 dstPC, const std::unique_ptr &srcStmt) { + const std::map &mapPCLabelStmt = context.GetMapPCLabelStmt(); + auto it = mapPCLabelStmt.find(dstPC); + JBCStmtPesudoLabel *stmtLabel = nullptr; + if (it == mapPCLabelStmt.end()) { + stmtLabel = static_cast(RegisterFEIRStmt(std::make_unique())); + context.UpdateMapPCLabelStmt(dstPC, stmtLabel); + } else { + stmtLabel = it->second; + } + ASSERT(stmtLabel != nullptr, "null ptr check"); + stmtLabel->AddExtraPred(*srcStmt); + return stmtLabel; +} + +void JBCFunction::ArrangeStmts() { + context.ArrangeStmts(); +} + +void JBCFunction::InitStack2FEHelper() { + const jbc::JBCAttrCode *code = method.GetCode(); + // args + uint32 nargs = 0; + for (FEIRType *type : methodHelper.GetArgTypes()) { + PrimType pt = type->GetPrimType(); + if (type->IsScalar() && (pt == PTY_i64 || pt == PTY_f64)) { + nargs += JBCStack2FEHelper::kRegNumOffWide; + } else { + nargs += JBCStack2FEHelper::kRegNumOff; + } + } + if (code == nullptr) { + stack2feHelper.SetNArgs(nargs); + stack2feHelper.SetNLocals(0); + stack2feHelper.SetNStacks(0); + stack2feHelper.SetNSwaps(0); + return; + } + stack2feHelper.SetNArgs(nargs); + CHECK_FATAL(nargs <= code->GetMaxLocals(), "invalid jbc method"); + stack2feHelper.SetNLocals(code->GetMaxLocals() - nargs); + stack2feHelper.SetNStacks(code->GetMaxStack()); + stack2feHelper.SetNSwaps(CalculateMaxSwapSize()); + if (!FEOptions::GetInstance().IsDumpInstComment()) { + return; + } + std::stringstream ss; + ss << "StackToReg Info: nStacks=" << stack2feHelper.GetNStacks() << + ", nSwaps=" << stack2feHelper.GetNSwaps() << + ", maxLocals=" << code->GetMaxLocals() << + ", nArgs=" << stack2feHelper.GetNArgs(); + feirStmtTail->InsertBefore(RegisterFEIRStmt(FEIRBuilder::CreateStmtComment(ss.str()))); + feirStmtTail->InsertBefore(RegisterFEIRStmt(FEIRBuilder::CreateStmtComment("==== Reg Map ===="))); + uint32 regStart = 0; + ss.str(""); + ss << " " << regStart << " - " << (regStart + stack2feHelper.GetNStacks() - 1) << ": stacks"; + feirStmtTail->InsertBefore(RegisterFEIRStmt(FEIRBuilder::CreateStmtComment(ss.str()))); + regStart += stack2feHelper.GetNStacks(); + if (stack2feHelper.GetNSwaps() > 0) { + ss.str(""); + ss << " " << regStart << " - " << (regStart + stack2feHelper.GetNSwaps() - 1) << ": swaps"; + feirStmtTail->InsertBefore(RegisterFEIRStmt(FEIRBuilder::CreateStmtComment(ss.str()))); + regStart += stack2feHelper.GetNSwaps(); + } + if (stack2feHelper.GetNLocals() > 0) { + ss.str(""); + ss << " " << regStart << " - " << (regStart + stack2feHelper.GetNLocals() - 1) << ": locals"; + feirStmtTail->InsertBefore(RegisterFEIRStmt(FEIRBuilder::CreateStmtComment(ss.str()))); + regStart += stack2feHelper.GetNLocals(); + } + if (stack2feHelper.GetNArgs() > 0) { + ss.str(""); + ss << " " << regStart << " - " << (regStart + stack2feHelper.GetNArgs() - 1) << ": args"; + feirStmtTail->InsertBefore(RegisterFEIRStmt(FEIRBuilder::CreateStmtComment(ss.str()))); + } + feirStmtTail->InsertBefore(RegisterFEIRStmt(FEIRBuilder::CreateStmtComment("================="))); +} + +uint32 JBCFunction::CalculateMaxSwapSize() const { + const FELinkListNode *nodeBB = genBBHead->GetNext(); + uint32 size = 0; + while (nodeBB != nullptr && nodeBB != genBBTail) { + const JBCBB *bb = static_cast(nodeBB); + uint32 tmp = bb->GetSwapSize(); + size = size > tmp ? size : tmp; + nodeBB = nodeBB->GetNext(); + } + return size; +} + +bool JBCFunction::LabelLabelIdx(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + uint32 idx = 0; + FELinkListNode *nodeStmt = genStmtHead->GetNext(); + while (nodeStmt != nullptr && nodeStmt != genStmtTail) { + JBCStmt *stmt = static_cast(nodeStmt); + if (stmt->GetJBCKind() == JBCStmtKind::kJBCStmtPesudoLabel || + stmt->GetJBCKind() == JBCStmtKind::kJBCStmtPesudoCatch) { + JBCStmtPesudoLabel *stmtLabel = static_cast(stmt); + stmtLabel->SetLabelIdx(idx); + idx++; + } + nodeStmt = nodeStmt->GetNext(); + } + return phaseResult.Finish(); +} + +bool JBCFunction::NeedConvertToInt32(const std::unique_ptr &var) { + ASSERT(var != nullptr, "nullptr check for var"); + const std::unique_ptr &type = var->GetType(); + if (!type->IsScalar()) { + return false; + } + PrimType pty = type->GetPrimType(); + // Z: PTY_u1 + // B: PTY_i8 + // C: PTY_u16 + // S: PTY_i16 + if (pty == PTY_u1 || pty == PTY_u8 || pty == PTY_i8 || pty == PTY_u16 || pty == PTY_i16) { + return true; + } else { + return false; + } +} +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_function_context.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_function_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87ceb84e22b6108d8a08c48a41160354aa980f15 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_function_context.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_function_context.h" + +namespace maple { +int32 JBCFunctionContext::RegisterJsrSlotRetAddr(uint16 slotIdx, uint32 nextPC) { + auto itInfo = mapJsrSlotRetAddr.find(slotIdx); + int32 jsrID; + if (itInfo == mapJsrSlotRetAddr.end()) { + jsrID = 0; + } else { + size_t size = itInfo->second.size(); + CHECK_FATAL(size < INT32_MAX, "jsr ID out of range"); + jsrID = static_cast(itInfo->second.size()); + } + mapJsrSlotRetAddr[slotIdx][jsrID] = nextPC; + return jsrID; +} + +void JBCFunctionContext::ArrangeStmts() { + /* Type of stmt: inst, label, try, endtry, catch, comment, loc + * endtry + * loc + * catch + * label + * try + * comment + * inst + */ + for (const std::pair &pcInst : mapPCStmtInst) { + uint32 pc = pcInst.first; + FEIRStmt *stmtInst = pcInst.second; + if (mapPCEndTryStmt.find(pc) != mapPCEndTryStmt.end()) { + stmtInst->InsertBefore(mapPCEndTryStmt[pc]); + } + if (mapPCStmtLOC.find(pc) != mapPCStmtLOC.end()) { + stmtInst->InsertBefore(mapPCStmtLOC[pc]); + } + if (mapPCCatchStmt.find(pc) != mapPCCatchStmt.end()) { + stmtInst->InsertBefore(mapPCCatchStmt[pc]); + } + if (mapPCLabelStmt.find(pc) != mapPCLabelStmt.end()) { + stmtInst->InsertBefore(mapPCLabelStmt[pc]); + } + if (mapPCTryStmt.find(pc) != mapPCTryStmt.end()) { + stmtInst->InsertBefore(mapPCTryStmt[pc]); + } + if (mapPCCommentStmt.find(pc) != mapPCCommentStmt.end()) { + stmtInst->InsertBefore(mapPCCommentStmt[pc]); + } + } +} + +const FEIRType *JBCFunctionContext::GetSlotType(uint16 slotIdx, uint32 pc) const { + CHECK_NULL_FATAL(code); + const jbc::JBCAttrLocalVariableInfo &localVarInfo = code->GetLocalVarInfo(); + CHECK_FATAL(pc < UINT16_MAX, "pc out of range"); + uint16 startPC = localVarInfo.GetStart(slotIdx, static_cast(pc)); + const jbc::JavaAttrLocalVariableInfoItem &info = localVarInfo.GetItemByStart(slotIdx, startPC); + return info.feirType; +} + +const FEIRType *JBCFunctionContext::GetSlotType(uint16 slotIdx) const { + CHECK_NULL_FATAL(code); + const jbc::JBCAttrLocalVariableInfo &localVarInfo = code->GetLocalVarInfo(); + CHECK_FATAL(currPC < UINT16_MAX, "pc out of range"); + uint16 startPC = localVarInfo.GetStart(slotIdx, static_cast(currPC)); + const jbc::JavaAttrLocalVariableInfoItem &info = localVarInfo.GetItemByStart(slotIdx, startPC); + return info.feirType; +} +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_input.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_input.cpp new file mode 100644 index 0000000000000000000000000000000000000000..458dc34eed539fa484eb518575b139620279cc08 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_input.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_input.h" +#include "basic_io.h" +#include "simple_zip.h" +#include "fe_macros.h" +#include "fe_options.h" +#include "hir2mpl_env.h" +#include "fe_manager.h" + +namespace maple { +namespace jbc { +namespace { +const std::string kClassFileSuffix = ".class"; +const uint32 kClassFileSuffixLength = 6; +const std::string kJarMetaInf = "META-INF"; +const uint32 kJarMetaInfLength = 8; +} +JBCInput::JBCInput(MIRModule &moduleIn) + : module(moduleIn), + mp(FEUtils::NewMempool("mempool for JBC Input Helper", false /* isLocalPool */)), + allocator(mp), + klassList(allocator.Adapter()) { + itKlass = klassList.end(); +} + +JBCInput::~JBCInput() { + mp = nullptr; +} + +void JBCInput::ReleaseMemPool() { + FEUtils::DeleteMempoolPtr(mp); +} + +bool JBCInput::ReadClassFile(const std::string &fileName) { + (void)GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fileName); + BasicIOMapFile file(fileName); + BasicIORead io(file, true); + if (file.OpenAndMap() == false) { + ERR(kLncErr, "Unable to open class file %s", fileName.c_str()); + return false; + } + JBCClass *klass = JBCClass::InClass(allocator, io); + if (klass == nullptr) { + ERR(kLncErr, "Unable to parse class file %s", fileName.c_str()); + file.Close(); + return false; + } + klass->SetFilePathName(fileName); + RegisterSrcFileInfo(*klass); + klassList.push_back(klass); + file.Close(); + return true; +} + +bool JBCInput::ReadClassFiles(const std::list &fileNames) { + bool success = true; + for (const std::string &fileName : fileNames) { + FE_INFO_LEVEL(FEOptions::kDumpLevelInfoDetail, "===== Process JBCInput::ReadClassFiles(%s) =====", + fileName.c_str()); + success = ReadClassFile(fileName) ? success : false; + } + return success; +} + +bool JBCInput::ReadJarFile(const std::string &fileName) { + (void)GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fileName); + BasicIOMapFile file(fileName); + bool success = true; + if (file.OpenAndMap() == false) { + ERR(kLncErr, "Unable to open jar file %s", fileName.c_str()); + return false; + } + SimpleZip zipFile(file); + zipFile.ParseFile(); + for (const std::unique_ptr &zipLocalFile : zipFile.GetFiles()) { + std::string zipLocalFileName = zipLocalFile->GetFileName(); + size_t len = zipLocalFileName.length(); + if (len > kClassFileSuffixLength && + zipLocalFileName.substr(len - kClassFileSuffixLength).compare(kClassFileSuffix) == 0) { + if (zipLocalFileName.length() >= kJarMetaInfLength && + zipLocalFileName.substr(0, kJarMetaInfLength).compare(kJarMetaInf) == 0) { + continue; + } + // class file + BasicIOMapFile classFile(zipLocalFileName, zipLocalFile->GetUnCompData(), zipLocalFile->GetUnCompDataSize()); + BasicIORead ioClassFile(classFile, true); + JBCClass *klass = JBCClass::InClass(allocator, ioClassFile); + if (klass == nullptr) { + ERR(kLncErr, "Unable to parse class file %s", zipLocalFileName.c_str()); + success = false; + } else { + klass->SetFilePathName(zipLocalFileName); + RegisterSrcFileInfo(*klass); + klassList.push_back(klass); + } + } + } + file.Close(); + if (!success) { + return false; + } + return true; +} + +bool JBCInput::ReadJarFiles(const std::list &fileNames) { + bool success = true; + for (const std::string &fileName : fileNames) { + FE_INFO_LEVEL(FEOptions::kDumpLevelInfoDetail, "===== Process JBCInput::ReadJarFiles(%s) =====", fileName.c_str()); + success = ReadJarFile(fileName) ? success : false; + } + return success; +} + +const JBCClass *JBCInput::GetFirstClass() { + if (klassList.size() == 0) { + return nullptr; + } + itKlass = klassList.begin(); + return *itKlass; +} + +const JBCClass *JBCInput::GetNextClass() { + if (itKlass == klassList.end()) { + return nullptr; + } + ++itKlass; + if (itKlass == klassList.end()) { + return nullptr; + } + return *itKlass; +} + +void JBCInput::RegisterSrcFileInfo(JBCClass &klass) { + GStrIdx fileNameIdx; + if (FEOptions::GetInstance().IsJBCInfoUsePathName()) { + fileNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(klass.GetFilePathName()); + } else { + fileNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(klass.GetFileName()); + } + uint32 srcFileIdx = HIR2MPLEnv::GetInstance().NewSrcFileIdx(fileNameIdx); + module.PushbackFileInfo(MIRInfoPair(fileNameIdx, srcFileIdx)); + klass.SetSrcFileInfoIdx(srcFileIdx); +} +} // namespace jbc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_opcode.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_opcode.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b75ee723df39e7d82a91730698b8438e03011879 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_opcode.cpp @@ -0,0 +1,1573 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_opcode.h" +#include "jbc_class_const.h" +#include "jbc_class_const_pool.h" +#include "jbc_util.h" +#include "fe_type_manager.h" + +namespace maple { +namespace jbc { +// ---------- JBCOpcodeInfo ---------- +JBCOpcodeInfo::JBCOpcodeInfo() { +#define JBC_OP(mOp, mValue, mKind, mName, mFlag) \ + table[kOp##mOp].kind = kOpKind##mKind; \ + table[kOp##mOp].name = mName; \ + table[kOp##mOp].flags = mFlag; +#include "jbc_opcode.def" +#undef JBC_OP +} + +// ---------- JBCOp ---------- +JBCOpcodeInfo JBCOp::opcodeInfo; +std::vector JBCOp::emptyPrimTypes; + +JBCOp::JBCOp(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : alloc(allocator), op(opIn), kind(kindIn), wide(wideIn) {} + +bool JBCOp::CheckNotWide(const BasicIORead &io) const { + // wide only can be used with i/f/l/d/aload, i/f/l/d/astore, ret, and iinc + if (wide) { + ERR(kLncErr, "opcode %s @ pc=%u can not own wide prefix", GetOpcodeName().c_str(), io.GetPos() - 1); + return false; + } + return true; +} + +std::string JBCOp::DumpImpl(const JBCConstPool &constPool) const { + (void) constPool; + return GetOpcodeName(); +} + +const std::vector &JBCOp::GetInputTypesFromStackImpl() const { + return emptyPrimTypes; +} + +std::vector JBCOp::GetInputTypesFromStackImpl(const JBCConstPool &constPool) const { + (void) constPool; + return GetInputTypesFromStackImpl(); +} + +JBCPrimType JBCOp::GetOutputTypesToStackImpl() const { + return kTypeDefault; +} + +JBCPrimType JBCOp::GetOutputTypesToStackImpl(const JBCConstPool &constPool) const { + (void) constPool; + return GetOutputTypesToStackImpl(); +} + +// ---------- JBCOpUnused ---------- +JBCOpUnused::JBCOpUnused(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn) {} + +bool JBCOpUnused::ParseFileImpl(BasicIORead &io) { + (void) io; + WARN(kLncWarn, "Unused opcode %s", GetOpcodeName().c_str()); + return true; +} + +// ---------- JBCOpReversed ---------- +JBCOpReversed::JBCOpReversed(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn) {} + +bool JBCOpReversed::ParseFileImpl(BasicIORead &io) { + (void) io; + ERR(kLncErr, "Reversed opcode %s", GetOpcodeName().c_str()); + return false; +} + +// ---------- JBCOpDefault ---------- +std::map> JBCOpDefault::mapOpInputTypes = JBCOpDefault::InitMapOpInputTypes(); +std::map JBCOpDefault::mapOpOutputType = JBCOpDefault::InitMapOpOutputType(); + +JBCOpDefault::JBCOpDefault(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn) {} + +bool JBCOpDefault::ParseFileImpl(BasicIORead &io) { + if (JBCOp::CheckNotWide(io) == false) { + return false; + } + return true; +} + +const std::vector &JBCOpDefault::GetInputTypesFromStackImpl() const { + auto it = mapOpInputTypes.find(op); + CHECK_FATAL(it != mapOpInputTypes.end(), "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +JBCPrimType JBCOpDefault::GetOutputTypesToStackImpl() const { + auto it = mapOpOutputType.find(op); + CHECK_FATAL(it != mapOpOutputType.end(), "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +std::map> JBCOpDefault::InitMapOpInputTypes() { + std::map> ans; + ans[kOpNop] = emptyPrimTypes; + InitMapOpInputTypesForArrayLoad(ans); + InitMapOpInputTypesForArrayStore(ans); + InitMapOpInputTypesForMathBinop(ans); + InitMapOpInputTypesForMathUnop(ans); + InitMapOpInputTypesForConvert(ans); + InitMapOpInputTypesForCompare(ans); + InitMapOpInputTypesForReturn(ans); + InitMapOpInputTypesForThrow(ans); + InitMapOpInputTypesForMonitor(ans); + InitMapOpInputTypesForArrayLength(ans); + return ans; +} + +std::map JBCOpDefault::InitMapOpOutputType() { + std::map ans; + ans[kOpNop] = kTypeDefault; + InitMapOpOutputTypesForArrayLoad(ans); + InitMapOpOutputTypesForArrayStore(ans); + InitMapOpOutputTypesForMathBinop(ans); + InitMapOpOutputTypesForMathUnop(ans); + InitMapOpOutputTypesForConvert(ans); + InitMapOpOutputTypesForCompare(ans); + InitMapOpOutputTypesForReturn(ans); + InitMapOpOutputTypesForThrow(ans); + InitMapOpOutputTypesForMonitor(ans); + InitMapOpOutputTypesForArrayLength(ans); + return ans; +} + +void JBCOpDefault::InitMapOpInputTypesForArrayLoad(std::map> &ans) { + ans[kOpIALoad] = std::vector({ kTypeRef, kTypeInt }); + ans[kOpLALoad] = std::vector({ kTypeRef, kTypeInt }); + ans[kOpFALoad] = std::vector({ kTypeRef, kTypeInt }); + ans[kOpDALoad] = std::vector({ kTypeRef, kTypeInt }); + ans[kOpAALoad] = std::vector({ kTypeRef, kTypeInt }); + ans[kOpBALoad] = std::vector({ kTypeRef, kTypeInt }); + ans[kOpCALoad] = std::vector({ kTypeRef, kTypeInt }); + ans[kOpSALoad] = std::vector({ kTypeRef, kTypeInt }); +} + +void JBCOpDefault::InitMapOpOutputTypesForArrayLoad(std::map &ans) { + ans[kOpIALoad] = kTypeInt; + ans[kOpLALoad] = kTypeLong; + ans[kOpFALoad] = kTypeFloat; + ans[kOpDALoad] = kTypeDouble; + ans[kOpAALoad] = kTypeRef; + ans[kOpBALoad] = kTypeByteOrBoolean; + ans[kOpCALoad] = kTypeChar; + ans[kOpSALoad] = kTypeShort; +} + +void JBCOpDefault::InitMapOpInputTypesForArrayStore(std::map> &ans) { + ans[kOpIAStore] = std::vector({ kTypeRef, kTypeInt, kTypeInt }); + ans[kOpLAStore] = std::vector({ kTypeRef, kTypeInt, kTypeLong }); + ans[kOpFAStore] = std::vector({ kTypeRef, kTypeInt, kTypeFloat }); + ans[kOpDAStore] = std::vector({ kTypeRef, kTypeInt, kTypeDouble }); + ans[kOpAAStore] = std::vector({ kTypeRef, kTypeInt, kTypeRef }); + ans[kOpBAStore] = std::vector({ kTypeRef, kTypeInt, kTypeByteOrBoolean }); + ans[kOpCAStore] = std::vector({ kTypeRef, kTypeInt, kTypeChar }); + ans[kOpSAStore] = std::vector({ kTypeRef, kTypeInt, kTypeShort }); +} + +void JBCOpDefault::InitMapOpOutputTypesForArrayStore(std::map &ans) { + ans[kOpIAStore] = kTypeDefault; + ans[kOpLAStore] = kTypeDefault; + ans[kOpFAStore] = kTypeDefault; + ans[kOpDAStore] = kTypeDefault; + ans[kOpAAStore] = kTypeDefault; + ans[kOpBAStore] = kTypeDefault; + ans[kOpCAStore] = kTypeDefault; + ans[kOpSAStore] = kTypeDefault; +} + +void JBCOpDefault::InitMapOpInputTypesForMathBinop(std::map> &ans) { + ans[kOpIAdd] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpLAdd] = std::vector({ kTypeLong, kTypeLong }); + ans[kOpFAdd] = std::vector({ kTypeFloat, kTypeFloat }); + ans[kOpDAdd] = std::vector({ kTypeDouble, kTypeDouble }); + ans[kOpISub] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpLSub] = std::vector({ kTypeLong, kTypeLong }); + ans[kOpFSub] = std::vector({ kTypeFloat, kTypeFloat }); + ans[kOpDSub] = std::vector({ kTypeDouble, kTypeDouble }); + ans[kOpIMul] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpLMul] = std::vector({ kTypeLong, kTypeLong }); + ans[kOpFMul] = std::vector({ kTypeFloat, kTypeFloat }); + ans[kOpDMul] = std::vector({ kTypeDouble, kTypeDouble }); + ans[kOpIDiv] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpLDiv] = std::vector({ kTypeLong, kTypeLong }); + ans[kOpFDiv] = std::vector({ kTypeFloat, kTypeFloat }); + ans[kOpDDiv] = std::vector({ kTypeDouble, kTypeDouble }); + ans[kOpIRem] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpLRem] = std::vector({ kTypeLong, kTypeLong }); + ans[kOpFRem] = std::vector({ kTypeFloat, kTypeFloat }); + ans[kOpDRem] = std::vector({ kTypeDouble, kTypeDouble }); + ans[kOpIShl] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpLShl] = std::vector({ kTypeLong, kTypeInt }); + ans[kOpIShr] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpLShr] = std::vector({ kTypeLong, kTypeInt }); + ans[kOpIUShr] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpLUShr] = std::vector({ kTypeLong, kTypeInt }); + ans[kOpIAnd] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpLAnd] = std::vector({ kTypeLong, kTypeLong }); + ans[kOpIOr] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpLOr] = std::vector({ kTypeLong, kTypeLong }); + ans[kOpIXor] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpLXor] = std::vector({ kTypeLong, kTypeLong }); +} + +void JBCOpDefault::InitMapOpOutputTypesForMathBinop(std::map &ans) { + ans[kOpIAdd] = kTypeInt; + ans[kOpLAdd] = kTypeLong; + ans[kOpFAdd] = kTypeFloat; + ans[kOpDAdd] = kTypeDouble; + ans[kOpISub] = kTypeInt; + ans[kOpLSub] = kTypeLong; + ans[kOpFSub] = kTypeFloat; + ans[kOpDSub] = kTypeDouble; + ans[kOpIMul] = kTypeInt; + ans[kOpLMul] = kTypeLong; + ans[kOpFMul] = kTypeFloat; + ans[kOpDMul] = kTypeDouble; + ans[kOpIDiv] = kTypeInt; + ans[kOpLDiv] = kTypeLong; + ans[kOpFDiv] = kTypeFloat; + ans[kOpDDiv] = kTypeDouble; + ans[kOpIRem] = kTypeInt; + ans[kOpLRem] = kTypeLong; + ans[kOpFRem] = kTypeFloat; + ans[kOpDRem] = kTypeDouble; + ans[kOpIShl] = kTypeInt; + ans[kOpLShl] = kTypeLong; + ans[kOpIShr] = kTypeInt; + ans[kOpLShr] = kTypeLong; + ans[kOpIUShr] = kTypeInt; + ans[kOpLUShr] = kTypeLong; + ans[kOpIAnd] = kTypeInt; + ans[kOpLAnd] = kTypeLong; + ans[kOpIOr] = kTypeInt; + ans[kOpLOr] = kTypeLong; + ans[kOpIXor] = kTypeInt; + ans[kOpLXor] = kTypeLong; +} + +void JBCOpDefault::InitMapOpInputTypesForMathUnop(std::map> &ans) { + ans[kOpINeg] = std::vector({ kTypeInt }); + ans[kOpLNeg] = std::vector({ kTypeLong }); + ans[kOpFNeg] = std::vector({ kTypeFloat }); + ans[kOpDNeg] = std::vector({ kTypeDouble }); +} + +void JBCOpDefault::InitMapOpOutputTypesForMathUnop(std::map &ans) { + ans[kOpINeg] = kTypeInt; + ans[kOpLNeg] = kTypeLong; + ans[kOpFNeg] = kTypeFloat; + ans[kOpDNeg] = kTypeDouble; +} + +void JBCOpDefault::InitMapOpInputTypesForConvert(std::map> &ans) { + ans[kOpI2L] = std::vector({ kTypeInt }); + ans[kOpI2F] = std::vector({ kTypeInt }); + ans[kOpI2D] = std::vector({ kTypeInt }); + ans[kOpL2I] = std::vector({ kTypeLong }); + ans[kOpL2F] = std::vector({ kTypeLong }); + ans[kOpL2D] = std::vector({ kTypeLong }); + ans[kOpF2I] = std::vector({ kTypeFloat }); + ans[kOpF2L] = std::vector({ kTypeFloat }); + ans[kOpF2D] = std::vector({ kTypeFloat }); + ans[kOpD2I] = std::vector({ kTypeDouble }); + ans[kOpD2L] = std::vector({ kTypeDouble }); + ans[kOpD2F] = std::vector({ kTypeDouble }); + ans[kOpI2B] = std::vector({ kTypeInt }); + ans[kOpI2C] = std::vector({ kTypeInt }); + ans[kOpI2S] = std::vector({ kTypeInt }); +} + +void JBCOpDefault::InitMapOpOutputTypesForConvert(std::map &ans) { + ans[kOpI2L] = kTypeLong; + ans[kOpI2F] = kTypeFloat; + ans[kOpI2D] = kTypeDouble; + ans[kOpL2I] = kTypeInt; + ans[kOpL2F] = kTypeFloat; + ans[kOpL2D] = kTypeDouble; + ans[kOpF2I] = kTypeInt; + ans[kOpF2L] = kTypeLong; + ans[kOpF2D] = kTypeDouble; + ans[kOpD2I] = kTypeInt; + ans[kOpD2L] = kTypeLong; + ans[kOpD2F] = kTypeFloat; + ans[kOpI2B] = kTypeByteOrBoolean; + ans[kOpI2C] = kTypeChar; + ans[kOpI2S] = kTypeShort; +} + +void JBCOpDefault::InitMapOpInputTypesForCompare(std::map> &ans) { + ans[kOpLCmp] = std::vector({ kTypeLong, kTypeLong }); + ans[kOpFCmpl] = std::vector({ kTypeFloat, kTypeFloat }); + ans[kOpFCmpg] = std::vector({ kTypeFloat, kTypeFloat }); + ans[kOpDCmpl] = std::vector({ kTypeDouble, kTypeDouble }); + ans[kOpDCmpg] = std::vector({ kTypeDouble, kTypeDouble }); +} + +void JBCOpDefault::InitMapOpOutputTypesForCompare(std::map &ans) { + ans[kOpLCmp] = kTypeInt; + ans[kOpFCmpl] = kTypeInt; + ans[kOpFCmpg] = kTypeInt; + ans[kOpDCmpl] = kTypeInt; + ans[kOpDCmpg] = kTypeInt; +} + +void JBCOpDefault::InitMapOpInputTypesForReturn(std::map> &ans) { + ans[kOpIReturn] = std::vector({ kTypeInt }); + ans[kOpLReturn] = std::vector({ kTypeLong }); + ans[kOpFReturn] = std::vector({ kTypeFloat }); + ans[kOpDReturn] = std::vector({ kTypeDouble }); + ans[kOpAReturn] = std::vector({ kTypeRef }); + ans[kOpReturn] = emptyPrimTypes; +} + +void JBCOpDefault::InitMapOpOutputTypesForReturn(std::map &ans) { + ans[kOpIReturn] = kTypeDefault; + ans[kOpLReturn] = kTypeDefault; + ans[kOpFReturn] = kTypeDefault; + ans[kOpDReturn] = kTypeDefault; + ans[kOpAReturn] = kTypeDefault; + ans[kOpReturn] = kTypeDefault; +} + +void JBCOpDefault::InitMapOpInputTypesForThrow(std::map> &ans) { + ans[kOpAThrow] = std::vector({ kTypeRef }); +} + +void JBCOpDefault::InitMapOpOutputTypesForThrow(std::map &ans) { + ans[kOpAThrow] = kTypeDefault; +} + +void JBCOpDefault::InitMapOpInputTypesForMonitor(std::map> &ans) { + ans[kOpMonitorEnter] = std::vector({ kTypeRef }); + ans[kOpMonitorExit] = std::vector({ kTypeRef }); +} + +void JBCOpDefault::InitMapOpOutputTypesForMonitor(std::map &ans) { + ans[kOpMonitorEnter] = kTypeDefault; + ans[kOpMonitorExit] = kTypeDefault; +} + +void JBCOpDefault::InitMapOpInputTypesForArrayLength(std::map> &ans) { + ans[kOpArrayLength] = std::vector({ kTypeRef }); +} + +void JBCOpDefault::InitMapOpOutputTypesForArrayLength(std::map &ans) { + ans[kOpArrayLength] = kTypeInt; +} + +// ---------- JBCOpConst ---------- +std::map JBCOpConst::valueMapI = JBCOpConst::InitValueMapI(); +std::map JBCOpConst::valueMapJ = JBCOpConst::InitValueMapJ(); +std::map JBCOpConst::valueMapF = JBCOpConst::InitValueMapF(); +std::map JBCOpConst::valueMapD = JBCOpConst::InitValueMapD(); + +JBCOpConst::JBCOpConst(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn) { + u.raw = 0; +} + +bool JBCOpConst::ParseFileImpl(BasicIORead &io) { + bool success = false; + if (CheckNotWide(io) == false) { + return false; + } + switch (op) { + case jbc::kOpBiPush: + u.bvalue = io.ReadInt8(success); + break; + case jbc::kOpSiPush: + u.svalue = io.ReadInt16(success); + break; + case jbc::kOpLdc: + u.index = io.ReadUInt8(success); + break; + case jbc::kOpLdcW: + case jbc::kOpLdc2W: + u.index = io.ReadUInt16(success); + break; + default: + success = true; + break; + } + return success; +} + +JBCPrimType JBCOpConst::GetOutputTypesToStackImpl(const JBCConstPool &constPool) const { + switch (op) { + case jbc::kOpAConstNull: + return kTypeRef; + case jbc::kOpIConstM1: + case jbc::kOpIConst0: + case jbc::kOpIConst1: + case jbc::kOpIConst2: + case jbc::kOpIConst3: + case jbc::kOpIConst4: + case jbc::kOpIConst5: + return kTypeInt; + case jbc::kOpLConst0: + case jbc::kOpLConst1: + return kTypeLong; + case jbc::kOpFConst0: + case jbc::kOpFConst1: + case jbc::kOpFConst2: + return kTypeFloat; + case jbc::kOpDConst0: + case jbc::kOpDConst1: + return kTypeDouble; + case jbc::kOpBiPush: + return kTypeByteOrBoolean; + case jbc::kOpSiPush: + return kTypeShort; + case jbc::kOpLdc: + case jbc::kOpLdcW: + case jbc::kOpLdc2W: { + const JBCConst *constRaw = constPool.GetConstByIdx(GetIndex()); + if (constRaw != nullptr) { + switch (constRaw->GetTag()) { + case kConstInteger: + return jbc::kTypeInt; + case kConstFloat: + return jbc::kTypeFloat; + case kConstLong: + return jbc::kTypeLong; + case kConstDouble: + return jbc::kTypeDouble; + case kConstClass: + case kConstString: + return jbc::kTypeRef; + default: + CHECK_FATAL(false, "Unsupported const tag %d", constRaw->GetTag()); + } + } + break; + } + default: + CHECK_FATAL(false, "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + } + return kTypeDefault; +} + +std::string JBCOpConst::DumpImpl(const JBCConstPool &constPool) const { + switch (op) { + case jbc::kOpBiPush: + return DumpBiPush(); + case jbc::kOpSiPush: + return DumpSiPush(); + case jbc::kOpLdc: + case jbc::kOpLdcW: + case jbc::kOpLdc2W: + return DumpLdc(constPool); + default: + return JBCOp::DumpImpl(constPool); + } +} + +std::string JBCOpConst::DumpBiPush() const { + std::stringstream ss; + ss << GetOpcodeName() << " byte " << static_cast(u.bvalue); + return ss.str(); +} + +std::string JBCOpConst::DumpSiPush() const { + std::stringstream ss; + ss << GetOpcodeName() << " short " << static_cast(u.svalue); + return ss.str(); +} + +std::string JBCOpConst::DumpLdc(const JBCConstPool &constPool) const { + std::stringstream ss; + ss << GetOpcodeName() << " "; + const JBCConst *constRaw = constPool.GetConstByIdx(GetIndex()); + if (constRaw != nullptr) { + switch (constRaw->GetTag()) { + case kConstInteger: + case kConstFloat: { + const JBCConst4Byte *const4B = static_cast(constRaw); + if (constRaw->GetTag() == kConstInteger) { + ss << "int " << const4B->GetInt32(); + } else { + ss << "float " << const4B->GetFloat(); + } + break; + } + case kConstLong: + case kConstDouble: { + const JBCConst8Byte *const8B = static_cast(constRaw); + if (constRaw->GetTag() == kConstLong) { + ss << "long " << const8B->GetInt64(); + } else { + ss << "double " << const8B->GetDouble(); + } + break; + } + case kConstClass: { + const JBCConstClass *constClass = static_cast(constRaw); + ss << "Class " << constClass->GetClassNameOrin(); + break; + } + case kConstString: { + const JBCConstString *constString = static_cast(constRaw); + ss << "String " << "\"" << constString->GetString() << "\""; + break; + } + case kConstMethodType: { + ss << "MethodType "; + break; + } + case kConstMethodHandleInfo: { + ss << "MethodHandle "; + break; + } + default: + ss << "Unsupported const tag " << constRaw->GetTag(); + break; + } + } else { + ss << "invalid const index"; + } + return ss.str(); +} + +int32 JBCOpConst::GetValueInt() const { + auto it = valueMapI.find(op); + CHECK_FATAL(it != valueMapI.end(), "unsupport opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +int64 JBCOpConst::GetValueLong() const { + auto it = valueMapJ.find(op); + CHECK_FATAL(it != valueMapJ.end(), "unsupport opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +float JBCOpConst::GetValueFloat() const { + auto it = valueMapF.find(op); + CHECK_FATAL(it != valueMapF.end(), "unsupport opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +double JBCOpConst::GetValueDouble() const { + auto it = valueMapD.find(op); + CHECK_FATAL(it != valueMapD.end(), "unsupport opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +int8 JBCOpConst::GetValueByte() const { + CHECK_FATAL(op == kOpBiPush, "unsupport opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return u.bvalue; +} + +int16 JBCOpConst::GetValueShort() const { + CHECK_FATAL(op == kOpSiPush, "unsupport opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return u.svalue; +} + +std::map JBCOpConst::InitValueMapI() { + std::map valueMap; + valueMap[jbc::kOpIConstM1] = -1; + valueMap[jbc::kOpIConst0] = 0; + valueMap[jbc::kOpIConst1] = 1; + valueMap[jbc::kOpIConst2] = 2; + valueMap[jbc::kOpIConst3] = 3; + valueMap[jbc::kOpIConst4] = 4; + valueMap[jbc::kOpIConst5] = 5; + return valueMap; +} + +std::map JBCOpConst::InitValueMapJ() { + std::map valueMap; + valueMap[jbc::kOpLConst0] = 0L; + valueMap[jbc::kOpLConst1] = 1L; + return valueMap; +} + +std::map JBCOpConst::InitValueMapF() { + std::map valueMap; + valueMap[jbc::kOpFConst0] = 0.0F; + valueMap[jbc::kOpFConst1] = 1.0F; + valueMap[jbc::kOpFConst2] = 2.0F; + return valueMap; +} + +std::map JBCOpConst::InitValueMapD() { + std::map valueMap; + valueMap[jbc::kOpDConst0] = 0.0; + valueMap[jbc::kOpDConst1] = 1.0; + return valueMap; +} + +// ---------- JBCOpSlotOpr ---------- +std::map> JBCOpSlotOpr::mapSlotIdxAndType = + JBCOpSlotOpr::InitMapSlotIdxAndType(); +std::map> JBCOpSlotOpr::mapOpInputTypes = JBCOpSlotOpr::InitMapOpInputTypes(); +std::map JBCOpSlotOpr::mapOpOutputType = JBCOpSlotOpr::InitMapOpOutputType(); +std::vector JBCOpSlotOpr::inputTypesAddressOpr = { JBCPrimType::kTypeAddress }; + +JBCOpSlotOpr::JBCOpSlotOpr(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), slotIdx(0), isAddressOpr(false) {} + +bool JBCOpSlotOpr::IsAStore() const { + switch (op) { + case jbc::kOpAStore: + case jbc::kOpAStore0: + case jbc::kOpAStore1: + case jbc::kOpAStore2: + case jbc::kOpAStore3: + return true; + default: + return false; + } +} + +bool JBCOpSlotOpr::ParseFileImpl(BasicIORead &io) { + bool success = false; + switch (op) { + case jbc::kOpILoad: + case jbc::kOpLLoad: + case jbc::kOpFLoad: + case jbc::kOpDLoad: + case jbc::kOpALoad: + case jbc::kOpIStore: + case jbc::kOpLStore: + case jbc::kOpFStore: + case jbc::kOpDStore: + case jbc::kOpAStore: + if (wide) { + slotIdx = io.ReadUInt16(success); + } else { + slotIdx = io.ReadUInt8(success); + } + break; + default: + std::map>::const_iterator it = mapSlotIdxAndType.find(op); + if (it == mapSlotIdxAndType.end()) { + ERR(kLncErr, "Unexpected opcode %s for SlotOpr", GetOpcodeName().c_str()); + success = false; + } else { + slotIdx = it->second.first; + success = true; + } + break; + } + return success; +} + +const std::vector &JBCOpSlotOpr::GetInputTypesFromStackImpl() const { + if (isAddressOpr) { + return inputTypesAddressOpr; + } + auto it = mapOpInputTypes.find(op); + CHECK_FATAL(it != mapOpInputTypes.end(), "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +JBCPrimType JBCOpSlotOpr::GetOutputTypesToStackImpl() const { + auto it = mapOpOutputType.find(op); + CHECK_FATAL(it != mapOpOutputType.end(), "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +std::string JBCOpSlotOpr::DumpImpl(const JBCConstPool &constPool) const { + (void) constPool; + std::stringstream ss; + ss << GetOpcodeName() << " " << slotIdx; + return ss.str(); +} + +std::map> JBCOpSlotOpr::InitMapSlotIdxAndType() { + std::map> result; + result[kOpILoad] = std::make_pair(0, kTypeInt); + result[kOpLLoad] = std::make_pair(0, kTypeLong); + result[kOpFLoad] = std::make_pair(0, kTypeFloat); + result[kOpDLoad] = std::make_pair(0, kTypeDouble); + result[kOpALoad] = std::make_pair(0, kTypeRef); + result[kOpILoad0] = std::make_pair(0, kTypeInt); + result[kOpILoad1] = std::make_pair(1, kTypeInt); + result[kOpILoad2] = std::make_pair(2, kTypeInt); + result[kOpILoad3] = std::make_pair(3, kTypeInt); + result[kOpLLoad0] = std::make_pair(0, kTypeLong); + result[kOpLLoad1] = std::make_pair(1, kTypeLong); + result[kOpLLoad2] = std::make_pair(2, kTypeLong); + result[kOpLLoad3] = std::make_pair(3, kTypeLong); + result[kOpFLoad0] = std::make_pair(0, kTypeFloat); + result[kOpFLoad1] = std::make_pair(1, kTypeFloat); + result[kOpFLoad2] = std::make_pair(2, kTypeFloat); + result[kOpFLoad3] = std::make_pair(3, kTypeFloat); + result[kOpDLoad0] = std::make_pair(0, kTypeDouble); + result[kOpDLoad1] = std::make_pair(1, kTypeDouble); + result[kOpDLoad2] = std::make_pair(2, kTypeDouble); + result[kOpDLoad3] = std::make_pair(3, kTypeDouble); + result[kOpALoad0] = std::make_pair(0, kTypeRef); + result[kOpALoad1] = std::make_pair(1, kTypeRef); + result[kOpALoad2] = std::make_pair(2, kTypeRef); + result[kOpALoad3] = std::make_pair(3, kTypeRef); + result[kOpIStore] = std::make_pair(0, kTypeInt); + result[kOpLStore] = std::make_pair(0, kTypeLong); + result[kOpFStore] = std::make_pair(0, kTypeFloat); + result[kOpDStore] = std::make_pair(0, kTypeDouble); + result[kOpAStore] = std::make_pair(0, kTypeRef); + result[kOpIStore0] = std::make_pair(0, kTypeInt); + result[kOpIStore1] = std::make_pair(1, kTypeInt); + result[kOpIStore2] = std::make_pair(2, kTypeInt); + result[kOpIStore3] = std::make_pair(3, kTypeInt); + result[kOpLStore0] = std::make_pair(0, kTypeLong); + result[kOpLStore1] = std::make_pair(1, kTypeLong); + result[kOpLStore2] = std::make_pair(2, kTypeLong); + result[kOpLStore3] = std::make_pair(3, kTypeLong); + result[kOpFStore0] = std::make_pair(0, kTypeFloat); + result[kOpFStore1] = std::make_pair(1, kTypeFloat); + result[kOpFStore2] = std::make_pair(2, kTypeFloat); + result[kOpFStore3] = std::make_pair(3, kTypeFloat); + result[kOpDStore0] = std::make_pair(0, kTypeDouble); + result[kOpDStore1] = std::make_pair(1, kTypeDouble); + result[kOpDStore2] = std::make_pair(2, kTypeDouble); + result[kOpDStore3] = std::make_pair(3, kTypeDouble); + result[kOpAStore0] = std::make_pair(0, kTypeRef); + result[kOpAStore1] = std::make_pair(1, kTypeRef); + result[kOpAStore2] = std::make_pair(2, kTypeRef); + result[kOpAStore3] = std::make_pair(3, kTypeRef); + return result; +} + +std::map> JBCOpSlotOpr::InitMapOpInputTypes() { + std::map> ans; + ans[kOpILoad] = emptyPrimTypes; + ans[kOpFLoad] = emptyPrimTypes; + ans[kOpLLoad] = emptyPrimTypes; + ans[kOpDLoad] = emptyPrimTypes; + ans[kOpALoad] = emptyPrimTypes; + ans[kOpILoad0] = emptyPrimTypes; + ans[kOpILoad1] = emptyPrimTypes; + ans[kOpILoad2] = emptyPrimTypes; + ans[kOpILoad3] = emptyPrimTypes; + ans[kOpLLoad0] = emptyPrimTypes; + ans[kOpLLoad1] = emptyPrimTypes; + ans[kOpLLoad2] = emptyPrimTypes; + ans[kOpLLoad3] = emptyPrimTypes; + ans[kOpFLoad0] = emptyPrimTypes; + ans[kOpFLoad1] = emptyPrimTypes; + ans[kOpFLoad2] = emptyPrimTypes; + ans[kOpFLoad3] = emptyPrimTypes; + ans[kOpDLoad0] = emptyPrimTypes; + ans[kOpDLoad1] = emptyPrimTypes; + ans[kOpDLoad2] = emptyPrimTypes; + ans[kOpDLoad3] = emptyPrimTypes; + ans[kOpALoad0] = emptyPrimTypes; + ans[kOpALoad1] = emptyPrimTypes; + ans[kOpALoad2] = emptyPrimTypes; + ans[kOpALoad3] = emptyPrimTypes; + ans[kOpIStore] = std::vector({ kTypeInt }); + ans[kOpLStore] = std::vector({ kTypeLong }); + ans[kOpFStore] = std::vector({ kTypeFloat }); + ans[kOpDStore] = std::vector({ kTypeDouble }); + ans[kOpAStore] = std::vector({ kTypeRef }); + ans[kOpIStore0] = std::vector({ kTypeInt }); + ans[kOpIStore1] = std::vector({ kTypeInt }); + ans[kOpIStore2] = std::vector({ kTypeInt }); + ans[kOpIStore3] = std::vector({ kTypeInt }); + ans[kOpLStore0] = std::vector({ kTypeLong }); + ans[kOpLStore1] = std::vector({ kTypeLong }); + ans[kOpLStore2] = std::vector({ kTypeLong }); + ans[kOpLStore3] = std::vector({ kTypeLong }); + ans[kOpFStore0] = std::vector({ kTypeFloat }); + ans[kOpFStore1] = std::vector({ kTypeFloat }); + ans[kOpFStore2] = std::vector({ kTypeFloat }); + ans[kOpFStore3] = std::vector({ kTypeFloat }); + ans[kOpDStore0] = std::vector({ kTypeDouble }); + ans[kOpDStore1] = std::vector({ kTypeDouble }); + ans[kOpDStore2] = std::vector({ kTypeDouble }); + ans[kOpDStore3] = std::vector({ kTypeDouble }); + ans[kOpAStore0] = std::vector({ kTypeRef }); + ans[kOpAStore1] = std::vector({ kTypeRef }); + ans[kOpAStore2] = std::vector({ kTypeRef }); + ans[kOpAStore3] = std::vector({ kTypeRef }); + return ans; +} + +std::map JBCOpSlotOpr::InitMapOpOutputType() { + std::map ans; + ans[kOpILoad] = kTypeInt; + ans[kOpFLoad] = kTypeFloat; + ans[kOpLLoad] = kTypeLong; + ans[kOpDLoad] = kTypeDouble; + ans[kOpALoad] = kTypeRef; + ans[kOpILoad0] = kTypeInt; + ans[kOpILoad1] = kTypeInt; + ans[kOpILoad2] = kTypeInt; + ans[kOpILoad3] = kTypeInt; + ans[kOpLLoad0] = kTypeLong; + ans[kOpLLoad1] = kTypeLong; + ans[kOpLLoad2] = kTypeLong; + ans[kOpLLoad3] = kTypeLong; + ans[kOpFLoad0] = kTypeFloat; + ans[kOpFLoad1] = kTypeFloat; + ans[kOpFLoad2] = kTypeFloat; + ans[kOpFLoad3] = kTypeFloat; + ans[kOpDLoad0] = kTypeDouble; + ans[kOpDLoad1] = kTypeDouble; + ans[kOpDLoad2] = kTypeDouble; + ans[kOpDLoad3] = kTypeDouble; + ans[kOpALoad0] = kTypeRef; + ans[kOpALoad1] = kTypeRef; + ans[kOpALoad2] = kTypeRef; + ans[kOpALoad3] = kTypeRef; + ans[kOpIStore] = kTypeDefault; + ans[kOpLStore] = kTypeDefault; + ans[kOpFStore] = kTypeDefault; + ans[kOpDStore] = kTypeDefault; + ans[kOpAStore] = kTypeDefault; + ans[kOpIStore0] = kTypeDefault; + ans[kOpIStore1] = kTypeDefault; + ans[kOpIStore2] = kTypeDefault; + ans[kOpIStore3] = kTypeDefault; + ans[kOpLStore0] = kTypeDefault; + ans[kOpLStore1] = kTypeDefault; + ans[kOpLStore2] = kTypeDefault; + ans[kOpLStore3] = kTypeDefault; + ans[kOpFStore0] = kTypeDefault; + ans[kOpFStore1] = kTypeDefault; + ans[kOpFStore2] = kTypeDefault; + ans[kOpFStore3] = kTypeDefault; + ans[kOpDStore0] = kTypeDefault; + ans[kOpDStore1] = kTypeDefault; + ans[kOpDStore2] = kTypeDefault; + ans[kOpDStore3] = kTypeDefault; + ans[kOpAStore0] = kTypeDefault; + ans[kOpAStore1] = kTypeDefault; + ans[kOpAStore2] = kTypeDefault; + ans[kOpAStore3] = kTypeDefault; + return ans; +} + +// ---------- JBCOpMathInc ---------- +JBCOpMathInc::JBCOpMathInc(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), index(0), incr(0) {} + +bool JBCOpMathInc::ParseFileImpl(BasicIORead &io) { + bool success = false; + if (wide) { + index = io.ReadUInt16(success); + incr = io.ReadInt16(success); + } else { + index = io.ReadUInt8(success); + incr = io.ReadInt8(success); + } + return success; +} + +// ---------- JBCOpBranch ---------- +std::map> JBCOpBranch::mapOpInputTypes = JBCOpBranch::InitMapOpInputTypes(); + +JBCOpBranch::JBCOpBranch(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), target(0) {} + +bool JBCOpBranch::ParseFileImpl(BasicIORead &io) { + if (JBCOp::CheckNotWide(io) == false) { + return false; + } + bool success = true; + int64 pc = io.GetPos() - 1; + target = GetTargetbyInt64(pc + io.ReadInt16(success)); + return success; +} + +std::string JBCOpBranch::DumpImpl(const JBCConstPool &constPool) const { + (void) constPool; + std::stringstream ss; + ss << GetOpcodeName() << " " << target; + return ss.str(); +} + +const std::vector &JBCOpBranch::GetInputTypesFromStackImpl() const { + auto it = mapOpInputTypes.find(op); + CHECK_FATAL(it != mapOpInputTypes.end(), "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +std::map> JBCOpBranch::InitMapOpInputTypes() { + std::map> ans; + ans[kOpIfeq] = std::vector({ kTypeInt }); + ans[kOpIfne] = std::vector({ kTypeInt }); + ans[kOpIflt] = std::vector({ kTypeInt }); + ans[kOpIfge] = std::vector({ kTypeInt }); + ans[kOpIfgt] = std::vector({ kTypeInt }); + ans[kOpIfle] = std::vector({ kTypeInt }); + ans[kOpIfeq] = std::vector({ kTypeInt }); + ans[kOpIfICmpeq] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpIfICmpne] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpIfICmplt] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpIfICmpge] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpIfICmpgt] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpIfICmple] = std::vector({ kTypeInt, kTypeInt }); + ans[kOpIfACmpeq] = std::vector({ kTypeRef, kTypeRef }); + ans[kOpIfACmpne] = std::vector({ kTypeRef, kTypeRef }); + ans[kOpIfNull] = std::vector({ kTypeRef }); + ans[kOpIfNonNull] = std::vector({ kTypeRef }); + return ans; +} + +// ---------- JBCOpGoto ---------- +JBCOpGoto::JBCOpGoto(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), target(0) {} + +bool JBCOpGoto::ParseFileImpl(BasicIORead &io) { + if (JBCOp::CheckNotWide(io) == false) { + return false; + } + bool success = true; + int64 pc = io.GetPos() - 1; + switch (op) { + case jbc::kOpGoto: + target = GetTargetbyInt64(pc + io.ReadInt16(success)); + break; + case jbc::kOpGotoW: + target = GetTargetbyInt64(pc + io.ReadInt32(success)); + break; + default: + CHECK_FATAL(false, "Unexpected opcode %s for Goto", GetOpcodeName().c_str()); + return false; + } + return success; +} + +std::string JBCOpGoto::DumpImpl(const JBCConstPool &constPool) const { + (void) constPool; + std::stringstream ss; + ss << GetOpcodeName() << " " << target; + return ss.str(); +} + +// ---------- JBCOpSwitch ---------- +std::map> JBCOpSwitch::mapOpInputTypes = JBCOpSwitch::InitMapOpInputTypes(); + +JBCOpSwitch::JBCOpSwitch(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), + targets(std::less(), allocator.Adapter()), + targetDefault(0) {} + +bool JBCOpSwitch::ParseFileImpl(BasicIORead &io) { + bool success = false; + int64 pc = io.GetPos() - 1; + const uint32 kAlign32 = 4; + if (op == jbc::kOpTableSwitch) { + while (io.GetPos() % kAlign32 != 0) { + (void)io.ReadUInt8(success); + } + targetDefault = GetTargetbyInt64(pc + io.ReadUInt32(success)); + int32 low = io.ReadInt32(success); + int32 high = io.ReadInt32(success); + for (int32 i = low; i <= high && success; ++i) { + int32 offset = io.ReadInt32(success); + CHECK_FATAL(targets.insert(std::make_pair(i, GetTargetbyInt64(offset + pc))).second, "targets insert failed"); + } + } else if (op == jbc::kOpLookupSwitch) { + while (io.GetPos() % kAlign32 != 0) { + (void)io.ReadUInt8(success); + } + targetDefault = GetTargetbyInt64(pc + io.ReadUInt32(success)); + uint32 npairs = io.ReadUInt32(success); + for (uint32 i = 0; i < npairs && success; ++i) { + int32 value = io.ReadInt32(success); + int32 offset = io.ReadInt32(success); + CHECK_FATAL(targets.insert(std::make_pair(value, GetTargetbyInt64(offset + pc))).second, "targets insert failed"); + } + } + return success; +} + +const std::vector &JBCOpSwitch::GetInputTypesFromStackImpl() const { + auto it = mapOpInputTypes.find(op); + CHECK_FATAL(it != mapOpInputTypes.end(), "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +std::string JBCOpSwitch::DumpImpl(const JBCConstPool &constPool) const { + (void) constPool; + std::stringstream ss; + ss << GetOpcodeName() << " { default=" << targetDefault; + for (auto it : targets) { + ss << "," << it.first << ":" << it.second; + } + ss << " }"; + return ss.str(); +} + +std::map> JBCOpSwitch::InitMapOpInputTypes() { + std::map> ans; + ans[kOpTableSwitch] = std::vector({ kTypeInt }); + ans[kOpLookupSwitch] = std::vector({ kTypeInt }); + return ans; +} + +// ---------- JBCOpFieldOpr ---------- +JBCOpFieldOpr::JBCOpFieldOpr(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), fieldIdx(0) {} + +bool JBCOpFieldOpr::ParseFileImpl(BasicIORead &io) { + if (JBCOp::CheckNotWide(io) == false) { + return false; + } + bool success = false; + fieldIdx = io.ReadUInt16(success); + return success; +} + +const std::vector &JBCOpFieldOpr::GetInputTypesFromStackImpl() const { + CHECK_FATAL(false, "Restricted Calls"); + return emptyPrimTypes; +} + +std::vector JBCOpFieldOpr::GetInputTypesFromStackImpl(const JBCConstPool &constPool) const { + switch (op) { + case kOpGetField: + case kOpGetStatic: + return GetInputTypesFromStackForGet(constPool); + case kOpPutField: + case kOpPutStatic: + return GetInputTypesFromStackForPut(constPool); + default: + CHECK_FATAL(false, "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return emptyPrimTypes; + } +} + +JBCPrimType JBCOpFieldOpr::GetOutputTypesToStackImpl() const { + CHECK_FATAL(false, "Restricted Calls"); + return kTypeDefault; +} + +JBCPrimType JBCOpFieldOpr::GetOutputTypesToStackImpl(const JBCConstPool &constPool) const { + switch (op) { + case kOpGetField: + case kOpGetStatic: { + std::string desc = GetFieldType(constPool); + return JBCUtil::GetPrimTypeForName(desc); + } + case kOpPutField: + case kOpPutStatic: + return kTypeDefault; + default: + CHECK_FATAL(false, "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return kTypeDefault; + } +} + +std::string JBCOpFieldOpr::DumpImpl(const JBCConstPool &constPool) const { + std::stringstream ss; + ss << GetOpcodeName() << " "; + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(fieldIdx, JBCConstTag::kConstFieldRef); + if (constRaw == nullptr) { + ss << "unknown"; + } else { + const JBCConstRef *constRef = static_cast(constRaw); + CHECK_NULL_FATAL(constRef->GetConstClass()); + ss << constRef->GetConstClass()->GetClassNameOrin() << "." << constRef->GetName() << ":" << + constRef->GetDesc(); + } + return ss.str(); +} + +std::vector JBCOpFieldOpr::GetInputTypesFromStackForGet(const JBCConstPool &constPool) const { + (void) constPool; + std::vector ans; + if (op == kOpGetField) { + ans.push_back(kTypeRef); + } + return ans; +} + +std::vector JBCOpFieldOpr::GetInputTypesFromStackForPut(const JBCConstPool &constPool) const { + std::vector ans; + std::string desc = GetFieldType(constPool); + if (op == kOpPutField) { + ans.push_back(kTypeRef); + } + ans.push_back(JBCUtil::GetPrimTypeForName(desc)); + return ans; +} + +std::string JBCOpFieldOpr::GetFieldType(const JBCConstPool &constPool) const { + std::string desc = ""; + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(fieldIdx, kConstFieldRef); + if (constRaw != nullptr) { + const JBCConstRef *constRef = static_cast(constRaw); + desc = constRef->GetDesc(); + } + return desc; +} + +// ---------- JBCOpInvoke ---------- +JBCOpInvoke::JBCOpInvoke(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), methodIdx(0), count(0) {} + +bool JBCOpInvoke::ParseFileImpl(BasicIORead &io) { + if (JBCOp::CheckNotWide(io) == false) { + return false; + } + bool success = false; + switch (op) { + case jbc::kOpInvokeVirtual: + case jbc::kOpInvokeSpecial: + case jbc::kOpInvokeStatic: + methodIdx = io.ReadUInt16(success); + break; + case jbc::kOpInvokeInterface: + methodIdx = io.ReadUInt16(success); + count = io.ReadUInt8(success); + (void)io.ReadUInt8(success); + break; + case jbc::kOpInvokeDynamic: + methodIdx = io.ReadUInt16(success); + (void)io.ReadUInt8(success); + (void)io.ReadUInt8(success); + break; + default: + ASSERT(false, "Unexpected opcode %s for Invoke", GetOpcodeName().c_str()); + return false; + } + return success; +} + +const std::vector &JBCOpInvoke::GetInputTypesFromStackImpl() const { + CHECK_FATAL(false, "Restricted Calls"); + return emptyPrimTypes; +} + +std::vector JBCOpInvoke::GetInputTypesFromStackImpl(const JBCConstPool &constPool) const { + std::vector ans; + std::string desc = GetMethodDescription(constPool); + std::vector typeNames = JBCUtil::SolveMethodSignature(desc); + CHECK_FATAL(typeNames.size() > 0, "Invalid method description: %s", desc.c_str()); + if (op != kOpInvokeStatic && op != kOpInvokeDynamic) { + ans.push_back(kTypeRef); + } + for (size_t i = 1; i < typeNames.size(); i++) { + ans.push_back(JBCUtil::GetPrimTypeForName(typeNames[i])); + } + return ans; +} + +JBCPrimType JBCOpInvoke::GetOutputTypesToStackImpl() const { + CHECK_FATAL(false, "Restricted Calls"); + return kTypeDefault; +} + +JBCPrimType JBCOpInvoke::GetOutputTypesToStackImpl(const JBCConstPool &constPool) const { + std::string desc = GetMethodDescription(constPool); + std::vector typeNames = JBCUtil::SolveMethodSignature(desc); + CHECK_FATAL(typeNames.size() > 0, "Invalid method description: %s", desc.c_str()); + return JBCUtil::GetPrimTypeForName(typeNames[0]); +} + +std::string JBCOpInvoke::DumpImpl(const JBCConstPool &constPool) const { + std::stringstream ss; + ss << GetOpcodeName() << " "; + const JBCConst *constRaw = constPool.GetConstByIdx(methodIdx); + CHECK_NULL_FATAL(constRaw); + JBCConstTag tag = constRaw->GetTag(); + if (op == jbc::kOpInvokeDynamic) { + if (tag == kConstInvokeDynamic) { + const JBCConstInvokeDynamic *constInvokdDynamic = static_cast(constRaw); + CHECK_NULL_FATAL(constInvokdDynamic->GetConstNameAndType()); + ss << constInvokdDynamic->GetBSMAttrIdx() << ":" << + constInvokdDynamic->GetConstNameAndType()->GetName() << ":" << + constInvokdDynamic->GetConstNameAndType()->GetDesc(); + } else { + ss << "invalid const tag"; + } + } else { + if (tag == kConstMethodRef || tag == kConstInterfaceMethodRef) { + const JBCConstRef *constRef = static_cast(constRaw); + CHECK_NULL_FATAL(constRef->GetConstClass()); + ss << constRef->GetConstClass()->GetClassNameOrin() << "." << constRef->GetName() << ":" << + constRef->GetDesc(); + } else { + ss << "invalid const tag"; + } + } + return ss.str(); +} + +std::string JBCOpInvoke::GetMethodDescription(const JBCConstPool &constPool) const { + std::string desc = ""; + switch (op) { + case jbc::kOpInvokeVirtual: { + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(methodIdx, kConstMethodRef); + if (constRaw != nullptr) { + const JBCConstRef *constRef = static_cast(constRaw); + desc = constRef->GetDesc(); + } + break; + } + case jbc::kOpInvokeInterface: { + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(methodIdx, kConstInterfaceMethodRef); + if (constRaw != nullptr) { + const JBCConstRef *constRef = static_cast(constRaw); + desc = constRef->GetDesc(); + } + break; + } + case jbc::kOpInvokeStatic: + case jbc::kOpInvokeSpecial: { + const JBCConst *constRaw = constPool.GetConstByIdx(methodIdx); + if (constRaw != nullptr && (constRaw->GetTag() == kConstMethodRef || + constRaw->GetTag() == kConstInterfaceMethodRef)) { + const JBCConstRef *constRef = static_cast(constRaw); + desc = constRef->GetDesc(); + } + break; + } + case jbc::kOpInvokeDynamic: { + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(methodIdx, kConstInvokeDynamic); + if (constRaw != nullptr) { + const JBCConstInvokeDynamic *constDynamic = static_cast(constRaw); + desc = constDynamic->GetConstNameAndType()->GetDesc(); + } + break; + } + default: + CHECK_FATAL(false, "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + break; + } + return desc; +} + +// ---------- JBCOpJsrRet ---------- +JBCOpJsr::JBCOpJsr(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), target(0), slotIdx(0), jsrID(0) {} + +bool JBCOpJsr::ParseFileImpl(BasicIORead &io) { + if (JBCOp::CheckNotWide(io) == false) { + return false; + } + bool success = false; + int64 pc = io.GetPos() - 1; + switch (op) { + case jbc::kOpJsr: + target = GetTargetbyInt64(pc + io.ReadInt16(success)); + break; + case jbc::kOpJsrW: + target = GetTargetbyInt64(pc + io.ReadInt32(success)); + break; + default: + ASSERT(false, "Unexpected opcode %s for JSR", GetOpcodeName().c_str()); + return false; + } + return success; +} + +JBCPrimType JBCOpJsr::GetOutputTypesToStackImpl() const { + return JBCPrimType::kTypeAddress; +} + +std::string JBCOpJsr::DumpImpl(const JBCConstPool &constPool) const { + (void) constPool; + std::stringstream ss; + ss << GetOpcodeName() << " " << target; + return ss.str(); +} + +// ---------- JBCOpRet ---------- +JBCOpRet::JBCOpRet(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), index(0) {} + +bool JBCOpRet::ParseFileImpl(BasicIORead &io) { + bool success = false; + if (wide) { + index = io.ReadUInt16(success); + } else { + index = io.ReadUInt8(success); + } + return success; +} + +std::string JBCOpRet::DumpImpl(const JBCConstPool &constPool) const { + (void) constPool; + std::stringstream ss; + ss << GetOpcodeName() << " " << index; + return ss.str(); +} + +// ---------- JBCOpNew ---------- +std::map> JBCOpNew::mapOpInputTypes = JBCOpNew::InitMapOpInputTypes(); + +JBCOpNew::JBCOpNew(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), refTypeIdx(0), primType(kPrimNone) {} + +bool JBCOpNew::ParseFileImpl(BasicIORead &io) { + bool success = false; + switch (op) { + case jbc::kOpNew: + case jbc::kOpANewArray: + refTypeIdx = io.ReadUInt16(success); + break; + case jbc::kOpNewArray: + primType = io.ReadUInt8(success); + break; + default: + ASSERT(false, "Unexpected opcode %s for New", GetOpcodeName().c_str()); + return false; + } + return success; +} + +const std::vector &JBCOpNew::GetInputTypesFromStackImpl() const { + auto it = mapOpInputTypes.find(op); + CHECK_FATAL(it != mapOpInputTypes.end(), "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +JBCPrimType JBCOpNew::GetOutputTypesToStackImpl() const { + return kTypeRef; +} + +std::string JBCOpNew::DumpImpl(const JBCConstPool &constPool) const { + switch (op) { + case jbc::kOpNew: + case jbc::kOpANewArray: { + std::stringstream ss; + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(refTypeIdx, JBCConstTag::kConstClass); + CHECK_NULL_FATAL(constRaw); + const JBCConstClass *constClass = static_cast(constRaw); + ss << GetOpcodeName() << " " << constClass->GetClassNameOrin(); + return ss.str(); + } + case jbc::kOpNewArray: { + std::stringstream ss; + ss << GetOpcodeName() << " " << GetPrimTypeName(); + return ss.str(); + } + default: + ASSERT(false, "Unexpected opcode %s for New", GetOpcodeName().c_str()); + return ""; + } +} + +GStrIdx JBCOpNew::GetTypeNameIdx(const JBCConstPool &constPool) const { + switch (op) { + case jbc::kOpNew: + case jbc::kOpANewArray: { + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(refTypeIdx, JBCConstTag::kConstClass); + CHECK_NULL_FATAL(constRaw); + const JBCConstClass *constClass = static_cast(constRaw); + return constClass->GetClassNameIdxMpl(); + } + case jbc::kOpNewArray: + return GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(GetPrimTypeName()); + default: + ASSERT(false, "Unexpected opcode %s for New", GetOpcodeName().c_str()); + return GStrIdx(0); + } +} + +std::string JBCOpNew::GetTypeName(const JBCConstPool &constPool) const { + switch (op) { + case jbc::kOpNew: + case jbc::kOpANewArray: { + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(refTypeIdx, JBCConstTag::kConstClass); + CHECK_NULL_FATAL(constRaw); + const JBCConstClass *constClass = static_cast(constRaw); + return constClass->GetClassNameMpl(); + } + case jbc::kOpNewArray: + return GetPrimTypeName(); + default: + ASSERT(false, "Unexpected opcode %s for New", GetOpcodeName().c_str()); + return ""; + } +} + +const FEIRType *JBCOpNew::GetFEIRType(const JBCConstPool &constPool) const { + switch (op) { + case jbc::kOpNew: + case jbc::kOpANewArray: { + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(refTypeIdx, JBCConstTag::kConstClass); + CHECK_NULL_FATAL(constRaw); + const JBCConstClass *constClass = static_cast(constRaw); + return constClass->GetFEIRType(); + } + case jbc::kOpNewArray: + return GetPrimFEIRType().get(); + default: + CHECK_FATAL(false, "Unexpected opcode %s for New", GetOpcodeName().c_str()); + return FETypeManager::kPrimFEIRTypeUnknown.get(); + } +} + +std::string JBCOpNew::GetPrimTypeName() const { + switch (primType) { + case kPrimInt: + return "I"; + case kPrimBoolean: + return "Z"; + case kPrimByte: + return "B"; + case kPrimShort: + return "S"; + case kPrimChar: + return "C"; + case kPrimLong: + return "J"; + case kPrimFloat: + return "F"; + case kPrimDouble: + return "D"; + default: + return "undefined"; + } +} + +const UniqueFEIRType &JBCOpNew::GetPrimFEIRType() const { + switch (primType) { + case kPrimInt: + return FETypeManager::kPrimFEIRTypeI32; + case kPrimBoolean: + return FETypeManager::kPrimFEIRTypeU1; + case kPrimByte: + return FETypeManager::kPrimFEIRTypeI8; + case kPrimShort: + return FETypeManager::kPrimFEIRTypeI16; + case kPrimChar: + return FETypeManager::kPrimFEIRTypeU16; + case kPrimLong: + return FETypeManager::kPrimFEIRTypeI64; + case kPrimFloat: + return FETypeManager::kPrimFEIRTypeF32; + case kPrimDouble: + return FETypeManager::kPrimFEIRTypeF64; + default: + return FETypeManager::kPrimFEIRTypeUnknown; + } +} + +std::map> JBCOpNew::InitMapOpInputTypes() { + std::map> ans; + ans[kOpNew] = emptyPrimTypes; + ans[kOpNewArray] = std::vector({ kTypeInt }); + ans[kOpANewArray] = std::vector({ kTypeInt }); + return ans; +} + +// ---------- JBCOpMultiANewArray ---------- +JBCOpMultiANewArray::JBCOpMultiANewArray(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), refTypeIdx(0), dim(0) {} + +bool JBCOpMultiANewArray::ParseFileImpl(BasicIORead &io) { + bool success = false; + refTypeIdx = io.ReadUInt16(success); + dim = io.ReadUInt8(success); + return true; +} + +const std::vector &JBCOpMultiANewArray::GetInputTypesFromStackImpl() const { + CHECK_FATAL(false, "Restricted Calls"); + return emptyPrimTypes; +} + +std::vector JBCOpMultiANewArray::GetInputTypesFromStackImpl(const JBCConstPool &constPool) const { + (void) constPool; + std::vector ans; + for (uint8 i = 0; i < dim; i++) { + ans.push_back(kTypeInt); + } + return ans; +} + +JBCPrimType JBCOpMultiANewArray::GetOutputTypesToStackImpl() const { + return kTypeRef; +} + +std::string JBCOpMultiANewArray::DumpImpl(const JBCConstPool &constPool) const { + std::stringstream ss; + ss << GetOpcodeName() << " "; + const JBCConst *constRaw = constPool.GetConstByIdx(refTypeIdx); + CHECK_NULL_FATAL(constRaw); + if (constRaw->GetTag() == kConstClass) { + const JBCConstClass *constClass = static_cast(constRaw); + ss << constClass->GetClassNameOrin() << " dim=" << uint32{ dim }; + } else { + ss << "invalid const tag"; + } + return ss.str(); +} + +// ---------- JBCOpTypeCheck ---------- +std::map> JBCOpTypeCheck::mapOpInputTypes = JBCOpTypeCheck::InitMapOpInputTypes(); +std::map JBCOpTypeCheck::mapOpOutputType = JBCOpTypeCheck::InitMapOpOutputType(); + +JBCOpTypeCheck::JBCOpTypeCheck(MapleAllocator &allocator, JBCOpcode opIn, JBCOpcodeKind kindIn, bool wideIn) + : JBCOp(allocator, opIn, kindIn, wideIn), typeIdx(0) {} + +bool JBCOpTypeCheck::ParseFileImpl(BasicIORead &io) { + if (JBCOp::CheckNotWide(io) == false) { + return false; + } + bool success = false; + switch (op) { + case jbc::kOpCheckCast: + case jbc::kOpInstanceOf: + typeIdx = io.ReadUInt16(success); + break; + default: + ASSERT(false, "Unexpected opcode %s for TypeCheck", GetOpcodeName().c_str()); + return false; + } + return success; +} + +const std::vector &JBCOpTypeCheck::GetInputTypesFromStackImpl() const { + auto it = mapOpInputTypes.find(op); + CHECK_FATAL(it != mapOpInputTypes.end(), "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +JBCPrimType JBCOpTypeCheck::GetOutputTypesToStackImpl() const { + auto it = mapOpOutputType.find(op); + CHECK_FATAL(it != mapOpOutputType.end(), "Unsupported opcode %s", opcodeInfo.GetOpcodeName(op).c_str()); + return it->second; +} + +std::string JBCOpTypeCheck::DumpImpl(const JBCConstPool &constPool) const { + std::stringstream ss; + ss << GetOpcodeName() << " "; + const JBCConst *constRaw = constPool.GetConstByIdxWithTag(typeIdx, kConstClass); + if (constRaw == nullptr) { + ss << "invalid type idx"; + return ss.str(); + } + const JBCConstClass *constClass = static_cast(constRaw); + ss << constClass->GetClassNameOrin(); + return ss.str(); +} + +std::map> JBCOpTypeCheck::InitMapOpInputTypes() { + std::map> ans; + ans[kOpCheckCast] = std::vector({ kTypeRef }); + ans[kOpInstanceOf] = std::vector({ kTypeRef }); + return ans; +} + +std::map JBCOpTypeCheck::InitMapOpOutputType() { + std::map ans; + ans[kOpCheckCast] = kTypeRef; + ans[kOpInstanceOf] = kTypeInt; + return ans; +} +} // namespace jbc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_opcode_helper.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_opcode_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a5fec151b45671a3911120112142746b8d55e82 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_opcode_helper.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_opcode_helper.h" +#include "jbc_class_const.h" +#include "jbc_util.h" +#include "fe_type_manager.h" + +namespace maple { +std::map> JBCOpcodeHelper::mapOpInputPrimTypes = + JBCOpcodeHelper::InitMapOpInputPrimTypes(); + +std::map JBCOpcodeHelper::funcPtrMapGetBaseTypeName = + JBCOpcodeHelper::InitFuncPtrMapGetBaseTypeName(); + +JBCOpcodeHelper::JBCOpcodeHelper(const jbc::JBCClassMethod &argMethod) : method(argMethod) {} + +std::vector JBCOpcodeHelper::GetBaseTypeNamesForOP(const jbc::JBCOp &op, bool &success) { + auto it = funcPtrMapGetBaseTypeName.find(op.GetOpcodeKind()); + if (it == funcPtrMapGetBaseTypeName.end()) { + return GetBaseTypeNamesForOPDefault(success); + } else { + return (this->*(it->second))(op, success); + } +} + +std::map JBCOpcodeHelper::InitFuncPtrMapGetBaseTypeName() { + std::map ans; + ans[jbc::kOpKindConst] = &JBCOpcodeHelper::GetBaseTypeNamesForOPConst; + ans[jbc::kOpKindStaticFieldOpr] = &JBCOpcodeHelper::GetBaseTypeNamesForOPFieldOpr; + ans[jbc::kOpKindFieldOpr] = &JBCOpcodeHelper::GetBaseTypeNamesForOPFieldOpr; + ans[jbc::kOpKindInvoke] = &JBCOpcodeHelper::GetBaseTypeNamesForOPInvoke; + ans[jbc::kOpKindNew] = &JBCOpcodeHelper::GetBaseTypeNamesForOPNew; + ans[jbc::kOpKindMultiANewArray] = &JBCOpcodeHelper::GetBaseTypeNamesForOPMultiANewArray; + ans[jbc::kOpKindTypeCheck] = &JBCOpcodeHelper::GetBaseTypeNamesForOPTypeCheck; + return ans; +} + +std::vector JBCOpcodeHelper::GetBaseTypeNamesForOPDefault(bool &success) const { + success = true; + return std::vector(); +} + +std::vector JBCOpcodeHelper::GetBaseTypeNamesForOPConst(const jbc::JBCOp &op, bool &success) { + std::vector ans; + const jbc::JBCOpConst &opConst = static_cast(op); + if (op.GetOpcode() == jbc::kOpLdc || op.GetOpcode() == jbc::kOpLdcW) { + const jbc::JBCConstPool &constPool = method.GetConstPool(); + const jbc::JBCConst *constItem = constPool.GetConstByIdx(opConst.GetIndex()); + if (constItem == nullptr) { + ssLastError.str(""); + ssLastError << "invalid const pool index (" << opConst.GetIndex() << ") in method " + << method.GetClassName() << "." << method.GetName() << ":" << method.GetDescription(); + success = false; + return ans; + } + if (constItem->GetTag() == jbc::kConstClass) { + success = true; + const jbc::JBCConstClass *constClass = static_cast(constItem); + std::string typeName = constClass->GetClassNameOrin(); + std::string baseTypeName = FETypeManager::GetBaseTypeName(typeName, false); + ans.push_back(baseTypeName); + } + } + success = true; + return ans; +} + +std::vector JBCOpcodeHelper::GetBaseTypeNamesForOPFieldOpr(const jbc::JBCOp &op, bool &success) { + std::vector ans; + const jbc::JBCOpFieldOpr &opFieldOpr = static_cast(op); + const jbc::JBCConstPool &constPool = method.GetConstPool(); + const jbc::JBCConst *constItem = constPool.GetConstByIdxWithTag(opFieldOpr.GetFieldIdx(), jbc::kConstFieldRef); + if (constItem == nullptr) { + success = false; + return ans; + } + const jbc::JBCConstRef *constRef = static_cast(constItem); + ans.push_back(FETypeManager::GetBaseTypeName(constRef->GetDesc(), false)); + success = true; + return ans; +} + +std::vector JBCOpcodeHelper::GetBaseTypeNamesForOPInvoke(const jbc::JBCOp &op, bool &success) { + std::vector ans; + const jbc::JBCOpInvoke &opInvoke = static_cast(op); + const jbc::JBCConstPool &constPool = method.GetConstPool(); + const jbc::JBCConst *constItem = constPool.GetConstByIdx(opInvoke.GetMethodIdx()); + if (constItem == nullptr || + (constItem->GetTag() != jbc::kConstMethodRef && constItem->GetTag() != jbc::kConstInterfaceMethodRef)) { + success = false; + return ans; + } + const jbc::JBCConstRef *constRef = static_cast(constItem); + const std::string desc = constRef->GetDesc(); + std::vector typeNames = jbc::JBCUtil::SolveMethodSignature(desc); + for (const std::string &typeName : typeNames) { + ans.push_back(FETypeManager::GetBaseTypeName(typeName, false)); + } + success = true; + return ans; +} + +std::vector JBCOpcodeHelper::GetBaseTypeNamesForOPNew(const jbc::JBCOp &op, bool &success) { + std::vector ans; + const jbc::JBCOpNew &opNew = static_cast(op); + const jbc::JBCConstPool &constPool = method.GetConstPool(); + if (op.GetOpcode() == jbc::kOpNew || op.GetOpcode() == jbc::kOpANewArray) { + const jbc::JBCConst *constItem = constPool.GetConstByIdxWithTag(opNew.GetRefTypeIdx(), jbc::kConstClass); + if (constItem == nullptr) { + success = false; + return ans; + } + const jbc::JBCConstClass *constClass = static_cast(constItem); + ans.push_back(FETypeManager::GetBaseTypeName(constClass->GetClassNameOrin(), false)); + } + success = true; + return ans; +} + +std::vector JBCOpcodeHelper::GetBaseTypeNamesForOPMultiANewArray(const jbc::JBCOp &op, bool &success) { + std::vector ans; + const jbc::JBCOpMultiANewArray &opArray = static_cast(op); + const jbc::JBCConstPool &constPool = method.GetConstPool(); + const jbc::JBCConst *constItem = constPool.GetConstByIdxWithTag(opArray.GetRefTypeIdx(), jbc::kConstClass); + if (constItem == nullptr) { + success = false; + return ans; + } + const jbc::JBCConstClass *constClass = static_cast(constItem); + ans.push_back(FETypeManager::GetBaseTypeName(constClass->GetClassNameOrin(), false)); + success = true; + return ans; +} + +std::vector JBCOpcodeHelper::GetBaseTypeNamesForOPTypeCheck(const jbc::JBCOp &op, bool &success) { + std::vector ans; + const jbc::JBCOpTypeCheck &opTypeCheck = static_cast(op); + const jbc::JBCConstPool &constPool = method.GetConstPool(); + const jbc::JBCConst *constItem = constPool.GetConstByIdxWithTag(opTypeCheck.GetTypeIdx(), jbc::kConstClass); + if (constItem == nullptr) { + success = false; + return ans; + } + const jbc::JBCConstClass *constClass = static_cast(constItem); + ans.push_back(FETypeManager::GetBaseTypeName(constClass->GetClassNameOrin(), false)); + success = true; + return ans; +} + +std::map> JBCOpcodeHelper::InitMapOpInputPrimTypes() { + std::map> ans; + InitMapOpInputPrimTypesForConst(ans); + + return ans; +} + +void JBCOpcodeHelper::InitMapOpInputPrimTypesForConst(std::map> &ans) { + ans[jbc::kOpAConstNull] = std::vector(); + ans[jbc::kOpIConstM1] = std::vector(); + ans[jbc::kOpIConst0] = std::vector(); + ans[jbc::kOpIConst1] = std::vector(); + ans[jbc::kOpIConst2] = std::vector(); + ans[jbc::kOpIConst3] = std::vector(); + ans[jbc::kOpIConst4] = std::vector(); + ans[jbc::kOpIConst5] = std::vector(); + ans[jbc::kOpLConst0] = std::vector(); + ans[jbc::kOpLConst1] = std::vector(); + ans[jbc::kOpFConst0] = std::vector(); + ans[jbc::kOpFConst1] = std::vector(); + ans[jbc::kOpFConst2] = std::vector(); + ans[jbc::kOpDConst0] = std::vector(); + ans[jbc::kOpDConst1] = std::vector(); + ans[jbc::kOpBiPush] = std::vector(); + ans[jbc::kOpSiPush] = std::vector(); + ans[jbc::kOpLdc] = std::vector(); + ans[jbc::kOpLdcW] = std::vector(); + ans[jbc::kOpLdc2W] = std::vector(); +} +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_stack2fe_helper.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_stack2fe_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..be0dc49fd9c00dddaa0873a900bf94816bf3f1b4 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_stack2fe_helper.cpp @@ -0,0 +1,707 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_stack2fe_helper.h" +#include +#include "mpl_logging.h" + +namespace maple { +JBCStack2FEHelper::JBCStack2FEHelper(bool argUseNestExpr) + : useNestExpr(argUseNestExpr) {} + +// Function Name: GetRegNumForSlot +// Description: adjust slotNum using following layout +// set baseLocal as nStacks + nSwaps +// set allLocals as nLocals + nArgs +// 0 ~ baseLocal - 1: stack reg (local) +// baseLocal ~ baseLocal + nLocals - 1: local var +// (mapping to slotNum: nArgs ~ allLocals - 1) +// baseLocal + nLocals ~ baseLocal + allLocals - 1: args var +// (mapping to slotNum: 0 ~ nArgs - 1) +// +uint32 JBCStack2FEHelper::GetRegNumForSlot(uint32 slotNum) const { + uint32 baseLocal = nStacks + nSwaps; + uint32 allLocals = nLocals + nArgs; + CHECK_FATAL(slotNum < allLocals, "GetRegNumForSlot: out of range"); + if (slotNum >= nArgs) { + // local var + // nArgs ~ nArgs + nLocals - 1 --> baseLocal ~ baseLocal + nLocals - 1 + return baseLocal - nArgs + slotNum; + } else { + // arg var + // 0 ~ nArgs - 1 --> baseLocal + nLocals ~ baseLocal + nLocals + nArgs - 1 + return baseLocal + nLocals + slotNum; + } +} + +uint32 JBCStack2FEHelper::GetRegNumForStack() const { + std::set setAvaliable = regNumForStacks; + for (const StackItem &item : stack) { + const UniqueFEIRVar &var = item.first; + if (IsItemDummy(item)) { + continue; + } + ASSERT(var->GetKind() == FEIRVarKind::kFEIRVarReg, "unsupported var kind"); + FEIRVarReg *ptrVarReg = static_cast(var.get()); + (void)setAvaliable.erase(ptrVarReg->GetRegNum()); + if (IsItemWide(item)) { + (void)setAvaliable.erase(ptrVarReg->GetRegNum() + 1); + } + } + CHECK_FATAL(setAvaliable.size() > 0, "no avaliable reg number to use"); + return *(setAvaliable.begin()); +} + +bool JBCStack2FEHelper::PushItem(UniqueFEIRVar var, PrimType pty) { + if (stack.size() >= nStacks) { + ERR(kLncErr, "stack out of range"); + return false; + } + stack.push_back(MakeStackItem(std::move(var), pty)); + if (IsPrimTypeWide(pty)) { + stack.push_back(MakeStackItem(UniqueFEIRVar(nullptr), pty)); + } + return true; +} + +UniqueFEIRVar JBCStack2FEHelper::PushItem(PrimType pty) { + uint32 regNum = GetRegNumForStack(); + UniqueFEIRVar var = FEIRBuilder::CreateVarReg(regNum, pty); + if (!PushItem(var->Clone(), pty)) { + return UniqueFEIRVar(nullptr); + } else { + return var; + } +} + +UniqueFEIRStmt JBCStack2FEHelper::PushItem(UniqueFEIRExpr expr, PrimType pty, bool hasException) { + uint32 regNum = GetRegNumForStack(); + UniqueFEIRVar varDst = FEIRBuilder::CreateVarReg(regNum, pty); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(varDst->Clone(), std::move(expr), hasException); + if (PushItem(std::move(varDst), pty)) { + return UniqueFEIRStmt(nullptr); + } else { + return stmt; + } +} + +UniqueFEIRStmt JBCStack2FEHelper::PushItem(UniqueFEIRExpr expr, UniqueFEIRType type, bool hasException) { + uint32 regNum = GetRegNumForStack(); + UniqueFEIRVar varDst = FEIRBuilder::CreateVarReg(regNum, std::move(type)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(varDst->Clone(), std::move(expr), hasException); + PrimType pty = PTY_unknown; + if (!type->IsScalar()) { + pty = PTY_ref; + } else { + pty = type->GetPrimType(); + } + if (!PushItem(std::move(varDst), pty)) { + return UniqueFEIRStmt(nullptr); + } else { + return stmt; + } +} + +UniqueFEIRVar JBCStack2FEHelper::PopItem(PrimType pty) { + size_t size = stack.size(); + if (IsPrimTypeWide(pty)) { + if (size < 2) { // pop wide item operation need at least 2 items in stack + ERR(kLncErr, "stack items are not enough for pop operation"); + return UniqueFEIRVar(); + } + StackItem &item1 = stack[size - 1]; // the 1st item from top + StackItem &item2 = stack[size - 2]; // the 2nd item from top + if (IsItemDummy(item1) && IsItemWide(item2) && item2.second == pty) { + UniqueFEIRVar ans = std::move(item2.first); + stack.pop_back(); + stack.pop_back(); + return ans; + } else { + ERR(kLncErr, "invalid stack items for pop wide item operation"); + return UniqueFEIRVar(nullptr); + } + } else { + if (size < 1) { // pop normal item operation need at least 1 item in stack + ERR(kLncErr, "stack items are not enough for pop operation"); + return UniqueFEIRVar(nullptr); + } + StackItem &item = stack[size - 1]; // the 1st item from top + if (IsItemNormal(item) && item.second == pty) { + UniqueFEIRVar ans = std::move(item.first); + stack.pop_back(); + return ans; + } else { + ERR(kLncErr, "invalid stack items for pop item operation"); + return UniqueFEIRVar(nullptr); + } + } +} + +UniqueFEIRVar JBCStack2FEHelper::PopItem(UniqueFEIRType type) { + UniqueFEIRVar var = PopItem(type->GetPrimType()); + var->SetType(std::move(type)); + return var; +} + +UniqueFEIRVar JBCStack2FEHelper::PopItem(bool isWide, PrimType &pty) { + size_t size = stack.size(); + pty = PTY_unknown; + if (isWide) { + if (size < 2) { // pop wide item operation need at least 2 items in stack + ERR(kLncErr, "stack items are not enough for pop operation"); + return UniqueFEIRVar(nullptr); + } + StackItem &item1 = stack[size - 1]; // the 1st item from top + StackItem &item2 = stack[size - 2]; // the 2nd item from top + if (IsItemDummy(item1) && IsItemWide(item2)) { + UniqueFEIRVar ans = std::move(item2.first); + pty = item2.second; + stack.pop_back(); + stack.pop_back(); + return ans; + } else { + ERR(kLncErr, "invalid stack items for pop wide item operation"); + return UniqueFEIRVar(nullptr); + } + } else { + if (size < 1) { // pop normal item operation need at least 1 item in stack + ERR(kLncErr, "stack items are not enough for pop operation"); + return UniqueFEIRVar(nullptr); + } + StackItem &item = stack[size - 1]; // the 1st item from top + if (IsItemNormal(item)) { + UniqueFEIRVar ans = std::move(item.first); + pty = item.second; + stack.pop_back(); + return ans; + } else { + ERR(kLncErr, "invalid stack items for pop wide item operation"); + return UniqueFEIRVar(nullptr); + } + } +} + +UniqueFEIRVar JBCStack2FEHelper::PopItemAuto(PrimType &pty) { + size_t size = stack.size(); + if (size < 1) { // pop item operation need at least 1 item in stack + ERR(kLncErr, "stack items are not enough for pop operation"); + return UniqueFEIRVar(nullptr); + } + pty = PTY_unknown; + StackItem &item1 = stack[size - 1]; // the 1st item from top + if (IsItemDummy(item1)) { + if (size < 2) { // pop wide item operation need at least 2 items in stack + ERR(kLncErr, "stack items are not enough for pop operation"); + return UniqueFEIRVar(nullptr); + } + StackItem &item2 = stack[size - 2]; // the 2nd item from top + if (IsItemWide(item2)) { + UniqueFEIRVar ans = std::move(item2.first); + pty = item2.second; + stack.pop_back(); + stack.pop_back(); + return ans; + } else { + ERR(kLncErr, "invalid stack items for pop wide item operation"); + return UniqueFEIRVar(nullptr); + } + } else if (IsItemNormal(item1)) { + UniqueFEIRVar ans = std::move(item1.first); + pty = item1.second; + stack.pop_back(); + return ans; + } else { + ERR(kLncErr, "invalid stack items for pop wide item operation"); + return UniqueFEIRVar(nullptr); + } +} + +bool JBCStack2FEHelper::Swap() { + size_t size = stack.size(); + if (size < 2) { // swap operation need at least 2 items in stack + ERR(kLncErr, "stack is not enough for swap operation"); + return false; + } + StackItem &item1 = stack[size - 1]; // the 1st item from top + StackItem &item2 = stack[size - 2]; // the 2nd item from top + if (IsItemNormal(item1) && IsItemNormal(item2)) { + UniqueFEIRVar var1 = std::move(item1.first); + PrimType pty1 = item1.second; + UniqueFEIRVar var2 = std::move(item2.first); + PrimType pty2 = item2.second; + stack.pop_back(); + stack.pop_back(); + stack.push_back(MakeStackItem(std::move(var1), pty1)); + stack.push_back(MakeStackItem(std::move(var2), pty2)); + return true; + } else { + ERR(kLncErr, "invalid stack items for swap operation"); + return false; + } +} + +bool JBCStack2FEHelper::Pop(jbc::JBCOpcode opcode) { + switch (opcode) { + case jbc::kOpPop: + return Pop(); + case jbc::kOpPop2: + return Pop2(); + default: + ERR(kLncErr, "unsupported op: %s", jbc::JBCOp::GetOpcodeInfo().GetOpcodeName(opcode).c_str()); + return false; + } +} + +bool JBCStack2FEHelper::Dup(jbc::JBCOpcode opcode) { + switch (opcode) { + case jbc::kOpDup: + return Dup(); + case jbc::kOpDupX1: + return DupX1(); + case jbc::kOpDupX2: + return DupX2(); + case jbc::kOpDup2: + return Dup2(); + case jbc::kOpDup2X1: + return Dup2X1(); + case jbc::kOpDup2X2: + return Dup2X2(); + default: + ERR(kLncErr, "unsupported op: %s", jbc::JBCOp::GetOpcodeInfo().GetOpcodeName(opcode).c_str()); + return false; + } +} + +std::list JBCStack2FEHelper::GenerateSwapStmts() { + std::list ans; + PrimType pty = PTY_unknown; + UniqueFEIRVar varStack = PopItemAuto(pty); + uint32 swapRegNum = nStacks; + while (varStack != nullptr) { + UniqueFEIRVar varSwap = std::make_unique(swapRegNum, pty); + UniqueFEIRExpr exprDRead = FEIRBuilder::CreateExprDRead(std::move(varStack)); + UniqueFEIRStmt stmtDAssign = FEIRBuilder::CreateStmtDAssign(std::move(varSwap), std::move(exprDRead)); + ans.push_back(std::move(stmtDAssign)); + if (pty == PTY_i64 || pty == PTY_f64) { + swapRegNum += kRegNumOffWide; + } else { + swapRegNum += kRegNumOff; + } + varStack = PopItemAuto(pty); + } + return ans; +} + +std::list JBCStack2FEHelper::LoadSwapStack(const JBCStackHelper &stackHelper, bool &success) { + std::list ans; + std::vector jbcStackItems = stackHelper.GetStackItems(); + std::vector primStackItems = JBCStackItemTypesToPrimTypes(jbcStackItems); + stack.clear(); + if (!CheckSwapValid(primStackItems)) { + success = false; + return ans; + } + std::vector> swapRegs = GeneralSwapRegNum(primStackItems); + uint32 regNumStack = 0; + for (const std::pair &item : swapRegs) { + PrimType pty = item.second; + UniqueFEIRVar varSwap = std::make_unique(item.first, pty); + UniqueFEIRVar varStack = std::make_unique(regNumStack, pty); + UniqueFEIRExpr exprDRead = FEIRBuilder::CreateExprDRead(std::move(varSwap)); + UniqueFEIRStmt stmtDAssign = FEIRBuilder::CreateStmtDAssign(varStack->Clone(), std::move(exprDRead)); + ans.push_back(std::move(stmtDAssign)); + stack.push_back(MakeStackItem(std::move(varStack), pty)); + if (pty == PTY_i64 || pty == PTY_f64) { + regNumStack += kRegNumOffWide; + stack.push_back(MakeStackItem(UniqueFEIRVar(nullptr), pty)); + } else { + regNumStack += kRegNumOff; + } + } + success = true; + return ans; +} + +PrimType JBCStack2FEHelper::JBCStackItemTypeToPrimType(jbc::JBCPrimType itemType) { + switch (itemType) { + case jbc::JBCPrimType::kTypeInt: + case jbc::JBCPrimType::kTypeByteOrBoolean: + case jbc::JBCPrimType::kTypeShort: + case jbc::JBCPrimType::kTypeChar: + return PTY_i32; + case jbc::JBCPrimType::kTypeLong: + return PTY_i64; + case jbc::JBCPrimType::kTypeFloat: + return PTY_f32; + case jbc::JBCPrimType::kTypeDouble: + return PTY_f64; + case jbc::JBCPrimType::kTypeRef: + return PTY_ref; + case jbc::JBCPrimType::kTypeAddress: + return PTY_a32; + case jbc::JBCPrimType::kTypeDefault: + return PTY_unknown; + default: + ERR(kLncErr, "Should not run here: unsupported type"); + return PTY_unknown; + } +} + +PrimType JBCStack2FEHelper::SimplifyPrimType(PrimType pty) { + switch (pty) { + case PTY_u1: // boolean + case PTY_i8: // byte + case PTY_i16: // short + case PTY_u16: // char + return PTY_i32; + default: + return pty; + } +} + +std::vector JBCStack2FEHelper::JBCStackItemTypesToPrimTypes(const std::vector itemTypes) { + std::vector primTypes; + for (jbc::JBCPrimType itemType : itemTypes) { + primTypes.push_back(JBCStackItemTypeToPrimType(itemType)); + } + return primTypes; +} + +bool JBCStack2FEHelper::CheckSwapValid(const std::vector items) const { + uint32 size = 0; + for (PrimType pty : items) { + if (pty == PTY_i64 || pty == PTY_f64) { + size += kRegNumOffWide; + } else { + size += kRegNumOff; + } + } + if (size > nSwaps) { + ERR(kLncErr, "swap stack out of range"); + return false; + } else { + return true; + } +} + +std::vector> JBCStack2FEHelper::GeneralSwapRegNum(const std::vector items) { + std::vector> ans; + size_t size = items.size(); + uint32 regNum = nStacks; + for (size_t i = 1; i <= size; i++) { + PrimType pty = items[size - i]; + ans.push_back(std::make_pair(regNum, pty)); + if (pty == PTY_i64 || pty == PTY_f64) { + regNum += 2; // wide type uses 2 stack items + } else { + regNum += 1; // normal type uses 1 stack items + } + } + std::reverse(ans.begin(), ans.end()); + return ans; +} + +std::string JBCStack2FEHelper::DumpStackInJavaFormat() const { + std::string ans; + for (const StackItem &item : stack) { + switch (item.second) { + case PTY_i32: + ans.push_back('I'); + break; + case PTY_i64: + ans.push_back('J'); + break; + case PTY_f32: + ans.push_back('F'); + break; + case PTY_f64: + ans.push_back('D'); + break; + case PTY_ref: + ans.push_back('R'); + break; + default: + return std::string("unsupport type") + GetPrimTypeName(item.second); + } + } + return ans; +} + +std::string JBCStack2FEHelper::DumpStackInInternalFormat() const { + std::string ans; + for (const StackItem &item : stack) { + if (IsItemNormal(item)) { + ans.push_back('N'); + } else if (IsItemWide(item)) { + ans.push_back('W'); + } else if (IsItemDummy(item)) { + ans.push_back('D'); + } else { + return "unsupport item"; + } + } + return ans; +} + +bool JBCStack2FEHelper::Pop() { + size_t size = stack.size(); + if (size < 1) { + ERR(kLncErr, "stack is not enough for pop operation"); + return false; + } + StackItem &item = stack[size - 1]; // the 1st item from top + if (IsItemNormal(item)) { + stack.pop_back(); + return true; + } else { + ERR(kLncErr, "invalid stack top item for pop operation"); + return false; + } +} + +bool JBCStack2FEHelper::Pop2() { + size_t size = stack.size(); + if (size < 2) { // 2 : The minimum size of the stack + ERR(kLncErr, "stack is not enough for pop2 operation"); + return false; + } + StackItem &item1 = stack[size - 1]; // the 1st item from top + StackItem &item2 = stack[size - 2]; // the 2nd item from top + if ((IsItemDummy(item1) && IsItemWide(item2)) || (IsItemNormal(item1) && IsItemNormal(item2))) { + stack.pop_back(); + stack.pop_back(); + return true; + } else { + ERR(kLncErr, "invalid stack top item for pop2 operation"); + return false; + } +} + +// notation for value used in Dup +// value(N): normal value (i32, f32) +// value(W): wide value (i64, f64) +// value(D): dummy value of wide value +bool JBCStack2FEHelper::Dup() { + size_t size = stack.size(); + if (size < 1) { // dup operation need at least 1 item in stack + ERR(kLncErr, "stack is not enough for dup operation"); + return false; + } + StackItem &item = stack[size - 1]; // the 1st item from top + if (IsItemNormal(item)) { + // before: ..., value(N) -> + // after: ..., value(N), value(N) -> + UniqueFEIRVar var = item.first->Clone(); + PrimType pty = item.second; + stack.push_back(MakeStackItem(std::move(var), pty)); + return true; + } else { + ERR(kLncErr, "invalid stack items for dup operation"); + return false; + } +} + +bool JBCStack2FEHelper::DupX1() { + size_t size = stack.size(); + if (size < 2) { // dup_x1 operation need at least 2 item in stack + ERR(kLncErr, "stack is not enough for dup_x1 operation"); + return false; + } + StackItem &item1 = stack[size - 1]; // the 1st item from top + StackItem &item2 = stack[size - 2]; // the 2nd item from top + if (IsItemNormal(item1) && IsItemNormal(item2)) { + // before: ..., value2(N), value1(N) -> + // after: ..., value1(N), value2(N), value1(N) -> + UniqueFEIRVar var1 = item1.first->Clone(); + PrimType pty1 = item1.second; + std::vector::iterator it = stack.end() - 2; // the 2nd item position from top + CHECK_FATAL(stack.insert(it, MakeStackItem(std::move(var1), pty1)) != stack.end(), "stack insert failed"); + return true; + } else { + ERR(kLncErr, "invalid stack items for dup_x1 operation"); + return false; + } +} + +bool JBCStack2FEHelper::DupX2() { + size_t size = stack.size(); + if (size < 3) { // dup_x1 operation need at least 3 item in stack + ERR(kLncErr, "stack is not enough for dup_x2 operation"); + return false; + } + StackItem &item1 = stack[size - 1]; // the 1st item from top + StackItem &item2 = stack[size - 2]; // the 2nd item from top + StackItem &item3 = stack[size - 3]; // the 3rd item from top + // situation 1 + // before: ..., value3(N), value2(N), value1(N) -> + // after: ..., value1(N), value3(N), value2(N), value1(N) -> + bool isSituation1 = (IsItemNormal(item1) && IsItemNormal(item2) && IsItemNormal(item3)); + // situation 2 + // before: ..., value3(W), value2(D), value1(N) -> + // after: ..., value1(N), value3(W), value2(D), value1(N) -> + bool isSituation2 = (IsItemNormal(item1) && IsItemDummy(item2) && IsItemWide(item3)); + if (!(isSituation1 || isSituation2)) { + ERR(kLncErr, "invalid stack items for dup_x2 operation"); + return false; + } + // situation1 situation2 + // value1 N N + UniqueFEIRVar var1 = item1.first->Clone(); + PrimType pty1 = item1.second; + // insert copy of value1 before the 3rd item from top + std::vector::iterator it = stack.end() - 3; + CHECK_FATAL(stack.insert(it, MakeStackItem(std::move(var1), pty1)) != stack.end(), "stack insert failed"); + return true; +} + +bool JBCStack2FEHelper::Dup2() { + size_t size = stack.size(); + if (size < 2) { // dup2 operation need at least 2 item in stack + ERR(kLncErr, "stack is not enough for dup2 operation"); + return false; + } + StackItem &item1 = stack[size - 1]; // the 1st item from top + StackItem &item2 = stack[size - 2]; // the 2nd item from top + // situation 1 + // before: ..., value2(N), value1(N) -> + // after: ..., value2(N), value1(N), value2(N), value1(N) -> + bool isSituation1 = (IsItemNormal(item1) && IsItemNormal(item2)); + // situation 2 + // before: ..., value2(W), value1(D) -> + // after: ..., value2(W), value1(D), value2(W), value1(D) -> + bool isSituation2 = (IsItemDummy(item1) && IsItemWide(item2)); + if (!(isSituation1 || isSituation2)) { + ERR(kLncErr, "invalid stack items for dup2 operation"); + return false; + } + // situation1 situation2 + // value1 N D + // value2 N W + UniqueFEIRVar var1; + UniqueFEIRVar var2; + PrimType pty1 = item1.second; + PrimType pty2 = item2.second; + if (isSituation1) { + var1 = item1.first->Clone(); + var2 = item2.first->Clone(); + } else { + var1 = UniqueFEIRVar(nullptr); + var2 = item2.first->Clone(); + } + // insert copy of value2 before the 2nd item from top + std::vector::iterator it = stack.end() - 2; + CHECK_FATAL(stack.insert(it, MakeStackItem(std::move(var2), pty2)) != stack.end(), "stack insert failed"); + // insert copy of value1 before the 2nd item from top + it = stack.end() - 2; + CHECK_FATAL(stack.insert(it, MakeStackItem(std::move(var1), pty1)) != stack.end(), "stack insert failed"); + return true; +} + +bool JBCStack2FEHelper::Dup2X1() { + size_t size = stack.size(); + if (size < 3) { // dup2_x1 operation need at least 3 item in stack + ERR(kLncErr, "stack is not enough for dup2_x1 operation"); + return false; + } + StackItem &item1 = stack[size - 1]; // the 1st item from top + StackItem &item2 = stack[size - 2]; // the 2nd item from top + StackItem &item3 = stack[size - 3]; // the 3rd item from top + // situation 1 + // before: ..., value3(N), value2(N), value1(N) -> + // after: ..., value2(N), value1(N), value3(N), value2(N), value1(N) -> + bool isSituation1 = (IsItemNormal(item1) && IsItemNormal(item2) && IsItemNormal(item3)); + // situation 2 + // before: ..., value3(N), value2(W), value1(D) -> + // after: ..., value2(W), value1(D), value3(N), value2(W), value1(D) -> + bool isSituation2 = (IsItemDummy(item1) && IsItemWide(item2) && IsItemNormal(item3)); + if (!(isSituation1 || isSituation2)) { + ERR(kLncErr, "invalid stack items for dup2_x1 operation"); + return false; + } + // situation1 situation2 + // value1 N D + // value2 N W + UniqueFEIRVar var1; + UniqueFEIRVar var2; + PrimType pty1 = item1.second; + PrimType pty2 = item2.second; + if (isSituation1) { + var1 = item1.first->Clone(); + var2 = item2.first->Clone(); + } else { + var1 = UniqueFEIRVar(nullptr); + var2 = item2.first->Clone(); + } + // insert copy of value2 before the 3rd item from top + std::vector::iterator it = stack.end() - 3; + CHECK_FATAL(stack.insert(it, MakeStackItem(std::move(var2), pty2)) != stack.end(), "stack insert failed"); + // insert copy of value1 before the 3rd item from top + it = stack.end() - 3; + CHECK_FATAL(stack.insert(it, MakeStackItem(std::move(var1), pty1)) != stack.end(), "stack insert failed"); + return true; +} + +bool JBCStack2FEHelper::Dup2X2() { + size_t size = stack.size(); + if (size < 4) { // dup2_x2 operation need at least 4 item in stack + ERR(kLncErr, "stack is not enough for dup2_x2 operation"); + return false; + } + StackItem &item1 = stack[size - 1]; // the 1st item from top + StackItem &item2 = stack[size - 2]; // the 2nd item from top + StackItem &item3 = stack[size - 3]; // the 3rd item from top + StackItem &item4 = stack[size - 4]; // the 4th item from top + // situation 1 + // before: ..., value4(N), value3(N), value2(N), value1(N) -> + // after: ..., value2(N), value1(N), value4(N), value3(N), value2(N), value1(N) -> + bool isSituation1 = (IsItemNormal(item1) && IsItemNormal(item2) && IsItemNormal(item3) && IsItemNormal(item4)); + // situation 2 + // before: ..., value4(N), value3(N), value2(W), value1(D) -> + // after: ..., value2(W), value1(D), value4(N), value3(N), value2(W), value1(D) -> + bool isSituation2 = (IsItemDummy(item1) && IsItemWide(item2) && IsItemNormal(item3) && IsItemNormal(item4)); + // situation 3 + // before: ..., value4(W), value3(D), value2(N), value1(N) -> + // after: ..., value2(N), value1(N), value4(W), value3(D), value2(W), value1(D) -> + bool isSituation3 = (IsItemNormal(item1) && IsItemNormal(item2) && IsItemDummy(item3) && IsItemWide(item4)); + // situation 4 + // before: ..., value4(W), value3(D), value2(W), value1(D) -> + // after: ..., value2(W), value1(D), value4(W), value3(D), value2(W), value1(D) -> + bool isSituation4 = (IsItemDummy(item1) && IsItemWide(item2) && IsItemDummy(item3) && IsItemWide(item4)); + if (!(isSituation1 || isSituation2 || isSituation3 || isSituation4)) { + ERR(kLncErr, "invalid stack items for dup2_x1 operation"); + return false; + } + // situation1 situation2 situation3 situation4 + // value1 N D N D + // value2 N W N W + UniqueFEIRVar var1; + UniqueFEIRVar var2; + PrimType pty1 = item1.second; + PrimType pty2 = item2.second; + if (isSituation1 || isSituation3) { + var1 = item1.first->Clone(); + var2 = item2.first->Clone(); + } else { + var1 = UniqueFEIRVar(nullptr); + var2 = item2.first->Clone(); + } + // insert copy of value2 before the 4th item from top + std::vector::iterator it = stack.end() - 4; + CHECK_FATAL(stack.insert(it, MakeStackItem(std::move(var2), pty2)) != stack.end(), "stack insert failed"); + // insert copy of value1 before the 4th item from top + it = stack.end() - 4; + CHECK_FATAL(stack.insert(it, MakeStackItem(std::move(var1), pty1)) != stack.end(), "stack insert failed"); + return true; +} +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_stack_helper.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_stack_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..326b089027d22a68cc2a6a22af24aa15e9527853 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_stack_helper.cpp @@ -0,0 +1,426 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_stack_helper.h" + +namespace maple { +namespace { +const uint32 kSize1 = 1; +const uint32 kSize2 = 2; +const uint32 kSize3 = 3; +const uint32 kSize4 = 4; +} // namespace + +void JBCStackHelper::Reset() { + stack.clear(); +} + +bool JBCStackHelper::StackChange(const jbc::JBCOp &op, const jbc::JBCConstPool &constPool) { + switch (op.GetOpcodeKind()) { + case jbc::kOpKindConst: { + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(constPool); + if (stackOutType != jbc::JBCPrimType::kTypeDefault) { + PushItem(stackOutType); + } else { + return false; + } + return true; + } + case jbc::kOpKindPop: + return Pop(op.GetOpcode()); + case jbc::kOpKindDup: + return Dup(op.GetOpcode()); + case jbc::kOpKindSwap: + return Swap(); + case jbc::kOpKindFieldOpr: + case jbc::kOpKindStaticFieldOpr: + case jbc::kOpKindInvoke: + case jbc::kOpKindMultiANewArray: { + std::vector stackInTypes = op.GetInputTypesFromStack(constPool); + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(constPool); + bool success = PopItems(stackInTypes); + if (success && stackOutType != jbc::JBCPrimType::kTypeDefault) { + PushItem(stackOutType); + } + return success; + } + default: { + const std::vector &stackInTypes = op.GetInputTypesFromStack(); + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(); + bool success = PopItems(stackInTypes); + if (success && stackOutType != jbc::JBCPrimType::kTypeDefault) { + PushItem(stackOutType); + } + return success; + } + } +} + +void JBCStackHelper::PushItem(jbc::JBCPrimType type) { + stack.push_back(GetGeneralType(type)); + if (type == jbc::JBCPrimType::kTypeLong) { + stack.push_back(jbc::JBCPrimType::kTypeLongDummy); + } else if (type == jbc::JBCPrimType::kTypeDouble) { + stack.push_back(jbc::JBCPrimType::kTypeDoubleDummy); + } else { + // nothing to be done + } +} + +void JBCStackHelper::PushItems(const std::vector &types) { + for (jbc::JBCPrimType type : types) { + PushItem(type); + } +} + +bool JBCStackHelper::PopItem(jbc::JBCPrimType type) { + if (stack.size() == 0) { + return false; + } + type = GetGeneralType(type); + switch (type) { + case jbc::JBCPrimType::kTypeInt: + case jbc::JBCPrimType::kTypeFloat: + case jbc::JBCPrimType::kTypeRef: + case jbc::JBCPrimType::kTypeAddress: + if (stack.size() >= kSize1 && stack.back() == type) { + stack.pop_back(); + return true; + } + break; + case jbc::JBCPrimType::kTypeLong: + if (stack.size() >= kSize2 && stack.back() == jbc::JBCPrimType::kTypeLongDummy) { + stack.pop_back(); + stack.pop_back(); + return true; + } + break; + case jbc::JBCPrimType::kTypeDouble: + if (stack.size() >= kSize2 && stack.back() == jbc::JBCPrimType::kTypeDoubleDummy) { + stack.pop_back(); + stack.pop_back(); + return true; + } + break; + case jbc::JBCPrimType::kTypeDefault: + return true; + default: + CHECK_FATAL(false, "Should not run here: invalid type"); + break; + } + return false; +} + +bool JBCStackHelper::PopItems(const std::vector &types) { + size_t idx = types.size() - 1; + for (size_t i = 0; i < types.size(); i++, idx--) { + if (PopItem(types[idx]) == false) { + return false; + } + } + return true; +} + +bool JBCStackHelper::Pop(jbc::JBCOpcode opcode) { + switch (opcode) { + case jbc::kOpPop: + if (stack.size() >= kSize1 && IsType1(stack.back())) { + stack.pop_back(); + return true; + } + break; + case jbc::kOpPop2: + if (stack.size() >= kSize2 && IsType2Dummy(stack.back())) { + stack.pop_back(); + stack.pop_back(); + return true; + } + break; + default: + CHECK_FATAL(false, "Unsupported opcode: %s", jbc::JBCOp::GetOpcodeInfo().GetOpcodeName(opcode).c_str()); + break; + } + return false; +} + +bool JBCStackHelper::Dup(jbc::JBCOpcode opcode) { + switch (opcode) { + case jbc::kOpDup: + return Dup(); + case jbc::kOpDupX1: + return DupX1(); + case jbc::kOpDupX2: + return DupX2(); + case jbc::kOpDup2: + return Dup2(); + case jbc::kOpDup2X1: + return Dup2X1(); + case jbc::kOpDup2X2: + return Dup2X2(); + default: + CHECK_FATAL(false, "Unsupported opcode: %s", jbc::JBCOp::GetOpcodeInfo().GetOpcodeName(opcode).c_str()); + break; + } + return false; +} + +bool JBCStackHelper::Dup() { + if (stack.size() < kSize1) { + return false; + } + jbc::JBCPrimType t = stack.back(); + if (IsType1(t)) { + stack.push_back(t); + return true; + } + return false; +} + +bool JBCStackHelper::DupX1() { + if (stack.size() < kSize2) { + return false; + } + jbc::JBCPrimType t1 = stack.back(); + stack.pop_back(); + jbc::JBCPrimType t2 = stack.back(); + stack.pop_back(); + bool success = (IsType1(t1) && IsType1(t2)); + if (success) { + stack.push_back(t1); + } + stack.push_back(t2); + stack.push_back(t1); + return success; +} + +bool JBCStackHelper::DupX2() { + if (stack.size() < kSize3) { + return false; + } + jbc::JBCPrimType t1 = stack.back(); + stack.pop_back(); + jbc::JBCPrimType t2 = stack.back(); + stack.pop_back(); + jbc::JBCPrimType t3 = stack.back(); + stack.pop_back(); + bool success = IsType1(t1); + if (success) { + stack.push_back(t1); + } + stack.push_back(t3); + stack.push_back(t2); + stack.push_back(t1); + return success; +} + +bool JBCStackHelper::Dup2() { + if (stack.size() < kSize2) { + return false; + } + jbc::JBCPrimType t1 = stack.back(); + stack.pop_back(); + jbc::JBCPrimType t2 = stack.back(); + stack.pop_back(); + bool success = ((IsType1(t1) && IsType1(t2)) || (IsType2Dummy(t1) && IsType2(t2))); + if (success) { + stack.push_back(t2); + stack.push_back(t1); + } + stack.push_back(t2); + stack.push_back(t1); + return success; +} + +bool JBCStackHelper::Dup2X1() { + if (stack.size() < kSize3) { + return false; + } + jbc::JBCPrimType t1 = stack.back(); + stack.pop_back(); + jbc::JBCPrimType t2 = stack.back(); + stack.pop_back(); + jbc::JBCPrimType t3 = stack.back(); + stack.pop_back(); + bool success = IsType1(t3); + if (success) { + stack.push_back(t2); + stack.push_back(t1); + } + stack.push_back(t3); + stack.push_back(t2); + stack.push_back(t1); + return success; +} + +bool JBCStackHelper::Dup2X2() { + if (stack.size() < kSize4) { + return false; + } + jbc::JBCPrimType t1 = stack.back(); + stack.pop_back(); + jbc::JBCPrimType t2 = stack.back(); + stack.pop_back(); + jbc::JBCPrimType t3 = stack.back(); + stack.pop_back(); + jbc::JBCPrimType t4 = stack.back(); + stack.pop_back(); + stack.push_back(t2); + stack.push_back(t1); + stack.push_back(t4); + stack.push_back(t3); + stack.push_back(t2); + stack.push_back(t1); + return true; +} + +bool JBCStackHelper::Swap() { + if (stack.size() < kSize2) { + return false; + } + jbc::JBCPrimType t1 = stack.back(); + stack.pop_back(); + jbc::JBCPrimType t2 = stack.back(); + stack.pop_back(); + if (IsType1(t1) && IsType1(t2)) { + stack.push_back(t1); + stack.push_back(t2); + return true; + } else { + stack.push_back(t2); + stack.push_back(t1); + return false; + } +} + +bool JBCStackHelper::IsType1(jbc::JBCPrimType type) const { + if (type == jbc::JBCPrimType::kTypeInt || type == jbc::JBCPrimType::kTypeFloat || + type == jbc::JBCPrimType::kTypeByteOrBoolean || type == jbc::JBCPrimType::kTypeChar || + type == jbc::JBCPrimType::kTypeShort || type == jbc::JBCPrimType::kTypeRef || + type == jbc::JBCPrimType::kTypeAddress) { + return true; + } else { + return false; + } +} + +bool JBCStackHelper::IsType2(jbc::JBCPrimType type) const { + if (type == jbc::JBCPrimType::kTypeLong || type == jbc::JBCPrimType::kTypeDouble) { + return true; + } else { + return false; + } +} + +bool JBCStackHelper::IsType2Dummy(jbc::JBCPrimType type) const { + if (type == jbc::JBCPrimType::kTypeLongDummy || type == jbc::JBCPrimType::kTypeDoubleDummy) { + return true; + } else { + return false; + } +} + +jbc::JBCPrimType JBCStackHelper::GetGeneralType(jbc::JBCPrimType type) const { + if (type == jbc::JBCPrimType::kTypeByteOrBoolean || type == jbc::JBCPrimType::kTypeChar || + type == jbc::JBCPrimType::kTypeShort) { + return jbc::JBCPrimType::kTypeInt; + } else { + return type; + } +} + +void JBCStackHelper::CopyFrom(const JBCStackHelper &src) { + for (jbc::JBCPrimType item : src.stack) { + stack.push_back(item); + } +} + +bool JBCStackHelper::EqualTo(const JBCStackHelper &src) { + if (stack.size() != src.stack.size()) { + return false; + } + for (size_t i = 0; i < stack.size(); i++) { + if (stack[i] != src.stack[i]) { + return false; + } + } + return true; +} + +bool JBCStackHelper::Contains(const JBCStackHelper &src) { + // this contains src (this >= src) + if (EqualTo(src)) { + return true; + } + size_t size = stack.size(); + size_t sizeSrc = src.stack.size(); + if (size < sizeSrc) { + return false; + } + for (size_t i = 1; i <= sizeSrc; i++) { + if (stack[size - i] != src.stack[sizeSrc - 1]) { + return false; + } + } + return true; +} + +void JBCStackHelper::Dump() const { + std::cout << "{"; + for (jbc::JBCPrimType item : stack) { + std::cout << GetTypeName(item) << " "; + } + std::cout << "}"; +} + +std::string JBCStackHelper::GetTypeName(jbc::JBCPrimType type) { + switch (type) { + case jbc::JBCPrimType::kTypeDefault: + return "default"; + case jbc::JBCPrimType::kTypeInt: + return "int"; + case jbc::JBCPrimType::kTypeLong: + return "long"; + case jbc::JBCPrimType::kTypeFloat: + return "float"; + case jbc::JBCPrimType::kTypeDouble: + return "double"; + case jbc::JBCPrimType::kTypeByteOrBoolean: + return "byte/boolean"; + case jbc::JBCPrimType::kTypeChar: + return "char"; + case jbc::JBCPrimType::kTypeShort: + return "short"; + case jbc::JBCPrimType::kTypeRef: + return "ref"; + case jbc::JBCPrimType::kTypeAddress: + return "address"; + case jbc::JBCPrimType::kTypeLongDummy: + return "long-dummy"; + case jbc::JBCPrimType::kTypeDoubleDummy: + return "double-dummy"; + default: + return "unknown"; + } +} + +std::vector JBCStackHelper::GetStackItems() const { + std::vector ans; + for (jbc::JBCPrimType item : stack) { + if (item != jbc::JBCPrimType::kTypeLongDummy && item != jbc::JBCPrimType::kTypeDoubleDummy) { + ans.push_back(item); + } + } + return ans; +} +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_stmt.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_stmt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..708395d4a5620ec2dc3be0a642ad5119b1276252 --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_stmt.cpp @@ -0,0 +1,1559 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_stmt.h" +#include +#include +#include +#include "opcodes.h" +#include "feir_stmt.h" +#include "feir_builder.h" +#include "fe_struct_elem_info.h" +#include "jbc_function_context.h" + +namespace maple { +// ---------- JBCStmtKindHelper ---------- +std::string JBCStmtKindHelper::JBCStmtKindName(JBCStmtKind kind) { + switch (kind) { + case kJBCStmtDefault: + return "JBCStmtDefault"; + case kJBCStmtFuncBeing: + return "JBCStmtFuncBegin"; + case kJBCStmtFuncEnd: + return "JBCStmtFuncEnd"; + case kJBCStmtInst: + return "JBCStmtInst"; + case kJBCStmtInstBranch: + return "JBCStmtInstBranch"; + case kJBCStmtPesudoComment: + return "JBCStmtPesudoComment"; + case kJBCStmtPesudoLabel: + return "JBCStmtPesudoLabel"; + case kJBCStmtPesudoLOC: + return "JBCStmtPesudoLOC"; + case kJBCStmtPesudoTry: + return "JBCStmtPesudoTry"; + case kJBCStmtPesudoEndTry: + return "JBCStmtPesudoEndTry"; + case kJBCStmtPesudoCatch: + return "JBCStmtPesudoCatch"; + default: + return "unknown"; + } +} + +// ---------- JBCStmtInst ---------- +std::map JBCStmtInst::funcPtrMapForEmitToFEIR = + JBCStmtInst::InitFuncPtrMapForEmitToFEIR(); +std::map JBCStmtInst::opcodeMapForMathBinop = JBCStmtInst::InitOpcodeMapForMathBinop(); +std::map JBCStmtInst::opcodeMapForMathUnop = JBCStmtInst::InitOpcodeMapForMathUnop(); +std::map JBCStmtInst::opcodeMapForMonitor = JBCStmtInst::InitOpcodeMapForMonitor(); + +JBCStmtInst::JBCStmtInst(const jbc::JBCOp &argOp) + : JBCStmt(kJBCStmtInst), + op(argOp) { + SetFallThru(op.IsFallThru()); +} + +bool JBCStmtInst::IsStmtInstImpl() const { + return true; +} + +void JBCStmtInst::DumpImpl(const std::string &prefix) const { + std::cout << prefix << "JBCStmtInst (id=" << id << ", " << + "kind=" << JBCStmtKindHelper::JBCStmtKindName(JBCkind) << ", " << + "op=" << op.GetOpcodeName() << + ")" << std::endl; +} + +std::string JBCStmtInst::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << op.GetOpcodeName(); + return ss.str(); +} + +std::list JBCStmtInst::EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const { + auto it = funcPtrMapForEmitToFEIR.find(op.GetOpcodeKind()); + if (it != funcPtrMapForEmitToFEIR.end()) { + return (this->*(it->second))(context, success); + } else { + return EmitToFEIRCommon(context, success); + } +} + +std::map JBCStmtInst::InitFuncPtrMapForEmitToFEIR() { + std::map ans; + ans[jbc::JBCOpcodeKind::kOpKindConst] = &JBCStmtInst::EmitToFEIRForOpConst; + ans[jbc::JBCOpcodeKind::kOpKindLoad] = &JBCStmtInst::EmitToFEIRForOpLoad; + ans[jbc::JBCOpcodeKind::kOpKindStore] = &JBCStmtInst::EmitToFEIRForOpStore; + ans[jbc::JBCOpcodeKind::kOpKindArrayLoad] = &JBCStmtInst::EmitToFEIRForOpArrayLoad; + ans[jbc::JBCOpcodeKind::kOpKindArrayStore] = &JBCStmtInst::EmitToFEIRForOpArrayStore; + ans[jbc::JBCOpcodeKind::kOpKindPop] = &JBCStmtInst::EmitToFEIRForOpPop; + ans[jbc::JBCOpcodeKind::kOpKindDup] = &JBCStmtInst::EmitToFEIRForOpDup; + ans[jbc::JBCOpcodeKind::kOpKindSwap] = &JBCStmtInst::EmitToFEIRForOpSwap; + ans[jbc::JBCOpcodeKind::kOpKindMathBinop] = &JBCStmtInst::EmitToFEIRForOpMathBinop; + ans[jbc::JBCOpcodeKind::kOpKindMathUnop] = &JBCStmtInst::EmitToFEIRForOpMathUnop; + ans[jbc::JBCOpcodeKind::kOpKindMathInc] = &JBCStmtInst::EmitToFEIRForOpMathInc; + ans[jbc::JBCOpcodeKind::kOpKindConvert] = &JBCStmtInst::EmitToFEIRForOpConvert; + ans[jbc::JBCOpcodeKind::kOpKindCompare] = &JBCStmtInst::EmitToFEIRForOpMathBinop; + ans[jbc::JBCOpcodeKind::kOpKindReturn] = &JBCStmtInst::EmitToFEIRForOpReturn; + ans[jbc::JBCOpcodeKind::kOpKindStaticFieldOpr] = &JBCStmtInst::EmitToFEIRForOpStaticFieldOpr; + ans[jbc::JBCOpcodeKind::kOpKindFieldOpr] = &JBCStmtInst::EmitToFEIRForOpFieldOpr; + ans[jbc::JBCOpcodeKind::kOpKindInvoke] = &JBCStmtInst::EmitToFEIRForOpInvoke; + ans[jbc::JBCOpcodeKind::kOpKindNew] = &JBCStmtInst::EmitToFEIRForOpNew; + ans[jbc::JBCOpcodeKind::kOpKindMultiANewArray] = &JBCStmtInst::EmitToFEIRForOpMultiANewArray; + ans[jbc::JBCOpcodeKind::kOpKindThrow] = &JBCStmtInst::EmitToFEIRForOpThrow; + ans[jbc::JBCOpcodeKind::kOpKindTypeCheck] = &JBCStmtInst::EmitToFEIRForOpTypeCheck; + ans[jbc::JBCOpcodeKind::kOpKindMonitor] = &JBCStmtInst::EmitToFEIRForOpMonitor; + ans[jbc::JBCOpcodeKind::kOpKindArrayLength] = &JBCStmtInst::EmitToFEIRForOpArrayLength; + return ans; +} + +std::map JBCStmtInst::InitOpcodeMapForMathBinop() { + std::map ans; + ans[jbc::kOpIAdd] = OP_add; + ans[jbc::kOpLAdd] = OP_add; + ans[jbc::kOpFAdd] = OP_add; + ans[jbc::kOpDAdd] = OP_add; + ans[jbc::kOpISub] = OP_sub; + ans[jbc::kOpLSub] = OP_sub; + ans[jbc::kOpFSub] = OP_sub; + ans[jbc::kOpDSub] = OP_sub; + ans[jbc::kOpIMul] = OP_mul; + ans[jbc::kOpLMul] = OP_mul; + ans[jbc::kOpFMul] = OP_mul; + ans[jbc::kOpDMul] = OP_mul; + ans[jbc::kOpIDiv] = OP_div; + ans[jbc::kOpLDiv] = OP_div; + ans[jbc::kOpFDiv] = OP_div; + ans[jbc::kOpDDiv] = OP_div; + ans[jbc::kOpIRem] = OP_rem; + ans[jbc::kOpLRem] = OP_rem; + ans[jbc::kOpFRem] = OP_rem; + ans[jbc::kOpDRem] = OP_rem; + ans[jbc::kOpIShl] = OP_shl; + ans[jbc::kOpLShl] = OP_shl; + ans[jbc::kOpIShr] = OP_ashr; + ans[jbc::kOpLShr] = OP_ashr; + ans[jbc::kOpIUShr] = OP_lshr; + ans[jbc::kOpLUShr] = OP_lshr; + ans[jbc::kOpIAnd] = OP_band; + ans[jbc::kOpLAnd] = OP_band; + ans[jbc::kOpIOr] = OP_bior; + ans[jbc::kOpLOr] = OP_bior; + ans[jbc::kOpIXor] = OP_bxor; + ans[jbc::kOpLXor] = OP_bxor; + ans[jbc::kOpLCmp] = OP_cmp; + ans[jbc::kOpFCmpl] = OP_cmpl; + ans[jbc::kOpFCmpg] = OP_cmpg; + ans[jbc::kOpDCmpl] = OP_cmpl; + ans[jbc::kOpDCmpg] = OP_cmpg; + return ans; +} + +std::map JBCStmtInst::InitOpcodeMapForMathUnop() { + std::map ans; + ans[jbc::kOpINeg] = OP_neg; + ans[jbc::kOpLNeg] = OP_neg; + ans[jbc::kOpFNeg] = OP_neg; + ans[jbc::kOpDNeg] = OP_neg; + return ans; +} + +std::map JBCStmtInst::InitOpcodeMapForMonitor() { + std::map ans; + ans[jbc::kOpMonitorEnter] = OP_syncenter; + ans[jbc::kOpMonitorExit] = OP_syncexit; + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpConst(JBCFunctionContext &context, bool &success) const { + switch (op.GetOpcode()) { + case jbc::kOpAConstNull: + return EmitToFEIRForOpAConstNull(context, success); + case jbc::kOpIConstM1: + case jbc::kOpIConst0: + case jbc::kOpIConst1: + case jbc::kOpIConst2: + case jbc::kOpIConst3: + case jbc::kOpIConst4: + case jbc::kOpIConst5: + return EmitToFEIRForOpIConst(context, success); + case jbc::kOpLConst0: + case jbc::kOpLConst1: + return EmitToFEIRForOpLConst(context, success); + case jbc::kOpFConst0: + case jbc::kOpFConst1: + case jbc::kOpFConst2: + return EmitToFEIRForOpFConst(context, success); + case jbc::kOpDConst0: + case jbc::kOpDConst1: + return EmitToFEIRForOpDConst(context, success); + case jbc::kOpBiPush: + return EmitToFEIRForOpBiPush(context, success); + case jbc::kOpSiPush: + return EmitToFEIRForOpSiPush(context, success); + case jbc::kOpLdc: + case jbc::kOpLdcW: + case jbc::kOpLdc2W: + return EmitToFEIRForOpLdc(context, success); + default: + ERR(kLncErr, "EmitToFEIRForOpConst: unsupport jbc opcode %s", + jbc::JBCOp::GetOpcodeInfo().GetOpcodeName(op.GetOpcode()).c_str()); + success = false; + return std::list(); + } +} + +std::list JBCStmtInst::EmitToFEIRForOpConstCommon(JBCFunctionContext &context, bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(constPool); + if (stackOutType != jbc::JBCPrimType::kTypeDefault) { + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackOutType); + UniqueFEIRVar var = stack2feHelper.PushItem(pty); + if (var == nullptr) { + success = false; + } + } else { + success = false; + } + if (!success) { + ERR(kLncErr, "Error when EmitToFEIRForOpConst"); + } + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpAConstNull(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + UniqueFEIRExpr exprConst = FEIRBuilder::CreateExprConstRefNull(); + UniqueFEIRVar varDst = stack2feHelper.PushItem(PTY_ref); + if (varDst == nullptr) { + success = false; + return ans; + } + UniqueFEIRStmt stmtDAssign = FEIRBuilder::CreateStmtDAssign(std::move(varDst), std::move(exprConst)); + ans.push_back(std::move(stmtDAssign)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpIConst(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpConst &opConst = static_cast(op); + int32 val = opConst.GetValueInt(); + UniqueFEIRStmt stmtDAssign = GenerateStmtForConstI32(stack2feHelper, val, success); + if (success) { + ans.push_back(std::move(stmtDAssign)); + } + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpLConst(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpConst &opConst = static_cast(op); + int64 val = opConst.GetValueLong(); + UniqueFEIRStmt stmtDAssign = GenerateStmtForConstI64(stack2feHelper, val, success); + if (success) { + ans.push_back(std::move(stmtDAssign)); + } + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpFConst(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpConst &opConst = static_cast(op); + float val = opConst.GetValueFloat(); + UniqueFEIRStmt stmtDAssign = GenerateStmtForConstF32(stack2feHelper, val, success); + if (success) { + ans.push_back(std::move(stmtDAssign)); + } + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpDConst(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpConst &opConst = static_cast(op); + double val = opConst.GetValueDouble(); + UniqueFEIRStmt stmtDAssign = GenerateStmtForConstF64(stack2feHelper, val, success); + if (success) { + ans.push_back(std::move(stmtDAssign)); + } + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpBiPush(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpConst &opConst = static_cast(op); + int8 val = opConst.GetValueByte(); + UniqueFEIRStmt stmtDAssign = GenerateStmtForConstI32(stack2feHelper, int32{ val }, success); + if (success) { + ans.push_back(std::move(stmtDAssign)); + } + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpSiPush(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpConst &opConst = static_cast(op); + int16 val = opConst.GetValueShort(); + UniqueFEIRStmt stmtDAssign = GenerateStmtForConstI32(stack2feHelper, int32{ val }, success); + if (success) { + ans.push_back(std::move(stmtDAssign)); + } + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpLdc(JBCFunctionContext &context, bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpConst &opConst = static_cast(op); + const jbc::JBCConst *constRaw = constPool.GetConstByIdx(opConst.GetIndex()); + if (constRaw == nullptr) { + success = false; + return ans; + } + UniqueFEIRStmt stmtDAssign; + switch (constRaw->GetTag()) { + case jbc::kConstInteger: { + const jbc::JBCConst4Byte *const4B = static_cast(constRaw); + stmtDAssign = GenerateStmtForConstI32(stack2feHelper, const4B->GetInt32(), success); + break; + } + case jbc::kConstFloat: { + const jbc::JBCConst4Byte *const4B = static_cast(constRaw); + stmtDAssign = GenerateStmtForConstF32(stack2feHelper, const4B->GetFloat(), success); + break; + } + case jbc::kConstLong: { + const jbc::JBCConst8Byte *const8B = static_cast(constRaw); + stmtDAssign = GenerateStmtForConstI64(stack2feHelper, const8B->GetInt64(), success); + break; + } + case jbc::kConstDouble: { + const jbc::JBCConst8Byte *const8B = static_cast(constRaw); + stmtDAssign = GenerateStmtForConstF64(stack2feHelper, const8B->GetDouble(), success); + break; + } + case jbc::kConstString: { + const jbc::JBCConstString *constString = static_cast(constRaw); + UniqueFEIRVar varDst = stack2feHelper.PushItem(PTY_ref); + stmtDAssign = FEIRBuilder::CreateStmtJavaConstString(std::move(varDst), constString->GetString()); + break; + } + case jbc::kConstClass: { + const jbc::JBCConstClass *constClass = static_cast(constRaw); + UniqueFEIRVar varDst = stack2feHelper.PushItem(PTY_ref); + stmtDAssign = FEIRBuilder::CreateStmtJavaConstClass(std::move(varDst), constClass->GetFEIRType()->Clone()); + break; + } + default: + ERR(kLncErr, "EmitToFEIRForOpLdc: unsupported const kind"); + success = false; + } + if (success && stmtDAssign != nullptr) { + ans.push_back(std::move(stmtDAssign)); + } + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpLoad(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpSlotOpr &opLoad = static_cast(op); + std::vector stackInTypes = op.GetInputTypesFromStack(); + CHECK_FATAL(stackInTypes.empty(), "no items should be popped"); + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(); + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackOutType); + uint32 regNum = stack2feHelper.GetRegNumForSlot(opLoad.GetSlotIdx()); + const FEIRType *slotType = context.GetSlotType(opLoad.GetSlotIdx(), pc); + UniqueFEIRVar var; + UniqueFEIRVar varStack = stack2feHelper.PushItem(pty); + if (slotType != nullptr) { + var = FEIRBuilder::CreateVarReg(regNum, slotType->Clone()); + varStack->SetType(slotType->Clone()); + } else { + var = FEIRBuilder::CreateVarReg(regNum, pty); + } + success = success && (varStack != nullptr); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(var)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(std::move(varStack), std::move(expr)); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpStore(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpSlotOpr &opStore = static_cast(op); + if (opStore.IsAddressOpr()) { + UniqueFEIRVar varTmp = stack2feHelper.PopItem(PTY_a32); + if (varTmp.get() == nullptr) { + success = false; + } + return ans; + } + std::vector stackInTypes = op.GetInputTypesFromStack(); + CHECK_FATAL(stackInTypes.size() == 1, "store op need one stack opnd"); + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[0]); + uint32 regSlot = stack2feHelper.GetRegNumForSlot(opStore.GetSlotIdx()); + const FEIRType *slotType = context.GetSlotType(opStore.GetSlotIdx(), pc); + UniqueFEIRVar varDst; + UniqueFEIRVar varSrc; + if (slotType != nullptr) { + varDst = FEIRBuilder::CreateVarReg(regSlot, slotType->Clone()); + varSrc = stack2feHelper.PopItem(pty); + varSrc->SetType(slotType->Clone()); + } else { + varDst = FEIRBuilder::CreateVarReg(regSlot, pty); + varSrc = stack2feHelper.PopItem(pty); + } + if (varSrc == nullptr) { + success = false; + return ans; + } + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(varSrc)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(std::move(varDst), std::move(expr)); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpArrayLoad(JBCFunctionContext &context, bool &success) const { + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + // Process In + std::vector stackInTypes = op.GetInputTypesFromStack(); + // ArrayLoad need 2 input opnds + CHECK_FATAL(stackInTypes.size() == 2, "invalid in types for ArrayLoad"); + PrimType ptyArray = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[0]); // opnd0: array + PrimType ptyIndex = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[1]); // opnd1: index + UniqueFEIRVar varIndex = stack2feHelper.PopItem(ptyIndex); + UniqueFEIRVar varArray = stack2feHelper.PopItem(ptyArray); + // Process Out + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(); + CHECK_FATAL(stackOutType != jbc::JBCPrimType::kTypeDefault, "invalid out type for ArrayLoad"); + PrimType ptyElem = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackOutType); + UniqueFEIRVar varElem = stack2feHelper.PushItem(ptyElem); + success = true; + return FEIRBuilder::CreateStmtArrayLoad(std::move(varElem), std::move(varArray), std::move(varIndex)); +} + +std::list JBCStmtInst::EmitToFEIRForOpArrayStore(JBCFunctionContext &context, bool &success) const { + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + // Process In + std::vector stackInTypes = op.GetInputTypesFromStack(); + // ArrayStore need 3 input opnds + CHECK_FATAL(stackInTypes.size() == 3, "invalid in types for ArrayStore"); + PrimType ptyArray = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[0]); // opnd0: array + PrimType ptyIndex = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[1]); // opnd1: index + PrimType ptyElem = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[2]); // opnd2: elem + UniqueFEIRVar varElem = stack2feHelper.PopItem(ptyElem); + UniqueFEIRVar varIndex = stack2feHelper.PopItem(ptyIndex); + UniqueFEIRVar varArray = stack2feHelper.PopItem(ptyArray); + success = true; + return FEIRBuilder::CreateStmtArrayStore(std::move(varElem), std::move(varArray), std::move(varIndex)); +} + +std::list JBCStmtInst::EmitToFEIRForOpPop(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + success = stack2feHelper.Pop(op.GetOpcode()); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpDup(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + success = stack2feHelper.Dup(op.GetOpcode()); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpSwap(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + success = stack2feHelper.Swap(); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpMathBinop(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + // obtain in/out types + std::vector stackInTypes = op.GetInputTypesFromStack(); + CHECK_FATAL(stackInTypes.size() == 2, "Not enough input opnds for math binary op"); // 2 : opnds num limit + PrimType pty0 = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[0]); + PrimType pty1 = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[1]); + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(); + PrimType ptyOut = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackOutType); + // stack operation + UniqueFEIRVar var1 = stack2feHelper.PopItem(pty1); + UniqueFEIRVar var0 = stack2feHelper.PopItem(pty0); + UniqueFEIRVar varOut = stack2feHelper.PushItem(ptyOut); + if (var1 == nullptr || var0 == nullptr || varOut == nullptr) { + success = false; + return ans; + } + auto it = opcodeMapForMathBinop.find(op.GetOpcode()); + if (it == opcodeMapForMathBinop.end()) { + success = false; + ERR(kLncErr, "EmitToFEIRForOpMathBinop: unsupport opcode %s", op.GetOpcodeName().c_str()); + return ans; + } + UniqueFEIRExpr expr = FEIRBuilder::CreateExprMathBinary(it->second, std::move(var0), std::move(var1)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(std::move(varOut), std::move(expr)); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpMathUnop(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + // obtain in/out types + std::vector stackInTypes = op.GetInputTypesFromStack(); + ASSERT(stackInTypes.size() == 1, "Not enough input opnds for math unary op"); + PrimType pty0 = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[0]); + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(); + PrimType ptyOut = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackOutType); + // stack operation + UniqueFEIRVar var0 = stack2feHelper.PopItem(pty0); + UniqueFEIRVar varOut = stack2feHelper.PushItem(ptyOut); + if (var0 == nullptr || varOut == nullptr) { + success = false; + return ans; + } + auto it = opcodeMapForMathUnop.find(op.GetOpcode()); + if (it == opcodeMapForMathUnop.end()) { + success = false; + ERR(kLncErr, "EmitToFEIRForOpMathUnop: unsupport opcode %s", op.GetOpcodeName().c_str()); + return ans; + } + UniqueFEIRExpr expr = FEIRBuilder::CreateExprMathUnary(it->second, std::move(var0)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(std::move(varOut), std::move(expr)); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpMathInc(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpMathInc &opInc = static_cast(op); + // no stack operation + uint32 regNum = stack2feHelper.GetRegNumForSlot(opInc.GetIndex()); + UniqueFEIRVar var0 = FEIRBuilder::CreateVarReg(regNum, PTY_i32); + UniqueFEIRVar varOut = var0->Clone(); + UniqueFEIRExpr opnd0 = FEIRBuilder::CreateExprDRead(std::move(var0)); + UniqueFEIRExpr opnd1 = FEIRBuilder::CreateExprConstI32(int32{ opInc.GetIncr() }); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprMathBinary(OP_add, std::move(opnd0), std::move(opnd1)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(std::move(varOut), std::move(expr)); + ans.push_back(std::move(stmt)); + success = true; + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpConvert(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + std::vector stackInTypes = op.GetInputTypesFromStack(); + ASSERT(stackInTypes.size() == 1, "invalid in type for convert"); + PrimType ptyIn = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[0]); + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(); + ASSERT(stackOutType != jbc::JBCPrimType::kTypeDefault, "invalid out type for convert"); + PrimType ptyOut = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackOutType); + UniqueFEIRVar varIn = stack2feHelper.PopItem(ptyIn); + if (varIn == nullptr) { + success = false; + return ans; + } + UniqueFEIRVar varOut = stack2feHelper.PushItem(ptyOut); + if (varOut == nullptr) { + success = false; + return ans; + } + UniqueFEIRExpr expr(nullptr); + uint8 bitSize = 0; + Opcode opExt = OP_sext; + switch (op.GetOpcode()) { + case jbc::kOpI2B: + bitSize = 8; + opExt = OP_sext; + break; + case jbc::kOpI2C: + bitSize = 16; + opExt = OP_zext; + break; + case jbc::kOpI2S: + bitSize = 16; + opExt = OP_sext; + break; + default: + expr = FEIRBuilder::CreateExprCvtPrim(std::move(varIn), ptyOut); + break; + } + if (expr == nullptr) { + expr = (opExt == OP_sext) ? FEIRBuilder::CreateExprSExt(std::move(varIn)) : + FEIRBuilder::CreateExprZExt(std::move(varIn)); + FEIRExprExtractBits *ptrExprExt = static_cast(expr.get()); + ptrExprExt->SetBitSize(bitSize); + } + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(std::move(varOut), std::move(expr)); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpCompare(const JBCFunctionContext &context, bool &success) const { + (void) context; + std::list ans; + success = true; + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpReturn(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + // obtain in/out types + std::vector stackInTypes = op.GetInputTypesFromStack(); + if (op.GetOpcode() == jbc::kOpReturn) { + ASSERT(stackInTypes.empty(), "Not enough input opnds for return op"); + UniqueFEIRStmt stmt = std::make_unique(UniqueFEIRExpr(nullptr)); + ans.push_back(std::move(stmt)); + } else { + ASSERT(stackInTypes.size() == 1, "Not enough input opnds for return op"); + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[0]); + UniqueFEIRVar var = stack2feHelper.PopItem(pty); + if (var == nullptr) { + success = false; + return ans; + } + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(var)); + UniqueFEIRStmt stmt = std::make_unique(std::move(expr)); + ans.push_back(std::move(stmt)); + } + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpStaticFieldOpr(JBCFunctionContext &context, bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpFieldOpr &opField = static_cast(op); + const jbc::JBCConst *constRaw = + constPool.GetConstByIdxWithTag(opField.GetFieldIdx(), jbc::JBCConstTag::kConstFieldRef); + CHECK_NULL_FATAL(constRaw); + const jbc::JBCConstRef *constRef = static_cast(constRaw); + FEStructFieldInfo *fieldInfo = static_cast(constRef->GetFEStructElemInfo()); + CHECK_NULL_FATAL(fieldInfo); + const FEIRType *fieldType = fieldInfo->GetType(); + PrimType pty = fieldType->IsScalar() ? fieldType->GetPrimType() : PTY_ref; + pty = JBCStack2FEHelper::SimplifyPrimType(pty); + if (op.GetOpcode() == jbc::kOpGetStatic) { + UniqueFEIRVar var = stack2feHelper.PushItem(pty); + UniqueFEIRStmt stmt = std::make_unique(nullptr, std::move(var), *fieldInfo, true); + ans.push_back(std::move(stmt)); + } else { + UniqueFEIRVar var = stack2feHelper.PopItem(pty); + UniqueFEIRStmt stmt = std::make_unique(nullptr, std::move(var), *fieldInfo, true); + ans.push_back(std::move(stmt)); + } + success = true; + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpFieldOpr(JBCFunctionContext &context, bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpFieldOpr &opField = static_cast(op); + const jbc::JBCConst *constRaw = + constPool.GetConstByIdxWithTag(opField.GetFieldIdx(), jbc::JBCConstTag::kConstFieldRef); + CHECK_NULL_FATAL(constRaw); + const jbc::JBCConstRef *constRef = static_cast(constRaw); + FEStructFieldInfo *fieldInfo = static_cast(constRef->GetFEStructElemInfo()); + CHECK_NULL_FATAL(fieldInfo); + const FEIRType *fieldType = fieldInfo->GetType(); + PrimType pty = fieldType->IsScalar() ? fieldType->GetPrimType() : PTY_ref; + pty = JBCStack2FEHelper::SimplifyPrimType(pty); + if (op.GetOpcode() == jbc::kOpGetField) { + UniqueFEIRVar varObj = stack2feHelper.PopItem(PTY_ref); + UniqueFEIRVar var = stack2feHelper.PushItem(pty); + UniqueFEIRStmt stmt = std::make_unique(std::move(varObj), std::move(var), *fieldInfo, false); + ans.push_back(std::move(stmt)); + } else { + UniqueFEIRVar var = stack2feHelper.PopItem(pty); + UniqueFEIRVar varObj = stack2feHelper.PopItem(PTY_ref); + UniqueFEIRStmt stmt = std::make_unique(std::move(varObj), std::move(var), *fieldInfo, false); + ans.push_back(std::move(stmt)); + } + success = true; + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpInvoke(JBCFunctionContext &context, bool &success) const { + switch (op.GetOpcode()) { + case jbc::kOpInvokeVirtual: + return EmitToFEIRForOpInvokeVirtual(context, success); + case jbc::kOpInvokeSpecial: + return EmitToFEIRForOpInvokeSpecial(context, success); + case jbc::kOpInvokeStatic: + return EmitToFEIRForOpInvokeStatic(context, success); + case jbc::kOpInvokeInterface: + return EmitToFEIRForOpInvokeInterface(context, success); + case jbc::kOpInvokeDynamic: + return EmitToFEIRForOpInvokeDynamic(context, success); + default: + CHECK_FATAL(false, "unsupported op: %s", op.GetOpcodeName().c_str()); + break; + } + return EmitToFEIRCommon2(context, success); +} + +void JBCStmtInst::PrepareInvokeParametersAndReturn(JBCStack2FEHelper &stack2feHelper, + const FEStructMethodInfo &info, + FEIRStmtCallAssign &callStmt, + bool isStatic) const { + const MapleVector &argTypes = info.GetArgTypes(); + for (size_t i = argTypes.size(); i > 0; --i) { + const FEIRType *argType = argTypes[static_cast(i - 1)]; + PrimType pty = argType->GetPrimType(); + UniqueFEIRVar var = stack2feHelper.PopItem(JBCStack2FEHelper::SimplifyPrimType(pty)); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(var)); + callStmt.AddExprArgReverse(std::move(expr)); + } + if (!isStatic) { + // push this + const FEIRType *thisType = info.GetOwnerType(); + PrimType pty = thisType->GetPrimType(); + UniqueFEIRVar var = stack2feHelper.PopItem(JBCStack2FEHelper::SimplifyPrimType(pty)); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(var)); + callStmt.AddExprArgReverse(std::move(expr)); + } + if (!info.IsReturnVoid()) { + const FEIRType *retType = info.GetReturnType(); + PrimType pty = retType->GetPrimType(); + UniqueFEIRVar var = stack2feHelper.PushItem(JBCStack2FEHelper::SimplifyPrimType(pty)); + callStmt.SetVar(std::move(var)); + } +} + +std::list JBCStmtInst::EmitToFEIRForOpInvokeVirtual(JBCFunctionContext &context, bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpInvoke &opInvoke = static_cast(op); + const jbc::JBCConst *constRaw = constPool.GetConstByIdx(opInvoke.GetMethodIdx()); + if (constRaw == nullptr || + (constRaw->GetTag() != jbc::JBCConstTag::kConstMethodRef && + constRaw->GetTag() != jbc::JBCConstTag::kConstInterfaceMethodRef)) { + success = false; + return ans; + } + const jbc::JBCConstRef *constRef = static_cast(constRaw); + FEStructMethodInfo *methodInfo = static_cast(constRef->GetFEStructElemInfo()); + UniqueFEIRStmt stmt = std::make_unique(*methodInfo, OP_virtualcall, nullptr, false); + FEIRStmtCallAssign *ptrStmt = static_cast(stmt.get()); + PrepareInvokeParametersAndReturn(stack2feHelper, *methodInfo, *ptrStmt, false); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpInvokeStatic(JBCFunctionContext &context, bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpInvoke &opInvoke = static_cast(op); + const jbc::JBCConst *constRaw = constPool.GetConstByIdx(opInvoke.GetMethodIdx()); + if (constRaw == nullptr || + (constRaw->GetTag() != jbc::JBCConstTag::kConstMethodRef && + constRaw->GetTag() != jbc::JBCConstTag::kConstInterfaceMethodRef)) { + success = false; + return ans; + } + const jbc::JBCConstRef *constRef = static_cast(constRaw); + FEStructMethodInfo *methodInfo = static_cast(constRef->GetFEStructElemInfo()); + UniqueFEIRStmt stmt = std::make_unique(*methodInfo, OP_call, nullptr, true); + FEIRStmtCallAssign *ptrStmt = static_cast(stmt.get()); + PrepareInvokeParametersAndReturn(stack2feHelper, *methodInfo, *ptrStmt, true); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpInvokeInterface(JBCFunctionContext &context, + bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpInvoke &opInvoke = static_cast(op); + const jbc::JBCConst *constRaw = constPool.GetConstByIdx(opInvoke.GetMethodIdx()); + if (constRaw == nullptr || + (constRaw->GetTag() != jbc::JBCConstTag::kConstMethodRef && + constRaw->GetTag() != jbc::JBCConstTag::kConstInterfaceMethodRef)) { + success = false; + return ans; + } + const jbc::JBCConstRef *constRef = static_cast(constRaw); + FEStructMethodInfo *methodInfo = static_cast(constRef->GetFEStructElemInfo()); + UniqueFEIRStmt stmt = std::make_unique(*methodInfo, OP_interfacecall, nullptr, false); + FEIRStmtCallAssign *ptrStmt = static_cast(stmt.get()); + PrepareInvokeParametersAndReturn(stack2feHelper, *methodInfo, *ptrStmt, false); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpInvokeSpecial(JBCFunctionContext &context, bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpInvoke &opInvoke = static_cast(op); + const jbc::JBCConst *constRaw = constPool.GetConstByIdx(opInvoke.GetMethodIdx()); + if (constRaw == nullptr || + (constRaw->GetTag() != jbc::JBCConstTag::kConstMethodRef && + constRaw->GetTag() != jbc::JBCConstTag::kConstInterfaceMethodRef)) { + success = false; + return ans; + } + const jbc::JBCConstRef *constRef = static_cast(constRaw); + FEStructMethodInfo *methodInfo = static_cast(constRef->GetFEStructElemInfo()); + Opcode mirOp = methodInfo->IsConstructor() ? OP_call : OP_superclasscall; + UniqueFEIRStmt stmt = std::make_unique(*methodInfo, mirOp, nullptr, false); + FEIRStmtCallAssign *ptrStmt = static_cast(stmt.get()); + PrepareInvokeParametersAndReturn(stack2feHelper, *methodInfo, *ptrStmt, false); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpInvokeDynamic(JBCFunctionContext &context, bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpInvoke &opInvoke = static_cast(op); + const jbc::JBCConst *constRaw = constPool.GetConstByIdx(opInvoke.GetMethodIdx()); + if (constRaw == nullptr || constRaw->GetTag() != jbc::JBCConstTag::kConstInvokeDynamic) { + success = false; + return ans; + } + const jbc::JBCConstInvokeDynamic *constDynamic = static_cast(constRaw); + FEStructMethodInfo *methodInfo = static_cast(constDynamic->GetFEStructElemInfo()); + UniqueFEIRStmt stmt = std::make_unique(*methodInfo, OP_call, nullptr, true); + FEIRStmtCallAssign *ptrStmt = static_cast(stmt.get()); + PrepareInvokeParametersAndReturn(stack2feHelper, *methodInfo, *ptrStmt, true); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpNew(JBCFunctionContext &context, bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpNew &opNew = static_cast(op); + UniqueFEIRType type = opNew.GetFEIRType(constPool)->Clone(); + UniqueFEIRExpr expr(nullptr); + switch (op.GetOpcode()) { + case jbc::kOpNew: { + expr = FEIRBuilder::CreateExprJavaNewInstance(type->Clone()); + break; + } + case jbc::kOpNewArray: + case jbc::kOpANewArray: { + UniqueFEIRVar varSize = stack2feHelper.PopItem(PTY_i32); + if (varSize == nullptr) { + success = false; + return ans; + } + (void)type->ArrayIncrDim(); + UniqueFEIRExpr exprSize = FEIRBuilder::CreateExprDRead(std::move(varSize)); + expr = FEIRBuilder::CreateExprJavaNewArray(type->Clone(), std::move(exprSize)); + break; + } + default: + FATAL(kLncFatal, "should not run here"); + return ans; + } + UniqueFEIRVar varDst = stack2feHelper.PushItem(PTY_ref); + if (varDst == nullptr || expr == nullptr) { + success = false; + return ans; + } + varDst->SetType(std::move(type)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(std::move(varDst), std::move(expr), true); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpMultiANewArray(JBCFunctionContext &context, bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCOpMultiANewArray &opArray = static_cast(op); + const jbc::JBCConst *constRaw = constPool.GetConstByIdxWithTag(opArray.GetRefTypeIdx(), + jbc::JBCConstTag::kConstClass); + if (constRaw == nullptr) { + success = false; + return ans; + } + const jbc::JBCConstClass *constClass = static_cast(constRaw); + UniqueFEIRStmt stmt = std::make_unique(nullptr, constClass->GetFEIRType()->Clone(), + nullptr); + std::vector stackInTypes = op.GetInputTypesFromStack(constPool); + std::reverse(stackInTypes.begin(), stackInTypes.end()); + FEIRStmtJavaMultiANewArray *javaMultiANewArray = static_cast(stmt.get()); + for (jbc::JBCPrimType popType : stackInTypes) { + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(popType); + UniqueFEIRVar var = stack2feHelper.PopItem(pty); + if (var == nullptr) { + success = false; + return ans; + } + javaMultiANewArray->AddVarSizeRev(std::move(var)); + } + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(constPool); + if (stackOutType == jbc::JBCPrimType::kTypeDefault) { + success = false; + return ans; + } + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackOutType); + UniqueFEIRVar varRet = stack2feHelper.PushItem(pty); + javaMultiANewArray->SetArrayType(varRet->GetType()->Clone()); + javaMultiANewArray->SetVar(std::move(varRet)); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpThrow(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + // obtain in/out types + std::vector stackInTypes = op.GetInputTypesFromStack(); + ASSERT(stackInTypes.size() == 1, "Not enough input opnds for return op"); + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackInTypes[0]); + UniqueFEIRVar var = stack2feHelper.PopItem(pty); + if (var == nullptr) { + success = false; + return ans; + } + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(var)); + UniqueFEIRStmt stmt = std::make_unique(OP_throw, std::move(expr)); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpTypeCheck(JBCFunctionContext &context, bool &success) const { + std::list ans; + const jbc::JBCConstPool &constPool = context.GetConstPool(); + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + jbc::JBCOpcode opcode = op.GetOpcode(); + const jbc::JBCOpTypeCheck &opTypeCheck = static_cast(op); + PrimType ptyIn = PTY_ref; + PrimType ptyOut = (opcode == jbc::kOpCheckCast) ? PTY_ref : PTY_i32; + UniqueFEIRVar varIn = stack2feHelper.PopItem(ptyIn); + UniqueFEIRVar varOut = stack2feHelper.PushItem(ptyOut); + uint16 constIdx = opTypeCheck.GetTypeIdx(); + const jbc::JBCConst *constRaw = constPool.GetConstByIdxWithTag(constIdx, jbc::JBCConstTag::kConstClass); + if (constRaw == nullptr) { + success = false; + return ans; + } + const jbc::JBCConstClass *constClass = static_cast(constRaw); + UniqueFEIRType type = constClass->GetFEIRType()->Clone(); + if (opcode == jbc::kOpCheckCast) { + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtJavaCheckCast(std::move(varOut), std::move(varIn), std::move(type)); + ans.push_back(std::move(stmt)); + } else { + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtJavaInstanceOf(std::move(varOut), std::move(varIn), std::move(type)); + ans.push_back(std::move(stmt)); + } + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpMonitor(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + // stack operation + UniqueFEIRVar var = stack2feHelper.PopItem(PTY_ref); + if (var == nullptr) { + success = false; + return ans; + } + auto it = opcodeMapForMonitor.find(op.GetOpcode()); + if (it == opcodeMapForMonitor.end()) { + success = false; + ERR(kLncErr, "EmitToFEIRForOpMathUnop: unsupport opcode %s", op.GetOpcodeName().c_str()); + return ans; + } + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(var)); + UniqueFEIRStmt stmt = std::make_unique(it->second, std::move(expr)); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRForOpArrayLength(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + // stack operation + // in + UniqueFEIRVar varArray = stack2feHelper.PopItem(PTY_ref); + if (varArray == nullptr) { + success = false; + return ans; + } + // out + UniqueFEIRVar varDst = stack2feHelper.PushItem(PTY_i32); + if (varDst == nullptr) { + success = false; + return ans; + } + UniqueFEIRExpr exprArray = FEIRBuilder::CreateExprDRead(std::move(varArray)); + UniqueFEIRExpr exprArrayLength = FEIRBuilder::CreateExprJavaArrayLength(std::move(exprArray)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(std::move(varDst), std::move(exprArrayLength), true); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInst::EmitToFEIRCommon(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + std::vector stackInTypes = op.GetInputTypesFromStack(); + std::reverse(stackInTypes.begin(), stackInTypes.end()); + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(); + for (jbc::JBCPrimType popType : stackInTypes) { + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(popType); + UniqueFEIRVar var = stack2feHelper.PopItem(pty); + if (var == nullptr) { + success = false; + break; + } + } + if (success && stackOutType != jbc::JBCPrimType::kTypeDefault) { + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackOutType); + UniqueFEIRVar var = stack2feHelper.PushItem(pty); + if (var == nullptr) { + success = false; + } + } + return ans; +} + +std::list JBCStmtInst::EmitToFEIRCommon2(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const jbc::JBCConstPool &constPool = context.GetConstPool(); + std::vector stackInTypes = op.GetInputTypesFromStack(constPool); + std::reverse(stackInTypes.begin(), stackInTypes.end()); + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(constPool); + for (jbc::JBCPrimType popType : stackInTypes) { + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(popType); + UniqueFEIRVar var = stack2feHelper.PopItem(pty); + if (var == nullptr) { + success = false; + break; + } + } + if (success && stackOutType != jbc::JBCPrimType::kTypeDefault) { + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackOutType); + UniqueFEIRVar var = stack2feHelper.PushItem(pty); + if (var == nullptr) { + success = false; + } + } + return ans; +} + +UniqueFEIRStmt JBCStmtInst::GenerateStmtForConstI32(JBCStack2FEHelper &stack2feHelper, int32 val, bool &success) const { + UniqueFEIRExpr exprConst = FEIRBuilder::CreateExprConstI32(val); + UniqueFEIRVar varDst = stack2feHelper.PushItem(PTY_i32); + if (varDst == nullptr) { + success = false; + return UniqueFEIRStmt(nullptr); + } + UniqueFEIRStmt stmtDAssign = FEIRBuilder::CreateStmtDAssign(std::move(varDst), std::move(exprConst)); + return stmtDAssign; +} + +UniqueFEIRStmt JBCStmtInst::GenerateStmtForConstI64(JBCStack2FEHelper &stack2feHelper, int64 val, bool &success) const { + UniqueFEIRExpr exprConst = FEIRBuilder::CreateExprConstI64(val); + UniqueFEIRVar varDst = stack2feHelper.PushItem(PTY_i64); + if (varDst == nullptr) { + success = false; + return UniqueFEIRStmt(nullptr); + } + UniqueFEIRStmt stmtDAssign = FEIRBuilder::CreateStmtDAssign(std::move(varDst), std::move(exprConst)); + return stmtDAssign; +} + +UniqueFEIRStmt JBCStmtInst::GenerateStmtForConstF32(JBCStack2FEHelper &stack2feHelper, float val, bool &success) const { + UniqueFEIRExpr exprConst = FEIRBuilder::CreateExprConstF32(val); + UniqueFEIRVar varDst = stack2feHelper.PushItem(PTY_f32); + if (varDst == nullptr) { + success = false; + return UniqueFEIRStmt(nullptr); + } + UniqueFEIRStmt stmtDAssign = FEIRBuilder::CreateStmtDAssign(std::move(varDst), std::move(exprConst)); + return stmtDAssign; +} + +UniqueFEIRStmt JBCStmtInst::GenerateStmtForConstF64(JBCStack2FEHelper &stack2feHelper, double val, + bool &success) const { + UniqueFEIRExpr exprConst = FEIRBuilder::CreateExprConstF64(val); + UniqueFEIRVar varDst = stack2feHelper.PushItem(PTY_f64); + if (varDst == nullptr) { + success = false; + return UniqueFEIRStmt(nullptr); + } + UniqueFEIRStmt stmtDAssign = FEIRBuilder::CreateStmtDAssign(std::move(varDst), std::move(exprConst)); + return stmtDAssign; +} + +// ---------- JBCStmtInstBranch ---------- +std::map> JBCStmtInstBranch::opcodeMapForCondGoto = + JBCStmtInstBranch::InitOpcodeMapForCondGoto(); + +std::map JBCStmtInstBranch::funcPtrMapForEmitToFEIR = + JBCStmtInstBranch::InitFuncPtrMapForEmitToFEIR(); + +JBCStmtInstBranch::JBCStmtInstBranch(const jbc::JBCOp &argOp) + : JBCStmt(kStmtPesudo, kJBCStmtInstBranch), + op(argOp) { + SetFallThru(op.IsFallThru()); +} + +bool JBCStmtInstBranch::IsStmtInstImpl() const { + return true; +} + +void JBCStmtInstBranch::DumpImpl(const std::string &prefix) const { + std::cout << prefix << "JBCStmtInstBranch (id=" << id << ", " << + "kind=" << JBCStmtKindHelper::JBCStmtKindName(JBCkind) << ", " << + "op=" << op.GetOpcodeName() << ", " << + "targets={"; + for (FEIRStmt *stmt : extraSuccs) { + std::cout << stmt->GetID() << " "; + } + std::cout << "})" << std::endl; +} + +std::string JBCStmtInstBranch::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << op.GetOpcodeName(); + return ss.str(); +} + +std::list JBCStmtInstBranch::EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const { + auto it = funcPtrMapForEmitToFEIR.find(op.GetOpcodeKind()); + if (it != funcPtrMapForEmitToFEIR.end()) { + return (this->*(it->second))(context, success); + } else { + return EmitToFEIRCommon(context, success); + } +} + +JBCStmtPesudoLabel *JBCStmtInstBranch::GetTarget(const std::map &mapPCStmtLabel, + uint32 pc) const { + auto itTarget = mapPCStmtLabel.find(pc); + if (itTarget == mapPCStmtLabel.end()) { + ERR(kLncErr, "target@pc=%u not found", pc); + return nullptr; + } + return itTarget->second; +} + +std::map JBCStmtInstBranch::InitFuncPtrMapForEmitToFEIR() { + std::map ans; + ans[jbc::JBCOpcodeKind::kOpKindGoto] = &JBCStmtInstBranch::EmitToFEIRForOpGoto; + ans[jbc::JBCOpcodeKind::kOpKindBranch] = &JBCStmtInstBranch::EmitToFEIRForOpBranch; + ans[jbc::JBCOpcodeKind::kOpKindSwitch] = &JBCStmtInstBranch::EmitToFEIRForOpSwitch; + ans[jbc::JBCOpcodeKind::kOpKindJsr] = &JBCStmtInstBranch::EmitToFEIRForOpJsr; + ans[jbc::JBCOpcodeKind::kOpKindRet] = &JBCStmtInstBranch::EmitToFEIRForOpRet; + return ans; +} + +std::list JBCStmtInstBranch::EmitToFEIRForOpGoto(JBCFunctionContext &context, bool &success) const { + std::list ans; + const std::map &mapPCStmtLabel = context.GetMapPCLabelStmt(); + const jbc::JBCOpGoto &opGoto = static_cast(op); + auto it = mapPCStmtLabel.find(opGoto.GetTarget()); + if (it == mapPCStmtLabel.end()) { + ERR(kLncErr, "target not found for inst branch"); + success = false; + } else { + JBCStmtPesudoLabel *stmtLabel = it->second; + CHECK_NULL_FATAL(stmtLabel); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtGoto(stmtLabel->GetLabelIdx()); + ans.push_back(std::move(stmt)); + } + return ans; +} + +std::list JBCStmtInstBranch::EmitToFEIRForOpBranch(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const std::map &mapPCStmtLabel = context.GetMapPCLabelStmt(); + const jbc::JBCOpBranch &opBranch = static_cast(op); + auto itTarget = mapPCStmtLabel.find(opBranch.GetTarget()); + if (itTarget == mapPCStmtLabel.end()) { + ERR(kLncErr, "target not found for inst branch"); + success = false; + return ans; + } + JBCStmtPesudoLabel *stmtLabel = itTarget->second; + CHECK_NULL_FATAL(stmtLabel); + auto it = opcodeMapForCondGoto.find(op.GetOpcode()); + if (it == opcodeMapForCondGoto.end()) { + ERR(kLncErr, "unsupport opcode %s", op.GetOpcodeName().c_str()); + success = false; + return ans; + } + Opcode opStmt = std::get<0>(it->second); + Opcode opCompExpr = std::get<1>(it->second); + uint8 mode = std::get<2>(it->second); + // opnds + UniqueFEIRExpr expr0; + UniqueFEIRExpr expr1; + PrimType pty = ((mode & kModeUseRef) == 0) ? PTY_i32 : PTY_ref; + if ((mode & kModeUseZeroAsSecondOpnd) == 0) { + UniqueFEIRVar var1 = stack2feHelper.PopItem(pty); + if (var1 == nullptr) { + success = false; + return ans; + } + expr1 = FEIRBuilder::CreateExprDRead(std::move(var1)); + } else { + expr1 = (pty == PTY_ref) ? FEIRBuilder::CreateExprConstRefNull() : FEIRBuilder::CreateExprConstI32(0); + } + UniqueFEIRVar var0 = stack2feHelper.PopItem(pty); + if (var0 == nullptr) { + success = false; + return ans; + } + expr0 = FEIRBuilder::CreateExprDRead(std::move(var0)); + UniqueFEIRExpr exprComp = FEIRBuilder::CreateExprMathBinary(opCompExpr, std::move(expr0), std::move(expr1)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtCondGoto(stmtLabel->GetLabelIdx(), opStmt, std::move(exprComp)); + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInstBranch::EmitToFEIRForOpSwitch(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const std::map &mapPCStmtLabel = context.GetMapPCLabelStmt(); + const jbc::JBCOpSwitch &opSwitch = static_cast(op); + UniqueFEIRVar var = stack2feHelper.PopItem(PTY_i32); + if (var == nullptr) { + success = false; + return ans; + } + UniqueFEIRExpr exprValue = FEIRBuilder::CreateExprDRead(std::move(var)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtSwitch(std::move(exprValue)); + FEIRStmtSwitch *ptrStmtSwitch = static_cast(stmt.get()); + CHECK_NULL_FATAL(ptrStmtSwitch); + // default target + auto itTargetDefault = mapPCStmtLabel.find(opSwitch.GetDefaultTarget()); + if (itTargetDefault == mapPCStmtLabel.end()) { + ERR(kLncErr, "target not found for inst switch"); + success = false; + return ans; + } + CHECK_NULL_FATAL(itTargetDefault->second); + ptrStmtSwitch->SetDefaultLabelIdx(itTargetDefault->second->GetLabelIdx()); + // value targets + for (const auto &itItem : opSwitch.GetTargets()) { + auto itTarget = mapPCStmtLabel.find(itItem.second); + if (itTarget == mapPCStmtLabel.end()) { + ERR(kLncErr, "target not found for inst switch"); + success = false; + return ans; + } + CHECK_NULL_FATAL(itTarget->second); + ptrStmtSwitch->AddTarget(itItem.first, itTarget->second->GetLabelIdx()); + } + ans.push_back(std::move(stmt)); + return ans; +} + +std::list JBCStmtInstBranch::EmitToFEIRForOpJsr(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + const std::map &mapPCStmtLabel = context.GetMapPCLabelStmt(); + const jbc::JBCOpJsr &opJsr = static_cast(op); + auto itTarget = mapPCStmtLabel.find(opJsr.GetTarget()); + if (itTarget == mapPCStmtLabel.end()) { + ERR(kLncErr, "target not found for inst jsr"); + success = false; + return ans; + } + JBCStmtPesudoLabel *stmtLabel = itTarget->second; + CHECK_NULL_FATAL(stmtLabel); + uint32 slotRegNum = stack2feHelper.GetRegNumForSlot(opJsr.GetSlotIdx()); + UniqueFEIRVar var = FEIRBuilder::CreateVarReg(slotRegNum, PTY_i32, false); + (void)stack2feHelper.PushItem(var->Clone(), PTY_a32); + UniqueFEIRExpr exprConst = FEIRBuilder::CreateExprConstI32(opJsr.GetJsrID()); + UniqueFEIRStmt stmtJsr = FEIRBuilder::CreateStmtDAssign(std::move(var), std::move(exprConst)); + UniqueFEIRStmt stmtGoto = FEIRBuilder::CreateStmtGoto(stmtLabel->GetLabelIdx()); + ans.push_back(std::move(stmtJsr)); + ans.push_back(std::move(stmtGoto)); + return ans; +} + +std::list JBCStmtInstBranch::EmitToFEIRForOpRet(JBCFunctionContext &context, bool &success) const { + return EmitToFEIRForOpRetImpl(context, success); +} + +std::list JBCStmtInstBranch::EmitToFEIRCommon(JBCFunctionContext &context, bool &success) const { + std::list ans; + JBCStack2FEHelper &stack2feHelper = context.GetStack2FEHelper(); + std::vector stackInTypes = op.GetInputTypesFromStack(); + std::reverse(stackInTypes.begin(), stackInTypes.end()); + jbc::JBCPrimType stackOutType = op.GetOutputTypesToStack(); + for (jbc::JBCPrimType popType : stackInTypes) { + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(popType); + UniqueFEIRVar var = stack2feHelper.PopItem(pty); + if (var == nullptr) { + success = false; + break; + } + } + if (success && stackOutType != jbc::JBCPrimType::kTypeDefault) { + PrimType pty = JBCStack2FEHelper::JBCStackItemTypeToPrimType(stackOutType); + UniqueFEIRVar var = stack2feHelper.PushItem(pty); + if (var == nullptr) { + success = false; + } + } + return ans; +} + +std::map> JBCStmtInstBranch::InitOpcodeMapForCondGoto() { + std::map> ans; + ans[jbc::kOpIfeq] = std::make_tuple(OP_brtrue, OP_eq, kModeUseZeroAsSecondOpnd); + ans[jbc::kOpIfne] = std::make_tuple(OP_brfalse, OP_eq, kModeUseZeroAsSecondOpnd); + ans[jbc::kOpIflt] = std::make_tuple(OP_brtrue, OP_lt, kModeUseZeroAsSecondOpnd); + ans[jbc::kOpIfge] = std::make_tuple(OP_brtrue, OP_ge, kModeUseZeroAsSecondOpnd); + ans[jbc::kOpIfgt] = std::make_tuple(OP_brtrue, OP_gt, kModeUseZeroAsSecondOpnd); + ans[jbc::kOpIfle] = std::make_tuple(OP_brtrue, OP_le, kModeUseZeroAsSecondOpnd); + ans[jbc::kOpIfICmpeq] = std::make_tuple(OP_brtrue, OP_eq, kModeDefault); + ans[jbc::kOpIfICmpne] = std::make_tuple(OP_brfalse, OP_eq, kModeDefault); + ans[jbc::kOpIfICmplt] = std::make_tuple(OP_brtrue, OP_lt, kModeDefault); + ans[jbc::kOpIfICmpge] = std::make_tuple(OP_brtrue, OP_ge, kModeDefault); + ans[jbc::kOpIfICmpgt] = std::make_tuple(OP_brtrue, OP_gt, kModeDefault); + ans[jbc::kOpIfICmple] = std::make_tuple(OP_brtrue, OP_le, kModeDefault); + ans[jbc::kOpIfACmpeq] = std::make_tuple(OP_brtrue, OP_eq, kModeUseRef); + ans[jbc::kOpIfACmpne] = std::make_tuple(OP_brfalse, OP_eq, kModeUseRef); + ans[jbc::kOpIfNull] = std::make_tuple(OP_brtrue, OP_eq, kModeUseRef | kModeUseZeroAsSecondOpnd); + ans[jbc::kOpIfNonNull] = std::make_tuple(OP_brfalse, OP_eq, kModeUseRef | kModeUseZeroAsSecondOpnd); + return ans; +} + +// ---------- JBCStmtInstBranchRet ---------- +JBCStmtInstBranchRet::JBCStmtInstBranchRet(const jbc::JBCOp &argOp) + : JBCStmtInstBranch(argOp) { + JBCkind = kJBCStmtInstBranchRet; +} + +std::list JBCStmtInstBranchRet::EmitToFEIRForOpRetImpl(JBCFunctionContext &context, + bool &success) const { + std::list ans; + const std::map &mapPCStmtLabel = context.GetMapPCLabelStmt(); + const std::map> &mapJsrSlotRetAddr = context.GetMapJsrSlotRetAddr(); + const jbc::JBCOpRet &opRet = static_cast(op); + uint16 slotIdx = opRet.GetIndex(); + auto itJsrInfo = mapJsrSlotRetAddr.find(slotIdx); + if (itJsrInfo == mapJsrSlotRetAddr.end()) { + WARN(kLncWarn, "jsr info not found"); + success = false; + return ans; + } + const std::map &jsrInfo = itJsrInfo->second; + if (jsrInfo.size() == 1) { + auto itInfo = jsrInfo.begin(); + JBCStmtPesudoLabel *stmtLabel = GetTarget(mapPCStmtLabel, itInfo->second); + if (stmtLabel == nullptr) { + success = false; + return ans; + } + UniqueFEIRStmt stmtGoto = FEIRBuilder::CreateStmtGoto(stmtLabel->GetLabelIdx()); + ans.push_back(std::move(stmtGoto)); + } else { + uint32 idx = 0; + UniqueFEIRVar var = FEIRBuilder::CreateVarReg(slotIdx, PTY_i32); + UniqueFEIRExpr exprValue = FEIRBuilder::CreateExprDRead(std::move(var)); + UniqueFEIRStmt stmtSwitch = FEIRBuilder::CreateStmtSwitch(std::move(exprValue)); + FEIRStmtSwitch *ptrStmtSwitch = static_cast(stmtSwitch.get()); + for (auto itInfo : jsrInfo) { + JBCStmtPesudoLabel *stmtLabel = GetTarget(mapPCStmtLabel, itInfo.second); + if (stmtLabel == nullptr) { + success = false; + return ans; + } + if (idx == jsrInfo.size() - 1) { + ptrStmtSwitch->SetDefaultLabelIdx(stmtLabel->GetLabelIdx()); + } else { + ptrStmtSwitch->AddTarget(itInfo.first, stmtLabel->GetLabelIdx()); + } + ++idx; + } + ans.push_back(std::move(stmtSwitch)); + } + return ans; +} + +// ---------- JBCStmtPesudoLabel ---------- +void JBCStmtPesudoLabel::DumpImpl(const std::string &prefix) const { + std::cout << prefix << "JBCStmtPesudoLabel (id=" << id << "," << + "kind=" << JBCStmtKindHelper::JBCStmtKindName(JBCkind) << ", " << + "preds={"; + for (FEIRStmt *stmt : extraPreds) { + std::cout << stmt->GetID() << " "; + } + std::cout << "})" << std::endl; +} + +std::string JBCStmtPesudoLabel::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": label" << labelIdx; + return ss.str(); +} + +std::list JBCStmtPesudoLabel::EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const { + (void) context; + std::list ans; + UniqueFEIRStmt stmt = std::make_unique(labelIdx); + ans.push_back(std::move(stmt)); + success = true; + return ans; +} + +// ---------- JBCStmtPesudoCatch ---------- +void JBCStmtPesudoCatch::DumpImpl(const std::string &prefix) const { + std::cout << prefix << "JBCStmtPesudoCatch (id=" << id << "," << + "kind=" << JBCStmtKindHelper::JBCStmtKindName(JBCkind) << ", " << + "preds={"; + for (FEIRStmt *stmt : extraPreds) { + std::cout << stmt->GetID() << " "; + } + std::cout << "})" << std::endl; +} + +std::string JBCStmtPesudoCatch::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": catch" << labelIdx; + return ss.str(); +} + +std::list JBCStmtPesudoCatch::EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const { + (void) context; + std::list ans; + UniqueFEIRStmt stmt = std::make_unique(labelIdx); + FEIRStmtPesudoCatch *feirStmt = static_cast(stmt.get()); + for (GStrIdx typeNameIdx : catchTypeNames) { + feirStmt->AddCatchTypeNameIdx(typeNameIdx); + } + ans.push_back(std::move(stmt)); + success = true; + return ans; +} + +// ---------- JBCStmtPesudoTry ---------- +void JBCStmtPesudoTry::DumpImpl(const std::string &prefix) const { + std::cout << prefix << "JBCStmtPesudoTry (id=" << id << "," << + "kind=" << JBCStmtKindHelper::JBCStmtKindName(JBCkind) << ", " << + "succs={"; + for (JBCStmtPesudoCatch *stmt : catchStmts) { + std::cout << stmt->GetID() << " "; + } + std::cout << "})" << std::endl; +} + +std::string JBCStmtPesudoTry::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": try"; + return ss.str(); +} + +std::list JBCStmtPesudoTry::EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const { + (void) context; + std::list ans; + UniqueFEIRStmt stmt = std::make_unique(); + FEIRStmtPesudoJavaTry *feirStmt = static_cast(stmt.get()); + for (JBCStmtPesudoCatch *stmtCatch : catchStmts) { + feirStmt->AddCatchLabelIdx(stmtCatch->GetLabelIdx()); + } + ans.push_back(std::move(stmt)); + success = true; + return ans; +} + +// ---------- JBCStmtPesudoEndTry ---------- +void JBCStmtPesudoEndTry::DumpImpl(const std::string &prefix) const { + std::cout << prefix << "JBCStmtPesudoEndTry (id=" << id << ", " << + "kind=" << JBCStmtKindHelper::JBCStmtKindName(JBCkind) << + ")" << std::endl; +} + +std::string JBCStmtPesudoEndTry::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": endtry"; + return ss.str(); +} + +std::list JBCStmtPesudoEndTry::EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const { + (void) context; + std::list ans; + UniqueFEIRStmt stmt = std::make_unique(); + ans.push_back(std::move(stmt)); + success = true; + return ans; +} + +// ---------- JBCStmtPesudoComment ---------- +void JBCStmtPesudoComment::DumpImpl(const std::string &prefix) const { + (void) prefix; +} + +std::string JBCStmtPesudoComment::DumpDotStringImpl() const { + return ""; +} + +std::list JBCStmtPesudoComment::EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const { + (void) context; + std::list ans; + UniqueFEIRStmt stmt = std::make_unique(content); + ans.push_back(std::move(stmt)); + success = true; + return ans; +} + +// ---------- JBCStmtPesudoLOC ---------- +void JBCStmtPesudoLOC::DumpImpl(const std::string &prefix) const { + std::cout << prefix << "LOC " << srcFileIdx << " " << lineNumber << std::endl; +} + +std::string JBCStmtPesudoLOC::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": LOC " << srcFileIdx << " " << lineNumber; + return ss.str(); +} + +std::list JBCStmtPesudoLOC::EmitToFEIRImpl(JBCFunctionContext &context, bool &success) const { + (void) context; + std::list ans; + UniqueFEIRStmt stmt = std::make_unique(srcFileIdx, lineNumber); + ans.push_back(std::move(stmt)); + success = true; + return ans; +} +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/class/src/jbc_util.cpp b/src/hir2mpl/bytecode_input/class/src/jbc_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fff2612fecea2fc3f2fd38e5d5b2ed29421cd3cf --- /dev/null +++ b/src/hir2mpl/bytecode_input/class/src/jbc_util.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "jbc_util.h" +#include "mpl_logging.h" + +namespace maple { +namespace jbc { +std::string JBCUtil::ClassInternalNameToFullName(const std::string &name) { + if (name[0] == '[') { + return name; + } else { + return "L" + name + ";"; + } +} + +std::vector JBCUtil::SolveMethodSignature(const std::string &signature) { + std::vector ans; + size_t pos1 = signature.find('('); + size_t pos2 = signature.find(')'); + if (pos1 == std::string::npos || pos2 == std::string::npos || pos1 > pos2) { + CHECK_FATAL(false, "invalid method signature %s", signature.c_str()); + } + std::string paramTypeNames = signature.substr(pos1 + 1, pos2 - pos1 - 1); + std::string retTypeName = signature.substr(pos2 + 1); + ans.push_back(retTypeName); + while (paramTypeNames.length() > 0) { + std::string typeName = SolveParamName(paramTypeNames); + ans.push_back(typeName); + paramTypeNames = paramTypeNames.substr(typeName.length()); + } + return ans; +} + +std::string JBCUtil::SolveParamName(const std::string &signature) { + if (signature.empty()) { + return ""; + } + char c = signature[0]; + switch (c) { + case '[': + return "[" + SolveParamName(signature.substr(1)); + case 'L': { + size_t pos = signature.find(';'); + CHECK_FATAL(pos != std::string::npos, "invalid type %s", signature.c_str()); + return signature.substr(0, pos + 1); + } + default: { + std::string ans = ""; + ans.push_back(c); + return ans; + } + } +} + +JBCPrimType JBCUtil::GetPrimTypeForName(const std::string &name) { + switch (name[0]) { + case '[': + case 'L': + return kTypeRef; + case 'I': + return kTypeInt; + case 'J': + return kTypeLong; + case 'F': + return kTypeFloat; + case 'D': + return kTypeDouble; + case 'B': + return kTypeByteOrBoolean; + case 'Z': + return kTypeByteOrBoolean; + case 'C': + return kTypeChar; + case 'S': + return kTypeShort; + case 'V': + return kTypeDefault; + default: + CHECK_FATAL(false, "Unsupported type name %s", name.c_str()); + } + return kTypeDefault; +} +} // namespace jbc +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/ark_annotation_map.h b/src/hir2mpl/bytecode_input/common/include/ark_annotation_map.h new file mode 100644 index 0000000000000000000000000000000000000000..291b0d548ac44bcdd294c4ae8b726a6c44751a7a --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/ark_annotation_map.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_ARK_ANNOTATION_MAP_H +#define HIR2MPL_BC_INPUT_INCLUDE_ARK_ANNOTATION_MAP_H +#include +#include "global_tables.h" + +namespace maple { +namespace bc { +class ArkAnnotationMap { + public: + inline static ArkAnnotationMap &GetArkAnnotationMap() { + return annotationMap; + } + + void Init(); + const std::string &GetAnnotationTypeName(const std::string &orinName); + const std::set &GetArkAnnotationTypeNames() const { + return arkAnnotationTypeNames; + } + + private: + ArkAnnotationMap() = default; + ~ArkAnnotationMap() = default; + + static ArkAnnotationMap annotationMap; + std::map pragmaTypeNameMap; + std::set arkAnnotationTypeNames; +}; +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_ARK_ANNOTATION_MAP_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/ark_annotation_processor.h b/src/hir2mpl/bytecode_input/common/include/ark_annotation_processor.h new file mode 100644 index 0000000000000000000000000000000000000000..c4ba6b5d43529ad45304ecba98822ee5355fd5d7 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/ark_annotation_processor.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_ARK_ANNOTATION_PROCESSOR_H +#define HIR2MPL_BC_INPUT_INCLUDE_ARK_ANNOTATION_PROCESSOR_H +#include "global_tables.h" +#include "namemangler.h" +namespace maple { +namespace bc { +class ArkAnnotationProcessor { + public: + static void Process(); +}; + +class ArkAnnotation { + public: + void Init(); + bool IsFastNative(const TyIdx &tyIdx) const; + bool IsCriticalNative(const TyIdx &tyIdx) const; + bool IsCallerSensitive(const TyIdx &tyIdx) const; + bool IsPermanent(const TyIdx &tyIdx) const; + bool IsPermanent(const std::string &str) const; + bool IsRCUnowned(const TyIdx &tyIdx) const; + bool IsRCUnownedCap(const TyIdx &tyIdx) const; + bool IsRCUnownedCapList(const TyIdx &tyIdx) const; + bool IsRCUnownedLocal(const TyIdx &tyIdx) const; + bool IsRCUnownedLocalOld(const TyIdx &tyIdx) const; + bool IsRCUnownedThis(const TyIdx &tyIdx) const; + bool IsRCUnownedOuter(const TyIdx &tyIdx) const; + bool IsRCWeak(const TyIdx &tyIdx) const; + static ArkAnnotation &GetInstance() { + return instance; + } + + static GStrIdx GetStrIdxFromDexName(const std::string &name) { + return GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(name)); + } + + private: + ArkAnnotation() = default; + ~ArkAnnotation() = default; + static MIRStructType *GetStructType(const TyIdx &tyIdx); + + static ArkAnnotation instance; + std::set typeNameSetForFastNative; + std::set typeNameSetForCriticalNative; + std::set typeNameSetForCallerSensitive; + std::set typeNameSetForPermanent; + std::set typeNameSetForRCUnowned; + std::set typeNameSetForRCUnownedCap; + std::set typeNameSetForRCUnownedCapList; + std::set typeNameSetForRCUnownedLocal; + std::set typeNameSetForRCUnownedThis; + std::set typeNameSetForRCUnownedOuter; + std::set typeNameSetForRCWeak; + GStrIdx typeNameIdxForRCUnownedLocalOld; +}; +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_ARK_ANNOTATION_PROCESSOR_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/bc_class.h b/src/hir2mpl/bytecode_input/common/include/bc_class.h new file mode 100644 index 0000000000000000000000000000000000000000..41ad79f432ac96feb088a19b542fa210ed807255 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_class.h @@ -0,0 +1,369 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef HIR2MPL_BC_INPUT_INCLUDE_BC_CLASS_H +#define HIR2MPL_BC_INPUT_INCLUDE_BC_CLASS_H +#include +#include +#include +#include +#include "types_def.h" +#include "bc_instruction.h" +#include "feir_stmt.h" +#include "bc_parser_base.h" +#include "feir_var.h" +#include "mempool.h" +#include "bc_pragma.h" + +namespace maple { +namespace bc { +using BCAttrKind = uint32; +class BCClass; + +class BCAttr { + public: + BCAttr(BCAttrKind k, const GStrIdx &idx) : kind(k), nameIdx(idx) {} + ~BCAttr() = default; + + protected: + BCAttrKind kind; + GStrIdx nameIdx; +}; + +class BCAttrMap { + public: + BCAttrMap() = default; + ~BCAttrMap() = default; + + protected: + std::map>>> mapAttrs; +}; + +class BCClassElem { + public: + BCClassElem(const BCClass &klassIn, uint32 acc, const std::string &nameIn, const std::string &descIn); + virtual ~BCClassElem() = default; + const std::string &GetName() const; + const std::string &GetDescription() const; + uint32 GetItemIdx() const; + uint32 GetIdx() const; + uint32 GetAccessFlag() const; + bool IsStatic() const; + const std::string &GetClassName() const; + const BCClass &GetBCClass() const; + GStrIdx GetClassNameMplIdx() const; + + protected: + virtual uint32 GetItemIdxImpl() const = 0; + virtual uint32 GetIdxImpl() const = 0; + virtual bool IsStaticImpl() const = 0; + const BCClass &klass; + uint32 accessFlag; + std::string name; + std::string descriptor; + BCAttrMap attrMap; +}; + +class BCClassField : public BCClassElem { + public: + BCClassField(const BCClass &klassIn, uint32 acc, const std::string &nameIn, const std::string &descIn) + : BCClassElem(klassIn, acc, nameIn, descIn) {} + ~BCClassField() = default; + + protected: + uint32 GetItemIdxImpl() const override = 0; + uint32 GetIdxImpl() const override = 0; +}; + +class BCCatchInfo { + public: + BCCatchInfo(uint32 handlerAddrIn, const GStrIdx &argExceptionNameIdx, bool isCatchAllIn); + ~BCCatchInfo() = default; + + uint32 GetHandlerAddr() const { + return handlerAddr; + } + + GStrIdx GetExceptionNameIdx() const { + return exceptionNameIdx; + } + + bool GetIsCatchAll() const { + return isCatchAll; + } + + protected: + uint32 handlerAddr; + GStrIdx exceptionNameIdx; + bool isCatchAll = false; +}; + +class BCTryInfo { + public: + BCTryInfo(uint32 startAddrIn, uint32 endAddrIn, std::unique_ptr>> catchesIn) + : startAddr(startAddrIn), endAddr(endAddrIn), catches(std::move(catchesIn)) {} + ~BCTryInfo() = default; + + uint32 GetStartAddr() const { + return startAddr; + } + + uint32 GetEndAddr() const { + return endAddr; + } + + const std::list> *GetCatches() const { + return catches.get(); + } + static void DumpTryCatchInfo(const std::unique_ptr>> &tryInfos); + + protected: + uint32 startAddr; + uint32 endAddr; + std::unique_ptr>> catches; +}; + +class BCClassMethod : public BCClassElem { + public: + BCClassMethod(const BCClass &klassIn, uint32 acc, bool isVirtualIn, const std::string &nameIn, + const std::string &descIn) + : BCClassElem(klassIn, acc, nameIn, descIn), isVirtual(isVirtualIn), + methodMp(FEUtils::NewMempool("MemPool for BCClassMethod", true /* isLcalPool */)), + allocator(methodMp) {} + ~BCClassMethod() { + methodMp = nullptr; + } + void SetPCBCInstructionMap(MapleMap *mapIn) { + pcBCInstructionMap = mapIn; + } + void SetMethodInstOffset(const uint16 *pos); + void SetRegisterTotalSize(uint16 size); + uint16 GetRegisterTotalSize() const; + void SetRegisterInsSize(uint16 size); + void SetCodeOff(uint32 off); + uint32 GetCodeOff() const; + void AddMethodDepSet(const std::string &depType); + bool IsVirtual() const; + bool IsNative() const; + bool IsInit() const; + bool IsClinit() const; + std::string GetFullName() const; + void ProcessInstructions(); + std::list EmitInstructionsToFEIR() const; + const uint16 *GetInstPos() const; + + void SetTryInfos(std::unique_ptr>> infos) { + tryInfos = std::move(infos); + } + + std::size_t GetTriesSize() const { + return tryInfos->size(); + } + + uint32 GetThisRegNum() const { + return IsStatic() ? UINT32_MAX : static_cast(registerTotalSize - registerInsSize); + } + + void SetSrcPositionInfo(const std::map &srcPosInfo) { +#ifdef DEBUG + pSrcPosInfo = &srcPosInfo; +#else + (void) srcPosInfo; +#endif + } + + const std::map>> *GetSrcLocalInfoPtr() const { + return srcLocals.get(); + } + + void SetSrcLocalInfo( + std::unique_ptr>>> srcLocalsIn) { + srcLocals = std::move(srcLocalsIn); + } + + std::vector> GenArgVarList() const; + void GenArgRegs(); + std::vector GetSigTypeNames() const { + return sigTypeNames; + } + bool HasCode() const { + return pcBCInstructionMap != nullptr && !pcBCInstructionMap->empty(); + } + + bool IsRcPermanent() const { + return isPermanent; + } + + void SetIsRcPermanent(bool flag) { + isPermanent = flag; + } + + const MemPool *GetMemPool() const { + return methodMp; + } + + void ReleaseMempool() { + FEUtils::DeleteMempoolPtr(methodMp); + } + + MapleAllocator &GetAllocator() { + return allocator; + } + + protected: + uint32 GetItemIdxImpl() const override = 0; + uint32 GetIdxImpl() const override = 0; + virtual bool IsVirtualImpl() const = 0; + virtual bool IsNativeImpl() const = 0; + virtual bool IsInitImpl() const = 0; + virtual bool IsClinitImpl() const = 0; + void ProcessTryCatch(); + virtual std::vector> GenArgVarListImpl() const = 0; + void TypeInfer(); + void InsertPhi(const std::vector &dom, std::vector &src); + static TypeInferItem *ConstructTypeInferItem(MapleAllocator &alloc, uint32 pos, BCReg* bcReg, TypeInferItem *prev); + static std::vector ConstructNewRegTypeMap(MapleAllocator &alloc, uint32 pos, + const std::vector ®TypeMap); + std::list GenReTypeStmtsThroughArgs() const; + void Traverse(std::list>> &pcDefedRegsList, + std::vector> &dominances, + std::set &visitedSet); + void PrecisifyRegType(); + virtual void GenArgRegsImpl() = 0; + static void LinkJumpTarget(const std::map &targetFEIRStmtMap, + const std::list &gotoFEIRStmts, + const std::list &switchFEIRStmts); + void DumpBCInstructionMap() const; + void SetSrcPosInfo(); + MapleMap *pcBCInstructionMap = nullptr; + std::unique_ptr>> tryInfos; +#ifdef DEBUG + const std::map *pSrcPosInfo = nullptr; +#endif + // map>> + std::unique_ptr>>> srcLocals; + std::vector> argRegs; + std::vector sigTypeNames; + bool isVirtual = false; + uint16 registerTotalSize = UINT16_MAX; + uint16 registerInsSize = UINT16_MAX; + uint32 codeOff = UINT32_MAX; + const uint16 *instPos = nullptr; // method instructions start pos in bc file + std::set visitedPcSet; + std::set multiInDegreeSet; + std::list regTypes; + // isPermanent is true means the rc annotation @Permanent is used + bool isPermanent = false; + + MemPool *methodMp; + MapleAllocator allocator; +}; + +class BCClass { + public: + BCClass(uint32 idx, const BCParserBase &parserIn) : classIdx(idx), parser(parserIn) {} + ~BCClass() = default; + + uint32 GetClassIdx() const { + return classIdx; + } + + const BCParserBase &GetBCParser() const { + return parser; + } + + bool IsInterface() const { + return isInterface; + } + + void SetFilePathName(const std::string &path) { + filePathName = path; + } + + void SetSrcFileInfo(const std::string &name); + void SetIRSrcFileSigIdx(const GStrIdx &strIdx) { + irSrcFileSigIdx = strIdx; + } + + bool IsMultiDef() const { + return isMultiDef; + } + + void SetIsMultiDef(bool flag) { + isMultiDef = flag; + } + + uint32 GetSrcFileIdx() const { + return srcFileIdx; + } + + void SetIsInterface(bool flag) { + isInterface = flag; + } + void SetSuperClasses(const std::list &names); + void SetInterface(const std::string &name); + void SetAccFlag(uint32 flag); + void SetField(std::unique_ptr field); + void SetMethod(std::unique_ptr method); + void SetClassName(const std::string &classNameOrinIn); + void SetAnnotationsDirectory(std::unique_ptr annotationsDirectory); + void InsertStaticFieldConstVal(MIRConst *cst); + void InsertFinalStaticStringID(uint32 stringID); + std::vector GetFinalStaticStringIDVec() const { + return finalStaticStringID; + } + std::vector GetStaticFieldsConstVal() const; + const std::string &GetClassName(bool mapled) const; + + GStrIdx GetClassNameMplIdx() const { + return classNameMplIdx; + } + + const std::list &GetSuperClassNames() const; + const std::vector &GetSuperInterfaceNames() const; + std::string GetSourceFileName() const; + GStrIdx GetIRSrcFileSigIdx() const; + uint32 GetAccessFlag() const; + int32 GetFileNameHashId() const; + + const std::vector> &GetFields() const; + std::vector> &GetMethods(); + const std::unique_ptr &GetAnnotationsDirectory() const; + + protected: + bool isInterface = false; + bool isMultiDef = false; + uint32 classIdx; + uint32 srcFileIdx = 0; + uint32 accFlag = 0; + GStrIdx classNameOrinIdx; + GStrIdx classNameMplIdx; + GStrIdx srcFileNameIdx; + GStrIdx irSrcFileSigIdx; + const BCParserBase &parser; + std::list superClassNameList; + std::vector interfaces; + std::vector> fields; + std::vector> methods; + std::unique_ptr annotationsDirectory; + std::vector staticFieldsConstVal; + std::vector finalStaticStringID; + BCAttrMap attrMap; + std::string filePathName; + mutable std::mutex bcClassMtx; +}; +} +} +#endif // HIR2MPL_BC_INPUT_INCLUDE_BC_CLASS_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/bc_class2fe_helper.h b/src/hir2mpl/bytecode_input/common/include/bc_class2fe_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..a66b6e6b5ed3a007f60e90b80dbe53c297fbe349 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_class2fe_helper.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef HIR2MPL_BC_INPUT_INCLUDE_BC_CLASS2FE_HELPER_H +#define HIR2MPL_BC_INPUT_INCLUDE_BC_CLASS2FE_HELPER_H +#include "fe_input_helper.h" +#include "bc_class.h" +#include "bc_pragma.h" +namespace maple { +namespace bc { +class BCClass2FEHelper : public FEInputStructHelper { + public: + BCClass2FEHelper(MapleAllocator &allocator, BCClass &klassIn); + ~BCClass2FEHelper() = default; + + protected: + std::string GetStructNameOrinImpl() const override; + std::string GetStructNameMplImpl() const override; + std::list GetSuperClassNamesImpl() const override; + std::vector GetInterfaceNamesImpl() const override; + std::string GetSourceFileNameImpl() const override; + MIRStructType *CreateMIRStructTypeImpl(bool &error) const override; + uint64 GetRawAccessFlagsImpl() const override; + GStrIdx GetIRSrcFileSigIdxImpl() const override; + bool IsMultiDefImpl() const override; + std::string GetSrcFileNameImpl() const override; + + BCClass &klass; + + private: + void TryMarkMultiDefClass(MIRStructType &typeImported) const; +}; + +class BCClassField2FEHelper : public FEInputFieldHelper { + public: + BCClassField2FEHelper(MapleAllocator &allocator, const BCClassField &fieldIn) + : FEInputFieldHelper(allocator), + field(fieldIn) {} + ~BCClassField2FEHelper() = default; + FieldAttrs AccessFlag2Attribute(uint32 accessFlag) const; + + protected: + virtual FieldAttrs AccessFlag2AttributeImpl(uint32 accessFlag) const = 0; + bool ProcessDeclImpl(MapleAllocator &allocator) override; + bool ProcessDeclWithContainerImpl(MapleAllocator &allocator) override; + const BCClassField &field; +}; + +class BCClassMethod2FEHelper : public FEInputMethodHelper { + public: + BCClassMethod2FEHelper(MapleAllocator &allocator, std::unique_ptr &methodIn); + ~BCClassMethod2FEHelper() = default; + std::unique_ptr &GetMethod() const { + return method; + } + + protected: + bool ProcessDeclImpl(MapleAllocator &allocator) override; + void SolveReturnAndArgTypesImpl(MapleAllocator &allocator) override; + std::string GetMethodNameImpl(bool inMpl, bool full) const override; + bool IsVargImpl() const override; + bool HasThisImpl() const override; + MIRType *GetTypeForThisImpl() const override; + + virtual bool IsClinit() const = 0; + virtual bool IsInit() const = 0; + bool IsVirtualImpl() const override; + bool IsNativeImpl() const override; + bool HasCodeImpl() const override; + + std::unique_ptr &method; +}; + +class BCInputPragmaHelper : public FEInputPragmaHelper { + public: + BCInputPragmaHelper(BCAnnotationsDirectory &bcAnnotationsDirectoryIn) + : bcAnnotationsDirectory(bcAnnotationsDirectoryIn) {} + virtual ~BCInputPragmaHelper() = default; + + protected: + std::vector &GenerateMIRPragmasImpl() override { + return bcAnnotationsDirectory.EmitPragmas(); + } + + private: + BCAnnotationsDirectory &bcAnnotationsDirectory; +}; +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_BC_CLASS2FE_HELPER_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/bc_compiler_component-inl.h b/src/hir2mpl/bytecode_input/common/include/bc_compiler_component-inl.h new file mode 100644 index 0000000000000000000000000000000000000000..432f850c012cd06f94e84d0f72813643dc10dd5a --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_compiler_component-inl.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_BC_COMPILER_COMPONENT_INL_H_ +#define HIR2MPL_BC_INPUT_INCLUDE_BC_COMPILER_COMPONENT_INL_H_ +#include "bc_compiler_component.h" +#include "fe_timer.h" +#include "bc_function.h" +#include "dex_class2fe_helper.h" +#include "fe_manager.h" +#include "class_loader_context.h" +#include "class_linker.h" + +namespace maple { +namespace bc { +template +BCCompilerComponent::BCCompilerComponent(MIRModule &module) + : HIR2MPLCompilerComponent(module, kSrcLangJava), + mp(FEUtils::NewMempool("MemPool for BCCompilerComponent", false /* isLcalPool */)), + allocator(mp), + bcInput(std::make_unique>(module)) {} + +template +BCCompilerComponent::~BCCompilerComponent() { + mp = nullptr; +} + +template +bool BCCompilerComponent::ParseInputImpl() { + FETimer timer; + bool success = true; + timer.StartAndDump("BCCompilerComponent::ParseInput()"); + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process BCCompilerComponent::ParseInput() ====="); + const std::list &inputClassNames = {}; + std::vector inputNames; + if (typeid(T) == typeid(DexReader)) { + inputNames = FEOptions::GetInstance().GetInputDexFiles(); + } else { + CHECK_FATAL(false, "Reader is not supported. Exit."); + } + success = success && bcInput->ReadBCFiles(inputNames, inputClassNames); + CHECK_FATAL(success, "BCCompilerComponent::ParseInput failed. Exit."); + bc::BCClass *klass = bcInput->GetFirstClass(); + while (klass != nullptr) { + if (typeid(T) == typeid(DexReader)) { + FEInputStructHelper *structHelper = allocator.GetMemPool()->template New(allocator, *klass); + FEInputPragmaHelper *pragmaHelper = + allocator.GetMemPool()->template New(*(klass->GetAnnotationsDirectory())); + structHelper->SetPragmaHelper(pragmaHelper); + structHelper->SetStaticFieldsConstVal(klass->GetStaticFieldsConstVal()); + structHelpers.push_back(structHelper); + } else { + CHECK_FATAL(false, "Reader is not supported. Exit."); + } + klass = bcInput->GetNextClass(); + } + timer.StopAndDumpTimeMS("BCCompilerComponent::ParseInput()"); + return success; +} + +template +bool BCCompilerComponent::LoadOnDemandTypeImpl() { + FETimer timer; + bool success = true; + timer.StartAndDump("BCCompilerComponent::LoadOnDemandType()"); + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process BCCompilerComponent::LoadOnDemandType() ====="); + // Collect dependent type names in dexfile + std::unordered_set allDepSet; + success = success && bcInput->CollectDependentTypeNamesOnAllBCFiles(allDepSet); + CHECK_FATAL(success, "BCCompilerComponent::CollectDepTypeNames failed. Exit."); + // Collect class def type names in dexfile + std::unordered_set allClassSet; + success = success && bcInput->CollectClassNamesOnAllBCFiles(allClassSet); + // Find dependent types and resolve types to bcClasses + std::list> klassList; + success = success && LoadOnDemandType2BCClass(allDepSet, allClassSet, klassList); + // All dependent bcClasses are loaded into the mir globaltable and used like mplt + std::list> structHelpers; + success = success && LoadOnDemandBCClass2FEClass(klassList, structHelpers, !FEOptions::GetInstance().IsNoMplFile()); + timer.StopAndDumpTimeMS("BCCompilerComponent::LoadOnDemandType()"); + return success; +} + +template +bool BCCompilerComponent::LoadOnDemandType2BCClass(const std::unordered_set &allDepsSet, + const std::unordered_set &allDefsSet, + std::list> &klassList) { + FETimer timer; + timer.StartAndDump("LoadOnDemandType2BCClass::Open dep dexfiles"); + bool success = true; + ClassLoaderContext *classLoaderContext = nullptr; + const ClassLoaderInfo *classLoader = nullptr; + std::vector> bootClassPaths; + std::string spec = FEOptions::GetInstance().GetXBootClassPath(); + if (!spec.empty()) { // Xbootclasspath + INFO(kLncInfo, "XBootClassPath=%s", spec.c_str()); + success = success && ClassLoaderContext::OpenDexFiles(spec, bootClassPaths); + } + spec = FEOptions::GetInstance().GetClassLoaderContext(); + if (!spec.empty()) { // PCL + INFO(kLncInfo, "PCL=%s", spec.c_str()); + classLoaderContext = ClassLoaderContext::Create(spec, *mp); + if (classLoaderContext != nullptr) { + classLoader = classLoaderContext->GetClassLoader(); + } + } + timer.StopAndDumpTimeMS("LoadOnDemandType2BCClass::Open dep dexfiles"); + ClassLinker *classLinker = mp->New(bootClassPaths); + for (const std::string &className : allDepsSet) { + classLinker->FindClass(className, nullptr, klassList); + } + // if same class name is existed in src dexFile and dependent set, import class from dependent set preferentially + for (const std::string &className : allDefsSet) { + classLinker->FindClass(className, nullptr, klassList, true); + } + return success; +} + +template +bool BCCompilerComponent::LoadOnDemandBCClass2FEClass( + const std::list> &klassList, + std::list> &structHelpers, + bool isEmitDepsMplt) { + for (const std::unique_ptr &klass : klassList) { + std::unique_ptr structHelper = std::make_unique(allocator, *klass); + FEInputPragmaHelper *pragmaHelper = + allocator.GetMemPool()->template New(*(klass->GetAnnotationsDirectory())); + structHelper->SetPragmaHelper(pragmaHelper); + structHelper->SetIsOnDemandLoad(true); + structHelpers.push_back(std::move(structHelper)); + } + for (const std::unique_ptr &helper : structHelpers) { + ASSERT_NOT_NULL(helper); + (void)helper->PreProcessDecl(); + } + for (const std::unique_ptr &helper : structHelpers) { + ASSERT_NOT_NULL(helper); + (void)helper->ProcessDecl(); + helper->ProcessPragma(); + } + if (isEmitDepsMplt) { + std::string outName = module.GetFileName(); + size_t lastDot = outName.find_last_of("."); + std::string outNameWithoutType; + if (lastDot == std::string::npos) { + outNameWithoutType = outName; + } else { + outNameWithoutType = outName.substr(0, lastDot); + } + std::string depFileName = outNameWithoutType + ".Deps.mplt"; + module.GetImportFiles().push_back(module.GetMIRBuilder()->GetOrCreateStringIndex(depFileName)); + module.DumpToHeaderFile(!FEOptions::GetInstance().IsGenAsciiMplt(), depFileName); + } + FEOptions::ModeDepSameNamePolicy mode = FEOptions::GetInstance().GetModeDepSameNamePolicy(); + switch (mode) { + case FEOptions::ModeDepSameNamePolicy::kSys: + // Set kSrcMpltSys flag, loading on-demand dependent types from system + FEManager::GetTypeManager().SetMirImportedTypes(FETypeFlag::kSrcMpltSys); + break; + case FEOptions::ModeDepSameNamePolicy::kSrc: + // Set kSrcMplt flag, same name types are then overridden from src file after loaded on-demand dependent type + FEManager::GetTypeManager().SetMirImportedTypes(FETypeFlag::kSrcMplt); + break; + } + for (uint32 i = 1; i < GlobalTables::GetGsymTable().GetSymbolTableSize(); ++i) { + MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbol(i); + if ((symbol != nullptr) && (symbol->GetSKind() == kStFunc)) { + symbol->SetIsImportedDecl(true); + } + } + return true; +} + +template +void BCCompilerComponent::ProcessPragmaImpl() { + FETimer timer; + timer.StartAndDump("BCCompilerComponent::ProcessPragmaImpl()"); + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process BCCompilerComponent::ProcessPragmaImpl() ====="); + for (FEInputStructHelper *helper : structHelpers) { + ASSERT_NOT_NULL(helper); + helper->ProcessPragma(); + } + timer.StopAndDumpTimeMS("BCCompilerComponent::ProcessPragmaImpl()"); +} + +template +std::unique_ptr BCCompilerComponent::CreatFEFunctionImpl(FEInputMethodHelper *methodHelper) { + BCClassMethod2FEHelper *bcMethodHelper = static_cast(methodHelper); + GStrIdx methodNameIdx = methodHelper->GetMethodNameIdx(); + bool isStatic = methodHelper->IsStatic(); + MIRFunction *mirFunc = FEManager::GetTypeManager().GetMIRFunction(methodNameIdx, isStatic); + CHECK_NULL_FATAL(mirFunc); + std::unique_ptr feFunction = std::make_unique(*bcMethodHelper, *mirFunc, phaseResultTotal); + module.AddFunction(mirFunc); + feFunction->Init(); + return feFunction; +} + +template +std::string BCCompilerComponent::GetComponentNameImpl() const { + return "BCCompilerComponent"; +} + +template +bool BCCompilerComponent::ParallelableImpl() const { + return true; +} + +template +void BCCompilerComponent::DumpPhaseTimeTotalImpl() const { + INFO(kLncInfo, "[PhaseTime] BCCompilerComponent"); + HIR2MPLCompilerComponent::DumpPhaseTimeTotalImpl(); +} + +template +void BCCompilerComponent::ReleaseMemPoolImpl() { + FEUtils::DeleteMempoolPtr(mp); +} +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_BC_COMPILER_COMPONENT_INL_H_ diff --git a/src/hir2mpl/bytecode_input/common/include/bc_compiler_component.h b/src/hir2mpl/bytecode_input/common/include/bc_compiler_component.h new file mode 100644 index 0000000000000000000000000000000000000000..fc5fccf2c0d5be13cae642cc10e8179edbb652b4 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_compiler_component.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_BC_COMPILER_COMPONENT_H +#define HIR2MPL_BC_INPUT_INCLUDE_BC_COMPILER_COMPONENT_H +#include "fe_macros.h" +#include "hir2mpl_compiler_component.h" +#include "bc_input.h" + +namespace maple { +namespace bc { +template +class BCCompilerComponent : public HIR2MPLCompilerComponent { + public: + explicit BCCompilerComponent(MIRModule &module); + ~BCCompilerComponent(); + + protected: + bool ParseInputImpl() override; + bool LoadOnDemandTypeImpl() override; + void ProcessPragmaImpl() override; + std::unique_ptr CreatFEFunctionImpl(FEInputMethodHelper *methodHelper) override; + std::string GetComponentNameImpl() const override; + bool ParallelableImpl() const override; + void DumpPhaseTimeTotalImpl() const override; + void ReleaseMemPoolImpl() override; + + private: + bool LoadOnDemandType2BCClass(const std::unordered_set &allDepsSet, + const std::unordered_set &allDefsSet, + std::list> &klassList); + bool LoadOnDemandBCClass2FEClass(const std::list> &klassList, + std::list> &structHelpers, + bool isEmitDepsMplt); + + MemPool *mp; + MapleAllocator allocator; + std::unique_ptr> bcInput; +}; // class BCCompilerComponent +} // namespace bc +} // namespace maple +#include "bc_compiler_component-inl.h" +#endif // HIR2MPL_BC_INPUT_INCLUDE_BC_COMPILER_COMPONENT_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/bc_function.h b/src/hir2mpl/bytecode_input/common/include/bc_function.h new file mode 100644 index 0000000000000000000000000000000000000000..dedebf5387aeb9a1a17328c4820314f5a31944c0 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_function.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL_FE_BC_INPUT_BC_FUNTION_H +#define MPL_FE_BC_INPUT_BC_FUNTION_H +#include "fe_function.h" +#include "bc_class2fe_helper.h" + +namespace maple { +namespace bc { +class BCFunction : public FEFunction { + public: + BCFunction(const BCClassMethod2FEHelper &argMethodHelper, MIRFunction &mirFunc, + const std::unique_ptr &argPhaseResultTotal); + virtual ~BCFunction() = default; + + protected: + bool GenerateGeneralStmt(const std::string &phaseName) override { + WARN(kLncWarn, "Phase: %s may not need.", phaseName.c_str()); + return true; + } + + bool GenerateArgVarList(const std::string &phaseName) override; + bool GenerateAliasVars(const std::string &phaseName) override; + + bool PreProcessTypeNameIdx() override { + return true; + } + + void GenerateGeneralStmtFailCallBack() override {} + + void GenerateGeneralDebugInfo() override {} + + bool VerifyGeneral() override { + return true; + } + + void VerifyGeneralFailCallBack() override {} + + bool HasThis() override { + return methodHelper.HasThis(); + } + + bool IsNative() override { + return methodHelper.IsNative(); + } + + bool EmitToFEIRStmt(const std::string &phaseName) override; + + void InitImpl() override; + void SetMIRFunctionInfo(); + void PreProcessImpl() override; + bool ProcessImpl() override; + bool ProcessFEIRFunction() override; + void FinishImpl() override; + bool EmitToMIR(const std::string &phaseName) override; + + const BCClassMethod2FEHelper &methodHelper; + std::unique_ptr &method; + bool error = false; +}; +} // namespace bc +} // namespace maple +#endif \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/bc_input-inl.h b/src/hir2mpl/bytecode_input/common/include/bc_input-inl.h new file mode 100644 index 0000000000000000000000000000000000000000..66b37d80476bf8ecc46b4f15ccffff5d4a273d58 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_input-inl.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_BC_INPUT_INL_H_ +#define HIR2MPL_BC_INPUT_INCLUDE_BC_INPUT_INL_H_ +#include "bc_input.h" +#include +#include "dex_parser.h" +#include "hir2mpl_env.h" + +namespace maple { +namespace bc { +template +bool BCInput::ReadBCFile(uint32 index, const std::string &fileName, const std::list &classNamesIn) { + std::unique_ptr bcParser; + if (typeid(T) == typeid(DexReader)) { + bcParser = std::make_unique(index, fileName, classNamesIn); + } else { + CHECK_FATAL(false, "Unsupported BC reader: %s in BCInput", typeid(T).name()); + } + if (bcParser->OpenFile() == false) { + return false; + } + if (bcParser->ParseHeader() == false) { + ERR(kLncErr, "Parse Header failed in : %s.", fileName.c_str()); + return false; + } + if (bcParser->Verify() == false) { + ERR(kLncErr, "Verify file failed in : %s.", fileName.c_str()); + return false; + } + if (bcParser->RetrieveClasses(bcClasses) == false) { + ERR(kLncErr, "Retrieve classes failed in : %s.", fileName.c_str()); + return false; + } + (void)bcParserMap.insert(std::make_pair(fileName, std::move(bcParser))); + return true; +} + +template +bool BCInput::ReadBCFiles(const std::vector &fileNames, const std::list &classNamesIn) { + for (uint32 i = 0; i < fileNames.size(); ++i) { + if (BCInput::ReadBCFile(i, fileNames[i], classNamesIn) == false) { + return false; + } + RegisterFileInfo(fileNames[i]); + } + return true; +} + +template +BCClass *BCInput::GetFirstClass() { + if (bcClasses.size() == 0) { + return nullptr; + } + itKlass = bcClasses.begin(); + return itKlass->get(); +} + +template +BCClass *BCInput::GetNextClass() { + if (itKlass == bcClasses.end()) { + return nullptr; + } + ++itKlass; + if (itKlass == bcClasses.end()) { + return nullptr; + } + return itKlass->get(); +} + +template +void BCInput::RegisterFileInfo(const std::string &fileName) { + GStrIdx fileNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fileName); + GStrIdx fileInfoIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("INFO_filename"); + module.PushFileInfoPair(MIRInfoPair(fileInfoIdx, fileNameIdx)); + module.PushFileInfoIsString(true); +} + +template +bool BCInput::CollectDependentTypeNamesOnAllBCFiles(std::unordered_set &allDepSet) { + FEOptions::ModeCollectDepTypes mode = FEOptions::GetInstance().GetModeCollectDepTypes(); + bool isSuccess = true; + switch (mode) { + case FEOptions::ModeCollectDepTypes::kAll: + isSuccess = CollectAllDepTypeNamesOnAllBCFiles(allDepSet); + break; + case FEOptions::ModeCollectDepTypes::kFunc: + isSuccess = CollectMethodDepTypeNamesOnAllBCFiles(allDepSet); + break; + } + return isSuccess; +} + +template +bool BCInput::CollectAllDepTypeNamesOnAllBCFiles(std::unordered_set &allDepSet) { + for (auto &item : bcParserMap) { + std::unordered_set depSet; + if (item.second->CollectAllDepTypeNames(depSet) == false) { + ERR(kLncErr, "Collect all dependent typenames failed in : %s.", item.first.c_str()); + return false; + } + allDepSet.insert(depSet.begin(), depSet.end()); + } + BCUtil::AddDefaultDepSet(allDepSet); // allDepSet is equal to "DefaultTypeSet + TypeSet - ClassSet" + std::unordered_set classSet; + (void)CollectClassNamesOnAllBCFiles(classSet); + for (const auto &elem : classSet) { + (void)allDepSet.erase(elem); + } + return true; +} + +template +bool BCInput::CollectMethodDepTypeNamesOnAllBCFiles(std::unordered_set &depSet) { + bool isSuccess = true; + for (const std::unique_ptr &klass : bcClasses) { + if (klass == nullptr) { + continue; + } + std::list superClassNames = klass->GetSuperClassNames(); + depSet.insert(superClassNames.begin(), superClassNames.end()); + std::vector superInterfaceNames = klass->GetSuperInterfaceNames(); + depSet.insert(superInterfaceNames.begin(), superInterfaceNames.end()); + for (const std::unique_ptr &method : klass->GetMethods()) { + if (method == nullptr) { + continue; + } + (void)klass->GetBCParser().CollectMethodDepTypeNames(depSet, *method); + } + } + std::unordered_set classSet; + isSuccess = isSuccess && CollectClassNamesOnAllBCFiles(classSet); + BCUtil::AddDefaultDepSet(depSet); // DepSet is equal to "DefaultTypeSet + TypeSet - ClassSet" + for (const auto &elem : classSet) { + (void)depSet.erase(elem); + } + return isSuccess; +} + +template +bool BCInput::CollectClassNamesOnAllBCFiles(std::unordered_set &allClassSet) { + for (auto &item : bcParserMap) { + std::unordered_set classSet; + if (item.second->CollectAllClassNames(classSet) == false) { + ERR(kLncErr, "Collect all class names failed in : %s.", item.first.c_str()); + return false; + } + allClassSet.insert(classSet.begin(), classSet.end()); + } + return true; +} +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_BC_INPUT_INL_H_ diff --git a/src/hir2mpl/bytecode_input/common/include/bc_input.h b/src/hir2mpl/bytecode_input/common/include/bc_input.h new file mode 100644 index 0000000000000000000000000000000000000000..21d657fc3a5de219f8212f22e7e8252d394159f3 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_input.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef HIR2MPL_BC_INPUT_INCLUDE_BC_INPUT_H +#define HIR2MPL_BC_INPUT_INCLUDE_BC_INPUT_H +#include +#include +#include "mir_module.h" +#include "bc_class.h" +#include "bc_parser.h" + +namespace maple { +namespace bc { +template +class BCInput { + public: + explicit BCInput(MIRModule &moduleIn) : module(moduleIn) {} + ~BCInput() = default; + bool ReadBCFile(uint32 index, const std::string &fileName, const std::list &classNamesIn); + bool ReadBCFiles(const std::vector &fileNames, const std::list &classNamesIn); + const MIRModule &GetModule() const { + return module; + } + BCClass *GetFirstClass(); + BCClass *GetNextClass(); + void RegisterFileInfo(const std::string &fileName); + bool CollectDependentTypeNamesOnAllBCFiles(std::unordered_set &allDepSet); + bool CollectClassNamesOnAllBCFiles(std::unordered_set &allClassSet); + + private: + bool CollectAllDepTypeNamesOnAllBCFiles(std::unordered_set &allDepSet); + bool CollectMethodDepTypeNamesOnAllBCFiles(std::unordered_set &allDepSet); + + std::map> bcParserMap; // map + MIRModule &module; + + std::list> bcClasses; + std::list>::const_iterator itKlass; +}; +} +} +#include "bc_input-inl.h" +#endif // HIR2MPL_BC_INPUT_INCLUDE_BC_INPUT_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/bc_instruction.h b/src/hir2mpl/bytecode_input/common/include/bc_instruction.h new file mode 100644 index 0000000000000000000000000000000000000000..0181dbd1d299454365d90fffa06e73ccf051b2c1 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_instruction.h @@ -0,0 +1,445 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_BC_INSTRUCTION_H +#define HIR2MPL_BC_INPUT_INCLUDE_BC_INSTRUCTION_H +#include +#include +#include "types_def.h" +#include "bc_util.h" +#include "feir_stmt.h" +#include "feir_var_reg.h" + +namespace maple { +namespace bc { +class BCClassMethod; +struct BCReg; +class BCInstruction { + public: + BCInstruction(MapleAllocator &allocatorIn, uint32 pcIn, uint8 opcodeIn) + : opcode(opcodeIn), + pc(pcIn), + allocator(allocatorIn), + catchedExTypeNamesIdx(allocator.Adapter()), + handlerTargets(allocator.Adapter()), + defedRegs(allocator.Adapter()), + usedRegs(allocator.Adapter()), + handlers(allocator.Adapter()) {} + virtual ~BCInstruction() = default; + void InitBCInStruction(uint16 kind, bool wide, bool throwable); + BCInstructionKind GetInstKind() const; + bool IsWide() const; + void SetInstructionKind(BCInstructionKind kind); + bool IsConditionBranch() const; + bool IsGoto() const; + bool IsSwitch() const; + bool IsTarget() const; + bool IsTryStart() const; + bool IsTryEnd() const; + bool IsCatch() const; + void SetReturnInst(BCInstruction *inst); + bool HasReturn() const; + bool IsReturn() const; + uint32 GetPC() const; + uint8 GetOpcode() const; + std::vector GetTargets() const; + void SetDefaultTarget(BCInstruction *inst); + void AddHandler(BCInstruction *handler); + void SetWidth(uint8 size); + uint8 GetWidth() const; + void SetCatchable(); + bool IsCatchable() const; + bool IsFallThru() const; + void SetBCRegType(const BCInstruction &inst); + void AddHandlerTarget(uint32 target); + MapleVector GetHandlerTargets() const; + MapleList *GetDefedRegs(); + MapleList *GetUsedRegs(); + void SetRegTypeInTypeInfer(); + void SetFuncNameIdx(const GStrIdx &methodIdx); + void SetSrcPositionInfo(uint32 fileIdxIn, uint32 lineNumIn); + void SetOpName(const char *name); + const char *GetOpName() const; + void Parse(BCClassMethod &method); + void SetExceptionType(const GStrIdx &typeNameIdx); + std::list EmitToFEIRStmts(); + + protected: + virtual std::vector GetTargetsImpl() const; + virtual void ParseImpl(BCClassMethod &method) = 0; + virtual std::list EmitToFEIRStmtsImpl() = 0; + void GenCommentStmt(std::list &stmts) const; + UniqueFEIRStmt GenLabelStmt() const; + UniqueFEIRStmt GenCatchStmt() const; + UniqueFEIRStmt GenTryLabelStmt() const; + UniqueFEIRStmt GenTryEndLabelStmt() const; + virtual void SetRegTypeInTypeInferImpl() {} + virtual void SetBCRegTypeImpl(const BCInstruction &inst) { + (void) inst; + } // for move-result and move-exception + std::list GenRetypeStmtsAfterDef() const; + std::list GenRetypeStmtsBeforeUse() const; + void SetSrcFileInfo(std::list &stmts) const; + bool isThrowable = false; + bool isWide = false; + bool isReturn = false; + bool isCatchable = false; + uint8 width = UINT8_MAX; // Default value, unuseable + uint8 opcode; + BCInstructionKind instKind = kUnKnownKind; + uint32 funcNameIdx = UINT32_MAX; + uint32 srcFileIdx = 0; + uint32 srcFileLineNum = 0; + uint32 pc; +#ifdef DEBUG + const char *opName = nullptr; +#endif + BCInstruction *returnInst = nullptr; + BCInstruction *defaultTarget = nullptr; + MapleAllocator &allocator; + MapleSet catchedExTypeNamesIdx; + MapleVector handlerTargets; // This instruction may throw exception and reach these handlers + MapleList defedRegs; + MapleList usedRegs; + MapleList handlers; +}; + +// Forward declaration +struct BCReg; +struct TypeInferItem; + +struct BCRegTypeItem { + BCRegTypeItem(const GStrIdx &idx, bool isIndeterminateIn = false, bool isFromDefIn = false) + : typeNameIdx(idx), isIndeterminate(isIndeterminateIn), isFromDef(isFromDefIn) {} + BCRegTypeItem(const BCRegTypeItem &item) + : typeNameIdx(item.typeNameIdx), isIndeterminate(item.isIndeterminate) {} + ~BCRegTypeItem() = default; + + PrimType GetPrimType() const; + PrimType GetBasePrimType() const; + BCRegTypeItem *Clone(const MapleAllocator &allocator) { + return allocator.GetMemPool()->New(typeNameIdx, isIndeterminate); + } + + void Copy(const BCRegTypeItem &src) { + typeNameIdx = src.typeNameIdx; + isIndeterminate = src.isIndeterminate; + isFromDef = src.isFromDef; + } + bool operator==(const BCRegTypeItem &item) const { + return typeNameIdx == item.typeNameIdx; + } + + bool IsRef() const { + return GetPrimType() == PTY_ref; + } + + bool IsMorePreciseType(const BCRegTypeItem &typeItemIn) const; + + // for debug + void DumpTypeName() const { + LogInfo::MapleLogger(kLlDbg) << GlobalTables::GetStrTable().GetStringFromStrIdx(typeNameIdx) << "\n"; + } + + void SetPos(uint32 pc) { + pos = pc; + } + + void SetDom(bool flag) { + isDom = flag; + } + + bool IsDom() const { + return isDom; + } + + GStrIdx typeNameIdx; + bool isIndeterminate = false; + // means `is def ` or `come from def` + bool isFromDef = false; + uint32 pos = UINT32_MAX; + + bool isDom = false; +}; + +class BCRegType { + public: + BCRegType(MapleAllocator &allocatorIn, BCReg ®, const GStrIdx &typeNameIdxIn, bool isIndeterminateIn = false); + ~BCRegType() = default; + MapleAllocator &GetAllocator() { + return allocator; + } + + void SetTypeNameIdx(const GStrIdx &idx) { + regTypeItem->typeNameIdx = idx; + } + + bool IsIndeterminate() const { + return regTypeItem->isIndeterminate; + } + + void SetIsIndeterminate(bool flag) { + regTypeItem->isIndeterminate = flag; + } + + static void InsertUniqueTypeItem(MapleList &itemSet, BCRegTypeItem *item) { + for (auto &elem : itemSet) { + if ((!elem->isIndeterminate && !item->isIndeterminate && (*elem) == (*item)) || elem == item) { + return; + } + } + itemSet.emplace_back(item); + } + + void UpdateUsedSet(BCRegTypeItem *typeItem) { + if (typeItem->isIndeterminate) { + InsertUniqueTypeItem(fuzzyTypesUsedAs, typeItem); + } + InsertUniqueTypeItem(*typesUsedAs, typeItem); + } + + void UpdateFuzzyUsedSet(BCRegTypeItem *typeItem) { + if (typeItem->isIndeterminate) { + InsertUniqueTypeItem(fuzzyTypesUsedAs, typeItem); + } + } + + void SetRegTypeItem(BCRegTypeItem *item) { + regTypeItem = item; + } + + const BCRegTypeItem *GetRegTypeItem() const { + return regTypeItem; + } + + MapleList *GetUsedTypes() { + return typesUsedAs; + } + + void PrecisifyTypes(bool isTry = false); + + void PrecisifyRelatedTypes(const BCRegTypeItem *realType); + + void PrecisifyElemTypes(const BCRegTypeItem *realType); + + bool IsPrecisified() const { + return precisified; + } + + static BCRegTypeItem *GetMostPreciseType(const MapleList &types); + + void AddElemType(BCRegTypeItem *item) { + elemTypes.emplace(item); + } + + void SetUsedTypes(MapleList *types) { + typesUsedAs = types; + } + + void SetPos(uint32 pc) { + pos = pc; + } + + uint32 GetPos() const { + return pos; + } + + void RegisterRelatedBCRegType(BCRegType *ty) { + relatedBCRegTypes.emplace_back(ty); + } + + void RegisterLivesInfo(uint32 posStart) { + livesBegins.emplace_back(posStart); + } + + bool IsBefore(uint32 posCurr, uint32 end) const { + for (auto p : livesBegins) { + if (p == posCurr) { + return true; + } + if (p == end) { + return false; + } + } + CHECK_FATAL(false, "Should not get here."); + return true; + } + + private: + MapleAllocator &allocator; + BCReg &curReg; + BCRegTypeItem *regTypeItem; + MapleList *typesUsedAs = nullptr; + MapleList fuzzyTypesUsedAs; + bool precisified = false; + MapleSet elemTypes; + uint32 pos = UINT32_MAX; + // `0` for args, `pc + 1` for local defs + MapleVector livesBegins; + + std::list relatedBCRegTypes; +}; + +struct BCRegValue { + union { + uint64 raw64 = 0; + uint32 raw32; + } primValue; +}; + +struct BCReg { + BCReg() = default; + virtual ~BCReg() = default; + bool isDef = false; + uint32 regNum = UINT32_MAX; + BCRegType *regType = nullptr; + BCRegValue *regValue = nullptr; + BCRegTypeItem *regTypeItem = nullptr; + bool IsConstZero() const; + UniqueFEIRType GenFEIRType() const; + UniqueFEIRVar GenFEIRVarReg() const; + std::list GenRetypeStmtsAfterDef() const; + std::list GenRetypeStmtsBeforeUse() const; + // a reg maybe store a primitive pointer type var. + // If it is a primitive ptr, GetPrimType() return a PTY_ref + // GetBasePrimType() return a corresponding prim type + // If it is not a primitive pointer type, GetPrimType() and GetBasePrimType() return a same PrimType. + PrimType GetPrimType() const; + PrimType GetBasePrimType() const; + std::unique_ptr Clone() const { + return CloneImpl(); + } + + protected: + virtual UniqueFEIRType GenFEIRTypeImpl() const; + virtual UniqueFEIRVar GenFEIRVarRegImpl() const; + virtual std::unique_ptr CloneImpl() const; +}; + +// for TypeInfer +struct TypeInferItem { + TypeInferItem(MapleAllocator &alloc, uint32 pos, BCReg *regIn, TypeInferItem *prev) + : beginPos(pos), + prevs(alloc.Adapter()), + aliveUsedTypes(alloc.GetMemPool()->New>(alloc.Adapter())), + reg(regIn) { + if (prev == nullptr) { + reg->regType->SetUsedTypes(aliveUsedTypes); + } else { + (void)RegisterInPrevs(prev); + } + reg->regType->RegisterLivesInfo(pos); + } + + bool RegisterInPrevs(TypeInferItem *prev) { + for (auto e : prevs) { + if (e == prev) { + return false; + } + } + prevs.emplace_back(prev); + return true; + } + + void InsertUniqueAliveTypes(const TypeInferItem *end, const MapleList *types) { + if (end != nullptr && end->reg == this->reg && end->reg->regType->IsBefore(this->beginPos, end->beginPos)) { + return; + } + std::vector workList; + uint32 index = 0; + workList.emplace_back(this); + while (index < workList.size()) { + auto currItem = workList[index++]; + currItem->isAlive = true; + for (auto type : *types) { + bool duplicate = false; + for (auto ty : *(currItem->aliveUsedTypes)) { + if (ty == type) { + duplicate = true; + break; + } + } + if (!duplicate) { + currItem->aliveUsedTypes->emplace_back(type); + currItem->reg->regType->UpdateFuzzyUsedSet(type); + } + } + // insert into its prevs cyclely + for (auto prev : currItem->prevs) { + if (end != nullptr && end->reg == prev->reg && end->reg->regType->IsBefore(prev->beginPos, end->beginPos)) { + continue; + } + bool exist = false; + for (uint32 i = 0; i < workList.size(); ++i) { + if (workList[i] == prev) { + exist = true; + break; + } + } + if (!exist) { + workList.emplace_back(prev); + } + } + } + } + + void InsertUniqueAliveType(const TypeInferItem *end, BCRegTypeItem *type) { + if (end != nullptr && end->reg == this->reg && end->reg->regType->IsBefore(this->beginPos, end->beginPos)) { + return; + } + std::vector workList; + uint32 index = 0; + workList.emplace_back(this); + while (index < workList.size()) { + auto currItem = workList[index++]; + currItem->isAlive = true; + bool duplicate = false; + for (auto ty : *(currItem->aliveUsedTypes)) { + if (ty == type) { + duplicate = true; + break; + } + } + if (!duplicate) { + currItem->aliveUsedTypes->emplace_back(type); + currItem->reg->regType->UpdateFuzzyUsedSet(type); + } + // insert into its prevs cyclely + for (auto prev : currItem->prevs) { + if (end != nullptr && end->reg == prev->reg && end->reg->regType->IsBefore(prev->beginPos, end->beginPos)) { + continue; + } + bool exist = false; + for (uint32 i = 0; i < workList.size(); ++i) { + if (workList[i] == prev) { + exist = true; + break; + } + } + if (!exist) { + workList.emplace_back(prev); + } + } + } + } + + uint32 beginPos; + MapleList prevs; + MapleList *aliveUsedTypes = nullptr; + BCReg *reg = nullptr; + bool isAlive = false; +}; +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_BC_INSTRUCTION_H diff --git a/src/hir2mpl/bytecode_input/common/include/bc_io.h b/src/hir2mpl/bytecode_input/common/include/bc_io.h new file mode 100644 index 0000000000000000000000000000000000000000..84578e4ab3ff05541ba56a741ed9ee407bf2ea04 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_io.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL_FE_BC_INPUT_BC_IO_H +#define MPL_FE_BC_INPUT_BC_IO_H +#include +#include "basic_io.h" + +namespace maple { +namespace bc { +class BCIO : public BasicIOMapFile { + public: + explicit BCIO(const std::string &fileName); + ~BCIO() = default; + + static bool IsBigEndian() { + union { + uint16 v16; + uint8 a[sizeof(uint16) / sizeof(uint8)]; + } u; + u.v16 = 0x1234; + return u.a[0] == 0x12; + } + + protected: + bool isBigEndianHost = true; +}; + +struct RawData { + const uint8 *context; + uint32 size; +}; + +class BCReader : public BCIO, public BasicIORead { + public: + explicit BCReader(const std::string &fileName); + virtual ~BCReader(); + bool RetrieveHeader(RawData &data); + void SetEndianTag(bool isBigEndian); + template + T GetRealInteger(T value) const { + if (isBigEndian == isBigEndianHost || sizeof(T) == sizeof(uint8)) { + return value; // Same Endian, not need to convert + } else { + union U { + uint8 a[sizeof(T)]; + T val; + } u0; + u0.val = value; + U u1; + for (size_t i = 0; i < sizeof(T); ++i) { + u1.a[i] = u0.a[sizeof(T) - 1 - i]; + } + return u1.val; + } + } + + struct ClassElem { + std::string className; + std::string elemName; + std::string typeName; + }; + + std::string GetStringFromIdx(uint32 idx) const; + std::string GetTypeNameFromIdx(uint32 idx) const; + ClassElem GetClassMethodFromIdx(uint32 idx) const; + ClassElem GetClassFieldFromIdx(uint32 idx) const; + std::string GetSignature(uint32 idx) const; + uint32 GetFileIndex() const; + std::string GetIRSrcFileSignature() const; + + protected: + virtual std::string GetStringFromIdxImpl(uint32 idx) const = 0; + virtual std::string GetTypeNameFromIdxImpl(uint32 idx) const = 0; + virtual ClassElem GetClassMethodFromIdxImpl(uint32 idx) const = 0; + virtual ClassElem GetClassFieldFromIdxImpl(uint32 idx) const = 0; + virtual std::string GetSignatureImpl(uint32 idx) const = 0; + virtual uint32 GetFileIndexImpl() const = 0; + virtual bool RetrieveHeaderImpl(RawData &data); + std::string irSrcFileSignature; +}; +} // namespace bc +} // namespace maple +#endif // MPL_FE_BC_INPUT_BC_IO_H diff --git a/src/hir2mpl/bytecode_input/common/include/bc_op_factory.h b/src/hir2mpl/bytecode_input/common/include/bc_op_factory.h new file mode 100644 index 0000000000000000000000000000000000000000..ca3c274ff2497a1ca4cc4e6bbe589f43c169a865 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_op_factory.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL_FE_BC_INPUT_BC_OP_FACTORY_H +#define MPL_FE_BC_INPUT_BC_OP_FACTORY_H +#include +#include +#include "mempool_allocator.h" +#include "types_def.h" +#include "bc_instruction.h" + +namespace maple { +namespace bc { +class BCOpFactory { + public: + template + static BCInstruction *BCOpGenerator(MapleAllocator &allocator, uint32 pc) { + MemPool *mp = allocator.GetMemPool(); + BCInstruction *op = mp->New(allocator, pc, opcode); + op->InitBCInStruction(kind, wide, throwable); + return op; + } + using funcPtr = BCInstruction*(*)(MapleAllocator&, uint32); +}; +} // namespace bc +} // namespace maple +#endif // MPL_FE_BC_INPUT_BC_OP_FACTORY_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/bc_parser-inl.h b/src/hir2mpl/bytecode_input/common/include/bc_parser-inl.h new file mode 100644 index 0000000000000000000000000000000000000000..f6ecf59e7c51cebdb980489c6bab0119c0a2b386 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_parser-inl.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_BC_PARSER_INL_H_ +#define HIR2MPL_BC_INPUT_INCLUDE_BC_PARSER_INL_H_ +#include "bc_parser.h" + +namespace maple { +namespace bc { +template +BCParser::BCParser(uint32 fileIdxIn, const std::string &fileNameIn, const std::list &classNamesIn) + : BCParserBase(fileIdxIn, fileNameIn, classNamesIn), reader(std::make_unique(fileIdxIn, fileNameIn)) {} + +template +bool BCParser::OpenFileImpl() { + return reader->OpenAndMap(); +} + +template +int MethodProcessTask::RunImpl(MplTaskParam *param) { + (void)param; + parser.ProcessDexClassMethod(klass, isVirtual, index, idxPair); + return 0; +} + +template +int MethodProcessTask::FinishImpl(MplTaskParam *param) { + (void)param; + return 0; +} + +template +void MethodProcessSchedular::AddMethodProcessTask(T &parser, + std::unique_ptr &klass, bool isVirtual, uint32 index, std::pair &idxPair) { + std::unique_ptr> task = + std::make_unique>(parser, klass, isVirtual, index, idxPair); + AddTask(task.get()); + tasks.push_back(std::move(task)); +} + +template +void MethodProcessSchedular::CallbackThreadMainStart() { + std::thread::id tid = std::this_thread::get_id(); + if (FEOptions::GetInstance().GetDumpLevel() >= FEOptions::kDumpLevelInfoDebug) { + INFO(kLncInfo, "Start Run Thread (tid=%lx)", tid); + } + FEConfigParallel::GetInstance().RegisterRunThreadID(tid); +} +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_BC_PARSER_INL_H_ \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/bc_parser.h b/src/hir2mpl/bytecode_input/common/include/bc_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..92189e8e6803d03cfee5976459bbd916d019724f --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_parser.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL_FE_BC_INPUT_BC_PARSER_H +#define MPL_FE_BC_INPUT_BC_PARSER_H +#include +#include +#include +#include "bc_io.h" +#include "bc_class.h" +#include "bc_parser_base.h" +#include "mpl_scheduler.h" +#include "fe_options.h" + +namespace maple { +namespace bc { +template +class BCParser : public BCParserBase { + public: + BCParser(uint32 fileIdxIn, const std::string &fileNameIn, const std::list &classNamesIn); + ~BCParser() = default; + + protected: + bool OpenFileImpl(); + uint32 CalculateCheckSumImpl(const uint8 *data, uint32 size) = 0; + bool ParseHeaderImpl() = 0; + bool VerifyImpl() = 0; + virtual bool RetrieveIndexTables() = 0; + bool RetrieveUserSpecifiedClasses(std::list> &klasses) = 0; + bool RetrieveAllClasses(std::list> &klasses) = 0; + bool CollectAllDepTypeNamesImpl(std::unordered_set &depSet) = 0; + bool CollectMethodDepTypeNamesImpl(std::unordered_set &depSet, BCClassMethod &bcMethod) const = 0; + bool CollectAllClassNamesImpl(std::unordered_set &classSet) = 0; + + std::unique_ptr reader; +}; + +template +class MethodProcessTask : public MplTask { + public: + MethodProcessTask(T &argParser, std::unique_ptr &argKlass, + bool argIsVirtual, uint32 index, std::pair argIdxPair) + : isVirtual(argIsVirtual), + index(index), + klass(argKlass), + idxPair(argIdxPair), + parser(argParser) {} + virtual ~MethodProcessTask() = default; + + protected: + int RunImpl(MplTaskParam *param) override; + int FinishImpl(MplTaskParam *param) override; + + private: + bool isVirtual; + uint32 index; + std::unique_ptr &klass; + std::pair idxPair; + T &parser; +}; + +template +class MethodProcessSchedular : public MplScheduler { + public: + MethodProcessSchedular(const std::string &name) + : MplScheduler(name) {} + ~MethodProcessSchedular() { + FEConfigParallel::GetInstance().RunThreadIDCleanUp(); + } + + void AddMethodProcessTask(T &parser, std::unique_ptr &klass, + bool isVirtual, uint32 index, std::pair &idxPair); + void SetDumpTime(bool arg) { + dumpTime = arg; + } + + protected: + void CallbackThreadMainStart() override; + + private: + std::list>> tasks; +}; +} // namespace bc +} // namespace maple +#include "bc_parser-inl.h" +#endif // MPL_FE_BC_INPUT_BC_PARSER_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/bc_parser_base.h b/src/hir2mpl/bytecode_input/common/include/bc_parser_base.h new file mode 100644 index 0000000000000000000000000000000000000000..e23f02d9a2720dac3b38d74531d4c8398493ce85 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_parser_base.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_BC_PARSER_BASE_H +#define HIR2MPL_BC_INPUT_INCLUDE_BC_PARSER_BASE_H +#include +#include +#include +#include "types_def.h" +#include "bc_io.h" + +namespace maple { +namespace bc { +class BCClass; +class BCClassMethod; +class BCParserBase { + public: + BCParserBase(uint32 fileIdxIn, const std::string &fileNameIn, const std::list &classNamesIn); + virtual ~BCParserBase() = default; + bool OpenFile(); + bool ParseHeader(); + bool Verify(); + int32 GetFileNameHashId() const { + return fileNameHashId; + } + uint32 CalculateCheckSum(const uint8 *data, uint32 size); + bool RetrieveClasses(std::list> &klasses); + const BCReader *GetReader() const; + bool CollectAllDepTypeNames(std::unordered_set &depSet); + bool CollectMethodDepTypeNames(std::unordered_set &depSet, BCClassMethod &bcMethod) const; + bool CollectAllClassNames(std::unordered_set &classSet); + void ProcessMethodBody(BCClassMethod &method, uint32 classIdx, uint32 methodItemIdx, bool isVirtual) const { + ProcessMethodBodyImpl(method, classIdx, methodItemIdx, isVirtual); + } + + protected: + virtual const BCReader *GetReaderImpl() const = 0; + virtual bool OpenFileImpl() = 0; + virtual uint32 CalculateCheckSumImpl(const uint8 *data, uint32 size) = 0; + virtual bool ParseHeaderImpl() = 0; + virtual bool VerifyImpl() = 0; + virtual bool RetrieveIndexTables() = 0; + virtual bool RetrieveUserSpecifiedClasses(std::list> &klasses) = 0; + virtual bool RetrieveAllClasses(std::list> &klasses) = 0; + virtual bool CollectAllDepTypeNamesImpl(std::unordered_set &depSet) = 0; + virtual bool CollectMethodDepTypeNamesImpl(std::unordered_set &depSet, + BCClassMethod &bcMethod) const = 0; + virtual bool CollectAllClassNamesImpl(std::unordered_set &classSet) = 0; + virtual void ProcessMethodBodyImpl(BCClassMethod &method, + uint32 classIdx, uint32 methodItemIdx, bool isVirtual) const = 0; + + uint32 fileIdx; + const std::string fileName; + const std::list &classNames; + const int32 fileNameHashId; +}; +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_BC_PARSER_BASE_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/bc_pragma.h b/src/hir2mpl/bytecode_input/common/include/bc_pragma.h new file mode 100644 index 0000000000000000000000000000000000000000..28258bd93c246f40d46ae2a3ff611d5252e19004 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_pragma.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_BC_PRAGMA_H +#define HIR2MPL_BC_INPUT_INCLUDE_BC_PRAGMA_H +#include +#include +#include +#include "mir_module.h" +#include "mir_pragma.h" +#include "mempool.h" + +namespace maple { +namespace bc { +class BCAnnotationsDirectory { + public: + BCAnnotationsDirectory(MIRModule &moduleArg, MemPool &mpArg) + : module(moduleArg), mp(mpArg) {} + virtual ~BCAnnotationsDirectory() = default; + std::vector &EmitPragmas() { + return EmitPragmasImpl(); + } + + protected: + virtual std::vector &EmitPragmasImpl() = 0; + MIRModule &module; + MemPool ∓ + std::vector pragmas; +}; +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_BC_PRAGMA_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/bc_util.h b/src/hir2mpl/bytecode_input/common/include/bc_util.h new file mode 100644 index 0000000000000000000000000000000000000000..43ba35277f48bb07c5ba9b355515bf349ecd96f6 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/bc_util.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_BC_UTIL_H +#define HIR2MPL_BC_INPUT_INCLUDE_BC_UTIL_H +#include +#include +#include +#include +#include "types_def.h" +#include "cfg_primitive_types.h" +#include "global_tables.h" +namespace maple { +namespace bc { +enum BCInstructionKind : uint16 { + kUnKnownKind = 0, + kFallThru = 0x0001, + kConditionBranch = 0x0002, + kGoto = 0x0004, + kSwitch = 0x0008, + kTarget = 0x0010, + kTryStart = 0x0020, + kTryEnd = 0x0040, + kCatch = 0x0080, + kReturn = 0x0100, +}; + +enum BCRegVarType { + kUnknownType = 0, + kPrimitive = 1, + kBoolean = 3, + kLong = 17, + kFloat = 33, + kDouble = 65, + kRef = 2, +}; + +class BCUtil { + public: + static const std::string kUnknown; + static const std::string kPrimitive; + static const std::string kBoolean; + static const std::string kByte; + static const std::string kChar; + static const std::string kShort; + static const std::string kInt; + static const std::string kLong; + static const std::string kFloat; + static const std::string kDouble; + static const std::string kVoid; + static const std::string kWide; + static const std::string kAggregate; + static const std::string kJavaObjectName; + static const std::string kJavaStringName; + static const std::string kJavaByteClassName; + static const std::string kJavaShortClassName; + static const std::string kJavaIntClassName; + static const std::string kJavaLongClassName; + static const std::string kJavaFloatClassName; + static const std::string kJavaDoubleClassName; + static const std::string kJavaCharClassName; + static const std::string kJavaBoolClassName; + static const std::string kJavaClassName; + static const std::string kJavaMethodHandleName; + static const std::string kJavaExceptionName; + static const std::string kJavaThrowableName; + + static const std::string kJavaMethodHandleInvoke; + static const std::string kJavaMethodHandleInvokeExact; + + static const std::string kABoolean; + static const std::string kAByte; + static const std::string kAShort; + static const std::string kAChar; + static const std::string kAInt; + static const std::string kALong; + static const std::string kAFloat; + static const std::string kADouble; + static const std::string kAJavaObjectName; + + static inline GStrIdx &GetBooleanIdx() { + static GStrIdx booleanIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kBoolean); + return booleanIdx; + } + + static inline GStrIdx &GetIntIdx() { + static GStrIdx intIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kInt); + return intIdx; + } + + static inline GStrIdx &GetLongIdx() { + static GStrIdx longIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kLong); + return longIdx; + } + + static inline GStrIdx &GetFloatIdx() { + static GStrIdx floatIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kFloat); + return floatIdx; + } + + static inline GStrIdx &GetDoubleIdx() { + static GStrIdx doubleIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kDouble); + return doubleIdx; + } + + static inline GStrIdx &GetByteIdx() { + static GStrIdx byteIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kByte); + return byteIdx; + } + + static inline GStrIdx &GetCharIdx() { + static GStrIdx charIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kChar); + return charIdx; + } + + static inline GStrIdx &GetShortIdx() { + static GStrIdx shortIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kShort); + return shortIdx; + } + + static inline GStrIdx &GetVoidIdx() { + static GStrIdx voidIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kVoid); + return voidIdx; + } + + static inline GStrIdx &GetJavaObjectNameMplIdx() { + static GStrIdx javaObjectNameMplIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(kJavaObjectName)); + return javaObjectNameMplIdx; + } + + static inline GStrIdx &GetJavaStringNameMplIdx() { + static GStrIdx javaStringNameMplIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(kJavaStringName)); + return javaStringNameMplIdx; + } + + static inline GStrIdx &GetJavaClassNameMplIdx() { + static GStrIdx javaClassNameMplIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(kJavaClassName)); + return javaClassNameMplIdx; + } + + static inline GStrIdx &GetJavaExceptionNameMplIdx() { + static GStrIdx javaExceptionNameMplIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(kJavaExceptionName)); + return javaExceptionNameMplIdx; + } + + static inline GStrIdx &GetJavaThrowableNameMplIdx() { + static GStrIdx javaThrowableNameMplIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(kJavaThrowableName)); + return javaThrowableNameMplIdx; + } + + static inline GStrIdx &GetJavaMethodHandleNameMplIdx() { + static GStrIdx javaMethodHandleNameMplIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(kJavaMethodHandleName)); + return javaMethodHandleNameMplIdx; + } + + static inline GStrIdx &GetABooleanIdx() { + static GStrIdx aBooleanIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kABoolean); + return aBooleanIdx; + } + + static inline GStrIdx &GetAIntIdx() { + static GStrIdx aIntIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kAInt); + return aIntIdx; + } + + static inline GStrIdx &GetALongIdx() { + static GStrIdx aLongIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kALong); + return aLongIdx; + } + + static inline GStrIdx &GetAByteIdx() { + static GStrIdx aByteIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kAByte); + return aByteIdx; + } + + static inline GStrIdx &GetACharIdx() { + static GStrIdx aCharIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kAChar); + return aCharIdx; + } + + static inline GStrIdx &GetAShortIdx() { + static GStrIdx aShortIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kAShort); + return aShortIdx; + } + + static inline GStrIdx &GetAFloatIdx() { + static GStrIdx aFloatIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kAFloat); + return aFloatIdx; + } + + static inline GStrIdx &GetADoubleIdx() { + static GStrIdx aDoubleIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kADouble); + return aDoubleIdx; + } + + static inline GStrIdx &GetAJavaObjectNameMplIdx() { + static GStrIdx aJavaObjectNameMplIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(kAJavaObjectName)); + return aJavaObjectNameMplIdx; + } + + // JavaMultiANewArray + static inline GStrIdx &GetMultiANewArrayFullIdx() { + static GStrIdx multiANewArrayFullIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::EncodeName("Ljava/lang/reflect/Array;|newInstance|(Ljava/lang/Class;[I)Ljava/lang/Object;")); + return multiANewArrayFullIdx; + } + + static inline GStrIdx &GetMultiANewArrayClassIdx() { + static GStrIdx multiANewArrayClassIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::EncodeName("Ljava/lang/reflect/Array;")); + return multiANewArrayClassIdx; + } + + static inline GStrIdx &GetMultiANewArrayElemIdx() { + static GStrIdx multiANewArrayElemIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::EncodeName("newInstance")); + return multiANewArrayElemIdx; + } + + static inline GStrIdx &GetMultiANewArrayTypeIdx() { + static GStrIdx multiANewArrayTypeIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::EncodeName("(Ljava/lang/Class;[I)Ljava/lang/Object;")); + return multiANewArrayTypeIdx; + } + + // value element name + static inline GStrIdx &GetPragmaElementNameValueIdx() { + static GStrIdx pragmaElementNameValueIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("value"); + return pragmaElementNameValueIdx; + } + + static bool IsWideType(const GStrIdx &name); + static bool IsMorePrecisePrimitiveType(const GStrIdx &name0, const GStrIdx &name1); + static PrimType GetPrimType(const GStrIdx &name); + static bool IsJavaReferenceType(const GStrIdx &typeNameIdx); + static bool IsJavaPrimitveType(const GStrIdx &typeNameIdx); + static bool IsJavaPrimitiveTypeName(const std::string typeName); + static bool IsArrayType(const GStrIdx &typeNameIdx); + static std::string TrimArrayModifier(const std::string &typeName); + static void AddDefaultDepSet(std::unordered_set &typeSet); + static uint32 Name2RegNum(const std::string &name); + static bool HasContainSuffix(const std::string &value, const std::string &suffix); +}; // BCUtil +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_BC_UTIL_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/include/rc_setter.h b/src/hir2mpl/bytecode_input/common/include/rc_setter.h new file mode 100644 index 0000000000000000000000000000000000000000..9bdaf2a0622eea1d8651fdc1ede6de52f224a05a --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/include/rc_setter.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef BC_INPUT_INCLUDE_RC_SETTER_H +#define BC_INPUT_INCLUDE_RC_SETTER_H +#include +#include +#include +#include "types_def.h" +#include "bc_class.h" +#include "mir_type.h" +#include "mir_function.h" + +namespace maple { +namespace bc { +class RCSetter { + public: + static RCSetter &GetRCSetter() { + ASSERT(rcSetter != nullptr, "rcSetter is not initialize"); + return *rcSetter; + } + + static void InitRCSetter(const std::string &whiteListName) { + rcSetter = new RCSetter(whiteListName); + } + + static void ReleaseRCSetter() { + if (rcSetter != nullptr) { + delete rcSetter; + rcSetter = nullptr; + } + } + + void ProcessClassRCAnnotation(const GStrIdx &classIdx, const std::vector &pragmas); + void ProcessMethodRCAnnotation(MIRFunction &mirFunc, const std::string &className, + MIRStructType &structType, const MIRPragma &pragma); + void ProcessFieldRCAnnotation(const StructElemNameIdx &fieldElemNameIdx, + const MIRType &fieldType, const std::vector &pragmas); + void GetUnownedVarInLocalVars(const BCClassMethod &method, MIRFunction &mirFunction); + void CollectUnownedLocalFuncs(MIRFunction *func); + void CollectUnownedLocalVars(MIRFunction *func, const GStrIdx &strIdx); + void CollectInputStmtField(StmtNode *stmt, const GStrIdx &fieldName); + void SetRCFieldAttrByWhiteList(FieldAttrs &attr, const std::string &className, const std::string &fieldName); + void SetAttrRCunowned(MIRFunction &mirFunction, const std::set &unownedRegNums) const; + void MarkRCAttributes() const; + + private: + explicit RCSetter(const std::string &whiteListName) : rcFieldAttrWhiteListName(whiteListName) { + if (!rcFieldAttrWhiteListName.empty()) { + LoadRCFieldAttrWhiteList(rcFieldAttrWhiteListName); + } + } + ~RCSetter() = default; + void MarkRCUnownedForUnownedLocalFunctions() const; + void MarkRCUnownedForAnonymousClasses() const; + void MarkRCUnownedForLambdaClasses() const; + void SetRCUnownedAttributeInternalSetFieldAttrRCUnowned(size_t opnd, const MIRFunction &calledFunc) const; + void SetRCUnownedAttribute(const CallNode &callNode, MIRFunction &func, + const MIRFunction &calledFunc, const std::set &gStrIdx) const; + bool IsAnonymousInner(const MIRStructType &structType) const; + bool IsMethodEnclosing(const MIRFunction &func, const MIRStructType &structType) const; + void LoadRCFieldAttrWhiteList(const std::string &file); + + static RCSetter *rcSetter; + const std::string rcFieldAttrWhiteListName; + std::map>> rcFieldAttrWhiteListMap; + std::set unownedLocalFuncs; + std::map> unownedLocalVars; + std::map iputStmtFieldMap; +}; +} // namespace bc +} // namespace maple +#endif // BC_INPUT_INCLUDE_RC_SETTER_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/src/ark_annotation_map.cpp b/src/hir2mpl/bytecode_input/common/src/ark_annotation_map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d10ec2577cef7167d76e99e10cad722f5357c3a5 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/src/ark_annotation_map.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ark_annotation_map.h" + +namespace maple { +namespace bc { +ArkAnnotationMap ArkAnnotationMap::annotationMap; + +void ArkAnnotationMap::Init() { + // AnnotationDefault + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FAnnotationDefault_3B", + "Lark_2Fannotation_2FAnnotationDefault_3B")); + // EnclosingClass + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FEnclosingClass_3B", + "Lark_2Fannotation_2FEnclosingClass_3B")); + // EnclosingMethod + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FEnclosingMethod_3B", + "Lark_2Fannotation_2FEnclosingMethod_3B")); + // InnerClass + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FInnerClass_3B", + "Lark_2Fannotation_2FInnerClass_3B")); + // KnownFailure + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FKnownFailure_3B", + "Lark_2Fannotation_2FKnownFailure_3B")); + // MemberClasses + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FMemberClasses_3B", + "Lark_2Fannotation_2FMemberClasses_3B")); + // MethodParameters + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FMethodParameters_3B", + "Lark_2Fannotation_2FMethodParameters_3B")); + // Signature + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FSignature_3B", + "Lark_2Fannotation_2FSignature_3B")); + // SourceDebugExtension + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FSourceDebugExtension_3B", + "Lark_2Fannotation_2FSourceDebugExtension_3B")); + // TestTargetClass + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FTestTargetClass_3B", + "Lark_2Fannotation_2FTestTargetClass_3B")); + // TestTarget + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FTestTarget_3B", + "Lark_2Fannotation_2FTestTarget_3B")); + // Throws + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2FThrows_3B", + "Lark_2Fannotation_2FThrows_3B")); + // compact + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2Fcompat_2FUnsupportedAppUsage_3B", + "Lark_2Fannotation_2Fcompat_2FUnsupportedAppUsage_3B")); + // codegen + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2Fcodegen_2FCovariantReturnType_3B", + "Lark_2Fannotation_2Fcodegen_2FCovariantReturnType_3B")); + // optimization + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2Foptimization_2FCriticalNative_3B", + "Lark_2Fannotation_2Foptimization_2FCriticalNative_3B")); + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2Foptimization_2FDeadReferenceSafe_3B", + "Lark_2Fannotation_2Foptimization_2FDeadReferenceSafe_3B")); + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2Foptimization_2FFastNative_3B", + "Lark_2Fannotation_2Foptimization_2FFastNative_3B")); + pragmaTypeNameMap.insert(std::make_pair("Ldalvik_2Fannotation_2Foptimization_2FReachabilitySensitive_3B", + "Lark_2Fannotation_2Foptimization_2FReachabilitySensitive_3B")); + for (auto &it : pragmaTypeNameMap) { + (void)arkAnnotationTypeNames.insert(it.second); + } +} + +const std::string &ArkAnnotationMap::GetAnnotationTypeName(const std::string &orinName) { + std::map::iterator it = pragmaTypeNameMap.find(orinName); + if (it == pragmaTypeNameMap.end()) { + return orinName; + } else { + return it->second; + } +} +} // namespace bc +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/src/ark_annotation_processor.cpp b/src/hir2mpl/bytecode_input/common/src/ark_annotation_processor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..86d37127bc922c06fd2286071018347d6729368f --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/src/ark_annotation_processor.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ark_annotation_processor.h" +#include "ark_annotation_map.h" +#include "fe_manager.h" +#include "mpl_logging.h" +namespace maple { +namespace bc { +void ArkAnnotationProcessor::Process() { + ArkAnnotationMap::GetArkAnnotationMap().Init(); + ArkAnnotation::GetInstance().Init(); + const std::set &arkAnnotationTypeNames = + ArkAnnotationMap::GetArkAnnotationMap().GetArkAnnotationTypeNames(); + for (const std::string &arkAnnotationTypeName : arkAnnotationTypeNames) { + (void)FEManager::GetTypeManager().CreateClassOrInterfaceType(arkAnnotationTypeName, true, FETypeFlag::kSrcUnknown); + } +} + +// ---------- ArkAnnotation ---------- +ArkAnnotation ArkAnnotation::instance; + +void ArkAnnotation::Init() { + // FastNative + typeNameSetForFastNative.insert(GetStrIdxFromDexName("Ldalvik/annotation/optimization/FastNative;")); + typeNameSetForFastNative.insert(GetStrIdxFromDexName("Lark/annotation/optimization/FastNative;")); + // CriticalNative + typeNameSetForCriticalNative.insert(GetStrIdxFromDexName("Ldalvik/annotation/optimization/CriticalNative;")); + typeNameSetForCriticalNative.insert(GetStrIdxFromDexName("Lark/annotation/optimization/CriticalNative;")); + // CallerSensitive + typeNameSetForCallerSensitive.insert(GetStrIdxFromDexName("Lsun/reflect/CallerSensitive;")); + // Permanent + typeNameSetForPermanent.insert(GetStrIdxFromDexName("Lcom/huawei/ark/annotation/Permanent;")); + typeNameSetForPermanent.insert(GetStrIdxFromDexName("Lharmonyos/annotation/Permanent;")); + typeNameSetForPermanent.insert(GetStrIdxFromDexName("Lark/annotation/Permanent;")); + // RCU + typeNameSetForRCUnowned.insert(GetStrIdxFromDexName("Ljava/lang/annotation/RCUnownedRef;")); + typeNameSetForRCUnowned.insert(GetStrIdxFromDexName("Lcom/huawei/ark/annotation/Unowned;")); + typeNameSetForRCUnowned.insert(GetStrIdxFromDexName("Lharmonyos/annotation/Unowned;")); + typeNameSetForRCUnowned.insert(GetStrIdxFromDexName("Lark/annotation/Unowned;")); + // RCUnownedCap + typeNameSetForRCUnownedCap.insert(GetStrIdxFromDexName("Ljava/lang/annotation/RCUnownedCapRef;")); + // RCUnownedCapList + typeNameSetForRCUnownedCapList.insert(GetStrIdxFromDexName("Ljava/lang/annotation/RCUnownedCapRef$List;")); + // RCUnownedLocal + typeNameSetForRCUnownedLocal.insert(GetStrIdxFromDexName("Lcom/huawei/ark/annotation/UnownedLocal;")); + typeNameSetForRCUnownedLocal.insert(GetStrIdxFromDexName("Lharmonyos/annotation/UnownedLocal;")); + typeNameSetForRCUnownedLocal.insert(GetStrIdxFromDexName("Lark/annotation/UnownedLocal;")); + // RCUnownedLocalOld + typeNameIdxForRCUnownedLocalOld = GetStrIdxFromDexName("Ljava/lang/annotation/RCLocalUnownedRef;"); + // RCUnownedThis + typeNameSetForRCUnownedThis.insert(GetStrIdxFromDexName("Ljava/lang/annotation/RCUnownedThisRef;")); + // RCUnownedOuter + typeNameSetForRCUnownedOuter.insert(GetStrIdxFromDexName("Lcom/huawei/ark/annotation/UnownedOuter;")); + typeNameSetForRCUnownedOuter.insert(GetStrIdxFromDexName("Lharmonyos/annotation/UnownedOuter;")); + typeNameSetForRCUnownedOuter.insert(GetStrIdxFromDexName("Lark/annotation/UnownedOuter;")); + // RCWeak + typeNameSetForRCWeak.insert(GetStrIdxFromDexName("Ljava/lang/annotation/RCWeakRef;")); + typeNameSetForRCWeak.insert(GetStrIdxFromDexName("Lcom/huawei/ark/annotation/Weak;")); + typeNameSetForRCWeak.insert(GetStrIdxFromDexName("Lharmonyos/annotation/Weak;")); + typeNameSetForRCWeak.insert(GetStrIdxFromDexName("Lark/annotation/Weak;")); +} + +bool ArkAnnotation::IsFastNative(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameSetForFastNative.find(sType->GetNameStrIdx()) != typeNameSetForFastNative.end(); +} + +bool ArkAnnotation::IsCriticalNative(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameSetForCriticalNative.find(sType->GetNameStrIdx()) != typeNameSetForCriticalNative.end(); +} + +bool ArkAnnotation::IsCallerSensitive(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameSetForCallerSensitive.find(sType->GetNameStrIdx()) != typeNameSetForCallerSensitive.end(); +} + +bool ArkAnnotation::IsPermanent(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameSetForPermanent.find(sType->GetNameStrIdx()) != typeNameSetForPermanent.end(); +} + +bool ArkAnnotation::IsPermanent(const std::string &str) const { + for (auto idx : typeNameSetForPermanent) { + std::string annoName = GlobalTables::GetStrTable().GetStringFromStrIdx(idx); + annoName = namemangler::DecodeName(annoName); + if (annoName.compare(str) == 0) { + return true; + } + } + return false; +} + +bool ArkAnnotation::IsRCUnowned(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameSetForRCUnowned.find(sType->GetNameStrIdx()) != typeNameSetForRCUnowned.end(); +} + +bool ArkAnnotation::IsRCUnownedCap(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameSetForRCUnownedCap.find(sType->GetNameStrIdx()) != typeNameSetForRCUnownedCap.end(); +} + +bool ArkAnnotation::IsRCUnownedCapList(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameSetForRCUnownedCapList.find(sType->GetNameStrIdx()) != typeNameSetForRCUnownedCapList.end(); +} + +bool ArkAnnotation::IsRCUnownedLocal(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameSetForRCUnownedLocal.find(sType->GetNameStrIdx()) != typeNameSetForRCUnownedLocal.end(); +} + +bool ArkAnnotation::IsRCUnownedLocalOld(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameIdxForRCUnownedLocalOld == sType->GetNameStrIdx(); +} + +bool ArkAnnotation::IsRCUnownedThis(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameSetForRCUnownedThis.find(sType->GetNameStrIdx()) != typeNameSetForRCUnownedThis.end(); +} + +bool ArkAnnotation::IsRCUnownedOuter(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameSetForRCUnownedOuter.find(sType->GetNameStrIdx()) != typeNameSetForRCUnownedOuter.end(); +} + +bool ArkAnnotation::IsRCWeak(const TyIdx &tyIdx) const { + MIRStructType *sType = GetStructType(tyIdx); + return sType == nullptr ? + false : typeNameSetForRCWeak.find(sType->GetNameStrIdx()) != typeNameSetForRCWeak.end(); +} + +MIRStructType *ArkAnnotation::GetStructType(const TyIdx &tyIdx) { + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + if (!type->IsMIRClassType() && !type->IsMIRInterfaceType()) { + return nullptr; + } + return static_cast(type); +} +} // namespace bc +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/src/bc_class.cpp b/src/hir2mpl/bytecode_input/common/src/bc_class.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1cfb6e5ac6be776790882c66d9bfdc5e29489ab2 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/src/bc_class.cpp @@ -0,0 +1,601 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "bc_class.h" +#include "global_tables.h" +#include "fe_utils_java.h" +#include "fe_utils.h" +#include "fe_manager.h" +#include "fe_options.h" + +namespace maple { +namespace bc { +// ========== BCClassElem ========== +BCClassElem::BCClassElem(const BCClass &klassIn, uint32 acc, const std::string &nameIn, const std::string &descIn) + : klass(klassIn), + accessFlag(acc), + name(nameIn), + descriptor(descIn) {} + +const std::string &BCClassElem::GetName() const { + return name; +} + +const std::string &BCClassElem::GetDescription() const { + return descriptor; +} + +uint32 BCClassElem::GetItemIdx() const { + return GetItemIdxImpl(); +} + +uint32 BCClassElem::GetIdx() const { + return GetIdxImpl(); +} + +uint32 BCClassElem::GetAccessFlag() const { + return accessFlag; +} + +bool BCClassElem::IsStatic() const { + return IsStaticImpl(); +} + +const std::string &BCClassElem::GetClassName() const { + return klass.GetClassName(false); +} + +GStrIdx BCClassElem::GetClassNameMplIdx() const { + return klass.GetClassNameMplIdx(); +} + +const BCClass &BCClassElem::GetBCClass() const { + return klass; +} + +// ========== BCTryInfo ========== +void BCTryInfo::DumpTryCatchInfo(const std::unique_ptr>> &tryInfos) { + DEBUG_STMT( + for (const auto &tryInfo : *tryInfos) { + LogInfo::MapleLogger(kLlDbg) << "tryBlock: [" << std::hex << "0x" << tryInfo->GetStartAddr() << ", 0x" << + tryInfo->GetEndAddr() << ")"; + LogInfo::MapleLogger(kLlDbg) << " handler: "; + for (const auto &e : (*tryInfo->GetCatches())) { + LogInfo::MapleLogger(kLlDbg) << "0x" << e->GetHandlerAddr() << " "; + } + LogInfo::MapleLogger(kLlDbg) << std::endl; + }) +} + +// ========== BCClassMethod ========== +void BCClassMethod::SetMethodInstOffset(const uint16 *pos) { + instPos = pos; +} + +void BCClassMethod::SetRegisterTotalSize(uint16 size) { + registerTotalSize = size; +} + +uint16 BCClassMethod::GetRegisterTotalSize() const{ + return registerTotalSize; +} + +void BCClassMethod::SetCodeOff(uint32 off) { + codeOff = off; +} + +uint32 BCClassMethod::GetCodeOff() const { + return codeOff; +} + +void BCClassMethod::SetRegisterInsSize(uint16 size) { + registerInsSize = size; +} + +bool BCClassMethod::IsVirtual() const { + return IsVirtualImpl(); +} + +bool BCClassMethod::IsNative() const { + return IsNativeImpl(); +} + +bool BCClassMethod::IsInit() const { + return IsInitImpl(); +} + +bool BCClassMethod::IsClinit() const { + return IsClinitImpl(); +} + +std::string BCClassMethod::GetFullName() const { + return GetClassName() + "|" + GetName() + "|" + GetDescription(); +} + +void BCClassMethod::SetSrcPosInfo() { +#ifdef DEBUG + if ((FEOptions::GetInstance().IsDumpComment() || FEOptions::GetInstance().IsDumpLOC()) && + pSrcPosInfo != nullptr) { + uint32 srcPos = 0; + for (auto &[pos, inst] : *pcBCInstructionMap) { + auto it = pSrcPosInfo->find(pos); + if (it != pSrcPosInfo->end()) { + srcPos = it->second; // when pSrcPosInfo is valid, update srcPos + } + inst->SetSrcPositionInfo(klass.GetSrcFileIdx(), srcPos); + } + } +#endif +} + +void BCClassMethod::ProcessInstructions() { + if (pcBCInstructionMap->empty()) { + return; + } + // some instructions depend on exception handler, so we process try-catch info first + ProcessTryCatch(); + visitedPcSet.emplace(pcBCInstructionMap->begin()->first); + GStrIdx methodIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(GetFullName())); + for (auto itor = pcBCInstructionMap->begin(); itor != pcBCInstructionMap->end();) { + BCInstruction *inst = itor->second; + inst->SetFuncNameIdx(methodIdx); + inst->Parse(*this); + ++itor; + if (inst->IsConditionBranch() || inst->IsGoto() || inst->IsSwitch()) { + std::vector targets = inst->GetTargets(); + for (uint32 target : targets) { + auto it = pcBCInstructionMap->find(target); + CHECK_FATAL(it != pcBCInstructionMap->end(), "Invalid branch target 0x%x in method: %s", + target, GetFullName().c_str()); + it->second->SetInstructionKind(kTarget); + if (visitedPcSet.emplace(target).second == false) { + multiInDegreeSet.emplace(target); + } + } + if (inst->IsSwitch() && itor != pcBCInstructionMap->end()) { + itor->second->SetInstructionKind(kTarget); + inst->SetDefaultTarget(itor->second); + } + } + if (itor == pcBCInstructionMap->end()) { + continue; + } + if (inst->IsFallThru()) { + if (visitedPcSet.emplace(itor->first).second == false) { + multiInDegreeSet.emplace(itor->first); + } + } + if (itor->second->IsReturn()) { + inst->SetReturnInst(itor->second); + } + } + SetSrcPosInfo(); + if (FEOptions::GetInstance().GetTypeInferKind() == FEOptions::kLinearScan) { + TypeInfer(); + } +} + +void BCClassMethod::ProcessTryCatch() { + if (tryInfos == nullptr) { + return; + } + for (const auto &e : *tryInfos) { + uint32 tryStart = e->GetStartAddr(); + uint32 tryEnd = e->GetEndAddr(); + auto it = pcBCInstructionMap->find(tryStart); + CHECK_FATAL(it != pcBCInstructionMap->end(), "Invalid try start pos 0x%x in method: %s", tryStart, + GetFullName().c_str()); + it->second->SetInstructionKind(kTryStart); + BCInstruction *inst = it->second; + auto it1 = pcBCInstructionMap->find(tryEnd); + if (tryStart == tryEnd) { + it->second->SetInstructionKind(kTryEnd); + } else if (it1 != pcBCInstructionMap->end()) { + --it1; + it1->second->SetInstructionKind(kTryEnd); + } else { + // behind the last instruction + pcBCInstructionMap->rbegin()->second->SetInstructionKind(kTryEnd); + } + // Calculate catchable instructions + std::list catchableInsts; + while (it->second->GetPC() < tryEnd) { + it->second->SetCatchable(); + if (it->second->IsCatchable()) { + catchableInsts.emplace_back(it->second); + } + ++it; + if (it == pcBCInstructionMap->end()) { + break; + } + } + for (const auto &handler: *(e->GetCatches())) { + uint32 handlerPc = handler->GetHandlerAddr(); + auto elem = pcBCInstructionMap->find(handlerPc); + CHECK_FATAL(elem != pcBCInstructionMap->end(), "Invalid catch pos 0x%x in method: %s", handlerPc, + GetFullName().c_str()); + elem->second->SetInstructionKind(kCatch); + elem->second->SetExceptionType(handler->GetExceptionNameIdx()); + inst->AddHandler(elem->second); + for (auto catchableInst : catchableInsts) { + catchableInst->AddHandlerTarget(handlerPc); + if (visitedPcSet.emplace(handlerPc).second == false) { + multiInDegreeSet.emplace(handlerPc); + } + } + } + } +} + +// Use linear scan with SSA +// We insert phi behind the def in a edge before the dominance if the reg is alive under this dominance. +// A reg is default dead at its definition, we mark a reg alive only when it was used. +// And insert the reg def-type into `used alive types` if it is defined in a determinate type. +// We transfer reg live info through shared memory, record live-interval in dominancesMap and BCRegType::livesBegins. +// After a multi-in pos, we create a new TypeInferItem for a new live range. +// Insert `in-edge` into dominance `prevs`, for record complete reg use in circles by one pass. +void BCClassMethod::TypeInfer() { + std::set visitedSet; + // [pc, [regNum, TypeInferItem*]] + std::list>> pcDefedRegsList; + // [pc, [regNum, TypeInferItem*]] + std::vector> dominances((*pcBCInstructionMap).rbegin()->first + 1); + std::vector regTypeMap(registerTotalSize, nullptr); + for (auto ® : argRegs) { + regTypeMap[reg->regNum] = ConstructTypeInferItem(allocator, 0, reg.get(), nullptr); + regTypes.emplace_back(reg->regType); + } + visitedSet.emplace(0); + if (multiInDegreeSet.find(0) != multiInDegreeSet.end()) { + std::vector typeMap = ConstructNewRegTypeMap(allocator, 1, regTypeMap); + pcDefedRegsList.emplace_front(0, typeMap); + dominances[0] = typeMap; + } else { + pcDefedRegsList.emplace_front(0, regTypeMap); + } + Traverse(pcDefedRegsList, dominances, visitedSet); + PrecisifyRegType(); +} + +void BCClassMethod::Traverse(std::list>> &pcDefedRegsList, + std::vector> &dominances, std::set &visitedSet) { + while (!pcDefedRegsList.empty()) { + auto head = pcDefedRegsList.front(); + pcDefedRegsList.pop_front(); + BCInstruction *currInst = (*pcBCInstructionMap)[head.first]; + std::vector nextRegTypeMap = head.second; + auto usedRegs = currInst->GetUsedRegs(); + for (auto usedReg : *usedRegs) { + auto defedItem = nextRegTypeMap[usedReg->regNum]; + CHECK_FATAL(defedItem != nullptr && defedItem->reg != nullptr, + "Cannot find Reg%u defination at 0x%x:0x%x in method %s", + usedReg->regNum, head.first, currInst->GetOpcode(), GetFullName().c_str()); + usedReg->regValue = defedItem->reg->regValue; + usedReg->regType = defedItem->reg->regType; + currInst->SetRegTypeInTypeInfer(); + // Make the reg alive when it used, live range [defPos, usePos] + usedReg->regTypeItem->SetPos(currInst->GetPC()); + defedItem->InsertUniqueAliveType(nullptr, usedReg->regTypeItem); + } + auto defedRegs = currInst->GetDefedRegs(); + auto exHandlerTargets = currInst->GetHandlerTargets(); + uint32 next = currInst->GetPC() + currInst->GetWidth(); + for (auto exHandlerTarget : exHandlerTargets) { + if (visitedSet.emplace(exHandlerTarget).second == false) { + auto &domIt = dominances[exHandlerTarget]; + InsertPhi(domIt, nextRegTypeMap); + continue; + } + if ((multiInDegreeSet.find(exHandlerTarget) != multiInDegreeSet.end())) { + std::vector typeMap = ConstructNewRegTypeMap(allocator, exHandlerTarget + 1, nextRegTypeMap); + pcDefedRegsList.emplace_front(exHandlerTarget, typeMap); + dominances[exHandlerTarget] = typeMap; + } else { + pcDefedRegsList.emplace_front(exHandlerTarget, nextRegTypeMap); + } + Traverse(pcDefedRegsList, dominances, visitedSet); + } + for (auto defedReg : *defedRegs) { + TypeInferItem *item = ConstructTypeInferItem(allocator, currInst->GetPC() + 1, defedReg, nullptr); + nextRegTypeMap[defedReg->regNum] = item; + defedReg->regType->SetPos(currInst->GetPC()); + regTypes.emplace_back(defedReg->regType); + } + if (currInst->IsFallThru() && next <= pcBCInstructionMap->rbegin()->first) { + if (visitedSet.emplace(next).second == false) { + auto &domIt = dominances[next]; + InsertPhi(domIt, nextRegTypeMap); + } else { + if (multiInDegreeSet.find(next) != multiInDegreeSet.end()) { + std::vector typeMap = ConstructNewRegTypeMap(allocator, next + 1, nextRegTypeMap); + pcDefedRegsList.emplace_front(next, typeMap); + dominances[next] = typeMap; + } else { + pcDefedRegsList.emplace_front(next, nextRegTypeMap); + } + // Use stack to replace recursive call, avoid `call stack` overflow in long `fallthru` code. + // And `fallthu` instructions can not disrupt visit order. + if (currInst->IsConditionBranch() || currInst->IsSwitch()) { + Traverse(pcDefedRegsList, dominances, visitedSet); + } + } + } + auto normalTargets = currInst->GetTargets(); + for (auto normalTarget : normalTargets) { + if (visitedSet.emplace(normalTarget).second == false) { + auto &domIt = dominances[normalTarget]; + InsertPhi(domIt, nextRegTypeMap); + continue; + } + if (multiInDegreeSet.find(normalTarget) != multiInDegreeSet.end()) { + std::vector typeMap = ConstructNewRegTypeMap(allocator, normalTarget + 1, nextRegTypeMap); + pcDefedRegsList.emplace_front(normalTarget, typeMap); + dominances[normalTarget] = typeMap; + } else { + pcDefedRegsList.emplace_front(normalTarget, nextRegTypeMap); + } + Traverse(pcDefedRegsList, dominances, visitedSet); + } + } +} + +void BCClassMethod::InsertPhi(const std::vector &dom, std::vector &src) { + for (auto &d : dom) { + if (d == nullptr) { + continue; + } + auto srcItem = src[d->reg->regNum]; + if (srcItem == d) { + continue; + } + if (d->RegisterInPrevs(srcItem) == false) { + continue; + } + + if (d->isAlive == false) { + continue; + } + CHECK_FATAL(srcItem != nullptr, "ByteCode RA error."); + for (auto ty : *(d->aliveUsedTypes)) { + ty->SetDom(true); + } + srcItem->InsertUniqueAliveTypes(d, d->aliveUsedTypes); + } +} + +TypeInferItem *BCClassMethod::ConstructTypeInferItem( + MapleAllocator &alloc, uint32 pos, BCReg *bcReg, TypeInferItem *prev) { + TypeInferItem *item = alloc.GetMemPool()->New(alloc, pos, bcReg, prev); + return item; +} + +std::vector BCClassMethod::ConstructNewRegTypeMap(MapleAllocator &alloc, uint32 pos, + const std::vector ®TypeMap) { + std::vector res(regTypeMap.size(), nullptr); + size_t i = 0; + for (const auto &elem : regTypeMap) { + if (elem != nullptr) { + res[i] = ConstructTypeInferItem(alloc, pos, elem->reg, elem); + } + ++i; + } + return res; +} + +std::list BCClassMethod::GenReTypeStmtsThroughArgs() const { + std::list stmts; + for (const auto &argReg : argRegs) { + std::list stmts0 = argReg->GenRetypeStmtsAfterDef(); + for (auto &stmt : stmts0) { + stmts.emplace_back(std::move(stmt)); + } + } + return stmts; +} + +void BCClassMethod::PrecisifyRegType() { + for (auto elem : regTypes) { + elem->PrecisifyTypes(); + } +} + +std::list BCClassMethod::EmitInstructionsToFEIR() const { + std::list stmts; + if (!HasCode()) { + return stmts; // Skip abstract and native method, not emit it to mpl but mplt. + } + if (IsStatic() && GetName().compare("") != 0) { // Not insert JAVA_CLINIT_CHECK in + GStrIdx containerNameIdx = GetClassNameMplIdx(); + uint32 typeID = UINT32_MAX; + if (FEOptions::GetInstance().IsAOT()) { + const std::string &mplClassName = GetBCClass().GetClassName(true); + int32 dexFileHashCode = GetBCClass().GetBCParser().GetFileNameHashId(); + typeID = FEManager::GetTypeManager().GetTypeIDFromMplClassName(mplClassName, dexFileHashCode); + } + UniqueFEIRStmt stmt = + std::make_unique(INTRN_JAVA_CLINIT_CHECK, + std::make_unique(PTY_ref, containerNameIdx), + nullptr, typeID); + stmts.emplace_back(std::move(stmt)); + } + std::map targetFEIRStmtMap; + std::list gotoFEIRStmts; + std::list switchFEIRStmts; + std::list retypeStmts = GenReTypeStmtsThroughArgs(); + for (auto &stmt : retypeStmts) { + stmts.emplace_back(std::move(stmt)); + } + for (const auto &elem : *pcBCInstructionMap) { + std::list instStmts = elem.second->EmitToFEIRStmts(); + for (auto &e : instStmts) { + if (e->GetKind() == kStmtPesudoLabel) { + targetFEIRStmtMap.emplace(static_cast(e.get())->GetPos(), + static_cast(e.get())); + } + if (e->GetKind() == kStmtGoto || e->GetKind() == kStmtCondGoto) { + gotoFEIRStmts.emplace_back(static_cast(e.get())); + } + if (e->GetKind() == kStmtSwitch) { + switchFEIRStmts.emplace_back(static_cast(e.get())); + } + stmts.emplace_back(std::move(e)); + } + } + LinkJumpTarget(targetFEIRStmtMap, gotoFEIRStmts, switchFEIRStmts); // Link jump target + return stmts; +} + +void BCClassMethod::LinkJumpTarget(const std::map &targetFEIRStmtMap, + const std::list &gotoFEIRStmts, + const std::list &switchFEIRStmts) { + for (auto &e : gotoFEIRStmts) { + auto target = targetFEIRStmtMap.find(e->GetTarget()); + CHECK_FATAL(target != targetFEIRStmtMap.end(), "Cannot find the target for goto/condGoto"); + e->SetStmtTarget(*(target->second)); + } + for (auto &e : switchFEIRStmts) { + uint32 label = e->GetDefaultLabelIdx(); + if (label != UINT32_MAX) { + auto defaultTarget = targetFEIRStmtMap.find(label); + CHECK_FATAL(defaultTarget != targetFEIRStmtMap.end(), "Cannot find the default target for Switch"); + e->SetDefaultTarget(defaultTarget->second); + } + for (const auto &valueLabel : e->GetMapValueLabelIdx()) { + auto target = targetFEIRStmtMap.find(valueLabel.second); + CHECK_FATAL(target != targetFEIRStmtMap.end(), "Cannot find the target for Switch"); + e->AddTarget(valueLabel.first, target->second); + } + } +} + +void BCClassMethod::DumpBCInstructionMap() const { + // Only used in DEBUG manually + DEBUG_STMT( + uint32 idx = 0; + for (const auto &[pos, instPtr] : *pcBCInstructionMap) { + LogInfo::MapleLogger(kLlDbg) << "index: " << std::dec << idx++ << " pc: 0x" << std::hex << pos << + " opcode: 0x" << instPtr->GetOpcode() << std::endl; + }); +} + +const uint16 *BCClassMethod::GetInstPos() const { + return instPos; +} + +std::vector> BCClassMethod::GenArgVarList() const { + return GenArgVarListImpl(); +} + +void BCClassMethod::GenArgRegs() { + return GenArgRegsImpl(); +} + +// ========== BCCatchInfo ========== +BCCatchInfo::BCCatchInfo(uint32 handlerAddrIn, const GStrIdx &argExceptionNameIdx, bool iscatchAllIn) + : handlerAddr(handlerAddrIn), + exceptionNameIdx(argExceptionNameIdx), + isCatchAll(iscatchAllIn) {} +// ========== BCClass ========== +void BCClass::SetSrcFileInfo(const std::string &name) { + srcFileNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + srcFileIdx = FEManager::GetManager().RegisterSourceFileIdx(srcFileNameIdx); +} + +void BCClass::SetSuperClasses(const std::list &names) { + if (names.empty()) { + return; // No parent class + } + superClassNameList = names; +} + +void BCClass::SetInterface(const std::string &name) { + interfaces.push_back(name); +} + +void BCClass::SetAccFlag(uint32 flag) { + accFlag = flag; +} + +void BCClass::SetField(std::unique_ptr field) { + fields.push_back(std::move(field)); +} + +void BCClass::SetMethod(std::unique_ptr method) { + std::lock_guard lock(bcClassMtx); + methods.push_back(std::move(method)); +} + +void BCClass::InsertFinalStaticStringID(uint32 stringID) { + finalStaticStringID.push_back(stringID); +} + +void BCClass::SetClassName(const std::string &classNameOrin) { + classNameOrinIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(classNameOrin); + classNameMplIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(classNameOrin)); +} + +const std::unique_ptr &BCClass::GetAnnotationsDirectory() const { + return annotationsDirectory; +} + +void BCClass::SetAnnotationsDirectory(std::unique_ptr annotationsDirectoryIn) { + annotationsDirectory = std::move(annotationsDirectoryIn); +} + +std::vector BCClass::GetStaticFieldsConstVal() const { + return staticFieldsConstVal; +} + +void BCClass::InsertStaticFieldConstVal(MIRConst *cst) { + staticFieldsConstVal.push_back(cst); +} + +const std::string &BCClass::GetClassName(bool mapled) const { + return mapled ? GlobalTables::GetStrTable().GetStringFromStrIdx(classNameMplIdx) : + GlobalTables::GetStrTable().GetStringFromStrIdx(classNameOrinIdx); +} + +const std::list &BCClass::GetSuperClassNames() const { + return superClassNameList; +} + +const std::vector &BCClass::GetSuperInterfaceNames() const { + return interfaces; +} + +std::string BCClass::GetSourceFileName() const { + return GlobalTables::GetStrTable().GetStringFromStrIdx(srcFileNameIdx); +} + +GStrIdx BCClass::GetIRSrcFileSigIdx() const { + return irSrcFileSigIdx; +} + +int32 BCClass::GetFileNameHashId() const { + return parser.GetFileNameHashId(); +} + +uint32 BCClass::GetAccessFlag() const { + return accFlag; +} + +const std::vector> &BCClass::GetFields() const { + return fields; +} + +std::vector> &BCClass::GetMethods() { + return methods; +} +} // namespace bc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/common/src/bc_class2fe_helper.cpp b/src/hir2mpl/bytecode_input/common/src/bc_class2fe_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..16454593af3942f3d6867afeaa99cbd63fac2cbf --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/src/bc_class2fe_helper.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "bc_class2fe_helper.h" +#include "fe_macros.h" +#include "fe_manager.h" +#include "fe_utils_java.h" +namespace maple { +namespace bc { +BCClass2FEHelper::BCClass2FEHelper(MapleAllocator &allocator, bc::BCClass &klassIn) + : FEInputStructHelper(allocator), klass(klassIn) { + srcLang = kSrcLangJava; +} + +std::string BCClass2FEHelper::GetStructNameOrinImpl() const { + return klass.GetClassName(false); +} + +std::string BCClass2FEHelper::GetStructNameMplImpl() const { + return klass.GetClassName(true); +} + +std::list BCClass2FEHelper::GetSuperClassNamesImpl() const { + return klass.GetSuperClassNames(); +} + +std::vector BCClass2FEHelper::GetInterfaceNamesImpl() const { + return klass.GetSuperInterfaceNames(); +} + +std::string BCClass2FEHelper::GetSourceFileNameImpl() const { + return klass.GetSourceFileName(); +} + +void BCClass2FEHelper::TryMarkMultiDefClass(MIRStructType &typeImported) const { + MIRTypeKind kind = typeImported.GetKind(); + uint32 typeSrcSigIdx = 0; + static const GStrIdx keySignatureStrIdx = + GlobalTables::GetStrTable().GetStrIdxFromName("INFO_ir_srcfile_signature"); + if (kind == kTypeClass || kind == kTypeClassIncomplete) { + auto &classType = static_cast(typeImported); + typeSrcSigIdx = classType.GetInfo(keySignatureStrIdx); + } else if (kind == kTypeInterface || kind == kTypeInterfaceIncomplete) { + auto &interfaceType = static_cast(typeImported); + typeSrcSigIdx = interfaceType.GetInfo(keySignatureStrIdx); + } + // Find type definition in both dependent libraries and current compilation unit, mark the type multidef, + // and we will mark all it's methods multidef later. + // MiddleEnd will NOT inline the caller and callee with multidef attr. + if (typeSrcSigIdx != 0 && klass.GetIRSrcFileSigIdx() != typeSrcSigIdx) { + klass.SetIsMultiDef(true); + } +} + +MIRStructType *BCClass2FEHelper::CreateMIRStructTypeImpl(bool &error) const { + std::string classNameMpl = GetStructNameMplImpl(); + if (classNameMpl.empty()) { + error = true; + ERR(kLncErr, "class name is empty"); + return nullptr; + } + FE_INFO_LEVEL(FEOptions::kDumpLevelInfoDetail, "CreateMIRStrucType for %s", classNameMpl.c_str()); + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(classNameMpl); + MIRStructType *typeImported = FEManager::GetTypeManager().GetImportedType(nameIdx); + if (typeImported != nullptr) { + TryMarkMultiDefClass(*typeImported); + } + + bool isCreate = false; + MIRStructType *type = FEManager::GetTypeManager().GetOrCreateClassOrInterfaceType(nameIdx, klass.IsInterface(), + FETypeFlag::kSrcInput, isCreate); + error = false; + // fill global type name table + GStrIdx typeNameIdx = type->GetNameStrIdx(); + TyIdx prevTyIdx = GlobalTables::GetTypeNameTable().GetTyIdxFromGStrIdx(typeNameIdx); + if (prevTyIdx == TyIdx(0)) { + GlobalTables::GetTypeNameTable().SetGStrIdxToTyIdx(typeNameIdx, type->GetTypeIndex()); + } + // setup eh root type + if (FEManager::GetModule().GetThrowableTyIdx() == 0 && + (type->GetKind() == kTypeClass || type->GetKind() == kTypeClassIncomplete)) { + GStrIdx ehTypeNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::GetInternalNameLiteral(namemangler::kJavaLangObjectStr)); + if (ehTypeNameIdx == type->GetNameStrIdx()) { + FEManager::GetModule().SetThrowableTyIdx(type->GetTypeIndex()); + } + } + return isCreate ? type : nullptr; +} + +uint64 BCClass2FEHelper::GetRawAccessFlagsImpl() const { + return static_cast(klass.GetAccessFlag()); +} + +GStrIdx BCClass2FEHelper::GetIRSrcFileSigIdxImpl() const { + return klass.GetIRSrcFileSigIdx(); +} + +bool BCClass2FEHelper::IsMultiDefImpl() const { + return klass.IsMultiDef(); +} + +std::string BCClass2FEHelper::GetSrcFileNameImpl() const { + return klass.GetSourceFileName(); +} + +// ========== BCClassField2FEHelper ========== +FieldAttrs BCClassField2FEHelper::AccessFlag2Attribute(uint32 accessFlag) const { + return AccessFlag2AttributeImpl(accessFlag); +} + +bool BCClassField2FEHelper::ProcessDeclImpl(MapleAllocator &allocator) { + (void) allocator; + CHECK_FATAL(false, "should not run here"); + return false; +} + +bool BCClassField2FEHelper::ProcessDeclWithContainerImpl(MapleAllocator &allocator) { + (void) allocator; + std::string klassNameMpl; + std::string fieldNameMpl; + std::string typeNameMpl; + bool isStatic = field.IsStatic(); + uint64 mapIdx = (static_cast(field.GetBCClass().GetBCParser().GetReader()->GetFileIndex()) << 32) | + field.GetIdx(); + StructElemNameIdx *structElemNameIdx = FEManager::GetManager().GetFieldStructElemNameIdx(mapIdx); + if (structElemNameIdx == nullptr) { + klassNameMpl = namemangler::EncodeName(field.GetClassName()); + fieldNameMpl = namemangler::EncodeName(field.GetName()); + typeNameMpl = namemangler::EncodeName(field.GetDescription()); + if (fieldNameMpl.empty()) { + ERR(kLncErr, "invalid name for %s field: %u in class %s", field.IsStatic() ? "static" : "instance", + field.GetItemIdx(), klassNameMpl.c_str()); + return false; + } + if (typeNameMpl.empty()) { + ERR(kLncErr, "invalid descriptor for %s field: %u in class %s", field.IsStatic() ? "static" : "instance", + field.GetItemIdx(), klassNameMpl.c_str()); + return false; + } + structElemNameIdx = FEManager::GetManager().GetStructElemMempool()->New( + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(klassNameMpl), + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fieldNameMpl), + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(typeNameMpl), + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(klassNameMpl + namemangler::kNameSplitterStr + + fieldNameMpl + namemangler::kNameSplitterStr + typeNameMpl)); + FEManager::GetManager().SetFieldStructElemNameIdx(mapIdx, *structElemNameIdx); + } else { + klassNameMpl = GlobalTables::GetStrTable().GetStringFromStrIdx(structElemNameIdx->klass); + fieldNameMpl = GlobalTables::GetStrTable().GetStringFromStrIdx(structElemNameIdx->elem); + typeNameMpl = GlobalTables::GetStrTable().GetStringFromStrIdx(structElemNameIdx->type); + } + FEStructElemInfo *elemInfo = FEManager::GetTypeManager().RegisterStructFieldInfo( + *structElemNameIdx, kSrcLangJava, isStatic); + elemInfo->SetDefined(); + elemInfo->SetFromDex(); + // control anti-proguard through FEOptions only. + FEOptions::ModeJavaStaticFieldName modeStaticField = FEOptions::GetInstance().GetModeJavaStaticFieldName(); + bool withType = (modeStaticField == FEOptions::kAllType) || + (isStatic && modeStaticField == FEOptions::kSmart); + GStrIdx idx; + if (!isStatic && !withType) { + idx = structElemNameIdx->elem; + } else if (isStatic && withType) { + idx = structElemNameIdx->full; + } else { + std::string name = isStatic ? (klassNameMpl + namemangler::kNameSplitterStr) : ""; + name += fieldNameMpl; + name += withType ? (namemangler::kNameSplitterStr + typeNameMpl) : ""; + idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + } + FieldAttrs attrs = AccessFlag2Attribute(field.GetAccessFlag()); + MIRType *fieldType = FEManager::GetTypeManager().GetOrCreateTypeFromName(typeNameMpl, FETypeFlag::kSrcUnknown, true); + ASSERT(fieldType != nullptr, "nullptr check for fieldType"); + mirFieldPair.first = idx; + mirFieldPair.second.first = fieldType->GetTypeIndex(); + mirFieldPair.second.second = attrs; + return true; +} + +// ========== BCClassMethod2FEHelper ========== +BCClassMethod2FEHelper::BCClassMethod2FEHelper(MapleAllocator &allocator, std::unique_ptr &methodIn) + : FEInputMethodHelper(allocator), + method(methodIn) { + srcLang = kSrcLangJava; +} + +bool BCClassMethod2FEHelper::ProcessDeclImpl(MapleAllocator &allocator) { + uint64 mapIdx = (static_cast(method->GetBCClass().GetBCParser().GetReader()->GetFileIndex()) << 32) | + method->GetIdx(); + StructElemNameIdx *structElemNameIdx = FEManager::GetManager().GetMethodStructElemNameIdx(mapIdx); + if (structElemNameIdx == nullptr) { + structElemNameIdx = FEManager::GetManager().GetStructElemMempool()->New( + method->GetClassName(), method->GetName(), method->GetDescription()); + FEManager::GetManager().SetMethodStructElemNameIdx(mapIdx, *structElemNameIdx); + } + const std::string &methodShortName = method->GetName(); + CHECK_FATAL(!methodShortName.empty(), "error: method name is empty"); + if (methodShortName.compare("main") == 0) { + FEManager::GetMIRBuilder().GetMirModule().SetEntryFuncName( + GlobalTables::GetStrTable().GetStringFromStrIdx(structElemNameIdx->full)); + } + methodNameIdx = structElemNameIdx->full; + SolveReturnAndArgTypes(allocator); + FuncAttrs attrs = GetAttrs(); + bool isStatic = IsStatic(); + bool isVarg = IsVarg(); + CHECK_FATAL(retType != nullptr, "function must have return type"); + MIRType *mirReturnType = nullptr; + bool usePtr = (srcLang == kSrcLangJava); + if (retType->GetPrimType() == PTY_void) { + mirReturnType = retType->GenerateMIRType(srcLang, false); + } else { + mirReturnType = retType->GenerateMIRType(srcLang, usePtr); + } + ASSERT(mirReturnType != nullptr, "return type is nullptr"); + std::vector argsTypeIdx; + for (FEIRType *type : argTypes) { + MIRType *argType = type->GenerateMIRType(srcLang, usePtr); + argsTypeIdx.emplace_back(argType->GetTypeIndex()); + } + FEStructElemInfo *elemInfo = FEManager::GetTypeManager().RegisterStructMethodInfo( + *structElemNameIdx, kSrcLangJava, isStatic); + elemInfo->SetDefined(); + elemInfo->SetFromDex(); + mirFunc = FEManager::GetTypeManager().CreateFunction(methodNameIdx, mirReturnType->GetTypeIndex(), + argsTypeIdx, isVarg, isStatic); + mirMethodPair.first = mirFunc->GetStIdx(); + mirMethodPair.second.first = mirFunc->GetMIRFuncType()->GetTypeIndex(); + mirMethodPair.second.second = attrs; + mirFunc->SetFuncAttrs(attrs); + return true; +} + +std::string BCClassMethod2FEHelper::GetMethodNameImpl(bool inMpl, bool full) const { + std::string klassName = method->GetClassName(); + std::string methodName = method->GetName(); + if (!full) { + return inMpl ? namemangler::EncodeName(methodName) : methodName; + } + std::string descName = method->GetDescription(); + std::string fullName = klassName + "|" + methodName + "|" + descName; + return inMpl ? namemangler::EncodeName(fullName) : fullName; +} + +void BCClassMethod2FEHelper::SolveReturnAndArgTypesImpl(MapleAllocator &allocator) { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mempool is nullptr"); + std::string klassName = method->GetClassName(); + std::string methodName = GetMethodName(false); + if (HasThis()) { + FEIRTypeDefault *type = mp->New(); + type->LoadFromJavaTypeName(klassName, false); + argTypes.push_back(type); + } + const std::vector &returnAndArgTypeNames = FEUtilJava::SolveMethodSignature(methodName); + bool first = true; + for (const std::string &typeName : returnAndArgTypeNames) { + FEIRTypeDefault *type = mp->New(); + type->LoadFromJavaTypeName(typeName, false); + if (first) { + retType = type; + first = false; + } else { + argTypes.push_back(type); + } + } +} + +bool BCClassMethod2FEHelper::IsVargImpl() const { + return false; // No variable arguments +} + +bool BCClassMethod2FEHelper::HasThisImpl() const { + return !IsStatic(); +} + +MIRType *BCClassMethod2FEHelper::GetTypeForThisImpl() const { + FEIRTypeDefault type; + const std::string &klassName = method->GetClassName(); + type.LoadFromJavaTypeName(klassName, false); + return type.GenerateMIRType(true); +} + +bool BCClassMethod2FEHelper::IsVirtualImpl() const { + return method->IsVirtual(); +} + +bool BCClassMethod2FEHelper::IsNativeImpl() const { + return method->IsNative(); +} + +bool BCClassMethod2FEHelper::HasCodeImpl() const { + return method->HasCode(); +} +} // namespace bc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/common/src/bc_function.cpp b/src/hir2mpl/bytecode_input/common/src/bc_function.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4ef5f0159d10461cdcf43a6f49a4398dd39bac67 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/src/bc_function.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "bc_function.h" +#include "fe_macros.h" +#include "fe_manager.h" +#include "feir_type_helper.h" +#include "feir_builder.h" +#include "rc_setter.h" + +namespace maple { +namespace bc { +BCFunction::BCFunction(const BCClassMethod2FEHelper &argMethodHelper, MIRFunction &mirFunc, + const std::unique_ptr &argPhaseResultTotal) + : FEFunction(mirFunc, argPhaseResultTotal), + methodHelper(argMethodHelper), + method(methodHelper.GetMethod()) {} + +void BCFunction::PreProcessImpl() { + ; // Empty +} + +void BCFunction::InitImpl() { + FEFunction::InitImpl(); +} + +void BCFunction::SetMIRFunctionInfo() { + GStrIdx idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(method->GetFullName()); + SET_FUNC_INFO_PAIR(mirFunction, "INFO_fullname", idx, true); + idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(method->GetClassName()); + SET_FUNC_INFO_PAIR(mirFunction, "INFO_classname", idx, true); + idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(method->GetName()); + SET_FUNC_INFO_PAIR(mirFunction, "INFO_funcname", idx, true); + SET_FUNC_INFO_PAIR(mirFunction, "INFO_methodidx", method->GetIdx(), false); + SET_FUNC_INFO_PAIR(mirFunction, "INFO_registers", method->GetRegisterTotalSize(), false); + SET_FUNC_INFO_PAIR(mirFunction, "INFO_tries_size", method->GetTriesSize(), false); + SET_FUNC_INFO_PAIR(mirFunction, "INFO_dexthisreg", method->GetThisRegNum(), false); + SET_FUNC_INFO_PAIR(mirFunction, "INFO_codeoff", method->GetCodeOff(), false); +} + +bool BCFunction::ProcessImpl() { + FE_INFO_LEVEL(FEOptions::kDumpLevelInfoDetail, "BCFunction::Process() for %s", method->GetFullName().c_str()); + bool success = true; + method->GetBCClass().GetBCParser().ProcessMethodBody(*method, + method->GetBCClass().GetClassIdx(), + method->GetItemIdx(), + method->IsVirtual()); + SetMIRFunctionInfo(); + success = success && GenerateArgVarList("gen arg var list"); + success = success && EmitToFEIRStmt("emit to feir"); + success = success && ProcessFEIRFunction(); + if (!success) { + error = true; + ERR(kLncErr, "BCFunction::Process() failed for %s", method->GetFullName().c_str()); + } + return success; +} + +bool BCFunction::GenerateAliasVars(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + if (method == nullptr || method->GetSrcLocalInfoPtr() == nullptr) { + return phaseResult.Finish(true); + } + // map>> + for (auto &local : *method->GetSrcLocalInfoPtr()) { + for (auto &item : local.second) { + if (std::get<0>(item) == "this") { + continue; + } + UniqueFEIRType type = FEIRTypeHelper::CreateTypeByJavaName(std::get<1>(item), false, false); + MIRType *mirType = FEManager::GetTypeManager().GetOrCreateTypeFromName( + namemangler::EncodeName(std::get<1>(item)), FETypeFlag::kSrcUnknown, true); + UniqueFEIRVar localVar = FEIRBuilder::CreateVarReg(local.first, std::move(type)); + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::EncodeName(std::get<0>(item))); + MIRAliasVars aliasVar; + aliasVar.memPoolStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(localVar->GetName(*mirType)); + aliasVar.tyIdx = mirType->GetTypeIndex(); + if (!std::get<2>(item).empty()) { + aliasVar.sigStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(std::get<2>(item)); + } + mirFunction.SetAliasVarMap(nameIdx, aliasVar); + } + } + return phaseResult.Finish(true); +} + +bool BCFunction::ProcessFEIRFunction() { + bool success = true; + success = success && UpdateRegNum2This("fe/update reg num to this pointer"); + return success; +} + +bool BCFunction::GenerateArgVarList(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + argVarList = method->GenArgVarList(); + return phaseResult.Finish(); +} + +bool BCFunction::EmitToFEIRStmt(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + std::list feirStmts = method->EmitInstructionsToFEIR(); + AppendFEIRStmts(feirStmts); + return phaseResult.Finish(true); +} + +void BCFunction::FinishImpl() { + (void)UpdateFormal("finish/update formal"); + (void)EmitToMIR("finish/emit to mir"); + (void)GenerateAliasVars("finish/generate alias vars"); + if (FEOptions::GetInstance().IsRC()) { + RCSetter::GetRCSetter().GetUnownedVarInLocalVars(*method, mirFunction); + } + bool recordTime = FEOptions::GetInstance().IsDumpPhaseTime() || FEOptions::GetInstance().IsDumpPhaseTimeDetail(); + if (phaseResultTotal != nullptr && recordTime) { + phaseResultTotal->Combine(phaseResult); + } + if (FEOptions::GetInstance().IsDumpPhaseTimeDetail()) { + INFO(kLncInfo, "[PhaseTime] function: %s", method->GetFullName().c_str()); + phaseResult.Dump(); + } + method->ReleaseMempool(); + BCClassMethod *methodPtr = method.release(); + delete methodPtr; +} + +bool BCFunction::EmitToMIR(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + // Not gen funcbody for abstract method + if (methodHelper.HasCode() || methodHelper.IsNative()) { + mirFunction.NewBody(); + FEManager::GetMIRBuilder().SetCurrentFunction(mirFunction); + FEManager::SetCurrentFEFunction(*this); + EmitToMIRStmt(); + } + return phaseResult.Finish(); +} +} // namespace bc +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/src/bc_instruction.cpp b/src/hir2mpl/bytecode_input/common/src/bc_instruction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c8ac5512389e0e1d30fb19b106f37a165e543279 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/src/bc_instruction.cpp @@ -0,0 +1,561 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "bc_instruction.h" +#include +#include "bc_class.h" +#include "feir_builder.h" +#include "fe_manager.h" +#include "fe_options.h" + +namespace maple { +namespace bc { +void BCInstruction::InitBCInStruction(uint16 kind, bool wide, bool throwable) { + instKind = static_cast(instKind | kind); + isWide = wide; + isThrowable = throwable; +} + +void BCInstruction::SetWidth(uint8 size) { + width = size; +} + +uint8 BCInstruction::GetWidth() const { + return width; +} + +void BCInstruction::SetCatchable() { + isCatchable = isThrowable; +} + +bool BCInstruction::IsCatchable() const { + return isCatchable; +} + +BCInstructionKind BCInstruction::GetInstKind() const { + return instKind; +} + +bool BCInstruction::IsWide() const { + return isWide; +} + +void BCInstruction::SetInstructionKind(BCInstructionKind kind) { + instKind = static_cast(static_cast(instKind) | static_cast(kind)); +} + +void BCInstruction::Parse(BCClassMethod &method) { + ParseImpl(method); +} + +void BCInstruction::SetExceptionType(const GStrIdx &typeNameIdx) { + catchedExTypeNamesIdx.emplace(typeNameIdx); + SetBCRegType(*this); +} + +std::list BCInstruction::EmitToFEIRStmts() { + std::list stmts; + // Do not modify following stmt order + GenCommentStmt(stmts); + if ((instKind & kTarget) || (instKind & kCatch)) { + if (instKind & kCatch) { + UniqueFEIRStmt stmt = GenCatchStmt(); + stmts.emplace_back(std::move(stmt));; + } else { + UniqueFEIRStmt stmt = GenLabelStmt(); + stmts.emplace_back(std::move(stmt)); + } + } + if (instKind & kTryStart) { + UniqueFEIRStmt stmt = GenTryLabelStmt(); + stmts.emplace_back(std::move(stmt)); + } + std::list instStmts = EmitToFEIRStmtsImpl(); + for (auto it = instStmts.begin(); it != instStmts.end(); ++it) { + it->get()->SetThrowable(isThrowable); + if (FEOptions::GetInstance().IsAOT()) { + it->get()->SetHexPC(pc); + } + stmts.emplace_back(std::move(*it)); + } + std::list retypeStmts = GenRetypeStmtsAfterDef(); + for (auto it = retypeStmts.begin(); it != retypeStmts.end(); ++it) { + stmts.emplace_back(std::move(*it)); + } + if (instKind & kTryEnd) { + UniqueFEIRStmt stmt = GenTryEndLabelStmt(); + stmts.emplace_back(std::move(stmt)); + } + SetSrcFileInfo(stmts); + return stmts; +} + +void BCInstruction::SetSrcFileInfo(std::list &stmts) const { +#ifdef DEBUG + if (FEOptions::GetInstance().IsDumpLOC() && !stmts.empty()) { + (*stmts.begin())->SetSrcFileInfo(srcFileIdx, srcFileLineNum); + } +#else + (void) stmts; +#endif +} + +bool BCInstruction::IsFallThru() const { + return instKind & kFallThru; +} + +bool BCInstruction::IsConditionBranch() const { + return instKind & kConditionBranch; +} + +bool BCInstruction::IsGoto() const { + return instKind & kGoto; +} + +bool BCInstruction::IsSwitch() const { + return instKind & kSwitch; +} + +bool BCInstruction::IsTarget() const { + return instKind & kTarget; +} + +bool BCInstruction::IsTryStart() const { + return instKind & kTryStart; +} + +bool BCInstruction::IsTryEnd() const { + return instKind & kTryEnd; +} + +bool BCInstruction::IsCatch() const { + return instKind & kCatch; +} + +void BCInstruction::SetReturnInst(BCInstruction *inst) { + inst->SetBCRegType(*this); + returnInst = inst; +} + +void BCInstruction::SetBCRegType(const BCInstruction &inst) { + SetBCRegTypeImpl(inst); +} + +bool BCInstruction::HasReturn() const { + return returnInst != nullptr; +} + +bool BCInstruction::IsReturn() const { + return isReturn; +} + +uint32 BCInstruction::GetPC() const { + return pc; +} + +uint8 BCInstruction::GetOpcode() const { + return opcode; +} + +std::vector BCInstruction::GetTargets() const { + return GetTargetsImpl(); +} + +void BCInstruction::SetDefaultTarget(BCInstruction *inst) { + defaultTarget = inst; +} + +void BCInstruction::AddHandler(BCInstruction *handler) { + auto it = std::find(handlers.begin(), handlers.end(), handler); + if (it == handlers.end()) { + handlers.emplace_back(handler); + } +} + +void BCInstruction::AddHandlerTarget(uint32 target) { + handlerTargets.emplace_back(target); +} + +MapleVector BCInstruction::GetHandlerTargets() const { + return handlerTargets; +} + +MapleList *BCInstruction::GetDefedRegs() { + return &defedRegs; +} + +MapleList *BCInstruction::GetUsedRegs() { + return &usedRegs; +} + +void BCInstruction::SetRegTypeInTypeInfer() { + SetRegTypeInTypeInferImpl(); +} + +std::vector BCInstruction::GetTargetsImpl() const { + return std::vector{}; // Default empty, means invalid +} + +void BCInstruction::GenCommentStmt(std::list &stmts) const { +#ifdef DEBUG + if (FEOptions::GetInstance().IsDumpComment()) { + std::ostringstream oss; + // 4 means 4-character width + oss << "LINE " << FEManager::GetManager().GetSourceFileNameFromIdx(srcFileIdx) << " : " << srcFileLineNum << + ", INST_IDX : " << pc << " ||" << std::setfill('0') << std::setw(4) << std::hex << pc << ": " << + (opName == nullptr ? "invalid op" : opName); + stmts.emplace_back(FEIRBuilder::CreateStmtComment(oss.str())); + } +#else + (void) stmts; +#endif +} + +UniqueFEIRStmt BCInstruction::GenLabelStmt() const { + return std::make_unique(funcNameIdx, pc); +} + +UniqueFEIRStmt BCInstruction::GenCatchStmt() const { + std::unique_ptr stmt = std::make_unique(funcNameIdx, pc); + for (const auto &exTypeNameIdx : catchedExTypeNamesIdx) { + stmt->AddCatchTypeNameIdx(exTypeNameIdx); + } + return stmt; +} + +UniqueFEIRStmt BCInstruction::GenTryLabelStmt() const { + std::unique_ptr javaTry = std::make_unique(funcNameIdx); + for (const auto &handler : handlers) { + javaTry->AddCatchLabelIdx(handler->GetPC()); + } + return javaTry; +} + +UniqueFEIRStmt BCInstruction::GenTryEndLabelStmt() const { + return std::make_unique(); +} + +std::list BCInstruction::GenRetypeStmtsAfterDef() const { + std::list stmts; + for (BCReg *reg : defedRegs) { + std::list stmts0 = reg->GenRetypeStmtsAfterDef(); + for (auto &stmt : stmts0) { + stmts.emplace_back(std::move(stmt)); + } + } + return stmts; +} + +std::list BCInstruction::GenRetypeStmtsBeforeUse() const { + std::list stmts; + for (BCReg *reg : usedRegs) { + std::list stmts0 = reg->GenRetypeStmtsBeforeUse(); + for (auto &stmt : stmts0) { + stmts.emplace_back(std::move(stmt)); + } + } + return stmts; +} + +void BCInstruction::SetFuncNameIdx(const GStrIdx &methodIdx) { + funcNameIdx = methodIdx; +} + +void BCInstruction::SetSrcPositionInfo(uint32 fileIdxIn, uint32 lineNumIn) { + srcFileIdx = fileIdxIn; + srcFileLineNum = lineNumIn; +} + + +void BCInstruction::SetOpName(const char *name) { +#ifdef DEBUG + opName = name; +#else + (void) name; +#endif +} + +const char *BCInstruction::GetOpName() const { +#ifdef DEBUG + return opName; +#else + return nullptr; +#endif +} + +// ========== BCRegTypeItem ========== +PrimType BCRegTypeItem::GetPrimType() const { + return GetBasePrimType(); +} + +PrimType BCRegTypeItem::GetBasePrimType() const { + return BCUtil::GetPrimType(typeNameIdx); +} + +bool BCRegTypeItem::IsMorePreciseType(const BCRegTypeItem &typeItemIn) const { + if (IsRef() && !typeItemIn.IsRef()) { + return true; + } else if (!IsRef() && typeItemIn.IsRef()) { + return false; + } else if (IsRef() && typeItemIn.IsRef()) { + const std::string &name0 = GlobalTables::GetStrTable().GetStringFromStrIdx(typeNameIdx); + const std::string &name1 = GlobalTables::GetStrTable().GetStringFromStrIdx(typeItemIn.typeNameIdx); + uint8 dim0 = FEUtils::GetDim(name0); + uint8 dim1 = FEUtils::GetDim(name1); + if (dim0 == dim1) { + GStrIdx name0Idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name0.substr(dim0)); + GStrIdx name1Idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name1.substr(dim0)); + if (name0Idx == name1Idx || dim0 == 0) { + if (!isIndeterminate && typeItemIn.isIndeterminate) { + return true; + } else if (isIndeterminate && !typeItemIn.isIndeterminate) { + return false; + } else if (isIndeterminate && typeItemIn.isIndeterminate) { + return name1Idx == BCUtil::GetJavaObjectNameMplIdx(); + } else { + return isFromDef ? + (name0Idx == BCUtil::GetJavaObjectNameMplIdx() || name1Idx != BCUtil::GetJavaObjectNameMplIdx()) : + (name0Idx != BCUtil::GetJavaObjectNameMplIdx() || name1Idx == BCUtil::GetJavaObjectNameMplIdx()); + } + } else { + BCRegTypeItem item0(name0Idx, isIndeterminate); + BCRegTypeItem item1(name1Idx, typeItemIn.isIndeterminate); + return item0.IsMorePreciseType(item1); + } + } else { + return dim0 > dim1; + } + } else { + if (!isIndeterminate && typeItemIn.isIndeterminate) { + return true; + } else if (isIndeterminate && !typeItemIn.isIndeterminate) { + return false; + } else { + return BCUtil::IsMorePrecisePrimitiveType(typeNameIdx, typeItemIn.typeNameIdx); + } + } +} + +// ========== BCRegType ========== +BCRegType::BCRegType(MapleAllocator &allocatorIn, BCReg ®, const GStrIdx &typeNameIdxIn, bool isIndeterminateIn) + : allocator(allocatorIn), curReg(reg), + regTypeItem(allocator.GetMemPool()->New(typeNameIdxIn, isIndeterminateIn, true)), + fuzzyTypesUsedAs(allocator.Adapter()), + elemTypes(allocator.Adapter()), + livesBegins(allocator.Adapter()) { + curReg.regTypeItem = regTypeItem; + if (isIndeterminateIn) { + fuzzyTypesUsedAs.emplace_back(regTypeItem); + } +} + +void BCRegType::PrecisifyTypes(bool isTry) { + if (precisified) { + return; + } + if (!isTry) { + precisified = true; + } + if (curReg.IsConstZero() || typesUsedAs == nullptr || typesUsedAs->empty()) { + return; + } + // insert defed type into `used` + typesUsedAs->emplace_back(regTypeItem); + BCRegTypeItem *realType = nullptr; + PrecisifyRelatedTypes(realType); + if (fuzzyTypesUsedAs.size() != 0 || realType == nullptr) { + if (realType == nullptr || realType->isIndeterminate) { + realType = GetMostPreciseType(*typesUsedAs); + if (realType != nullptr) { + for (auto &elem : fuzzyTypesUsedAs) { + elem->Copy(*realType); + } + } + } + } + if (!realType->isIndeterminate) { + PrecisifyElemTypes(realType); + } +} + +void BCRegType::PrecisifyRelatedTypes(const BCRegTypeItem *realType) { + for (auto rType : relatedBCRegTypes) { + // try to get type from use first. + // if failed, get type from def. + rType->PrecisifyTypes(true); + if (rType->IsIndeterminate()) { + if (realType == nullptr) { + realType = GetMostPreciseType(*typesUsedAs); + if (realType != nullptr) { + for (auto &fuzzyTy : fuzzyTypesUsedAs) { + fuzzyTy->Copy(*realType); + } + } + } + if (!realType->isIndeterminate) { + rType->PrecisifyTypes(true); + } + } else { + rType->precisified = true; + } + } +} + +void BCRegType::PrecisifyElemTypes(const BCRegTypeItem *arrayType) { + for (auto elem : elemTypes) { + if (elem->isIndeterminate) { + const std::string &arrTypeName = GlobalTables::GetStrTable().GetStringFromStrIdx(arrayType->typeNameIdx); + if (arrTypeName.size() > 1 && arrTypeName.at(0) == 'A') { + GStrIdx elemTypeIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(arrTypeName.substr(1)); + elem->typeNameIdx = elemTypeIdx; + elem->isIndeterminate = false; + } else { + CHECK_FATAL(curReg.regValue != nullptr, "Not an array type or const 0"); + } + } + } +} + +BCRegTypeItem *BCRegType::GetMostPreciseType(const MapleList &types) { + BCRegTypeItem *retType = nullptr; + if (types.empty()) { + return retType; + } + auto it = types.begin(); + retType = *it; + ++it; + while (it != types.end()) { + if ((*it)->IsMorePreciseType(*retType)) { + retType = *it; + } + ++it; + } + return retType; +} + +// ========== BCReg ========== +PrimType BCReg::GetPrimType() const { + return regTypeItem->GetPrimType(); +} + +PrimType BCReg::GetBasePrimType() const { + return regTypeItem->GetBasePrimType(); +} + +bool BCReg::IsConstZero() const { + if (regValue != nullptr) { + return regValue->primValue.raw32 == 0; + } + return false; +} + +UniqueFEIRType BCReg::GenFEIRType() const { + return GenFEIRTypeImpl(); +} + +UniqueFEIRVar BCReg::GenFEIRVarReg() const { + return GenFEIRVarRegImpl(); +} + +UniqueFEIRVar BCReg::GenFEIRVarRegImpl() const { + return std::make_unique(regNum, GenFEIRTypeImpl()); +} + +UniqueFEIRType BCReg::GenFEIRTypeImpl() const { + PrimType pty = GetBasePrimType(); + return std::make_unique(pty, regTypeItem->typeNameIdx); +} + +std::list BCReg::GenRetypeStmtsAfterDef() const { + std::list retypeStmts; + // Not gen retype stmt for use reg, same def-use type reg. + if (!isDef) { + return retypeStmts; + } + std::unique_ptr dstReg = this->Clone(); + std::unique_ptr tmpItem = std::make_unique(GStrIdx(0), false); + dstReg->regTypeItem = tmpItem.get(); + PrimType ptyDef = regTypeItem->GetPrimType(); + + std::list unqTypeItems; + if (regType->GetUsedTypes() != nullptr) { + for (const auto &usedType : *(regType->GetUsedTypes())) { + bool exist = false; + for (auto &elem : unqTypeItems) { + if ((*usedType) == (*elem)) { + if (usedType->IsDom()) { + elem->SetDom(true); + } + exist = true; + break; + } + } + if (exist == false) { + unqTypeItems.emplace_back(usedType); + } + } + } + + for (const auto &usedType : unqTypeItems) { + PrimType ptyUsed = usedType->GetPrimType(); + if ((*usedType) == (*regTypeItem) || + (usedType->isIndeterminate && + ((ptyUsed == PTY_i64 && ptyDef == PTY_f64) || (ptyUsed == PTY_i32 && ptyDef == PTY_f32)))) { + continue; + } + // Create retype stmt + dstReg->regTypeItem->Copy(*usedType); + UniqueFEIRStmt retypeStmt = + FEIRBuilder::CreateStmtRetype(dstReg->GenFEIRVarReg(), this->GenFEIRVarReg()); + if (retypeStmt != nullptr) { + if (FEOptions::GetInstance().IsAOT() && usedType->IsDom()) { + retypeStmt->SetHexPC(regType->GetPos()); + } + retypeStmts.emplace_back(std::move(retypeStmt)); + } + } + return retypeStmts; +} + +std::list BCReg::GenRetypeStmtsBeforeUse() const { + std::list retypeStmts; + // Not gen retype stmt for def reg, same def-use type reg. + // And Not gen retype stmt, if the defiend type is indeterminate. + const BCRegTypeItem *defed = regType->GetRegTypeItem(); + if (isDef) { + return retypeStmts; + } + if (!((*regTypeItem) == (*defed))) { + BCReg srcReg; + std::unique_ptr tmpItem = std::make_unique(GStrIdx(0), false); + srcReg.regTypeItem = tmpItem.get(); + // Create retype stmt + srcReg.regNum = regNum; + srcReg.regTypeItem->Copy(*defed); + UniqueFEIRStmt retypeStmt = + FEIRBuilder::CreateStmtRetype(this->GenFEIRVarReg(), srcReg.GenFEIRVarReg()); + if (retypeStmt != nullptr) { + retypeStmts.emplace_back(std::move(retypeStmt)); + } + } + return retypeStmts; +} + +std::unique_ptr BCReg::CloneImpl() const { + auto reg = std::make_unique(); + *reg = *this; + return reg; +} +} // namespace bc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/common/src/bc_io.cpp b/src/hir2mpl/bytecode_input/common/src/bc_io.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fab0438a6a3f3e437d0d38ca056382726f08d714 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/src/bc_io.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "bc_io.h" +namespace maple { +namespace bc { +BCIO::BCIO(const std::string &fileName) : BasicIOMapFile(fileName), isBigEndianHost(IsBigEndian()) {} + +BCReader::BCReader(const std::string &fileName) : BCIO(fileName), BasicIORead(*this, false) {} + +BCReader::~BCReader() { + Close(); +} + +bool BCReader::RetrieveHeader(RawData &data) { + return RetrieveHeaderImpl(data); +} + +void BCReader::SetEndianTag(bool isBigEndianIn) { + isBigEndian = isBigEndianIn; +} + +bool BCReader::RetrieveHeaderImpl(RawData &data) { + (void)data; + CHECK_FATAL(false, "NIY"); + return false; +} + +std::string BCReader::GetStringFromIdx(uint32 idx) const { + return GetStringFromIdxImpl(idx); +} + +std::string BCReader::GetTypeNameFromIdx(uint32 idx) const { + return GetTypeNameFromIdxImpl(idx); +} + +BCReader::ClassElem BCReader::GetClassMethodFromIdx(uint32 idx) const { + return GetClassMethodFromIdxImpl(idx); +} + +BCReader::ClassElem BCReader::GetClassFieldFromIdx(uint32 idx) const { + return GetClassFieldFromIdxImpl(idx); +} + +std::string BCReader::GetSignature(uint32 idx) const { + return GetSignatureImpl(idx); +} + +uint32 BCReader::GetFileIndex() const { + return GetFileIndexImpl(); +} + +std::string BCReader::GetIRSrcFileSignature() const { + return irSrcFileSignature; +} +} // namespace bc +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/src/bc_parser_base.cpp b/src/hir2mpl/bytecode_input/common/src/bc_parser_base.cpp new file mode 100644 index 0000000000000000000000000000000000000000..89ba8f0bf287b5dac8d16c38843dca212df70876 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/src/bc_parser_base.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "bc_parser_base.h" +#include "mpl_logging.h" +#include "mir_module.h" +namespace maple { +namespace bc { +BCParserBase::BCParserBase(uint32 fileIdxIn, const std::string &fileNameIn, const std::list &classNamesIn) + : fileIdx(fileIdxIn), fileName(fileNameIn), classNames(classNamesIn), + fileNameHashId(-1) {} + +const BCReader *BCParserBase::GetReader() const { + return GetReaderImpl(); +} + +bool BCParserBase::OpenFile() { + return OpenFileImpl(); +} + +bool BCParserBase::ParseHeader() { + return ParseHeaderImpl(); +} + +bool BCParserBase::Verify() { + return VerifyImpl(); +} + +uint32 BCParserBase::CalculateCheckSum(const uint8 *data, uint32 size) { + return CalculateCheckSumImpl(data, size); +} + +bool BCParserBase::RetrieveClasses(std::list> &klasses) { + if (RetrieveIndexTables() == false) { + ERR(kLncErr, "RetrieveIndexTables failed"); + return false; + } + if (!classNames.empty()) { + return RetrieveUserSpecifiedClasses(klasses); + } else { + return RetrieveAllClasses(klasses); + } +} + +bool BCParserBase::CollectAllDepTypeNames(std::unordered_set &depSet) { + return CollectAllDepTypeNamesImpl(depSet); +} + +bool BCParserBase::CollectMethodDepTypeNames(std::unordered_set &depSet, BCClassMethod &bcMethod) const { + return CollectMethodDepTypeNamesImpl(depSet, bcMethod); +} + +bool BCParserBase::CollectAllClassNames(std::unordered_set &classSet) { + return CollectAllClassNamesImpl(classSet); +} +} // namespace bc +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/src/bc_pragma.cpp b/src/hir2mpl/bytecode_input/common/src/bc_pragma.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d4f2bfb9ba77edbd3e46254ab98599db9f2ef053 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/src/bc_pragma.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "bc_pragma.h" +namespace maple { +namespace bc { +std::vector &BCAnnotationsDirectory::EmitPragmasImpl() { + CHECK_FATAL(false, "this method must be overrided!!!"); + return pragmas; +} +} // namespace bc +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/common/src/bc_util.cpp b/src/hir2mpl/bytecode_input/common/src/bc_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6f04d880e6223dd0560aa137f265b2bed35cc8b --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/src/bc_util.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "bc_util.h" +#include "fe_utils.h" +#include "fe_options.h" +#include "mpl_logging.h" +namespace maple { +namespace bc { +const std::string BCUtil::kUnknown = "Unknown"; +const std::string BCUtil::kPrimitive = "Primitive"; +const std::string BCUtil::kBoolean = "Z"; +const std::string BCUtil::kByte = "B"; +const std::string BCUtil::kShort = "S"; +const std::string BCUtil::kChar = "C"; +const std::string BCUtil::kInt = "I"; +const std::string BCUtil::kLong = "J"; +const std::string BCUtil::kFloat = "F"; +const std::string BCUtil::kDouble = "D"; +const std::string BCUtil::kVoid = "V"; +const std::string BCUtil::kWide = "wide"; +const std::string BCUtil::kAggregate = "Aggregate"; +const std::string BCUtil::kJavaObjectName = "Ljava/lang/Object;"; +const std::string BCUtil::kJavaStringName = "Ljava/lang/String;"; +const std::string BCUtil::kJavaByteClassName = "Ljava/lang/Byte;"; +const std::string BCUtil::kJavaShortClassName = "Ljava/lang/Short;"; +const std::string BCUtil::kJavaIntClassName = "Ljava/lang/Integer;"; +const std::string BCUtil::kJavaLongClassName = "Ljava/lang/Long;"; +const std::string BCUtil::kJavaFloatClassName = "Ljava/lang/Float;"; +const std::string BCUtil::kJavaDoubleClassName = "Ljava/lang/Double;"; +const std::string BCUtil::kJavaCharClassName = "Ljava/lang/Character;"; +const std::string BCUtil::kJavaBoolClassName = "Ljava/lang/Boolean;"; +const std::string BCUtil::kJavaClassName = "Ljava/lang/Class;"; +const std::string BCUtil::kJavaMethodHandleName = "Ljava/lang/invoke/MethodHandle;"; +const std::string BCUtil::kJavaExceptionName = "Ljava/lang/Exception;"; +const std::string BCUtil::kJavaThrowableName = "Ljava/lang/Throwable;"; + +const std::string BCUtil::kJavaMethodHandleInvoke = "Ljava/lang/invoke/MethodHandle;|invoke|"; +const std::string BCUtil::kJavaMethodHandleInvokeExact = "Ljava/lang/invoke/MethodHandle;|invokeExact|"; + +const std::string BCUtil::kABoolean = "AZ"; +const std::string BCUtil::kAByte = "AB"; +const std::string BCUtil::kAShort = "AS"; +const std::string BCUtil::kAChar = "AC"; +const std::string BCUtil::kAInt = "AI"; +const std::string BCUtil::kALong = "AJ"; +const std::string BCUtil::kAFloat = "AF"; +const std::string BCUtil::kADouble = "AD"; +const std::string BCUtil::kAJavaObjectName = "ALjava/lang/Object;"; + +bool BCUtil::IsWideType(const GStrIdx &name) { + return name == GetDoubleIdx() || name == GetLongIdx(); +} + +bool BCUtil::IsMorePrecisePrimitiveType(const GStrIdx &name0, const GStrIdx &name1) { + static std::vector typeWidthMap = { + BCUtil::GetVoidIdx(), + BCUtil::GetBooleanIdx(), + BCUtil::GetByteIdx(), + BCUtil::GetCharIdx(), + BCUtil::GetShortIdx(), + BCUtil::GetIntIdx(), + BCUtil::GetFloatIdx(), + BCUtil::GetLongIdx(), + BCUtil::GetDoubleIdx() + }; + if (name0 == name1) { + return false; + } + uint32 name0Idx = UINT32_MAX; + uint32 name1Idx = UINT32_MAX; + for (uint32 i = 0; i < typeWidthMap.size(); ++i) { + if (typeWidthMap[i] == name0) { + name0Idx = i; + continue; + } + if (typeWidthMap[i] == name1) { + name1Idx = i; + continue; + } + } + CHECK_FATAL(name0Idx != UINT32_MAX && name1Idx != UINT32_MAX, "name0's or name1's primitive type is not supported."); + return name0Idx > name1Idx; +} + +PrimType BCUtil::GetPrimType(const GStrIdx &typeNameIdx) { + if (typeNameIdx == BCUtil::GetBooleanIdx()) { + return PTY_u1; + } + if (typeNameIdx == BCUtil::GetByteIdx()) { + return PTY_i8; + } + if (typeNameIdx == BCUtil::GetShortIdx()) { + return PTY_i16; + } + if (typeNameIdx == BCUtil::GetCharIdx()) { + return PTY_u16; + } + if (typeNameIdx == BCUtil::GetIntIdx()) { + return PTY_i32; + } + if (typeNameIdx == BCUtil::GetLongIdx()) { + return PTY_i64; + } + if (typeNameIdx == BCUtil::GetFloatIdx()) { + return PTY_f32; + } + if (typeNameIdx == BCUtil::GetDoubleIdx()) { + return PTY_f64; + } + if (typeNameIdx == BCUtil::GetVoidIdx()) { + return PTY_void; + } + // Wide, Primitive, Agg + return PTY_ref; +} + +bool BCUtil::IsJavaReferenceType(const GStrIdx &typeNameIdx) { + PrimType primType = GetPrimType(typeNameIdx); + return (primType == PTY_ref); +} + +bool BCUtil::IsJavaPrimitveType(const GStrIdx &typeNameIdx) { + return !IsJavaReferenceType(typeNameIdx); +} + +bool BCUtil::IsJavaPrimitiveTypeName(const std::string typeName) { + return ((typeName == kBoolean) || (typeName == kByte) || (typeName == kBoolean) || (typeName == kShort) || + (typeName == kChar) || (typeName == kInt) || (typeName == kLong) || (typeName == kFloat) || + (typeName == kDouble)); +} + +bool BCUtil::IsArrayType(const GStrIdx &typeNameIdx) { + std::string typeName = GlobalTables::GetStrTable().GetStringFromStrIdx(typeNameIdx); + uint8 dim = FEUtils::GetDim(typeName); + return dim != 0; +} + +std::string BCUtil::TrimArrayModifier(const std::string &typeName) { + std::size_t index = 0; + for (; index < typeName.size(); ++index) { + if (typeName[index] != '[') { + break; + } + } + if (index != 0) { + return typeName.substr(index, typeName.size()); + } else { + return typeName; + } +} + +void BCUtil::AddDefaultDepSet(std::unordered_set &typeTable) { + typeTable.emplace("Ljava/lang/Class;"); + typeTable.emplace("Ljava/lang/Runnable;"); + typeTable.emplace("Ljava/lang/ClassLoader;"); + typeTable.emplace("Ljava/lang/StringFactory;"); + // pre-load dependent types for maple_ipa preinline phase + typeTable.emplace("Ljava/lang/System;"); + typeTable.emplace("Ljava/lang/String;"); + typeTable.emplace("Ljava/lang/Math;"); + typeTable.emplace("Ljava/lang/Long;"); + typeTable.emplace("Ljava/lang/Throwable;"); + typeTable.emplace("Ljava/io/PrintStream;"); + typeTable.emplace("Ljava/io/InputStream;"); + typeTable.emplace("Lsun/misc/FloatingDecimal;"); + typeTable.emplace("Ljava/lang/reflect/Field;"); + typeTable.emplace("Ljava/lang/annotation/Annotation;"); + typeTable.emplace("Ljava/lang/AbstractStringBuilder;"); + typeTable.emplace("Ljava/io/UnixFileSystem;"); + typeTable.emplace("Ljava/util/concurrent/atomic/AtomicInteger;"); + typeTable.emplace("Ljava/lang/reflect/Method;"); +} + +// get the serial number in register name, for example 2 in Reg2_I +uint32 BCUtil::Name2RegNum(const std::string &name) { + const std::size_t regPrefixLen = strlen("Reg"); + std::size_t numLen = name.length() - regPrefixLen; + // Nonreg names also reach here, e.g. "_this". Make sure they are not handle. + const std::size_t regVarMinLen = 6; + if (numLen < regVarMinLen - regPrefixLen || name.compare(0, regPrefixLen, "Reg") != 0) { + return UINT32_MAX; + } + std::string regName = name.substr(regPrefixLen); + std::size_t i = 0; + for (; i < numLen; i++) { + if (regName[i] < '0' || regName[i] > '9') { + break; + } + } + + if (i == 0) { + return UINT32_MAX; + } + int regNum = std::stoi(regName.substr(0, i)); + return static_cast(regNum); +} + +bool BCUtil::HasContainSuffix(const std::string &value, const std::string &suffix) { + if (suffix.size() > value.size()) { + return false; + } + return std::equal(suffix.rbegin(), suffix.rend(), value.rbegin()); +} +} // namespace bc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/common/src/rc_setter.cpp b/src/hir2mpl/bytecode_input/common/src/rc_setter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7dfda5c4625c7bb49ac397b508d695f4767d836 --- /dev/null +++ b/src/hir2mpl/bytecode_input/common/src/rc_setter.cpp @@ -0,0 +1,444 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "rc_setter.h" +#include +#include "ark_annotation_map.h" +#include "ark_annotation_processor.h" +#include "fe_manager.h" +#include "bc_util.h" + +namespace maple { +namespace bc { +RCSetter *RCSetter::rcSetter = nullptr; + +void RCSetter::ProcessClassRCAnnotation(const GStrIdx &classIdx, const std::vector &pragmas) { + if (pragmas.empty()) { + return; + } + MIRStructType *type = FEManager::GetTypeManager().GetStructTypeFromName(classIdx); + for (auto pragma : pragmas) { + if (pragma->GetKind() != kPragmaClass || pragma->GetStrIdx() != type->GetNameStrIdx()) { + continue; + } + if (!ArkAnnotation::GetInstance().IsRCUnownedOuter(pragma->GetTyIdx()) && + !ArkAnnotation::GetInstance().IsRCUnownedThis(pragma->GetTyIdx())) { + continue; + } + const std::string &className = type->GetName(); + MIRSymbol *jcSymbol = FEManager::GetMIRBuilder().GetOrCreateGlobalDecl(className, *type); + if (jcSymbol != nullptr) { + jcSymbol->SetAttr(ATTR_rcunownedthis); + } + for (auto &field : type->GetFields()) { + std::string fieldName = GlobalTables::GetStrTable().GetStringFromStrIdx(field.first); + const std::string prefix = "this_24"; + if (fieldName.compare(0, prefix.size(), prefix) == 0) { + field.second.second.SetAttr(FLDATTR_rcunowned); + } + } + } +} + +void RCSetter::ProcessMethodRCAnnotation(MIRFunction &mirFunc, const std::string &className, + MIRStructType &structType, const MIRPragma &pragma) { + if (ArkAnnotation::GetInstance().IsRCUnownedOuter(pragma.GetTyIdx()) || + ArkAnnotation::GetInstance().IsRCUnownedThis(pragma.GetTyIdx())) { + // set ATTR_rcunowned to the field this$n of local class + // the current function belongs to + MIRSymbol *jcSymbol = FEManager::GetMIRBuilder().GetOrCreateGlobalDecl(className, structType); + if (jcSymbol != nullptr) { + jcSymbol->SetAttr(ATTR_rcunownedthis); + } + for (auto &field : structType.GetFields()) { + const std::string &fieldName = GlobalTables::GetStrTable().GetStringFromStrIdx(field.first); + const std::string prefix = "this_24"; + if (fieldName.compare(0, prefix.size(), prefix) == 0) { + field.second.second.SetAttr(FLDATTR_rcunowned); + } + } + } else if (ArkAnnotation::GetInstance().IsRCUnownedCap(pragma.GetTyIdx()) || + ArkAnnotation::GetInstance().IsRCUnownedCapList(pragma.GetTyIdx())) { + // handle old RCUnownedCapRef annotation. + MIRPragmaElement *elem = pragma.GetElementVector()[0]; + if (ArkAnnotation::GetInstance().IsRCUnownedCap(pragma.GetTyIdx())) { + GStrIdx strIdx(elem->GetI32Val()); + CollectUnownedLocalVars(&mirFunc, strIdx); + } else if (ArkAnnotation::GetInstance().IsRCUnownedCapList(pragma.GetTyIdx())) { + for (auto eit : elem->GetSubElemVec()) { + if (eit->GetSubElemVec().empty()) { + continue; + } + MIRPragmaElement *e = eit->GetSubElemVec()[0]; + GStrIdx strIdx(e->GetI32Val()); + CollectUnownedLocalVars(&mirFunc, strIdx); + } + } + } +} + +void RCSetter::ProcessFieldRCAnnotation(const StructElemNameIdx &fieldElemNameIdx, + const MIRType &fieldType, const std::vector &pragmas) { + if (pragmas.empty()) { + return; + } + for (auto pragma : pragmas) { + if (pragma->GetKind() != kPragmaVar || + pragma->GetStrIdx() != fieldElemNameIdx.elem || + pragma->GetTyIdxEx() != fieldType.GetTypeIndex()) { + continue; + } + if (!ArkAnnotation::GetInstance().IsRCWeak(pragma->GetTyIdx()) && + !ArkAnnotation::GetInstance().IsRCUnowned(pragma->GetTyIdx())) { + continue; + } + FieldAttrKind attr; + if (ArkAnnotation::GetInstance().IsRCWeak(pragma->GetTyIdx())) { + attr = FLDATTR_rcweak; + } else if (ArkAnnotation::GetInstance().IsRCUnowned(pragma->GetTyIdx())) { + attr = FLDATTR_rcunowned; + } + MIRStructType *structType = FEManager::GetTypeManager().GetStructTypeFromName(fieldElemNameIdx.klass); + for (auto &field : structType->GetFields()) { + if (field.first == fieldElemNameIdx.elem) { + field.second.second.SetAttr(attr); + break; + } + } + } +} + +void RCSetter::GetUnownedVarInLocalVars(const BCClassMethod &method, MIRFunction &mirFunction) { + if (method.GetSrcLocalInfoPtr() == nullptr) { + return; + } + std::set unownedRegNums; + // map>> + for (auto &local : *method.GetSrcLocalInfoPtr()) { + for (auto &item : local.second) { + bool isUnowned = BCUtil::HasContainSuffix(std::get<0>(item), "$unowned"); + if (isUnowned) { + GStrIdx strIdx = FEManager::GetMIRBuilder().GetOrCreateStringIndex(namemangler::EncodeName(std::get<0>(item))); + CollectUnownedLocalVars(&mirFunction, strIdx); + (void)unownedRegNums.insert(local.first); + } + } + } + // set ATTR_rcunowned for symbols according their reg num. + SetAttrRCunowned(mirFunction, unownedRegNums); +} + +void RCSetter::SetAttrRCunowned(MIRFunction &mirFunction, const std::set &unownedRegNums) const { + if (unownedRegNums.empty()) { + return; + } + MIRSymbolTable *symTab = mirFunction.GetSymTab(); + if (symTab == nullptr) { + return; + } + for (uint32 i = 0; i < mirFunction.GetSymTab()->GetSymbolTableSize(); ++i) { + MIRSymbol *symbol = mirFunction.GetSymTab()->GetSymbolFromStIdx(i); + if (symbol == nullptr) { + continue; + } + MIRType *ty = symbol->GetType(); + if (ty->GetPrimType() == PTY_ref || ty->GetPrimType() == PTY_ptr) { + uint32 regNum = BCUtil::Name2RegNum(symbol->GetName()); + if (unownedRegNums.find(regNum) != unownedRegNums.end()) { + symbol->SetAttr(ATTR_rcunowned); + } + } + } +} + +void RCSetter::MarkRCUnownedForUnownedLocalFunctions() const { + // mark all local variables unowned for @UnownedLocal functions. + for (auto func : unownedLocalFuncs) { + for (uint32 idx = 0; idx < func->GetSymTab()->GetSymbolTableSize(); idx++) { + MIRSymbol *sym = func->GetSymTab()->GetSymbolFromStIdx(idx); + if (sym == nullptr) { + continue; + } + MIRType *ty = sym->GetType(); + if (ty->GetPrimType() == PTY_ref || ty->GetPrimType() == PTY_ptr) { + sym->SetAttr(ATTR_rcunowned); + } + } + } +} + +bool RCSetter::IsAnonymousInner(const MIRStructType &structType) const { + if (!(structType.GetKind() == kTypeClass || structType.GetKind() == kTypeInterface)) { + return false; + } + // inner class has annotation Ldalvik/annotation/InnerClass; + bool isCreat = false; + const std::string &className = + ArkAnnotationMap::GetArkAnnotationMap().GetAnnotationTypeName("Ldalvik_2Fannotation_2FInnerClass_3B"); + MIRStructType *inner = FEManager::GetTypeManager().GetOrCreateClassOrInterfaceType( + className, true, FETypeFlag::kSrcExtern, isCreat); + GStrIdx strIdx = FEManager::GetMIRBuilder().GetOrCreateStringIndex("name"); + unsigned tyIdx = inner->GetTypeIndex(); + if (structType.GetKind() == kTypeClass) { + const MIRClassType &classType = static_cast(structType); + for (auto it : classType.GetPragmaVec()) { + if (it->GetTyIdx() == tyIdx) { + for (auto eit : it->GetElementVector()) { + // inner class and has no name + if (eit->GetNameStrIdx() == strIdx && eit->GetI32Val() == 0) { + return true; + } + } + } + } + } else if (structType.GetKind() == kTypeInterface) { + const MIRInterfaceType &interfaceType = static_cast(structType); + for (auto it : interfaceType.GetPragmaVec()) { + if (it->GetTyIdx() == tyIdx) { + for (auto eit : it->GetElementVector()) { + // inner class and has no name + if (eit->GetNameStrIdx() == strIdx && eit->GetI32Val() == 0) { + return true; + } + } + } + } + } + return false; +} + +bool RCSetter::IsMethodEnclosing(const MIRFunction &func, const MIRStructType &structType) const { + if (!(structType.GetKind() == kTypeClass || structType.GetKind() == kTypeInterface)) { + return false; + } + bool isCreat = false; + const std::string &className = namemangler::GetInternalNameLiteral( + ArkAnnotationMap::GetArkAnnotationMap().GetAnnotationTypeName("Ldalvik_2Fannotation_2FEnclosingMethod_3B")); + MIRStructType *inner = FEManager::GetTypeManager().GetOrCreateClassOrInterfaceType( + className, true, FETypeFlag::kSrcExtern, isCreat); + unsigned tyIdx = inner->GetTypeIndex(); + if (structType.GetKind() == kTypeClass) { + const MIRClassType &classType = static_cast(structType); + for (auto it : classType.GetPragmaVec()) { + if (it->GetTyIdx() == tyIdx && !(it->GetElementVector().empty()) && + func.GetNameStrIdx() == it->GetElementVector()[0]->GetI32Val()) { + return true; + } + } + } else if (structType.GetKind() == kTypeInterface) { + const MIRInterfaceType &interfaceType = static_cast(structType); + for (auto it : interfaceType.GetPragmaVec()) { + if (it->GetTyIdx() == tyIdx && (!it->GetElementVector().empty()) && + func.GetNameStrIdx() == it->GetElementVector()[0]->GetI32Val()) { + return true; + } + } + } + return false; +} + +void RCSetter::MarkRCUnownedForAnonymousClasses() const { + // mark captured unowned fields for anonymous class. + for (auto mit : unownedLocalVars) { + MIRFunction *func = mit.first; + // check for anonymous class + // mark captured var name aaa -> val$aaa (or val_24aaa) field in anonymous class + for (auto sit : FEManager::GetTypeManager().GetStructNameTypeMap()) { + ASSERT_NOT_NULL(sit.second.first); + if (IsAnonymousInner(*(sit.second.first)) && IsMethodEnclosing(*func, *(sit.second.first))) { + for (auto &fit : sit.second.first->GetFields()) { + const std::string &fieldName = GlobalTables::GetStrTable().GetStringFromStrIdx(fit.first); + constexpr size_t prefixLength = sizeof("val_24") - 1; + if (fieldName.compare(0, prefixLength, "val_24") == 0) { + std::string nameWithSuffix = fieldName + "_24unowned"; + for (auto nit : mit.second) { + GStrIdx strIdx(nit); + const std::string &varName = GlobalTables::GetStrTable().GetStringFromStrIdx(strIdx); + if (nameWithSuffix.compare(prefixLength, varName.length(), varName) == 0 || + fieldName.compare(prefixLength, varName.length(), varName) == 0) { + fit.second.second.SetAttr(FLDATTR_rcunowned); + } + } + } + } + } + } + } +} + +void RCSetter::SetRCUnownedAttributeInternalSetFieldAttrRCUnowned(size_t opnd, const MIRFunction &calledFunc) const { + const MIRSymbol *arg = calledFunc.GetFormal(opnd); + for (const StmtNode *s = calledFunc.GetBody()->GetFirst(); s != nullptr; s = s->GetNext()) { + // 1. checking iassign statements that assign parameter arg + if (s->GetOpCode() != OP_iassign) { + continue; + } + const IassignNode *ian = static_cast(s); + const BaseNode *val = ian->GetRHS(); + if (val->GetOpCode() != OP_dread) { + continue; + } + const DreadNode *valDrn = static_cast(val); + const MIRSymbol *valSymbol = calledFunc.GetLocalOrGlobalSymbol(valDrn->GetStIdx()); + const GStrIdx &valStrIdx = valSymbol->GetNameStrIdx(); + if (valStrIdx != arg->GetNameStrIdx()) { + continue; + } + // 2. get the class fields of the iassign statement + auto it = iputStmtFieldMap.find(s); + if (it != iputStmtFieldMap.end()) { + const GStrIdx &fieldStrIdx = it->second; + // 3. set rcunwoned attribute for that field + const MIRType *type = calledFunc.GetClassType(); + CHECK_NULL_FATAL(type); + MIRType *typePtr = GlobalTables::GetTypeTable().GetTypeFromTyIdx(type->GetTypeIndex()); + MIRStructType *structType = static_cast(typePtr); + for (auto &fit : structType->GetFields()) { + if (fit.first == fieldStrIdx) { + fit.second.second.SetAttr(FLDATTR_rcunowned); + break; + } + } + } + } +} + +void RCSetter::SetRCUnownedAttribute(const CallNode &callNode, MIRFunction &func, + const MIRFunction &calledFunc, const std::set &gStrIdx) const { + for (size_t i = 0; i < callNode.NumOpnds(); ++i) { + BaseNode *bn = callNode.GetNopndAt(i); + if (bn->GetOpCode() != OP_dread) { + continue; + } + DreadNode *drn = static_cast(bn); + const MIRSymbol *symbol = func.GetLocalOrGlobalSymbol(drn->GetStIdx()); + const GStrIdx &strIdx = symbol->GetNameStrIdx(); + // checking maple name in ALIAS + for (auto als : func.GetAliasVarMap()) { + if (als.second.memPoolStrIdx != strIdx) { + continue; + } + for (auto sit : gStrIdx) { + if (sit != als.first) { + continue; + } + // now we have a link and a field need to be set rcunowned + // + // the focus is the i_th parameter arg. + // we will go through body of of the lambda class + // 1. checking iassign statements that assign parameter arg + // 2. get the class fields of the iassign statement + // 3. set rcunwoned attribute for that field + SetRCUnownedAttributeInternalSetFieldAttrRCUnowned(i, calledFunc); + } + } + } +} + +void RCSetter::MarkRCUnownedForLambdaClasses() const { + // mark captured unowned fields for lambda classes. + for (auto mit : unownedLocalVars) { + MIRFunction *func = mit.first; + // scan function body to find lambda functions used + // and set rcunowned attribute on corresponding captured fields + // of local classes for lambda functions + for (const StmtNode *stmt = func->GetBody()->GetFirst(); stmt != nullptr; stmt = stmt->GetNext()) { + if (stmt->GetOpCode() != OP_callassigned) { + continue; + } + const CallNode *call = static_cast(stmt); + MIRFunction *calledFunc = GlobalTables::GetFunctionTable().GetFuncTable().at(call->GetPUIdx()); + // only care calling of local classes for lambda functions + if (!(calledFunc->GetAttr(FUNCATTR_constructor) && calledFunc->GetAttr(FUNCATTR_public) && + calledFunc->GetAttr(FUNCATTR_synthetic))) { + continue; + } + // go through call arguments to find maple names with ALIAS info + // and their src names matching captured var names + SetRCUnownedAttribute(*call, *func, *calledFunc, mit.second); + } + } +} + +void RCSetter::MarkRCAttributes() const { + MarkRCUnownedForUnownedLocalFunctions(); + MarkRCUnownedForAnonymousClasses(); + MarkRCUnownedForLambdaClasses(); +} + +void RCSetter::CollectUnownedLocalFuncs(MIRFunction *func) { + (void)unownedLocalFuncs.insert(func); +} + +void RCSetter::CollectUnownedLocalVars(MIRFunction *func, const GStrIdx &strIdx) { + (void)unownedLocalVars[func].insert(strIdx); +} + +void RCSetter::CollectInputStmtField(StmtNode *stmt, const GStrIdx &fieldName) { + (void)iputStmtFieldMap.emplace(stmt, fieldName); +} + +void RCSetter::LoadRCFieldAttrWhiteList(const std::string &file) { + std::string line; + std::ifstream infile(file); + uint32 lineNum = 0; + std::vector vecItem; + std::vector vecAttr; + std::string item; + std::string className; + std::string fieldName; + CHECK_FATAL(infile.is_open(), "(ToIDEUser)RCFieldAttrWhiteList file %s open failed", file.c_str()); + while (std::getline(infile, line)) { + lineNum++; + if (line.at(0) == '#') { + continue; + } + std::stringstream ss; + ss.str(line); + vecItem.clear(); + while (std::getline(ss, item, ':')) { + vecItem.push_back(item); + } + CHECK_FATAL(vecItem.size() > 2, "(ToIDEUser)invalid line %d in RCFieldAttrWhiteList file %s", lineNum, + file.c_str()); + className = vecItem[0]; + fieldName = vecItem[1]; + vecAttr.clear(); + for (size_t i = 2; i < vecItem.size(); i++) { + std::string &strAttr = vecItem[i]; + if (strAttr.compare("RCWeak") == 0) { + vecAttr.push_back(FLDATTR_rcweak); + } else if (strAttr.compare("RCUnowned") == 0) { + vecAttr.push_back(FLDATTR_rcunowned); + } + } + rcFieldAttrWhiteListMap[className][fieldName] = vecAttr; + } + infile.close(); +} + +void RCSetter::SetRCFieldAttrByWhiteList(FieldAttrs &attr, const std::string &className, + const std::string &fieldName) { + auto itClass = rcFieldAttrWhiteListMap.find(className); + if (itClass != rcFieldAttrWhiteListMap.end()) { + auto itField = itClass->second.find(fieldName); + if (itField != itClass->second.end()) { + for (auto &attrIt : itField->second) { + attr.SetAttr(attrIt); + } + } + } +} +} // namespace bc +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/include/class_linker.h b/src/hir2mpl/bytecode_input/dex/include/class_linker.h new file mode 100644 index 0000000000000000000000000000000000000000..e76a7d9eb3c49ab5691c24d61d3492b4a2f1164a --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/class_linker.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef HIR2MPL_BC_INPUT_CLASS_LINKER_H +#define HIR2MPL_BC_INPUT_CLASS_LINKER_H +#include "class_loader_context.h" + +namespace maple { +class ClassLinker { + public: + explicit ClassLinker(std::vector> &classPath); + virtual ~ClassLinker() = default; + + void FindClass(const std::string &className, ClassLoaderInfo *classLoader, + std::list> &list, bool isDefClass = false); + void LoadSuperAndInterfaces(const std::unique_ptr &klass, ClassLoaderInfo *classLoader, + std::list> &klassList); + private: + std::unique_ptr FindInSharedLib(const std::string &className, ClassLoaderInfo &classLoader); + std::unique_ptr FindInBaseClassLoader(const std::string &className, ClassLoaderInfo *classLoader); + std::unique_ptr FindInClassLoaderClassPath(const std::string &className, + ClassLoaderInfo &classLoader) const; + std::vector> bootClassPath; + std::unordered_set processedClassName; +}; +} // end namespace maple +#endif // HIR2MPL_BC_INPUT_CLASS_LINKER_H diff --git a/src/hir2mpl/bytecode_input/dex/include/class_loader_context.h b/src/hir2mpl/bytecode_input/dex/include/class_loader_context.h new file mode 100644 index 0000000000000000000000000000000000000000..7b2e09f915038a1ca1efc7585036b7270019e21a --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/class_loader_context.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_CLASS_LOADER_CONTEXT_H +#define HIR2MPL_BC_INPUT_CLASS_LOADER_CONTEXT_H +#include "dex_parser.h" + +namespace maple { +enum ClassLoaderType { + kInvalidClassLoader = 0, + kPathClassLoader = 1, + kDelegateLastClassLoader = 2, + kInMemoryDexClassLoader = 3 +}; + +class ClassLoaderInfo { + public: + ClassLoaderType type; + ClassLoaderInfo *parent; + std::vector classPaths; + std::vector> hexElements; + std::vector checksums; + std::vector sharedLibraries; +}; + +class ClassLoaderContext { + public: + ClassLoaderContext(MemPool &mpIn) : mp(mpIn) {} + virtual ~ClassLoaderContext() { + loaderChain = nullptr; + } + + static ClassLoaderContext *Create(const std::string &spec, MemPool &mp); + ClassLoaderInfo *CreateClassLoader(const std::string &spec); + static bool OpenDexFiles(const std::string &spec, std::vector> &dexFileParsers); + + bool IsSpecialSharedLib() const { + return isSpecialSharedLib; + } + + const ClassLoaderInfo *GetClassLoader() const { + return loaderChain; + } + + private: + ClassLoaderType GetCLType(const std::string &clString); + const char *GetCLTypeName(ClassLoaderType type) const; + size_t FindMatchingSharedLibraryCloseMarker(const std::string& spec, size_t sharedLibraryOpenIndex); + ClassLoaderInfo *ParseInternal(const std::string &spec); + ClassLoaderInfo *ParseClassLoaderSpec(const std::string &spec); + bool ParseSharedLibraries(std::string &sharedLibrariesSpec, ClassLoaderInfo &info); + bool Parse(const std::string &spec); + ClassLoaderInfo *loaderChain = nullptr; + bool isSpecialSharedLib = false; + MemPool ∓ + static const char kPathClassLoaderString[]; + static const char kDelegateLastClassLoaderString[]; + static const char kInMemoryDexClassLoaderString[]; + static const char kClassLoaderOpeningMark; + static const char kClassLoaderClosingMark; + static const char kClassLoaderSharedLibraryOpeningMark; + static const char kClassLoaderSharedLibraryClosingMark; + static const char kClassLoaderSharedLibrarySeparator; + static const char kClassLoaderSeparator; + static const char kClasspathSeparator; + static const char kSpecialSharedLib[]; +}; +} // end namespace maple +#endif // HIR2MPL_BC_INPUT_CLASS_LOADER_CONTEXT_H diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_class.h b/src/hir2mpl/bytecode_input/dex/include/dex_class.h new file mode 100644 index 0000000000000000000000000000000000000000..bf3edbc9ef7825f8f38f4a17487bea1bc4841b9d --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_class.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL_FE_BC_INPUT_DEX_CLASS_H +#define MPL_FE_BC_INPUT_DEX_CLASS_H +#include "bc_class.h" +namespace maple { +namespace bc { +class DexClass : public BCClass { + public: + DexClass(uint32 idx, const BCParserBase &parser) : BCClass(idx, parser) {} + ~DexClass() = default; +}; + +class DexClassField : public BCClassField { + public: + DexClassField(const BCClass &klassIn, uint32 itemIdxIn, uint32 idxIn, uint32 acc, const std::string &nameIn, + const std::string &descIn) + : BCClassField(klassIn, acc, nameIn, descIn), itemIdx(itemIdxIn), idx(idxIn) {} + ~DexClassField() = default; + + protected: + uint32 GetItemIdxImpl() const override; + uint32 GetIdxImpl() const override; + bool IsStaticImpl() const override; + uint32 itemIdx; + uint32 idx; +}; + +class DEXTryInfo : public BCTryInfo { + public: + DEXTryInfo(uint32 startAddrIn, uint32 endAddrIn, std::unique_ptr>> catchesIn) + : BCTryInfo(startAddrIn, endAddrIn, std::move(catchesIn)) {} + ~DEXTryInfo() = default; +}; + +class DEXCatchInfo : public BCCatchInfo { + public: + DEXCatchInfo(uint32 pcIn, const GStrIdx &exceptionNameIdx, bool catchAll) + : BCCatchInfo(pcIn, exceptionNameIdx, catchAll) {} + ~DEXCatchInfo() = default; +}; + +class DexClassMethod : public BCClassMethod { + public: + DexClassMethod(const BCClass &klassIn, uint32 itemIdxIn, uint32 idxIn, bool isVirtualIn, uint32 acc, + const std::string &nameIn, const std::string &descIn) + : BCClassMethod(klassIn, acc, isVirtualIn, nameIn, descIn), itemIdx(itemIdxIn), idx(idxIn) {} + ~DexClassMethod() = default; + + protected: + uint32 GetItemIdxImpl() const override; + uint32 GetIdxImpl() const override; + bool IsStaticImpl() const override; + bool IsVirtualImpl() const override; + bool IsNativeImpl() const override; + bool IsInitImpl() const override; + bool IsClinitImpl() const override; + std::vector> GenArgVarListImpl() const override; + void GenArgRegsImpl() override; + uint32 itemIdx; + uint32 idx; +}; +} // namespace bc +} // namespace maple +#endif // MPL_FE_BC_INPUT_DEX_CLASS_H diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_class2fe_helper.h b/src/hir2mpl/bytecode_input/dex/include/dex_class2fe_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..1980671e617a0b466bd625dc741fddfd1e5bfa48 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_class2fe_helper.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#ifndef HIR2MPL_BC_INPUT_INCLUDE_DEX_CLASS2FE_HELPER_H +#define HIR2MPL_BC_INPUT_INCLUDE_DEX_CLASS2FE_HELPER_H +#include "bc_class2fe_helper.h" +namespace maple { +namespace bc { +class DexClass2FEHelper : public BCClass2FEHelper { + public: + DexClass2FEHelper(MapleAllocator &allocator, bc::BCClass &klassIn); + ~DexClass2FEHelper() = default; + + protected: + void InitFieldHelpersImpl() override; + void InitMethodHelpersImpl() override; + TypeAttrs GetStructAttributeFromInputImpl() const override; +}; + +class DexClassField2FEHelper : public BCClassField2FEHelper { + public: + DexClassField2FEHelper(MapleAllocator &allocator, const BCClassField &fieldIn) + : BCClassField2FEHelper(allocator, fieldIn) {} + ~DexClassField2FEHelper() = default; + + protected: + FieldAttrs AccessFlag2AttributeImpl(uint32 accessFlag) const override; +}; + +class DexClassMethod2FEHelper : public BCClassMethod2FEHelper { + public: + DexClassMethod2FEHelper(MapleAllocator &allocator, std::unique_ptr &methodIn) + : BCClassMethod2FEHelper(allocator, methodIn) {} + ~DexClassMethod2FEHelper() = default; + + protected: + FuncAttrs GetAttrsImpl() const override; + bool IsStaticImpl() const override; + + bool IsClinit() const override; + bool IsInit() const override; +}; +} +} +#endif // HIR2MPL_BC_INPUT_INCLUDE_DEX_CLASS2FE_HELPER_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_encode_value.h b/src/hir2mpl/bytecode_input/dex/include/dex_encode_value.h new file mode 100644 index 0000000000000000000000000000000000000000..e5a1b2b3bb1b0331c72f0655f3e2b14f1f5c62e3 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_encode_value.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef DEX_ENCODE_VALUE_H +#define DEX_ENCODE_VALUE_H +#include "dex_class.h" +#include "dexfile_interface.h" + +namespace maple { +namespace bc { +enum DexEncodeValueType { + kValueByte = 0x00, // (none; must be 0) ubyte[1] + kValueShort = 0x02, // size - 1 (0…1) ubyte[size] + kValueChar = 0x03, // size - 1 (0…1) ubyte[size] + kValueInt = 0x04, // size - 1 (0…3) ubyte[size] + kValueLong = 0x06, // size - 1 (0…7) ubyte[size] + kValueFloat = 0x10, // size - 1 (0…3) ubyte[size] + kValueDouble = 0x11, // size - 1 (0…7) ubyte[size] + kValueMethodType = 0x15, // size - 1 (0…3) ubyte[size] + kValueMethodHandle = 0x16, // size - 1 (0…3) ubyte[size] + kValueString = 0x17, // size - 1 (0…3) ubyte[size] + kValueType = 0x18, // size - 1 (0…3) ubyte[size] + kValueField = 0x19, // size - 1 (0…3) ubyte[size] + kValueMethod = 0x1a, // size - 1 (0…3) ubyte[size] + kValueEnum = 0x1b, // size - 1 (0…3) ubyte[size] + kValueArray = 0x1c, // (none; must be 0) encoded_array + kValueAnnotation = 0x1d, // (none; must be 0) encoded_annotation + kValueNull = 0x1e, // (none; must be 0) (none) + kValueBoolean = 0x1f // boolean (0…1) (none) +}; + +class DexEncodeValue { + public: + DexEncodeValue(MemPool &mpIn, maple::IDexFile &dexFileIn) : mp(mpIn), dexFile(dexFileIn) {} + ~DexEncodeValue() = default; + void ProcessEncodedValue(const uint8 **data, uint8 valueType, uint8 valueArg, MIRConst *&cst, uint32 &stringID); + + private: + uint64 GetUVal(const uint8 **data, uint8 len) const; + MIRType *GetTypeFromValueType(uint8 valueType) const; + void ProcessEncodedValue(const uint8 **data, MIRConst *&cst); + MIRStr16Const *ProcessStringValue(const uint8 **data, uint8 valueArg, uint32 &stringID); + MIRIntConst *ProcessIntValue(const uint8 **data, uint8 valueArg, MIRType &type); + MIRAggConst *ProcessArrayValue(const uint8 **data); + void ProcessAnnotationValue(const uint8 **data); + + MemPool ∓ + maple::IDexFile &dexFile; + union { + int32 i; + int64 j; + uint64 u; + float f; + double d; + } valBuf; +}; +} // namespace bc +} // namespace maple +#endif // DEX_ENCODE_VALUE_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_file_item_type.def b/src/hir2mpl/bytecode_input/dex/include/dex_file_item_type.def new file mode 100644 index 0000000000000000000000000000000000000000..fb8dc93c63e0f2885049c2c81ec70a3ddfc5673e --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_file_item_type.def @@ -0,0 +1,22 @@ +// DEX_FILE_ITEM_TYPE(name) +// DEX_FILE_ITEM_TYPE(HeaderItem) +DEX_FILE_ITEM_TYPE(StringIdItem) +DEX_FILE_ITEM_TYPE(TypeIdItem) +DEX_FILE_ITEM_TYPE(ProtoIdItem) +DEX_FILE_ITEM_TYPE(FieldIdItem) +DEX_FILE_ITEM_TYPE(MethodIdItem) +DEX_FILE_ITEM_TYPE(ClassDefItem) +DEX_FILE_ITEM_TYPE(CallSiteIdItem) +DEX_FILE_ITEM_TYPE(MethodHandleItem) +// DEX_FILE_ITEM_TYPE(MapList) +DEX_FILE_ITEM_TYPE(TypeList) +DEX_FILE_ITEM_TYPE(AnnotationSetRefList) +DEX_FILE_ITEM_TYPE(AnnotationSetItem) +/*DEX_FILE_ITEM_TYPE(ClassDataItem) +DEX_FILE_ITEM_TYPE(CodeItem) +DEX_FILE_ITEM_TYPE(StringDataItem) +DEX_FILE_ITEM_TYPE(DebugInfoItem) +DEX_FILE_ITEM_TYPE(AnnotationItem) +DEX_FILE_ITEM_TYPE(EncodedArrayItem) +DEX_FILE_ITEM_TYPE(AnnotationsDirectoryItem) +DEX_FILE_ITEM_TYPE(HiddenapiClassDataItem)*/ \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_file_util.h b/src/hir2mpl/bytecode_input/dex/include/dex_file_util.h new file mode 100644 index 0000000000000000000000000000000000000000..d2741f6ed83ff20bf18e79bd5909ec0867618b5c --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_file_util.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL_FE_BC_INPUT_DEX_FILE_UTIL_H +#define MPL_FE_BC_INPUT_DEX_FILE_UTIL_H +#include "types_def.h" +namespace maple { +namespace bc { +enum DexOpCode { +#define OP(opcode, category, kind, wide, throwable) kDexOp##opcode, +#include "dex_opcode.def" +#undef OP +}; + +class DexFileUtil { + public: + // Access flags + static constexpr uint32 kDexAccPublic = 0x0001; // class, method, field + static constexpr uint32 kDexAccPrivate = 0x0002; // method, field + static constexpr uint32 kDexAccProtected = 0x0004; // method, field + static constexpr uint32 kDexAccStatic = 0x0008; // method, field + static constexpr uint32 kDexAccFinal = 0x0010; // class, method, field + static constexpr uint32 kAccDexSynchronized = 0x0020; // method (only allowed on natives) + static constexpr uint32 kDexAccSuper = 0x0020; // class + static constexpr uint32 kDexAccBridge = 0x0040; // method + static constexpr uint32 kDexAccVolatile = 0x0040; // field + static constexpr uint32 kDexAccVarargs = 0x0080; // method, method + static constexpr uint32 kDexAccTransient = 0x0080; // field + static constexpr uint32 kDexAccNative = 0x0100; // method + static constexpr uint32 kDexAccInterface = 0x0200; // class + static constexpr uint32 kDexAccAbstract = 0x0400; // class, method + static constexpr uint32 kDexAccStrict = 0x0800; // method + static constexpr uint32 kDexAccSynthetic = 0x1000; // class, method + static constexpr uint32 kDexAccAnnotation = 0x2000; // class + static constexpr uint32 kDexAccEnum = 0x4000; + static constexpr uint32 kDexAccConstructor = 0x00010000; // method + static constexpr uint32 kDexDeclaredSynchronized = 0x00020000; + + enum ItemType { + kTypeHeaderItem = 0x0000, + kTypeStringIdItem, + kTypeTypeIdItem, + kTypeProtoIdItem, + kTypeFieldIdItem, + kTypeMethodIdItem, + kTypeClassDefItem, + kTypeCallSiteIdItem, + kTypeMethodHandleItem, + kTypeMapList = 0x1000, + kTypeTypeList, + kTypeAnnotationSetRefList, + kTypeAnnotationSetItem, + kTypeClassDataItem = 0x2000, + kTypeCodeItem, + kTypeStringDataItem, + kTypeDebugInfoItem, + kTypeAnnotationItem, + kTypeEncodedArrayItem, + kTypeAnnotationsDirectoryItem, + kTypeHiddenapiClassDataItem = 0xF000 + }; + + static uint32 Adler32(const uint8 *data, uint32 size); + static constexpr uint8 kMagicSize = 8; + static const uint8 kDexFileMagic[kMagicSize]; + static constexpr uint32 kCheckSumDataOffSet = 12; + static constexpr uint32 kFileSizeOffSet = 32; + static constexpr uint32 kHeaderSizeOffSet = 36; + static constexpr uint32 kEndianTagOffSet = 40; + static const uint8 kEndianConstant[4]; // 0x12345678; + static const uint8 kReverseEndianConstant[4]; // 0x78563412; + static constexpr uint32 kNoIndex = 0xffffffff; +}; +} // namespace bc +} // namespace maple +#endif // MPL_FE_BC_INPUT_DEX_FILE_UTIL_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_op.h b/src/hir2mpl/bytecode_input/dex/include/dex_op.h new file mode 100644 index 0000000000000000000000000000000000000000..4a98e2425a1d43ee8822b4cc182f8b4a2f11ee50 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_op.h @@ -0,0 +1,718 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_DEX_OP_H +#define HIR2MPL_BC_INPUT_INCLUDE_DEX_OP_H +#include +#include +#include "bc_op_factory.h" +#include "bc_instruction.h" +#include "dex_file_util.h" +#include "bc_parser_base.h" +#include "fe_manager.h" +namespace maple { +namespace bc { +class DexOp : public BCInstruction { + public: + DexOp(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOp() = default; + void SetVA(uint32 num); + void SetVB(uint32 num); + void SetWideVB(uint64 num); + void SetArgs(const MapleList &args); + void SetVC(uint32 num); + void SetVH(uint32 num); + static std::string GetArrayElementTypeFromArrayType(const std::string &typeName); + + protected: + void ParseImpl(BCClassMethod &method) override { + (void) method; + } + // Should be removed after all instruction impled + std::list EmitToFEIRStmtsImpl() override { + return std::list(); + } + + virtual void SetVAImpl(uint32 num) {} + virtual void SetVBImpl(uint32 num) {} + virtual void SetWideVBImpl(uint64 num) {} + virtual void SetArgsImpl(const MapleList &args) {}; + virtual void SetVCImpl(uint32 num) {} + virtual void SetVHImpl(uint32 num) {} + + StructElemNameIdx *structElemNameIdx = nullptr; +}; + +struct DexReg : public BCReg { + uint32 dexLitStrIdx = UINT32_MAX; // string idx of dex + uint32 dexTypeIdx = UINT32_MAX; // type idx of dex +}; + +class DexOpNop : public DexOp { + public: + DexOpNop(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpNop() = default; +}; + +// 0x01: move vA, vB ~ 0x09: move-object/16 vAAAA, vBBBB +class DexOpMove : public DexOp { + public: + DexOpMove(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpMove() = default; + + protected: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetRegTypeInTypeInferImpl() override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + DexReg vB; +}; + +// 0x0a: move-result vAA ~ 0x0c: move-result-object vAA +class DexOpMoveResult : public DexOp { + public: + DexOpMoveResult(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpMoveResult() = default; + void SetVATypeNameIdx(const GStrIdx &idx); + DexReg GetVA() const; + + protected: + void SetVAImpl(uint32 num) override; + void SetBCRegTypeImpl(const BCInstruction &inst) override; + DexReg vA; +}; + +// 0x0c +class DexOpMoveException : public DexOp { + public: + DexOpMoveException(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpMoveException() = default; + + protected: + void SetVAImpl(uint32 num) override; + void SetBCRegTypeImpl(const BCInstruction &inst) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; +}; + +// 0x0e ~ 0x11 +class DexOpReturn : public DexOp { + public: + DexOpReturn(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpReturn() = default; + + protected: + void SetVAImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + bool isReturnVoid = false; +}; + +// 0x12 ~ 0x19 +class DexOpConst : public DexOp { + public: + DexOpConst(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpConst() = default; + + protected: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetWideVBImpl(uint64 num) override; + std::list EmitToFEIRStmtsImpl() override; + + private: + DexReg vA; +}; + +// 0x1a ~ 0x1b +class DexOpConstString : public DexOp { + public: + DexOpConstString(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpConstString() = default; + + protected: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + uint32 fileIdx = 0; + DexReg vA; + MapleString strValue; +}; + +// 0x1c +class DexOpConstClass : public DexOp { + public: + DexOpConstClass(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpConstClass() = default; + + protected: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + uint32 dexTypeIdx = 0; + GStrIdx mplTypeNameIdx; +}; + +// 0x1d ~ 0x1e +class DexOpMonitor : public DexOp { + public: + DexOpMonitor(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpMonitor() = default; + + protected: + void SetVAImpl(uint32 num) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; +}; + +// 0x1f +class DexOpCheckCast : public DexOp { + public: + DexOpCheckCast(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpCheckCast() = default; + + protected: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + DexReg vDef; + uint32 targetDexTypeIdx = 0; + GStrIdx targetTypeNameIdx; +}; + +// 0x20 +class DexOpInstanceOf : public DexOp { + public: + DexOpInstanceOf(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpInstanceOf() = default; + + protected: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetVCImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + DexReg vB; + uint32 targetDexTypeIdx = 0; + std::string typeName; +}; + +// 0x21 +class DexOpArrayLength : public DexOp { + public: + DexOpArrayLength(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpArrayLength() = default; + + protected: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + DexReg vB; +}; + +// 0x22 +class DexOpNewInstance : public DexOp { + public: + DexOpNewInstance(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpNewInstance() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + bool isSkipNewString = false; + // isRcPermanent is true means the rc annotation @Permanent is used + bool isRcPermanent = false; +}; + +// 0x23 +class DexOpNewArray : public DexOp { + public: + DexOpNewArray(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpNewArray() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetVCImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + DexReg vB; + // isRcPermanent is true means the rc annotation @Permanent is used + bool isRcPermanent = false; +}; + +// 0x24 ~ 0x25 +class DexOpFilledNewArray : public DexOp { + public: + DexOpFilledNewArray(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpFilledNewArray() = default; + GStrIdx GetReturnType() const; + + protected: + std::list EmitToFEIRStmtsImpl() override; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetArgsImpl(const MapleList &args) override; + void ParseImpl(BCClassMethod &method) override; + bool isRange = false; + uint32 argsSize = 0; + uint32 dexArrayTypeIdx = UINT32_MAX; + GStrIdx arrayTypeNameIdx; + GStrIdx elemTypeNameIdx; + MapleList argRegs; + MapleVector vRegs; +}; + +// 0x26 +class DexOpFillArrayData : public DexOp { + public: + DexOpFillArrayData(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpFillArrayData() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + const int8 *arrayData = nullptr; + int32 offset = INT32_MAX; + uint32 size = 0; +}; + +// 0x27 +class DexOpThrow : public DexOp { + public: + DexOpThrow(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpThrow() = default; + + private: + void SetVAImpl(uint32 num) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; +}; + +// 0x28 ~ 0x2a +class DexOpGoto : public DexOp { + public: + DexOpGoto(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpGoto() = default; + + private: + std::vector GetTargetsImpl() const override; + void SetVAImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + int32 offset = 0; + uint32 target = 0; +}; + +// 0x2b ~ 0x2c +class DexOpSwitch : public DexOp { + public: + DexOpSwitch(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpSwitch() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::vector GetTargetsImpl() const override; + std::list EmitToFEIRStmtsImpl() override; + bool isPacked = false; + int32 offset = 0; + DexReg vA; + MapleMap> keyTargetOPpcMap; +}; + +// 0x2d ~ 0x31 +class DexOpCompare : public DexOp { + public: + DexOpCompare(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpCompare() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetVCImpl(uint32 num) override; + std::list EmitToFEIRStmtsImpl() override; + Opcode GetOpcodeFromDexIns() const; + DexReg vA; + DexReg vB; + DexReg vC; +}; + +// 0x32 ~ 0x37 +class DexOpIfTest : public DexOp { + public: + DexOpIfTest(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpIfTest() = default; + + protected: + std::vector GetTargetsImpl() const override; + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetVCImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + DexReg vB; + int32 offset = 0; + uint32 target = 0; +}; + +// 0x38 ~ 0x3d +class DexOpIfTestZ : public DexOp { + public: + DexOpIfTestZ(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpIfTestZ() = default; + + private: + std::vector GetTargetsImpl() const override; + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + int32 offset = 0; + uint32 target = 0; +}; + +// 0x3e ~ 0x43, 0x73, 0x79 ~ 0x7a, 0xe3 ~ 0x f9 +class DexOpUnused : public DexOp { + public: + DexOpUnused(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpUnused() = default; +}; + +// 0x44 ~ 0x4a +class DexOpAget : public DexOp { + public: + DexOpAget(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpAget() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetVCImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + void SetRegTypeInTypeInferImpl() override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + DexReg vB; + DexReg vC; +}; + +// 0x4a ~ 0x51 +class DexOpAput : public DexOp { + public: + DexOpAput(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpAput() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetVCImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + void SetRegTypeInTypeInferImpl() override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + DexReg vB; + DexReg vC; +}; + +// 0x52 ~ 0x58 +class DexOpIget : public DexOp { + public: + DexOpIget(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpIget() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetVCImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + DexReg vB; + uint32 index = UINT32_MAX; +}; + +// 0x59 ~ 0x5f +class DexOpIput : public DexOp { + public: + DexOpIput(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpIput() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetVCImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + DexReg vB; + uint32 index = UINT32_MAX; +}; + +// 0x60 ~ 0x66 +class DexOpSget : public DexOp { + public: + DexOpSget(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpSget() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + uint32 index = UINT32_MAX; + GStrIdx containerNameIdx; + DexReg vA; + int32 dexFileHashCode = -1; +}; + +// 0x67 ~ 0x6d +class DexOpSput : public DexOp { + public: + DexOpSput(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpSput() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + uint32 index = UINT32_MAX; + int32 dexFileHashCode = -1; +}; + +class DexOpInvoke : public DexOp { + public: + DexOpInvoke(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpInvoke() = default; + std::string GetReturnType() const; + + protected: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetVCImpl(uint32 num) override; + void SetArgsImpl(const MapleList &args) override; + void ParseImpl(BCClassMethod &method) override; + void PrepareInvokeParametersAndReturn(const FEStructMethodInfo &feMethodInfo, FEIRStmtCallAssign &stmt) const; + std::list EmitToFEIRStmtsImpl() override; + bool IsStatic() const; + bool ReplaceStringFactory(BCReader::ClassElem &methodInfo, MapleList &argRegNums); + bool isStringFactory = false; + uint32 argSize = 0; + uint32 arg0VRegNum = UINT32_MAX; + uint32 methodIdx = 0; + MapleList argRegs; + MapleVector argVRegs; + std::vector retArgsTypeNames; + DexReg retReg; +}; + +// 0x6e, 0x74 +class DexOpInvokeVirtual : public DexOpInvoke { + public: + DexOpInvokeVirtual(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpInvokeVirtual() = default; +}; + +// 0x6f, 0x75 +class DexOpInvokeSuper : public DexOpInvoke { + public: + DexOpInvokeSuper(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpInvokeSuper() = default; +}; + +// 0x70, 0x76 +class DexOpInvokeDirect : public DexOpInvoke { + public: + DexOpInvokeDirect(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpInvokeDirect() = default; +}; + +// 0x71, 0x77 +class DexOpInvokeStatic : public DexOpInvoke { + public: + DexOpInvokeStatic(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpInvokeStatic() = default; +}; + +// 0x72, 0x78 +class DexOpInvokeInterface : public DexOpInvoke { + public: + DexOpInvokeInterface(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpInvokeInterface() = default; +}; + +// 0x7b, 0x8f +class DexOpUnaryOp : public DexOp { + public: + DexOpUnaryOp(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpUnaryOp() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + std::list EmitToFEIRStmtsImpl() override; + static std::map> InitOpcodeMapForUnary(); + // map> + static inline std::map> &GetOpcodeMapForUnary() { + static std::map> opcodeMapForUnary = InitOpcodeMapForUnary(); + return opcodeMapForUnary; + } + DexReg vA; + DexReg vB; + Opcode mirOp = OP_undef; +}; + +// 0x90, 0xaf +class DexOpBinaryOp : public DexOp { + public: + DexOpBinaryOp(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpBinaryOp() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetVCImpl(uint32 num) override; + Opcode GetOpcodeFromDexIns() const; + std::list EmitToFEIRStmtsImpl() override; + DexReg vA; + DexReg vB; + DexReg vC; +}; + +// 0xb0, 0xcf +class DexOpBinaryOp2Addr : public DexOp { + public: + DexOpBinaryOp2Addr(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpBinaryOp2Addr() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + Opcode GetOpcodeFromDexIns() const; + std::list EmitToFEIRStmtsImpl() override; + DexReg vDef; + DexReg vA; + DexReg vB; +}; + +// 0xd0 ~ 0xe2 +class DexOpBinaryOpLit : public DexOp { + public: + DexOpBinaryOpLit(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpBinaryOpLit() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + void SetVCImpl(uint32 num) override; + Opcode GetOpcodeFromDexIns() const; + std::list EmitToFEIRStmtsImpl() override; + bool isLit8; // 8 bits / 16 bits signed int constant + union { + int8 i8; + int16 i16; + } constValue; + DexReg vA; + DexReg vB; +}; + +// 0xfa ~ 0xfb +class DexOpInvokePolymorphic: public DexOpInvoke { + public: + DexOpInvokePolymorphic(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpInvokePolymorphic() = default; + + protected: + void SetVHImpl(uint32 num) override; + void ParseImpl(BCClassMethod &method) override; + std::list EmitToFEIRStmtsImpl() override; + bool isStatic = false; + uint32 protoIdx = 0; + std::string fullNameMpl; + std::string protoName; + uint32 callerClassID = UINT32_MAX; +}; + +// 0xfc ~ 0xfd +class DexOpInvokeCustom : public DexOp { + public: + DexOpInvokeCustom(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpInvokeCustom() = default; + + private: + void SetVBImpl(uint32 num) override; + void SetArgsImpl(const MapleList &args) override; + MapleList argRegs; + MapleVector argVRegs; + uint32 callSiteIdx = 0; +}; + +// 0xfe +class DexOpConstMethodHandle : public DexOp { + public: + DexOpConstMethodHandle(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpConstMethodHandle() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + DexReg vA; + uint32 mhIdx = 0; +}; + +// 0xff +class DexOpConstMethodType : public DexOp { + public: + DexOpConstMethodType(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn); + ~DexOpConstMethodType() = default; + + private: + void SetVAImpl(uint32 num) override; + void SetVBImpl(uint32 num) override; + DexReg vA; + uint32 protoIdx = 0; +}; + +constexpr BCOpFactory::funcPtr dexOpGeneratorMap[] = { +#define OP(opcode, category, kind, wide, throwable) \ + BCOpFactory::BCOpGenerator, +#include "dex_opcode.def" +#undef OP +}; +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_DEX_OP_H diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_opcode.def b/src/hir2mpl/bytecode_input/dex/include/dex_opcode.def new file mode 100644 index 0000000000000000000000000000000000000000..9ab9e739fb953b0139767393855a055663fb05d6 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_opcode.def @@ -0,0 +1,257 @@ +// OP(name, category, kind, isWide, throwable) +OP(Nop, Nop, FallThru, false, false) +OP(Move, Move, FallThru, false, false) +OP(MoveFrom16, Move, FallThru, false, false) +OP(Move16, Move, FallThru, false, false) +OP(MoveWide, Move, FallThru, true, false) +OP(MoveWideFrom16, Move, FallThru, true, false) +OP(MoveWide16, Move, FallThru, true, false) +OP(MoveObject, Move, FallThru, false, false) +OP(MoveObjectFrom16, Move, FallThru, false, false) +OP(MoveObject16, Move, FallThru, false, false) +OP(MoveResult, MoveResult, FallThru, false, false) +OP(MoveResultWide, MoveResult, FallThru, true, false) +OP(MoveResultObject, MoveResult, FallThru, false, false) +OP(MoveException, MoveException, Catch | kFallThru, false, false) +OP(ReturnVoid, Return, UnKnownKind, false, false) +OP(Return, Return, UnKnownKind, false, false) +OP(ReturnWide, Return, UnKnownKind, true, false) +OP(ReturnObject, Return, UnKnownKind, false, false) +OP(Const4, Const, FallThru, false, false) +OP(Const16, Const, FallThru, false, false) +OP(Const, Const, FallThru, false, false) +OP(ConstHigh16, Const, FallThru, false, false) +OP(ConstWide16, Const, FallThru, true, false) +OP(ConstWide32, Const, FallThru, true, false) +OP(ConstWide, Const, FallThru, true, false) +OP(ConstWideHigh16, Const, FallThru, true, false) +OP(ConstString, ConstString, FallThru, false, true) +OP(ConstStringJumbo, ConstString, FallThru, false, true) +OP(ConstClass, ConstClass, FallThru, false, true) +OP(MonitorEnter, Monitor, FallThru, false, true) +OP(MonitorExit, Monitor, FallThru, false, true) +OP(CheckCast, CheckCast, FallThru, false, true) +OP(InstanceOf, InstanceOf, FallThru, false, true) +OP(ArrayLength, ArrayLength, FallThru, false, true) +OP(NewInstance, NewInstance, FallThru, false, true) +OP(NewArray, NewArray, FallThru, false, true) +OP(FilledNewArray, FilledNewArray, FallThru, false, true) +OP(FilledNewArrayRange, FilledNewArray, FallThru, false, true) +OP(FillArrayData, FillArrayData, FallThru, false, true) +OP(Throw, Throw, UnKnownKind, false, true) +OP(Goto, Goto, Goto, false, false) +OP(Goto16, Goto, Goto, false, false) +OP(Goto32, Goto, Goto, false, false) +OP(PackedSwitch, Switch, Switch | kFallThru, false, false) +OP(SparseSwitch, Switch, Switch | kFallThru, false, false) +OP(CmplFloat, Compare, FallThru, false, false) +OP(CmpgFloat, Compare, FallThru, false, false) +OP(CmplDouble, Compare, FallThru, true, false) +OP(CmpgDouble, Compare, FallThru, true, false) +OP(CmpLong, Compare, FallThru, true, false) +OP(IfEq, IfTest, ConditionBranch | kFallThru, false, false) +OP(IfNe, IfTest, ConditionBranch | kFallThru, false, false) +OP(IfLt, IfTest, ConditionBranch | kFallThru, false, false) +OP(IfGe, IfTest, ConditionBranch | kFallThru, false, false) +OP(IfGt, IfTest, ConditionBranch | kFallThru, false, false) +OP(IfLe, IfTest, ConditionBranch | kFallThru, false, false) +OP(IfEqZ, IfTestZ, ConditionBranch | kFallThru, false, false) +OP(IfNeZ, IfTestZ, ConditionBranch | kFallThru, false, false) +OP(IfLtZ, IfTestZ, ConditionBranch | kFallThru, false, false) +OP(IfGeZ, IfTestZ, ConditionBranch | kFallThru, false, false) +OP(IfGtZ, IfTestZ, ConditionBranch | kFallThru, false, false) +OP(IfLeZ, IfTestZ, ConditionBranch | kFallThru, false, false) +OP(Unused3E, Unused, UnKnownKind, false, false) +OP(Unused3F, Unused, UnKnownKind, false, false) +OP(Unused40, Unused, UnKnownKind, false, false) +OP(Unused41, Unused, UnKnownKind, false, false) +OP(Unused42, Unused, UnKnownKind, false, false) +OP(Unused43, Unused, UnKnownKind, false, false) +OP(Aget, Aget, FallThru, false, true) +OP(AgetWide, Aget, FallThru, true, true) +OP(AgetObject, Aget, FallThru, false, true) +OP(AgetBoolean, Aget, FallThru, false, true) +OP(AgetByte, Aget, FallThru, false, true) +OP(AgetChar, Aget, FallThru, false, true) +OP(AgetShort, Aget, FallThru, false, true) +OP(Aput, Aput, FallThru, false, true) +OP(AputWide, Aput, FallThru, true, true) +OP(AputObject, Aput, FallThru, false, true) +OP(AputBoolean, Aput, FallThru, false, true) +OP(AputByte, Aput, FallThru, false, true) +OP(AputChar, Aput, FallThru, false, true) +OP(AputShort, Aput, FallThru, false, true) +OP(Iget, Iget, FallThru, false, true) +OP(IgetWide, Iget, FallThru, true, true) +OP(IgetObject, Iget, FallThru, false, true) +OP(IgetBoolean, Iget, FallThru, false, true) +OP(IgetByte, Iget, FallThru, false, true) +OP(IgetChar, Iget, FallThru, false, true) +OP(IgetShort, Iget, FallThru, false, true) +OP(Iput, Iput, FallThru, false, true) +OP(IputWide, Iput, FallThru, true, true) +OP(IputObject, Iput, FallThru, false, true) +OP(IputBoolean, Iput, FallThru, false, true) +OP(IputByte, Iput, FallThru, false, true) +OP(IputChar, Iput, FallThru, false, true) +OP(IputShort, Iput, FallThru, false, true) +OP(Sget, Sget, FallThru, false, true) +OP(SgetWide, Sget, FallThru, true, true) +OP(SgetObject, Sget, FallThru, false, true) +OP(SgetBoolean, Sget, FallThru, false, true) +OP(SgetByte, Sget, FallThru, false, true) +OP(SgetChar, Sget, FallThru, false, true) +OP(SgetShort, Sget, FallThru, false, true) +OP(Sput, Sput, FallThru, false, true) +OP(SputWide, Sput, FallThru, true, true) +OP(SputObject, Sput, FallThru, false, true) +OP(SputBoolean, Sput, FallThru, false, true) +OP(SputByte, Sput, FallThru, false, true) +OP(SputChar, Sput, FallThru, false, true) +OP(SputShort, Sput, FallThru, false, true) +OP(InvokeVirtual, InvokeVirtual, FallThru, false, true) +OP(InvokeSuper, InvokeSuper, FallThru, false, true) +OP(InvokeDirect, InvokeDirect, FallThru, false, true) +OP(InvokeStatic, InvokeStatic, FallThru, false, true) +OP(InvokeInterface, InvokeInterface, FallThru, false, true) +OP(Unused73, Unused, UnKnownKind, false, false) +OP(InvokeVirtualRange, InvokeVirtual, FallThru, false, true) +OP(InvokeSuperRange, InvokeSuper, FallThru, false, true) +OP(InvokeDirectRange, InvokeDirect, FallThru, false, true) +OP(InvokeStaticRange, InvokeStatic, FallThru, false, true) +OP(InvokeInterfaceRange, InvokeInterface, FallThru, false, true) +OP(Unused79, Unused, UnKnownKind, false, false) +OP(Unused7a, Unused, UnKnownKind, false, false) +OP(NegInt, UnaryOp, FallThru, false, false) +OP(NotInt, UnaryOp, FallThru, false, false) +OP(NegLong, UnaryOp, FallThru, true, false) +OP(NotLong, UnaryOp, FallThru, true, false) +OP(NegFloat, UnaryOp, FallThru, false, false) +OP(NegDouble, UnaryOp, FallThru, true, false) +OP(IntToLong, UnaryOp, FallThru, true, false) +OP(IntToFloat, UnaryOp, FallThru, false, false) +OP(IntToDouble, UnaryOp, FallThru, true, false) +OP(LongToInt, UnaryOp, FallThru, true, false) +OP(LongToFloat, UnaryOp, FallThru, true, false) +OP(LongToDouble, UnaryOp, FallThru, true, false) +OP(FloatToInt, UnaryOp, FallThru, false, false) +OP(FloatToLong, UnaryOp, FallThru, true, false) +OP(FloatToDouble, UnaryOp, FallThru, true, false) +OP(DoubleToInt, UnaryOp, FallThru, true, false) +OP(DoubleToLong, UnaryOp, FallThru, true, false) +OP(DoubleToFloat, UnaryOp, FallThru, true, false) +OP(IntToByte, UnaryOp, FallThru, false, false) +OP(IntToChar, UnaryOp, FallThru, false, false) +OP(IntToShort, UnaryOp, FallThru, false, false) +OP(AddInt, BinaryOp, FallThru, false, false) +OP(SubInt, BinaryOp, FallThru, false, false) +OP(MulInt, BinaryOp, FallThru, false, false) +OP(DivInt, BinaryOp, FallThru, false, true) +OP(RemInt, BinaryOp, FallThru, false, true) +OP(AndInt, BinaryOp, FallThru, false, false) +OP(OrInt, BinaryOp, FallThru, false, false) +OP(XorInt, BinaryOp, FallThru, false, false) +OP(ShlInt, BinaryOp, FallThru, false, false) +OP(ShrInt, BinaryOp, FallThru, false, false) +OP(UshrInt, BinaryOp, FallThru, false, false) +OP(AddLong, BinaryOp, FallThru, true, false) +OP(SubLong, BinaryOp, FallThru, true, false) +OP(MulLong, BinaryOp, FallThru, true, false) +OP(DivLong, BinaryOp, FallThru, true, true) +OP(RemLong, BinaryOp, FallThru, true, true) +OP(AndLong, BinaryOp, FallThru, true, false) +OP(OrLong, BinaryOp, FallThru, true, false) +OP(XorLong, BinaryOp, FallThru, true, false) +OP(ShlLong, BinaryOp, FallThru, true, false) +OP(ShrLong, BinaryOp, FallThru, true, false) +OP(UshrLong, BinaryOp, FallThru, true, false) +OP(AddFloat, BinaryOp, FallThru, false, false) +OP(SubFloat, BinaryOp, FallThru, false, false) +OP(MulFloat, BinaryOp, FallThru, false, false) +OP(DivFloat, BinaryOp, FallThru, false, false) +OP(RemFloat, BinaryOp, FallThru, false, false) +OP(AddDouble, BinaryOp, FallThru, true, false) +OP(SubDouble, BinaryOp, FallThru, true, false) +OP(MulDouble, BinaryOp, FallThru, true, false) +OP(DivDouble, BinaryOp, FallThru, true, false) +OP(RemDouble, BinaryOp, FallThru, true, false) +OP(AddInt2Addr, BinaryOp2Addr, FallThru, false, false) +OP(SubInt2Addr, BinaryOp2Addr, FallThru, false, false) +OP(MulInt2Addr, BinaryOp2Addr, FallThru, false, false) +OP(DivInt2Addr, BinaryOp2Addr, FallThru, false, true) +OP(RemInt2Addr, BinaryOp2Addr, FallThru, false, true) +OP(AndInt2Addr, BinaryOp2Addr, FallThru, false, false) +OP(OrInt2Addr, BinaryOp2Addr, FallThru, false, false) +OP(XorInt2Addr, BinaryOp2Addr, FallThru, false, false) +OP(ShlInt2Addr, BinaryOp2Addr, FallThru, false, false) +OP(ShrInt2Addr, BinaryOp2Addr, FallThru, false, false) +OP(UshrInt2Addr, BinaryOp2Addr, FallThru, false, false) +OP(AddLong2Addr, BinaryOp2Addr, FallThru, true, false) +OP(SubLong2Addr, BinaryOp2Addr, FallThru, true, false) +OP(MulLong2Addr, BinaryOp2Addr, FallThru, true, false) +OP(DivLong2Addr, BinaryOp2Addr, FallThru, true, true) +OP(RemLong2Addr, BinaryOp2Addr, FallThru, true, true) +OP(AndLong2Addr, BinaryOp2Addr, FallThru, true, false) +OP(OrLong2Addr, BinaryOp2Addr, FallThru, true, false) +OP(XorLong2Addr, BinaryOp2Addr, FallThru, true, false) +OP(ShlLong2Addr, BinaryOp2Addr, FallThru, true, false) +OP(ShrLong2Addr, BinaryOp2Addr, FallThru, true, false) +OP(UshrLong2Addr, BinaryOp2Addr, FallThru, true, false) +OP(AddFloat2Addr, BinaryOp2Addr, FallThru, false, false) +OP(SubFloat2Addr, BinaryOp2Addr, FallThru, false, false) +OP(MulFloat2Addr, BinaryOp2Addr, FallThru, false, false) +OP(DivFloat2Addr, BinaryOp2Addr, FallThru, false, false) +OP(RemFloat2Addr, BinaryOp2Addr, FallThru, false, false) +OP(AddDouble2Addr, BinaryOp2Addr, FallThru, true, false) +OP(SubDouble2Addr, BinaryOp2Addr, FallThru, true, false) +OP(MulDouble2Addr, BinaryOp2Addr, FallThru, true, false) +OP(DivDouble2Addr, BinaryOp2Addr, FallThru, true, false) +OP(RemDouble2Addr, BinaryOp2Addr, FallThru, true, false) +OP(AddIntLit16, BinaryOpLit, FallThru, false, false) +OP(RsubInt, BinaryOpLit, FallThru, false, false) +OP(MulIntLit16, BinaryOpLit, FallThru, false, false) +OP(DivIntLit16, BinaryOpLit, FallThru, false, true) +OP(RemIntLit16, BinaryOpLit, FallThru, false, true) +OP(AndIntLit16, BinaryOpLit, FallThru, false, false) +OP(OrIntLit16, BinaryOpLit, FallThru, false, false) +OP(XorIntLit16, BinaryOpLit, FallThru, false, false) +OP(AddIntLit8, BinaryOpLit, FallThru, false, false) +OP(RsubIntLit8, BinaryOpLit, FallThru, false, false) +OP(MulIntLit8, BinaryOpLit, FallThru, false, false) +OP(DivIntLit8, BinaryOpLit, FallThru, false, true) +OP(RemIntLit8, BinaryOpLit, FallThru, false, true) +OP(AndIntLit8, BinaryOpLit, FallThru, false, false) +OP(OrIntLit8, BinaryOpLit, FallThru, false, false) +OP(XorIntLit8, BinaryOpLit, FallThru, false, false) +OP(ShlIntLit8, BinaryOpLit, FallThru, false, false) +OP(ShrIntLit8, BinaryOpLit, FallThru, false, false) +OP(UshrIntLit8, BinaryOpLit, FallThru, false, false) +OP(UnusedE3, Unused, UnKnownKind, false, false) +OP(UnusedE4, Unused, UnKnownKind, false, false) +OP(UnusedE5, Unused, UnKnownKind, false, false) +OP(UnusedE6, Unused, UnKnownKind, false, false) +OP(UnusedE7, Unused, UnKnownKind, false, false) +OP(UnusedE8, Unused, UnKnownKind, false, false) +OP(UnusedE9, Unused, UnKnownKind, false, false) +OP(UnusedEA, Unused, UnKnownKind, false, false) +OP(UnusedEB, Unused, UnKnownKind, false, false) +OP(UnusedEC, Unused, UnKnownKind, false, false) +OP(UnusedED, Unused, UnKnownKind, false, false) +OP(UnusedEE, Unused, UnKnownKind, false, false) +OP(UnusedEF, Unused, UnKnownKind, false, false) +OP(UnusedF0, Unused, UnKnownKind, false, false) +OP(UnusedF1, Unused, UnKnownKind, false, false) +OP(UnusedF2, Unused, UnKnownKind, false, false) +OP(UnusedF3, Unused, UnKnownKind, false, false) +OP(UnusedF4, Unused, UnKnownKind, false, false) +OP(UnusedF5, Unused, UnKnownKind, false, false) +OP(UnusedF6, Unused, UnKnownKind, false, false) +OP(UnusedF7, Unused, UnKnownKind, false, false) +OP(UnusedF8, Unused, UnKnownKind, false, false) +OP(UnusedF9, Unused, UnKnownKind, false, false) +OP(InvokePolymorphic, InvokePolymorphic, FallThru, false, true) +OP(InvokePolymorphicRange, InvokePolymorphic, FallThru, false, true) +OP(InvokeCustom, InvokeCustom, FallThru, false, true) +OP(InvokeCustomRange, InvokeCustom, FallThru, false, true) +OP(ConstMethodHandle, ConstMethodHandle, FallThru, false, true) +OP(ConstMethodType, ConstMethodType, FallThru, false, true) \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_parser.h b/src/hir2mpl/bytecode_input/dex/include/dex_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..180c69f23e988a9be63a8c2d4fb2da860228d782 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_parser.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL_FE_DEX_INPUT_DEX_PARSER_H +#define MPL_FE_DEX_INPUT_DEX_PARSER_H +#include "bc_parser.h" +#include "dex_reader.h" +#include "dex_class.h" +#include "types_def.h" + +namespace maple { +namespace bc { +class DexParser : public BCParser { + public: + DexParser(uint32 fileIdxIn, const std::string &fileNameIn, const std::list &classNamesIn); + ~DexParser() = default; + void ProcessDexClassMethod(const std::unique_ptr &dexClass, bool isVirtual, + uint32 index, std::pair &idxPair); + void SetDexFile(std::unique_ptr iDexFileIn); + std::unique_ptr FindClassDef(const std::string &className); + + protected: + const BCReader *GetReaderImpl() const override; + uint32 CalculateCheckSumImpl(const uint8 *data, uint32 size) override; + bool ParseHeaderImpl() override; + bool VerifyImpl() override; + bool RetrieveIndexTables() override; + bool RetrieveUserSpecifiedClasses(std::list> &klasses) override; + bool RetrieveAllClasses(std::list> &klasses) override; + bool CollectAllDepTypeNamesImpl(std::unordered_set &depSet) override; + bool CollectMethodDepTypeNamesImpl(std::unordered_set &depSet, BCClassMethod &bcMethod) const override; + bool CollectAllClassNamesImpl(std::unordered_set &classSet) override; + void ProcessMethodBodyImpl(BCClassMethod &method, + uint32 classIdx, uint32 methodItemIdx, bool isVirtual) const override; + + private: + std::unique_ptr ProcessDexClass(uint32 classIdx); + void ProcessDexClassDef(const std::unique_ptr &dexClass); + void ProcessDexClassInterfaceParent(const std::unique_ptr &dexClass); + void ProcessDexClassFields(const std::unique_ptr &dexClass); + void ProcessDexClassMethods(const std::unique_ptr &dexClass, bool isVirtual); + void ProcessDexClassMethodDecls(const std::unique_ptr &dexClass, bool isVirtual); + void ProcessDexClassAnnotationDirectory(const std::unique_ptr &dexClass); + void ProcessDexClassStaticFieldInitValue(const std::unique_ptr &dexClass); +}; +} // namespace bc +} // namespace maple +#endif // MPL_FE_DEX_INPUT_DEX_PARSER_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_pragma.h b/src/hir2mpl/bytecode_input/dex/include/dex_pragma.h new file mode 100644 index 0000000000000000000000000000000000000000..d6d0b00accb6aa96a10c7e41d4e5f597aff557f3 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_pragma.h @@ -0,0 +1,282 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_BC_INPUT_INCLUDE_DEX_PRAGMA_H +#define HIR2MPL_BC_INPUT_INCLUDE_DEX_PRAGMA_H +#include +#include +#include +#include "bc_pragma.h" +#include "mir_module.h" +#include "mir_const.h" +#include "mempool.h" +#include "dexfile_interface.h" + +namespace maple { +namespace bc { +class DexBCAnnotationElement { + public: + DexBCAnnotationElement(MIRModule &moduleArg, MemPool &mpArg, IDexFile &iDexFileArg, const uint8_t **annotationDataArg) + : module(moduleArg), + mp(mpArg), + iDexFile(iDexFileArg), + annotationData(annotationDataArg) {} + ~DexBCAnnotationElement() { + annotationData = nullptr; + } + + static uint64 GetUVal(const uint8 **data, uint8 len) { + // get value, max 8 bytes, little-endian + uint64 val = 0; + for (uint8 j = 0; j <= len; j++) { + val |= (static_cast(*(*data)++) << (j << 3)); + } + return val; + } + + MIRPragmaElement *EmitPragmaElement() { + return ProcessAnnotationElement(annotationData); + } + + private: + MIRPragmaElement *ProcessAnnotationElement(const uint8 **data); + void ProcessAnnotationEncodedValue(const uint8 **data, MIRPragmaElement &element, MIRConst *&cst); + void ProcessAnnotationEncodedValue(const uint8 **data, MIRPragmaElement &element, PragmaValueType valueType, + uint8 valueArg, MIRConst *&cst); + MIRIntConst *ProcessAnnotationEncodedValueInternalProcessIntValue(const uint8 **data, MIRPragmaElement &element, + uint8 valueArg, MIRType &type); + MIRStr16Const *ProcessAnnotationEncodedValueInternalProcessStringValue(const uint8 **data, MIRPragmaElement &element, + uint8 valueArg); + void ProcessAnnotationEncodedValueInternalProcessTypeValue(const uint8 **data, MIRPragmaElement &element, + uint8 valueArg); + void ProcessAnnotationEncodedValueInternalProcessFieldValue(const uint8 **data, MIRPragmaElement &element, + uint8 valueArg); + void ProcessAnnotationEncodedValueInternalProcessMethodValue(const uint8 **data, MIRPragmaElement &element, + uint8 valueArg); + MIRAggConst *ProcessAnnotationEncodedValueInternalProcessArrayValue(const uint8 **data, MIRPragmaElement &element); + void ProcessAnnotationEncodedValueInternalProcessAnnotationValue(const uint8 **data, MIRPragmaElement &element); + static MIRType *GetTypeFromValueType(PragmaValueType valueType); + + MIRModule &module; + MemPool ∓ + IDexFile &iDexFile; + const uint8_t **annotationData; +}; + +class DexBCAnnotation { + public: + DexBCAnnotation(MIRModule &moduleArg, MemPool &mpArg, IDexFile &iDexFileArg, const IDexAnnotation *iDexAnnotationArg) + : module(moduleArg), + mp(mpArg), + iDexFile(iDexFileArg), + iDexAnnotation(iDexAnnotationArg) {} + ~DexBCAnnotation() { + iDexAnnotation = nullptr; + } + + MIRPragma *EmitPragma(PragmaKind kind, const GStrIdx &pragIdx, int32 paramNum = -1, const TyIdx &tyIdxEx = TyIdx(0)); + + private: + MIRModule &module; + MemPool ∓ + IDexFile &iDexFile; + const IDexAnnotation *iDexAnnotation; +}; + +class DexBCAnnotationSet { + public: + DexBCAnnotationSet(MIRModule &moduleArg, MemPool &mpArg, IDexFile &iDexFileArg, + const IDexAnnotationSet *iDexAnnotationSetArg) + : module(moduleArg), + mp(mpArg), + iDexFile(iDexFileArg), + iDexAnnotationSet(iDexAnnotationSetArg) { + Init(); + } + + ~DexBCAnnotationSet() { + iDexAnnotationSet = nullptr; + annotations.clear(); + } + + size_t GetSize() const { + return annotations.size(); + } + + const DexBCAnnotation &GetAnnotation(size_t idx) const { + return *(annotations[idx]); + } + + void AddAnnotation(std::unique_ptr annotation) { + annotations.push_back(std::move(annotation)); + } + + bool IsValid() const { + return iDexAnnotationSet->IsValid(); + } + + std::vector &EmitPragmas(PragmaKind kind, const GStrIdx &pragIdx, int32 paramNum = -1, + const TyIdx &tyIdxEx = TyIdx(0)); + + private: + void Init(); + MIRModule &module; + MemPool ∓ + IDexFile &iDexFile; + const IDexAnnotationSet *iDexAnnotationSet; + std::vector> annotations; + std::vector pragmas; +}; + +class DexBCAnnotationSetList { + public: + DexBCAnnotationSetList(MIRModule &moduleArg, MemPool &mpArg, IDexFile &iDexFileArg, + const IDexAnnotationSetList *iDexAnnotationSetListArg) + : module(moduleArg), + mp(mpArg), + iDexFile(iDexFileArg), + iDexAnnotationSetList(iDexAnnotationSetListArg) { + Init(); + } + + ~DexBCAnnotationSetList() { + iDexAnnotationSetList = nullptr; + annotationSets.clear(); + } + + std::vector &EmitPragmas(PragmaKind kind, const GStrIdx &pragIdx); + + private: + void Init(); + MIRModule &module; + MemPool ∓ + IDexFile &iDexFile; + const IDexAnnotationSetList *iDexAnnotationSetList; + std::vector> annotationSets; + std::vector pragmas; +}; + +class DexBCFieldAnnotations { + public: + DexBCFieldAnnotations(MIRModule &moduleArg, MemPool &mpArg, IDexFile &iDexFileArg, + const IDexFieldAnnotations *iDexFieldAnnotationsArg) + : module(moduleArg), + mp(mpArg), + iDexFile(iDexFileArg), + iDexFieldAnnotations(iDexFieldAnnotationsArg) { + Init(); + } + + ~DexBCFieldAnnotations() { + iDexFieldAnnotations = nullptr; + } + std::vector &EmitPragmas(); + + private: + void Init(); + MIRModule &module; + MemPool ∓ + IDexFile &iDexFile; + const IDexFieldAnnotations *iDexFieldAnnotations; + std::unique_ptr annotationSet; +}; + +class DexBCMethodAnnotations { + public: + DexBCMethodAnnotations(MIRModule &moduleArg, MemPool &mpArg, IDexFile &iDexFileArg, + const IDexMethodAnnotations *iDexMethodAnnotationsArg) + : module(moduleArg), + mp(mpArg), + iDexFile(iDexFileArg), + iDexMethodAnnotations(iDexMethodAnnotationsArg) { + Init(); + } + + ~DexBCMethodAnnotations() { + iDexMethodAnnotations = nullptr; + } + + std::vector &EmitPragmas(); + + private: + void Init(); + void SetupFuncAttrs(); + void SetupFuncAttrWithPragma(MIRFunction &mirFunc, const MIRPragma &pragma); + MIRFunction *GetMIRFunction(const GStrIdx &nameIdx) const; + MIRModule &module; + MemPool ∓ + IDexFile &iDexFile; + const IDexMethodAnnotations *iDexMethodAnnotations = nullptr; + std::unique_ptr annotationSet; + std::vector *pragmasPtr = nullptr; + GStrIdx methodFullNameStrIdx; + const IDexMethodIdItem *methodID = nullptr; +}; + +class DexBCParameterAnnotations { + public: + DexBCParameterAnnotations(MIRModule &moduleArg, MemPool &mpArg, IDexFile &iDexFileArg, + const IDexParameterAnnotations *iDexParameterAnnotationsArg) + : module(moduleArg), + mp(mpArg), + iDexFile(iDexFileArg), + iDexParameterAnnotations(iDexParameterAnnotationsArg) { + Init(); + } + + virtual ~DexBCParameterAnnotations() = default; + std::vector &EmitPragmas(); + + private: + void Init(); + MIRModule &module; + MemPool ∓ + IDexFile &iDexFile; + const IDexParameterAnnotations *iDexParameterAnnotations; + std::unique_ptr annotationSetList; + std::vector pragmas; +}; + +class DexBCAnnotationsDirectory : public BCAnnotationsDirectory { + public: + DexBCAnnotationsDirectory(MIRModule &moduleArg, MemPool &mpArg, IDexFile &iDexFileArg, + const std::string &classNameArg, + const IDexAnnotationsDirectory *iDexAnnotationsDirectoryArg) + : BCAnnotationsDirectory(moduleArg, mpArg), + iDexFile(iDexFileArg), + className(classNameArg), + iDexAnnotationsDirectory(iDexAnnotationsDirectoryArg) { + Init(); + } + + ~DexBCAnnotationsDirectory() { + iDexAnnotationsDirectory = nullptr; + } + + protected: + std::vector &EmitPragmasImpl() override; + + private: + void Init(); + IDexFile &iDexFile; + std::string className; + const IDexAnnotationsDirectory *iDexAnnotationsDirectory; + std::unique_ptr classAnnotationSet; + std::vector> fieldAnnotationsItems; + std::vector> methodAnnotationsItems; + std::vector> parameterAnnotationsItems; +}; +} // namespace bc +} // namespace maple +#endif // HIR2MPL_BC_INPUT_INCLUDE_DEX_PRAGMA_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_reader.h b/src/hir2mpl/bytecode_input/dex/include/dex_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..eb99cc1bd1baa4c6f467f9630e3ef0b10fadb256 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_reader.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL_FE_DEX_INPUT_DEX_READER_H +#define MPL_FE_DEX_INPUT_DEX_READER_H +#include +#include +#include "dexfile_interface.h" +#include "types_def.h" +#include "bc_instruction.h" +#include "bc_class.h" +#include "bc_io.h" + +namespace maple { +namespace bc { +typedef std::map>> SrcLocalInfo; + +class DexReader : public BCReader { + public: + DexReader(uint32 fileIdxIn, const std::string &fileNameIn) + : BCReader(fileNameIn), fileIdx(fileIdxIn) {} + ~DexReader() = default; + void SetDexFile(std::unique_ptr dexFile); + uint32 GetClassItemsSize() const; + const char *GetClassJavaSourceFileName(uint32 classIdx) const; + bool IsInterface(uint32 classIdx) const; + uint32 GetClassAccFlag(uint32 classIdx) const; + std::string GetClassName(uint32 classIdx) const; + std::list GetSuperClasses(uint32 classIdx, bool mapled = false) const; + std::vector GetClassInterfaceNames(uint32 classIdx, bool mapled = false) const; + std::string GetClassFieldName(uint32 fieldIdx, bool mapled = false) const; + std::string GetClassFieldTypeName(uint32 fieldIdx, bool mapled = false) const; + std::string GetClassMethodName(uint32 methodIdx, bool mapled = false) const; + std::string GetClassMethodDescName(uint32 methodIdx, bool mapled = false) const; + MapleMap *ResolveInstructions(MapleAllocator &allocator, + const IDexMethodItem* dexMethodItem, + bool mapled = false) const; + std::unique_ptr>> ResolveTryInfos(const IDexMethodItem* dexMethodItem) const; + void ResovleSrcPositionInfo(const IDexMethodItem* dexMethodItem, + std::map &srcPosInfo) const; + std::unique_ptr ResovleSrcLocalInfo(const IDexMethodItem &dexMethodItem) const; + bool ReadAllDepTypeNames(std::unordered_set &depSet); + bool ReadMethodDepTypeNames(std::unordered_set &depSet, + uint32 classIdx, uint32 methodItemx, bool isVirtual) const; + bool ReadAllClassNames(std::unordered_set &classSet) const; + + maple::IDexFile &GetIDexFile() const { + return *iDexFile; + } + std::unordered_map GetDefiningClassNameTypeIdMap() const; // for init + const uint16 *GetMethodInstOffset(const IDexMethodItem* dexMethodItem) const; + uint16 GetClassMethodRegisterTotalSize(const IDexMethodItem* dexMethodItem) const; + uint16 GetClassMethodRegisterInSize(const IDexMethodItem* dexMethodItem) const; + uint32 GetCodeOff(const IDexMethodItem* dexMethodItem) const; + + protected: + bool OpenAndMapImpl() override; + + private: + std::string GetStringFromIdxImpl(uint32 idx) const override; + std::string GetTypeNameFromIdxImpl(uint32 idx) const override; + ClassElem GetClassMethodFromIdxImpl(uint32 idx) const override; + ClassElem GetClassFieldFromIdxImpl(uint32 idx) const override; + std::string GetSignatureImpl(uint32 idx) const override; + uint32 GetFileIndexImpl() const override; + MapleMap *ConstructBCPCInstructionMap( + MapleAllocator &allocator, const std::map> &pcInstMap) const; + BCInstruction *ConstructBCInstruction(MapleAllocator &allocator, + const std::pair> &p) const; + std::unique_ptr>> ConstructBCTryInfoList( + uint32 codeOff, const std::vector &tryItems) const; + std::unique_ptr>> ConstructBCCatchList( + std::vector &catchHandlerItems) const; + uint32 GetVA(const IDexInstruction *inst) const; + uint32 GetVB(const IDexInstruction *inst) const; + uint64 GetWideVB(const IDexInstruction *inst) const; + uint32 GetVC(const IDexInstruction *inst) const; + void GetArgVRegs(const IDexInstruction *inst, MapleList &vRegs) const; + uint32 GetVH(const IDexInstruction *inst) const; + uint8 GetWidth(const IDexInstruction *inst) const; + const char *GetOpName(const IDexInstruction *inst) const; + void ReadMethodTryCatchDepTypeNames(std::unordered_set &depSet, const IDexMethodItem &method) const; + void AddDepTypeName(std::unordered_set &depSet, const std::string &typeName, bool isTrim) const; + + uint32 fileIdx; + std::unique_ptr iDexFile; +}; +} // namespace bc +} // namespace maple +#endif // MPL_FE_DEX_INPUT_DEX_READER_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_strfac.h b/src/hir2mpl/bytecode_input/dex/include/dex_strfac.h new file mode 100644 index 0000000000000000000000000000000000000000..3b069b2c3cce4c2e24dfd63e1b83ce89422b8d11 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_strfac.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL_FE_BC_INPUT_DEX_STRFAC_H +#define MPL_FE_BC_INPUT_DEX_STRFAC_H +#include + +namespace maple { +class DexStrFactory { + public: + static std::string GetStringFactoryFuncname(const std::string &funcName); + static bool IsStringInit(const std::string &funcName); +}; +} // namespace maple +#endif // MPL_FE_BC_INPUT_DEX_STRFAC_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_strfac_map.def b/src/hir2mpl/bytecode_input/dex/include/dex_strfac_map.def new file mode 100644 index 0000000000000000000000000000000000000000..0613bd0b291de7d26a8770798ffe962ca8719f60 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_strfac_map.def @@ -0,0 +1,80 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +const char * const strV2 = "Ljava/lang/String;||()V"; +const char * const strAB2 = "Ljava/lang/String;||([B)V"; +const char * const strABI2 = "Ljava/lang/String;||([BI)V"; +const char * const strABII2 = "Ljava/lang/String;||([BII)V"; +const char * const strABIII2 = "Ljava/lang/String;||([BIII)V"; +const char * const strABIIS2 = "Ljava/lang/String;||([BIILjava/lang/String;)V"; +const char * const strABIIT2 = "Ljava/lang/String;||([BIILjava/nio/charset/Charset;)V"; +const char * const strABS2 = "Ljava/lang/String;||([BLjava/lang/String;)V"; +const char * const strABT2 = "Ljava/lang/String;||([BLjava/nio/charset/Charset;)V"; +const char * const strAC2 = "Ljava/lang/String;||([C)V"; +const char * const strACZ2 = "Ljava/lang/String;||([CZ)V"; +const char * const strACII2 = "Ljava/lang/String;||([CII)V"; +const char * const strAIII2 = "Ljava/lang/String;||([III)V"; +const char * const strIIAC2 = "Ljava/lang/String;||(II[C)V"; +const char * const strS2 = "Ljava/lang/String;||(Ljava/lang/String;)V"; +const char * const strF2 = "Ljava/lang/String;||(Ljava/lang/StringBuffer;)V"; +const char * const strD2 = "Ljava/lang/String;||(Ljava/lang/StringBuilder;)V"; +const char * const strFacV2 = "Ljava/lang/StringFactory;|newEmptyString|()Ljava/lang/String;"; +const char * const strFacAB2 = + "Ljava/lang/StringFactory;|newStringFromBytes|([B)Ljava/lang/String;"; +const char * const strFacABI2 = + "Ljava/lang/StringFactory;|newStringFromBytes|([BI)Ljava/lang/String;"; +const char * const strFacABII2 = + "Ljava/lang/StringFactory;|newStringFromBytes|([BII)Ljava/lang/String;"; +const char * const strFacABIII2 = + "Ljava/lang/StringFactory;|newStringFromBytes|([BIII)Ljava/lang/String;"; +const char * const strFacABIIS2 = + "Ljava/lang/StringFactory;|newStringFromBytes|([BIILjava/lang/String;)Ljava/lang/String;"; +const char * const strFacABIIT2 = + "Ljava/lang/StringFactory;|newStringFromBytes|([BIILjava/nio/charset/Charset;)Ljava/lang/String;"; +const char * const strFacABS2 = + "Ljava/lang/StringFactory;|newStringFromBytes|([BLjava/lang/String;)Ljava/lang/String;"; +const char * const strFacABT2 = + "Ljava/lang/StringFactory;|newStringFromBytes|([BLjava/nio/charset/Charset;)Ljava/lang/String;"; +const char * const strFacAC2 = + "Ljava/lang/StringFactory;|newStringFromChars|([C)Ljava/lang/String;"; +const char * const strFacACII2 = + "Ljava/lang/StringFactory;|newStringFromChars|([CII)Ljava/lang/String;"; +const char * const strFacAIII2 = + "Ljava/lang/StringFactory;|newStringFromCodePoints|([III)Ljava/lang/String;"; +const char * const strFacIIAC2 = + "Ljava/lang/StringFactory;|newStringFromChars|(II[C)Ljava/lang/String;"; +const char * const strFacS2 = + "Ljava/lang/StringFactory;|newStringFromString|(Ljava/lang/String;)Ljava/lang/String;"; +const char * const strFacF2 = + "Ljava/lang/StringFactory;|newStringFromStringBuffer|(Ljava/lang/StringBuffer;)Ljava/lang/String;"; +const char * const strFacD2 = + "Ljava/lang/StringFactory;|newStringFromStringBuilder|(Ljava/lang/StringBuilder;)Ljava/lang/String;"; + +STR_STRFAC_MAP2(strV2, strFacV2) +STR_STRFAC_MAP2(strAB2, strFacAB2) +STR_STRFAC_MAP2(strABI2, strFacABI2) +STR_STRFAC_MAP2(strABII2, strFacABII2) +STR_STRFAC_MAP2(strABIII2, strFacABIII2) +STR_STRFAC_MAP2(strABIIS2, strFacABIIS2) +STR_STRFAC_MAP2(strABIIT2, strFacABIIT2) +STR_STRFAC_MAP2(strABS2, strFacABS2) +STR_STRFAC_MAP2(strABT2, strFacABT2) +STR_STRFAC_MAP2(strAC2, strFacAC2) +STR_STRFAC_MAP2(strACZ2, strFacAC2) +STR_STRFAC_MAP2(strACII2, strFacACII2) +STR_STRFAC_MAP2(strAIII2, strFacAIII2) +STR_STRFAC_MAP2(strIIAC2, strFacIIAC2) +STR_STRFAC_MAP2(strS2, strFacS2) +STR_STRFAC_MAP2(strF2, strFacF2) +STR_STRFAC_MAP2(strD2, strFacD2) diff --git a/src/hir2mpl/bytecode_input/dex/include/dex_util.h b/src/hir2mpl/bytecode_input/dex/include/dex_util.h new file mode 100644 index 0000000000000000000000000000000000000000..8c51e01b7e363b06be4c0a8d9a21618fba07d475 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dex_util.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL_FE_BC_INPUT_DEX_UTIL_H +#define MPL_FE_BC_INPUT_DEX_UTIL_H +#include +#include "dex_op.h" +#include "bc_instruction.h" +#include "types_def.h" +namespace maple { +namespace bc { +static std::map dexOp2MIROp = { + { kDexOpAddInt, OP_add }, + { kDexOpSubInt, OP_sub }, + { kDexOpMulInt, OP_mul }, + { kDexOpDivInt, OP_div }, + { kDexOpRemInt, OP_rem }, + { kDexOpAndInt, OP_band }, + { kDexOpOrInt, OP_bior }, + { kDexOpXorInt, OP_bxor }, + { kDexOpShlInt, OP_shl }, + { kDexOpShrInt, OP_ashr }, + { kDexOpUshrInt, OP_lshr }, + + { kDexOpAddLong, OP_add }, + { kDexOpSubLong, OP_sub }, + { kDexOpMulLong, OP_mul }, + { kDexOpDivLong, OP_div }, + { kDexOpRemLong, OP_rem }, + { kDexOpAndLong, OP_band }, + { kDexOpOrLong, OP_bior }, + { kDexOpXorLong, OP_bxor }, + { kDexOpShlLong, OP_shl }, + { kDexOpShrLong, OP_ashr }, + { kDexOpUshrLong, OP_lshr }, + + { kDexOpAddFloat, OP_add }, + { kDexOpSubFloat, OP_sub }, + { kDexOpMulFloat, OP_mul }, + { kDexOpDivFloat, OP_div }, + { kDexOpRemFloat, OP_rem }, + { kDexOpAddDouble, OP_add }, + { kDexOpSubDouble, OP_sub }, + { kDexOpMulDouble, OP_mul }, + { kDexOpDivDouble, OP_div }, + { kDexOpRemDouble, OP_rem }, +}; + +static std::map dexOp2Addr2MIROp = { + { kDexOpAddInt2Addr, OP_add }, + { kDexOpSubInt2Addr, OP_sub }, + { kDexOpMulInt2Addr, OP_mul }, + { kDexOpDivInt2Addr, OP_div }, + { kDexOpRemInt2Addr, OP_rem }, + { kDexOpAndInt2Addr, OP_band }, + { kDexOpOrInt2Addr, OP_bior }, + { kDexOpXorInt2Addr, OP_bxor }, + { kDexOpShlInt2Addr, OP_shl }, + { kDexOpShrInt2Addr, OP_ashr }, + { kDexOpUshrInt2Addr, OP_lshr }, + + { kDexOpAddLong2Addr, OP_add }, + { kDexOpSubLong2Addr, OP_sub }, + { kDexOpMulLong2Addr, OP_mul }, + { kDexOpDivLong2Addr, OP_div }, + { kDexOpRemLong2Addr, OP_rem }, + { kDexOpAndLong2Addr, OP_band }, + { kDexOpOrLong2Addr, OP_bior }, + { kDexOpXorLong2Addr, OP_bxor }, + { kDexOpShlLong2Addr, OP_shl }, + { kDexOpShrLong2Addr, OP_ashr }, + { kDexOpUshrLong2Addr, OP_lshr }, + + { kDexOpAddFloat2Addr, OP_add }, + { kDexOpSubFloat2Addr, OP_sub }, + { kDexOpMulFloat2Addr, OP_mul }, + { kDexOpDivFloat2Addr, OP_div }, + { kDexOpRemFloat2Addr, OP_rem }, + { kDexOpAddDouble2Addr, OP_add }, + { kDexOpSubDouble2Addr, OP_sub }, + { kDexOpMulDouble2Addr, OP_mul }, + { kDexOpDivDouble2Addr, OP_div }, + { kDexOpRemDouble2Addr, OP_rem }, +}; + +static std::map dexOpCmp2MIROp = { + { kDexOpCmpLong, OP_cmp }, + { kDexOpCmplFloat, OP_cmpl }, + { kDexOpCmpgFloat, OP_cmpg }, + { kDexOpCmplDouble, OP_cmpl }, + { kDexOpCmpgDouble, OP_cmpg }, +}; + +static std::map dexOpLit2MIROp = { + { kDexOpAddIntLit16, OP_add }, + { kDexOpRsubInt, OP_sub }, + { kDexOpMulIntLit16, OP_mul }, + { kDexOpDivIntLit16, OP_div }, + { kDexOpRemIntLit16, OP_rem }, + { kDexOpAndIntLit16, OP_band }, + { kDexOpOrIntLit16, OP_bior }, + { kDexOpXorIntLit16, OP_bxor }, + + { kDexOpAddIntLit8, OP_add }, + { kDexOpRsubIntLit8, OP_sub }, + { kDexOpMulIntLit8, OP_mul }, + { kDexOpDivIntLit8, OP_div }, + { kDexOpRemIntLit8, OP_rem }, + { kDexOpAndIntLit8, OP_band }, + { kDexOpOrIntLit8, OP_bior }, + { kDexOpXorIntLit8, OP_bxor }, + { kDexOpShlIntLit8, OP_shl }, + { kDexOpShrIntLit8, OP_ashr }, + { kDexOpUshrIntLit8, OP_lshr }, +}; + +static std::map dexOpConditionOp2MIROp = { + { kDexOpIfEq, OP_eq }, + { kDexOpIfNe, OP_ne }, + { kDexOpIfLt, OP_lt }, + { kDexOpIfGe, OP_ge }, + { kDexOpIfGt, OP_gt }, + { kDexOpIfLe, OP_le }, + + { kDexOpIfEqZ, OP_eq }, + { kDexOpIfNeZ, OP_ne }, + { kDexOpIfLtZ, OP_lt }, + { kDexOpIfGeZ, OP_ge }, + { kDexOpIfGtZ, OP_gt }, + { kDexOpIfLeZ, OP_le }, +}; + +static std::map dexOpInvokeOp2MIROp = { + { kDexOpInvokeVirtual, OP_virtualcallassigned }, + { kDexOpInvokeVirtualRange, OP_virtualcallassigned }, + { kDexOpInvokeSuper, OP_superclasscallassigned }, + { kDexOpInvokeSuperRange, OP_superclasscallassigned }, + { kDexOpInvokeDirect, OP_callassigned }, + { kDexOpInvokeDirectRange, OP_callassigned }, + { kDexOpInvokeStatic, OP_callassigned }, + { kDexOpInvokeStaticRange, OP_callassigned }, + { kDexOpInvokeInterface, OP_interfacecallassigned }, + { kDexOpInvokeInterfaceRange, OP_interfacecallassigned }, +}; + +class DEXUtil { + private: + DEXUtil() = default; + ~DEXUtil() = default; +}; +} // namespace bc +} // namespace maple +#endif // MPL_FE_BC_INPUT_DEX_UTIL_H \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/include/dexfile_factory.h b/src/hir2mpl/bytecode_input/dex/include/dexfile_factory.h new file mode 100644 index 0000000000000000000000000000000000000000..9110ab59b64eb6d0cb2f105c9a497bdbc129fa1b --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dexfile_factory.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_DEX_INPUT_INCLUDE_DEXFILE_FACTORY_H +#define HIR2MPL_DEX_INPUT_INCLUDE_DEXFILE_FACTORY_H + +#include +#include "dexfile_interface.h" + +namespace maple { +class DexFileFactory { + public: + std::unique_ptr NewInstance() const; +}; +} // namespace maple + +#endif /* HIR2MPL_DEX_INPUT_INCLUDE_DEXFILE_FACTORY_H_ */ diff --git a/src/hir2mpl/bytecode_input/dex/include/dexfile_interface.h b/src/hir2mpl/bytecode_input/dex/include/dexfile_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..57e9ee0ac2b11b9fc63cea77aa2496cf39f55123 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dexfile_interface.h @@ -0,0 +1,750 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_DEX_INPUT_INCLUDE_DEXFILE_INTERFACE_H +#define HIR2MPL_DEX_INPUT_INCLUDE_DEXFILE_INTERFACE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "namemangler.h" + +namespace maple { +enum ValueType { + kByte = 0x00, + kShort = 0x02, + kChar = 0x03, + kInt = 0x04, + kLong = 0x06, + kFloat = 0x10, + kDouble = 0x11, + kMethodType = 0x15, + kMethodHandle = 0x16, + kString = 0x17, + kType = 0x18, + kField = 0x19, + kMethod = 0x1a, + kEnum = 0x1b, + kArray = 0x1c, + kAnnotation = 0x1d, + kNull = 0x1e, + kBoolean = 0x1f +}; +const uint16_t kIDexNumPackedOpcodes = 0x100; +const uint16_t kIDexPackedSwitchSignature = 0x100; +const uint16_t kIDexSparseSwitchSignature = 0x200; + +// opcode in dex file +enum IDexOpcode : uint8_t { + kOpNop = 0x00, + kOpMove = 0x01, + kOpMoveFrom16 = 0x02, + kOpMove16 = 0x03, + kOpMoveWide = 0x04, + kOpMoveWideFrom16 = 0x05, + kOpMoveWide16 = 0x06, + kOpMoveObject = 0x07, + kOpMoveObjectFrom16 = 0x08, + kOpMoveObject16 = 0x09, + kOpMoveResult = 0x0a, + kOpMoveResultWide = 0x0b, + kOpMoveResultObject = 0x0c, + kOpMoveException = 0x0d, + kOpReturnVoid = 0x0e, + kOpReturn = 0x0f, + kOpReturnWide = 0x10, + kOpReturnObject = 0x11, + kOpConst4 = 0x12, + kOpConst16 = 0x13, + kOpConst = 0x14, + kOpConstHigh16 = 0x15, + kOpConstWide16 = 0x16, + kOpConstWide32 = 0x17, + kOpConstWide = 0x18, + kOpConstWideHigh16 = 0x19, + kOpConstString = 0x1a, + kOpConstStringJumbo = 0x1b, + kOpConstClass = 0x1c, + kOpMonitorEnter = 0x1d, + kOpMonitorExit = 0x1e, + kOpCheckCast = 0x1f, + kOpInstanceOf = 0x20, + kOpArrayLength = 0x21, + kOpNewInstance = 0x22, + kOpNewArray = 0x23, + kOpFilledNewArray = 0x24, + kOpFilledNewArrayRange = 0x25, + kOpFillArrayData = 0x26, + kOpThrow = 0x27, + kOpGoto = 0x28, + kOpGoto16 = 0x29, + kOpGoto32 = 0x2a, + kOpPackedSwitch = 0x2b, + kOpSparseSwitch = 0x2c, + kOpCmplFloat = 0x2d, + kOpCmpgFloat = 0x2e, + kOpCmplDouble = 0x2f, + kOpCmpgDouble = 0x30, + kOpCmpLong = 0x31, + kOpIfEq = 0x32, + kOpIfNe = 0x33, + kOpIfLt = 0x34, + kOpIfGe = 0x35, + kOpIfGt = 0x36, + kOpIfLe = 0x37, + kOpIfEqz = 0x38, + kOpIfNez = 0x39, + kOpIfLtz = 0x3a, + kOpIfGez = 0x3b, + kOpIfGtz = 0x3c, + kOpIfLez = 0x3d, + kOpUnused3E = 0x3e, + kOpUnused3F = 0x3f, + kOpUnused40 = 0x40, + kOpUnused41 = 0x41, + kOpUnused42 = 0x42, + kOpUnused43 = 0x43, + kOpAget = 0x44, + kOpAgetWide = 0x45, + kOpAgetObject = 0x46, + kOpAgetBoolean = 0x47, + kOpAgetByte = 0x48, + kOpAgetChar = 0x49, + kOpAgetShort = 0x4a, + kOpAput = 0x4b, + kOpAputWide = 0x4c, + kOpAputObject = 0x4d, + kOpAputBoolean = 0x4e, + kOpAputByte = 0x4f, + kOpAputChar = 0x50, + kOpAputShort = 0x51, + kOpIget = 0x52, + kOpIgetWide = 0x53, + kOpIgetObject = 0x54, + kOpIgetBoolean = 0x55, + kOpIgetByte = 0x56, + kOpIgetChar = 0x57, + kOpIgetShort = 0x58, + kOpIput = 0x59, + kOpIputWide = 0x5a, + kOpIputObject = 0x5b, + kOpIputBoolean = 0x5c, + kOpIputByte = 0x5d, + kOpIputChar = 0x5e, + kOpIputShort = 0x5f, + kOpSget = 0x60, + kOpSgetWide = 0x61, + kOpSgetObject = 0x62, + kOpSgetBoolean = 0x63, + kOpSgetByte = 0x64, + kOpSgetChar = 0x65, + kOpSgetShort = 0x66, + kOpSput = 0x67, + kOpSputWide = 0x68, + kOpSputObject = 0x69, + kOpSputBoolean = 0x6a, + kOpSputByte = 0x6b, + kOpSputChar = 0x6c, + kOpSputShort = 0x6d, + kOpInvokeVirtual = 0x6e, + kOpInvokeSuper = 0x6f, + kOpInvokeDirect = 0x70, + kOpInvokeStatic = 0x71, + kOpInvokeInterface = 0x72, + kOpUnused73 = 0x73, + kOpInvokeVirtualRange = 0x74, + kOpInvokeSuperRange = 0x75, + kOpInvokeDirectRange = 0x76, + kOpInvokeStaticRange = 0x77, + kOpInvokeInterfaceRange = 0x78, + kOpUnused79 = 0x79, + kOpUnused7A = 0x7a, + kOpNegInt = 0x7b, + kOpNotInt = 0x7c, + kOpNegLong = 0x7d, + kOpNotLong = 0x7e, + kOpNegFloat = 0x7f, + kOpNegDouble = 0x80, + kOpIntToLong = 0x81, + kOpIntToFloat = 0x82, + kOpIntToDouble = 0x83, + kOpLongToInt = 0x84, + kOpLongToFloat = 0x85, + kOpLongToDouble = 0x86, + kOpFloatToInt = 0x87, + kOpFloatToLong = 0x88, + kOpFloatToDouble = 0x89, + kOpDoubleToInt = 0x8a, + kOpDoubleToLong = 0x8b, + kOpDoubleToFloat = 0x8c, + kOpIntToByte = 0x8d, + kOpIntToChar = 0x8e, + kOpIntToShort = 0x8f, + kOpAddInt = 0x90, + kOpSubInt = 0x91, + kOpMulInt = 0x92, + kOpDivInt = 0x93, + kOpRemInt = 0x94, + kOpAndInt = 0x95, + kOpOrInt = 0x96, + kOpXorInt = 0x97, + kOpShlInt = 0x98, + kOpShrInt = 0x99, + kOpUshrInt = 0x9a, + kOpAddLong = 0x9b, + kOpSubLong = 0x9c, + kOpMulLong = 0x9d, + kOpDivLong = 0x9e, + kOpRemLong = 0x9f, + kOpAndLong = 0xa0, + kOpOrLong = 0xa1, + kOpXorLong = 0xa2, + kOpShlLong = 0xa3, + kOpShrLong = 0xa4, + kOpUshrLong = 0xa5, + kOpAddFloat = 0xa6, + kOpSubFloat = 0xa7, + kOpMulFloat = 0xa8, + kOpDivFloat = 0xa9, + kOpRemFloat = 0xaa, + kOpAddDouble = 0xab, + kOpSubDouble = 0xac, + kOpMulDouble = 0xad, + kOpDivDouble = 0xae, + kOpRemDouble = 0xaf, + kOpAddInt2Addr = 0xb0, + kOpSubInt2Addr = 0xb1, + kOpMulInt2Addr = 0xb2, + kOpDivInt2Addr = 0xb3, + kOpRemInt2Addr = 0xb4, + kOpAndInt2Addr = 0xb5, + kOpOrInt2Addr = 0xb6, + kOpXorInt2Addr = 0xb7, + kOpShlInt2Addr = 0xb8, + kOpShrInt2Addr = 0xb9, + kOpUshrInt2Addr = 0xba, + kOpAddLong2Addr = 0xbb, + kOpSubLong2Addr = 0xbc, + kOpMulLong2Addr = 0xbd, + kOpDivLong2Addr = 0xbe, + kOpRemLong2Addr = 0xbf, + kOpAndLong2Addr = 0xc0, + kOpOrLong2Addr = 0xc1, + kOpXorLong2Addr = 0xc2, + kOpShlLong2Addr = 0xc3, + kOpShrLong2Addr = 0xc4, + kOpUshrLong2Addr = 0xc5, + kOpAddFloat2Addr = 0xc6, + kOpSubFloat2Addr = 0xc7, + kOpMulFloat2Addr = 0xc8, + kOpDivFloat2Addr = 0xc9, + kOpRemFloat2Addr = 0xca, + kOpAddDouble2Addr = 0xcb, + kOpSubDouble2Addr = 0xcc, + kOpMulDouble2Addr = 0xcd, + kOpDivDouble2Addr = 0xce, + kOpRemDouble2Addr = 0xcf, + kOpAddIntLit16 = 0xd0, + kOpRsubInt = 0xd1, + kOpMulIntLit16 = 0xd2, + kOpDivIntLit16 = 0xd3, + kOpRemIntLit16 = 0xd4, + kOpAndIntLit16 = 0xd5, + kOpOrIntLit16 = 0xd6, + kOpXorIntLit16 = 0xd7, + kOpAddIntLit8 = 0xd8, + kOpRsubIntLit8 = 0xd9, + kOpMulIntLit8 = 0xda, + kOpDivIntLit8 = 0xdb, + kOpRemIntLit8 = 0xdc, + kOpAndIntLit8 = 0xdd, + kOpOrIntLit8 = 0xde, + kOpXorIntLit8 = 0xdf, + kOpShlIntLit8 = 0xe0, + kOpShrIntLit8 = 0xe1, + kOpUshrIntLit8 = 0xe2, + kOpIgetVolatile = 0xe3, + kOpIputVolatile = 0xe4, + kOpSgetVolatile = 0xe5, + kOpSputVolatile = 0xe6, + kOpIgetObjectVolatile = 0xe7, + kOpIgetWideVolatile = 0xe8, + kOpIputWideVolatile = 0xe9, + kOpSgetWideVolatile = 0xea, + kOpSputWideVolatile = 0xeb, + kOpBreakpoint = 0xec, + kOpThrowVerificationError = 0xed, + kOpExecuteInline = 0xee, + kOpExecuteInlineRange = 0xef, + kOpInvokeObjectInitRange = 0xf0, + kOpReturnVoidBarrier = 0xf1, + kOpIgetQuick = 0xf2, + kOpIgetWideQuick = 0xf3, + kOpIgetObjectQuick = 0xf4, + kOpIputQuick = 0xf5, + kOpIputWideQuick = 0xf6, + kOpIputObjectQuick = 0xf7, + kOpInvokeVirtualQuick = 0xf8, + kOpInvokeVirtualQuickRange = 0xf9, + kOpInvokePolymorphic = 0xfa, + kOpInvokePolymorphicRange = 0xfb, + kOpInvokeCustom = 0xfc, + kOpInvokeCustomRange = 0xfd, + kOpSputObjectVolatile = 0xfe, + kOpUnusedFF = 0xff +}; + +enum IDexInstructionIndexType : uint8_t { + kIDexIndexUnknown = 0, + kIDexIndexNone, // has no index + kIDexIndexTypeRef, // type reference index + kIDexIndexStringRef, // string reference index + kIDexIndexMethodRef, // method reference index + kIDexIndexFieldRef, // field reference index + kIDexIndexFieldOffset, // field offset (for static linked fields) + kIDexIndexVtableOffset, // vtable offset (for static linked methods) + kIDexIndexMethodAndProtoRef, // method index and proto indexv + kIDexIndexCallSiteRef, // call site index + kIDexIndexInlineMethod, // inline method index (for inline linked methods) + kIDexIndexVaries // "It depends." Used for throw-verification-error +}; + +enum IDexInstructionFormat : uint8_t { + kIDexFmt10x, // op + kIDexFmt12x, // op vA, vB + kIDexFmt11n, // op vA, #+B + kIDexFmt11x, // op vAA + kIDexFmt10t, // op +AA + kIDexFmt20t, // op +AAAA + kIDexFmt22x, // op vAA, vBBBB + kIDexFmt21t, // op vAA, +BBBB + kIDexFmt21s, // op vAA, #+BBBB + kIDexFmt21h, // op vAA, #+BBBB00000[00000000] + kIDexFmt21c, // op vAA, thing@BBBB + kIDexFmt23x, // op vAA, vBB, vCC + kIDexFmt22b, // op vAA, vBB, #+CC + kIDexFmt22t, // op vA, vB, +CCCC + kIDexFmt22s, // op vA, vB, #+CCCC + kIDexFmt22c, // op vA, vB, thing@CCCC + kIDexFmt32x, // op vAAAA, vBBBB + kIDexFmt30t, // op +AAAAAAAA + kIDexFmt31t, // op vAA, +BBBBBBBB + kIDexFmt31i, // op vAA, #+BBBBBBBB + kIDexFmt31c, // op vAA, string@BBBBBBBB + kIDexFmt35c, // op {vC,vD,vE,vF,vG}, thing@BBBB + kIDexFmt3rc, // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB + kIDexFmt45cc, // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH + kIDexFmt4rcc, // op {VCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH + kIDexFmt51l // op vAA, #+BBBBBBBBBBBBBBBB +}; + +class IDexFile; + +class IDexInstruction { + public: + IDexInstruction() = default; + virtual ~IDexInstruction() = default; + virtual IDexOpcode GetOpcode() const = 0; + virtual const char *GetOpcodeName() const = 0; + virtual uint32_t GetVRegA() const = 0; + virtual uint32_t GetVRegB() const = 0; + virtual uint64_t GetVRegBWide() const = 0; + virtual uint32_t GetVRegC() const = 0; + virtual uint32_t GetVRegH() const = 0; + virtual uint32_t GetArg(uint32_t index) const = 0; + virtual bool HasVRegA() const = 0; + virtual bool HasVRegB() const = 0; + virtual bool HasWideVRegB() const = 0; + virtual bool HasVRegC() const = 0; + virtual bool HasVRegH() const = 0; + virtual bool HasArgs() const = 0; + virtual IDexInstructionIndexType GetIndexType() const = 0; + virtual IDexInstructionFormat GetFormat() const = 0; + virtual size_t GetWidth() const = 0; + virtual void SetOpcode(IDexOpcode opcode) = 0; + virtual void SetVRegB(uint32_t vRegB) = 0; + virtual void SetVRegBWide(uint64_t vRegBWide) = 0; + virtual void SetIndexType(IDexInstructionIndexType indexType) = 0; +}; + +class IDexCatchHandlerItem { + public: + IDexCatchHandlerItem(uint32_t typeIdx, uint32_t address) : typeIdx(typeIdx), address(address) {} + ~IDexCatchHandlerItem() = default; + IDexCatchHandlerItem(const IDexCatchHandlerItem &item) = default; + IDexCatchHandlerItem &operator=(const IDexCatchHandlerItem&) = default; + uint32_t GetHandlerTypeIdx() const; + uint32_t GetHandlerAddress() const; + bool IsCatchAllHandlerType() const; + + private: + uint32_t typeIdx; // input parameter + uint32_t address; // input parameter +}; + +class IDexTryItem { + public: + static const IDexTryItem *GetInstance(const void *item); + uint32_t GetStartAddr() const; + uint32_t GetEndAddr() const; + void GetCatchHandlerItems(const IDexFile &dexFile, uint32_t codeOff, + std::vector &items) const; + + private: + IDexTryItem() = default; + virtual ~IDexTryItem() = default; +}; + +class IDexProtoIdItem { + public: + static const IDexProtoIdItem *GetInstance(const IDexFile &dexFile, uint32_t index); + const char *GetReturnTypeName(const IDexFile &dexFile) const; + uint32_t GetParameterTypeSize(const IDexFile &dexFile) const; + void GetParameterTypeIndexes(const IDexFile &dexFile, std::vector &indexes) const; + std::string GetDescriptor(const IDexFile &dexFile) const; + const char *GetShorty(const IDexFile &dexFile) const; + + private: + IDexProtoIdItem() = default; + virtual ~IDexProtoIdItem() = default; +}; + +class IDexMethodIdItem { + public: + static const IDexMethodIdItem *GetInstance(const IDexFile &dexFile, uint32_t index); + uint32_t GetClassIdx() const; + const char *GetDefiningClassName(const IDexFile &dexFile) const; + uint16_t GetProtoIdx() const; + const IDexProtoIdItem *GetProtoIdItem(const IDexFile &dexFile) const; + uint32_t GetNameIdx() const; + const char *GetShortMethodName(const IDexFile &dexFile) const; + std::string GetDescriptor(const IDexFile &dexFile) const; + + private: + IDexMethodIdItem() = default; + virtual ~IDexMethodIdItem() = default; +}; + +class IDexMethodItem { + public: + IDexMethodItem(uint32_t methodIdx, uint32_t accessFlags, uint32_t codeOff); + uint32_t GetMethodCodeOff(const IDexMethodItem *item) const; + virtual ~IDexMethodItem() = default; + uint32_t GetMethodIdx() const; + const IDexMethodIdItem *GetMethodIdItem(const IDexFile &dexFile) const; + uint32_t GetAccessFlags() const; + bool HasCode(const IDexFile &dexFile) const; + uint16_t GetRegistersSize(const IDexFile &dexFile) const; + uint16_t GetInsSize(const IDexFile &dexFile) const; + uint16_t GetOutsSize(const IDexFile &dexFile) const; + uint16_t GetTriesSize(const IDexFile &dexFile) const; + uint32_t GetInsnsSize(const IDexFile &dexFile) const; + const uint16_t *GetInsnsByOffset(const IDexFile &dexFile, uint32_t offset) const; + uint32_t GetCodeOff() const; + bool IsStatic() const; + void GetPCInstructionMap(const IDexFile &dexFile, + std::map> &pcInstructionMap) const; + void GetTryItems(const IDexFile &dexFile, std::vector &tryItems) const; + void GetSrcPositionInfo(const IDexFile &dexFile, std::map &srcPosInfo) const; + void GetSrcLocalInfo(const IDexFile &dexFile, + std::map>> &srcLocal) const; + + private: + uint32_t methodIdx; // input parameter + uint32_t accessFlags; // input parameter + uint32_t codeOff; // input parameter +}; + +class IDexFieldIdItem { + public: + static const IDexFieldIdItem *GetInstance(const IDexFile &dexFile, uint32_t index); + uint32_t GetClassIdx() const; + const char *GetDefiningClassName(const IDexFile &dexFile) const; + uint32_t GetTypeIdx() const; + const char *GetFieldTypeName(const IDexFile &dexFile) const; + uint32_t GetNameIdx() const; + const char *GetShortFieldName(const IDexFile &dexFile) const; + + private: + IDexFieldIdItem() = default; + virtual ~IDexFieldIdItem() = default; +}; + +class IDexFieldItem { + public: + IDexFieldItem(uint32_t fieldIndex, uint32_t accessFlags); + virtual ~IDexFieldItem() = default; + uint32_t GetFieldIdx() const; + const IDexFieldIdItem *GetFieldIdItem(const IDexFile &dexFile) const; + uint32_t GetAccessFlags() const; + + private: + uint32_t fieldIndex; // input parameter + uint32_t accessFlags; // input parameter +}; + +class IDexAnnotation { + public: + static const IDexAnnotation *GetInstance(const void *data); + uint8_t GetVisibility() const; + const uint8_t *GetAnnotationData() const; + + private: + IDexAnnotation() = default; + virtual ~IDexAnnotation() = default; +}; + +class IDexAnnotationSet { + public: + static const IDexAnnotationSet *GetInstance(const void *data); + void GetAnnotations(const IDexFile &dexFile, std::vector &item) const; + bool IsValid() const; + + private: + IDexAnnotationSet() = default; + virtual ~IDexAnnotationSet() = default; +}; + +class IDexAnnotationSetList { + public: + static const IDexAnnotationSetList *GetInstance(const void *data); + void GetAnnotationSets(const IDexFile &dexFile, std::vector &items) const; + + private: + IDexAnnotationSetList() = default; + virtual ~IDexAnnotationSetList() = default; +}; + +class IDexFieldAnnotations { + public: + static const IDexFieldAnnotations *GetInstance(const void *data); + const IDexFieldIdItem *GetFieldIdItem(const IDexFile &dexFile) const; + const IDexAnnotationSet *GetAnnotationSet(const IDexFile &dexFile) const; + uint32_t GetFieldIdx() const; + + private: + IDexFieldAnnotations() = default; + virtual ~IDexFieldAnnotations() = default; +}; + +class IDexMethodAnnotations { + public: + static const IDexMethodAnnotations *GetInstance(const void *data); + const IDexMethodIdItem *GetMethodIdItem(const IDexFile &dexFile) const; + const IDexAnnotationSet *GetAnnotationSet(const IDexFile &dexFile) const; + uint32_t GetMethodIdx() const; + + private: + IDexMethodAnnotations() = default; + virtual ~IDexMethodAnnotations() = default; +}; + +class IDexParameterAnnotations { + public: + static const IDexParameterAnnotations *GetInstance(const void *data); + const IDexMethodIdItem *GetMethodIdItem(const IDexFile &dexFile) const; + const IDexAnnotationSetList *GetAnnotationSetList(const IDexFile &dexFile) const; + uint32_t GetMethodIdx() const; + + private: + IDexParameterAnnotations() = default; + virtual ~IDexParameterAnnotations() = default; +}; + +class IDexAnnotationsDirectory { + public: + static const IDexAnnotationsDirectory *GetInstance(const void *data); + bool HasClassAnnotationSet(const IDexFile &dexFile) const; + bool HasFieldAnnotationsItems(const IDexFile &dexFile) const; + bool HasMethodAnnotationsItems(const IDexFile &dexFile) const; + bool HasParameterAnnotationsItems(const IDexFile &dexFile) const; + const IDexAnnotationSet *GetClassAnnotationSet(const IDexFile &dexFile) const; + void GetFieldAnnotationsItems(const IDexFile &dexFile, + std::vector &items) const; + void GetMethodAnnotationsItems(const IDexFile &dexFile, + std::vector &items) const; + void GetParameterAnnotationsItems(const IDexFile &dexFile, + std::vector &items) const; + + private: + IDexAnnotationsDirectory() = default; + virtual ~IDexAnnotationsDirectory() = default; +}; + +class IDexClassItem { + public: + uint32_t GetClassIdx() const; + const char *GetClassName(const IDexFile &dexFile) const; + uint32_t GetAccessFlags() const; + uint32_t GetSuperclassIdx() const; + const char *GetSuperClassName(const IDexFile &dexFile) const; + uint32_t GetInterfacesOff() const; + void GetInterfaceTypeIndexes(const IDexFile &dexFile, std::vector &indexes) const; + void GetInterfaceNames(const IDexFile &dexFile, std::vector &names) const; + uint32_t GetSourceFileIdx() const; + const char *GetJavaSourceFileName(const IDexFile &dexFile) const; + bool HasAnnotationsDirectory(const IDexFile &dexFile) const; + uint32_t GetAnnotationsOff() const; + const IDexAnnotationsDirectory *GetAnnotationsDirectory(const IDexFile &dexFile) const; + uint32_t GetClassDataOff() const; + std::vector> GetFields(const IDexFile &dexFile) const; + bool HasStaticValuesList() const; + const uint8_t *GetStaticValuesList(const IDexFile &dexFile) const; + bool IsInterface() const; + bool IsSuperclassValid() const; + std::vector> GetMethodsIdxAndFlag(const IDexFile &dexFile, bool isVirtual) const; + std::unique_ptr GetDirectMethod(const IDexFile &dexFile, uint32_t index) const; + std::unique_ptr GetVirtualMethod(const IDexFile &dexFile, uint32_t index) const; + + private: + IDexClassItem() = default; + virtual ~IDexClassItem() = default; +}; + +class IDexHeader { + public: + static const IDexHeader *GetInstance(const IDexFile &dexFile); + uint8_t GetMagic(uint32_t index) const; + uint32_t GetChecksum() const; + std::string GetSignature() const; + uint32_t GetFileSize() const; + uint32_t GetHeaderSize() const; + uint32_t GetEndianTag() const; + uint32_t GetLinkSize() const; + uint32_t GetLinkOff() const; + uint32_t GetMapOff() const; + uint32_t GetStringIdsSize() const; + uint32_t GetStringIdsOff() const; + uint32_t GetTypeIdsSize() const; + uint32_t GetTypeIdsOff() const; + uint32_t GetProtoIdsSize() const; + uint32_t GetProtoIdsOff() const; + uint32_t GetFieldIdsSize() const; + uint32_t GetFieldIdsOff() const; + uint32_t GetMethodIdsSize() const; + uint32_t GetMethodIdsOff() const; + uint32_t GetClassDefsSize() const; + uint32_t GetClassDefsOff() const; + uint32_t GetDataSize() const; + uint32_t GetDataOff() const; + std::string GetDexVesion() const; + + private: + IDexHeader() = default; + virtual ~IDexHeader() = default; +}; + +class IDexMapList { + public: + static const IDexMapList *GetInstance(const void *data); + uint32_t GetSize() const; + uint16_t GetType(uint32_t index) const; + uint32_t GetTypeSize(uint32_t index) const; + + private: + IDexMapList() = default; + virtual ~IDexMapList() = default; +}; + +class ResolvedMethodHandleItem; +class ResolvedMethodType { + public: + static const ResolvedMethodType *GetInstance(const IDexFile &dexFile, const ResolvedMethodHandleItem &item); + static const ResolvedMethodType *GetInstance(const IDexFile &dexFile, uint32_t callSiteId); + static void SignatureTypes(const std::string &mt, std::list &types); + static std::string SignatureReturnType(const std::string &mt); + const std::string GetReturnType(const IDexFile &dexFile) const; + const std::string GetRawType(const IDexFile &dexFile) const; + void GetArgTypes(const IDexFile &dexFile, std::list &types) const; + private: + ResolvedMethodType() = default; + ~ResolvedMethodType() = default; +}; + +class ResolvedMethodHandleItem { + public: + static const ResolvedMethodHandleItem *GetInstance(const IDexFile &dexFile, uint32_t index); + bool IsInstance() const; + bool IsInvoke() const; + const std::string GetDeclaringClass(const IDexFile &dexFile) const; + const std::string GetMember(const IDexFile &dexFile) const; + const std::string GetMemeberProto(const IDexFile &dexFile) const; + const ResolvedMethodType *GetMethodType(const IDexFile &dexFile) const; + const std::string GetInvokeKind() const; + + private: + ResolvedMethodHandleItem() = default; + ~ResolvedMethodHandleItem() = default; +}; + +class ResolvedCallSiteIdItem { + public: + static const ResolvedCallSiteIdItem *GetInstance(const IDexFile &dexFile, uint32_t index); + uint32_t GetDataOff() const; + uint32_t GetMethodHandleIndex(const IDexFile &dexFile) const; + const ResolvedMethodType *GetMethodType(const IDexFile &dexFile) const; + const std::string GetProto(const IDexFile &dexFile) const; + const std::string GetMethodName(const IDexFile &dexFile) const; + void GetLinkArgument(const IDexFile &dexFile, std::list> &args) const; + + private: + ResolvedCallSiteIdItem() = default; + ~ResolvedCallSiteIdItem() = default; +}; + +class IDexFile { + public: + IDexFile() = default; + virtual ~IDexFile() = default; + virtual bool Open(const std::string &fileName) = 0; + virtual const void *GetData() const = 0; + virtual uint32_t GetFileIdx() const = 0; + virtual void SetFileIdx(uint32_t fileIdxArg) = 0; + virtual const uint8_t *GetBaseAddress() const = 0; + virtual const IDexHeader *GetHeader() const = 0; + virtual const IDexMapList *GetMapList() const = 0; + virtual uint32_t GetStringDataOffset(uint32_t index) const = 0; + virtual uint32_t GetTypeDescriptorIndex(uint32_t index) const = 0; + virtual const char *GetStringByIndex(uint32_t index) const = 0; + virtual const char *GetStringByTypeIndex(uint32_t index) const = 0; + virtual const IDexProtoIdItem *GetProtoIdItem(uint32_t index) const = 0; + virtual const IDexFieldIdItem *GetFieldIdItem(uint32_t index) const = 0; + virtual const IDexMethodIdItem *GetMethodIdItem(uint32_t index) const = 0; + virtual uint32_t GetClassItemsSize() const = 0; + virtual const IDexClassItem *GetClassItem(uint32_t index) const = 0; + virtual bool IsNoIndex(uint32_t index) const = 0; + virtual uint32_t GetTypeIdFromName(const std::string &className) const = 0; + virtual uint32_t ReadUnsignedLeb128(const uint8_t **pStream) const = 0; + virtual uint32_t FindClassDefIdx(const std::string &descriptor) const = 0; + virtual std::unordered_map GetDefiningClassNameTypeIdMap() const = 0; + + // ===== DecodeDebug ===== + using DebugNewPositionCallback = int (*)(void *cnxt, uint32_t address, uint32_t lineNum); + using DebugNewLocalCallback = void (*)(void *cnxt, uint16_t reg, uint32_t startAddress, uint32_t endAddress, + const char *name, const char *descriptor, const char *signature); + virtual void DecodeDebugLocalInfo(const IDexMethodItem &method, DebugNewLocalCallback newLocalCb) = 0; + virtual void DecodeDebugPositionInfo(const IDexMethodItem &method, DebugNewPositionCallback newPositionCb) = 0; + + // ===== Call Site ======= + virtual const ResolvedCallSiteIdItem *GetCallSiteIdItem(uint32_t idx) const = 0; + virtual const ResolvedMethodHandleItem *GetMethodHandleItem(uint32_t idx) const = 0; +}; +} // namespace maple +#endif // HIR2MPL_DEX_INPUT_INCLUDE_DEXFILE_INTERFACE_H diff --git a/src/hir2mpl/bytecode_input/dex/include/dexfile_libdexfile.h b/src/hir2mpl/bytecode_input/dex/include/dexfile_libdexfile.h new file mode 100644 index 0000000000000000000000000000000000000000..bbb2a59dd3e8656af312124183bfde7c94dfb7a3 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/dexfile_libdexfile.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_DEX_INPUT_INCLUDE_DEXFILE_LIBDEXFILE_H +#define HIR2MPL_DEX_INPUT_INCLUDE_DEXFILE_LIBDEXFILE_H + +#include "dexfile_interface.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace maple { +class DexInstruction : public IDexInstruction { + public: + explicit DexInstruction(const art::Instruction &artInstruction); + ~DexInstruction() = default; + void Init(); + IDexOpcode GetOpcode() const override; + const char *GetOpcodeName() const override; + uint32_t GetVRegA() const override; + uint32_t GetVRegB() const override; + uint64_t GetVRegBWide() const override; + uint32_t GetVRegC() const override; + uint32_t GetVRegH() const override; + bool HasVRegA() const override; + bool HasVRegB() const override; + bool HasWideVRegB() const override; + bool HasVRegC() const override; + bool HasVRegH() const override; + bool HasArgs() const override; + uint32_t GetArg(uint32_t index) const override; + IDexInstructionIndexType GetIndexType() const override; + IDexInstructionFormat GetFormat() const override; + size_t GetWidth() const override; + void SetOpcode(IDexOpcode opcode) override; + void SetVRegB(uint32_t vRegB) override; + void SetVRegBWide(uint64_t vRegBWide) override; + void SetIndexType(IDexInstructionIndexType indexType) override; + + private: + IDexOpcode opcode; + IDexInstructionIndexType indexType; + uint32_t vA; + uint32_t vB; + uint64_t vBWide; + uint32_t vC; + uint32_t vH; + const art::Instruction *artInstruction = nullptr; // input parameter + uint32_t arg[art::Instruction::kMaxVarArgRegs]; +}; + +class LibDexFile : public IDexFile { + public: + LibDexFile() = default; + LibDexFile(std::unique_ptr artDexFile, + std::unique_ptr contentPtrIn); + ~LibDexFile(); + bool Open(const std::string &fileName) override; + const void *GetData() const override { + return dexFile; + } + + uint32_t GetFileIdx() const override { + return fileIdx; + } + + void SetFileIdx(uint32_t fileIdxArg) override { + fileIdx = fileIdxArg; + } + + const uint8_t *GetBaseAddress() const override; + const IDexHeader *GetHeader() const override; + const IDexMapList *GetMapList() const override; + uint32_t GetStringDataOffset(uint32_t index) const override; + uint32_t GetTypeDescriptorIndex(uint32_t index) const override; + const char *GetStringByIndex(uint32_t index) const override; + const char *GetStringByTypeIndex(uint32_t index) const override; + const IDexProtoIdItem *GetProtoIdItem(uint32_t index) const override; + const IDexFieldIdItem *GetFieldIdItem(uint32_t index) const override; + const IDexMethodIdItem *GetMethodIdItem(uint32_t index) const override; + uint32_t GetClassItemsSize() const override; + const IDexClassItem *GetClassItem(uint32_t index) const override; + bool IsNoIndex(uint32_t index) const override; + uint32_t GetTypeIdFromName(const std::string &className) const override; + uint32_t ReadUnsignedLeb128(const uint8_t **pStream) const override; + uint32_t FindClassDefIdx(const std::string &descriptor) const override; + std::unordered_map GetDefiningClassNameTypeIdMap() const override; + + // ===== DecodeDebug ===== + void DecodeDebugLocalInfo(const IDexMethodItem &method, DebugNewLocalCallback newLocalCb) override; + void DecodeDebugPositionInfo(const IDexMethodItem &method, DebugNewPositionCallback newPositionCb) override; + + // ===== Call Site ======= + const ResolvedCallSiteIdItem *GetCallSiteIdItem(uint32_t idx) const override; + const ResolvedMethodHandleItem *GetMethodHandleItem(uint32_t idx) const override; + + private: + void DebugNewLocalCb(void *context, const art::DexFile::LocalInfo &entry) const; + bool DebugNewPositionCb(void *context, const art::DexFile::PositionInfo &entry) const; + bool CheckFileSize(size_t fileSize); + uint32_t fileIdx = 0; + // use for save opened content when load on-demand type from opened dexfile + std::unique_ptr contentPtr; + const art::DexFile *dexFile = nullptr; + const IDexHeader *header = nullptr; + const IDexMapList *mapList = nullptr; + DebugNewLocalCallback debugNewLocalCb = nullptr; + DebugNewPositionCallback debugNewPositionCb = nullptr; + std::string content; + std::vector> dexFiles; +}; +} // namespace maple +#endif // HIR2MPL_DEX_INPUT_INCLUDE_DEXFILE_LIBDEXFILE_H diff --git a/src/hir2mpl/bytecode_input/dex/include/string_view_format.h b/src/hir2mpl/bytecode_input/dex/include/string_view_format.h new file mode 100644 index 0000000000000000000000000000000000000000..7aafd7d83cb169d3c0fc7c7ccb853519aeb729a8 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/include/string_view_format.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef STRING_VIEW_FORMAT_H +#define STRING_VIEW_FORMAT_H +#if defined(USE_LLVM) || defined(__ANDROID__) || defined(DARWIN) +#include +using StringView = std::string_view; +#else +#include +using StringView = std::experimental::string_view; +#endif +#endif // STRING_VIEW_FORMAT_H diff --git a/src/hir2mpl/bytecode_input/dex/src/class_linker.cpp b/src/hir2mpl/bytecode_input/dex/src/class_linker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f613b045766865408ddc2fbe3205fc2752ec12c4 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/class_linker.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "class_linker.h" +#include "fe_macros.h" + +namespace maple { +ClassLinker::ClassLinker(std::vector> &classPath) { + for (std::unique_ptr& dexFileParser : classPath) { + bootClassPath.push_back(std::move(dexFileParser)); + } +} + +static std::unique_ptr FindInClassPath(const std::string &descriptor, + std::vector> &dexFileParsers) { + for (std::unique_ptr &dexFileParser : dexFileParsers) { + CHECK_NULL_FATAL(dexFileParser); + std::unique_ptr klass = dexFileParser->FindClassDef(descriptor); + if (klass != nullptr) { + return klass; + } + } + return nullptr; +} + +std::unique_ptr ClassLinker::FindInSharedLib(const std::string &className, ClassLoaderInfo &classLoader) { + for (uint32 i = 0; i < classLoader.sharedLibraries.size(); ++i) { + std::unique_ptr result = FindInBaseClassLoader(className, classLoader.sharedLibraries[i]); + if (result) { + return result; + } + } + return nullptr; +} + +std::unique_ptr ClassLinker::FindInClassLoaderClassPath(const std::string &className, + ClassLoaderInfo &classLoader) const { + return FindInClassPath(className, classLoader.hexElements); +} + +std::unique_ptr ClassLinker::FindInBaseClassLoader(const std::string &className, + ClassLoaderInfo *classLoader) { + if (classLoader == nullptr) { + return FindInClassPath(className, bootClassPath); + } + if (classLoader->type == kPathClassLoader || classLoader->type == kInMemoryDexClassLoader) { + // Parent; Shared Libraries; Class loader dex files + std::unique_ptr result = FindInBaseClassLoader(className, classLoader->parent); + if (result != nullptr) { + return result; + } + result = FindInSharedLib(className, *classLoader); + if (result != nullptr) { + return result; + } + return FindInClassLoaderClassPath(className, *classLoader); + } + if (classLoader->type == kDelegateLastClassLoader) { + // Boot class path; Shared class path; Class loader dex files; Parent + std::unique_ptr result = FindInClassPath(className, bootClassPath); + if (result != nullptr) { + return result; + } + result = FindInSharedLib(className, *classLoader); + if (result != nullptr) { + return result; + } + result = FindInClassLoaderClassPath(className, *classLoader); + if (result != nullptr) { + return result; + } + return FindInBaseClassLoader(className, classLoader->parent); + } + return nullptr; +} + +void ClassLinker::LoadSuperAndInterfaces(const std::unique_ptr &klass, ClassLoaderInfo *classLoader, + std::list> &klassList) { + if (klass->GetSuperClassNames().size() > 0) { + FindClass(klass->GetSuperClassNames().front(), classLoader, klassList); + } + for (std::string interfaceName : klass->GetSuperInterfaceNames()) { + FindClass(interfaceName, classLoader, klassList); + } +} + +void ClassLinker::FindClass(const std::string &className, ClassLoaderInfo *classLoader, + std::list> &klassList, bool isDefClass) { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(className); + auto it = processedClassName.find(nameIdx); + if (it != processedClassName.end()) { + if (isDefClass) { + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "Same class is existed: %s", className.c_str()); + } + return; + } + // Find in bootclasspath + std::unique_ptr klass; + if (classLoader == nullptr) { + klass = FindInClassPath(className, bootClassPath); + } else { // Find in classLoader files + klass = FindInBaseClassLoader(className, classLoader); + } + if (klass != nullptr) { + if (isDefClass) { + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "Same class is existed: %s", className.c_str()); + } + FE_INFO_LEVEL(FEOptions::kDumpLevelInfoDetail, "klassName=%s", klass->GetClassName(false).c_str()); + LoadSuperAndInterfaces(klass, classLoader, klassList); + (void)processedClassName.insert(nameIdx); + klassList.push_back(std::move(klass)); + } else if (!isDefClass) { + WARN(kLncWarn, "Find class failed: %s", className.c_str()); + } +} +} diff --git a/src/hir2mpl/bytecode_input/dex/src/class_loader_context.cpp b/src/hir2mpl/bytecode_input/dex/src/class_loader_context.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c47b6e6d60d3b8d1b15d6d00b83fac6f1b76f623 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/class_loader_context.cpp @@ -0,0 +1,281 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include +#include "dexfile_libdexfile.h" +#include "class_loader_context.h" + +namespace maple { +const char ClassLoaderContext::kPathClassLoaderString[] = "PCL"; +const char ClassLoaderContext::kDelegateLastClassLoaderString[] = "DLC"; +const char ClassLoaderContext::kInMemoryDexClassLoaderString[] = "IMC"; +const char ClassLoaderContext::kClassLoaderOpeningMark = '['; +const char ClassLoaderContext::kClassLoaderClosingMark = ']'; +const char ClassLoaderContext::kClassLoaderSharedLibraryOpeningMark = '{'; +const char ClassLoaderContext::kClassLoaderSharedLibraryClosingMark = '}'; +const char ClassLoaderContext::kClassLoaderSharedLibrarySeparator = '#'; +const char ClassLoaderContext::kClassLoaderSeparator = ';'; +const char ClassLoaderContext::kClasspathSeparator = ','; +const char ClassLoaderContext::kSpecialSharedLib[] = "&"; + +size_t ClassLoaderContext::FindMatchingSharedLibraryCloseMarker(const std::string& spec, + size_t sharedLibraryOpenIndex) { + uint32_t counter = 1; + size_t stringIndex = sharedLibraryOpenIndex + 1; + size_t sharedLibraryClose = std::string::npos; + while (counter != 0) { + sharedLibraryClose = spec.find_first_of(kClassLoaderSharedLibraryClosingMark, stringIndex); + size_t sharedLibraryOpen = spec.find_first_of(kClassLoaderSharedLibraryOpeningMark, stringIndex); + if (sharedLibraryClose == std::string::npos) { + break; + } + if ((sharedLibraryOpen == std::string::npos) || + (sharedLibraryClose < sharedLibraryOpen)) { + --counter; + stringIndex = sharedLibraryClose + 1; + } else { + ++counter; + stringIndex = sharedLibraryOpen + 1; + } + } + return sharedLibraryClose; +} + +ClassLoaderType ClassLoaderContext::GetCLType(const std::string& clString) { + if (clString.compare(0, strlen(kPathClassLoaderString), kPathClassLoaderString) == 0) { + return kPathClassLoader; + } else if (clString.compare(0, strlen(kDelegateLastClassLoaderString), kDelegateLastClassLoaderString) == 0) { + return kDelegateLastClassLoader; + } else if (clString.compare(0, strlen(kInMemoryDexClassLoaderString), kInMemoryDexClassLoaderString) == 0) { + return kInMemoryDexClassLoader; + } + return kInvalidClassLoader; +} + +const char* ClassLoaderContext::GetCLTypeName(ClassLoaderType type) const { + switch (type) { + case kPathClassLoader: { + return kPathClassLoaderString; + } + case kDelegateLastClassLoader: { + return kDelegateLastClassLoaderString; + } + case kInMemoryDexClassLoader: { + return kInMemoryDexClassLoaderString; + } + default: { + return nullptr; + } + } +} + +ClassLoaderInfo *ClassLoaderContext::ParseClassLoaderSpec(const std::string &spec) { + ClassLoaderType classLoaderType = GetCLType(spec); + if (classLoaderType == kInvalidClassLoader) { + return nullptr; + } + if (classLoaderType == kInMemoryDexClassLoader) { + return nullptr; + } + const char* classLoaderTypeStr = GetCLTypeName(classLoaderType); + CHECK_FATAL(classLoaderTypeStr != nullptr, "classLoaderTypeStr return a nullptr!"); + size_t typeStrZize = strlen(classLoaderTypeStr); + // Check the opening and closing markers. + if (spec[typeStrZize] != kClassLoaderOpeningMark) { + return nullptr; + } + if ((spec[spec.length() - 1] != kClassLoaderClosingMark) && + (spec[spec.length() - 1] != kClassLoaderSharedLibraryClosingMark)) { + return nullptr; + } + size_t closingIndex = spec.find_first_of(kClassLoaderClosingMark); + std::string classpath = spec.substr(typeStrZize + 1, closingIndex - typeStrZize - 1); + ClassLoaderInfo *info = mp.New(); + info->type = classLoaderType; + if (!OpenDexFiles(classpath, info->hexElements)) { + return nullptr; + }; + if ((spec[spec.length() - 1] == kClassLoaderSharedLibraryClosingMark) && + (spec[spec.length() - 2] != kClassLoaderSharedLibraryOpeningMark)) { + size_t startIndex = spec.find_first_of(kClassLoaderSharedLibraryOpeningMark); + if (startIndex == std::string::npos) { + return nullptr; + } + std::string sharedLibrariesSpec = spec.substr(startIndex + 1, spec.length() - startIndex - 2); + if (!ParseSharedLibraries(sharedLibrariesSpec, *info)) { + return nullptr; + } + } + return info; +} + +bool ClassLoaderContext::ParseSharedLibraries(std::string &sharedLibrariesSpec, ClassLoaderInfo &info) { + size_t cursor = 0; + while (cursor != sharedLibrariesSpec.length()) { + size_t sharedLibrarySeparator = sharedLibrariesSpec.find_first_of(kClassLoaderSharedLibrarySeparator, cursor); + size_t sharedLibraryOpen = sharedLibrariesSpec.find_first_of(kClassLoaderSharedLibraryOpeningMark, cursor); + std::string sharedLibrarySpec; + if (sharedLibrarySeparator == std::string::npos) { + sharedLibrarySpec = sharedLibrariesSpec.substr(cursor, sharedLibrariesSpec.length() - cursor); + cursor = sharedLibrariesSpec.length(); + } else if ((sharedLibraryOpen == std::string::npos) || (sharedLibraryOpen > sharedLibrarySeparator)) { + sharedLibrarySpec = sharedLibrariesSpec.substr(cursor, sharedLibrarySeparator - cursor); + cursor = sharedLibrarySeparator + 1; + } else { + size_t closing_marker = FindMatchingSharedLibraryCloseMarker(sharedLibrariesSpec, sharedLibraryOpen); + if (closing_marker == std::string::npos) { + return false; + } + sharedLibrarySpec = sharedLibrariesSpec.substr(cursor, closing_marker + 1 - cursor); + cursor = closing_marker + 1; + if (cursor != sharedLibrariesSpec.length() && + sharedLibrariesSpec[cursor] == kClassLoaderSharedLibrarySeparator) { + ++cursor; + } + } + ClassLoaderInfo *sharedLibrary = ParseInternal(sharedLibrarySpec); + if (sharedLibrary == nullptr) { + return false; + } + info.sharedLibraries.push_back(sharedLibrary); + } + return true; +} + +ClassLoaderInfo *ClassLoaderContext::ParseInternal(const std::string &spec) { + std::string remaining = spec; + ClassLoaderInfo *first = nullptr; + ClassLoaderInfo *previousIteration = nullptr; + while (!remaining.empty()) { + std::string currentSpec; + size_t classLoaderSeparator = remaining.find_first_of(kClassLoaderSeparator); + size_t sharedLibraryOpen = remaining.find_first_of(kClassLoaderSharedLibraryOpeningMark); + if (classLoaderSeparator == std::string::npos) { + currentSpec = remaining; + remaining = ""; + } else if ((sharedLibraryOpen == std::string::npos) || (sharedLibraryOpen > classLoaderSeparator)) { + currentSpec = remaining.substr(0, classLoaderSeparator); + remaining = remaining.substr(sharedLibraryOpen + 1, remaining.size() - classLoaderSeparator - 1); + } else { + size_t sharedLibraryClose = FindMatchingSharedLibraryCloseMarker(remaining, sharedLibraryOpen); + CHECK_FATAL(sharedLibraryClose != std::string::npos, + "Invalid class loader spec: %s", currentSpec.c_str()); + currentSpec = remaining.substr(0, sharedLibraryClose + 1); + if (remaining.size() == sharedLibraryClose + 1) { + remaining = ""; + } else if ((remaining.size() == sharedLibraryClose + 2) || + (remaining.at(sharedLibraryClose + 1) != kClassLoaderSeparator)) { + CHECK_FATAL(false, "Invalid class loader spec: %s", currentSpec.c_str()); + return nullptr; + } else { + remaining = remaining.substr(sharedLibraryClose + 2, remaining.size() - sharedLibraryClose - 2); + } + } + ClassLoaderInfo *info = ParseClassLoaderSpec(currentSpec); + CHECK_FATAL(info != nullptr, "Invalid class loader spec: %s", currentSpec.c_str()); + if (first == nullptr) { + first = info; + previousIteration = first; + } else { + CHECK_NULL_FATAL(previousIteration); + previousIteration->parent = info; + previousIteration = previousIteration->parent; + } + } + return first; +} + +// Process PCL/DLC string, and open the corresponding byte code file (dex/jar/apk) +bool ClassLoaderContext::Parse(const std::string &spec) { + if (spec.empty()) { + return false; + } + // Output to IFile, used by collision check when trying to load IFile. + if (spec.compare(kSpecialSharedLib) == 0) { + isSpecialSharedLib = true; + return false; + } + loaderChain = ParseInternal(spec); + return loaderChain != nullptr; +} + +// PCL +ClassLoaderContext *ClassLoaderContext::Create(const std::string &spec, MemPool &mp) { + ClassLoaderContext *retv = mp.New(mp); + if (retv->Parse(spec)) { + return retv; + } else { + return nullptr; + } +} + +// compiled File +ClassLoaderInfo *ClassLoaderContext::CreateClassLoader(const std::string &spec) { + ClassLoaderInfo *classLoader = mp.New(); + classLoader->type = kPathClassLoader; + classLoader->parent = loaderChain; + loaderChain = classLoader; + if (!OpenDexFiles(spec, classLoader->hexElements)) { + CHECK_FATAL(false, "Fail to Open Dex Files!"); + }; + return loaderChain; +} + +bool ClassLoaderContext::OpenDexFiles(const std::string &spec, + std::vector> &openedFileParsers) { + if (spec.empty()) { + return false; + } + bool isSuccess = true; + const std::vector &fileNames = FEUtils::Split(spec, kClasspathSeparator); + uint depFileIdx = UINT32_MAX; + for (const std::string &fileName : fileNames) { + const bool verifyChecksum = true; + const bool verify = true; + std::unique_ptr content = std::make_unique(); + // If the file is not a .dex file, the function tries .zip/.jar/.apk files, + // all of which are Zip archives with "classes.dex" inside. + if (!android::base::ReadFileToString(fileName, content.get())) { + WARN(kLncErr, "%s ReadFileToString failed", fileName.c_str()); + isSuccess = false; + continue; + } + // content size must > 0, otherwise previous step return false + const art::DexFileLoader dexFileLoader; + art::DexFileLoaderErrorCode errorCode; + std::string errorMsg; + std::vector> dexFiles; + if (!dexFileLoader.OpenAll(reinterpret_cast(content->data()), content->size(), fileName, verify, + verifyChecksum, &errorCode, &errorMsg, &dexFiles)) { + // Display returned error message to user. Note that this error behavior + // differs from the error messages shown by the original Dalvik dexdump. + WARN(kLncErr, "%s open fialed, errorMsg: %s", fileName.c_str(), errorMsg.c_str()); + isSuccess = false; + continue; + } + for (size_t i = 0; i < dexFiles.size(); ++i) { + std::unique_ptr iDexFile = std::make_unique( + std::move(dexFiles[i]), std::move(content)); + iDexFile->SetFileIdx(depFileIdx); + const std::list &inputClassNames = {}; + const std::string str = fileName + " (classes" + std::to_string(i + 1) + ")"; // mark dependent dexfile name + std::unique_ptr bcParser = std::make_unique(depFileIdx, str, inputClassNames); + bcParser->SetDexFile(std::move(iDexFile)); + openedFileParsers.push_back(std::move(bcParser)); + --depFileIdx; + } + } + return isSuccess; +} +} diff --git a/src/hir2mpl/bytecode_input/dex/src/dex_class.cpp b/src/hir2mpl/bytecode_input/dex/src/dex_class.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90da7c6329d9c43fdb7010e672d783551c4c6d91 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dex_class.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dex_class.h" +#include "dex_file_util.h" +#include "dex_op.h" +#include "fe_utils_java.h" +namespace maple { +namespace bc { +// ========== DexClassField ========== +bool DexClassField::IsStaticImpl() const { + return accessFlag & DexFileUtil::kDexAccStatic; +} + +uint32 DexClassField::GetItemIdxImpl() const { + return itemIdx; +} + +uint32 DexClassField::GetIdxImpl() const { + return idx; +} + +// ========== DexClassMethod ========== +bool DexClassMethod::IsStaticImpl() const { + return accessFlag & DexFileUtil::kDexAccStatic; +} + +bool DexClassMethod::IsVirtualImpl() const { + return isVirtual; +} + +bool DexClassMethod::IsNativeImpl() const { + return accessFlag & DexFileUtil::kDexAccNative; +} + +bool DexClassMethod::IsInitImpl() const { + return GetName().compare("") == 0; +} + +bool DexClassMethod::IsClinitImpl() const { + return GetName().compare("") == 0; +} + +uint32 DexClassMethod::GetItemIdxImpl() const { + return itemIdx; +} + +uint32 DexClassMethod::GetIdxImpl() const { + return idx; +} + +std::vector> DexClassMethod::GenArgVarListImpl() const { + std::vector> args; + for (const auto ® : argRegs) { + args.emplace_back(reg->GenFEIRVarReg()); + } + return args; +} + +void DexClassMethod::GenArgRegsImpl() { + uint32 regNum = registerTotalSize - registerInsSize; + std::string proto = GetDescription(); + sigTypeNames = FEUtilJava::SolveMethodSignature(proto); + if (!IsClinit() && ((GetAccessFlag() & DexFileUtil::kDexAccStatic) == 0)) { + std::unique_ptr reg = std::make_unique(); + reg->regNum = regNum; + reg->isDef = true; + regNum += 1; + reg->regType = allocator.GetMemPool()->New(allocator, *reg, GetClassNameMplIdx()); + argRegs.emplace_back(std::move(reg)); + } + if (sigTypeNames.size() > 1) { + for (size_t i = 1; i < sigTypeNames.size(); ++i) { + std::unique_ptr reg = std::make_unique(); + reg->regNum = regNum; + reg->isDef = true; + GStrIdx sigTypeNamesIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(sigTypeNames.at(i))); + reg->regType = allocator.GetMemPool()->New(allocator, *reg, sigTypeNamesIdx); + argRegs.emplace_back(std::move(reg)); + regNum += (BCUtil::IsWideType(sigTypeNamesIdx) ? 2 : 1); + } + } +} +} // namespace bc +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/src/dex_class2fe_helper.cpp b/src/hir2mpl/bytecode_input/dex/src/dex_class2fe_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..88e36800463511e016894d434a064095b7f8b914 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dex_class2fe_helper.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dex_class2fe_helper.h" +#include "dex_file_util.h" +#include "fe_options.h" +#include "mpl_logging.h" +#include "fe_manager.h" +namespace maple { +namespace bc { +// ========== DexClass2FEHelper ========== +DexClass2FEHelper::DexClass2FEHelper(MapleAllocator &allocator, bc::BCClass &klassIn) + : BCClass2FEHelper(allocator, klassIn) {} + +TypeAttrs DexClass2FEHelper::GetStructAttributeFromInputImpl() const { + TypeAttrs attrs; + uint32 klassAccessFlag = klass.GetAccessFlag(); + if (klassAccessFlag & DexFileUtil::kDexAccPublic) { + attrs.SetAttr(ATTR_public); + } + if (klassAccessFlag & DexFileUtil::kDexAccFinal) { + attrs.SetAttr(ATTR_final); + } + if (klassAccessFlag & DexFileUtil::kDexAccAbstract) { + attrs.SetAttr(ATTR_abstract); + } + if (klassAccessFlag & DexFileUtil::kDexAccSynthetic) { + attrs.SetAttr(ATTR_synthetic); + } + if (klassAccessFlag & DexFileUtil::kDexAccAnnotation) { + attrs.SetAttr(ATTR_annotation); + } + if (klassAccessFlag & DexFileUtil::kDexAccEnum) { + attrs.SetAttr(ATTR_enum); + } + return attrs; +} + +void DexClass2FEHelper::InitFieldHelpersImpl() { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mem pool is nullptr"); + for (const std::unique_ptr &field : klass.GetFields()) { + ASSERT(field != nullptr, "field is nullptr"); + BCClassField2FEHelper *fieldHelper = mp->New(allocator, *field); + fieldHelpers.push_back(fieldHelper); + } +} + +void DexClass2FEHelper::InitMethodHelpersImpl() { + MemPool *mp = allocator.GetMemPool(); + ASSERT(mp != nullptr, "mem pool is nullptr"); + for (std::unique_ptr &method : klass.GetMethods()) { + ASSERT(method != nullptr, "method is nullptr"); + BCClassMethod2FEHelper *methodHelper = mp->New(allocator, method); + methodHelpers.push_back(methodHelper); + } +} + +// ========== DexClassField2FEHelper ========== +FieldAttrs DexClassField2FEHelper::AccessFlag2AttributeImpl(uint32 accessFlag) const { + FieldAttrs attrs; + if (accessFlag & DexFileUtil::kDexAccPublic) { + attrs.SetAttr(FLDATTR_public);; + } + if (accessFlag & DexFileUtil::kDexAccPrivate) { + attrs.SetAttr(FLDATTR_private); + } + if (accessFlag & DexFileUtil::kDexAccProtected) { + attrs.SetAttr(FLDATTR_protected); + } + if (accessFlag & DexFileUtil::kDexAccStatic) { + attrs.SetAttr(FLDATTR_static); + } + if (accessFlag & DexFileUtil::kDexAccFinal) { + attrs.SetAttr(FLDATTR_final); + } + if (accessFlag & DexFileUtil::kDexAccVolatile) { + attrs.SetAttr(FLDATTR_volatile); + } + if (accessFlag & DexFileUtil::kDexAccTransient) { + attrs.SetAttr(FLDATTR_transient); + } + if (accessFlag & DexFileUtil::kDexAccSynthetic) { + attrs.SetAttr(FLDATTR_synthetic); + } + if (accessFlag & DexFileUtil::kDexAccEnum) { + attrs.SetAttr(FLDATTR_enum); + } + return attrs; +} + +// ========== DexClassMethod2FEHelper ========== +FuncAttrs DexClassMethod2FEHelper::GetAttrsImpl() const { + FuncAttrs attrs; + uint32 accessFlag = method->GetAccessFlag(); + if (accessFlag & DexFileUtil::kDexAccPublic) { + attrs.SetAttr(FUNCATTR_public); + } + if (accessFlag & DexFileUtil::kDexAccPrivate) { + attrs.SetAttr(FUNCATTR_private); + } + if (accessFlag & DexFileUtil::kDexAccProtected) { + attrs.SetAttr(FUNCATTR_protected); + } + if (accessFlag & DexFileUtil::kDexAccStatic) { + attrs.SetAttr(FUNCATTR_static); + } + if (accessFlag & DexFileUtil::kDexAccFinal) { + attrs.SetAttr(FUNCATTR_final); + } + if (accessFlag & DexFileUtil::kAccDexSynchronized) { + attrs.SetAttr(FUNCATTR_synchronized); + } + if (accessFlag & DexFileUtil::kDexAccBridge) { + attrs.SetAttr(FUNCATTR_bridge); + } + if (accessFlag & DexFileUtil::kDexAccVarargs) { + attrs.SetAttr(FUNCATTR_varargs); + } + if (accessFlag & DexFileUtil::kDexAccNative) { + attrs.SetAttr(FUNCATTR_native); + } + if (accessFlag & DexFileUtil::kDexAccAbstract) { + attrs.SetAttr(FUNCATTR_abstract); + } + if (accessFlag & DexFileUtil::kDexAccStrict) { + attrs.SetAttr(FUNCATTR_strict); + } + if (accessFlag & DexFileUtil::kDexAccSynthetic) { + attrs.SetAttr(FUNCATTR_synthetic); + } + if (accessFlag & DexFileUtil::kDexAccConstructor) { + attrs.SetAttr(FUNCATTR_constructor); + } + if (accessFlag & DexFileUtil::kDexDeclaredSynchronized) { + attrs.SetAttr(FUNCATTR_declared_synchronized); + } + if (IsVirtual()) { + attrs.SetAttr(FUNCATTR_virtual); + } + return attrs; +} + +bool DexClassMethod2FEHelper::IsStaticImpl() const { + if (IsClinit()) { + return true; + } + uint32 accessFlag = method->GetAccessFlag(); + if ((accessFlag & DexFileUtil::kDexAccStatic) != 0) { + return true; + } + return false; +} + +bool DexClassMethod2FEHelper::IsClinit() const { + return method->IsClinit(); +} + +bool DexClassMethod2FEHelper::IsInit() const { + return method->IsInit(); +} +} // namespace bc +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/src/dex_encode_value.cpp b/src/hir2mpl/bytecode_input/dex/src/dex_encode_value.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd0ef7a118b25118d72b6c76b999a7c3af59ff27 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dex_encode_value.cpp @@ -0,0 +1,192 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dex_encode_value.h" +#include "fe_manager.h" + +namespace maple { +namespace bc { +uint64 DexEncodeValue::GetUVal(const uint8 **data, uint8 len) const { + // get value, max 8 bytes, little-endian + uint64 val = 0; + for (uint8 j = 0; j <= len; j++) { + val |= (static_cast(*(*data)++) << (j << 3)); + } + return val; +} + +MIRIntConst *DexEncodeValue::ProcessIntValue(const uint8 **data, uint8 valueArg, MIRType &type) { + // sign extended val + uint64 val = GetUVal(data, valueArg); + uint32 shiftBit = static_cast((7 - valueArg) * 8); // 7 : max shift bit args + CHECK_FATAL(valueArg <= 7, "shiftBit positive check"); + uint64 sVal = (static_cast(val) << shiftBit) >> shiftBit; + MIRIntConst *intCst = mp.New(sVal, type); + return intCst; +} + +MIRStr16Const *DexEncodeValue::ProcessStringValue(const uint8 **data, uint8 valueArg, uint32 &stringID) { + uint64 val = GetUVal(data, valueArg); + stringID = static_cast(val); + std::string str = namemangler::GetOriginalNameLiteral(dexFile.GetStringByIndex(static_cast(val))); + std::u16string str16; + (void)namemangler::UTF8ToUTF16(str16, str); + MIRStr16Const *strCst = mp.New(str16, *GlobalTables::GetTypeTable().GetPtr()); + return strCst; +} + +MIRType *DexEncodeValue::GetTypeFromValueType(uint8 valueType) const { + switch (valueType) { + case kValueBoolean: + return GlobalTables::GetTypeTable().GetInt8(); + case kValueByte: + return GlobalTables::GetTypeTable().GetInt8(); + case kValueShort: + return GlobalTables::GetTypeTable().GetInt16(); + case kValueChar: + return GlobalTables::GetTypeTable().GetUInt16(); + case kValueInt: + return GlobalTables::GetTypeTable().GetInt32(); + case kValueLong: + return GlobalTables::GetTypeTable().GetInt64(); + case kValueFloat: + return GlobalTables::GetTypeTable().GetFloat(); + case kValueDouble: + return GlobalTables::GetTypeTable().GetDouble(); + default: + return GlobalTables::GetTypeTable().GetPtr(); + } +} + +MIRAggConst *DexEncodeValue::ProcessArrayValue(const uint8 **data) { + unsigned arraySize = dexFile.ReadUnsignedLeb128(data); + uint64 dataVal = *(*data); + uint8 newValueType = dataVal & 0x1f; + MIRType *elemType = GetTypeFromValueType(static_cast(newValueType)); + MIRType *arrayTypeWithSize = GlobalTables::GetTypeTable().GetOrCreateArrayType(*elemType, 1, &arraySize); + MIRAggConst *aggCst = mp.New(FEManager::GetModule(), *arrayTypeWithSize); + for (uint32 i = 0; i < arraySize; ++i) { + MIRConst *mirConst = nullptr; + ProcessEncodedValue(data, mirConst); + aggCst->PushBack(mirConst); + } + return aggCst; +} + +void DexEncodeValue::ProcessAnnotationValue(const uint8 **data) { + uint32 annoSize = dexFile.ReadUnsignedLeb128(data); + MIRConst *mirConst = nullptr; + for (uint32 i = 0; i < annoSize; ++i) { + ProcessEncodedValue(data, mirConst); + } +} + +void DexEncodeValue::ProcessEncodedValue(const uint8 **data, MIRConst *&cst) { + uint64 dataVal = *(*data)++; + uint32 noMeaning = 0; + // valueArgs : dataVal >> 5, The higher three bits are valid. + ProcessEncodedValue(data, static_cast(dataVal & 0x1f), static_cast(dataVal >> 5), cst, noMeaning); +} + +void DexEncodeValue::ProcessEncodedValue(const uint8 **data, uint8 valueType, uint8 valueArg, MIRConst *&cst, + uint32 &stringID) { + uint64 val = 0; + cst = mp.New(0, *GlobalTables::GetTypeTable().GetInt32()); + switch (valueType) { + case kValueByte: { + val = GetUVal(data, valueArg); + cst = mp.New(val, *GlobalTables::GetTypeTable().GetInt8()); + break; + } + case kValueShort: { + cst = ProcessIntValue(data, valueArg, *GlobalTables::GetTypeTable().GetInt16()); + break; + } + case kValueChar: { + val = GetUVal(data, valueArg); + cst = mp.New(val, *GlobalTables::GetTypeTable().GetUInt16()); + break; + } + case kValueInt: { + cst = ProcessIntValue(data, valueArg, *GlobalTables::GetTypeTable().GetInt32()); + break; + } + case kValueLong: { + cst = ProcessIntValue(data, valueArg, *GlobalTables::GetTypeTable().GetInt64()); + break; + } + case kValueFloat: { + val = GetUVal(data, valueArg); + // fill 0s for least significant bits + valBuf.u = val << ((3 - valueArg) << 3); + cst = mp.New(valBuf.f, *GlobalTables::GetTypeTable().GetFloat()); + break; + } + case kValueDouble: { + val = GetUVal(data, valueArg); + // fill 0s for least significant bits + valBuf.u = val << ((7 - valueArg) << 3); + cst = mp.New(valBuf.d, *GlobalTables::GetTypeTable().GetDouble()); + break; + } + case kValueString: { + cst = ProcessStringValue(data, valueArg, stringID); + break; + } + case kValueMethodType: { + break; + } + case kValueType: { + (void)GetUVal(data, valueArg); + break; + } + case kValueMethodHandle: { + break; + } + case kValueEnum: + // should fallthrough + [[fallthrough]]; + case kValueField: { + (void)GetUVal(data, valueArg); + break; + } + case kValueMethod: { + (void)GetUVal(data, valueArg); + break; + } + case kValueArray: { + CHECK_FATAL(!valueArg, "value_arg != 0"); + cst = ProcessArrayValue(data); + break; + } + case kValueAnnotation: { + (void)GetUVal(data, valueArg); + break; + } + case kValueNull: { + CHECK_FATAL(!valueArg, "value_arg != 0"); + cst = mp.New(0, *GlobalTables::GetTypeTable().GetInt8()); + break; + } + case kValueBoolean: { + cst = mp.New(valueArg, *GlobalTables::GetTypeTable().GetInt8()); + break; + } + default: { + break; + } + } +} +} // namespace bc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/dex/src/dex_file_util.cpp b/src/hir2mpl/bytecode_input/dex/src/dex_file_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d09cc7c2c51f6516b975e6f9274de7b535e60f5 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dex_file_util.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dex_file_util.h" +namespace maple { +namespace bc { +const uint8 DexFileUtil::kDexFileMagic[] = {0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x39, 0x00}; // dex\n039\0 +const uint8 DexFileUtil::kEndianConstant[] = {0x12, 0x34, 0x56, 0x78}; // 0x12345678 +const uint8 DexFileUtil::kReverseEndianConstant[] = {0x78, 0x56, 0x34, 0x12}; // 0x78563412 + +uint32 DexFileUtil::Adler32(const uint8 *data, uint32 size) { + // May be different with adler32 in libz + uint32 kMod = 65521; + // Calculate A + uint16 a = 1; + for (uint32 i = 0; i < size; ++i) { + a += *(data + i); // truncate the data over 16bit + } + a %= kMod; + + // Caculate B + uint16 item = 1; + uint16 b = 0; + for (uint32 i = 0; i < size; ++i) { + item = item + *(data + i); + b += item; + } + b %= kMod; + + return (static_cast(b) << 16) | static_cast(a); +} +} // namespace bc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/dex/src/dex_op.cpp b/src/hir2mpl/bytecode_input/dex/src/dex_op.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24e85c957ad5ab3500414ed5e93d2e96bdd1c595 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dex_op.cpp @@ -0,0 +1,1851 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dex_op.h" +#include "dex_file_util.h" +#include "mpl_logging.h" +#include "namemangler.h" +#include "global_tables.h" +#include "bc_class.h" +#include "feir_builder.h" +#include "fe_utils_java.h" +#include "dex_util.h" +#include "feir_type_helper.h" +#include "dex_strfac.h" +#include "fe_options.h" +#include "feir_var_name.h" +#include "ark_annotation_processor.h" + +namespace maple { +namespace bc { +// ========== DexOp ========== +DexOp::DexOp(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : BCInstruction(allocatorIn, pcIn, opcodeIn) {} + +void DexOp::SetVA(uint32 num) { + SetVAImpl(num); +} + +void DexOp::SetVB(uint32 num) { + SetVBImpl(num); +} + +void DexOp::SetWideVB(uint64 num) { + SetWideVBImpl(num); +} + +void DexOp::SetArgs(const MapleList &args) { + SetArgsImpl(args); +} + +void DexOp::SetVC(uint32 num) { + SetVCImpl(num); +} + +void DexOp::SetVH(uint32 num) { + SetVHImpl(num); +} + +std::string DexOp::GetArrayElementTypeFromArrayType(const std::string &typeName) { + CHECK_FATAL(!typeName.empty() && typeName[0] == 'A', "Invalid array type name %s", typeName.c_str()); + return typeName.substr(1); +} + +// ========== DexOpNop ========== +DexOpNop::DexOpNop(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) : DexOp(allocatorIn, pcIn, opcodeIn) {} + +// ========== DexOpMove ========== +DexOpMove::DexOpMove(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpMove::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + GStrIdx typeNameIdx; + if (kDexOpMove <= opcode && opcode <= kDexOpMove16) { + typeNameIdx = BCUtil::GetIntIdx(); + } else if (kDexOpMoveWide <= opcode && opcode <= kDexOpMoveWide16) { + typeNameIdx = BCUtil::GetLongIdx(); + } else if (kDexOpMoveObject <= opcode && opcode <= kDexOpMoveObject16) { + typeNameIdx = BCUtil::GetJavaObjectNameMplIdx(); + } else { + CHECK_FATAL(false, "invalid opcode: %x in `DexOpMove`", opcode); + } + vA.regType = allocator.GetMemPool()->New(allocator, vA, typeNameIdx, true); + defedRegs.emplace_back(&vA); +} + +void DexOpMove::SetVBImpl(uint32 num) { + vB.regNum = num; + vB.regTypeItem = vA.regTypeItem; + usedRegs.emplace_back(&vB); +} + +void DexOpMove::SetRegTypeInTypeInferImpl() { + vB.regType->RegisterRelatedBCRegType(vA.regType); +} + +std::list DexOpMove::EmitToFEIRStmtsImpl() { + std::list stmts; + std::unique_ptr dreadExpr = std::make_unique(vB.GenFEIRVarReg()); + UniqueFEIRStmt stmt = std::make_unique(vA.GenFEIRVarReg(), std::move(dreadExpr)); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpMoveResult ========= +DexOpMoveResult::DexOpMoveResult(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) { + isReturn = true; +} + +void DexOpMoveResult::SetVATypeNameIdx(const GStrIdx &idx) { + vA.regType->SetTypeNameIdx(idx); +} + +DexReg DexOpMoveResult::GetVA() const { + return vA; +} + +void DexOpMoveResult::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); +} + +void DexOpMoveResult::SetBCRegTypeImpl(const BCInstruction &inst) { + if ((kDexOpInvokeVirtual <= inst.GetOpcode() && inst.GetOpcode() <= kDexOpInvokeInterface) || + (kDexOpInvokeVirtualRange <= inst.GetOpcode() && inst.GetOpcode() <= kDexOpInvokeInterfaceRange) || + (kDexOpInvokePolymorphic <= inst.GetOpcode() && inst.GetOpcode() <= kDexOpInvokeCustomRange)) { + GStrIdx retTyIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::EncodeName(static_cast(inst).GetReturnType())); + vA.regType = allocator.GetMemPool()->New(allocator, vA, retTyIdx); + } else if (inst.GetOpcode() == kDexOpFilledNewArray || inst.GetOpcode() == kDexOpFilledNewArrayRange) { + vA.regType = allocator.GetMemPool()->New( + allocator, vA, static_cast(inst).GetReturnType()); + } else { + CHECK_FATAL(false, "the reg of opcode %u should be inserted in move-result", inst.GetOpcode()); + } +} + +// ========== DexOpMoveException ========== +DexOpMoveException::DexOpMoveException(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpMoveException::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); +} + +void DexOpMoveException::SetBCRegTypeImpl(const BCInstruction &inst) { + (void) inst; + GStrIdx exceptionTypeNameIdx = *(catchedExTypeNamesIdx.begin()); + vA.regType = allocator.GetMemPool()->New(allocator, vA, exceptionTypeNameIdx); + // If exception type is primitive type, it should be <* void> + if (vA.GetBasePrimType() != PTY_ref) { + vA.regTypeItem->typeNameIdx = BCUtil::GetJavaThrowableNameMplIdx(); + } +} + +std::list DexOpMoveException::EmitToFEIRStmtsImpl() { + std::list stmts; + std::unique_ptr readExpr = std::make_unique(PTY_ref, -kSregThrownval); + UniqueFEIRStmt stmt = std::make_unique(vA.GenFEIRVarReg(), std::move(readExpr)); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpReturn ========== +DexOpReturn::DexOpReturn(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpReturn::SetVAImpl(uint32 num) { + if (opcode == kDexOpReturnVoid) { + isReturnVoid = true; + return; + } + vA.regNum = num; + usedRegs.emplace_back(&vA); +} + +void DexOpReturn::ParseImpl(BCClassMethod &method) { + GStrIdx usedTypeNameIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(method.GetSigTypeNames().at(0))); + vA.regTypeItem = allocator.GetMemPool()->New(usedTypeNameIdx); +} + +std::list DexOpReturn::EmitToFEIRStmtsImpl() { + std::list ans; + if (isReturnVoid) { + UniqueFEIRStmt stmt = std::make_unique(UniqueFEIRExpr(nullptr)); + ans.emplace_back(std::move(stmt)); + } else { + UniqueFEIRVar var = vA.GenFEIRVarReg(); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(var)); + UniqueFEIRStmt stmt = std::make_unique(std::move(expr)); + ans.emplace_back(std::move(stmt)); + } + return ans; +} + +// ========== DexOpConst ========== +DexOpConst::DexOpConst(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpConst::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + vA.regValue = allocator.GetMemPool()->New(); + defedRegs.emplace_back(&vA); +} + +void DexOpConst::SetVBImpl(uint32 num) { + if (opcode != kDexOpConstWide) { + vA.regValue->primValue.raw32 = num; + } + if (!isWide) { + vA.regType = allocator.GetMemPool()->New(allocator, vA, BCUtil::GetIntIdx()); + } +} + +void DexOpConst::SetWideVBImpl(uint64 num) { + if (opcode == kDexOpConstWide) { + vA.regValue->primValue.raw64 = num; + } + if (isWide) { + vA.regType = allocator.GetMemPool()->New(allocator, vA, BCUtil::GetLongIdx()); + } +} + +std::list DexOpConst::EmitToFEIRStmtsImpl() { + std::list ans; + UniqueFEIRExpr expr; + DexReg vATmp; + vATmp.regNum = vA.regNum; + GStrIdx typeNameIdx; + if (isWide) { + typeNameIdx = BCUtil::GetLongIdx(); + } else { + typeNameIdx = BCUtil::GetIntIdx(); + } + vATmp.regType = allocator.GetMemPool()->New(allocator, vATmp, typeNameIdx, true); + switch (opcode) { + case kDexOpConst4: { + expr = FEIRBuilder::CreateExprConstI8(static_cast(vA.regValue->primValue.raw32)); + expr = FEIRBuilder::CreateExprCvtPrim(std::move(expr), PTY_i32); + break; + } + case kDexOpConst16: { + expr = FEIRBuilder::CreateExprConstI16(static_cast(vA.regValue->primValue.raw32)); + expr = FEIRBuilder::CreateExprCvtPrim(std::move(expr), PTY_i32); + break; + } + case kDexOpConst: { + expr = FEIRBuilder::CreateExprConstI32(static_cast(vA.regValue->primValue.raw32)); + break; + } + case kDexOpConstHigh16: { + expr = FEIRBuilder::CreateExprConstI16(static_cast(vA.regValue->primValue.raw32)); + expr = FEIRBuilder::CreateExprCvtPrim(std::move(expr), PTY_i32); + UniqueFEIRExpr exprBit = FEIRBuilder::CreateExprConstI32(16); // 16 means right-zero-extended to 32 bits + expr = FEIRBuilder::CreateExprMathBinary(OP_shl, std::move(expr), std::move(exprBit)); + break; + } + case kDexOpConstWide16: { + expr = FEIRBuilder::CreateExprConstI16(static_cast(vA.regValue->primValue.raw64)); + expr = FEIRBuilder::CreateExprCvtPrim(std::move(expr), PTY_i64); + break; + } + case kDexOpConstWide32: { + expr = FEIRBuilder::CreateExprConstI32(static_cast(vA.regValue->primValue.raw64)); + expr = FEIRBuilder::CreateExprCvtPrim(std::move(expr), PTY_i64); + break; + } + case kDexOpConstWide: { + expr = FEIRBuilder::CreateExprConstI64(static_cast(vA.regValue->primValue.raw64)); + break; + } + case kDexOpConstWideHigh16: { + expr = FEIRBuilder::CreateExprConstI16(static_cast(vA.regValue->primValue.raw64)); + expr = FEIRBuilder::CreateExprCvtPrim(std::move(expr), PTY_i64); + UniqueFEIRExpr exprBit = FEIRBuilder::CreateExprConstI32(48); // 48 means right-zero-extended to 64 bits + expr = FEIRBuilder::CreateExprMathBinary(OP_shl, std::move(expr), std::move(exprBit)); + break; + } + default: { + CHECK_FATAL(false, "Unsupported const-op: %u", opcode); + break; + } + } + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(vATmp.GenFEIRVarReg(), std::move(expr)); + ans.emplace_back(std::move(stmt)); + if (!(*vA.regTypeItem == *vATmp.regTypeItem)) { + stmt = FEIRBuilder::CreateStmtRetype(vA.GenFEIRVarReg(), vATmp.GenFEIRVarReg()); + ans.emplace_back(std::move(stmt)); + } + return ans; +} + +// ========== DexOpConstString ========== +DexOpConstString::DexOpConstString(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn), strValue(allocator.GetMemPool()) {} + +void DexOpConstString::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.regType = allocator.GetMemPool()->New(allocator, vA, BCUtil::GetJavaStringNameMplIdx()); + vA.isDef = true; + defedRegs.emplace_back(&vA); +} + +void DexOpConstString::SetVBImpl(uint32 num) { + vA.dexLitStrIdx = num; +} + +void DexOpConstString::ParseImpl(BCClassMethod &method) { + fileIdx = method.GetBCClass().GetBCParser().GetReader()->GetFileIndex(); + strValue = method.GetBCClass().GetBCParser().GetReader()->GetStringFromIdx(vA.dexLitStrIdx); + if (FEOptions::GetInstance().IsRC() && !method.IsRcPermanent() && + ArkAnnotation::GetInstance().IsPermanent(strValue.c_str())) { + // "Lcom/huawei/ark/annotation/Permanent;" and "Lark/annotation/Permanent;" + // indicates next new-instance / new-array Permanent object + method.SetIsRcPermanent(true); + } +} + +std::list DexOpConstString::EmitToFEIRStmtsImpl() { + std::list stmts; + UniqueFEIRVar dstVar = vA.GenFEIRVarReg(); + UniqueFEIRStmt stmt = std::make_unique(std::move(dstVar), strValue.c_str(), + fileIdx, vA.dexLitStrIdx); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpConstClass ========== +DexOpConstClass::DexOpConstClass(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpConstClass::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + vA.regType = allocator.GetMemPool()->New(allocator, vA, BCUtil::GetJavaClassNameMplIdx()); + defedRegs.emplace_back(&vA); +} + +void DexOpConstClass::SetVBImpl(uint32 num) { + dexTypeIdx = num; +} + +void DexOpConstClass::ParseImpl(BCClassMethod &method) { + const std::string &typeName = method.GetBCClass().GetBCParser().GetReader()->GetTypeNameFromIdx(dexTypeIdx); + const std::string &mplTypeName = namemangler::EncodeName(typeName); + mplTypeNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(mplTypeName); +} + +std::list DexOpConstClass::EmitToFEIRStmtsImpl() { + std::list stmts; + UniqueFEIRVar dstVar = vA.GenFEIRVarReg(); + UniqueFEIRType refType = std::make_unique(BCUtil::GetPrimType(mplTypeNameIdx), mplTypeNameIdx); + UniqueFEIRExpr expr = std::make_unique(std::move(refType), INTRN_JAVA_CONST_CLASS, + std::make_unique(PTY_ref), dexTypeIdx); + UniqueFEIRStmt stmt = std::make_unique(std::move(dstVar), std::move(expr)); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpMonitor ========== +DexOpMonitor::DexOpMonitor(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpMonitor::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetJavaObjectNameMplIdx(), true); + usedRegs.emplace_back(&vA); +} + +std::list DexOpMonitor::EmitToFEIRStmtsImpl() { + std::list stmts; + std::list exprs; + UniqueFEIRExpr expr = std::make_unique(vA.GenFEIRVarReg()); + exprs.emplace_back(std::move(expr)); + if (opcode == kDexOpMonitorEnter) { + expr = std::make_unique(static_cast(2), PTY_i32); + exprs.emplace_back(std::move(expr)); + } + UniqueFEIRStmt stmt = + std::make_unique(opcode == kDexOpMonitorEnter ? OP_syncenter : OP_syncexit, std::move(exprs)); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpCheckCast ========= +DexOpCheckCast::DexOpCheckCast(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpCheckCast::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetJavaObjectNameMplIdx(), true); + usedRegs.emplace_back(&vA); // use vA to gen vDef + vDef.regNum = num; + vDef.isDef = true; + defedRegs.emplace_back(&vDef); +} + +void DexOpCheckCast::SetVBImpl(uint32 num) { + targetDexTypeIdx = num; +} + +void DexOpCheckCast::ParseImpl(BCClassMethod &method) { + const std::string &typeName = method.GetBCClass().GetBCParser().GetReader()->GetTypeNameFromIdx(targetDexTypeIdx); + targetTypeNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(typeName)); + vDef.regType = allocator.GetMemPool()->New(allocator, vDef, targetTypeNameIdx); +} + +std::list DexOpCheckCast::EmitToFEIRStmtsImpl() { + std::list stmts; + if (vA.GetPrimType() == PTY_i32) { + // only null ptr approach here + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtRetype(vDef.GenFEIRVarReg(), vA.GenFEIRVarReg()); + stmts.emplace_back(std::move(stmt)); + stmt = FEIRBuilder::CreateStmtJavaCheckCast(vDef.GenFEIRVarReg(), vDef.GenFEIRVarReg(), + FEIRBuilder::CreateTypeByJavaName(GlobalTables::GetStrTable().GetStringFromStrIdx(targetTypeNameIdx), true), + targetDexTypeIdx); + stmts.emplace_back(std::move(stmt)); + } else { + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtJavaCheckCast(vDef.GenFEIRVarReg(), vA.GenFEIRVarReg(), + FEIRBuilder::CreateTypeByJavaName(GlobalTables::GetStrTable().GetStringFromStrIdx(targetTypeNameIdx), true), + targetDexTypeIdx); + stmts.emplace_back(std::move(stmt)); + } + return stmts; +} + +// ========== DexOpInstanceOf ========= +DexOpInstanceOf::DexOpInstanceOf(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpInstanceOf::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); + vA.regType = allocator.GetMemPool()->New(allocator, vA, BCUtil::GetBooleanIdx()); +} + +void DexOpInstanceOf::SetVBImpl(uint32 num) { + vB.regNum = num; + vB.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetJavaObjectNameMplIdx(), true); + usedRegs.emplace_back(&vB); +} + +void DexOpInstanceOf::SetVCImpl(uint32 num) { + targetDexTypeIdx = num; +} + +void DexOpInstanceOf::ParseImpl(BCClassMethod &method) { + typeName = method.GetBCClass().GetBCParser().GetReader()->GetTypeNameFromIdx(targetDexTypeIdx); +} + +std::list DexOpInstanceOf::EmitToFEIRStmtsImpl() { + std::list stmts; + const std::string &targetTypeName = namemangler::EncodeName(typeName); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtJavaInstanceOf(vA.GenFEIRVarReg(), vB.GenFEIRVarReg(), + FEIRBuilder::CreateTypeByJavaName(targetTypeName, true), + targetDexTypeIdx); + stmts.emplace_back(std::move(stmt)); + typeName.clear(); + typeName.shrink_to_fit(); + return stmts; +} + +// ========== DexOpArrayLength ========= +DexOpArrayLength::DexOpArrayLength(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpArrayLength::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); + vA.regType = allocator.GetMemPool()->New(allocator, vA, BCUtil::GetIntIdx()); +} + +void DexOpArrayLength::SetVBImpl(uint32 num) { + vB.regNum = num; + vB.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetABooleanIdx(), true); + usedRegs.emplace_back(&vB); +} + +std::list DexOpArrayLength::EmitToFEIRStmtsImpl() { + CHECK_FATAL(BCUtil::IsArrayType(vB.regTypeItem->typeNameIdx), + "Invalid array type: %s in DexOpArrayLength", + GlobalTables::GetStrTable().GetStringFromStrIdx(vB.regTypeItem->typeNameIdx).c_str()); + std::list stmts; + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtArrayLength(vA.GenFEIRVarReg(), vB.GenFEIRVarReg()); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpNewInstance ========= +DexOpNewInstance::DexOpNewInstance(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpNewInstance::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; +} + +void DexOpNewInstance::SetVBImpl(uint32 num) { + vA.dexTypeIdx = num; +} + +void DexOpNewInstance::ParseImpl(BCClassMethod &method) { + const std::string &typeName = method.GetBCClass().GetBCParser().GetReader()->GetTypeNameFromIdx(vA.dexTypeIdx); + // we should register vA in defs, even if it was new-instance java.lang.String. + // Though new-instance java.lang.String would be replaced by StringFactory at following java.lang.String., + // and vA is defed by StringFactory. + // In some cases, vA may be used between new-instance and its invokation. + vA.regType = allocator.GetMemPool()->New(allocator, vA, + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(typeName))); + defedRegs.emplace_back(&vA); + if (method.IsRcPermanent()) { + isRcPermanent = true; + method.SetIsRcPermanent(false); + } +} + +std::list DexOpNewInstance::EmitToFEIRStmtsImpl() { + std::list stmts; + if (isSkipNewString) { + return stmts; + } + std::unique_ptr stmtCall = std::make_unique( + INTRN_JAVA_CLINIT_CHECK, std::make_unique(PTY_ref, vA.regTypeItem->typeNameIdx), nullptr, + vA.dexTypeIdx); + stmts.emplace_back(std::move(stmtCall)); + UniqueFEIRExpr exprJavaNewInstance = FEIRBuilder::CreateExprJavaNewInstance( + vA.GenFEIRType(), vA.dexTypeIdx, isRcPermanent); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(vA.GenFEIRVarReg(), std::move(exprJavaNewInstance)); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpNewArray ========= +DexOpNewArray::DexOpNewArray(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpNewArray::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); +} + +void DexOpNewArray::SetVBImpl(uint32 num) { + vB.regNum = num; + vB.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetIntIdx()); + usedRegs.emplace_back(&vB); +} + +void DexOpNewArray::SetVCImpl(uint32 num) { + vA.dexTypeIdx = num; +} + +void DexOpNewArray::ParseImpl(BCClassMethod &method) { + const std::string &typeName = method.GetBCClass().GetBCParser().GetReader()->GetTypeNameFromIdx(vA.dexTypeIdx); + vA.regType = allocator.GetMemPool()->New(allocator, vA, + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(typeName))); + if (method.IsRcPermanent()) { + isRcPermanent = true; + method.SetIsRcPermanent(false); + } +} + +std::list DexOpNewArray::EmitToFEIRStmtsImpl() { + std::list stmts; + UniqueFEIRExpr exprSize = FEIRBuilder::CreateExprDRead(vB.GenFEIRVarReg()); + UniqueFEIRExpr exprJavaNewArray = FEIRBuilder::CreateExprJavaNewArray(vA.GenFEIRType(), std::move(exprSize), + vA.dexTypeIdx, isRcPermanent); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(vA.GenFEIRVarReg(), std::move(exprJavaNewArray)); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpFilledNewArray ========= +DexOpFilledNewArray::DexOpFilledNewArray(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn), argRegs(allocator.Adapter()), vRegs(allocator.Adapter()) { + isRange = (opcode == kDexOpFilledNewArrayRange); +} + +void DexOpFilledNewArray::SetVAImpl(uint32 num) { + argsSize = num; +} + +void DexOpFilledNewArray::SetVBImpl(uint32 num) { + dexArrayTypeIdx = num; +} + +void DexOpFilledNewArray::SetArgsImpl(const MapleList &args) { + argRegs = args; +} + +GStrIdx DexOpFilledNewArray::GetReturnType() const { + return arrayTypeNameIdx; +} + +void DexOpFilledNewArray::ParseImpl(BCClassMethod &method) { + const std::string &typeName = method.GetBCClass().GetBCParser().GetReader()->GetTypeNameFromIdx(dexArrayTypeIdx); + const std::string &typeNameMpl = namemangler::EncodeName(typeName); + arrayTypeNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(typeNameMpl); + const std::string &elemTypeName = GetArrayElementTypeFromArrayType(typeNameMpl); + elemTypeNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(elemTypeName); + for (uint32 regNum : argRegs) { + DexReg reg; + reg.regNum = regNum; + reg.regTypeItem = allocator.GetMemPool()->New(elemTypeNameIdx); + vRegs.emplace_back(reg); + } + for (auto ® : vRegs) { + usedRegs.emplace_back(®); + } +} + +std::list DexOpFilledNewArray::EmitToFEIRStmtsImpl() { + std::list stmts; + auto exprRegList = std::make_unique>(); + for (auto vReg : vRegs) { + UniqueFEIRExpr exprReg = FEIRBuilder::CreateExprDRead(vReg.GenFEIRVarReg()); + exprRegList->emplace_back(std::move(exprReg)); + } + UniqueFEIRVar var = nullptr; + if (HasReturn()) { + static_cast(returnInst)->SetVATypeNameIdx(arrayTypeNameIdx); + var = static_cast(returnInst)->GetVA().GenFEIRVarReg(); + } else { + return stmts; + } + const std::string &elemName = GlobalTables::GetStrTable().GetStringFromStrIdx(elemTypeNameIdx); + UniqueFEIRType elemType = FEIRTypeHelper::CreateTypeByJavaName(elemName, true, false); + std::unique_ptr stmt = std::make_unique( + INTRN_JAVA_FILL_NEW_ARRAY, std::move(elemType), std::move(var), std::move(exprRegList)); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpFillArrayData ========= +DexOpFillArrayData::DexOpFillArrayData(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpFillArrayData::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetVoidIdx(), true); + usedRegs.emplace_back(&vA); +} + +void DexOpFillArrayData::SetVBImpl(uint32 num) { + offset = static_cast(num); // signed value in unsigned data buffer +} + +void DexOpFillArrayData::ParseImpl(BCClassMethod &method) { + const uint16 *data = method.GetInstPos() + pc + offset; + size = *(reinterpret_cast(&data[2])); + arrayData = reinterpret_cast(&data[4]); +} + +std::list DexOpFillArrayData::EmitToFEIRStmtsImpl() { + CHECK_FATAL(BCUtil::IsArrayType(vA.regTypeItem->typeNameIdx), + "Invalid array type: %s in DexOpFillArrayData", + GlobalTables::GetStrTable().GetStringFromStrIdx(vA.regTypeItem->typeNameIdx).c_str()); + std::list stmts; + thread_local static std::stringstream ss(""); + ss.str(""); + ss << "const_array_" << funcNameIdx << "_" << pc; + UniqueFEIRVar arrayReg = vA.GenFEIRVarReg(); + const std::string &arrayTypeName = GlobalTables::GetStrTable().GetStringFromStrIdx(vA.regTypeItem->typeNameIdx); + CHECK_FATAL(arrayTypeName.size() > 1 && arrayTypeName.at(0) == 'A' && + BCUtil::IsJavaPrimitveType(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(arrayTypeName.substr(1))), + "Invalid type %s", arrayTypeName.c_str()); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtJavaFillArrayData(std::move(arrayReg), arrayData, size, ss.str()); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpThrow ========= +DexOpThrow::DexOpThrow(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpThrow::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetJavaThrowableNameMplIdx(), true); + usedRegs.emplace_back(&vA); +} + +std::list DexOpThrow::EmitToFEIRStmtsImpl() { + std::list stmts; + if (BCUtil::IsJavaReferenceType(vA.regTypeItem->typeNameIdx)) { + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(vA.GenFEIRVarReg()); + UniqueFEIRStmt stmt = std::make_unique(OP_throw, std::move(expr)); + stmts.emplace_back(std::move(stmt)); + } else { + CHECK_FATAL(vA.regValue != nullptr && vA.regValue->primValue.raw32 == 0, "only null or ref can be thrown."); + DexReg vAtmp; + vAtmp.regNum = vA.regNum; + vAtmp.regType = allocator.GetMemPool()->New(allocator, vAtmp, BCUtil::GetJavaThrowableNameMplIdx()); + UniqueFEIRStmt retypeStmt = FEIRBuilder::CreateStmtRetype(vAtmp.GenFEIRVarReg(), vA.GenFEIRVarReg()); + stmts.emplace_back(std::move(retypeStmt)); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(vAtmp.GenFEIRVarReg()); + UniqueFEIRStmt stmt = std::make_unique(OP_throw, std::move(expr)); + stmts.emplace_back(std::move(stmt)); + } + return stmts; +} + +// ========== DexOpGoto ========= +DexOpGoto::DexOpGoto(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpGoto::SetVAImpl(uint32 num) { + offset = static_cast(num); +} + +std::vector DexOpGoto::GetTargetsImpl() const { + std::vector res; + res.emplace_back(static_cast(offset + pc)); + return res; +} + +void DexOpGoto::ParseImpl(BCClassMethod &method) { + (void) method; + target = static_cast(offset + pc); +} + +std::list DexOpGoto::EmitToFEIRStmtsImpl() { + std::list stmts; + UniqueFEIRStmt stmt = std::make_unique(funcNameIdx, target); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpSwitch ========= +DexOpSwitch::DexOpSwitch(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn), keyTargetOPpcMap(allocator.Adapter()) { + isPacked = (opcode == kDexOpPackedSwitch); +} + +void DexOpSwitch::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetIntIdx()); + usedRegs.emplace_back(&vA); +} + +void DexOpSwitch::SetVBImpl(uint32 num) { + offset = static_cast(num); +} + +void DexOpSwitch::ParseImpl(BCClassMethod &method) { + const uint16 *data = method.GetInstPos() + pc + offset; + if (isPacked) { + uint16 size = data[1]; + int32 key = *(reinterpret_cast(&data[2])); + const int32 *targets = reinterpret_cast(&data[4]); + for (uint16 i = 0; i < size; i++) { + uint32 target = static_cast(pc + targets[i]); + keyTargetOPpcMap.emplace(key, std::make_pair(target, pc)); + key = key + 1; + } + } else { + uint16 size = data[1]; + const int32 *keys = reinterpret_cast(&data[2]); + const int32 *targets = reinterpret_cast(&data[2 + size * 2]); + for (uint16 i = 0; i < size; i++) { + int32 key = keys[i]; + uint32 target = static_cast(pc + targets[i]); + keyTargetOPpcMap.emplace(key, std::make_pair(target, pc)); + } + } +} + +std::vector DexOpSwitch::GetTargetsImpl() const { + std::vector res; + for (const auto &elem : keyTargetOPpcMap) { + res.emplace_back(elem.second.first); + } + return res; +} + +std::list DexOpSwitch::EmitToFEIRStmtsImpl() { + std::list stmts; + UniqueFEIRExpr expr = std::make_unique(vA.GenFEIRVarReg()); + std::unique_ptr stmt = std::make_unique(funcNameIdx, std::move(expr)); + if (defaultTarget == nullptr) { + stmt->SetDefaultLabelIdx(UINT32_MAX); // no default target, switch is the last instruction of the file + } else { + stmt->SetDefaultLabelIdx(defaultTarget->GetPC()); + } + for (auto &e : keyTargetOPpcMap) { + stmt->AddTarget(e.first, e.second.first); + } + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpCompare ========= +DexOpCompare::DexOpCompare(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} +void DexOpCompare::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); + vA.regType = allocator.GetMemPool()->New(allocator, vA, BCUtil::GetIntIdx()); +} + +void DexOpCompare::SetVBImpl(uint32 num) { + vB.regNum = num; + GStrIdx typeNameIdx; + if (opcode == kDexOpCmplFloat || opcode == kDexOpCmpgFloat) { + typeNameIdx = BCUtil::GetFloatIdx(); + } else if (opcode == kDexOpCmplDouble || opcode == kDexOpCmpgDouble) { + typeNameIdx = BCUtil::GetDoubleIdx(); + } else { + // kDexOpCmpLong + typeNameIdx = BCUtil::GetLongIdx(); + } + vB.regTypeItem = allocator.GetMemPool()->New(typeNameIdx); + usedRegs.emplace_back(&vB); +} + +void DexOpCompare::SetVCImpl(uint32 num) { + vC = vB; + vC.regNum = num; + vC.regTypeItem = vB.regTypeItem; + usedRegs.emplace_back(&vC); +} + +Opcode DexOpCompare::GetOpcodeFromDexIns() const { + auto mirOp = dexOpCmp2MIROp.find(opcode); + CHECK_FATAL(mirOp != dexOpCmp2MIROp.end(), "Invalid opcode: 0x%x in dexOpCmp2MIROp", opcode); + return mirOp->second; +} + +std::list DexOpCompare::EmitToFEIRStmtsImpl() { + std::list stmts; + UniqueFEIRExpr cmpExpr = + FEIRBuilder::CreateExprMathBinary(GetOpcodeFromDexIns(), vB.GenFEIRVarReg(), vC.GenFEIRVarReg()); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(vA.GenFEIRVarReg(), std::move(cmpExpr)); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpIfTest ========= +DexOpIfTest::DexOpIfTest(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpIfTest::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetIntIdx(), true); + usedRegs.emplace_back(&vA); +} + +void DexOpIfTest::SetVBImpl(uint32 num) { + vB.regNum = num; + vB.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetIntIdx(), true); + usedRegs.emplace_back(&vB); +} + +void DexOpIfTest::SetVCImpl(uint32 num) { + offset = static_cast(num); +} + +std::vector DexOpIfTest::GetTargetsImpl() const { + std::vector res; + res.emplace_back(static_cast(offset + pc)); + return res; +} + +void DexOpIfTest::ParseImpl(BCClassMethod &method) { + (void) method; + target = static_cast(offset + pc); +} + +std::list DexOpIfTest::EmitToFEIRStmtsImpl() { + std::list stmts; + DexReg vATmp; + DexReg vBTmp; + vATmp = vA; + vBTmp = vB; + // opnd of if-test should be same PTY type. + // Or one opnd must be nullptr, such as const 0. + if (vA.GetPrimType() == PTY_ref && vB.GetPrimType() != PTY_ref) { + CHECK_FATAL(vB.regValue != nullptr && vB.regValue->primValue.raw32 == 0, + "Cannot compare a ref var with an integer."); + vBTmp.regTypeItem = vATmp.regTypeItem; + UniqueFEIRStmt retypeStmt = FEIRBuilder::CreateStmtRetype(vBTmp.GenFEIRVarReg(), vB.GenFEIRVarReg()); + stmts.emplace_back(std::move(retypeStmt)); + } else if (vA.GetPrimType() != PTY_ref && vB.GetPrimType() == PTY_ref) { + CHECK_FATAL(vA.regValue != nullptr && vA.regValue->primValue.raw32 == 0, + "Cannot compare a ref var with an integer."); + vATmp.regTypeItem = vBTmp.regTypeItem; + UniqueFEIRStmt retypeStmt = FEIRBuilder::CreateStmtRetype(vATmp.GenFEIRVarReg(), vA.GenFEIRVarReg()); + stmts.emplace_back(std::move(retypeStmt)); + } + UniqueFEIRExpr exprA = std::make_unique(vATmp.GenFEIRVarReg()); + UniqueFEIRExpr exprB = std::make_unique(vBTmp.GenFEIRVarReg()); + auto itor = dexOpConditionOp2MIROp.find(static_cast(opcode)); + CHECK_FATAL(itor != dexOpConditionOp2MIROp.end(), "Invalid opcode: %u in DexOpIfTest", opcode); + // All primitive var should be compared in i32. + if (vATmp.GetPrimType() != PTY_ref) { + if (vATmp.GetPrimType() != PTY_i32) { + exprA = std::make_unique(std::make_unique(PTY_i32, BCUtil::GetIntIdx()), + OP_cvt, std::move(exprA)); + } + if (vBTmp.GetPrimType() != PTY_i32) { + exprB = std::make_unique(std::make_unique(PTY_i32, BCUtil::GetIntIdx()), + OP_cvt, std::move(exprB)); + } + } + std::unique_ptr expr = + std::make_unique(itor->second, std::move(exprA), std::move(exprB)); + UniqueFEIRStmt stmt = + std::make_unique(OP_brtrue, funcNameIdx, target, std::move(expr)); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpIfTestZ ========= +DexOpIfTestZ::DexOpIfTestZ(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpIfTestZ::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetIntIdx(), true); + usedRegs.emplace_back(&vA); +} + +void DexOpIfTestZ::SetVBImpl(uint32 num) { + offset = static_cast(num); +} + +std::vector DexOpIfTestZ::GetTargetsImpl() const { + std::vector res; + res.emplace_back(static_cast(offset + pc)); + return res; +} + +void DexOpIfTestZ::ParseImpl(BCClassMethod &method) { + (void) method; + target = static_cast(offset + pc); +} + +std::list DexOpIfTestZ::EmitToFEIRStmtsImpl() { + std::list stmts; + UniqueFEIRStmt stmt = nullptr; + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(vA.GenFEIRVarReg()); + if (vA.GetPrimType() == PTY_u1 && opcode == kDexOpIfEqZ) { + stmt = std::make_unique(OP_brfalse, funcNameIdx, target, std::move(expr)); + } else if (vA.GetPrimType() == PTY_u1 && opcode == kDexOpIfNeZ) { + stmt = std::make_unique(OP_brtrue, funcNameIdx, target, std::move(expr)); + } else { + UniqueFEIRExpr constExpr = std::make_unique(static_cast(0), vA.GetPrimType()); + auto itor = dexOpConditionOp2MIROp.find(static_cast(opcode)); + CHECK_FATAL(itor != dexOpConditionOp2MIROp.end(), "Invalid opcode: %u in DexOpIfTestZ", opcode); + expr = FEIRBuilder::CreateExprMathBinary(itor->second, std::move(expr), std::move(constExpr)); + stmt = std::make_unique(OP_brtrue, funcNameIdx, target, std::move(expr)); + } + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpUnused ========= +DexOpUnused::DexOpUnused(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +// ========== DexOpAget ========= +DexOpAget::DexOpAget(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpAget::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); +} + +void DexOpAget::SetVBImpl(uint32 num) { + vB.regNum = num; + usedRegs.emplace_back(&vB); +} + +void DexOpAget::SetVCImpl(uint32 num) { + vC.regNum = num; + vC.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetIntIdx()); + usedRegs.emplace_front(&vC); +} + +void DexOpAget::ParseImpl(BCClassMethod &method) { + (void) method; + GStrIdx elemTypeNameIdx; + GStrIdx usedTypeNameIdx; + bool isIndeterminateType = false; + switch (opcode) { + case kDexOpAget: { + // int or float + elemTypeNameIdx = BCUtil::GetIntIdx(); + usedTypeNameIdx = BCUtil::GetAIntIdx(); + isIndeterminateType = true; + break; + } + case kDexOpAgetWide: { + elemTypeNameIdx = BCUtil::GetLongIdx(); + usedTypeNameIdx = BCUtil::GetALongIdx(); + isIndeterminateType = true; + break; + } + case kDexOpAgetObject: { + elemTypeNameIdx = BCUtil::GetJavaObjectNameMplIdx(); + usedTypeNameIdx = BCUtil::GetAJavaObjectNameMplIdx(); + isIndeterminateType = true; + break; + } + case kDexOpAgetBoolean: { + elemTypeNameIdx = BCUtil::GetBooleanIdx(); + usedTypeNameIdx = BCUtil::GetABooleanIdx(); + break; + } + case kDexOpAgetByte: { + elemTypeNameIdx = BCUtil::GetByteIdx(); + usedTypeNameIdx = BCUtil::GetAByteIdx(); + break; + } + case kDexOpAgetChar: { + elemTypeNameIdx = BCUtil::GetCharIdx(); + usedTypeNameIdx = BCUtil::GetACharIdx(); + break; + } + case kDexOpAgetShort: { + elemTypeNameIdx = BCUtil::GetShortIdx(); + usedTypeNameIdx = BCUtil::GetAShortIdx(); + break; + } + default: { + CHECK_FATAL(false, "Invalid opcode : 0x%x in DexOpAget", opcode); + break; + } + } + vA.regType = allocator.GetMemPool()->New(allocator, vA, elemTypeNameIdx, isIndeterminateType); + vB.regTypeItem = allocator.GetMemPool()->New(usedTypeNameIdx, isIndeterminateType); +} + +void DexOpAget::SetRegTypeInTypeInferImpl() { + if (vB.regType != nullptr && vC.regType != nullptr) { + vB.regType->AddElemType(vA.regTypeItem); + } +} + +std::list DexOpAget::EmitToFEIRStmtsImpl() { + DexReg vAtmp; + vAtmp.regNum = vA.regNum; + const std::string arrayTypeName = GlobalTables::GetStrTable().GetStringFromStrIdx(vB.regTypeItem->typeNameIdx); + if (arrayTypeName.size() > 1 && arrayTypeName.at(0) == 'A') { + vAtmp.regTypeItem = allocator.GetMemPool()->New( + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(arrayTypeName.substr(1))); + } else { + CHECK_FATAL(false, "Invalid array type %s", arrayTypeName.c_str()); + } + std::list stmts = FEIRBuilder::CreateStmtArrayLoad(vAtmp.GenFEIRVarReg(), vB.GenFEIRVarReg(), + vC.GenFEIRVarReg()); + + if (!((*vAtmp.regTypeItem) == (*vA.regTypeItem))) { + UniqueFEIRStmt retypeStmt = + FEIRBuilder::CreateStmtRetype(vA.GenFEIRVarReg(), vAtmp.GenFEIRVarReg()); + stmts.emplace_back(std::move(retypeStmt)); + } + return stmts; +} + +// ========== DexOpAput ========= +DexOpAput::DexOpAput(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpAput::SetVAImpl(uint32 num) { + vA.regNum = num; + usedRegs.emplace_back(&vA); +} + +void DexOpAput::SetVBImpl(uint32 num) { + vB.regNum = num; + usedRegs.emplace_back(&vB); +} + +void DexOpAput::SetVCImpl(uint32 num) { + vC.regNum = num; + vC.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetIntIdx()); + usedRegs.emplace_back(&vC); +} + +void DexOpAput::ParseImpl(BCClassMethod &method) { + (void) method; + GStrIdx elemTypeNameIdx; + GStrIdx usedTypeNameIdx; + bool isIndeterminate = false; + switch (opcode) { + case kDexOpAput: { + // Int or float + elemTypeNameIdx = BCUtil::GetIntIdx(); + usedTypeNameIdx = BCUtil::GetAIntIdx(); + isIndeterminate = true; + break; + } + case kDexOpAputWide: { + elemTypeNameIdx = BCUtil::GetLongIdx(); + usedTypeNameIdx = BCUtil::GetALongIdx(); + isIndeterminate = true; + break; + } + case kDexOpAputObject: { + elemTypeNameIdx = BCUtil::GetJavaObjectNameMplIdx(); + usedTypeNameIdx = BCUtil::GetAJavaObjectNameMplIdx(); + isIndeterminate = true; + break; + } + case kDexOpAputBoolean: { + elemTypeNameIdx = BCUtil::GetBooleanIdx(); + usedTypeNameIdx = BCUtil::GetABooleanIdx(); + break; + } + case kDexOpAputByte: { + elemTypeNameIdx = BCUtil::GetByteIdx(); + usedTypeNameIdx = BCUtil::GetAByteIdx(); + break; + } + case kDexOpAputChar: { + elemTypeNameIdx = BCUtil::GetCharIdx(); + usedTypeNameIdx = BCUtil::GetACharIdx(); + break; + } + case kDexOpAputShort: { + elemTypeNameIdx = BCUtil::GetShortIdx(); + usedTypeNameIdx = BCUtil::GetAShortIdx(); + break; + } + default: { + CHECK_FATAL(false, "Invalid opcode : 0x%x in DexOpAput", opcode); + break; + } + } + vA.regTypeItem = allocator.GetMemPool()->New(elemTypeNameIdx, isIndeterminate); + vB.regTypeItem = allocator.GetMemPool()->New(usedTypeNameIdx, isIndeterminate); +} + +void DexOpAput::SetRegTypeInTypeInferImpl() { + if (vA.regType != nullptr && vB.regType != nullptr && vC.regType != nullptr) { + vB.regType->AddElemType(vA.regTypeItem); + } +} + +std::list DexOpAput::EmitToFEIRStmtsImpl() { + DexReg vAtmp; + vAtmp.regNum = vA.regNum; + const std::string &arrayTypeName = GlobalTables::GetStrTable().GetStringFromStrIdx(vB.regTypeItem->typeNameIdx); + if (arrayTypeName.size() > 1 && arrayTypeName.at(0) == 'A') { + vAtmp.regTypeItem = allocator.GetMemPool()->New( + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(arrayTypeName.substr(1))); + } else { + CHECK_FATAL(false, "Invalid array type %s", arrayTypeName.c_str()); + } + std::list stmts = FEIRBuilder::CreateStmtArrayStore(vAtmp.GenFEIRVarReg(), vB.GenFEIRVarReg(), + vC.GenFEIRVarReg()); + if (!((*vAtmp.regTypeItem) == (*vA.regTypeItem))) { + UniqueFEIRStmt retypeStmt = + FEIRBuilder::CreateStmtRetype(vAtmp.GenFEIRVarReg(), vA.GenFEIRVarReg()); + stmts.emplace_front(std::move(retypeStmt)); + } + return stmts; +} + +// ========== DexOpIget ========= +DexOpIget::DexOpIget(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpIget::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); +} + +void DexOpIget::SetVBImpl(uint32 num) { + vB.regNum = num; + usedRegs.emplace_back(&vB); +} + +void DexOpIget::SetVCImpl(uint32 num) { + index = num; +} + +void DexOpIget::ParseImpl(BCClassMethod &method) { + BCReader::ClassElem field = method.GetBCClass().GetBCParser().GetReader()->GetClassFieldFromIdx(index); + uint64 mapIdx = (static_cast(method.GetBCClass().GetBCParser().GetReader()->GetFileIndex()) << 32) | index; + structElemNameIdx = FEManager::GetManager().GetFieldStructElemNameIdx(mapIdx); + if (structElemNameIdx == nullptr) { + structElemNameIdx = FEManager::GetManager().GetStructElemMempool()->New( + field.className, field.elemName, field.typeName); + FEManager::GetManager().SetFieldStructElemNameIdx(mapIdx, *structElemNameIdx); + } + vA.regType = allocator.GetMemPool()->New(allocator, vA, structElemNameIdx->type); + vB.regTypeItem = allocator.GetMemPool()->New(structElemNameIdx->klass); +} + +std::list DexOpIget::EmitToFEIRStmtsImpl() { + std::list stmts; + FEStructFieldInfo *fieldInfo = static_cast( + FEManager::GetTypeManager().RegisterStructFieldInfo(*structElemNameIdx, kSrcLangJava, false)); + UniqueFEIRStmt stmt = std::make_unique(vB.GenFEIRVarReg(), vA.GenFEIRVarReg(), *fieldInfo, false); + stmts.push_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpIput ========= +DexOpIput::DexOpIput(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpIput::SetVAImpl(uint32 num) { + vA.regNum = num; + usedRegs.emplace_back(&vA); +} + +void DexOpIput::SetVBImpl(uint32 num) { + vB.regNum = num; + usedRegs.emplace_back(&vB); +} + +void DexOpIput::SetVCImpl(uint32 num) { + index = num; +} + +void DexOpIput::ParseImpl(BCClassMethod &method) { + BCReader::ClassElem field = method.GetBCClass().GetBCParser().GetReader()->GetClassFieldFromIdx(index); + uint64 mapIdx = (static_cast(method.GetBCClass().GetBCParser().GetReader()->GetFileIndex()) << 32) | index; + structElemNameIdx = FEManager::GetManager().GetFieldStructElemNameIdx(mapIdx); + if (structElemNameIdx == nullptr) { + structElemNameIdx = FEManager::GetManager().GetStructElemMempool()->New( + field.className, field.elemName, field.typeName); + FEManager::GetManager().SetFieldStructElemNameIdx(mapIdx, *structElemNameIdx); + } + vA.regTypeItem = allocator.GetMemPool()->New(structElemNameIdx->type); + vB.regTypeItem = allocator.GetMemPool()->New(structElemNameIdx->klass); +} + +std::list DexOpIput::EmitToFEIRStmtsImpl() { + std::list stmts; + FEStructFieldInfo *fieldInfo = static_cast( + FEManager::GetTypeManager().RegisterStructFieldInfo(*structElemNameIdx, kSrcLangJava, false)); + UniqueFEIRStmt stmt = std::make_unique(vB.GenFEIRVarReg(), vA.GenFEIRVarReg(), *fieldInfo, false); + stmts.push_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpSget ========= +DexOpSget::DexOpSget(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpSget::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); +} + +void DexOpSget::SetVBImpl(uint32 num) { + index = num; +} + +void DexOpSget::ParseImpl(BCClassMethod &method) { + BCReader::ClassElem field = method.GetBCClass().GetBCParser().GetReader()->GetClassFieldFromIdx(index); + uint64 mapIdx = (static_cast(method.GetBCClass().GetBCParser().GetReader()->GetFileIndex()) << 32) | index; + structElemNameIdx = FEManager::GetManager().GetFieldStructElemNameIdx(mapIdx); + if (structElemNameIdx == nullptr) { + structElemNameIdx = FEManager::GetManager().GetStructElemMempool()->New( + field.className, field.elemName, field.typeName); + FEManager::GetManager().SetFieldStructElemNameIdx(mapIdx, *structElemNameIdx); + } + vA.regType = allocator.GetMemPool()->New(allocator, vA, structElemNameIdx->type); + dexFileHashCode = method.GetBCClass().GetBCParser().GetFileNameHashId(); +} + +std::list DexOpSget::EmitToFEIRStmtsImpl() { + std::list ans; + FEStructFieldInfo *fieldInfo = static_cast( + FEManager::GetTypeManager().RegisterStructFieldInfo(*structElemNameIdx, kSrcLangJava, true)); + CHECK_NULL_FATAL(fieldInfo); + fieldInfo->SetFieldID(index); + UniqueFEIRVar var = vA.GenFEIRVarReg(); + UniqueFEIRStmt stmt = std::make_unique(nullptr, std::move(var), *fieldInfo, true, dexFileHashCode); + ans.emplace_back(std::move(stmt)); + return ans; +} + +// ========== DexOpSput ========= +DexOpSput::DexOpSput(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpSput::SetVAImpl(uint32 num) { + vA.regNum = num; + usedRegs.emplace_back(&vA); +} + +void DexOpSput::SetVBImpl(uint32 num) { + index = num; +} + +void DexOpSput::ParseImpl(BCClassMethod &method) { + BCReader::ClassElem field = method.GetBCClass().GetBCParser().GetReader()->GetClassFieldFromIdx(index); + uint64 mapIdx = (static_cast(method.GetBCClass().GetBCParser().GetReader()->GetFileIndex()) << 32) | index; + structElemNameIdx = FEManager::GetManager().GetFieldStructElemNameIdx(mapIdx); + if (structElemNameIdx == nullptr) { + structElemNameIdx = FEManager::GetManager().GetStructElemMempool()->New( + field.className, field.elemName, field.typeName); + FEManager::GetManager().SetFieldStructElemNameIdx(mapIdx, *structElemNameIdx); + } + vA.regTypeItem = allocator.GetMemPool()->New(structElemNameIdx->type); + dexFileHashCode = method.GetBCClass().GetBCParser().GetFileNameHashId(); +} + +std::list DexOpSput::EmitToFEIRStmtsImpl() { + std::list stmts; + FEStructFieldInfo *fieldInfo = static_cast( + FEManager::GetTypeManager().RegisterStructFieldInfo(*structElemNameIdx, kSrcLangJava, true)); + CHECK_NULL_FATAL(fieldInfo); + UniqueFEIRVar var = vA.GenFEIRVarReg(); + fieldInfo->SetFieldID(index); + UniqueFEIRStmt stmt = std::make_unique(nullptr, std::move(var), *fieldInfo, true, + dexFileHashCode); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpInvoke ========= +DexOpInvoke::DexOpInvoke(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn), argRegs(allocator.Adapter()), argVRegs(allocator.Adapter()) {} + +std::string DexOpInvoke::GetReturnType() const { + CHECK_FATAL(!retArgsTypeNames.empty(), "Should parse DexOpInvoke first for retrieving signature."); + return retArgsTypeNames[0]; +} + +void DexOpInvoke::SetVAImpl(uint32 num) { + argSize = num; +} + +void DexOpInvoke::SetVBImpl(uint32 num) { + methodIdx = num; +} + +void DexOpInvoke::SetVCImpl(uint32 num) { + arg0VRegNum = num; +} + +void DexOpInvoke::SetArgsImpl(const MapleList &args) { + argRegs = args; +} + +bool DexOpInvoke::ReplaceStringFactory(BCReader::ClassElem &methodInfo, MapleList &argRegNums) { + const std::string &fullName = methodInfo.className + "|" + methodInfo.elemName + "|" + methodInfo.typeName; + if (!DexStrFactory::IsStringInit(fullName)) { + return false; + } + isStringFactory = true; + std::string strFacCalleeName = DexStrFactory::GetStringFactoryFuncname(fullName); + CHECK_FATAL(!strFacCalleeName.empty(), "Can not find string factory call for %s", fullName.c_str()); + std::vector names = FEUtils::Split(strFacCalleeName, '|'); + // 3 parts: ClassName|ElemName|Signature + CHECK_FATAL(names.size() == 3, "Invalid funcname %s", strFacCalleeName.c_str()); + methodInfo.className = names.at(0); + methodInfo.elemName = names.at(1); + methodInfo.typeName = names.at(2); + // push this as return + retReg.regNum = argRegNums.front(); + retReg.isDef = true; + argRegNums.pop_front(); + retReg.regType = allocator.GetMemPool()->New(allocator, retReg, BCUtil::GetJavaStringNameMplIdx()); + defedRegs.emplace_back(&retReg); + return true; +} + +void DexOpInvoke::ParseImpl(BCClassMethod &method) { + MapleList &argRegNums = argRegs; + uint64 mapIdx = (static_cast(method.GetBCClass().GetBCParser().GetReader()->GetFileIndex()) << 32) | + methodIdx; + BCReader::ClassElem methodInfo = method.GetBCClass().GetBCParser().GetReader()->GetClassMethodFromIdx(methodIdx); + // for string factory, the highest bit for string factory flag + if (ReplaceStringFactory(methodInfo, argRegNums)) { + mapIdx = mapIdx | 0x8000000000000000; + } + structElemNameIdx = FEManager::GetManager().GetMethodStructElemNameIdx(mapIdx); + if (structElemNameIdx == nullptr) { + structElemNameIdx = FEManager::GetManager().GetStructElemMempool()->New( + methodInfo.className, methodInfo.elemName, methodInfo.typeName); + FEManager::GetManager().SetMethodStructElemNameIdx(mapIdx, *structElemNameIdx); + } + retArgsTypeNames = FEUtilJava::SolveMethodSignature(methodInfo.typeName); + DexReg reg; + if (!IsStatic()) { + reg.regNum = argRegNums.front(); + argRegNums.pop_front(); + reg.regTypeItem = allocator.GetMemPool()->New(structElemNameIdx->klass); + argVRegs.emplace_back(reg); + } + for (size_t i = 1; i < retArgsTypeNames.size(); ++i) { + reg.regNum = argRegNums.front(); + argRegNums.pop_front(); + GStrIdx usedTypeNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::EncodeName(retArgsTypeNames[i])); + if (BCUtil::IsWideType(usedTypeNameIdx)) { + argRegNums.pop_front(); // next regNum is consumed by wide type(long, double) + } + reg.regTypeItem = allocator.GetMemPool()->New(usedTypeNameIdx); + argVRegs.emplace_back(reg); + } + for (auto &vReg : argVRegs) { + usedRegs.emplace_back(&vReg); + } +} + +void DexOpInvoke::PrepareInvokeParametersAndReturn(const FEStructMethodInfo &feMethodInfo, + FEIRStmtCallAssign &stmt) const { + const MapleVector &argTypes = feMethodInfo.GetArgTypes(); + for (size_t i = argTypes.size(); i > 0; --i) { + UniqueFEIRVar var = argVRegs[i - 1 + (IsStatic() ? 0 : 1)].GenFEIRVarReg(); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(var)); + stmt.AddExprArgReverse(std::move(expr)); + } + if (!IsStatic()) { + // push this + UniqueFEIRVar var = argVRegs[0].GenFEIRVarReg(); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(var)); + stmt.AddExprArgReverse(std::move(expr)); + } + if (HasReturn()) { + static_cast(returnInst)->SetVATypeNameIdx( + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(retArgsTypeNames.at(0)))); + UniqueFEIRVar var = static_cast(returnInst)->GetVA().GenFEIRVarReg(); + stmt.SetVar(std::move(var)); + } + if (isStringFactory) { + stmt.SetVar(retReg.GenFEIRVarReg()); + } +} + +std::list DexOpInvoke::EmitToFEIRStmtsImpl() { + std::list ans; + UniqueFEIRStmt stmt; + FEStructMethodInfo *info = static_cast( + FEManager::GetTypeManager().RegisterStructMethodInfo(*structElemNameIdx, kSrcLangJava, IsStatic())); + auto itor = dexOpInvokeOp2MIROp.find(static_cast(opcode)); + CHECK_FATAL(itor != dexOpInvokeOp2MIROp.end(), "Unsupport opcode: 0x%x in DexOpInvoke", opcode); + stmt = std::make_unique(*info, itor->second, nullptr, IsStatic()); + FEIRStmtCallAssign *ptrStmt = static_cast(stmt.get()); + PrepareInvokeParametersAndReturn(*info, *ptrStmt); + ans.emplace_back(std::move(stmt)); + retArgsTypeNames.clear(); + retArgsTypeNames.shrink_to_fit(); + return ans; +} + +bool DexOpInvoke::IsStatic() const { + return opcode == kDexOpInvokeStatic || opcode == kDexOpInvokeStaticRange || isStringFactory; +} + +// ========== DexOpInvokeVirtual ========= +DexOpInvokeVirtual::DexOpInvokeVirtual(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOpInvoke(allocatorIn, pcIn, opcodeIn) {} + +// ========== DexOpInvokeSuper ========= +DexOpInvokeSuper::DexOpInvokeSuper(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOpInvoke(allocatorIn, pcIn, opcodeIn) {} + +// ========== DexOpInvokeDirect ========= +DexOpInvokeDirect::DexOpInvokeDirect(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOpInvoke(allocatorIn, pcIn, opcodeIn) {} + +// ========== DexOpInvokeStatic ========= +DexOpInvokeStatic::DexOpInvokeStatic(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOpInvoke(allocatorIn, pcIn, opcodeIn) {} + +// ========== DexOpInvokeInterface ========= +DexOpInvokeInterface::DexOpInvokeInterface(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOpInvoke(allocatorIn, pcIn, opcodeIn) {} + +// ========== DexOpUnaryOp ========= +DexOpUnaryOp::DexOpUnaryOp(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpUnaryOp::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); + auto it = GetOpcodeMapForUnary().find(opcode); + CHECK_FATAL(it != GetOpcodeMapForUnary().end(), "Invalid opcode: %u in DexOpUnaryOp", opcode); + mirOp = std::get<0>(it->second); + vA.regType = allocator.GetMemPool()->New(allocator, vA, std::get<1>(it->second)); + vB.regTypeItem = allocator.GetMemPool()->New(std::get<2>(it->second)); +} + +void DexOpUnaryOp::SetVBImpl(uint32 num) { + vB.regNum = num; + // vB's type is set in SetVAImpl + usedRegs.emplace_back(&vB); +} + +std::list DexOpUnaryOp::EmitToFEIRStmtsImpl() { + std::list stmts; + UniqueFEIRExpr exprDread = FEIRBuilder::CreateExprDRead(vB.GenFEIRVarReg()); + UniqueFEIRExpr experUnary = nullptr; + switch (mirOp) { + case OP_cvt: + experUnary = FEIRBuilder::CreateExprCvtPrim(std::move(exprDread), vA.GetPrimType()); + break; + case OP_sext: + experUnary = FEIRBuilder::CreateExprSExt(std::move(exprDread), vA.GetPrimType()); + break; + case OP_zext: + experUnary = FEIRBuilder::CreateExprZExt(std::move(exprDread), vA.GetPrimType()); + break; + case OP_neg: + case OP_bnot: + experUnary = FEIRBuilder::CreateExprMathUnary(mirOp, std::move(exprDread)); + break; + default: + CHECK_FATAL(false, "Invalid mir opcode: %u in DexOpUnaryOp", mirOp); + break; + } + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(vA.GenFEIRVarReg(), std::move(experUnary)); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +std::map> DexOpUnaryOp::InitOpcodeMapForUnary() { + std::map> ans; + ans[kDexOpIntToLong] = std::make_tuple(OP_cvt, BCUtil::GetLongIdx(), BCUtil::GetIntIdx()); + ans[kDexOpIntToFloat] = std::make_tuple(OP_cvt, BCUtil::GetFloatIdx(), BCUtil::GetIntIdx()); + ans[kDexOpIntToDouble] = std::make_tuple(OP_cvt, BCUtil::GetDoubleIdx(), BCUtil::GetIntIdx()); + ans[kDexOpLongToInt] = std::make_tuple(OP_cvt, BCUtil::GetIntIdx(), BCUtil::GetLongIdx()); + ans[kDexOpLongToFloat] = std::make_tuple(OP_cvt, BCUtil::GetFloatIdx(), BCUtil::GetLongIdx()); + ans[kDexOpLongToDouble] = std::make_tuple(OP_cvt, BCUtil::GetDoubleIdx(), BCUtil::GetLongIdx()); + ans[kDexOpFloatToInt] = std::make_tuple(OP_cvt, BCUtil::GetIntIdx(), BCUtil::GetFloatIdx()); + ans[kDexOpFloatToLong] = std::make_tuple(OP_cvt, BCUtil::GetLongIdx(), BCUtil::GetFloatIdx()); + ans[kDexOpFloatToDouble] = std::make_tuple(OP_cvt, BCUtil::GetDoubleIdx(), BCUtil::GetFloatIdx()); + ans[kDexOpDoubleToInt] = std::make_tuple(OP_cvt, BCUtil::GetIntIdx(), BCUtil::GetDoubleIdx()); + ans[kDexOpDoubleToLong] = std::make_tuple(OP_cvt, BCUtil::GetLongIdx(), BCUtil::GetDoubleIdx()); + ans[kDexOpDoubleToFloat] = std::make_tuple(OP_cvt, BCUtil::GetFloatIdx(), BCUtil::GetDoubleIdx()); + ans[kDexOpIntToByte] = std::make_tuple(OP_sext, BCUtil::GetByteIdx(), BCUtil::GetIntIdx()); + ans[kDexOpIntToChar] = std::make_tuple(OP_zext, BCUtil::GetCharIdx(), BCUtil::GetIntIdx()); + ans[kDexOpIntToShort] = std::make_tuple(OP_sext, BCUtil::GetShortIdx(), BCUtil::GetIntIdx()); + ans[kDexOpNegInt] = std::make_tuple(OP_neg, BCUtil::GetIntIdx(), BCUtil::GetIntIdx()); + ans[kDexOpNotInt] = std::make_tuple(OP_bnot, BCUtil::GetIntIdx(), BCUtil::GetIntIdx()); + ans[kDexOpNegLong] = std::make_tuple(OP_neg, BCUtil::GetLongIdx(), BCUtil::GetLongIdx()); + ans[kDexOpNotLong] = std::make_tuple(OP_bnot, BCUtil::GetLongIdx(), BCUtil::GetLongIdx()); + ans[kDexOpNegFloat] = std::make_tuple(OP_neg, BCUtil::GetFloatIdx(), BCUtil::GetFloatIdx()); + ans[kDexOpNegDouble] = std::make_tuple(OP_neg, BCUtil::GetDoubleIdx(), BCUtil::GetDoubleIdx()); + return ans; +} + +// ========== DexOpBinaryOp ========= +DexOpBinaryOp::DexOpBinaryOp(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpBinaryOp::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); + GStrIdx typeNameIdx; // typeName of A, B, C are same + if (kDexOpAddInt <= opcode && opcode <= kDexOpUshrInt) { + typeNameIdx = BCUtil::GetIntIdx(); + } else if (kDexOpAddLong <= opcode && opcode <= kDexOpUshrLong) { + typeNameIdx = BCUtil::GetLongIdx(); + } else if (kDexOpAddFloat <= opcode && opcode <= kDexOpRemFloat) { + typeNameIdx = BCUtil::GetFloatIdx(); + } else if (kDexOpAddDouble <= opcode && opcode <= kDexOpRemDouble) { + typeNameIdx = BCUtil::GetDoubleIdx(); + } else { + CHECK_FATAL(false, "Invalid opcode: 0x%x in DexOpBinaryOp", opcode); + } + vA.regType = allocator.GetMemPool()->New(allocator, vA, typeNameIdx); +} + +void DexOpBinaryOp::SetVBImpl(uint32 num) { + vB.regNum = num; + vB.regTypeItem = allocator.GetMemPool()->New(*(vA.regTypeItem)); + usedRegs.emplace_back(&vB); +} + +void DexOpBinaryOp::SetVCImpl(uint32 num) { + vC.regNum = num; + if (kDexOpShlLong <= opcode && opcode <= kDexOpUshrLong) { + vC.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetIntIdx()); + } else { + vC.regTypeItem = allocator.GetMemPool()->New(*(vA.regTypeItem)); + } + usedRegs.emplace_back(&vC); +} + +Opcode DexOpBinaryOp::GetOpcodeFromDexIns(void) const { + auto mirOp = dexOp2MIROp.find(opcode); + CHECK_FATAL(mirOp != dexOp2MIROp.end(), "Invalid opcode: 0x%x in DexOpBinaryOp", opcode); + return mirOp->second; +} + +std::list DexOpBinaryOp::EmitToFEIRStmtsImpl() { + std::list stmts; + if (kDexOpAddInt <= opcode && opcode <= kDexOpRemDouble) { + UniqueFEIRExpr exprB = std::make_unique(vB.GenFEIRVarReg()); + UniqueFEIRExpr exprC = std::make_unique(vC.GenFEIRVarReg()); + std::unique_ptr binaryOp2AddrExpr = + std::make_unique(GetOpcodeFromDexIns(), std::move(exprB), std::move(exprC)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(vA.GenFEIRVarReg(), std::move(binaryOp2AddrExpr)); + stmts.emplace_back(std::move(stmt)); + } else { + CHECK_FATAL(false, "Invalid opcode: 0x%x in DexOpBinaryOp", opcode); + } + return stmts; +} + +// ========== DexOpBinaryOp2Addr ========= +DexOpBinaryOp2Addr::DexOpBinaryOp2Addr(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpBinaryOp2Addr::SetVAImpl(uint32 num) { + vDef.regNum = num; + vDef.isDef = true; + vA.regNum = num; + defedRegs.emplace_back(&vDef); + usedRegs.emplace_back(&vA); + // typeName of A, B are same, except `shl-long/2addr` ~ `ushr-long/2addr` + GStrIdx typeNameAIdx; + GStrIdx typeNameBIdx; + if (kDexOpAddInt2Addr <= opcode && opcode <= kDexOpUshrInt2Addr) { + typeNameAIdx = BCUtil::GetIntIdx(); + typeNameBIdx = typeNameAIdx; + } else if (kDexOpAddLong2Addr <= opcode && opcode <= kDexOpXorLong2Addr) { + typeNameAIdx = BCUtil::GetLongIdx(); + typeNameBIdx = typeNameAIdx; + } else if (kDexOpShlLong2Addr <= opcode && opcode <= kDexOpUshrLong2Addr) { + typeNameAIdx = BCUtil::GetLongIdx(); + typeNameBIdx = BCUtil::GetIntIdx(); + } else if (kDexOpAddFloat2Addr <= opcode && opcode <= kDexOpRemFloat2Addr) { + typeNameAIdx = BCUtil::GetFloatIdx(); + typeNameBIdx = typeNameAIdx; + } else if (kDexOpAddDouble2Addr <= opcode && opcode <= kDexOpRemDouble2Addr) { + typeNameAIdx = BCUtil::GetDoubleIdx(); + typeNameBIdx = typeNameAIdx; + } else { + CHECK_FATAL(false, "Invalid opcode: 0x%x in DexOpBinaryOp2Addr", opcode); + } + vDef.regType = allocator.GetMemPool()->New(allocator, vDef, typeNameAIdx); + vA.regTypeItem = allocator.GetMemPool()->New(typeNameAIdx); + vB.regTypeItem = allocator.GetMemPool()->New(typeNameBIdx); +} + +void DexOpBinaryOp2Addr::SetVBImpl(uint32 num) { + vB.regNum = num; + // type is set in SetVAImpl + usedRegs.emplace_back(&vB); +} + +Opcode DexOpBinaryOp2Addr::GetOpcodeFromDexIns(void) const { + auto mirOp = dexOp2Addr2MIROp.find(opcode); + CHECK_FATAL(mirOp != dexOp2Addr2MIROp.end(), "Invalid opcode: 0x%x in DexOpBinaryOp2Addr", opcode); + return mirOp->second; +} + +std::list DexOpBinaryOp2Addr::EmitToFEIRStmtsImpl() { + std::list stmts; + if (kDexOpAddInt2Addr <= opcode && opcode <= kDexOpRemDouble2Addr) { + UniqueFEIRExpr exprDst = std::make_unique(vA.GenFEIRVarReg()); + UniqueFEIRExpr exprSrc = std::make_unique(vB.GenFEIRVarReg()); + std::unique_ptr binaryOp2AddrExpr = + std::make_unique(GetOpcodeFromDexIns(), std::move(exprDst), std::move(exprSrc)); + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(vA.GenFEIRVarReg(), std::move(binaryOp2AddrExpr)); + stmts.emplace_back(std::move(stmt)); + } else { + CHECK_FATAL(false, "Invalid opcode: 0x%x in DexOpBinaryOp2Addr", opcode); + } + return stmts; +} + +// ========== DexOpBinaryOpLit ========= +DexOpBinaryOpLit::DexOpBinaryOpLit(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) { + isLit8 = (kDexOpAddIntLit8 <= opcode && opcode <= kDexOpUshrIntLit8); +} + +void DexOpBinaryOpLit::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); + vA.regType = allocator.GetMemPool()->New(allocator, vA, BCUtil::GetIntIdx()); +} + +void DexOpBinaryOpLit::SetVBImpl(uint32 num) { + vB.regNum = num; + vB.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetIntIdx()); + usedRegs.emplace_back(&vB); +} + +void DexOpBinaryOpLit::SetVCImpl(uint32 num) { + if (isLit8) { + constValue.i8 = static_cast(num); + } else { + constValue.i16 = static_cast(num); + } +} + +Opcode DexOpBinaryOpLit::GetOpcodeFromDexIns() const { + auto mirOp = dexOpLit2MIROp.find(opcode); + CHECK_FATAL(mirOp != dexOpLit2MIROp.end(), "Invalid opcode: 0x%x in DexOpBinaryOpLit", opcode); + return mirOp->second; +} + +std::list DexOpBinaryOpLit::EmitToFEIRStmtsImpl() { + std::list stmts; + UniqueFEIRExpr exprConst = isLit8 ? FEIRBuilder::CreateExprConstI8(constValue.i8) : + FEIRBuilder::CreateExprConstI16(constValue.i16); + UniqueFEIRExpr exprCvt = FEIRBuilder::CreateExprCvtPrim(std::move(exprConst), PTY_i32); + UniqueFEIRExpr exprDreadB = FEIRBuilder::CreateExprDRead(vB.GenFEIRVarReg()); + UniqueFEIRExpr exprBinary = nullptr; + if (opcode == kDexOpRsubInt || opcode == kDexOpRsubIntLit8) { + // reverse opnd + exprBinary = FEIRBuilder::CreateExprMathBinary(GetOpcodeFromDexIns(), std::move(exprCvt), std::move(exprDreadB)); + } else { + exprBinary = FEIRBuilder::CreateExprMathBinary(GetOpcodeFromDexIns(), std::move(exprDreadB), std::move(exprCvt)); + } + UniqueFEIRStmt stmt = FEIRBuilder::CreateStmtDAssign(vA.GenFEIRVarReg(), std::move(exprBinary)); + stmts.emplace_back(std::move(stmt)); + return stmts; +} + +// ========== DexOpInvokePolymorphic ========= +DexOpInvokePolymorphic::DexOpInvokePolymorphic(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOpInvoke(allocatorIn, pcIn, opcodeIn) {} + +void DexOpInvokePolymorphic::SetVHImpl(uint32 num) { + protoIdx = num; +} + +void DexOpInvokePolymorphic::ParseImpl(BCClassMethod &method) { + isStatic = method.IsStatic(); + const BCReader::ClassElem &methodInfo = + method.GetBCClass().GetBCParser().GetReader()->GetClassMethodFromIdx(methodIdx); + const std::string &funcName = methodInfo.className + "|" + methodInfo.elemName + "|" + methodInfo.typeName; + if (FEOptions::GetInstance().IsAOT()) { + std::string callerClassName = method.GetBCClass().GetClassName(true); + int32 dexFileHashCode = method.GetBCClass().GetBCParser().GetFileNameHashId(); + callerClassID = FEManager::GetTypeManager().GetTypeIDFromMplClassName(callerClassName, dexFileHashCode); + } + fullNameMpl = namemangler::EncodeName(funcName); + protoName = method.GetBCClass().GetBCParser().GetReader()->GetSignature(protoIdx); + retArgsTypeNames = FEUtilJava::SolveMethodSignature(protoName); + DexReg reg; + MapleList argRegNums = argRegs; + std::string typeName; + // Receiver + { + reg.regNum = arg0VRegNum; + reg.regTypeItem = allocator.GetMemPool()->New(BCUtil::GetJavaMethodHandleNameMplIdx()); + argVRegs.emplace_back(reg); + } + if (opcode == kDexOpInvokePolymorphicRange) { + argRegNums.pop_front(); // Skip first reg num for 'receiver' + } + for (size_t i = 1; i < retArgsTypeNames.size(); ++i) { + reg.regNum = argRegNums.front(); + argRegNums.pop_front(); + typeName = retArgsTypeNames[i]; + typeName = namemangler::EncodeName(typeName); + GStrIdx usedTypeNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(typeName); + if (BCUtil::IsWideType(usedTypeNameIdx)) { + argRegNums.pop_front(); // next regNum is consumed by wide type(long, double) + } + reg.regTypeItem = allocator.GetMemPool()->New(usedTypeNameIdx); + argVRegs.emplace_back(reg); + } + for (auto &vReg : argVRegs) { + usedRegs.emplace_back(&vReg); + } +} + +std::list DexOpInvokePolymorphic::EmitToFEIRStmtsImpl() { + std::list stmts; + std::unique_ptr> args = std::make_unique>(); + for (const auto ® : argVRegs) { + args->emplace_back(reg.GenFEIRVarReg()); + } + std::unique_ptr stmt = std::make_unique( + INTRN_JAVA_POLYMORPHIC_CALL, fullNameMpl, protoName, std::move(args), callerClassID, isStatic); + if (HasReturn()) { + static_cast(returnInst)->SetVATypeNameIdx( + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(retArgsTypeNames.at(0)))); + UniqueFEIRVar var = static_cast(returnInst)->GetVA().GenFEIRVarReg(); + stmt->SetVar(std::move(var)); + } else if (retArgsTypeNames[0] != "V") { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("retvarpoly"); + std::unique_ptr retTmpVarType = FEIRBuilder::CreateTypeByJavaName(retArgsTypeNames[0], false); + UniqueFEIRVar retTmpVar = std::make_unique(nameIdx, retTmpVarType->Clone(), false); + stmt->SetVar(std::move(retTmpVar)); + } + + stmts.emplace_back(std::move(stmt)); + retArgsTypeNames.clear(); + retArgsTypeNames.shrink_to_fit(); + fullNameMpl.clear(); + fullNameMpl.shrink_to_fit(); + protoName.clear(); + protoName.shrink_to_fit(); + return stmts; +} + +// ========== DexOpInvokeCustom ========= +DexOpInvokeCustom::DexOpInvokeCustom(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn), argRegs(allocator.Adapter()), argVRegs(allocator.Adapter()) {} + +void DexOpInvokeCustom::SetVBImpl(uint32 num) { + callSiteIdx = num; +} + +void DexOpInvokeCustom::SetArgsImpl(const MapleList &args) { + argRegs = args; +} + +// ========== DexOpConstMethodHandle ========= +DexOpConstMethodHandle::DexOpConstMethodHandle(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpConstMethodHandle::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); +} + +void DexOpConstMethodHandle::SetVBImpl(uint32 num) { + mhIdx = num; +} +// ========== DexOpConstMethodType ========= +DexOpConstMethodType::DexOpConstMethodType(MapleAllocator &allocatorIn, uint32 pcIn, DexOpCode opcodeIn) + : DexOp(allocatorIn, pcIn, opcodeIn) {} + +void DexOpConstMethodType::SetVAImpl(uint32 num) { + vA.regNum = num; + vA.isDef = true; + defedRegs.emplace_back(&vA); +} + +void DexOpConstMethodType::SetVBImpl(uint32 num) { + protoIdx = num; +} +} // namespace bc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/dex/src/dex_parser.cpp b/src/hir2mpl/bytecode_input/dex/src/dex_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48092dd79bd2ead3f504036443a1899cde1ad465 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dex_parser.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dex_parser.h" +#include "fe_manager.h" +#include "dex_pragma.h" +#include "dex_encode_value.h" +#include "fe_manager.h" +#include "fe_options.h" +#include "dex_file_util.h" + +namespace maple { +namespace bc { +DexParser::DexParser(uint32 fileIdxIn, const std::string &fileNameIn, const std::list &classNamesIn) + : BCParser(fileIdxIn, fileNameIn, classNamesIn) {} + +const BCReader *DexParser::GetReaderImpl() const { + return reader.get(); +} + +void DexParser::SetDexFile(std::unique_ptr iDexFileIn) { + reader->SetDexFile(std::move(iDexFileIn)); +} + +uint32 DexParser::CalculateCheckSumImpl(const uint8 *data, uint32 size) { + (void) data; + (void) size; + return 0; // Not work in DexParser +} + +bool DexParser::ParseHeaderImpl() { + return true; // Not work in DexParser +} + +bool DexParser::VerifyImpl() { + return true; // Not work in DexParser +} + +bool DexParser::RetrieveIndexTables() { + return true; +} + +bool DexParser::RetrieveUserSpecifiedClasses(std::list> &klasses) { + (void) klasses; + return false; +} + +bool DexParser::RetrieveAllClasses(std::list> &klasses) { + uint32 classItemsSize = reader->GetClassItemsSize(); + for (uint32 classIdx = 0; classIdx < classItemsSize; ++classIdx) { + klasses.push_back(ProcessDexClass(classIdx)); + } + return true; +} + +bool DexParser::CollectAllDepTypeNamesImpl(std::unordered_set &depSet) { + return reader->ReadAllDepTypeNames(depSet); +} + +bool DexParser::CollectMethodDepTypeNamesImpl(std::unordered_set &depSet, BCClassMethod &bcMethod) const { + return reader->ReadMethodDepTypeNames(depSet, bcMethod.GetBCClass().GetClassIdx(), + bcMethod.GetItemIdx(), bcMethod.IsVirtual()); +} + +bool DexParser::CollectAllClassNamesImpl(std::unordered_set &classSet) { + return reader->ReadAllClassNames(classSet); +} + +std::unique_ptr DexParser::FindClassDef(const std::string &className) { + const BCReader *reader = GetReader(); + const DexReader *dexReader = static_cast(reader); + maple::IDexFile &iDexFile = dexReader->GetIDexFile(); + uint32 classIdx = iDexFile.FindClassDefIdx(className); + if (classIdx == DexFileUtil::kNoIndex) { + return nullptr; + } + std::unique_ptr dexClass = std::make_unique(classIdx, *this); + ProcessDexClassDef(dexClass); + ProcessDexClassFields(dexClass); + ProcessDexClassMethodDecls(dexClass, false); + ProcessDexClassMethodDecls(dexClass, true); + ProcessDexClassAnnotationDirectory(dexClass); + return dexClass; +} + +std::unique_ptr DexParser::ProcessDexClass(uint32 classIdx) { + std::unique_ptr dexClass = std::make_unique(classIdx, *this); + ProcessDexClassDef(dexClass); + ProcessDexClassFields(dexClass); + // direct methods are ahead of virtual methods in class + ProcessDexClassMethods(dexClass, false); + ProcessDexClassMethods(dexClass, true); + ProcessDexClassAnnotationDirectory(dexClass); + if (!FEOptions::GetInstance().IsGenMpltOnly()) { + ProcessDexClassStaticFieldInitValue(dexClass); + } + return dexClass; +} + +void DexParser::ProcessDexClassDef(const std::unique_ptr &dexClass) { + uint32 classIdx = dexClass->GetClassIdx(); + dexClass->SetFilePathName(fileName); + const char *srcFileName = reader->GetClassJavaSourceFileName(classIdx); + dexClass->SetSrcFileInfo(srcFileName == nullptr ? "unknown" : srcFileName); + dexClass->SetAccFlag(reader->GetClassAccFlag(classIdx)); + const std::string &className = reader->GetClassName(classIdx); + dexClass->SetClassName(className); + dexClass->SetIsInterface(reader->IsInterface(classIdx)); + dexClass->SetSuperClasses(reader->GetSuperClasses(classIdx)); + GStrIdx irSrcFileSigIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(reader->GetIRSrcFileSignature()); + dexClass->SetIRSrcFileSigIdx(irSrcFileSigIdx); + ProcessDexClassInterfaceParent(dexClass); +} + +void DexParser::ProcessDexClassFields(const std::unique_ptr &dexClass) { + uint32 classIdx = dexClass->GetClassIdx(); + maple::IDexFile &iDexFile = reader->GetIDexFile(); + std::vector> fieldItems = iDexFile.GetClassItem(classIdx)->GetFields(iDexFile); + for (uint32 idx = 0; idx < fieldItems.size(); ++idx) { + std::unique_ptr dexClassField = std::make_unique( + *dexClass, idx, fieldItems[idx]->GetFieldIdx(), + fieldItems[idx]->GetAccessFlags(), + reader->GetClassFieldName(fieldItems[idx]->GetFieldIdx()), + reader->GetClassFieldTypeName(fieldItems[idx]->GetFieldIdx())); + dexClass->SetField(std::move(dexClassField)); + } +} + +void DexParser::ProcessDexClassInterfaceParent(const std::unique_ptr &dexClass) { + uint32 classIdx = dexClass->GetClassIdx(); + const std::vector &names = reader->GetClassInterfaceNames(classIdx); + for (const auto &name : names) { + dexClass->SetInterface(name); + } +} + +void DexParser::ProcessMethodBodyImpl(BCClassMethod &method, + uint32 classIdx, uint32 methodItemIdx, bool isVirtual) const { + maple::IDexFile &iDexFile = reader->GetIDexFile(); + std::unique_ptr dexMethodItem; + if (isVirtual) { + dexMethodItem = iDexFile.GetClassItem(classIdx)->GetVirtualMethod(iDexFile, methodItemIdx); + } else { + dexMethodItem = iDexFile.GetClassItem(classIdx)->GetDirectMethod(iDexFile, methodItemIdx); + } + method.GenArgRegs(); + method.SetMethodInstOffset(reader->GetMethodInstOffset(dexMethodItem.get())); + method.SetPCBCInstructionMap( + reader->ResolveInstructions(method.GetAllocator(), dexMethodItem.get())); + method.SetSrcLocalInfo(reader->ResovleSrcLocalInfo(*dexMethodItem)); + method.SetTryInfos(reader->ResolveTryInfos(dexMethodItem.get())); +#ifdef DEBUG + std::map srcPosInfo; + reader->ResovleSrcPositionInfo(dexMethodItem.get(), srcPosInfo); + method.SetSrcPositionInfo(srcPosInfo); +#endif + method.ProcessInstructions(); +} + +void DexParser::ProcessDexClassMethod(const std::unique_ptr &dexClass, + bool isVirtual, uint32 index, std::pair &idxPair) { + std::unique_ptr method = std::make_unique( + *dexClass, index, idxPair.first, isVirtual, idxPair.second, + reader->GetClassMethodName(idxPair.first), reader->GetClassMethodDescName(idxPair.first)); + uint32 classIdx = dexClass->GetClassIdx(); + maple::IDexFile &iDexFile = reader->GetIDexFile(); + std::unique_ptr dexMethodItem; + if (isVirtual) { + dexMethodItem = iDexFile.GetClassItem(classIdx)->GetVirtualMethod(iDexFile, method->GetItemIdx()); + } else { + dexMethodItem = iDexFile.GetClassItem(classIdx)->GetDirectMethod(iDexFile, method->GetItemIdx()); + } + method->SetRegisterTotalSize(reader->GetClassMethodRegisterTotalSize(dexMethodItem.get())); + method->SetRegisterInsSize(reader->GetClassMethodRegisterInSize(dexMethodItem.get())); + method->SetCodeOff(reader->GetCodeOff(dexMethodItem.get())); + dexClass->SetMethod(std::move(method)); +} + +void DexParser::ProcessDexClassMethods(const std::unique_ptr &dexClass, bool isVirtual) { + uint32 classIdx = dexClass->GetClassIdx(); + maple::IDexFile &iDexFile = reader->GetIDexFile(); + std::vector> methodItemsIdxAndFlag = + iDexFile.GetClassItem(classIdx)->GetMethodsIdxAndFlag(iDexFile, isVirtual); + uint32 index = 0; + for (auto idxPair : methodItemsIdxAndFlag) { + ProcessDexClassMethod(dexClass, isVirtual, index++, idxPair); + } +} + +void DexParser::ProcessDexClassMethodDecls(const std::unique_ptr &dexClass, bool isVirtual) { + uint32 classIdx = dexClass->GetClassIdx(); + maple::IDexFile &iDexFile = reader->GetIDexFile(); + std::vector> methodItemsIdxAndFlag = + iDexFile.GetClassItem(classIdx)->GetMethodsIdxAndFlag(iDexFile, isVirtual); + uint32 index = 0; + for (auto idxPair : methodItemsIdxAndFlag) { + std::unique_ptr method = std::make_unique( + *dexClass, index++, idxPair.first, isVirtual, idxPair.second, + reader->GetClassMethodName(idxPair.first), reader->GetClassMethodDescName(idxPair.first)); + dexClass->SetMethod(std::move(method)); + } +} + +void DexParser::ProcessDexClassAnnotationDirectory(const std::unique_ptr &dexClass) { + const BCReader *reader = GetReader(); + const DexReader *dexReader = static_cast(reader); + maple::IDexFile &iDexFile = dexReader->GetIDexFile(); + uint32 classDefIdx = dexClass->GetClassIdx(); + const IDexClassItem *iDexClassItem = iDexFile.GetClassItem(classDefIdx); + const IDexAnnotationsDirectory *iDexAnnotationsDirectory = iDexClassItem->GetAnnotationsDirectory(iDexFile); + MIRModule &module = FEManager::GetModule(); + std::unique_ptr annotationsDirectory = + std::make_unique(module, *(module.GetMemPool()), iDexFile, + iDexClassItem->GetClassName(iDexFile), iDexAnnotationsDirectory); + dexClass->SetAnnotationsDirectory(std::move(annotationsDirectory)); +} + +void DexParser::ProcessDexClassStaticFieldInitValue(const std::unique_ptr &dexClass) { + const BCReader *reader = GetReader(); + const DexReader *dexReader = static_cast(reader); + maple::IDexFile &iDexFile = dexReader->GetIDexFile(); + std::unique_ptr dexEncodeValue = + std::make_unique(*FEManager::GetModule().GetMemPool(), iDexFile); + uint32 classDefIdx = dexClass->GetClassIdx(); + const IDexClassItem *classItem = iDexFile.GetClassItem(classDefIdx); + const uint8 *staticValuesList = classItem->GetStaticValuesList(iDexFile); + if (staticValuesList == nullptr) { + return; + } + const uint8 **data = &staticValuesList; + uint32 size = iDexFile.ReadUnsignedLeb128(data); + for (uint32 i = 0; i < size; ++i) { + MIRConst *cst = nullptr; + uint64 dataVal = *(*data)++; + uint8 valueArg = static_cast(dataVal >> 5); // valueArgs : dataVal >> 5, The higher three bits are valid. + uint8 valueType = dataVal & 0x1f; + // get initialization value, max 8 bytes, little-endian + uint32 stringID = 0; + dexEncodeValue->ProcessEncodedValue(data, valueType, valueArg, cst, stringID); + dexClass->InsertStaticFieldConstVal(cst); + if (FEOptions::GetInstance().IsAOT() && (valueType == kValueString)) { + dexClass->InsertFinalStaticStringID(stringID); + } + } +} +} // namespace bc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/dex/src/dex_pragma.cpp b/src/hir2mpl/bytecode_input/dex/src/dex_pragma.cpp new file mode 100644 index 0000000000000000000000000000000000000000..da55cd4d955212289839918307aeed8bf6a8c1f3 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dex_pragma.cpp @@ -0,0 +1,538 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dex_pragma.h" +#include "global_tables.h" +#include "ark_annotation_map.h" +#include "fe_manager.h" +#include "bc_util.h" +#include "fe_manager.h" +#include "ark_annotation_processor.h" +#include "rc_setter.h" + +namespace maple { +namespace bc { +// ---------- DexBCAnnotationElement ---------- +MIRPragmaElement *DexBCAnnotationElement::ProcessAnnotationElement(const uint8 **data) { + uint32 nameIdx = iDexFile.ReadUnsignedLeb128(data); + const char *elemNameFieldOrig = iDexFile.GetStringByIndex(nameIdx); + const std::string elemNameField = namemangler::EncodeName(elemNameFieldOrig); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(elemNameField); + MIRPragmaElement *element = mp.New(module); + element->SetNameStrIdx(strIdx); + // Process encoded value. + uint64 dataVal = *(*data)++; + uint8 valueArg = static_cast(dataVal >> 5); + uint8 valueType = dataVal & 0x1f; + PragmaValueType pragmaValueType = static_cast(valueType); + element->SetType(pragmaValueType); + MIRConst *cst = nullptr; + ProcessAnnotationEncodedValue(data, *element, pragmaValueType, valueArg, cst); + return element; +} + +void DexBCAnnotationElement::ProcessAnnotationEncodedValue(const uint8 **data, MIRPragmaElement &element, + MIRConst *&cst) { + uint64 dataVal = *(*data)++; + ProcessAnnotationEncodedValue(data, element, static_cast(dataVal & 0x1f), + static_cast(dataVal >> 5), cst); +} + +void DexBCAnnotationElement::ProcessAnnotationEncodedValue(const uint8 **data, MIRPragmaElement &element, + PragmaValueType valueType, uint8 valueArg, MIRConst *&cst) { + element.SetType(valueType); + uint64 val = 0; + cst = mp.New(0, *GlobalTables::GetTypeTable().GetInt32()); + switch (valueType) { + case kValueByte: { + val = GetUVal(data, valueArg); + element.SetU64Val(val); + cst = mp.New(val, *GlobalTables::GetTypeTable().GetInt8()); + break; + } + case kValueShort: { + cst = ProcessAnnotationEncodedValueInternalProcessIntValue(data, element, valueArg, + *GlobalTables::GetTypeTable().GetInt16()); + break; + } + case kValueChar: { + val = GetUVal(data, valueArg); + cst = mp.New(val, *GlobalTables::GetTypeTable().GetUInt16()); + element.SetU64Val(val); + break; + } + case kValueInt: { + cst = ProcessAnnotationEncodedValueInternalProcessIntValue(data, element, valueArg, + *GlobalTables::GetTypeTable().GetInt32()); + break; + } + case kValueLong: { + cst = ProcessAnnotationEncodedValueInternalProcessIntValue(data, element, valueArg, + *GlobalTables::GetTypeTable().GetInt64()); + break; + } + case kValueFloat: { + val = GetUVal(data, valueArg); + // fill 0s for least significant bits + element.SetU64Val(val << ((3 - valueArg) << 3)); + cst = mp.New(element.GetFloatVal(), *GlobalTables::GetTypeTable().GetFloat()); + break; + } + case kValueDouble: { + val = GetUVal(data, valueArg); + // fill 0s for least significant bits + element.SetU64Val(val << ((7 - valueArg) << 3)); + cst = mp.New(element.GetDoubleVal(), *GlobalTables::GetTypeTable().GetDouble()); + break; + } + case kValueString: { + cst = ProcessAnnotationEncodedValueInternalProcessStringValue(data, element, valueArg); + break; + } + case kValueMethodType: { + element.SetU64Val(0xdeadbeef); + break; + } + case kValueType: { + ProcessAnnotationEncodedValueInternalProcessTypeValue(data, element, valueArg); + break; + } + case kValueMethodHandle: { + element.SetU64Val(0xdeadbeef); + break; + } + case kValueEnum: + // should fallthrough + [[fallthrough]]; + case kValueField: { + ProcessAnnotationEncodedValueInternalProcessFieldValue(data, element, valueArg); + break; + } + case kValueMethod: { + ProcessAnnotationEncodedValueInternalProcessMethodValue(data, element, valueArg); + break; + } + case kValueArray: { + CHECK_FATAL(!valueArg, "value_arg != 0"); + cst = ProcessAnnotationEncodedValueInternalProcessArrayValue(data, element); + break; + } + case kValueAnnotation: { + CHECK_FATAL(!valueArg, "value_arg != 0"); + ProcessAnnotationEncodedValueInternalProcessAnnotationValue(data, element); + break; + } + case kValueNull: { + CHECK_FATAL(!valueArg, "value_arg != 0"); + element.SetU64Val(0); + cst = mp.New(0, *GlobalTables::GetTypeTable().GetInt8()); + break; + } + case kValueBoolean: { + element.SetU64Val(valueArg); + cst = mp.New(valueArg, *GlobalTables::GetTypeTable().GetInt8()); + break; + } + default: { + break; + } + } +} + +MIRIntConst *DexBCAnnotationElement::ProcessAnnotationEncodedValueInternalProcessIntValue(const uint8 **data, + MIRPragmaElement &element, + uint8 valueArg, + MIRType &type) { + // sign extended val + uint64 val = GetUVal(data, valueArg); + uint32 shiftBit = static_cast((7 - valueArg) * 8); + CHECK_FATAL(valueArg <= 7, "shiftBit positive check"); + uint64 sVal = (static_cast(val) << shiftBit) >> shiftBit; + element.SetI64Val(static_cast(sVal)); + MIRIntConst *intCst = mp.New(sVal, type); + return intCst; +} + +MIRStr16Const *DexBCAnnotationElement::ProcessAnnotationEncodedValueInternalProcessStringValue(const uint8 **data, + MIRPragmaElement &ele, + uint8 valueArg) { + uint64 val = GetUVal(data, valueArg); + std::string str = namemangler::GetOriginalNameLiteral(iDexFile.GetStringByIndex(static_cast(val))); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(str); + ele.SetU64Val(static_cast(strIdx)); + std::u16string str16; + (void)namemangler::UTF8ToUTF16(str16, str); + MIRStr16Const *strCst = mp.New(str16, *GlobalTables::GetTypeTable().GetPtr()); + return strCst; +} + +void DexBCAnnotationElement::ProcessAnnotationEncodedValueInternalProcessTypeValue(const uint8 **data, + MIRPragmaElement &element, + uint8 valueArg) { + uint64 val = GetUVal(data, valueArg); + std::string str = iDexFile.GetStringByTypeIndex(static_cast(val)); + const std::string name = namemangler::EncodeName(str); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + element.SetU64Val(static_cast(strIdx)); +} + +void DexBCAnnotationElement::ProcessAnnotationEncodedValueInternalProcessFieldValue(const uint8 **data, + MIRPragmaElement &element, + uint8 valueArg) { + uint64 val = GetUVal(data, valueArg); + const IDexFieldIdItem *fieldID = iDexFile.GetFieldIdItem(static_cast(val)); + ASSERT_NOT_NULL(fieldID); + std::string str = fieldID->GetShortFieldName(iDexFile); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(str); + element.SetU64Val(static_cast(strIdx)); +} + +void DexBCAnnotationElement::ProcessAnnotationEncodedValueInternalProcessMethodValue(const uint8 **data, + MIRPragmaElement &element, + uint8 valueArg) { + uint64 val = GetUVal(data, valueArg); + const IDexMethodIdItem *methodID = iDexFile.GetMethodIdItem(static_cast(val)); + ASSERT_NOT_NULL(methodID); + std::string fullName = std::string(methodID->GetDefiningClassName(iDexFile)) + "|" + + methodID->GetShortMethodName(iDexFile) + "|" + + methodID->GetDescriptor(iDexFile); + std::string funcName = namemangler::EncodeName(fullName); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcName); + element.SetU64Val(static_cast(strIdx)); +} + +MIRAggConst *DexBCAnnotationElement::ProcessAnnotationEncodedValueInternalProcessArrayValue(const uint8 **data, + MIRPragmaElement &element) { + unsigned arraySize = iDexFile.ReadUnsignedLeb128(data); + uint64 dataVal = *(*data); + uint8 newValueType = dataVal & 0x1f; + MIRType *elemType = GetTypeFromValueType(static_cast(newValueType)); + MIRType *arrayTypeWithSize = GlobalTables::GetTypeTable().GetOrCreateArrayType(*elemType, 1, &arraySize); + MIRAggConst *aggCst = module.GetMemPool()->New(module, *arrayTypeWithSize); + for (unsigned int i = 0; i < arraySize; ++i) { + MIRPragmaElement *subElement = mp.New(module); + MIRConst *mirConst = nullptr; + ProcessAnnotationEncodedValue(data, *subElement, mirConst); + element.SubElemVecPushBack(subElement); + aggCst->PushBack(mirConst); + } + return aggCst; +} + +void DexBCAnnotationElement::ProcessAnnotationEncodedValueInternalProcessAnnotationValue(const uint8 **data, + MIRPragmaElement &element) { + unsigned typeIdx = iDexFile.ReadUnsignedLeb128(data); + std::string str = iDexFile.GetStringByTypeIndex(typeIdx); + const std::string name = namemangler::EncodeName(str); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + element.SetTypeStrIdx(strIdx); + unsigned annoSize = iDexFile.ReadUnsignedLeb128(data); + MIRConst *mirConst = nullptr; + for (unsigned int i = 0; i < annoSize; ++i) { + MIRPragmaElement *subElement = mp.New(module); + unsigned nameIdx = iDexFile.ReadUnsignedLeb128(data); + str = iDexFile.GetStringByIndex(nameIdx); + strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(str); + subElement->SetNameStrIdx(strIdx); + ProcessAnnotationEncodedValue(data, *subElement, mirConst); + element.SubElemVecPushBack(subElement); + } +} + +MIRType *DexBCAnnotationElement::GetTypeFromValueType(PragmaValueType valueType) { + switch (valueType) { + case kValueBoolean: + return GlobalTables::GetTypeTable().GetInt8(); + case kValueByte: + return GlobalTables::GetTypeTable().GetInt8(); + case kValueShort: + return GlobalTables::GetTypeTable().GetInt16(); + case kValueChar: + return GlobalTables::GetTypeTable().GetUInt16(); + case kValueInt: + return GlobalTables::GetTypeTable().GetInt32(); + case kValueLong: + return GlobalTables::GetTypeTable().GetInt64(); + case kValueFloat: + return GlobalTables::GetTypeTable().GetFloat(); + case kValueDouble: + return GlobalTables::GetTypeTable().GetDouble(); + default: + return GlobalTables::GetTypeTable().GetPtr(); + } +} + +// ---------- DexBCAnnotation ---------- +MIRPragma *DexBCAnnotation::EmitPragma(PragmaKind kind, const GStrIdx &pragIdx, int32 paramNum, const TyIdx &tyIdxEx) { + uint8 visibility = iDexAnnotation->GetVisibility(); + const uint8 *annotationData = iDexAnnotation->GetAnnotationData(); + uint32 typeIdx = iDexFile.ReadUnsignedLeb128(&annotationData); + std::string className = namemangler::EncodeName(iDexFile.GetStringByTypeIndex(typeIdx)); + className = ArkAnnotationMap::GetArkAnnotationMap().GetAnnotationTypeName(className); + bool isCreate = false; + MIRStructType *structType = + FEManager::GetTypeManager().GetOrCreateClassOrInterfaceType(className, false, FETypeFlag::kSrcUnknown, isCreate); + MIRPragma *pragma = mp.New(module); + pragma->SetKind(kind); + pragma->SetStrIdx(pragIdx); + pragma->SetTyIdx(structType->GetTypeIndex()); + pragma->SetTyIdxEx(tyIdxEx); + pragma->SetVisibility(visibility); + pragma->SetParamNum(paramNum); + uint32 size = iDexFile.ReadUnsignedLeb128(&annotationData); + while (size-- != 0) { + DexBCAnnotationElement dexBCAnnotationElement(module, mp, iDexFile, &annotationData); + MIRPragmaElement *element = dexBCAnnotationElement.EmitPragmaElement(); + pragma->PushElementVector(element); + } + return pragma; +} + +// ---------- DexBCAnnotationSet ---------- +void DexBCAnnotationSet::Init() { + std::vector iDexAnnotations; + iDexAnnotationSet->GetAnnotations(iDexFile, iDexAnnotations); + for (uint32 i = 0; i < iDexAnnotations.size(); i++) { + const IDexAnnotation *iDexAnnotation = iDexAnnotations[i]; + std::unique_ptr annotation = std::make_unique(module, mp, iDexFile, + iDexAnnotation); + annotations.push_back(std::move(annotation)); + } +} + +std::vector &DexBCAnnotationSet::EmitPragmas(PragmaKind kind, const GStrIdx &pragIdx, int32 paramNum, + const TyIdx &tyIdxEx) { + pragmas.clear(); + for (const std::unique_ptr &annotation : annotations) { + MIRPragma *pragma = annotation->EmitPragma(kind, pragIdx, paramNum, tyIdxEx); + pragmas.push_back(pragma); + } + return pragmas; +} + +// ---------- DexBCAnnotationSetList ---------- +void DexBCAnnotationSetList::Init() { + std::vector iDexAnnotationSets; + iDexAnnotationSetList->GetAnnotationSets(iDexFile, iDexAnnotationSets); + for (uint32 i = 0; i < iDexAnnotationSets.size(); i++) { + const IDexAnnotationSet *iDexAnnotationSet = iDexAnnotationSets[i]; + std::unique_ptr annotationSet = std::make_unique(module, mp, iDexFile, + iDexAnnotationSet); + annotationSets.push_back(std::move(annotationSet)); + } +} + +std::vector &DexBCAnnotationSetList::EmitPragmas(PragmaKind kind, const GStrIdx &pragIdx) { + pragmas.clear(); + for (uint32 i = 0; i < annotationSets.size(); i++) { + const std::unique_ptr &annotationSet = annotationSets[i]; + if (annotationSet->IsValid()) { + std::vector &innerPragmas = annotationSet->EmitPragmas(kind, pragIdx, static_cast(i)); + for (MIRPragma *pragma : innerPragmas) { + pragmas.push_back(pragma); + } + } + } + return pragmas; +} + +// ---------- DexBCFieldAnnotations ---------- +void DexBCFieldAnnotations::Init() { + const IDexAnnotationSet *iDexAnnotationSet = iDexFieldAnnotations->GetAnnotationSet(iDexFile); + annotationSet = std::make_unique(module, mp, iDexFile, iDexAnnotationSet); +} + +std::vector &DexBCFieldAnnotations::EmitPragmas() { + const IDexFieldIdItem *fieldID = iDexFieldAnnotations->GetFieldIdItem(iDexFile); + const std::string &fieldTypeName = namemangler::EncodeName(fieldID->GetFieldTypeName(iDexFile)); + MIRType *fieldType = FEManager::GetTypeManager().GetOrCreateTypeFromName(fieldTypeName, FETypeFlag::kSrcUnknown, + true); + CHECK_NULL_FATAL(fieldType); + uint64 mapIdx = (static_cast(iDexFile.GetFileIdx()) << 32) | iDexFieldAnnotations->GetFieldIdx(); + StructElemNameIdx *structElemNameIdx = FEManager::GetManager().GetFieldStructElemNameIdx(mapIdx); + ASSERT(structElemNameIdx != nullptr, "structElemNameIdx is nullptr."); + std::vector &pragmas = + annotationSet->EmitPragmas(kPragmaVar, structElemNameIdx->elem, -1, fieldType->GetTypeIndex()); + if (FEOptions::GetInstance().IsRC()) { + RCSetter::GetRCSetter().ProcessFieldRCAnnotation(*structElemNameIdx, *fieldType, pragmas); + } + return pragmas; +} + +// ---------- DexBCMethodAnnotations ---------- +void DexBCMethodAnnotations::Init() { + const IDexAnnotationSet *iDexAnnotationSet = iDexMethodAnnotations->GetAnnotationSet(iDexFile); + annotationSet = std::make_unique(module, mp, iDexFile, iDexAnnotationSet); +} + +std::vector &DexBCMethodAnnotations::EmitPragmas() { + methodID = iDexMethodAnnotations->GetMethodIdItem(iDexFile); + uint64 mapIdx = (static_cast(iDexFile.GetFileIdx()) << 32) | iDexMethodAnnotations->GetMethodIdx(); + StructElemNameIdx *structElemNameIdx = FEManager::GetManager().GetMethodStructElemNameIdx(mapIdx); + ASSERT(structElemNameIdx != nullptr, "structElemNameIdx is nullptr."); + methodFullNameStrIdx = structElemNameIdx->full; + pragmasPtr = &(annotationSet->EmitPragmas(kPragmaFunc, methodFullNameStrIdx)); + if (pragmasPtr->size() > 0) { + SetupFuncAttrs(); + } + return *pragmasPtr; +} + +void DexBCMethodAnnotations::SetupFuncAttrs() { + MIRFunction *func = GetMIRFunction(methodFullNameStrIdx); + CHECK_NULL_FATAL(func); + for (MIRPragma *pragma : *pragmasPtr) { + SetupFuncAttrWithPragma(*func, *pragma); + } +} + +void DexBCMethodAnnotations::SetupFuncAttrWithPragma(MIRFunction &mirFunc, const MIRPragma &pragma) { + FuncAttrKind attr; + bool isAttrSet = true; + if (ArkAnnotation::GetInstance().IsFastNative(pragma.GetTyIdx())) { + attr = FUNCATTR_fast_native; + } else if (ArkAnnotation::GetInstance().IsCriticalNative(pragma.GetTyIdx())) { + attr = FUNCATTR_critical_native; + } else if (ArkAnnotation::GetInstance().IsCallerSensitive(pragma.GetTyIdx())) { + attr = FUNCATTR_callersensitive; + } else if (FEOptions::GetInstance().IsRC() && + (ArkAnnotation::GetInstance().IsRCUnownedLocal(pragma.GetTyIdx()) || + (ArkAnnotation::GetInstance().IsRCUnownedLocalOld(pragma.GetTyIdx()) && + pragma.GetElementVector().empty()))) { + attr = FUNCATTR_rclocalunowned; + RCSetter::GetRCSetter().CollectUnownedLocalFuncs(&mirFunc); + } else { + isAttrSet = false; // empty, for codedex cleanup + } + const char *definingClassName = methodID->GetDefiningClassName(iDexFile); + std::string mplClassName = namemangler::EncodeName(definingClassName); + MIRStructType *currStructType = FEManager::GetTypeManager().GetStructTypeFromName(mplClassName); + if (isAttrSet) { + mirFunc.SetAttr(attr); + // update method attribute in structure type as well + for (auto &mit : currStructType->GetMethods()) { + if (mit.first == mirFunc.GetStIdx()) { + mit.second.second.SetAttr(attr); + break; + } + } + } + if (FEOptions::GetInstance().IsRC()) { + RCSetter::GetRCSetter().ProcessMethodRCAnnotation(mirFunc, mplClassName, *currStructType, pragma); + } +} + +MIRFunction *DexBCMethodAnnotations::GetMIRFunction(const GStrIdx &nameIdx) const { + MIRFunction *func = nullptr; + bool isStatic = true; + func = FEManager::GetTypeManager().GetMIRFunction(nameIdx, isStatic); + if (func != nullptr) { + return func; + } + isStatic = false; + func = FEManager::GetTypeManager().GetMIRFunction(nameIdx, isStatic); + return func; +} + +// ---------- DexBCParameterAnnotations ---------- +void DexBCParameterAnnotations::Init() { + if (iDexParameterAnnotations == nullptr) { + return; + } + const IDexAnnotationSetList *iDexAnnotationSetList = iDexParameterAnnotations->GetAnnotationSetList(iDexFile); + if (iDexAnnotationSetList == nullptr) { + return; + } + annotationSetList = std::make_unique(module, mp, iDexFile, iDexAnnotationSetList); +} + +std::vector &DexBCParameterAnnotations::EmitPragmas() { + pragmas.clear(); + if (annotationSetList == nullptr) { + return pragmas; + } + uint64 mapIdx = (static_cast(iDexFile.GetFileIdx()) << 32) | iDexParameterAnnotations->GetMethodIdx(); + StructElemNameIdx *structElemNameIdx = FEManager::GetManager().GetMethodStructElemNameIdx(mapIdx); + ASSERT(structElemNameIdx != nullptr, "structElemNameIdx is nullptr."); + return annotationSetList->EmitPragmas(kPragmaParam, structElemNameIdx->full); +} + +// ---------- DexBCAnnotationsDirectory ---------- +void DexBCAnnotationsDirectory::Init() { + if (iDexAnnotationsDirectory == nullptr) { + return; + } + if (iDexAnnotationsDirectory->HasClassAnnotationSet(iDexFile)) { + classAnnotationSet = std::make_unique(module, mp, iDexFile, + iDexAnnotationsDirectory->GetClassAnnotationSet(iDexFile)); + } + if (iDexAnnotationsDirectory->HasFieldAnnotationsItems(iDexFile)) { + std::vector iDexFieldAnnotationsItems; + iDexAnnotationsDirectory->GetFieldAnnotationsItems(iDexFile, iDexFieldAnnotationsItems); + for (const IDexFieldAnnotations* iDexFieldAnnotations : iDexFieldAnnotationsItems) { + std::unique_ptr fieldAnnotations = + std::make_unique(module, mp, iDexFile, iDexFieldAnnotations); + fieldAnnotationsItems.push_back(std::move(fieldAnnotations)); + } + } + if (iDexAnnotationsDirectory->HasMethodAnnotationsItems(iDexFile)) { + std::vector iDexMethodAnnotationsItems; + iDexAnnotationsDirectory->GetMethodAnnotationsItems(iDexFile, iDexMethodAnnotationsItems); + for (const IDexMethodAnnotations *iDexMethodAnnotations : iDexMethodAnnotationsItems) { + std::unique_ptr methodAnnotations = + std::make_unique(module, mp, iDexFile, iDexMethodAnnotations); + methodAnnotationsItems.push_back(std::move(methodAnnotations)); + } + } + if (iDexAnnotationsDirectory->HasParameterAnnotationsItems(iDexFile)) { + std::vector iDexParameterAnnotationsItems; + iDexAnnotationsDirectory->GetParameterAnnotationsItems(iDexFile, iDexParameterAnnotationsItems); + for (const IDexParameterAnnotations *iDexParameterAnnotations : iDexParameterAnnotationsItems) { + std::unique_ptr parameterAnnotations = + std::make_unique(module, mp, iDexFile, iDexParameterAnnotations); + parameterAnnotationsItems.push_back(std::move(parameterAnnotations)); + } + } +} + +std::vector &DexBCAnnotationsDirectory::EmitPragmasImpl() { + pragmas.clear(); + if (iDexAnnotationsDirectory == nullptr) { + return pragmas; + } + std::vector pragmasInner; + if (classAnnotationSet != nullptr) { + const GStrIdx &strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(className)); + pragmasInner = classAnnotationSet->EmitPragmas(kPragmaClass, strIdx); + if (FEOptions::GetInstance().IsRC()) { + RCSetter::GetRCSetter().ProcessClassRCAnnotation(strIdx, pragmasInner); + } + pragmas.insert(pragmas.end(), pragmasInner.begin(), pragmasInner.end()); + } + for (const std::unique_ptr &fieldAnnotations : fieldAnnotationsItems) { + pragmasInner = fieldAnnotations->EmitPragmas(); + pragmas.insert(pragmas.end(), pragmasInner.begin(), pragmasInner.end()); + } + for (const std::unique_ptr &methodAnnotations : methodAnnotationsItems) { + pragmasInner = methodAnnotations->EmitPragmas(); + pragmas.insert(pragmas.end(), pragmasInner.begin(), pragmasInner.end()); + } + for (const std::unique_ptr ¶meterAnnotations : parameterAnnotationsItems) { + pragmasInner = parameterAnnotations->EmitPragmas(); + pragmas.insert(pragmas.end(), pragmasInner.begin(), pragmasInner.end()); + } + return pragmas; +} +} // namespace bc +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/src/dex_reader.cpp b/src/hir2mpl/bytecode_input/dex/src/dex_reader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2d075b6f384997e35d3b71f74825a46caa37192 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dex_reader.cpp @@ -0,0 +1,406 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dex_reader.h" +#include "dexfile_factory.h" +#include "mpl_logging.h" +#include "dex_file_util.h" +#include "dex_op.h" +#include "dex_class.h" +#include "fe_utils_java.h" + +namespace maple { +namespace bc { +bool DexReader::OpenAndMapImpl() { + DexFileFactory dexFileFactory; + iDexFile = dexFileFactory.NewInstance(); + bool openResult = iDexFile->Open(fileName); + if (!openResult) { + ERR(kLncErr, "Failed to open dex file %s", fileName.c_str()); + return false; + } + iDexFile->SetFileIdx(fileIdx); + irSrcFileSignature = iDexFile->GetHeader()->GetSignature(); + return true; +} + +void DexReader::SetDexFile(std::unique_ptr iDexFileIn) { + iDexFile = std::move(iDexFileIn); +} + +uint32 DexReader::GetClassItemsSize() const { + return iDexFile->GetClassItemsSize(); +} + +const char *DexReader::GetClassJavaSourceFileName(uint32 classIdx) const { + return iDexFile->GetClassItem(classIdx)->GetJavaSourceFileName(GetIDexFile()); +} + +bool DexReader::IsInterface(uint32 classIdx) const { + return iDexFile->GetClassItem(classIdx)->IsInterface(); +} + +uint32 DexReader::GetClassAccFlag(uint32 classIdx) const { + return iDexFile->GetClassItem(classIdx)->GetAccessFlags(); +} + +std::string DexReader::GetClassName(uint32 classIdx) const { + const char *className = iDexFile->GetClassItem(classIdx)->GetClassName(GetIDexFile()); + CHECK_FATAL(className != nullptr, "class name of classItem: %u is empty.", classIdx); + return className; +} + +std::list DexReader::GetSuperClasses(uint32 classIdx, bool mapled) const { + const char *super = iDexFile->GetClassItem(classIdx)->GetSuperClassName(GetIDexFile()); + std::list superClasses; + if (super != nullptr) { + superClasses.emplace_back(mapled ? namemangler::EncodeName(super) : super); + } + return superClasses; +} + +std::vector DexReader::GetClassInterfaceNames(uint32 classIdx, bool mapled) const { + std::vector names; + iDexFile->GetClassItem(classIdx)->GetInterfaceNames(GetIDexFile(), names); + std::vector ret; + for (auto name : names) { + if (name != nullptr) { + ret.push_back(mapled ? namemangler::EncodeName(name) : name); + } + } + return ret; +} + +std::string DexReader::GetClassFieldName(uint32 fieldIdx, bool mapled) const { + const IDexFieldIdItem *fieldIdItem = iDexFile->GetFieldIdItem(fieldIdx); + const char *name = iDexFile->GetStringByIndex(fieldIdItem->GetNameIdx()); + return (mapled && name != nullptr) ? namemangler::EncodeName(name) : (name != nullptr ? name : ""); +} + +std::string DexReader::GetClassFieldTypeName(uint32 fieldIdx, bool mapled) const { + const IDexFieldIdItem *fieldIdItem = iDexFile->GetFieldIdItem(fieldIdx); + const char *name = fieldIdItem->GetFieldTypeName(GetIDexFile()); + return (mapled && name != nullptr) ? namemangler::EncodeName(name) : (name != nullptr ? name : ""); +} + +std::string DexReader::GetClassMethodName(uint32 methodIdx, bool mapled) const { + const IDexMethodIdItem *methodIdItem = iDexFile->GetMethodIdItem(methodIdx); + const char *name = iDexFile->GetStringByIndex(methodIdItem->GetNameIdx()); + return (mapled && name != nullptr) ? namemangler::EncodeName(name) : (name != nullptr ? name : ""); +} + +std::string DexReader::GetClassMethodDescName(uint32 methodIdx, bool mapled) const { + const IDexMethodIdItem *methodIdItem = iDexFile->GetMethodIdItem(methodIdx); + const std::string name = iDexFile->GetProtoIdItem(methodIdItem->GetProtoIdx())->GetDescriptor(GetIDexFile()); + return mapled ? namemangler::EncodeName(name) : name; +} + +std::string DexReader::GetStringFromIdxImpl(uint32 idx) const { + const char *str = iDexFile->GetStringByIndex(idx); + return str == nullptr ? "" : str; +} + +std::string DexReader::GetTypeNameFromIdxImpl(uint32 idx) const { + const char *str = iDexFile->GetStringByTypeIndex(idx); + return str == nullptr ? "" : str; +} + +BCReader::ClassElem DexReader::GetClassFieldFromIdxImpl(uint32 idx) const { + ClassElem elem; + const char *name = iDexFile->GetFieldIdItem(idx)->GetDefiningClassName(GetIDexFile()); + CHECK_FATAL(name != nullptr, "Failed: field class name is empty."); + elem.className = name; + name = iDexFile->GetFieldIdItem(idx)->GetShortFieldName(GetIDexFile()); + CHECK_FATAL(name != nullptr, "Failed: field name is empty."); + elem.elemName = name; + name = iDexFile->GetFieldIdItem(idx)->GetFieldTypeName(GetIDexFile()); + CHECK_FATAL(name != nullptr, "Failed: field type name is empty."); + elem.typeName = name; + return elem; +} + +std::unordered_map DexReader::GetDefiningClassNameTypeIdMap() const { + return iDexFile->GetDefiningClassNameTypeIdMap(); +} + +const uint16 *DexReader::GetMethodInstOffset(const IDexMethodItem* dexMethodItem) const { + return dexMethodItem->GetInsnsByOffset(*iDexFile, 0); +} + +uint16 DexReader::GetClassMethodRegisterTotalSize(const IDexMethodItem* dexMethodItem) const { + return dexMethodItem->GetRegistersSize(*iDexFile); +} + +uint16 DexReader::GetClassMethodRegisterInSize(const IDexMethodItem* dexMethodItem) const { + return dexMethodItem->GetInsSize(*iDexFile); +} + +uint32 DexReader::GetCodeOff(const IDexMethodItem* dexMethodItem) const { + return dexMethodItem->GetCodeOff(); +} + +BCReader::ClassElem DexReader::GetClassMethodFromIdxImpl(uint32 idx) const { + ClassElem elem; + const char *name = iDexFile->GetMethodIdItem(idx)->GetDefiningClassName(GetIDexFile()); + CHECK_FATAL(name != nullptr, "Failed: field class name is empty."); + elem.className = name; + name = iDexFile->GetMethodIdItem(idx)->GetShortMethodName(GetIDexFile()); + CHECK_FATAL(name != nullptr, "Failed: field name is empty."); + elem.elemName = name; + elem.typeName = iDexFile->GetMethodIdItem(idx)->GetDescriptor(GetIDexFile()); + return elem; +} + +std::string DexReader::GetSignatureImpl(uint32 idx) const { + return iDexFile->GetProtoIdItem(idx)->GetDescriptor(GetIDexFile()); +} + +uint32 DexReader::GetFileIndexImpl() const { + return iDexFile->GetFileIdx(); +} + +void DexReader::ResovleSrcPositionInfo( + const IDexMethodItem* dexMethodItem, + std::map &srcPosInfo) const { + dexMethodItem->GetSrcPositionInfo(GetIDexFile(), srcPosInfo); +} + + +std::unique_ptr DexReader::ResovleSrcLocalInfo(const IDexMethodItem &dexMethodItem) const { + auto srcLocals = std::make_unique(); + dexMethodItem.GetSrcLocalInfo(GetIDexFile(), *srcLocals); + return srcLocals; +} + +MapleMap *DexReader::ResolveInstructions( + MapleAllocator &allocator, const IDexMethodItem* dexMethodItem, bool mapled) const { + (void) mapled; + std::map> pcInstMap; + dexMethodItem->GetPCInstructionMap(GetIDexFile(), pcInstMap); + return ConstructBCPCInstructionMap(allocator, pcInstMap); +} + +MapleMap *DexReader::ConstructBCPCInstructionMap( + MapleAllocator &allocator, const std::map> &pcInstMap) const { + MapleMap *pcBCInstMap = + allocator.GetMemPool()->New>(allocator.Adapter()); + for (const auto &pcInst : pcInstMap) { + pcBCInstMap->emplace(pcInst.first, ConstructBCInstruction(allocator, pcInst)); + } + return pcBCInstMap; +} + +BCInstruction *DexReader::ConstructBCInstruction( + MapleAllocator &allocator, const std::pair> &p) const { + auto dexOp = + static_cast(dexOpGeneratorMap[static_cast(p.second.get()->GetOpcode())](allocator, p.first)); + dexOp->SetVA(GetVA(p.second.get())); + dexOp->SetVB(GetVB(p.second.get())); + dexOp->SetWideVB(GetWideVB(p.second.get())); + MapleList vRegs(allocator.Adapter()); + GetArgVRegs(p.second.get(), vRegs); + dexOp->SetArgs(vRegs); + dexOp->SetVC(GetVC(p.second.get())); + dexOp->SetVH(GetVH(p.second.get())); + dexOp->SetWidth(GetWidth(p.second.get())); + dexOp->SetOpName(GetOpName(p.second.get())); + return dexOp; +} + +uint32 DexReader::GetVA(const IDexInstruction *inst) const { + return inst->GetVRegA(); +} + +uint32 DexReader::GetVB(const IDexInstruction *inst) const { + return inst->GetVRegB(); +} + +uint64 DexReader::GetWideVB(const IDexInstruction *inst) const { + return inst->GetVRegBWide(); +} + +uint32 DexReader::GetVC(const IDexInstruction *inst) const { + return inst->GetVRegC(); +} + +void DexReader::GetArgVRegs(const IDexInstruction *inst, MapleList &vRegs) const { + if (inst->GetOpcode() == kOpFilledNewArray || + (kOpInvokeVirtual <= inst->GetOpcode() && inst->GetOpcode() <= kOpInvokeInterface) || + inst->GetOpcode() == kOpInvokePolymorphic || + inst->GetOpcode() == kOpInvokeCustom) { + for (uint32 i = 0; i < inst->GetVRegA(); ++i) { + vRegs.push_back(inst->GetArg(i)); + } + } else if (inst->GetOpcode() == kOpFilledNewArrayRange || + (kOpInvokeVirtualRange <= inst->GetOpcode() && inst->GetOpcode() <= kOpInvokeInterfaceRange) || + inst->GetOpcode() == kOpInvokePolymorphicRange || + inst->GetOpcode() == kOpInvokeCustomRange) { + for (uint32 i = 0; i < inst->GetVRegA(); ++i) { + vRegs.push_back(inst->GetVRegC() + i); + } + } +} + +uint32 DexReader::GetVH(const IDexInstruction *inst) const { + return inst->GetVRegH(); +} + +uint8 DexReader::GetWidth(const IDexInstruction *inst) const { + return inst->GetWidth(); +} + +const char *DexReader::GetOpName(const IDexInstruction *inst) const { + return inst->GetOpcodeName(); +} + +std::unique_ptr>> DexReader::ResolveTryInfos( + const IDexMethodItem* dexMethodItem) const { + std::vector tryItems; + dexMethodItem->GetTryItems(GetIDexFile(), tryItems); + uint32 codeOff = dexMethodItem->GetCodeOff(); + return ConstructBCTryInfoList(codeOff, tryItems); +} + +std::unique_ptr>> DexReader::ConstructBCTryInfoList( + uint32 codeOff, const std::vector &tryItems) const { + auto tryInfos = + std::make_unique>>(); + std::list> info; + for (const auto *tryItem : tryItems) { + std::vector dexCatchItems; + tryItem->GetCatchHandlerItems(GetIDexFile(), codeOff, dexCatchItems); + std::unique_ptr tryInfo = std::make_unique( + tryItem->GetStartAddr(), + tryItem->GetEndAddr(), + ConstructBCCatchList(dexCatchItems)); + tryInfos->push_back(std::move(tryInfo)); + info.push_back(std::move(tryInfo)); + } + return tryInfos; +} + +std::unique_ptr>> DexReader::ConstructBCCatchList( + std::vector &catchHandlerItems) const { + std::unique_ptr>> catches = + std::make_unique>>(); + for (const auto catchHandlerItem : catchHandlerItems) { + // Use V (void) catch exceptions + GStrIdx exceptionNameIdx = catchHandlerItem.IsCatchAllHandlerType() ? BCUtil::GetVoidIdx() : + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::EncodeName(iDexFile->GetStringByTypeIndex(catchHandlerItem.GetHandlerTypeIdx()))); + std::unique_ptr catchInfo = std::make_unique( + catchHandlerItem.GetHandlerAddress(), + exceptionNameIdx, + catchHandlerItem.IsCatchAllHandlerType()); + catches->push_back(std::move(catchInfo)); + } + return catches; +} + +bool DexReader::ReadAllDepTypeNames(std::unordered_set &depSet) { + for (uint32 i = 0; i < iDexFile->GetHeader()->GetTypeIdsSize(); ++i) { + std::string typeName = iDexFile->GetStringByTypeIndex(i); + std::string trimmedTypeName = BCUtil::TrimArrayModifier(typeName); + if (trimmedTypeName.size() != 0 && trimmedTypeName[0] == 'L') { + depSet.insert(trimmedTypeName); + } + } + return true; +} + +bool DexReader::ReadAllClassNames(std::unordered_set &classSet) const { + for (uint32 classIdx = 0; classIdx < iDexFile->GetClassItemsSize(); ++classIdx) { + const IDexClassItem *classItem = iDexFile->GetClassItem(classIdx); + classSet.emplace(classItem->GetClassName(GetIDexFile())); + } + return true; +} + +bool DexReader::ReadMethodDepTypeNames(std::unordered_set &depSet, + uint32 classIdx, uint32 methodItemx, bool isVirtual) const { + std::unique_ptr method; + if (isVirtual) { + method = iDexFile->GetClassItem(classIdx)->GetVirtualMethod(*iDexFile, methodItemx); + } else { + method = iDexFile->GetClassItem(classIdx)->GetDirectMethod(*iDexFile, methodItemx); + } + CHECK_NULL_FATAL(method.get()); + std::map> pcInstMap; + method->GetPCInstructionMap(GetIDexFile(), pcInstMap); + for (const auto &pcInst : pcInstMap) { + const std::unique_ptr &inst = pcInst.second; + IDexOpcode op = inst->GetOpcode(); + if (op >= kOpIget && op <= kOpIputShort) { + // field operation + const char *className = iDexFile->GetFieldIdItem(inst->GetVRegC())->GetDefiningClassName(GetIDexFile()); + CHECK_FATAL(className != nullptr, "field class name is empty."); + AddDepTypeName(depSet, className, false); + } else if (op >= kOpSget && op <= kOpSputShort) { + // field operation + const char *className = iDexFile->GetFieldIdItem(inst->GetVRegB())->GetDefiningClassName(GetIDexFile()); + CHECK_FATAL(className != nullptr, "field class name is empty."); + AddDepTypeName(depSet, className, false); + } else if (op >= kOpInvokeVirtual && op <= kOpInvokeInterfaceRange) { + // invoke inst + const IDexMethodIdItem *methodIdTmp = iDexFile->GetMethodIdItem(inst->GetVRegB()); + const char *className = methodIdTmp->GetDefiningClassName(GetIDexFile()); + CHECK_FATAL(className != nullptr, "method class name is empty."); + AddDepTypeName(depSet, className, true); + const std::string &typeName = methodIdTmp->GetDescriptor(GetIDexFile()); + std::vector retArgsTypeNames = FEUtilJava::SolveMethodSignature(typeName); + for (const std::string &item : retArgsTypeNames) { + AddDepTypeName(depSet, item, true); + } + } else if (op == kOpConstClass || op == kOpCheckCast || op == kOpFilledNewArray || op == kOpFilledNewArrayRange) { + AddDepTypeName(depSet, iDexFile->GetStringByTypeIndex(inst->GetVRegB()), true); + } else if (op == kOpInstanceOf || op == kOpNewArray) { + AddDepTypeName(depSet, iDexFile->GetStringByTypeIndex(inst->GetVRegC()), true); + } else if (op == kOpNewInstance) { + AddDepTypeName(depSet, iDexFile->GetStringByTypeIndex(inst->GetVRegB()), false); + } + ReadMethodTryCatchDepTypeNames(depSet, *method); + } + return true; +} + +void DexReader::ReadMethodTryCatchDepTypeNames(std::unordered_set &depSet, + const IDexMethodItem &method) const { + uint32 tryNum = method.GetTriesSize(GetIDexFile()); + if (tryNum == 0) { + return; + } + std::vector tryItems; + method.GetTryItems(GetIDexFile(), tryItems); + uint32 codeOff = method.GetCodeOff(); + for (const auto tryItem : tryItems) { + std::vector dexCatchItems; + tryItem->GetCatchHandlerItems(GetIDexFile(), codeOff, dexCatchItems); + for (const auto &handler: dexCatchItems) { + if (!handler.IsCatchAllHandlerType()) { + uint32 typeIdx = handler.GetHandlerTypeIdx(); + AddDepTypeName(depSet, iDexFile->GetStringByTypeIndex(typeIdx), false); + } + } + } +} + +void DexReader::AddDepTypeName(std::unordered_set &depSet, + const std::string &typeName, bool isTrim) const { + const std::string &trimmedTypeName = isTrim ? BCUtil::TrimArrayModifier(typeName) : typeName; + if (trimmedTypeName.size() != 0 && trimmedTypeName[0] == 'L') { + depSet.insert(trimmedTypeName); + } +} +} // namespace bc +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/dex/src/dex_strfac.cpp b/src/hir2mpl/bytecode_input/dex/src/dex_strfac.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87aa86bc7c32e3ddd3a54fc93db10a273af9285b --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dex_strfac.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dex_strfac.h" +#include "namemangler.h" + +namespace maple { +std::string DexStrFactory::GetStringFactoryFuncname(const std::string &funcName) { +#define STR_STRFAC_MAP2(N1, N2) \ + if (funcName.compare(N1) == 0) { \ + return N2; \ + } +#include "dex_strfac_map.def" +#undef STR_STRFAC_MAP2 + return ""; +} + +bool DexStrFactory::IsStringInit(const std::string &funcName) { + const std::string &mplName = "Ljava/lang/String;|"; + if (funcName.compare(0, mplName.length(), mplName) == 0) { + return true; + } + return false; +} +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/bytecode_input/dex/src/dexfile_factory.cpp b/src/hir2mpl/bytecode_input/dex/src/dexfile_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d292b5d3493e58a12558d7d983e957b9c4eba8d --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dexfile_factory.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dexfile_factory.h" +#include "dexfile_libdexfile.h" + +namespace maple { +std::unique_ptr DexFileFactory::NewInstance() const { + return std::make_unique(); +} +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/dex/src/dexfile_interface.cpp b/src/hir2mpl/bytecode_input/dex/src/dexfile_interface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3027b0ce7182ba0c657d0a355e66b1dc1ab9fce6 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dexfile_interface.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dexfile_interface.h" +#include "mpl_logging.h" + +namespace maple{ +void ResolvedMethodType::SignatureTypes(const std::string &mt, std::list &types) { + // three pointers linear scan algo + size_t startPos = 1; // pos 0 should be '(' + size_t currentPos = startPos; + size_t endPos = mt.find(")"); + CHECK_FATAL(endPos != std::string::npos, "(ToIDEUser)Invalid string format: %s", mt.c_str()); + CHECK_FATAL(startPos <= endPos, "(ToIDEUser)Invalid string format: %s", mt.c_str()); + while (startPos < endPos) { + switch (mt[currentPos]) { + case 'I': + case 'Z': + case 'B': + case 'C': + case 'V': + case 'S': + case 'J': + case 'F': + case 'D': { + types.push_back(namemangler::EncodeName(mt.substr(startPos, currentPos - startPos + 1))); + ++currentPos; + break; + } + case '[': + ++currentPos; + continue; + case 'L': + while (mt[currentPos++] != ';') {} // empty + types.push_back(namemangler::EncodeName(mt.substr(startPos, currentPos - startPos))); + break; + default: + std::cerr << "ResolvedMethodType: catastrophic error" << std::endl; + break; + } + startPos = currentPos; + } +} + +std::string ResolvedMethodType::SignatureReturnType(const std::string &mt) { + size_t endPos = mt.find(")"); + return namemangler::EncodeName(mt.substr(endPos + 1)); +} +} // namespace maple diff --git a/src/hir2mpl/bytecode_input/dex/src/dexfile_libdexfile.cpp b/src/hir2mpl/bytecode_input/dex/src/dexfile_libdexfile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0624909889f664fee8f4a5bb06f731c4c8561ff7 --- /dev/null +++ b/src/hir2mpl/bytecode_input/dex/src/dexfile_libdexfile.cpp @@ -0,0 +1,1704 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "dexfile_libdexfile.h" +#include +#include +#include +#include +#include +#include +#ifdef DARWIN +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "securec.h" + +std::ostream &art::operator<<(std::ostream &os, const art::Instruction::Format &format) { + switch (format) { + case art::Instruction::k10x: { + os << "k10x"; + break; + } + case art::Instruction::k12x: { + os << "k12x"; + break; + } + case art::Instruction::k11n: { + os << "k11n"; + break; + } + case art::Instruction::k11x: { + os << "k11x"; + break; + } + case art::Instruction::k10t: { + os << "k10t"; + break; + } + case art::Instruction::k20t: { + os << "k20t"; + break; + } + case art::Instruction::k22x: { + os << "k22x"; + break; + } + case art::Instruction::k21t: { + os << "k21t"; + break; + } + case art::Instruction::k21s: { + os << "k21s"; + break; + } + case art::Instruction::k21h: { + os << "k21h"; + break; + } + case art::Instruction::k21c: { + os << "k21c"; + break; + } + case art::Instruction::k23x: { + os << "k23x"; + break; + } + case art::Instruction::k22b: { + os << "k22b"; + break; + } + case art::Instruction::k22t: { + os << "k22t"; + break; + } + case art::Instruction::k22s: { + os << "k22s"; + break; + } + case art::Instruction::k22c: { + os << "k22c"; + break; + } + case art::Instruction::k32x: { + os << "k32x"; + break; + } + case art::Instruction::k30t: { + os << "k30t"; + break; + } + case art::Instruction::k31t: { + os << "k31t"; + break; + } + case art::Instruction::k31i: { + os << "k31i"; + break; + } + case art::Instruction::k31c: { + os << "k31c"; + break; + } + case art::Instruction::k35c: { + os << "k35c"; + break; + } + case art::Instruction::k3rc: { + os << "k3rc"; + break; + } + case art::Instruction::k45cc: { + os << "k45cc"; + break; + } + case art::Instruction::k4rcc: { + os << "k4rcc"; + break; + } + case art::Instruction::k51l: { + os << "k51l"; + break; + } + default: { + os << "unknown"; + } + } + return os; +} + +std::ostream &art::operator<<(std::ostream &os, const art::EncodedArrayValueIterator::ValueType &code) { + switch (code) { + case art::EncodedArrayValueIterator::ValueType::kByte: { + os << "Byte"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kShort: { + os << "Short"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kChar: { + os << "Char"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kInt: { + os << "Int"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kLong: { + os << "Long"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kFloat: { + os << "Float"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kDouble: { + os << "Double"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kMethodType: { + os << "MethodType"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kMethodHandle: { + os << "MethodHandle"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kString: { + os << "String"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kType: { + os << "Type"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kField: { + os << "Field"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kMethod: { + os << "Method"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kEnum: { + os << "Enum"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kArray: { + os << "Array"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kAnnotation: { + os << "Annotation"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kNull: { + os << "Null"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kBoolean: { + os << "Boolean"; + break; + } + default: { + os << "Unknown type (" << static_cast(code) << ")"; + } + } + return os; +} + +namespace maple { +const size_t kDexFileVersionStringLength = 3; +// =====DexInstruction start====== +DexInstruction::DexInstruction(const art::Instruction &artInstruction) + : opcode(kOpNop), + indexType(kIDexIndexUnknown), + vA(UINT32_MAX), + vB(UINT32_MAX), + vBWide(UINT32_MAX), + vC(UINT32_MAX), + vH(UINT32_MAX), + artInstruction(&artInstruction) {} + +IDexOpcode DexInstruction::GetOpcode() const { + return opcode; +} + +const char *DexInstruction::GetOpcodeName() const { + IDexOpcode iOpcode = GetOpcode(); + const art::Instruction::Code &artCode = art::Instruction::Code(static_cast(iOpcode)); + return art::Instruction::Name(artCode); +} + +uint32_t DexInstruction::GetVRegA() const { + return vA; +} + +uint32_t DexInstruction::GetVRegB() const { + return vB; +} + +uint64_t DexInstruction::GetVRegBWide() const { + return vBWide; +} + +uint32_t DexInstruction::GetVRegC() const { + return vC; +} + +uint32_t DexInstruction::GetVRegH() const { + return vH; +} + +uint32_t DexInstruction::GetArg(uint32_t index) const { + return arg[index]; +} + +IDexInstructionIndexType DexInstruction::GetIndexType() const { + return indexType; +} + +IDexInstructionFormat DexInstruction::GetFormat() const { + IDexOpcode iOpcode = GetOpcode(); + art::Instruction::Code artCode = art::Instruction::Code(static_cast(iOpcode)); + art::Instruction::Format artFormat = art::Instruction::FormatOf(artCode); + IDexInstructionFormat iFormat = static_cast(artFormat); + return iFormat; +} + +size_t DexInstruction::GetWidth() const { + return artInstruction->SizeInCodeUnits(); +} + +void DexInstruction::SetOpcode(IDexOpcode iOpCode) { + opcode = iOpCode; +} + +void DexInstruction::SetVRegB(uint32_t vRegB) { + vB = vRegB; +} + +void DexInstruction::SetVRegBWide(uint64_t vRegBWide) { + vBWide = vRegBWide; +} + +void DexInstruction::SetIndexType(IDexInstructionIndexType iIndexType) { + indexType = iIndexType; +} + +void DexInstruction::Init() { + art::Instruction::Code artCode = artInstruction->Opcode(); + opcode = static_cast(artCode); + if (artInstruction->HasVRegA()) { + vA = artInstruction->VRegA(); + } + if (artInstruction->HasVRegB() && !artInstruction->HasWideVRegB()) { + vB = artInstruction->VRegB(); + } + if (artInstruction->HasWideVRegB()) { + vBWide = artInstruction->WideVRegB(); + } + if (artInstruction->HasVRegC()) { + vC = artInstruction->VRegC(); + } + if (artInstruction->HasVRegH()) { + vH = artInstruction->VRegH(); + } + if (artInstruction->HasVarArgs()) { + (void)artInstruction->GetVarArgs(arg); + } + if ((artInstruction->Opcode() == art::Instruction::INVOKE_POLYMORPHIC) || + (artInstruction->Opcode() == art::Instruction::INVOKE_POLYMORPHIC_RANGE)) { + for (uint32_t i = 1; i < art::Instruction::kMaxVarArgRegs; i++) { + arg[i - 1] = arg[i]; + } + } + art::Instruction::IndexType artIndexType = art::Instruction::IndexTypeOf(artCode); + indexType = static_cast(artIndexType); +} + +bool DexInstruction::HasVRegA() const { + return artInstruction->HasVRegA(); +} + +bool DexInstruction::HasVRegB() const { + return artInstruction->HasVRegB(); +} + +bool DexInstruction::HasWideVRegB() const { + return artInstruction->HasWideVRegB(); +} + +bool DexInstruction::HasVRegC() const { + return artInstruction->HasVRegC(); +} + +bool DexInstruction::HasVRegH() const { + return artInstruction->HasVRegH(); +} + +bool DexInstruction::HasArgs() const { + return artInstruction->HasVarArgs(); +} +// =====DexInstruction end================ +// =====IDexCatchHandlerItem start========= +const art::DexFile *GetDexFile(const IDexFile &dexFile) { + return reinterpret_cast(dexFile.GetData()); +} + +const art::dex::ClassDef *GetClassDef(const IDexClassItem *item) { + return reinterpret_cast(item); +} + +uint32_t IDexCatchHandlerItem::GetHandlerTypeIdx() const { + return typeIdx; +} + +uint32_t IDexCatchHandlerItem::GetHandlerAddress() const { + return address; +} + +bool IDexCatchHandlerItem::IsCatchAllHandlerType() const { + return (typeIdx == art::DexFile::kDexNoIndex16); +} +// =====IDexCatchHandlerItem end=========== +// =====IDexTryItem start================== +const art::dex::TryItem *GetTryItem(const IDexTryItem *item) { + return reinterpret_cast(item); +} + +const IDexTryItem *IDexTryItem::GetInstance(const void *item) { + return reinterpret_cast(item); +} + +uint32_t IDexTryItem::GetStartAddr() const { + return GetTryItem(this)->start_addr_; +} + +uint32_t IDexTryItem::GetEndAddr() const { + return (GetTryItem(this)->start_addr_ + GetTryItem(this)->insn_count_); +} + +void IDexTryItem::GetCatchHandlerItems(const IDexFile &dexFile, uint32_t codeOff, + std::vector &items) const { + const art::dex::CodeItem *artCodeItem = GetDexFile(dexFile)->GetCodeItem(codeOff); + if (artCodeItem == nullptr) { + return; + } + art::CodeItemDataAccessor accessor(*GetDexFile(dexFile), artCodeItem); + art::CatchHandlerIterator handlerIterator(accessor, *GetTryItem(this)); + + while (handlerIterator.HasNext()) { + art::dex::TypeIndex artTypeIndex = handlerIterator.GetHandlerTypeIndex(); + uint32_t address = handlerIterator.GetHandlerAddress(); + uint16_t typeIdx = artTypeIndex.index_; + items.emplace_back(IDexCatchHandlerItem(typeIdx, address)); + handlerIterator.Next(); + } +} +// =====IDexTryItem end===================== +// =====IDexProtoIdItem start=============== +const art::dex::ProtoId *GetProtoId(const IDexProtoIdItem *item) { + return reinterpret_cast(item); +} + +const IDexProtoIdItem *GetDexProtoIdInstance(const art::DexFile &dexFile, uint32_t index) { + return reinterpret_cast(&(dexFile.GetProtoId(art::dex::ProtoIndex(index)))); +} + +const IDexProtoIdItem *IDexProtoIdItem::GetInstance(const IDexFile &dexFile, uint32_t index) { + return reinterpret_cast(&(GetDexFile(dexFile)->GetProtoId(art::dex::ProtoIndex(index)))); +} + +const char *IDexProtoIdItem::GetReturnTypeName(const IDexFile &dexFile) const { + return GetDexFile(dexFile)->GetReturnTypeDescriptor(*GetProtoId(this)); +} + +uint32_t IDexProtoIdItem::GetParameterTypeSize(const IDexFile &dexFile) const { + const art::dex::TypeList *typeList = GetDexFile(dexFile)->GetProtoParameters(*GetProtoId(this)); + if (typeList == nullptr) { + return 0; + } + return typeList->Size(); +} + +void IDexProtoIdItem::GetParameterTypeIndexes(const IDexFile &dexFile, std::vector &indexes) const { + const art::dex::TypeList *typeList = GetDexFile(dexFile)->GetProtoParameters(*GetProtoId(this)); + if (typeList == nullptr) { + return; + } + for (uint32_t i = 0; i < typeList->Size(); i++) { + uint16_t typeIndex = typeList->GetTypeItem(i).type_idx_.index_; + indexes.push_back(typeIndex); + } +} + +std::string IDexProtoIdItem::GetDescriptor(const IDexFile &dexFile) const { + std::string desc = GetDexFile(dexFile)->GetProtoSignature(*GetProtoId(this)).ToString(); + return desc; +} + +const char *IDexProtoIdItem::GetShorty(const IDexFile &dexFile) const { + return GetDexFile(dexFile)->StringDataByIdx(GetProtoId(this)->shorty_idx_); +} +// =====IDexProtoIdItem end========= +// =====IDexMethodIdItem start====== +const art::dex::MethodId *GetMethodId(const IDexMethodIdItem *item) { + return reinterpret_cast(item); +} + +const IDexMethodIdItem *IDexMethodIdItem::GetInstance(const IDexFile &dexFile, uint32_t index) { + return reinterpret_cast(&(GetDexFile(dexFile)->GetMethodId(index))); +} + +const IDexMethodIdItem *GetDexMethodIdInstance(const art::DexFile &dexFile, uint32_t index) { + return reinterpret_cast(&(dexFile.GetMethodId(index))); +} + +uint32_t IDexMethodIdItem::GetClassIdx() const { + return GetMethodId(this)->class_idx_.index_; +} + +const char *IDexMethodIdItem::GetDefiningClassName(const IDexFile &dexFile) const { + return GetDexFile(dexFile)->StringByTypeIdx(GetMethodId(this)->class_idx_); +} + +uint16_t IDexMethodIdItem::GetProtoIdx() const { + return GetMethodId(this)->proto_idx_.index_; +} + +const IDexProtoIdItem *IDexMethodIdItem::GetProtoIdItem(const IDexFile &dexFile) const { + return IDexProtoIdItem::GetInstance(dexFile, GetMethodId(this)->proto_idx_.index_); +} + +uint32_t IDexMethodIdItem::GetNameIdx() const { + return GetMethodId(this)->name_idx_.index_; +} + +const char *IDexMethodIdItem::GetShortMethodName(const IDexFile &dexFile) const { + return GetDexFile(dexFile)->StringDataByIdx(GetMethodId(this)->name_idx_); +} + +std::string IDexMethodIdItem::GetDescriptor(const IDexFile &dexFile) const { + return GetDexFile(dexFile)->GetMethodSignature(*GetMethodId(this)).ToString(); +} +// =====IDexMethodIdItem end======== +// =====IDexMethodItem start======== +const art::ClassAccessor::Method *GetMethod(const IDexMethodItem *item) { + return reinterpret_cast(item); +} + +IDexMethodItem::IDexMethodItem(uint32_t methodIdx, uint32_t accessFlags, uint32_t codeOff) + : methodIdx(methodIdx), accessFlags(accessFlags), codeOff(codeOff) {} + +uint32_t IDexMethodItem::GetMethodCodeOff(const IDexMethodItem *item) const { + (void) item; + return codeOff; +} + +uint32_t IDexMethodItem::GetMethodIdx() const { + return methodIdx; +} + +const IDexMethodIdItem *IDexMethodItem::GetMethodIdItem(const IDexFile &dexFile) const { + return IDexMethodIdItem::GetInstance(dexFile, GetMethodIdx()); +} + +uint32_t IDexMethodItem::GetAccessFlags() const { + return accessFlags; +} + +bool IDexMethodItem::HasCode(const IDexFile &dexFile) const { + art::CodeItemDataAccessor accessor(*GetDexFile(dexFile), GetDexFile(dexFile)->GetCodeItem(GetMethodCodeOff(this))); + return accessor.HasCodeItem(); +} + +uint16_t IDexMethodItem::GetRegistersSize(const IDexFile &dexFile) const { + const art::dex::CodeItem *artCodeItem = GetDexFile(dexFile)->GetCodeItem(GetMethodCodeOff(this)); + if (artCodeItem == nullptr) { + return 0; + } + art::CodeItemDataAccessor accessor(*GetDexFile(dexFile), artCodeItem); + return accessor.RegistersSize(); +} + +uint16_t IDexMethodItem::GetInsSize(const IDexFile &dexFile) const { + const art::dex::CodeItem *artCodeItem = GetDexFile(dexFile)->GetCodeItem(GetMethodCodeOff(this)); + if (artCodeItem == nullptr) { + return 0; + } + art::CodeItemDataAccessor accessor(*GetDexFile(dexFile), artCodeItem); + return accessor.InsSize(); +} + +uint16_t IDexMethodItem::GetOutsSize(const IDexFile &dexFile) const { + const art::dex::CodeItem *artCodeItem = GetDexFile(dexFile)->GetCodeItem(GetMethodCodeOff(this)); + if (artCodeItem == nullptr) { + return 0; + } + art::CodeItemDataAccessor accessor(*GetDexFile(dexFile), artCodeItem); + return accessor.OutsSize(); +} + +uint16_t IDexMethodItem::GetTriesSize(const IDexFile &dexFile) const { + const art::dex::CodeItem *artCodeItem = GetDexFile(dexFile)->GetCodeItem(GetMethodCodeOff(this)); + if (artCodeItem == nullptr) { + return 0; + } + art::CodeItemDataAccessor accessor(*GetDexFile(dexFile), artCodeItem); + return accessor.TriesSize(); +} + +uint32_t IDexMethodItem::GetInsnsSize(const IDexFile &dexFile) const { + const art::dex::CodeItem *artCodeItem = GetDexFile(dexFile)->GetCodeItem(GetMethodCodeOff(this)); + if (artCodeItem == nullptr) { + return 0; + } + art::CodeItemDataAccessor accessor(*GetDexFile(dexFile), artCodeItem); + return accessor.InsnsSizeInCodeUnits(); +} + +const uint16_t *IDexMethodItem::GetInsnsByOffset(const IDexFile &dexFile, uint32_t offset) const { + const art::dex::CodeItem *artCodeItem = GetDexFile(dexFile)->GetCodeItem(GetMethodCodeOff(this)); + if (artCodeItem == nullptr) { + return nullptr; + } + art::CodeItemDataAccessor accessor(*GetDexFile(dexFile), artCodeItem); + return (accessor.Insns() + offset); +} + +uint32_t IDexMethodItem::GetCodeOff() const { + return GetMethodCodeOff(this); +} + +bool IDexMethodItem::IsStatic() const { + bool isStatic = ((GetAccessFlags() & art::kAccStatic) > 0) ? true : false; + return isStatic; +} + +void IDexMethodItem::GetPCInstructionMap(const IDexFile &dexFile, + std::map> &pcInstructionMap) const { + const art::dex::CodeItem *artCodeItem = GetDexFile(dexFile)->GetCodeItem(GetMethodCodeOff(this)); + if (artCodeItem == nullptr) { + return; + } + std::unique_ptr artCodeItemDataAccessor = + std::make_unique(*GetDexFile(dexFile), artCodeItem); + art::CodeItemDataAccessor &accessor = *(artCodeItemDataAccessor.get()); + + for (const art::DexInstructionPcPair &pair : accessor) { + uint32_t dexPc = pair.DexPc(); + const art::Instruction &instruction = pair.Inst(); + std::unique_ptr dexInstruction = std::make_unique(instruction); + dexInstruction->Init(); + pcInstructionMap[dexPc] = std::move(dexInstruction); + } +} + +void IDexMethodItem::GetTryItems(const IDexFile &dexFile, std::vector &tryItems) const { + const art::dex::CodeItem *artCodeItem = GetDexFile(dexFile)->GetCodeItem(GetMethodCodeOff(this)); + if (artCodeItem == nullptr) { + return; + } + art::CodeItemDataAccessor accessor(*GetDexFile(dexFile), artCodeItem); + uint32_t triesSize = accessor.TriesSize(); + if (triesSize == 0) { + return; + } + const art::dex::TryItem *artTryItems = accessor.TryItems().begin(); + for (uint32_t tryIndex = 0; tryIndex < triesSize; tryIndex++) { + const art::dex::TryItem *artTry = artTryItems + tryIndex; + tryItems.push_back(IDexTryItem::GetInstance(artTry)); + } +} + +void IDexMethodItem::GetSrcPositionInfo(const IDexFile &dexFile, std::map &srcPosInfo) const { + const art::dex::CodeItem *artCodeItem = GetDexFile(dexFile)->GetCodeItem(GetMethodCodeOff(this)); + if (artCodeItem == nullptr) { + return; + } + art::CodeItemDebugInfoAccessor accessor(*GetDexFile(dexFile), artCodeItem, GetMethodIdx()); + bool succ = accessor.DecodeDebugPositionInfo([&](const art::DexFile::PositionInfo& entry) { + srcPosInfo.emplace(entry.address_, entry.line_); + return false; + }); + if (!succ) { + LOG(ERROR) << "ReadFileToString failed"; + return; + } +} + +void IDexMethodItem::GetSrcLocalInfo(const IDexFile &dexFile, + std::map>> &srcLocal) const { + const art::dex::CodeItem *artCodeItem = GetDexFile(dexFile)->GetCodeItem(GetMethodCodeOff(this)); + if (artCodeItem == nullptr) { + return; + } + art::CodeItemDebugInfoAccessor accessor(*GetDexFile(dexFile), artCodeItem, this->GetMethodIdx()); + (void)accessor.DecodeDebugLocalInfo(this->IsStatic(), this->GetMethodIdx(), + [&](const art::DexFile::LocalInfo &entry) { + if (entry.name_ != nullptr && entry.descriptor_ != nullptr) { + std::string signature = entry.signature_ != nullptr ? entry.signature_ : ""; + auto item = std::make_tuple(entry.name_, entry.descriptor_, signature); + srcLocal[entry.reg_].insert(item); + } + }); +} +// =====IDexMethodItem end========== +// =====IDexFieldIdItem start======= +const art::dex::FieldId *GetFieldId(const IDexFieldIdItem *item) { + return reinterpret_cast(item); +} + +const IDexFieldIdItem *IDexFieldIdItem::GetInstance(const IDexFile &dexFile, uint32_t index) { + return reinterpret_cast(&(GetDexFile(dexFile)->GetFieldId(index))); +} + +const IDexFieldIdItem *GetDexFieldIdInstance(const art::DexFile &dexFile, uint32_t index) { + return reinterpret_cast(&(dexFile.GetFieldId(index))); +} + +uint32_t IDexFieldIdItem::GetClassIdx() const { + return GetFieldId(this)->class_idx_.index_; +} + +const char *IDexFieldIdItem::GetDefiningClassName(const IDexFile &dexFile) const { + return GetDexFile(dexFile)->StringByTypeIdx(GetFieldId(this)->class_idx_); +} + +uint32_t IDexFieldIdItem::GetTypeIdx() const { + return GetFieldId(this)->type_idx_.index_; +} + +const char *IDexFieldIdItem::GetFieldTypeName(const IDexFile &dexFile) const { + return GetDexFile(dexFile)->StringByTypeIdx(GetFieldId(this)->type_idx_); +} + +uint32_t IDexFieldIdItem::GetNameIdx() const { + return GetFieldId(this)->name_idx_.index_; +} + +const char *IDexFieldIdItem::GetShortFieldName(const IDexFile &dexFile) const { + return GetDexFile(dexFile)->StringDataByIdx(GetFieldId(this)->name_idx_); +} +// =====IDexFieldIdItem end========= +// =====IDexFieldItem start========= +IDexFieldItem::IDexFieldItem(uint32_t fieldIndex, uint32_t accessFlags) + : fieldIndex(fieldIndex), accessFlags(accessFlags) {} + +uint32_t IDexFieldItem::GetFieldIdx() const { + return fieldIndex; +} + +const IDexFieldIdItem *IDexFieldItem::GetFieldIdItem(const IDexFile &dexFile) const { + return IDexFieldIdItem::GetInstance(dexFile, GetFieldIdx()); +} + +uint32_t IDexFieldItem::GetAccessFlags() const { + return accessFlags; +} +// =====IDexFieldItem end=========== +// =====IDexAnnotation start======== +const art::dex::AnnotationItem *GetAnnotationItem(const IDexAnnotation *item) { + return reinterpret_cast(item); +} + +const IDexAnnotation *IDexAnnotation::GetInstance(const void *data) { + return reinterpret_cast(data); +} + +uint8_t IDexAnnotation::GetVisibility() const { + return GetAnnotationItem(this)->visibility_; +} + +const uint8_t *IDexAnnotation::GetAnnotationData() const { + return GetAnnotationItem(this)->annotation_; +} +// =====IDexAnnotation end========== +// =====IDexAnnotationSet start===== +const art::dex::AnnotationSetItem *GetAnnotationSet(const IDexAnnotationSet *item) { + return reinterpret_cast(item); +} + +const IDexAnnotationSet *IDexAnnotationSet::GetInstance(const void *data) { + return reinterpret_cast(data); +} + +void IDexAnnotationSet::GetAnnotations(const IDexFile &dexFile, std::vector &items) const { + if (!IsValid()) { + return; + } + + for (uint32_t i = 0; i < GetAnnotationSet(this)->size_; i++) { + const art::dex::AnnotationItem *artAnnotationItem = + GetDexFile(dexFile)->GetAnnotationItem(GetAnnotationSet(this), i); + items.push_back(IDexAnnotation::GetInstance(artAnnotationItem)); + } +} + +bool IDexAnnotationSet::IsValid() const { + return (GetAnnotationSet(this) != nullptr) && (GetAnnotationSet(this)->size_ > 0); +} +// =====IDexAnnotationSet end========== +// =====IDexAnnotationSetList start==== +const art::dex::AnnotationSetRefList *GetAnnotationSetList(const IDexAnnotationSetList *list) { + return reinterpret_cast(list); +} + +const IDexAnnotationSetList *IDexAnnotationSetList::GetInstance(const void *data) { + return reinterpret_cast(data); +} + +void IDexAnnotationSetList::GetAnnotationSets(const IDexFile &dexFile, + std::vector &items) const { + for (uint32_t i = 0; i < GetAnnotationSetList(this)->size_; i++) { + const art::dex::AnnotationSetItem *setItem = + GetDexFile(dexFile)->GetSetRefItemItem(GetAnnotationSetList(this)->list_ + i); + // setItem == nullptr is a valid parameter, will check valid in later using. + items.push_back(IDexAnnotationSet::GetInstance(setItem)); + } +} +// =====IDexAnnotationSetList end====== +// =====IDexFieldAnnotations start===== +const art::dex::FieldAnnotationsItem *GetFieldAnnotations(const IDexFieldAnnotations *item) { + return reinterpret_cast(item); +} + +const IDexFieldAnnotations *IDexFieldAnnotations::GetInstance(const void *data) { + return reinterpret_cast(data); +} + +const IDexFieldIdItem *IDexFieldAnnotations::GetFieldIdItem(const IDexFile &dexFile) const { + return IDexFieldIdItem::GetInstance(dexFile, GetFieldAnnotations(this)->field_idx_); +} + +const IDexAnnotationSet *IDexFieldAnnotations::GetAnnotationSet(const IDexFile &dexFile) const { + const art::dex::AnnotationSetItem *artAnnotationSet = + GetDexFile(dexFile)->GetFieldAnnotationSetItem(*GetFieldAnnotations(this)); + // artAnnotationSet == nullptr is a valid parameter, will check valid in later using. + return IDexAnnotationSet::GetInstance(artAnnotationSet); +} + +uint32_t IDexFieldAnnotations::GetFieldIdx() const { + return GetFieldAnnotations(this)->field_idx_; +} +// =====IDexFieldAnnotations end======= +// =====IDexMethodAnnotations start==== +const art::dex::MethodAnnotationsItem *GetMethodAnnotations(const IDexMethodAnnotations *item) { + return reinterpret_cast(item); +} + +const IDexMethodAnnotations *IDexMethodAnnotations::GetInstance(const void *data) { + return reinterpret_cast(data); +} + +const IDexMethodIdItem *IDexMethodAnnotations::GetMethodIdItem(const IDexFile &dexFile) const { + return IDexMethodIdItem::GetInstance(dexFile, GetMethodAnnotations(this)->method_idx_); +} + +const IDexAnnotationSet *IDexMethodAnnotations::GetAnnotationSet(const IDexFile &dexFile) const { + const art::dex::AnnotationSetItem *artAnnotationSetItem = + GetDexFile(dexFile)->GetMethodAnnotationSetItem(*GetMethodAnnotations(this)); + // artAnnotationSetItem == nullptr is a valid parameter, will check valid in later using. + return IDexAnnotationSet::GetInstance(artAnnotationSetItem); +} + +uint32_t IDexMethodAnnotations::GetMethodIdx() const { + return GetMethodAnnotations(this)->method_idx_; +} +// =====IDexMethodAnnotations end======== +// =====IDexParameterAnnotations start=== +const art::dex::ParameterAnnotationsItem *GetParameterAnnotations(const IDexParameterAnnotations *item) { + return reinterpret_cast(item); +} + +const IDexParameterAnnotations *IDexParameterAnnotations::GetInstance(const void *data) { + return reinterpret_cast(data); +} + +const IDexMethodIdItem *IDexParameterAnnotations::GetMethodIdItem(const IDexFile &dexFile) const { + return IDexMethodIdItem::GetInstance(dexFile, GetMethodIdx()); +} + +const IDexAnnotationSetList *IDexParameterAnnotations::GetAnnotationSetList(const IDexFile &dexFile) const { + const art::dex::AnnotationSetRefList *setRefList = + GetDexFile(dexFile)->GetParameterAnnotationSetRefList(GetParameterAnnotations(this)); + if (setRefList == nullptr) { + return nullptr; + } else { + return IDexAnnotationSetList::GetInstance(setRefList); + } +} + +uint32_t IDexParameterAnnotations::GetMethodIdx() const { + return GetParameterAnnotations(this)->method_idx_; +} +// =====IDexParameterAnnotations end===== +// =====IDexAnnotationsDirectory start=== +const art::dex::AnnotationsDirectoryItem *GetAnnotationsDirectory(const IDexAnnotationsDirectory *item) { + return reinterpret_cast(item); +} + +const IDexAnnotationsDirectory *IDexAnnotationsDirectory::GetInstance(const void *data) { + return reinterpret_cast(data); +} + +bool IDexAnnotationsDirectory::HasClassAnnotationSet(const IDexFile &dexFile) const { + const art::dex::AnnotationSetItem *classAnnotationSetItem = + GetDexFile(dexFile)->GetClassAnnotationSet(GetAnnotationsDirectory(this)); + return classAnnotationSetItem != nullptr; +} + +bool IDexAnnotationsDirectory::HasFieldAnnotationsItems(const IDexFile &dexFile) const { + const art::dex::FieldAnnotationsItem *artFieldAnnotationsItem = + GetDexFile(dexFile)->GetFieldAnnotations(GetAnnotationsDirectory(this)); + return artFieldAnnotationsItem != nullptr; +} + +bool IDexAnnotationsDirectory::HasMethodAnnotationsItems(const IDexFile &dexFile) const { + const art::dex::MethodAnnotationsItem *artMethodAnnotationsItem = + GetDexFile(dexFile)->GetMethodAnnotations(GetAnnotationsDirectory(this)); + return artMethodAnnotationsItem != nullptr; +} + +bool IDexAnnotationsDirectory::HasParameterAnnotationsItems(const IDexFile &dexFile) const { + const art::dex::ParameterAnnotationsItem *parameterItem = + GetDexFile(dexFile)->GetParameterAnnotations(GetAnnotationsDirectory(this)); + return parameterItem != nullptr; +} + +const IDexAnnotationSet *IDexAnnotationsDirectory::GetClassAnnotationSet(const IDexFile &dexFile) const { + const art::dex::AnnotationSetItem *classAnnotationSetItem = + GetDexFile(dexFile)->GetClassAnnotationSet(GetAnnotationsDirectory(this)); + // classAnnotationSetItem == nullptr is a valid parameter, will check valid in later using. + return IDexAnnotationSet::GetInstance(classAnnotationSetItem); +} + +void IDexAnnotationsDirectory::GetFieldAnnotationsItems(const IDexFile &dexFile, + std::vector &items) const { + const art::dex::FieldAnnotationsItem *artFieldAnnotationsItem = + GetDexFile(dexFile)->GetFieldAnnotations(GetAnnotationsDirectory(this)); + if (artFieldAnnotationsItem == nullptr) { + return; + } + for (uint32_t i = 0; i < GetAnnotationsDirectory(this)->fields_size_; i++) { + items.push_back(IDexFieldAnnotations::GetInstance(artFieldAnnotationsItem + i)); + } +} + +void IDexAnnotationsDirectory::GetMethodAnnotationsItems(const IDexFile &dexFile, + std::vector &items) const { + const art::dex::MethodAnnotationsItem *artMethodAnnotationsItem = + GetDexFile(dexFile)->GetMethodAnnotations(GetAnnotationsDirectory(this)); + if (artMethodAnnotationsItem == nullptr) { + return; + } + for (uint32_t i = 0; i < GetAnnotationsDirectory(this)->methods_size_; i++) { + items.push_back(IDexMethodAnnotations::GetInstance(artMethodAnnotationsItem + i)); + } +} + +void IDexAnnotationsDirectory::GetParameterAnnotationsItems(const IDexFile &dexFile, + std::vector &items) + const { + const art::dex::ParameterAnnotationsItem *parameterItem = + GetDexFile(dexFile)->GetParameterAnnotations(GetAnnotationsDirectory(this)); + if (parameterItem == nullptr) { + return; + } + for (uint32_t i = 0; i < GetAnnotationsDirectory(this)->parameters_size_; i++) { + items.push_back(IDexParameterAnnotations::GetInstance(parameterItem + i)); + } +} +// =====IDexAnnotationsDirectory end===== +// =====IDexClassItem start============== +const IDexClassItem *GetDexClassInstance(const art::DexFile &dexFile, uint32_t index) { + return reinterpret_cast(&(dexFile.GetClassDef(index))); +} + +uint32_t IDexClassItem::GetClassIdx() const { + return GetClassDef(this)->class_idx_.index_; +} + +const char *IDexClassItem::GetClassName(const IDexFile &dexFile) const { + return GetDexFile(dexFile)->StringByTypeIdx(GetClassDef(this)->class_idx_); +} + +uint32_t IDexClassItem::GetAccessFlags() const { + return GetClassDef(this)->access_flags_; +} + +uint32_t IDexClassItem::GetSuperclassIdx() const { + return GetClassDef(this)->superclass_idx_.index_; +} + +const char *IDexClassItem::GetSuperClassName(const IDexFile &dexFile) const { + if (!GetClassDef(this)->superclass_idx_.IsValid()) { + return nullptr; + } + return GetDexFile(dexFile)->StringByTypeIdx(GetClassDef(this)->superclass_idx_); +} + +uint32_t IDexClassItem::GetInterfacesOff() const { + return GetClassDef(this)->interfaces_off_; +} + +void IDexClassItem::GetInterfaceTypeIndexes(const IDexFile &dexFile, std::vector &indexes) const { + const art::dex::TypeList *interfaces = GetDexFile(dexFile)->GetInterfacesList(*GetClassDef(this)); + if (interfaces == nullptr) { + return; + } + for (uint32_t i = 0; i < interfaces->Size(); i++) { + const art::dex::TypeItem &typeItem = interfaces->GetTypeItem(i); + art::dex::TypeIndex artTypeIndex = typeItem.type_idx_; + indexes.push_back(artTypeIndex.index_); + } +} + +void IDexClassItem::GetInterfaceNames(const IDexFile &dexFile, std::vector &names) const { + const art::dex::TypeList *interfaces = GetDexFile(dexFile)->GetInterfacesList(*GetClassDef(this)); + if (interfaces == nullptr) { + return; + } + for (uint32_t i = 0; i < interfaces->Size(); i++) { + const art::dex::TypeItem &typeItem = interfaces->GetTypeItem(i); + art::dex::TypeIndex artTypeIndex = typeItem.type_idx_; + const char *interfaceName = GetDexFile(dexFile)->StringByTypeIdx(artTypeIndex); + names.push_back(interfaceName); + } +} + +uint32_t IDexClassItem::GetSourceFileIdx() const { + return GetClassDef(this)->source_file_idx_.index_; +} + +const char *IDexClassItem::GetJavaSourceFileName(const IDexFile &dexFile) const { + if (GetClassDef(this)->source_file_idx_.index_ == art::dex::kDexNoIndex) { + return nullptr; + } + return GetDexFile(dexFile)->StringDataByIdx(GetClassDef(this)->source_file_idx_); +} + +bool IDexClassItem::HasAnnotationsDirectory(const IDexFile &dexFile) const { + return (GetDexFile(dexFile)->GetAnnotationsDirectory(*GetClassDef(this)) != nullptr); +} + +uint32_t IDexClassItem::GetAnnotationsOff() const { + return GetClassDef(this)->annotations_off_; +} + +const IDexAnnotationsDirectory *IDexClassItem::GetAnnotationsDirectory(const IDexFile &dexFile) const { + const art::dex::AnnotationsDirectoryItem *artDirectoryItem = + GetDexFile(dexFile)->GetAnnotationsDirectory(*GetClassDef(this)); + if (artDirectoryItem == nullptr) { + return nullptr; + } else { + return IDexAnnotationsDirectory::GetInstance(artDirectoryItem); + } +} + +uint32_t IDexClassItem::GetClassDataOff() const { + return GetClassDef(this)->class_data_off_; +} + +std::vector> IDexClassItem::GetFields(const IDexFile &dexFile) const { + std::vector> fields; + art::ClassAccessor accessor(*GetDexFile(dexFile), *GetClassDef(this)); + for (const art::ClassAccessor::Field &field : accessor.GetFields()) { + uint32_t fieldIdx = field.GetIndex(); + uint32_t accessFlags = field.GetAccessFlags(); + std::unique_ptr dexFieldItem = std::make_unique(fieldIdx, accessFlags); + fields.push_back(std::move(dexFieldItem)); + } + return fields; +} + +bool IDexClassItem::HasStaticValuesList() const { + return (GetClassDef(this)->static_values_off_ != 0); +} + +const uint8_t *IDexClassItem::GetStaticValuesList(const IDexFile &dexFile) const { + return GetDexFile(dexFile)->GetEncodedStaticFieldValuesArray(*GetClassDef(this)); +} + +bool IDexClassItem::IsInterface() const { + bool isInterface = ((GetAccessFlags() & art::kAccInterface) > 0) ? true : false; + return isInterface; +} + +bool IDexClassItem::IsSuperclassValid() const { + const art::dex::ClassDef *artClassDef = GetClassDef(this); + return artClassDef->superclass_idx_.IsValid(); +} + +std::vector> IDexClassItem::GetMethodsIdxAndFlag(const IDexFile &dexFile, + bool isVirtual) const { + std::vector> methodsIdx; + art::ClassAccessor accessor(*GetDexFile(dexFile), *GetClassDef(this)); + if (isVirtual) { + for (const art::ClassAccessor::Method &method : accessor.GetVirtualMethods()) { + methodsIdx.push_back(std::make_pair(method.GetIndex(), method.GetAccessFlags())); + } + } else { + for (const art::ClassAccessor::Method &method : accessor.GetDirectMethods()) { + methodsIdx.push_back(std::make_pair(method.GetIndex(), method.GetAccessFlags())); + } + } + return methodsIdx; +} + +std::unique_ptr IDexClassItem::GetDirectMethod(const IDexFile &dexFile, uint32_t index) const { + art::ClassAccessor accessor(*GetDexFile(dexFile), *GetClassDef(this)); + auto directMethodIt = accessor.GetDirectMethods().begin(); + for (uint32_t i = 0; i < index; ++i) { + ++directMethodIt; + } + std::unique_ptr dexMethodItem = std::make_unique(directMethodIt->GetIndex(), + directMethodIt->GetAccessFlags(), directMethodIt->GetCodeItemOffset()); + return dexMethodItem; +} + +std::unique_ptr IDexClassItem::GetVirtualMethod(const IDexFile &dexFile, uint32_t index) const { + art::ClassAccessor accessor(*GetDexFile(dexFile), *GetClassDef(this)); + auto virtualMethodIt = accessor.GetVirtualMethods().begin(); + for (uint32_t i = 0; i < index; ++i) { + ++virtualMethodIt; + } + std::unique_ptr dexMethodItem = std::make_unique(virtualMethodIt->GetIndex(), + virtualMethodIt->GetAccessFlags(), virtualMethodIt->GetCodeItemOffset()); + return dexMethodItem; +} +// =====IDexClassItem end================ +// =====Header start==================== +const art::DexFile *GetDexFile(const IDexHeader *header) { + return reinterpret_cast(header); +} + +const IDexHeader *IDexHeader::GetInstance(const IDexFile &dexFile) { + return reinterpret_cast(dexFile.GetData()); +} + +uint8_t IDexHeader::GetMagic(uint32_t index) const { + return GetDexFile(this)->GetHeader().magic_[index]; +} + +uint32_t IDexHeader::GetChecksum() const { + return GetDexFile(this)->GetHeader().checksum_; +} + +std::string IDexHeader::GetSignature() const { + static const char *const kHex = "0123456789abcdef"; + static constexpr size_t kHexNum = 16; + static constexpr size_t kSignatureSize = 20; + const uint8_t *signature = GetDexFile(this)->GetHeader().signature_; + std::string result; + for (size_t i = 0; i < kSignatureSize; ++i) { + uint8_t value = signature[i]; + result.push_back(kHex[value / kHexNum]); + result.push_back(kHex[value % kHexNum]); + } + return result; +} + +uint32_t IDexHeader::GetFileSize() const { + return GetDexFile(this)->GetHeader().file_size_; +} + +uint32_t IDexHeader::GetHeaderSize() const { + return GetDexFile(this)->GetHeader().header_size_; +} + +uint32_t IDexHeader::GetEndianTag() const { + return GetDexFile(this)->GetHeader().endian_tag_; +} + +uint32_t IDexHeader::GetLinkSize() const { + return GetDexFile(this)->GetHeader().link_size_; +} + +uint32_t IDexHeader::GetLinkOff() const { + return GetDexFile(this)->GetHeader().link_off_; +} + +uint32_t IDexHeader::GetMapOff() const { + return GetDexFile(this)->GetHeader().map_off_; +} + +uint32_t IDexHeader::GetStringIdsSize() const { + return GetDexFile(this)->GetHeader().string_ids_size_; +} + +uint32_t IDexHeader::GetStringIdsOff() const { + return GetDexFile(this)->GetHeader().string_ids_off_; +} + +uint32_t IDexHeader::GetTypeIdsSize() const { + return GetDexFile(this)->GetHeader().type_ids_size_; +} + +uint32_t IDexHeader::GetTypeIdsOff() const { + return GetDexFile(this)->GetHeader().type_ids_off_; +} + +uint32_t IDexHeader::GetProtoIdsSize() const { + return GetDexFile(this)->GetHeader().proto_ids_size_; +} + +uint32_t IDexHeader::GetProtoIdsOff() const { + return GetDexFile(this)->GetHeader().proto_ids_off_; +} + +uint32_t IDexHeader::GetFieldIdsSize() const { + return GetDexFile(this)->GetHeader().field_ids_size_; +} + +uint32_t IDexHeader::GetFieldIdsOff() const { + return GetDexFile(this)->GetHeader().field_ids_off_; +} + +uint32_t IDexHeader::GetMethodIdsSize() const { + return GetDexFile(this)->GetHeader().method_ids_size_; +} + +uint32_t IDexHeader::GetMethodIdsOff() const { + return GetDexFile(this)->GetHeader().method_ids_off_; +} + +uint32_t IDexHeader::GetClassDefsSize() const { + return GetDexFile(this)->GetHeader().class_defs_size_; +} + +uint32_t IDexHeader::GetClassDefsOff() const { + return GetDexFile(this)->GetHeader().class_defs_off_; +} + +uint32_t IDexHeader::GetDataSize() const { + return GetDexFile(this)->GetHeader().data_size_; +} + +uint32_t IDexHeader::GetDataOff() const { + return GetDexFile(this)->GetHeader().data_off_; +} + +std::string IDexHeader::GetDexVesion() const { + auto magic = reinterpret_cast(GetDexFile(this)->GetHeader().magic_); + std::string magicStr(magic); + size_t totalLength = magicStr.length(); + size_t pos = totalLength - kDexFileVersionStringLength; + std::string res = magicStr.substr(pos, kDexFileVersionStringLength); + return res; +} +// =====Header end=================== +// =====MapList start================ +const art::dex::MapList *GetMapList(const IDexMapList *list) { + return reinterpret_cast(list); +} + +const IDexMapList *IDexMapList::GetInstance(const void *data) { + return reinterpret_cast(data); +} + +uint32_t IDexMapList::GetSize() const { + return static_cast(GetMapList(this)->Size()); +} + +uint16_t IDexMapList::GetType(uint32_t index) const { + return GetMapList(this)->list_[index].type_; +} + +uint32_t IDexMapList::GetTypeSize(uint32_t index) const { + return GetMapList(this)->list_[index].size_; +} +// =====MapList end================== +// =====ResolvedMethodHandleItem start===== +const art::dex::MethodHandleItem *GetMethodHandle(const ResolvedMethodHandleItem *item) { + return reinterpret_cast(item); +} + +const ResolvedMethodHandleItem *ResolvedMethodHandleItem::GetInstance(const IDexFile &dexFile, uint32_t index) { + return reinterpret_cast(&(GetDexFile(dexFile)->GetMethodHandle(index))); +} + +bool ResolvedMethodHandleItem::IsInstance() const { + art::DexFile::MethodHandleType type = + static_cast(GetMethodHandle(this)->method_handle_type_); + return (type == art::DexFile::MethodHandleType::kInvokeInstance) || + (type == art::DexFile::MethodHandleType::kInvokeConstructor); +} + +bool ResolvedMethodHandleItem::IsInvoke() const { + art::DexFile::MethodHandleType type = + static_cast(GetMethodHandle(this)->method_handle_type_); + return (type == art::DexFile::MethodHandleType::kInvokeInstance) || + (type == art::DexFile::MethodHandleType::kInvokeConstructor) || + (type == art::DexFile::MethodHandleType::kInvokeStatic); +} + +const std::string ResolvedMethodHandleItem::GetDeclaringClass(const IDexFile &dexFile) const { + if (!IsInvoke()) { + return std::string(); + } + const char *declaringClass = nullptr; + const art::dex::MethodId &methodId = GetDexFile(dexFile)->GetMethodId(GetMethodHandle(this)->field_or_method_idx_); + declaringClass = GetDexFile(dexFile)->GetMethodDeclaringClassDescriptor(methodId); + return namemangler::EncodeName(declaringClass); +} + +const std::string ResolvedMethodHandleItem::GetMember(const IDexFile &dexFile) const { + if (!IsInvoke()) { + return std::string(); + } + const char *member = nullptr; + const art::dex::MethodId &methodId = GetDexFile(dexFile)->GetMethodId(GetMethodHandle(this)->field_or_method_idx_); + member = GetDexFile(dexFile)->GetMethodName(methodId); + return namemangler::EncodeName(member); +} + +const std::string ResolvedMethodHandleItem::GetMemeberProto(const IDexFile &dexFile) const { + if (!IsInvoke()) { + return std::string(); + } + const art::dex::MethodId &methodId = GetDexFile(dexFile)->GetMethodId(GetMethodHandle(this)->field_or_method_idx_); + std::string memberType = GetDexFile(dexFile)->GetMethodSignature(methodId).ToString(); + return GetDeclaringClass(dexFile) + "_7C" + GetMember(dexFile) + "_7C" + namemangler::EncodeName(memberType); +} + +const ResolvedMethodType *ResolvedMethodHandleItem::GetMethodType(const IDexFile &dexFile) const { + return ResolvedMethodType::GetInstance(dexFile, *this); +} + +const std::string ResolvedMethodHandleItem::GetInvokeKind() const { + art::DexFile::MethodHandleType type = + static_cast(GetMethodHandle(this)->method_handle_type_); + switch (type) { + case art::DexFile::MethodHandleType::kInvokeStatic: + return std::string("invoke-static"); + case art::DexFile::MethodHandleType::kInvokeInstance: + return std::string("invoke-instance"); + case art::DexFile::MethodHandleType::kInvokeConstructor: + return std::string("invoke-constructor"); + default: + return std::string(); + } +} +// =====ResolvedMethodHandleItem end===== +// =====ResolvedMethodType start===== +const art::dex::MethodId *GetMethodHandleId(const ResolvedMethodType *type) { + return reinterpret_cast(type); +} + +const art::dex::ProtoId *GetMethodCallSiteId(const ResolvedMethodType *type) { + auto value = reinterpret_cast(type); + return reinterpret_cast(value & (~1)); +} + +const ResolvedMethodType *ResolvedMethodType::GetInstance(const IDexFile &dexFile, + const ResolvedMethodHandleItem &item) { + const art::dex::MethodId *methodId = + &(GetDexFile(dexFile)->GetMethodId(GetMethodHandle(&item)->field_or_method_idx_)); + if ((reinterpret_cast(methodId) & 0x1) == 1) { + std::cerr << "Invalid MethodId address" << std::endl; + return nullptr; + } + return reinterpret_cast(methodId); +} + +const ResolvedMethodType *ResolvedMethodType::GetInstance(const IDexFile &dexFile, uint32_t callSiteId) { + const art::dex::ProtoId *methodId = &(GetDexFile(dexFile)->GetProtoId((art::dex::ProtoIndex)callSiteId)); + if ((reinterpret_cast(methodId) & 0x1) == 1) { + std::cerr << "Invalid MethodId address" << std::endl; + return nullptr; + } + return reinterpret_cast(reinterpret_cast(methodId) | 0x1); +} + +const std::string ResolvedMethodType::GetReturnType(const IDexFile &dexFile) const { + std::string rawType = GetRawType(dexFile); + return SignatureReturnType(rawType); +} + +const std::string ResolvedMethodType::GetRawType(const IDexFile &dexFile) const { + auto value = reinterpret_cast(this); + if ((value & 0x1) == 0) { + return GetDexFile(dexFile)->GetMethodSignature(*GetMethodHandleId(this)).ToString(); + } + return GetDexFile(dexFile)->GetProtoSignature(*GetMethodCallSiteId(this)).ToString(); +} + +void ResolvedMethodType::GetArgTypes(const IDexFile &dexFile, std::list &types) const { + std::string rawType = GetRawType(dexFile); + SignatureTypes(rawType, types); +} +// =====ResolvedMethodType end======= +// =====ResolvedCallSiteIdItem start===== +const art::dex::CallSiteIdItem *GetCallSiteId(const ResolvedCallSiteIdItem *item) { + return reinterpret_cast(item); +} + +const ResolvedCallSiteIdItem *ResolvedCallSiteIdItem::GetInstance(const IDexFile &dexFile, uint32_t index) { + const art::dex::CallSiteIdItem &callSiteId = GetDexFile(dexFile)->GetCallSiteId(index); + art::CallSiteArrayValueIterator it(*GetDexFile(dexFile), callSiteId); + if (it.Size() < 3) { // 3 stands for the min size of call site values. + std::cerr << "ERROR: Call site" << index << " has too few values." << std::endl; + return nullptr; + } + return reinterpret_cast(&callSiteId); +} + +uint32_t ResolvedCallSiteIdItem::GetDataOff() const { + return GetCallSiteId(this)->data_off_; +} + +uint32_t ResolvedCallSiteIdItem::GetMethodHandleIndex(const IDexFile &dexFile) const { + art::CallSiteArrayValueIterator it(*GetDexFile(dexFile), *GetCallSiteId(this)); + return static_cast(it.GetJavaValue().i); +} + +const std::string ResolvedCallSiteIdItem::GetMethodName(const IDexFile &dexFile) const { + art::CallSiteArrayValueIterator it(*GetDexFile(dexFile), *GetCallSiteId(this)); + it.Next(); + art::dex::StringIndex methodNameIdx = static_cast(it.GetJavaValue().i); + return std::string(GetDexFile(dexFile)->StringDataByIdx(methodNameIdx)); +} + +const std::string ResolvedCallSiteIdItem::GetProto(const IDexFile &dexFile) const { + art::CallSiteArrayValueIterator it(*GetDexFile(dexFile), *GetCallSiteId(this)); + it.Next(); + it.Next(); + uint32_t methodTypeIdx = static_cast(it.GetJavaValue().i); + const art::dex::ProtoId &methodTypeId = GetDexFile(dexFile)->GetProtoId((art::dex::ProtoIndex)methodTypeIdx); + return GetDexFile(dexFile)->GetProtoSignature(methodTypeId).ToString(); +} + +const ResolvedMethodType *ResolvedCallSiteIdItem::GetMethodType(const IDexFile &dexFile) const { + art::CallSiteArrayValueIterator it(*GetDexFile(dexFile), *GetCallSiteId(this)); + it.Next(); + it.Next(); + uint32_t methodTypeIdx = static_cast(it.GetJavaValue().i); + return ResolvedMethodType::GetInstance(dexFile, methodTypeIdx); +} + +void ResolvedCallSiteIdItem::GetLinkArgument(const IDexFile &dexFile, + std::list> &args) const { + art::CallSiteArrayValueIterator it(*GetDexFile(dexFile), *GetCallSiteId(this)); + it.Next(); + it.Next(); + it.Next(); + while (it.HasNext()) { + ValueType type = ValueType::kByte; + std::string value; + switch (it.GetValueType()) { + case art::EncodedArrayValueIterator::ValueType::kByte: { + type = ValueType::kByte; + value = android::base::StringPrintf("%u", it.GetJavaValue().b); + break; + } + case art::EncodedArrayValueIterator::ValueType::kString: { + // cannot define var in switch need brackets + type = ValueType::kString; + art::dex::StringIndex stringIdx = static_cast(it.GetJavaValue().i); + const char *str = GetDexFile(dexFile)->StringDataByIdx(stringIdx); + if (str == nullptr) { + LOG(FATAL) << "Invalid string from DexFile"; + } + value = str; + break; + } + case art::EncodedArrayValueIterator::ValueType::kMethodType: { + uint32_t protoIdx = static_cast(it.GetJavaValue().i); + const art::dex::ProtoId &protoId = GetDexFile(dexFile)->GetProtoId((art::dex::ProtoIndex)protoIdx); + type = ValueType::kMethodType; + value = GetDexFile(dexFile)->GetProtoSignature(protoId).ToString(); + break; + } + case art::EncodedArrayValueIterator::ValueType::kMethodHandle: { + type = ValueType::kMethodHandle; + value = android::base::StringPrintf("%d", it.GetJavaValue().i); + break; + } + case art::EncodedArrayValueIterator::ValueType::kType: { + art::dex::TypeIndex typeIdx = static_cast(it.GetJavaValue().i); + const char *str = GetDexFile(dexFile)->StringByTypeIdx(typeIdx); + if (str == nullptr) { + LOG(FATAL) << "Invalid string from DexFile"; + } + value = str; + type = ValueType::kType; + break; + } + case art::EncodedArrayValueIterator::ValueType::kNull: { + type = ValueType::kNull; + value = "null"; + break; + } + case art::EncodedArrayValueIterator::ValueType::kBoolean: { + value = it.GetJavaValue().z ? "true" : "false"; + type = ValueType::kBoolean; + break; + } + case art::EncodedArrayValueIterator::ValueType::kShort: { + type = ValueType::kShort; + value = android::base::StringPrintf("%d", it.GetJavaValue().s); + break; + } + case art::EncodedArrayValueIterator::ValueType::kChar: { + type = ValueType::kChar; + value = android::base::StringPrintf("%u", it.GetJavaValue().c); + break; + } + case art::EncodedArrayValueIterator::ValueType::kInt: { + type = ValueType::kInt; + value = android::base::StringPrintf("%d", it.GetJavaValue().i); + break; + } + case art::EncodedArrayValueIterator::ValueType::kLong: { + type = ValueType::kLong; + value = android::base::StringPrintf("%" PRId64 "64", it.GetJavaValue().j); + break; + } + case art::EncodedArrayValueIterator::ValueType::kFloat: { + type = ValueType::kFloat; + value = android::base::StringPrintf("%g", it.GetJavaValue().f); + break; + } + case art::EncodedArrayValueIterator::ValueType::kDouble: { + type = ValueType::kDouble; + value = android::base::StringPrintf("%g", it.GetJavaValue().d); + break; + } + default: { + LOG(FATAL) << "Unimplemented type " << it.GetValueType(); + } + } + args.push_back(std::make_pair(type, value)); + it.Next(); + } +} +// =====ResolvedCallSiteIdItem end=== +// =====LibDexFile start============= +LibDexFile::LibDexFile(std::unique_ptr artDexFile, + std::unique_ptr contentPtrIn) + : contentPtr(std::move(contentPtrIn)) { + dexFiles.push_back(std::move(artDexFile)); + dexFile = dexFiles[0].get(); + header = IDexHeader::GetInstance(*this); + mapList = IDexMapList::GetInstance(dexFile->GetMapList()); +} + +LibDexFile::~LibDexFile() { + dexFile = nullptr; +} + +bool LibDexFile::Open(const std::string &fileName) { + const bool kVerifyChecksum = true; + const bool kVerify = true; + // If the file is not a .dex file, the function tries .zip/.jar/.apk files, + // all of which are Zip archives with "classes.dex" inside. + if (!android::base::ReadFileToString(fileName, &content)) { + LOG(ERROR) << "ReadFileToString failed"; + return false; + } + // content size must > 0, otherwise previous step return false + if (!CheckFileSize(content.size())) { + return false; + } + const art::DexFileLoader dexFileLoader; + art::DexFileLoaderErrorCode errorCode; + std::string errorMsg; + if (!dexFileLoader.OpenAll(reinterpret_cast(content.data()), + content.size(), + fileName, + kVerify, + kVerifyChecksum, + &errorCode, + &errorMsg, + &dexFiles)) { + // Display returned error message to user. Note that this error behavior + // differs from the error messages shown by the original Dalvik dexdump. + LOG(ERROR) << errorMsg; + return false; + } + if (dexFiles.size() != 1) { + LOG(FATAL) << "Only support one dexfile now"; + } + dexFile = dexFiles[0].get(); + header = IDexHeader::GetInstance(*this); + mapList = IDexMapList::GetInstance(dexFile->GetMapList()); + return true; +} + +const uint8_t *LibDexFile::GetBaseAddress() const { + return dexFile->Begin(); +} + +const IDexHeader *LibDexFile::GetHeader() const { + return header; +} + +const IDexMapList *LibDexFile::GetMapList() const { + return mapList; +} + +uint32_t LibDexFile::GetStringDataOffset(uint32_t index) const { + const art::dex::StringId &artStringId = dexFile->GetStringId(art::dex::StringIndex(index)); + return artStringId.string_data_off_; +} + +uint32_t LibDexFile::GetTypeDescriptorIndex(uint32_t index) const { + const art::dex::TypeId &artTypeId = dexFile->GetTypeId(art::dex::TypeIndex(static_cast(index))); + return artTypeId.descriptor_idx_.index_; +} + +const char *LibDexFile::GetStringByIndex(uint32_t index) const { + const char *str = dexFile->StringDataByIdx(art::dex::StringIndex(index)); + if (str == nullptr) { + LOG(FATAL) << "Invalid or truncated dex file"; + } + return str; +} + +const char *LibDexFile::GetStringByTypeIndex(uint32_t index) const { + return dexFile->StringByTypeIdx(art::dex::TypeIndex(index)); +} + +const IDexProtoIdItem *LibDexFile::GetProtoIdItem(uint32_t index) const { + return IDexProtoIdItem::GetInstance(*this, index); +} + +const IDexFieldIdItem *LibDexFile::GetFieldIdItem(uint32_t index) const { + return IDexFieldIdItem::GetInstance(*this, index); +} + +const IDexMethodIdItem *LibDexFile::GetMethodIdItem(uint32_t index) const { + return IDexMethodIdItem::GetInstance(*this, index); +} + +uint32_t LibDexFile::GetClassItemsSize() const { + return dexFile->NumClassDefs(); +} + +const IDexClassItem *LibDexFile::GetClassItem(uint32_t index) const { + return GetDexClassInstance(*dexFile, index); +} + +bool LibDexFile::IsNoIndex(uint32_t index) const { + uint16_t index16 = static_cast(index); + return (index16 == art::DexFile::kDexNoIndex16); +} + +uint32_t LibDexFile::GetTypeIdFromName(const std::string &className) const { + return dexFile->GetIndexForTypeId(*dexFile->FindTypeId(className.c_str())).index_; +} + +uint32_t LibDexFile::ReadUnsignedLeb128(const uint8_t **pStream) const { + uint32_t result = art::DecodeUnsignedLeb128(pStream); + return result; +} + +uint32_t LibDexFile::FindClassDefIdx(const std::string &descriptor) const { + const art::dex::TypeId* typeId = dexFile->FindTypeId(descriptor.c_str()); + if (typeId != nullptr) { + art::dex::TypeIndex typeIdx = dexFile->GetIndexForTypeId(*typeId); + size_t classDefsSize = dexFile->NumClassDefs(); + if (classDefsSize == 0) { + return art::dex::kDexNoIndex; + } + for (uint32_t i = 0; i < classDefsSize; ++i) { + const art::dex::ClassDef &class_def = dexFile->GetClassDef(i); + if (class_def.class_idx_ == typeIdx) { + return i; + } + } + } + return art::dex::kDexNoIndex; +} + +std::unordered_map LibDexFile::GetDefiningClassNameTypeIdMap() const { + std::unordered_map definingClassNameTypeIdMap; + uint32_t classIdsSize = dexFile->NumTypeIds(); + for (uint32_t classIdIndex = 0; classIdIndex < classIdsSize; classIdIndex++) { + std::string className = dexFile->StringByTypeIdx(art::dex::TypeIndex(classIdIndex)); + definingClassNameTypeIdMap.insert(std::make_pair(namemangler::EncodeName(className), classIdIndex)); + } + return definingClassNameTypeIdMap; +} + +void LibDexFile::DecodeDebugLocalInfo(const IDexMethodItem &iDexMethodItem, + DebugNewLocalCallback newLocalCb) { + debugNewLocalCb = newLocalCb; + const art::dex::CodeItem *codeItem = dexFile->GetCodeItem(iDexMethodItem.GetCodeOff()); + art::CodeItemDebugInfoAccessor accessor(*dexFile, codeItem, iDexMethodItem.GetMethodIdx()); + (void)accessor.DecodeDebugLocalInfo(iDexMethodItem.IsStatic(), iDexMethodItem.GetMethodIdx(), + [&](const art::DexFile::LocalInfo &entry) { + DebugNewLocalCb(nullptr, entry); + }); +} + +void LibDexFile::DecodeDebugPositionInfo(const IDexMethodItem &iDexMethodItem, + DebugNewPositionCallback newPositionCb) { + debugNewPositionCb = newPositionCb; + const art::dex::CodeItem *codeItem = dexFile->GetCodeItem(iDexMethodItem.GetCodeOff()); + art::CodeItemDebugInfoAccessor accessor(*dexFile, codeItem, iDexMethodItem.GetMethodIdx()); + (void)accessor.DecodeDebugPositionInfo([&](const art::DexFile::PositionInfo &entry) { + return DebugNewPositionCb(nullptr, entry); + }); +} + +const ResolvedCallSiteIdItem *LibDexFile::GetCallSiteIdItem(uint32_t idx) const { + return ResolvedCallSiteIdItem::GetInstance(*this, idx); +} + +const ResolvedMethodHandleItem *LibDexFile::GetMethodHandleItem(uint32_t idx) const { + return ResolvedMethodHandleItem::GetInstance(*this, idx);; +} + +void LibDexFile::DebugNewLocalCb(void *context, const art::DexFile::LocalInfo &entry) const { + debugNewLocalCb(context, entry.reg_, entry.start_address_, entry.end_address_, + entry.name_ == nullptr ? "this" : entry.name_, entry.descriptor_ == nullptr ? "" : entry.descriptor_, + entry.signature_ == nullptr ? "" : entry.signature_); +} + +bool LibDexFile::DebugNewPositionCb(void *context, const art::DexFile::PositionInfo &entry) const { + debugNewPositionCb(context, entry.address_, entry.line_); + return false; +} + +bool LibDexFile::CheckFileSize(size_t fileSize) { + if (fileSize < sizeof(art::DexFile::Header)) { + LOG(ERROR) << "Invalid or truncated dex file"; + return false; + } + const art::DexFile::Header *fileHeader = reinterpret_cast(content.data()); + if (fileSize != fileHeader->file_size_) { + LOG(ERROR) << "Bad file size:" << fileSize << ", " << "expected:" << fileHeader->file_size_; + return false; + } + return true; +} +// =====LibDexFile end=============== +} // namespace maple diff --git a/src/hir2mpl/common/include/base64.h b/src/hir2mpl/common/include/base64.h new file mode 100644 index 0000000000000000000000000000000000000000..9ef98385f470522bfacff13cc21417ba0034e4bc --- /dev/null +++ b/src/hir2mpl/common/include/base64.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_BASE64_H +#define HIR2MPL_INCLUDE_COMMON_BASE64_H +#include +#include +#include "types_def.h" + +namespace maple { +class Base64 { + public: + static std::string Encode(const uint8 *input, size_t length); + static uint8 *Decode(const std::string &input, size_t &lengthRet); + static std::map InitEncodeMap(); + static std::map InitDecodeMap(); + + private: + Base64() = default; + ~Base64() = default; + + static std::map encodeMap; + static std::map decodeMap; + static size_t DecodeLength(const std::string &input); +}; +} // namespace maple +#endif \ No newline at end of file diff --git a/src/hir2mpl/common/include/basic_io.h b/src/hir2mpl/common/include/basic_io.h new file mode 100644 index 0000000000000000000000000000000000000000..3fae06fedc9d39ca9cbc66dfefda22a096df8253 --- /dev/null +++ b/src/hir2mpl/common/include/basic_io.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_BASIC_IO_H +#define HIR2MPL_INCLUDE_COMMON_BASIC_IO_H +#include +#include +#include +#include "mempool_allocator.h" +#include "types_def.h" +#include "mpl_logging.h" +#include "securec.h" + +namespace maple { +class BasicIOEndian { + public: + static const uint32 kLengthByte = 1; + static const uint32 kLengthWord = 2; + static const uint32 kLengthDWord = 4; + static const uint32 kLengthQWord = 8; + + static uint16 GetUInt16BigEndian(const uint8 *p) { + // for performance, validation of p must be done by caller + return static_cast((p[kBufIndex0] << kOffset8) | p[kBufIndex1]); + } + + static uint16 GetUInt16LittleEndian(const uint8 *p) { + // for performance, validation of p must be done by caller + return static_cast((p[kBufIndex1] << kOffset8) | p[kBufIndex0]); + } + + static uint32 GetUInt32BigEndian(const uint8 *p) { + // for performance, validation of p must be done by caller + uint32 value = 0; + for (uint32 i = 0; i < kLengthDWord; i++) { + value = (value << kOffset8) | p[i]; + } + return value; + } + + static uint32 GetUInt32LittleEndian(const uint8 *p) { + // for performance, validation of p must be done by caller + uint32 value = 0; + for (int i = static_cast(kLengthDWord) - 1; i >= 0; i--) { + value = (value << kOffset8) | p[i]; + } + return value; + } + + static uint64 GetUInt64BigEndian(const uint8 *p) { + // for performance, validation of p must be done by caller + uint64 value = 0; + for (uint32 i = 0; i < kLengthQWord; i++) { + value = (value << kOffset8) | p[i]; + } + return value; + } + + static uint64 GetUInt64LittleEndian(const uint8 *p) { + // for performance, validation of p must be done by caller + uint64 value = 0; + for (int i = static_cast(kLengthQWord) - 1; i >= 0; i--) { + value = (value << kOffset8) | p[i]; + } + return value; + } + + private: + static const uint32 kBufIndex0 = 0; + static const uint32 kBufIndex1 = 1; + static const uint32 kBufIndex2 = 2; + static const uint32 kBufIndex3 = 3; + static const uint32 kOffset8 = 8; + static const uint32 kOffset16 = 16; + static const uint32 kOffset24 = 24; + + BasicIOEndian() = default; + ~BasicIOEndian() = default; +}; + +class BasicIOMapFile { + public: + explicit BasicIOMapFile(const std::string &name); + BasicIOMapFile(const std::string &name, const uint8 *ptrIn, long lengthIn); + virtual ~BasicIOMapFile(); + bool OpenAndMap() { + return OpenAndMapImpl(); + } + void Close(); + static std::unique_ptr GenFileInMemory(const std::string &name, const uint8 *buf, size_t len); + + size_t GetLength() const { + return length; + } + + const uint8 *GetPtr() const { + return ptr; + } + + const uint8 *GetPtrOffset(size_t offset) const { + if (offset >= length) { + CHECK_FATAL(false, "offset is out of range"); + return nullptr; + } + return ptr + offset; + } + + const std::string &GetFileName() const { + return fileName; + } + + protected: + virtual bool OpenAndMapImpl(); + int fd; + const uint8 *ptr; + uint8 *ptrMemMap; + size_t length; + std::string fileName; +}; + +class BasicIORead { + public: + BasicIORead(BasicIOMapFile &f, bool bigEndian = false); + virtual ~BasicIORead() = default; + uint8 ReadUInt8(); + uint8 ReadUInt8(bool &success); + int8 ReadInt8(); + int8 ReadInt8(bool &success); + char ReadChar(); + char ReadChar(bool &success); + uint16 ReadUInt16(); + uint16 ReadUInt16(bool &success); + int16 ReadInt16(); + int16 ReadInt16(bool &success); + uint32 ReadUInt32(); + uint32 ReadUInt32(bool &success); + int32 ReadInt32(); + int32 ReadInt32(bool &success); + uint64 ReadUInt64(); + uint64 ReadUInt64(bool &success); + int64 ReadInt64(); + int64 ReadInt64(bool &success); + float ReadFloat(); + float ReadFloat(bool &success); + double ReadDouble(); + double ReadDouble(bool &success); + void ReadBufferUInt8(uint8 *dst, uint32 length); + void ReadBufferUInt8(uint8 *dst, uint32 length, bool &success); + void ReadBufferInt8(int8 *dst, uint32 length); + void ReadBufferInt8(int8 *dst, uint32 length, bool &success); + void ReadBufferChar(char *dst, uint32 length); + void ReadBufferChar(char *dst, uint32 length, bool &success); + std::string ReadString(uint32 length); + std::string ReadString(uint32 length, bool &success); + + const uint8 *GetBuffer(uint32 size) const { + if (pos + size > file.GetLength()) { + ERR(kLncErr, "BasicIORead: not enough data"); + return nullptr; + } else { + return file.GetPtrOffset(pos); + } + } + + const uint8 *GetSafeBuffer(uint32 size) const { + CHECK_FATAL(pos + size <= file.GetLength(), "not enough data"); + return file.GetPtrOffset(pos); + } + + const uint8 *GetSafeBufferAt(uint32 pos0, uint32 size) const { + CHECK_FATAL(pos0 + size <= file.GetLength(), "not enough data"); + return file.GetPtrOffset(pos0); + } + + const uint8 *GetSafeDataAt(uint32 offset) const { + CHECK_FATAL(0 < offset && offset < file.GetLength(), "Invalid offset: 0x%x, file total size: 0x%x", + offset, file.GetLength()); + return file.GetPtrOffset(offset); + } + + uint32 GetPos() const { + return pos; + } + + void SetPos(uint32 p) { + CHECK_FATAL(p < file.GetLength(), "invalid pos %d exceeds the length of file %ld", p, file.GetLength()); + pos = p; + } + + size_t GetFileLength() const { + return file.GetLength(); + } + + protected: + BasicIOMapFile &file; + bool isBigEndian; + uint32 pos; +}; +} // namespace maple +#endif diff --git a/src/hir2mpl/common/include/enhance_c_checker.h b/src/hir2mpl/common/include/enhance_c_checker.h new file mode 100644 index 0000000000000000000000000000000000000000..66eb5b720c32e934e9824d586b699ee0310e292f --- /dev/null +++ b/src/hir2mpl/common/include/enhance_c_checker.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_ENCCHECKER_H +#define HIR2MPL_INCLUDE_COMMON_ENCCHECKER_H +#include "feir_var.h" +#include "feir_stmt.h" +#include "ast_expr.h" +#include "ast_decl.h" + +namespace maple { +constexpr int64 kUndefValue = 0xdeadbeef; +static const char *kBoundsBuiltFunc = "__builtin_dynamic_bounds_cast"; +class ENCChecker { + public: + ENCChecker() = default; + ~ENCChecker() = default; + static bool HasNonnullAttrInExpr(MIRBuilder &mirBuilder, const UniqueFEIRExpr &expr, bool isNested = false); + static bool HasNullExpr(const UniqueFEIRExpr &expr); + static void CheckNonnullGlobalVarInit(const MIRSymbol &sym, const MIRConst *cst); + static void CheckNullFieldInGlobalStruct(MIRType &type, MIRAggConst &cst, const std::vector &initExprs); + static void CheckNonnullLocalVarInit(const MIRSymbol &sym, const ASTExpr *initExpr); + static void CheckNonnullLocalVarInit(const MIRSymbol &sym, const UniqueFEIRExpr &initFEExpr, + std::list &stmts); + static std::string GetNthStr(size_t index); + static std::string PrintParamIdx(const std::list &idxs); + static void CheckNonnullArgsAndRetForFuncPtr(const MIRType &dstType, const UniqueFEIRExpr &srcExpr, + uint32 fileNum, uint32 fileLine); + static bool HasNonnullFieldInStruct(const MIRType &mirType); + static bool HasNonnullFieldInPtrStruct(const MIRType &mirType); + static bool IsSameBoundary(const AttrBoundary &arg1, const AttrBoundary &arg2); + static void CheckBoundaryArgsAndRetForFuncPtr(const MIRType &dstType, const UniqueFEIRExpr &srcExpr, + uint32 fileNum, uint32 fileLine); + static UniqueFEIRExpr FindBaseExprInPointerOperation(const UniqueFEIRExpr &expr, bool isIncludingAddrof = false); + static MIRType *GetTypeFromAddrExpr(const UniqueFEIRExpr &expr); + static MIRType *GetArrayTypeFromExpr(const UniqueFEIRExpr &expr); + static MIRConst *GetMIRConstFromExpr(const UniqueFEIRExpr &expr); + static void AssignBoundaryVar(MIRBuilder &mirBuilder, const UniqueFEIRExpr &dstExpr, const UniqueFEIRExpr &srcExpr, + const UniqueFEIRExpr &lRealLenExpr, std::list &ans); + static void AssignUndefVal(MIRBuilder &mirBuilder, MIRSymbol &sym); + static std::string GetBoundaryName(const UniqueFEIRExpr &expr); + static bool IsGlobalVarInExpr(const UniqueFEIRExpr &expr); + static std::pair InsertBoundaryVar(MIRBuilder &mirBuilder, const UniqueFEIRExpr &expr); + static bool IsConstantIndex(const UniqueFEIRExpr &expr); + static void PeelNestedBoundaryChecking(std::list &stmts, const UniqueFEIRExpr &baseExpr); + static void ReduceBoundaryChecking(std::list &stmts, const UniqueFEIRExpr &expr); + static UniqueFEIRExpr GetRealBoundaryLenExprInFunc(const UniqueFEIRExpr &lenExpr, const ASTFunc &astFunc, + const ASTCallExpr &astCallExpr); + static UniqueFEIRExpr GetRealBoundaryLenExprInFuncByIndex(const TypeAttrs &typeAttrs, const MIRType &type, + const ASTCallExpr &astCallExpr); + static UniqueFEIRExpr GetRealBoundaryLenExprInField(const UniqueFEIRExpr &lenExpr, MIRStructType &baseType, + const UniqueFEIRExpr &dstExpr); + static void InitBoundaryVarFromASTDecl(const MapleAllocator &allocator, ASTDecl *ptrDecl, + ASTExpr *lenExpr, std::list &stmts); + static void InitBoundaryVar(MIRFunction &curFunction, const ASTDecl &ptrDecl, + UniqueFEIRExpr lenExpr, std::list &stmts); + static void InitBoundaryVar(MIRFunction &curFunction, const std::string &ptrName, MIRType &ptrType, + UniqueFEIRExpr lenExpr, std::list &stmts); + static std::pair InitBoundaryVar(MIRFunction &curFunction, const UniqueFEIRExpr &ptrExpr, + UniqueFEIRExpr lenExpr, std::list &stmts); + static UniqueFEIRExpr GetGlobalOrFieldLenExprInExpr(MIRBuilder &mirBuilder, const UniqueFEIRExpr &expr); + static void InsertBoundaryAssignChecking(MIRBuilder &mirBuilder, std::list &ans, + const UniqueFEIRExpr &srcExpr, uint32 fileIdx, uint32 fileLine); + static UniqueFEIRStmt InsertBoundaryLEChecking(UniqueFEIRExpr lenExpr, const UniqueFEIRExpr &srcExpr, + const UniqueFEIRExpr &dstExpr); + static void CheckBoundaryLenFinalAssign(MIRBuilder &mirBuilder, const UniqueFEIRVar &var, FieldID fieldID, + uint32 fileIdx, uint32 fileLine); + static void CheckBoundaryLenFinalAssign(MIRBuilder &mirBuilder, const UniqueFEIRType &addrType, FieldID fieldID, + uint32 fileIdx, uint32 fileLine); + static void CheckBoundaryLenFinalAddr(MIRBuilder &mirBuilder, const UniqueFEIRExpr &expr, + uint32 fileIdx, uint32 fileLine); + static MapleVector ReplaceBoundaryChecking(MIRBuilder &mirBuilder, const FEIRStmtNary *stmt); + static UniqueFEIRExpr GetBoundaryLenExprCache(uint32 hash); + static UniqueFEIRExpr GetBoundaryLenExprCache(const TypeAttrs &attr); + static UniqueFEIRExpr GetBoundaryLenExprCache(const FieldAttrs &attr); + static void InsertBoundaryInAtts(TypeAttrs &attr, const BoundaryInfo &boundary); + static void InsertBoundaryLenExprInAtts(TypeAttrs &attr, const UniqueFEIRExpr &expr); + static void InsertBoundaryInAtts(FieldAttrs &attr, const BoundaryInfo &boundary); + static void InsertBoundaryInAtts(FuncAttrs &attr, const BoundaryInfo &boundary); + static bool IsSafeRegion(const MIRBuilder &mirBuilder); + static bool IsUnsafeRegion(const MIRBuilder &mirBuilder); +}; // class ENCChecker +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_ENCCHECKER_H diff --git a/src/hir2mpl/common/include/fe_algorithm.h b/src/hir2mpl/common/include/fe_algorithm.h new file mode 100644 index 0000000000000000000000000000000000000000..7e7df74ad76b8974cec95f83cd35c931346aa046 --- /dev/null +++ b/src/hir2mpl/common/include/fe_algorithm.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_ALGORITHM_H +#define HIR2MPL_INCLUDE_COMMON_FE_ALGORITHM_H +#include +#include +#include +#include "types_def.h" +#include "fe_configs.h" + +namespace maple { +template +class CorrelativeMerge { + public: + using PtrMergeFunc = bool (T::*)(const T&); + using PtrMergableFunc = bool (T::*)() const; + CorrelativeMerge(std::map> &argCorrelationMap, PtrMergeFunc argPtrMergeFunc, + PtrMergableFunc argPtrMergableFunc) + : correlationMap(argCorrelationMap), + ptrMergeFunc(argPtrMergeFunc), + ptrMergableFunc(argPtrMergableFunc), + inLoop(false), + error(false), + success(false), + visitCount(0) {} + + ~CorrelativeMerge() = default; + void ProcessAll() { + visitCount = 0; + // loop check + LoopCheckAll(); + // process + CHECK_NULL_FATAL(ptrMergableFunc); + for (const std::pair> &item : correlationMap) { + T *dst = item.first; + CHECK_NULL_FATAL(dst); + if ((dst->*ptrMergableFunc)()) { + continue; + } + ProcessOne(*dst, true); + if (!success) { + error = true; + break; + } + } + } + + void LoopCheckAll() { + for (const std::pair> &item : correlationMap) { + visitedSet.clear(); + T *dst = item.first; + CHECK_NULL_FATAL(dst); + inLoop = false; + LoopCheck(*dst); + loopStatus[dst] = inLoop; + } + } + + void LoopCheck(T &dst) { + // loop check + if (visitedSet.find(&dst) != visitedSet.end()) { + inLoop = true; + return; + } + // correlation check + CHECK_FATAL(visitedSet.insert(&dst).second, "visitedSet insert failed"); + auto itCorr = correlationMap.find(&dst); + if (itCorr != correlationMap.end()) { + CHECK_NULL_FATAL(ptrMergableFunc); + for (T *src : itCorr->second) { + CHECK_NULL_FATAL(src); + if (!(src->*ptrMergableFunc)()) { + LoopCheck(*src); + if (inLoop) { + return; + } + } + } + } + } + + void ProcessOne(T &dst, bool first) { + if (first) { + success = true; + visitedSet.clear(); + } + // loop check + visitCount++; + // correlation end check + auto itCorr = correlationMap.find(&dst); + if (itCorr == correlationMap.end()) { + return; + } + CHECK_FATAL(visitedSet.insert(&dst).second, "visitedSet insert failed"); + // correlation check + auto itLoopStatus = loopStatus.find(&dst); + ASSERT(itLoopStatus != loopStatus.end(), "loop status not existed"); + bool updated = (first || !itLoopStatus->second); + if (ptrMergableFunc == nullptr || ptrMergeFunc == nullptr) { + CHECK_FATAL(false, "nullptr error."); + } + for (T *src : itCorr->second) { + CHECK_NULL_FATAL(src); + if (correlationMap.find(src) == correlationMap.end()) { + success = success && (dst.*ptrMergeFunc)(*src); + } else if ((src->*ptrMergableFunc)()) { + success = success && (dst.*ptrMergeFunc)(*src); + } else if (updatedSet.find(src) != updatedSet.end()) { + success = success && (dst.*ptrMergeFunc)(*src); + } else { + if (visitedSet.find(src) == visitedSet.end()) { + ProcessOne(*src, false); + success = success && (dst.*ptrMergeFunc)(*src); + } + } + } + if (!updated) { + return; + } + if (updatedSet.find(&dst) == updatedSet.end()) { + CHECK_FATAL(updatedSet.insert(&dst).second, "updatedSet insert failed"); + } + } + + uint32 GetVisitCount() const { + return visitCount; + } + + bool GetError() const { + return error; + } + + LLT_PRIVATE: + std::map> &correlationMap; + PtrMergeFunc ptrMergeFunc; + PtrMergableFunc ptrMergableFunc; + std::set visitedSet; + std::set updatedSet; + std::map loopStatus; + bool inLoop : 1; + bool error : 1; + bool success : 1; + uint32 visitCount; +}; // class CorrelativeMerge +} // namespace maple +#endif diff --git a/src/hir2mpl/common/include/fe_config_parallel.h b/src/hir2mpl/common/include/fe_config_parallel.h new file mode 100644 index 0000000000000000000000000000000000000000..6ef8c11163d851a9e3e78a3128a286742c6ebabe --- /dev/null +++ b/src/hir2mpl/common/include/fe_config_parallel.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_CONFIG_PARALLEL_H +#define HIR2MPL_INCLUDE_COMMON_FE_CONFIG_PARALLEL_H +#include +#include +#include +#include "types_def.h" +#include "mpl_logging.h" + +namespace maple { +class FEConfigParallel { + public: + FEConfigParallel(); + ~FEConfigParallel() = default; + static FEConfigParallel &GetInstance() { + return instance; + } + + uint32 GetNThread() const { + return nThread; + } + + void EnableParallel() { + enableParallel = true; + } + + void DisableParallel() { + enableParallel = false; + } + + bool IsInParallelMode() const { + return enableParallel && (nThread > 1); + } + + void RegisterRunThreadID(const std::thread::id &tid) { + mtx.lock(); + CHECK_FATAL(runThreadIDs.insert(tid).second == true, "failed to register thread id"); + mtx.unlock(); + } + + bool RunThreadParallelForbidden() { + if (!enableParallel) { + return false; + } + std::thread::id tid = std::this_thread::get_id(); + return runThreadIDs.find(tid) != runThreadIDs.end(); + } + + void RunThreadIDCleanUp() { + runThreadIDs.clear(); + } + + private: + static FEConfigParallel instance; + uint32 nThread; + bool enableParallel; + std::set runThreadIDs; + std::mutex mtx; +}; + +#define HIR2MPL_PARALLEL_FORBIDDEN() \ + do { \ + if (FEConfigParallel::GetInstance().RunThreadParallelForbidden()) { \ + maple::logInfo.EmitErrorMessage("HIR2MPL_PARALLEL_FORBIDDEN", __FILE__, __LINE__, "\n"); \ + FATAL(kLncFatal, "Forbidden invocation in parallel run thread"); \ + } \ + } while (0) +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FE_PARALLEL_CONFIG_H diff --git a/src/hir2mpl/common/include/fe_configs.h b/src/hir2mpl/common/include/fe_configs.h new file mode 100644 index 0000000000000000000000000000000000000000..b6088219f3ffa7b4aefbbd9a109e802aa41a751f --- /dev/null +++ b/src/hir2mpl/common/include/fe_configs.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_CONFIGS_H +#define HIR2MPL_INCLUDE_COMMON_FE_CONFIGS_H +#include "types_def.h" + +#if ENABLE_COV_CHECK == 1 +#define LLT_MOCK_TARGET virtual +#define LLT_MOCK_TARGET_VIRTUAL virtual +#define LLT_PUBLIC public +#define LLT_PROTECTED public +#define LLT_PRIVATE public +#else +#define LLT_MOCK_TARGET +#define LLT_MOCK_TARGET_VIRTUAL virtual +#define LLT_PUBLIC public +#define LLT_PROTECTED protected +#define LLT_PRIVATE private +#endif + +namespace maple { +using TypeDim = uint8; + +class FEConstants { + public: + const static uint8 kDimMax = UINT8_MAX; +}; // class FEContants +} // namespace maple + +#include "fe_config_parallel.h" +#endif // HIR2MPL_INCLUDE_COMMON_FE_CONFIGS_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/fe_diag_manager.h b/src/hir2mpl/common/include/fe_diag_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..0a2280f9b8c2c7751e6575386120853e68280f69 --- /dev/null +++ b/src/hir2mpl/common/include/fe_diag_manager.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_DIAG_MANAGER_H +#define HIR2MPL_INCLUDE_COMMON_FE_DIAG_MANAGER_H +#include +#include + +namespace maple { +enum FEErrno : int { + kNoError = 0, + kCmdParseError = 1, + kNoValidInput = 2, + kFEError = 3, +}; + +class FEDiagManager { + public: + FEDiagManager() = default; + ~FEDiagManager() = default; + + void IncErrNum(); + int GetDiagRes() const; + + private: + uint errNum = 0; + mutable std::mutex errNumMtx; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FE_DIAG_MANAGER_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/fe_file_ops.h b/src/hir2mpl/common/include/fe_file_ops.h new file mode 100644 index 0000000000000000000000000000000000000000..0102587f171292bd9f032f5461c39b2fdd2b1b4c --- /dev/null +++ b/src/hir2mpl/common/include/fe_file_ops.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_FILE_OPS_H +#define HIR2MPL_INCLUDE_COMMON_FE_FILE_OPS_H +#include + +namespace maple { +class FEFileOps { + public: + static std::string GetFilePath(const std::string &pathName); + static std::string GetFileNameWithExt(const std::string &pathName); + static std::string GetFileName(const std::string &pathName); + static std::string GetFileExtName(const std::string &pathName); + + private: + FEFileOps() = default; + ~FEFileOps() = default; +}; +} // namespace maple +#endif \ No newline at end of file diff --git a/src/hir2mpl/common/include/fe_file_type.h b/src/hir2mpl/common/include/fe_file_type.h new file mode 100644 index 0000000000000000000000000000000000000000..b4e51d55513c211e7e942cb2fb2d8c70c2b0bb38 --- /dev/null +++ b/src/hir2mpl/common/include/fe_file_type.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_FILE_TYPE_H +#define HIR2MPL_INCLUDE_COMMON_FE_FILE_TYPE_H +#include +#include +#include "types_def.h" +#include "basic_io.h" + +namespace maple { +class FEFileType { + public: + enum FileType { + kUnknownType, + kClass, + kJar, + kDex, + kAST, + kMAST, + }; + + inline static FEFileType &GetInstance() { + return fileType; + } + + FileType GetFileTypeByExtName(const std::string &extName) const; + FileType GetFileTypeByPathName(const std::string &pathName) const; + FileType GetFileTypeByMagicNumber(const std::string &pathName) const; + FileType GetFileTypeByMagicNumber(BasicIOMapFile &file) const; + FileType GetFileTypeByMagicNumber(uint32 magic) const; + void Reset(); + void LoadDefault(); + void RegisterExtName(FileType fileType, const std::string &extName); + void RegisterMagicNumber(FileType fileType, uint32 magicNumber); + static std::string GetPath(const std::string &pathName); + static std::string GetName(const std::string &pathName, bool withExt = true); + static std::string GetExtName(const std::string &pathName); + + private: + static FEFileType fileType; + static const uint32 kMagicClass = 0xBEBAFECA; + static const uint32 kMagicZip = 0x04034B50; + static const uint32 kMagicDex = 0x0A786564; + static const uint32 kMagicAST = 0x48435043; + static const uint32 kMagicMAST = 0xAB4C504D; + std::map mapExtNameType; + std::map mapTypeMagic; + std::map mapMagicType; + + FEFileType(); + ~FEFileType() = default; +}; +} +#endif diff --git a/src/hir2mpl/common/include/fe_function.h b/src/hir2mpl/common/include/fe_function.h new file mode 100644 index 0000000000000000000000000000000000000000..68ba49da312ca6ac4054973d999a92c01ec143d9 --- /dev/null +++ b/src/hir2mpl/common/include/fe_function.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_FUNCTION_H +#define HIR2MPL_INCLUDE_COMMON_FE_FUNCTION_H +#include +#include +#include +#include "types_def.h" +#include "mempool_allocator.h" +#include "safe_ptr.h" +#include "mir_function.h" +#include "fe_utils.h" +#include "feir_bb.h" +#include "feir_stmt.h" +#include "fe_timer_ns.h" +#include "feir_lower.h" +#include "feir_cfg.h" +#include "fe_function_phase_result.h" +#include "feir_type_infer.h" + +namespace maple { +#define SET_FUNC_INFO_PAIR(A, B, C, D) \ + A.PushbackMIRInfo(MIRInfoPair(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(B), C)); \ + A.PushbackIsString(D) + +class FEFunction { + public: + FEFunction(MIRFunction &argMIRFunction, const std::unique_ptr &argPhaseResultTotal); + virtual ~FEFunction(); + + // element memory manage method + FEIRStmt *RegisterGeneralStmt(std::unique_ptr stmt); + const std::unique_ptr &RegisterGeneralStmtUniqueReturn(std::unique_ptr stmt); + FEIRBB *RegisterFEIRBB(std::unique_ptr bb); + FEIRStmt *RegisterFEIRStmt(UniqueFEIRStmt stmt); + std::string GetDescription(); + void OutputUseDefChain(); + void OutputDefUseChain(); + + void SetSrcFileName(const std::string &fileName) { + srcFileName = fileName; + } + + const FEIRStmt *GetFEIRStmtHead() const { + ASSERT_NOT_NULL(feirStmtHead); + return feirStmtHead; + } + + const FEIRStmt *GetFEIRStmtTail() const { + ASSERT_NOT_NULL(feirStmtTail); + return feirStmtTail; + } + + void Init() { + InitImpl(); + } + + void AppendFEIRStmts(std::list &stmts); + void InsertFEIRStmtsBefore(FEIRStmt &pos, std::list &stmts); + + void PreProcess() { + PreProcessImpl(); + } + + bool Process() { + return ProcessImpl(); + } + + void Finish() { + FinishImpl(); + } + + uint32 GetStmtCount() const { + return stmtCount; + } + + std::unordered_map> &GetBoundaryMap() { + return boundaryMap; + } + + const std::unordered_map> &GetBoundaryMap() const { + return boundaryMap; + } + + void SetBoundaryMap(uint32 tag, const std::pair &boundaryVar) { + boundaryMap[tag] = boundaryVar; + } + + std::stack &GetSafeRegionFlag() { + return safeRegionFlag; + } + + const std::stack &GetSafeRegionFlag() const { + return safeRegionFlag; + } + + LLT_PROTECTED: + // run phase routines + virtual bool GenerateGeneralStmt(const std::string &phaseName) = 0; + virtual bool LabelGeneralStmts(const std::string &phaseName); + virtual bool LabelFEIRBBs(const std::string &phaseName); + virtual bool ProcessFEIRFunction(); + + virtual bool GenerateArgVarList(const std::string &phaseName) = 0; + virtual bool GenerateAliasVars(const std::string &phaseName) = 0; + virtual bool EmitToFEIRStmt(const std::string &phaseName) = 0; + virtual bool BuildMapLabelStmt(const std::string &phaseName); + virtual bool SetupFEIRStmtJavaTry(const std::string &phaseName); + virtual bool SetupFEIRStmtBranch(const std::string &phaseName); + virtual bool UpdateRegNum2This(const std::string &phaseName); + bool LowerFunc(const std::string &phaseName); + bool DumpFEIRBBs(const std::string &phaseName); + bool DumpFEIRCFGGraph(const std::string &phaseName); + bool BuildFEIRDFG(const std::string &phaseName); // process fe ir check point, build fe ir DFG + bool BuildFEIRUDDU(const std::string &phaseName); // build fe ir UD DU chain + bool TypeInfer(const std::string &phaseName); // feir based Type Infer + + // finish phase routines + bool BuildGeneralStmtBBMap(const std::string &phaseName); + bool UpdateFormal(const std::string &phaseName); + virtual bool EmitToMIR(const std::string &phaseName); + + // interface methods + virtual void InitImpl(); + virtual void PreProcessImpl() {} + virtual bool ProcessImpl() { + return true; + } + + virtual void FinishImpl() {} + virtual bool PreProcessTypeNameIdx() = 0; + virtual void GenerateGeneralStmtFailCallBack() = 0; + virtual void GenerateGeneralDebugInfo() = 0; + virtual bool VerifyGeneral() = 0; + virtual void VerifyGeneralFailCallBack() = 0; + virtual void DumpGeneralStmts(); + virtual std::string GetGeneralFuncName() const; + void EmitToMIRStmt(); + + void PhaseTimerStart(FETimerNS &timer); + void PhaseTimerStopAndDump(FETimerNS &timer, const std::string &label); + virtual void DumpFEIRCFGGraphForDFGEdge(std::ofstream &file); + virtual bool HasThis() = 0; + virtual bool IsNative() = 0; + void BuildMapLabelIdx(); + bool CheckPhaseResult(const std::string &phaseName); + + FEIRStmt *genStmtHead; + FEIRStmt *genStmtTail; + std::list genStmtListRaw; + FEIRBB *genBBHead; + FEIRBB *genBBTail; + FEIRStmt *feirStmtHead; + FEIRStmt *feirStmtTail; + FEIRBB *feirBBHead; + FEIRBB *feirBBTail; + std::unique_ptr feirLower; + std::unique_ptr feirCFG; + std::map genStmtBBMap; + std::vector> argVarList; + std::map mapLabelIdx; + std::map mapLabelStmt; + FEFunctionPhaseResult phaseResult; + const std::unique_ptr &phaseResultTotal; + std::string srcFileName = ""; + MIRSrcLang srcLang = kSrcLangJava; + MIRFunction &mirFunction; + + LLT_PRIVATE: + void OutputStmts(); + bool SetupFEIRStmtGoto(FEIRStmtGoto &stmt); + bool SetupFEIRStmtSwitch(FEIRStmtSwitch &stmt); + const FEIRStmtPesudoLOC *GetLOCForStmt(const FEIRStmt &feStmt) const; + void AddLocForStmt(const FEIRStmt &feIRStmt, std::list &mirStmts) const; + void LabelFEIRStmts(); // label fe ir stmts + FEIRBB *NewFEIRBB(uint32 &id); + bool IsBBEnd(const FEIRStmt &stmt) const; + bool MayBeBBEnd(const FEIRStmt &stmt) const; + bool ShouldNewBB(const FEIRBB *currBB, const FEIRStmt &currStmt) const; + void LinkFallThroughBBAndItsNext(FEIRBB &bb); + void LinkBranchBBAndItsTargets(FEIRBB &bb); + void LinkGotoBBAndItsTarget(FEIRBB &bb, const FEIRStmt &stmtTail); + void LinkSwitchBBAndItsTargets(FEIRBB &bb, const FEIRStmt &stmtTail); + void LinkBB(FEIRBB &predBB, FEIRBB &succBB); + FEIRBB &GetFEIRBBByStmt(const FEIRStmt &stmt); + bool CheckBBsStmtNoAuxTail(const FEIRBB &bb); + void ProcessCheckPoints(); + void InsertCheckPointForBBs(); + void InsertCheckPointForTrys(); + void InitFirstVisibleStmtForCheckPoints(); + void InitFEIRStmtCheckPointMap(); + void RegisterDFGNodes2CheckPoints(); + void RegisterDFGNodesForFuncParameters(); + void RegisterDFGNodesForStmts(); + bool CalculateDefs4AllUses(); + void InitTrans4AllVars(); + void InsertRetypeStmtsAfterDef(const UniqueFEIRVar& def); + FEIRStmtPesudoJavaTry2 &GetJavaTryByCheckPoint(FEIRStmtCheckPoint &checkPoint); + FEIRStmtCheckPoint &GetCheckPointByFEIRStmt(const FEIRStmt &stmt); + void SetUpDefVarTypeScatterStmtMap(); + FEIRStmt &GetStmtByDefVarTypeScatter(const FEIRVarTypeScatter &varTypeScatter); + void InsertRetypeStmt(const FEIRVarTypeScatter &fromVar, const FEIRType &toType); + void InsertCvtStmt(const FEIRVarTypeScatter &fromVar, const FEIRType &toType); + void InsertJavaMergeStmt(const FEIRVarTypeScatter &fromVar, const FEIRType &toType); + void InsertDAssignStmt4TypeCvt(const FEIRVarTypeScatter &fromVar, const FEIRType &toType, UniqueFEIRExpr expr); + bool WithFinalFieldsNeedBarrier(MIRClassType *classType, bool isStatic) const; + bool IsNeedInsertBarrier(); + + std::list> genStmtList; + std::list> genBBList; + // FeirStmts generated by feirLower are inserted after the kStmtPesudoFuncEnd and linked, + // Access sequential feirStmt instructions through a doubly linked FELinkListNode from feirStmtHead + std::list feirStmtList; + std::list> feirBBList; + std::map feirStmtBBMap; + std::map feirStmtCheckPointMap; + std::map checkPointJavaTryMap; + std::unique_ptr typeInfer; + uint32 stmtCount = 0; + std::map defVarTypeScatterStmtMap; + std::unordered_map> boundaryMap; // EnhanceC boundary var + std::stack safeRegionFlag; // EnhanceC saferegion(true: safe, false: unsafe) +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FE_FUNCTION_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/fe_function_phase_result.h b/src/hir2mpl/common/include/fe_function_phase_result.h new file mode 100644 index 0000000000000000000000000000000000000000..192981ed3e1af05ac45b3bbbe2d36ea515c7b375 --- /dev/null +++ b/src/hir2mpl/common/include/fe_function_phase_result.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_FUNCTION_PHASE_RESULT_H +#define HIR2MPL_INCLUDE_COMMON_FE_FUNCTION_PHASE_RESULT_H +#include +#include +#include +#include "types_def.h" +#include "fe_timer_ns.h" + +namespace maple { +class FEFunctionPhaseResult { + public: + explicit FEFunctionPhaseResult(bool argRecordTime = false) + : recordTime(argRecordTime), + success(true), + enable(true) {} + + ~FEFunctionPhaseResult() = default; + void Combine(const FEFunctionPhaseResult &result); + void Dump(); + void DumpMS(); + bool Finish(bool isSuccess); + bool Finish() { + return Finish(success); + } + + void Start() { + if (enable && recordTime) { + timer.Start(); + } + } + + bool IsSuccess() const { + return success; + } + + void Disable() { + enable = false; + } + + void Enable() { + enable = true; + } + + void RegisterPhaseName(const std::string &name) { + if (enable && recordTime) { + currPhaseName = name; + phaseNames.push_back(name); + } + } + + void RegisterPhaseNameAndStart(const std::string &name) { + if (enable && recordTime) { + currPhaseName = name; + phaseNames.push_back(name); + timer.Start(); + } + } + + private: + FETimerNS timer; + bool recordTime : 1; + bool success : 1; + bool enable : 1; + std::string currPhaseName = ""; + std::list phaseNames; + std::map phaseTimes; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FE_FUNCTION_PHASE_RESULT_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/fe_input.h b/src/hir2mpl/common/include/fe_input.h new file mode 100644 index 0000000000000000000000000000000000000000..369cdfe46bef2e1b82381337dbad4b45cd57704a --- /dev/null +++ b/src/hir2mpl/common/include/fe_input.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FE_INPUT_H +#define HIR2MPL_INCLUDE_FE_INPUT_H +#include +#include "global_tables.h" +#include "mir_module.h" +#include "mpl_logging.h" + +namespace maple { +class FEInputUnit { + public: + FEInputUnit() {} + virtual ~FEInputUnit() = default; + GStrIdx GetNameIdxOrin() { + return GetNameIdxOrinImpl(); + } + + GStrIdx GetNameIdxMpl() { + return GetNameIdxMplImpl(); + } + + std::string GetCatagoryName() { + return GetCatagoryNameImpl(); + } + + protected: + virtual GStrIdx GetNameIdxOrinImpl() = 0; + virtual GStrIdx GetNameIdxMplImpl() = 0; + virtual std::string GetCatagoryNameImpl() = 0; +}; + +enum FEInputSameNamePolicy { + kUseFirst, + kUseNewest, + kFatalOnce, + kFatalAll +}; + +template +class FEInputContent { + public: + FEInputContent(MapleAllocator &alloc); + ~FEInputContent() = default; + void RegisterItem(T &item); + void CheckSameName(); + + private: + MapleAllocator &allocator; + MapleList items; + MapleUnorderedMap nameItemMap; + MapleList sameNames; + FEInputSameNamePolicy policySameName; + + void EraseItem(GStrIdx nameIdxMpl); +}; + +class FEInputUnitExt { +}; + +class FEInputProgramUnit { +}; + +class FEInputUnitMethod : public FEInputUnit { + public: + FEInputUnitMethod(MapleAllocator &alloc); + ~FEInputUnitMethod() = default; + + protected: + std::string GetCatagoryNameImpl() override; + + MapleAllocator &allocator; +}; + +class FEInputUnitVariable : public FEInputUnit { + public: + FEInputUnitVariable(MapleAllocator &alloc); + ~FEInputUnitVariable() = default; + + protected: + std::string GetCatagoryNameImpl() override; + + MapleAllocator &allocator; +}; + +class FEInputUnitStruct : public FEInputUnit { + public: + explicit FEInputUnitStruct(MapleAllocator &alloc); + virtual ~FEInputUnitStruct() = default; + MIRTypeKind GetMIRTypeKind() const { + return typeKind; + } + + protected: + std::string GetCatagoryNameImpl() override; + + MapleAllocator &allocator; + FEInputContent methods; + FEInputContent methodsStatic; + FEInputContent fields; + FEInputContent fieldsStatic; + MIRTypeKind typeKind; +}; +} // namespace maple +#endif diff --git a/src/hir2mpl/common/include/fe_input_helper.h b/src/hir2mpl/common/include/fe_input_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..4faa813c13467fb15fbe8e3c594dcda065e8f48f --- /dev/null +++ b/src/hir2mpl/common/include/fe_input_helper.h @@ -0,0 +1,437 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FE_INPUT_HELPER_H +#define HIR2MPL_INCLUDE_FE_INPUT_HELPER_H +#include "mempool_allocator.h" +#include "mir_type.h" +#include "mir_pragma.h" +#include "mir_symbol.h" +#include "feir_type.h" +#include "fe_function.h" + +namespace maple { +typedef struct { + std::string klass; + std::string field; + std::string type; + std::string attr; +} ExtraField; + +class FEInputContainer { + public: + FEInputContainer() = default; + virtual ~FEInputContainer() = default; + MIRStructType *GetContainer() { + return GetContainerImpl(); + } + + protected: + virtual MIRStructType *GetContainerImpl() = 0; +}; + +class FEInputPragmaHelper { + public: + FEInputPragmaHelper() = default; + virtual ~FEInputPragmaHelper() = default; + std::vector &GenerateMIRPragmas() { + return GenerateMIRPragmasImpl(); + } + + protected: + virtual std::vector &GenerateMIRPragmasImpl() = 0; +}; + +class FEInputStructHelper; + +class FEInputGlobalVarHelper { + public: + FEInputGlobalVarHelper(MapleAllocator &allocatorIn) : allocator(allocatorIn) {} + virtual ~FEInputGlobalVarHelper() = default; + + bool ProcessDecl() { + return ProcessDecl(allocator); + } + + bool ProcessDecl(MapleAllocator &allocatorIn) { + return ProcessDeclImpl(allocatorIn); + } + + protected: + MapleAllocator &allocator; + virtual bool ProcessDeclImpl(MapleAllocator &allocator) = 0; +}; + +class FEInputFileScopeAsmHelper { + public: + FEInputFileScopeAsmHelper(MapleAllocator &allocatorIn) : allocator(allocatorIn) {} + virtual ~FEInputFileScopeAsmHelper() = default; + + bool ProcessDecl() { + return ProcessDecl(allocator); + } + + bool ProcessDecl(MapleAllocator &allocatorIn) { + return ProcessDeclImpl(allocatorIn); + } + + protected: + MapleAllocator &allocator; + virtual bool ProcessDeclImpl(MapleAllocator &allocator) = 0; +}; + +class FEInputFieldHelper { + public: + FEInputFieldHelper(MapleAllocator &allocator) {} + virtual ~FEInputFieldHelper() = default; + const FieldPair &GetMIRFieldPair() const { + return mirFieldPair; + } + + bool IsStatic() const { + return mirFieldPair.second.second.GetAttr(FLDATTR_static); + } + + bool ProcessDecl(MapleAllocator &allocator) { + return ProcessDeclImpl(allocator); + } + + bool ProcessDeclWithContainer(MapleAllocator &allocator) { + return ProcessDeclWithContainerImpl(allocator); + } + + static void SetFieldAttribute(const std::string &name, FieldAttrs &attr) { +#define FIELD_ATTR +#define ATTR(A) \ + if (!strcmp(name.c_str(), #A)) { \ + attr.SetAttr(FLDATTR_##A); \ + return; \ + } +#include "all_attributes.def" +#undef ATTR +#undef FIELD_ATTR + } + + protected: + virtual bool ProcessDeclImpl(MapleAllocator &allocator) = 0; + virtual bool ProcessDeclWithContainerImpl(MapleAllocator &allocator) = 0; + FieldPair mirFieldPair; +}; + +class FEInputMethodHelper { + public: + FEInputMethodHelper(MapleAllocator &allocatorIn) + : allocator(allocatorIn), + srcLang(kSrcLangUnknown), + feFunc(nullptr), + mirFunc(nullptr), + retType(nullptr), + argTypes(allocator.Adapter()), + retMIRType(nullptr), + argMIRTypes(allocator.Adapter()), + methodNameIdx(GStrIdx(0)) {} + + virtual ~FEInputMethodHelper() { + feFunc = nullptr; + mirFunc = nullptr; + retType = nullptr; + retMIRType = nullptr; + } + + const MethodPair &GetMIRMethodPair() const { + return mirMethodPair; + } + + const FEIRType *GetReturnType() const { + return retType; + } + + const MapleVector &GetArgTypes() const { + return argTypes; + } + + bool ProcessDecl() { + return ProcessDecl(allocator); + } + + bool ProcessDecl(MapleAllocator &allocatorIn) { + return ProcessDeclImpl(allocatorIn); + } + + void SolveReturnAndArgTypes(MapleAllocator &allocatorIn) { + SolveReturnAndArgTypesImpl(allocatorIn); + } + + std::string GetMethodName(bool inMpl, bool full = true) const { + return GetMethodNameImpl(inMpl, full); + } + + FuncAttrs GetAttrs() const { + return GetAttrsImpl(); + } + + bool IsStatic() const { + return IsStaticImpl(); + } + + bool IsVirtual() const { + return IsVirtualImpl(); + } + + bool IsNative() const { + return IsNativeImpl(); + } + + bool IsVarg() const { + return IsVargImpl(); + } + + bool HasThis() const { + return HasThisImpl(); + } + + MIRType *GetTypeForThis() const { + return GetTypeForThisImpl(); + } + + GStrIdx GetMethodNameIdx() const { + return methodNameIdx; + } + + bool HasCode() const { + return HasCodeImpl(); + } + + void SetClassTypeInfo(const MIRStructType &structType) { + mirFunc->SetClassTyIdx(structType.GetTypeIndex()); + } + + protected: + virtual bool ProcessDeclImpl(MapleAllocator &allocator); + virtual void SolveReturnAndArgTypesImpl(MapleAllocator &allocator) = 0; + virtual std::string GetMethodNameImpl(bool inMpl, bool full) const = 0; + virtual FuncAttrs GetAttrsImpl() const = 0; + virtual bool IsStaticImpl() const = 0; + virtual bool IsVirtualImpl() const = 0; + virtual bool IsNativeImpl() const = 0; + virtual bool IsVargImpl() const = 0; + virtual bool HasThisImpl() const = 0; + virtual MIRType *GetTypeForThisImpl() const = 0; + virtual bool HasCodeImpl() const = 0; + + MapleAllocator &allocator; + MIRSrcLang srcLang; + FEFunction *feFunc; + MIRFunction *mirFunc; + MethodPair mirMethodPair; + FEIRType *retType; + MapleVector argTypes; + // Added MIRType to support C and extended to Java later. + MIRType *retMIRType; + MapleVector argMIRTypes; + GStrIdx methodNameIdx; +}; + +class FEInputStructHelper : public FEInputContainer { + public: + explicit FEInputStructHelper(MapleAllocator &allocatorIn) + : allocator(allocatorIn), + mirStructType(nullptr), + mirSymbol(nullptr), + fieldHelpers(allocator.Adapter()), + methodHelpers(allocator.Adapter()), + pragmaHelper(nullptr), + staticFieldsConstVal(allocator.Adapter()), + isSkipped(false), + srcLang(kSrcLangJava) {} + + virtual ~FEInputStructHelper() { + mirStructType = nullptr; + mirSymbol = nullptr; + pragmaHelper = nullptr; + } + + bool IsSkipped() const { + return isSkipped; + } + + const TypeAttrs GetStructAttributeFromSymbol() const { + if (mirSymbol != nullptr) { + return mirSymbol->GetAttrs(); + } + return TypeAttrs(); + } + + MIRSrcLang GetSrcLang() const { + return srcLang; + } + + const MapleList &GetMethodHelpers() const { + return methodHelpers; + } + + bool PreProcessDecl() { + return PreProcessDeclImpl(); + } + + bool ProcessDecl() { + return ProcessDeclImpl(); + } + + std::string GetStructNameOrin() const { + return GetStructNameOrinImpl(); + } + + std::string GetStructNameMpl() const { + return GetStructNameMplImpl(); + } + + std::list GetSuperClassNames() const { + return GetSuperClassNamesImpl(); + } + + std::vector GetInterfaceNames() const { + return GetInterfaceNamesImpl(); + } + + std::string GetSourceFileName() const { + return GetSourceFileNameImpl(); + } + + std::string GetSrcFileName() const { + return GetSrcFileNameImpl(); + } + + MIRStructType *CreateMIRStructType(bool &error) const { + return CreateMIRStructTypeImpl(error); + } + + TypeAttrs GetStructAttributeFromInput() const { + return GetStructAttributeFromInputImpl(); + } + + uint64 GetRawAccessFlags() const { + return GetRawAccessFlagsImpl(); + } + + GStrIdx GetIRSrcFileSigIdx() const { + return GetIRSrcFileSigIdxImpl(); + } + + bool IsMultiDef() const { + return IsMultiDefImpl(); + } + + void InitFieldHelpers() { + InitFieldHelpersImpl(); + } + + void InitMethodHelpers() { + InitMethodHelpersImpl(); + } + + void SetPragmaHelper(FEInputPragmaHelper *pragmaHelperIn) { + pragmaHelper = pragmaHelperIn; + } + + void SetStaticFieldsConstVal(const std::vector &val) { + staticFieldsConstVal.resize(val.size()); + for (uint32 i = 0; i < val.size(); ++i) { + staticFieldsConstVal[i] = val[i]; + } + } + + void SetFinalStaticStringIDVec(const std::vector &stringIDVec) { + finalStaticStringID = stringIDVec; + } + + void SetIsOnDemandLoad(bool flag) { + isOnDemandLoad = flag; + } + + void ProcessPragma(); + + protected: + MIRStructType *GetContainerImpl(); + virtual bool PreProcessDeclImpl(); + virtual bool ProcessDeclImpl(); + virtual std::string GetStructNameOrinImpl() const = 0; + virtual std::string GetStructNameMplImpl() const = 0; + virtual std::list GetSuperClassNamesImpl() const = 0; + virtual std::vector GetInterfaceNamesImpl() const = 0; + virtual std::string GetSourceFileNameImpl() const = 0; + virtual std::string GetSrcFileNameImpl() const; + virtual MIRStructType *CreateMIRStructTypeImpl(bool &error) const = 0; + virtual TypeAttrs GetStructAttributeFromInputImpl() const = 0; + virtual uint64 GetRawAccessFlagsImpl() const = 0; + virtual GStrIdx GetIRSrcFileSigIdxImpl() const = 0; + virtual bool IsMultiDefImpl() const = 0; + virtual void InitFieldHelpersImpl() = 0; + virtual void InitMethodHelpersImpl() = 0; + void CreateSymbol(); + void ProcessDeclSuperClass(); + void ProcessDeclSuperClassForJava(); + void ProcessDeclImplements(); + void ProcessDeclDefInfo(); + void ProcessDeclDefInfoSuperNameForJava(); + void ProcessDeclDefInfoImplementNameForJava(); + void ProcessFieldDef(); + void ProcessExtraFields(); + void ProcessMethodDef(); + void ProcessStaticFields(); + + MapleAllocator &allocator; + MIRStructType *mirStructType; + MIRSymbol *mirSymbol; + MapleList fieldHelpers; + MapleList methodHelpers; + FEInputPragmaHelper *pragmaHelper; + MapleVector staticFieldsConstVal; + std::vector finalStaticStringID; + bool isSkipped; + MIRSrcLang srcLang; + bool isOnDemandLoad = false; +}; + +class FEInputHelper { + public: + explicit FEInputHelper(MapleAllocator &allocatorIn) + : allocator(allocatorIn), + fieldHelpers(allocator.Adapter()), + methodHelpers(allocator.Adapter()), + structHelpers(allocator.Adapter()) {} + ~FEInputHelper() = default; + bool PreProcessDecl(); + bool ProcessDecl(); + bool ProcessImpl() const; + void RegisterFieldHelper(FEInputFieldHelper &helper) { + fieldHelpers.push_back(&helper); + } + + void RegisterMethodHelper(FEInputMethodHelper &helper) { + methodHelpers.push_back(&helper); + } + + void RegisterStructHelper(FEInputStructHelper &helper) { + structHelpers.push_back(&helper); + } + + private: + MapleAllocator &allocator; + MapleList fieldHelpers; + MapleList methodHelpers; + MapleList structHelpers; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_FE_INPUT_HELPER_H diff --git a/src/hir2mpl/common/include/fe_java_string_manager.h b/src/hir2mpl/common/include/fe_java_string_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..9b372074bb8b5f07ce017f8de10222304dcc58e7 --- /dev/null +++ b/src/hir2mpl/common/include/fe_java_string_manager.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_JAVA_STRING_MANAGER_H +#define HIR2MPL_INCLUDE_COMMON_FE_JAVA_STRING_MANAGER_H +#include +#include +#include +#include "mir_module.h" +#include "mir_builder.h" + +namespace maple { +class FEJavaStringManager { + public: + FEJavaStringManager(MIRModule &argModule, MIRBuilder &mirBuilderIn); + ~FEJavaStringManager(); + void ClearStringMetaClassSymbolExternFlag(); + // profiling + void LoadProfilingData(const std::string &profileFileName); + MIRSymbol *GetLiteralPtrVar(const MIRSymbol *var) const; + MIRSymbol *GetLiteralPtrVar(const std::string &str) const; + MIRSymbol *GetLiteralPtrVar(const std::u16string &strU16) const; + // methods for string + MIRSymbol *CreateLiteralVar(MIRBuilder &mirBuilder, const std::string &str, bool isFieldValue); + MIRSymbol *CreateLiteralVar(MIRBuilder &mirBuilder, const std::u16string &strU16, bool isFieldValue); + MIRSymbol *GetLiteralVar(const std::string &str) const; + MIRSymbol *GetLiteralVar(const std::u16string &strU16) const; + static std::string GetLiteralGlobalName(const std::u16string &strU16); + static bool IsAllASCII(const std::u16string &strU16); + void GenStringMetaClassVar(); + + private: + using DWBuffer = struct { + uint64_t data; + uint32_t pos; + }; + + MIRArrayType *ConstructArrayType4Str(const std::u16string &strU16, bool compressible) const; + MIRAggConst *CreateByteArrayConst(const std::u16string &str, MIRArrayType &byteArrayType, bool compressible) const; + static std::vector SwapBytes(const std::u16string &strU16); + static uint16 ExchangeBytesPosition(uint16 input); + template + static void AddDataIntoByteArray(MIRAggConst &newConst, MemPool &mp, DWBuffer &buf, T data, MIRType &uInt64); + static void FinishByteArray(MIRAggConst &newConst, MemPool &mp, DWBuffer &buf, MIRType &uInt64); + + MIRModule &module; + MIRBuilder &mirBuilder; + bool useCompressedJavaString = true; + std::unordered_set preloadSet; + std::unordered_set literalSet; + std::unordered_set fieldValueSet; + std::map literalMap; + MIRType *typeString = nullptr; + MIRSymbol *stringMetaClassSymbol = nullptr; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FE_JAVA_STRING_MANAGER_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/fe_macros.h b/src/hir2mpl/common/include/fe_macros.h new file mode 100644 index 0000000000000000000000000000000000000000..37b0f9cb265a1131e9573ee50e23642090a569ff --- /dev/null +++ b/src/hir2mpl/common/include/fe_macros.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FE_MACROS_H +#define HIR2MPL_INCLUDE_FE_MACROS_H +#include +#include +#include +#include +#include +#include +#include "fe_options.h" +#include "mpl_logging.h" + +#define TIMEIT(message, stmt) do { \ + if (FEOptions::GetInstance().IsDumpTime()) { \ + struct timeval start, end; \ + (void)gettimeofday(&start, NULL); \ + stmt; \ + (void)gettimeofday(&end, NULL); \ + float t = ((end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec)) * 1.0 / 1000000.0; \ + INFO(kLncInfo, "[TIME] %s: %.3f sec", message, t); \ + } else { \ + stmt; \ + } \ +} while (0) \ + +#define PHASE_TIMER(message, stmt) do { \ + if (FEOptions::GetInstance().IsDumpPhaseTime()) { \ + struct timespec start = {0, 0}; \ + struct timespec end = {0, 0}; \ + (void)clock_gettime(CLOCK_REALTIME, &start); \ + stmt; \ + (void)clock_gettime(CLOCK_REALTIME, &end); \ + constexpr int64_t nsInS = 1000000000; \ + int64_t t = (end.tv_sec - start.tv_sec) * nsInS + (end.tv_nsec - start.tv_nsec); \ + INFO(kLncInfo, "[PhaseTime] %s: %lld ns", message, t); \ + } else { \ + stmt; \ + } \ +} while (0) \ + +#define FE_INFO_LEVEL(level, fmt, ...) do { \ + if (FEOptions::GetInstance().GetDumpLevel() >= level) { \ + INFO(kLncInfo, fmt, ##__VA_ARGS__); \ + } \ +} while (0) \ + +#define BIT_XOR(v1, v2) (((v1) && (!(v2))) || ((!(v1)) && (v2))) + +#define TRY_DO(run) do { \ + CHECK_FATAL(run, "%s", #run); \ +} while (0) + +#define FE_ERR(num, fmt, ...) do { \ + ERR(num, fmt, ##__VA_ARGS__); \ + FEManager::GetDiagManager().IncErrNum(); \ +} while (0) +#endif // ~HIR2MPL_INCLUDE_FE_MACROS_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/fe_manager.h b/src/hir2mpl/common/include/fe_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..ba96fb4755a00d2949f734d22da117524c1aecd7 --- /dev/null +++ b/src/hir2mpl/common/include/fe_manager.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_MANAGER_H +#define HIR2MPL_INCLUDE_COMMON_FE_MANAGER_H +#include +#include "mir_module.h" +#include "mir_builder.h" +#include "fe_type_manager.h" +#include "fe_java_string_manager.h" +#include "fe_diag_manager.h" +#include "fe_function.h" + +namespace maple { +class FEManager { + public: + static FEManager &GetManager() { + ASSERT(manager != nullptr, "manager is not initialize"); + return *manager; + } + + static FETypeManager &GetTypeManager() { + ASSERT(manager != nullptr, "manager is not initialize"); + return manager->typeManager; + } + + static FEJavaStringManager &GetJavaStringManager() { + ASSERT(manager != nullptr, "manager is not initialize"); + return manager->javaStringManager; + } + + static FEDiagManager &GetDiagManager() { + ASSERT(manager != nullptr, "manager is not initialize"); + return manager->diagManager; + } + + static MIRBuilder &GetMIRBuilder() { + ASSERT(manager != nullptr, "manager is not initialize"); + return manager->builder; + } + + static MIRModule &GetModule() { + ASSERT(manager != nullptr, "manager is not initialize"); + return manager->module; + } + + static void SetCurrentFEFunction(FEFunction &func) { + ASSERT(manager != nullptr, "manager is not initialize"); + manager->curFEFunction = &func; + } + + static FEFunction &GetCurrentFEFunction() { + ASSERT(manager != nullptr, "manager is not initialize"); + CHECK_NULL_FATAL(manager->curFEFunction); + return *manager->curFEFunction; + } + + static void Init(MIRModule &moduleIn) { + manager = new FEManager(moduleIn); + } + + static void Release() { + if (manager != nullptr) { + manager->typeManager.ReleaseMemPool(); + delete manager; + manager = nullptr; + } + } + + StructElemNameIdx *GetFieldStructElemNameIdx(uint64 index) { + auto it = mapFieldStructElemNameIdx.find(index); + if (it != mapFieldStructElemNameIdx.end()) { + return it->second; + } + return nullptr; + } + + void SetFieldStructElemNameIdx(uint64 index, StructElemNameIdx &structElemNameIdx) { + std::lock_guard lk(feManagerMapStructElemNameIdxMtx); + mapFieldStructElemNameIdx[index] = &structElemNameIdx; + } + + StructElemNameIdx *GetMethodStructElemNameIdx(uint64 index) { + auto it = mapMethodStructElemNameIdx.find(index); + if (it != mapMethodStructElemNameIdx.end()) { + return it->second; + } + return nullptr; + } + + void SetMethodStructElemNameIdx(uint64 index, StructElemNameIdx &structElemNameIdx) { + std::lock_guard lk(feManagerMapStructElemNameIdxMtx); + mapMethodStructElemNameIdx[index] = &structElemNameIdx; + } + + MemPool *GetStructElemMempool() { + return structElemMempool; + } + + void ReleaseStructElemMempool() { + FEUtils::DeleteMempoolPtr(structElemMempool); + } + + uint32 RegisterSourceFileIdx(const GStrIdx &strIdx) { + auto it = sourceFileIdxMap.find(strIdx); + if (it != sourceFileIdxMap.end()) { + return it->second; + } else { + // make src files start from #2, #1 is mpl file + size_t num = sourceFileIdxMap.size() + 2; + (void)sourceFileIdxMap.emplace(strIdx, num); +#ifdef DEBUG + idxSourceFileMap.emplace(num, strIdx); +#endif + module.PushbackFileInfo(MIRInfoPair(strIdx, num)); + return static_cast(num); + } + } + + std::string GetSourceFileNameFromIdx(uint32 idx) const { + auto it = idxSourceFileMap.find(idx); + if (it != idxSourceFileMap.end()) { + return GlobalTables::GetStrTable().GetStringFromStrIdx(it->second); + } + return "unknown"; + } + + private: + static FEManager *manager; + MIRModule &module; + FETypeManager typeManager; + FEDiagManager diagManager; + MIRBuilder builder; + FEFunction *curFEFunction = nullptr; + FEJavaStringManager javaStringManager; + MemPool *structElemMempool; + MapleAllocator structElemAllocator; + std::unordered_map mapFieldStructElemNameIdx; + std::unordered_map mapMethodStructElemNameIdx; + std::map sourceFileIdxMap; + std::map idxSourceFileMap; + explicit FEManager(MIRModule &moduleIn) + : module(moduleIn), + typeManager(module), + builder(&module), + javaStringManager(moduleIn, builder), + structElemMempool(FEUtils::NewMempool("MemPool for StructElemNameIdx", false /* isLcalPool */)), + structElemAllocator(structElemMempool) {} + ~FEManager() { + structElemMempool = nullptr; + } + mutable std::mutex feManagerMapStructElemNameIdxMtx; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FE_MANAGER_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/fe_options.h b/src/hir2mpl/common/include/fe_options.h new file mode 100644 index 0000000000000000000000000000000000000000..dea1d79b5f0827840ce9b4670d712ef5e83f419f --- /dev/null +++ b/src/hir2mpl/common/include/fe_options.h @@ -0,0 +1,558 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_OPTIONS_H +#define HIR2MPL_INCLUDE_COMMON_FE_OPTIONS_H +#include +#include +#include +#include +#include "mpl_logging.h" +#include "types_def.h" + +namespace maple { +class FEOptions { + public: + static const int kDumpLevelDisable = 0; + static const int kDumpLevelInfo = 1; + static const int kDumpLevelInfoDetail = 2; + static const int kDumpLevelInfoDebug = 3; + + enum ModeJavaStaticFieldName { + kNoType = 0, // without type + kAllType, // with type + kSmart // auto anti-proguard + }; + + enum ModeCollectDepTypes { + kAll = 0, // collect all dependent types + kFunc // collect func dependent types + }; + + enum ModeDepSameNamePolicy { + kSys = 0, // load type form sys when on-demand load same name type + kSrc // load type form src when on-demand load same name type + }; + + enum TypeInferKind { + kNo = 0, + kRoahAlgorithm, + kLinearScan + }; + + static FEOptions &GetInstance() { + return options; + } + + void Init() { + isJBCUseImpreciseType = true; + } + + // input control options + void AddInputClassFile(const std::string &fileName); + const std::list &GetInputClassFiles() const { + return inputClassFiles; + } + + void AddInputJarFile(const std::string &fileName); + const std::list &GetInputJarFiles() const { + return inputJarFiles; + } + + void AddInputDexFile(const std::string &fileName); + const std::vector &GetInputDexFiles() const { + return inputDexFiles; + } + + void AddInputASTFile(const std::string &fileName); + const std::vector &GetInputASTFiles() const { + return inputASTFiles; + } + + void AddInputMASTFile(const std::string &fileName); + const std::vector &GetInputMASTFiles() const { + return inputMASTFiles; + } + + void AddInputMpltFileFromSys(const std::string &fileName) { + inputMpltFilesFromSys.push_back(fileName); + } + + const std::list &GetInputMpltFilesFromSys() const { + return inputMpltFilesFromSys; + } + + void AddInputMpltFileFromApk(const std::string &fileName) { + inputMpltFilesFromApk.push_back(fileName); + } + + const std::list &GetInputMpltFilesFromApk() const { + return inputMpltFilesFromApk; + } + + void AddInputMpltFile(const std::string &fileName) { + inputMpltFiles.push_back(fileName); + } + + const std::list &GetInputMpltFiles() const { + return inputMpltFiles; + } + + // On Demand Type Creation + void SetXBootClassPath(const std::string &fileName) { + strXBootClassPath = fileName; + } + + const std::string &GetXBootClassPath() const { + return strXBootClassPath; + } + + void SetClassLoaderContext(const std::string &fileName) { + strClassLoaderContext = fileName; + } + + const std::string &GetClassLoaderContext() const { + return strClassLoaderContext; + } + + void SetCompileFileName(const std::string &fileName) { + strCompileFileName = fileName; + } + + const std::string &GetCompileFileName() const { + return strCompileFileName; + } + + void SetModeCollectDepTypes(ModeCollectDepTypes mode) { + modeCollectDepTypes = mode; + } + + ModeCollectDepTypes GetModeCollectDepTypes() const { + return modeCollectDepTypes; + } + + void SetModeDepSameNamePolicy(ModeDepSameNamePolicy mode) { + modeDepSameNamePolicy = mode; + } + + ModeDepSameNamePolicy GetModeDepSameNamePolicy() const { + return modeDepSameNamePolicy; + } + + // output control options + void SetIsGenMpltOnly(bool flag) { + isGenMpltOnly = flag; + } + + bool IsGenMpltOnly() const { + return isGenMpltOnly; + } + + void SetIsGenAsciiMplt(bool flag) { + isGenAsciiMplt = flag; + } + + bool IsGenAsciiMplt() const { + return isGenAsciiMplt; + } + + void SetOutputPath(const std::string &path) { + outputPath = path; + } + + const std::string &GetOutputPath() const { + return outputPath; + } + + void SetOutputName(const std::string &name) { + outputName = name; + } + + const std::string &GetOutputName() const { + return outputName; + } + + void EnableDumpInstComment() { + isDumpInstComment = true; + } + + void DisableDumpInstComment() { + isDumpInstComment = false; + } + + bool IsDumpInstComment() const { + return isDumpInstComment; + } + + void SetNoMplFile() { + isNoMplFile = true; + } + + bool IsNoMplFile() const { + return isNoMplFile; + } + + // debug info control options + void SetDumpLevel(int level) { + dumpLevel = level; + } + + int GetDumpLevel() const { + return dumpLevel; + } + + void SetIsDumpTime(bool flag) { + isDumpTime = flag; + } + + bool IsDumpTime() const { + return isDumpTime; + } + + void SetIsDumpComment(bool flag) { + isDumpComment = flag; + } + + bool IsDumpComment() const { + return isDumpComment; + } + + void SetIsDumpLOC(bool flag) { + isDumpLOC = flag; + } + + bool IsDumpLOC() const { + return isDumpLOC; + } + + void SetIsDumpPhaseTime(bool flag) { + isDumpPhaseTime = flag; + } + + bool IsDumpPhaseTime() const { + return isDumpPhaseTime; + } + + void SetIsDumpPhaseTimeDetail(bool flag) { + isDumpPhaseTimeDetail = flag; + } + + bool IsDumpPhaseTimeDetail() const { + return isDumpPhaseTimeDetail; + } + + // java compiler options + void SetModeJavaStaticFieldName(ModeJavaStaticFieldName mode) { + modeJavaStaticField = mode; + } + + ModeJavaStaticFieldName GetModeJavaStaticFieldName() const { + return modeJavaStaticField; + } + + void SetIsJBCUseImpreciseType(bool flag) { + isJBCUseImpreciseType = flag; + } + + bool IsJBCUseImpreciseType() const { + return isJBCUseImpreciseType; + } + + void SetIsJBCInfoUsePathName(bool flag) { + isJBCInfoUsePathName = flag; + } + + bool IsJBCInfoUsePathName() const { + return isJBCInfoUsePathName; + } + + void SetIsDumpJBCStmt(bool flag) { + isDumpJBCStmt = flag; + } + + bool IsDumpJBCStmt() const { + return isDumpJBCStmt; + } + + void SetIsDumpFEIRBB(bool flag) { + isDumpBB = flag; + } + + bool IsDumpFEIRBB() const { + return isDumpBB; + } + + void AddFuncNameForDumpCFGGraph(const std::string &funcName) { + funcNamesForDumpCFGGraph.insert(funcName); + } + + bool IsDumpFEIRCFGGraph(const std::string &funcName) const { + return funcNamesForDumpCFGGraph.find(funcName) != + funcNamesForDumpCFGGraph.end(); + } + + void SetIsDumpJBCAll(bool flag) { + isDumpJBCAll = flag; + } + + bool IsDumpJBCAll() const { + return isDumpJBCAll; + } + + void SetIsDumpJBCErrorOnly(bool flag) { + isDumpJBCErrorOnly = flag; + } + + bool IsDumpJBCErrorOnly() const { + return isDumpJBCErrorOnly; + } + + void SetIsEmitJBCLocalVarInfo(bool flag) { + isEmitJBCLocalVarInfo = flag; + } + + bool IsEmitJBCLocalVarInfo() const { + return isEmitJBCLocalVarInfo; + } + + // parallel + void SetNThreads(uint32 n) { + nthreads = n; + } + + uint32 GetNThreads() const { + return nthreads; + } + + void SetDumpThreadTime(bool arg) { + dumpThreadTime = arg; + } + + bool IsDumpThreadTime() const { + return dumpThreadTime; + } + + void AddDumpJBCFuncName(const std::string &funcName) { + if (!funcName.empty()) { + CHECK_FATAL(dumpJBCFuncNames.insert(funcName).second, "dumpJBCFuncNames insert failed"); + } + } + + const std::set &GetDumpJBCFuncNames() const { + return dumpJBCFuncNames; + } + + bool IsDumpJBCFuncName(const std::string &funcName) const { + return dumpJBCFuncNames.find(funcName) != dumpJBCFuncNames.end(); + } + + void SetTypeInferKind(TypeInferKind arg) { + typeInferKind = arg; + } + + TypeInferKind GetTypeInferKind() const { + return typeInferKind; + } + + bool IsRC() const { + return isRC; + } + + void SetRC(bool arg) { + isRC = arg; + } + + bool IsNoBarrier() const { + return isNoBarrier; + } + + void SetNoBarrier(bool arg) { + isNoBarrier = arg; + } + + bool HasJBC() const { + return ((inputClassFiles.size() != 0) || (inputJarFiles.size() != 0)); + } + + void SetIsAOT(bool flag) { + isAOT = flag; + } + + bool IsAOT() const { + return isAOT; + } + + void SetUseSignedChar(bool flag) { + useSignedChar = flag; + } + + bool IsUseSignedChar() const { + return useSignedChar; + } + + void SetBigEndian(bool flag) { + isBigEndian = flag; + } + + bool IsBigEndian() const { + return isBigEndian; + } + + void SetNpeCheckDynamic(bool flag) { + isNpeCheckDynamic = flag; + } + + bool IsNpeCheckDynamic() const { + return isNpeCheckDynamic; + } + + void SetBoundaryCheckDynamic(bool flag) { + isBoundaryCheckDynamic = flag; + } + + bool IsBoundaryCheckDynamic() const { + return isBoundaryCheckDynamic; + } + + void SetSafeRegion(bool flag) { + isEnableSafeRegion = flag; + } + + bool IsEnableSafeRegion() const { + return isEnableSafeRegion; + } + + void SetO2(bool flag) { + isO2 = flag; + } + + bool IsO2() const { + return isO2; + } + + void SetSimplifyShortCircuit(bool flag) { + isSimplifyShortCircuit = flag; + } + + bool IsSimplifyShortCircuit() const { + return isSimplifyShortCircuit; + } + + void SetEnableVariableArray(bool flag) { + isEnableVariableArray = flag; + } + + bool IsEnableVariableArray() const { + return isEnableVariableArray; + } + + void SetFuncInlineSize(uint32 size) { + funcInlineSize = size; + } + + uint32 GetFuncInlineSize() const { + return funcInlineSize; + } + + void SetWPAA(bool flag) { + wpaa = flag; + } + + bool GetWPAA() const { + return wpaa; + } + + private: + static FEOptions options; + // input control options + std::list inputClassFiles; + std::list inputJarFiles; + std::vector inputDexFiles; + std::vector inputASTFiles; + std::vector inputMASTFiles; + std::list inputMpltFilesFromSys; + std::list inputMpltFilesFromApk; + std::list inputMpltFiles; + + // On Demand Type Creation + std::string strXBootClassPath; + std::string strClassLoaderContext; + std::string strCompileFileName; + ModeCollectDepTypes modeCollectDepTypes = ModeCollectDepTypes::kFunc; + ModeDepSameNamePolicy modeDepSameNamePolicy = ModeDepSameNamePolicy::kSys; + + // output control options + bool isGenMpltOnly; + bool isGenAsciiMplt; + std::string outputPath; + std::string outputName; + bool isDumpInstComment = false; + bool isNoMplFile = false; + + // debug info control options + int dumpLevel; + bool isDumpTime; + bool isDumpComment = false; + bool isDumpLOC = true; + bool isDumpPhaseTime = false; + bool isDumpPhaseTimeDetail = false; + + // java compiler options + ModeJavaStaticFieldName modeJavaStaticField = ModeJavaStaticFieldName::kNoType; + bool isJBCUseImpreciseType = false; + bool isJBCInfoUsePathName = false; + bool isDumpJBCStmt = false; + bool isDumpJBCAll = false; + bool isDumpJBCErrorOnly = false; + std::set dumpJBCFuncNames; + bool isEmitJBCLocalVarInfo = false; + + // bc compiler options + bool isRC = false; + bool isNoBarrier = false; + bool isO2 = false; + bool isSimplifyShortCircuit = false; + bool isEnableVariableArray = false; + + // ast compiler options + bool useSignedChar = false; + bool isBigEndian = false; + + // general stmt/bb/cfg debug options + bool isDumpBB = false; + std::set funcNamesForDumpCFGGraph; + + // parallel + uint32 nthreads; + bool dumpThreadTime; + + // type-infer + TypeInferKind typeInferKind = kLinearScan; + + // symbol resolve + bool isAOT = false; + + // EnhanceC + bool isNpeCheckDynamic = false; + bool isBoundaryCheckDynamic = false; + bool isEnableSafeRegion = false; + + uint32 funcInlineSize = 0; + bool wpaa = false; + + FEOptions(); + ~FEOptions() = default; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FE_OPTIONS_H diff --git a/src/hir2mpl/common/include/fe_struct_elem_info.h b/src/hir2mpl/common/include/fe_struct_elem_info.h new file mode 100644 index 0000000000000000000000000000000000000000..b533e9c969cc4889679ac535905a4ab92f902c33 --- /dev/null +++ b/src/hir2mpl/common/include/fe_struct_elem_info.h @@ -0,0 +1,279 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_STRUCT_ELEM_INFO_H +#define HIR2MPL_INCLUDE_COMMON_FE_STRUCT_ELEM_INFO_H +#include +#include +#include "global_tables.h" +#include "fe_configs.h" +#include "feir_type.h" + +namespace maple { +struct StructElemNameIdx { + GStrIdx klass; + GStrIdx elem; + GStrIdx type; + GStrIdx full; + + StructElemNameIdx(const GStrIdx &argKlass, const GStrIdx &argElem, const GStrIdx &argType, const GStrIdx &argFull) + : klass(argKlass), elem(argElem), type(argType), full(argFull) {} + StructElemNameIdx(const std::string &klassStr, const std::string &elemStr, const std::string &typeStr) { + const std::string &fullName = klassStr + "|" + elemStr + "|" + typeStr; + klass = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(klassStr)); + elem = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(elemStr)); + type = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(typeStr)); + full = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::EncodeName(fullName)); + } + StructElemNameIdx(const std::string &funcStr) { + klass = GStrIdx(0); + elem = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcStr); + type = GStrIdx(0); + full = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcStr); + } + ~StructElemNameIdx() = default; +}; + +class FEStructElemInfo { + public: + FEStructElemInfo(MapleAllocator &allocatorIn, const StructElemNameIdx &argStructElemNameIdx, + MIRSrcLang argSrcLang, bool argIsStatic); + virtual ~FEStructElemInfo() = default; + + void Prepare(MIRBuilder &mirBuilder, bool argIsStatic) { + PrepareImpl(mirBuilder, argIsStatic); + } + + const std::string &GetStructName() const { + return GlobalTables::GetStrTable().GetStringFromStrIdx(structElemNameIdx.klass); + } + + const std::string &GetElemName() const { + return GlobalTables::GetStrTable().GetStringFromStrIdx(structElemNameIdx.elem); + } + + const GStrIdx &GetElemNameIdx() const { + return structElemNameIdx.elem; + } + + const std::string &GetSignatureName() const { + return GlobalTables::GetStrTable().GetStringFromStrIdx(structElemNameIdx.type); + } + + bool IsStatic() const { + return isStatic; + } + + bool IsMethod() const { + return isMethod; + } + + bool IsDefined() const { + return isDefined; + } + + void SetDefined() { + isDefined = true; + } + + void SetUndefined() { + isDefined = false; + } + + bool IsFromDex() const { + return isFromDex; + } + + void SetFromDex() { + isFromDex = true; + } + + MIRSrcLang GetSrcLang() const { + return srcLang; + } + + void SetSrcLang(MIRSrcLang lang) { + srcLang = lang; + } + + UniqueFEIRType GetActualContainerType() const; + const std::string GetActualContainerName() const { + return actualContainer.c_str(); + } + + LLT_PROTECTED: + virtual void PrepareImpl(MIRBuilder &mirBuilder, bool argIsStatic) = 0; + + bool isStatic : 1; + bool isMethod : 1; + bool isDefined : 1; + bool isFromDex : 1; + bool isPrepared : 1; + MIRSrcLang srcLang : 8; + MapleAllocator &allocator; + StructElemNameIdx structElemNameIdx; + MapleString actualContainer; // in maple format +}; + +using UniqueFEStructElemInfo = std::unique_ptr; + +class FEStructFieldInfo : public FEStructElemInfo { + public: + FEStructFieldInfo(MapleAllocator &allocatorIn, const StructElemNameIdx &argStructElemNameIdx, + MIRSrcLang argSrcLang, bool argIsStatic); + ~FEStructFieldInfo() { + fieldType = nullptr; + } + GStrIdx GetFieldNameIdx() const { + return fieldNameIdx; + } + + FieldID GetFieldID() const { + return fieldID; + } + + void SetFieldID(const FieldID argFieldID) { + fieldID = argFieldID; + } + + const FEIRType *GetType() const { + return fieldType; + } + + bool IsVolatile() const { + return isVolatile; + } + + LLT_PROTECTED: + void PrepareImpl(MIRBuilder &mirBuilder, bool argIsStatic) override; + + LLT_PRIVATE: + void LoadFieldType(); + void LoadFieldTypeJava(); + void PrepareStaticField(const MIRStructType &structType); + void PrepareNonStaticField(MIRBuilder &mirBuilder); + bool SearchStructFieldJava(MIRStructType &structType, MIRBuilder &mirBuilder, bool argIsStatic, + bool allowPrivate = true); + bool SearchStructFieldJava(const TyIdx &tyIdx, MIRBuilder &mirBuilder, bool argIsStatic, bool allowPrivate = true); + bool CompareFieldType(const FieldPair &fieldPair) const; + + FEIRType *fieldType; + GStrIdx fieldNameIdx; + FieldID fieldID; + bool isVolatile; +}; + +class FEStructMethodInfo : public FEStructElemInfo { + public: + FEStructMethodInfo(MapleAllocator &allocatorIn, const StructElemNameIdx &argStructElemNameIdx, + MIRSrcLang argSrcLang, bool argIsStatic); + ~FEStructMethodInfo(); + PUIdx GetPuIdx() const; + bool IsConstructor() const { + return isConstructor; + } + + bool IsReturnVoid() const { + return isReturnVoid; + } + + void SetReturnVoid() { + isReturnVoid = true; + } + + bool IsJavaPolymorphicCall() const { + return isJavaPolymorphicCall; + } + + bool IsJavaDynamicCall() const { + return isJavaDynamicCall; + } + + void SetJavaDyamicCall() { + isJavaDynamicCall = true; + } + + void UnsetJavaDynamicCall() { + isJavaDynamicCall = false; + } + + const FEIRType *GetReturnType() const { + return retType; + } + + void SetReturnType(FEIRType *type) { + retType = type; + } + + const FEIRType *GetOwnerType() const { + return ownerType; + } + + const MapleVector &GetArgTypes() const { + return argTypes; + } + + void SetArgTypes(const MapleVector &argTypesIn) { + argTypes = argTypesIn; + } + + void SetArgsName(const std::vector &names) { + argNames = names; + } + + const std::vector &GetArgsName() const { + return argNames; + } + + void SetFuncAttrs(const FuncAttrs &attrs) { + funcAttrs = attrs; + } + + const FuncAttrs &GetFuncAttrs() const { + return funcAttrs; + } + + MIRFunction *GetMirFunc() const { + CHECK_NULL_FATAL(mirFunc); + return mirFunc; + } + + LLT_PROTECTED: + void PrepareImpl(MIRBuilder &mirBuilder, bool argIsStatic) override; + + LLT_PRIVATE: + void LoadMethodType(); + void LoadMethodTypeJava(); + void PrepareMethod(); + void PrepareMethodC(); + void PrepareImplJava(MIRBuilder &mirBuilder, bool argIsStatic); + bool SearchStructMethodJava(MIRStructType &structType, MIRBuilder &mirBuilder, bool argIsStatic, + bool allowPrivate = true); + bool SearchStructMethodJavaInParent(MIRStructType &structType, MIRBuilder &mirBuilder, bool argIsStatic); + bool SearchStructMethodJava(const TyIdx &tyIdx, MIRBuilder &mirBuilder, bool argIsStatic, bool allowPrivate = true); + + bool isReturnVoid; + bool isConstructor; + bool isJavaPolymorphicCall; + bool isJavaDynamicCall; + GStrIdx methodNameIdx; + FEIRType *retType; + FEIRType *ownerType; + MIRFunction *mirFunc; + MapleVector argTypes; + std::vector argNames; + FuncAttrs funcAttrs; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FE_STRUCT_ELEM_INFO_H diff --git a/src/hir2mpl/common/include/fe_timer.h b/src/hir2mpl/common/include/fe_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..7ff67103e1047e442d7fd697f83f382494242f70 --- /dev/null +++ b/src/hir2mpl/common/include/fe_timer.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_TIMER_H +#define HIR2MPL_INCLUDE_COMMON_FE_TIMER_H +#include +#include +#include "mpl_timer.h" +#include "mpl_logging.h" +#include "fe_options.h" + +namespace maple { +class FETimer { + public: + FETimer() = default; + ~FETimer() = default; + void Start() { + if (!FEOptions::GetInstance().IsDumpTime()) { + return; + } + timer.Start(); + } + + void StartAndDump(const std::string &message) { + if (!FEOptions::GetInstance().IsDumpTime()) { + return; + } + CHECK_FATAL(!message.empty(), "message is empty"); + timer.Start(); + INFO(kLncInfo, "[Time] %s: starting...", message.c_str()); + } + + void StopAndDumpTimeMS(const std::string &message) { + if (!FEOptions::GetInstance().IsDumpTime()) { + return; + } + CHECK_FATAL(!message.empty(), "message is empty"); + timer.Stop(); + INFO(kLncInfo, "[Time] %s: finished (%ld ms)", message.c_str(), timer.ElapsedMilliseconds()); + } + + void StopAndDumpTimeS(const std::string &message) { + if (!FEOptions::GetInstance().IsDumpTime()) { + return; + } + CHECK_FATAL(!message.empty(), "message is empty"); + timer.Stop(); + INFO(kLncInfo, "[Time] %s: finished (%lf s)", message.c_str(), timer.ElapsedMilliseconds() / 1000.0); + } + + private: + MPLTimer timer; +}; // class FETimer +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FE_TIMER_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/fe_timer_ns.h b/src/hir2mpl/common/include/fe_timer_ns.h new file mode 100644 index 0000000000000000000000000000000000000000..6ade65f5afe9c4d7c9b90b89cc701f6771c4f5aa --- /dev/null +++ b/src/hir2mpl/common/include/fe_timer_ns.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_TIMER_NS_H +#define HIR2MPL_INCLUDE_COMMON_FE_TIMER_NS_H +#include +#include +#include + +namespace maple { +class FETimerNS { + public: + FETimerNS() = default; + ~FETimerNS() = default; + void Start(); + void Stop(); + int64_t GetTimeNS() const; + + private: + struct timespec timeStart = {0, 0}; + struct timespec timeEnd = {0, 0}; +}; // class FETimerNS +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FE_TIMER_NS_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/fe_type_hierarchy.h b/src/hir2mpl/common/include/fe_type_hierarchy.h new file mode 100644 index 0000000000000000000000000000000000000000..2c1899fd3ede2ccf6f59279c9e48839e2c4c2144 --- /dev/null +++ b/src/hir2mpl/common/include/fe_type_hierarchy.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FE_TYPE_HIERARCHY_H +#define HIR2MPL_INCLUDE_FE_TYPE_HIERARCHY_H +#include +#include +#include "mir_type.h" + +namespace maple { +class FETypeHierarchy { + public: + static FETypeHierarchy &GetInstance() { + return instance; + } + void InitByGlobalTable(); + void AddMIRType(const MIRClassType &type); + void AddMIRType(const MIRInterfaceType &type); + bool IsParentOf(const GStrIdx &parentIdx, const GStrIdx &childIdx); + + private: + static FETypeHierarchy instance; + std::map> mapIdxChildParent; + std::set> cache; + FETypeHierarchy() = default; + ~FETypeHierarchy() = default; + void AddParentChildRelation(const GStrIdx &parentIdx, const GStrIdx &childIdx); +}; // class FETypeHierarchy +} // namespace maple +#endif // HIR2MPL_INCLUDE_FE_TYPE_HIERARCHY_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/fe_type_manager.h b/src/hir2mpl/common/include/fe_type_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..d489ba0a9feeade19f0c4e10b8e13773b152f7dc --- /dev/null +++ b/src/hir2mpl/common/include/fe_type_manager.h @@ -0,0 +1,329 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FE_TYPE_MANAGER_H +#define HIR2MPL_INCLUDE_COMMON_FE_TYPE_MANAGER_H +#include +#include +#include +#include "mempool_allocator.h" +#include "mir_module.h" +#include "mir_type.h" +#include "mir_builder.h" +#include "feir_type.h" +#include "fe_struct_elem_info.h" +#include "fe_utils.h" +#include "feir_stmt.h" + +namespace maple { +enum FETypeFlag : uint16 { + kDefault = 0, + kSrcMpltSys = 1, + kSrcInput = 1 << 1, + kSrcMpltApk = 1 << 2, + kSrcMplt = 1 << 3, + kSrcExtern = 1 << 4, + kSrcUnknown = 1 << 5, + kSrcMask = 0x3F, +}; + +class FETypeSameNamePolicy { + public: + FETypeSameNamePolicy() : flag(0) {} + ~FETypeSameNamePolicy() = default; + bool IsUseLastest() const { + return (flag & kFlagUseLastest) != 0; + } + + bool IsFatal() const { + return (flag & kFlagFatal) != 0; + } + + void SetFlag(uint8 flagIn) { + flag = flagIn; + } + + static constexpr uint8 kFlagUseLastest = 0x1; + static constexpr uint8 kFlagFatal = 0x2; + + private: + // bitwise flag + // bit0: 0-use first, 1-use lastest + // bit1: 0-warning, 1-fatal + uint8 flag; +}; + +using FEStructTypePair = std::pair; + +class FETypeManager { + public: + // ---------- prim FEIRType ---------- + const static UniqueFEIRType kPrimFEIRTypeUnknown; + const static UniqueFEIRType kPrimFEIRTypeU1; + const static UniqueFEIRType kPrimFEIRTypeI8; + const static UniqueFEIRType kPrimFEIRTypeU8; + const static UniqueFEIRType kPrimFEIRTypeI16; + const static UniqueFEIRType kPrimFEIRTypeU16; + const static UniqueFEIRType kPrimFEIRTypeI32; + const static UniqueFEIRType kPrimFEIRTypeU32; + const static UniqueFEIRType kPrimFEIRTypeI64; + const static UniqueFEIRType kPrimFEIRTypeU64; + const static UniqueFEIRType kPrimFEIRTypeF32; + const static UniqueFEIRType kPrimFEIRTypeF64; + const static UniqueFEIRType kFEIRTypeJavaObject; + const static UniqueFEIRType kFEIRTypeJavaClass; + const static UniqueFEIRType kFEIRTypeJavaString; + + explicit FETypeManager(MIRModule &moduleIn); + ~FETypeManager(); + void ReleaseMemPool(); + bool LoadMplts(const std::list &mpltNames, FETypeFlag flag, const std::string &phaseName); + bool LoadMplt(const std::string &mpltName, FETypeFlag flag); + void CheckSameNamePolicy() const; + // method for Class or Interface generation + MIRStructType *GetClassOrInterfaceType(const GStrIdx &nameIdx) const; + MIRStructType *GetClassOrInterfaceType(const std::string &name) const { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + return GetClassOrInterfaceType(nameIdx); + } + + FETypeFlag GetClassOrInterfaceTypeFlag(const GStrIdx &nameIdx) const; + FETypeFlag GetClassOrInterfaceTypeFlag(const std::string &name) const { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + return GetClassOrInterfaceTypeFlag(nameIdx); + } + + MIRStructType *CreateClassOrInterfaceType(const GStrIdx &nameIdx, bool isInterface, FETypeFlag typeFlag); + MIRStructType *CreateClassOrInterfaceType(const std::string &name, bool isInterface, FETypeFlag typeFlag) { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + return CreateClassOrInterfaceType(nameIdx, isInterface, typeFlag); + } + + MIRStructType *GetOrCreateStructType(const std::string &name); + MIRStructType *CreateStructType(const std::string &name); + MIRType *GetOrCreateComplexStructType(const MIRType &elemType); + MIRStructType *GetOrCreateClassOrInterfaceType(const GStrIdx &nameIdx, bool isInterface, FETypeFlag typeFlag, + bool &isCreate); + MIRStructType *GetOrCreateClassOrInterfaceType(const std::string &name, bool isInterface, FETypeFlag typeFlag, + bool &isCreate) { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + return GetOrCreateClassOrInterfaceType(nameIdx, isInterface, typeFlag, isCreate); + } + + MIRType *GetOrCreateClassOrInterfacePtrType(const GStrIdx &nameIdx, bool isInterface, FETypeFlag typeFlag, + bool &isCreate); + MIRType *GetOrCreateClassOrInterfacePtrType(const std::string &name, bool isInterface, FETypeFlag typeFlag, + bool &isCreate) { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + return GetOrCreateClassOrInterfacePtrType(nameIdx, isInterface, typeFlag, isCreate); + } + + uint32 GetTypeIDFromMplClassName(const std::string &mplClassName, int32 dexFileHashCode) const; + MIRStructType *GetStructTypeFromName(const std::string &name); + MIRStructType *GetStructTypeFromName(const GStrIdx &nameIdx); + MIRType *GetOrCreateTypeFromName(const std::string &name, FETypeFlag typeFlag, bool usePtr); + MIRType *GetOrCreatePointerType(const MIRType &type, PrimType ptyPtr = PTY_ref); + MIRType *GetOrCreateArrayType(MIRType &elemType, uint8 dim, PrimType ptyPtr = PTY_ref); + MIRType *GetOrCreateJArrayType(MIRType &elemType, uint8 dim, PrimType ptyPtr = PTY_ref); + void AddClassToModule(const MIRStructType &structType); + + // ---------- methods for StructElemInfo ---------- + // structIdx = 0: global field/function without owner structure + FEStructElemInfo *RegisterStructFieldInfo( + const StructElemNameIdx &argStructElemNameIdx, MIRSrcLang argSrcLang, bool isStatic); + FEStructElemInfo *RegisterStructMethodInfo( + const StructElemNameIdx &argStructElemNameIdx, MIRSrcLang argSrcLang, bool isStatic); + FEStructElemInfo *RegisterStructMethodInfoC( + const std::string &name, MIRSrcLang argSrcLang, bool isStatic); + FEStructElemInfo *GetStructElemInfo(const GStrIdx &fullNameIdx) const; + + // ---------- methods for MIRFunction ---------- + /** + * Function Name: GetMIRFunction + * Description: get MIRFunction by class method name + * 1. return if exist in mpltFuncNameSymbolMap + * 2. return if exist in nameFuncMap + * 3. return null otherwise + * Parallel note: Parallelable + */ + MIRFunction *GetMIRFunction(const std::string &classMethodName, bool isStatic); + MIRFunction *GetMIRFunction(const GStrIdx &nameIdx, bool isStatic); + + /* + * Function Name: CreateMIRFunction + * Description: create MIRFunction by class method name + * 1. call GetMIRFunction first, if exist, return + * 2. create MIRFunction + * Parallel note: Non-parallelable + */ + MIRFunction *CreateFunction(const GStrIdx &nameIdx, const TyIdx &retTypeIdx, const std::vector &argsTypeIdx, + bool isVarg, bool isStatic); + MIRFunction *CreateFunction(const std::string &methodName, const std::string &returnTypeName, + const std::vector &argTypeNames, bool isVarg, bool isStatic); + + // FEIRType GetOrCreate + const FEIRType *GetOrCreateFEIRTypeByName(const std::string &typeName, const GStrIdx &typeNameIdx, + MIRSrcLang argSrcLang = kSrcLangJava); + const FEIRType *GetOrCreateFEIRTypeByName(const GStrIdx &typeNameIdx, MIRSrcLang argSrcLang = kSrcLangJava); + const FEIRType *GetFEIRTypeByName(const std::string &typeName) const; + const FEIRType *GetFEIRTypeByName(const GStrIdx &typeNameIdx) const; + + // MCC function + void InitMCCFunctions(); + MIRFunction *GetMCCFunction(const std::string &funcName) const; + MIRFunction *GetMCCFunction(const GStrIdx &funcNameIdx) const; + PUIdx GetPuIdxForMCCGetOrInsertLiteral() const { + return funcMCCGetOrInsertLiteral->GetPuidx(); + } + + // anti-proguard + bool IsAntiProguardFieldStruct(const GStrIdx &structNameIdx); + + static bool IsStructType(const MIRType &type); + static PrimType GetPrimType(const std::string &name); + static MIRType *GetMIRTypeForPrim(char c); + static MIRType *GetMIRTypeForPrim(const std::string &name) { + if (name.length() != 1) { + return nullptr; + } + return GetMIRTypeForPrim(name[0]); + } + + static std::string GetBaseTypeName(const std::string &name, uint32 &dim, bool inMpl = true); + static std::string GetBaseTypeName(const std::string &name, bool inMpl = true) { + uint32 dim = 0; + return GetBaseTypeName(name, dim, inMpl); + } + static void SetComplete(MIRStructType &structType); + static std::string TypeAttrsToString(const TypeAttrs &attrs); + + bool IsImportedType(const GStrIdx &typeNameIdx) const { + return structNameTypeMap.find(typeNameIdx) != structNameTypeMap.end(); + } + + MIRStructType *GetImportedType(const GStrIdx &typeNameIdx) const { + auto it = structNameTypeMap.find(typeNameIdx); + if (it != structNameTypeMap.end()) { + return it->second.first; + } + return nullptr; + } + + const std::unordered_map &GetStructNameTypeMap() const { + return structNameTypeMap; + } + void MarkExternStructType(); + void SetMirImportedTypes(FETypeFlag flag); + + void SetSrcLang(const MIRSrcLang &argSrcLang) { + srcLang = argSrcLang; + } + + void InsertBoundaryLenExprHashMap(uint32 hash, UniqueFEIRExpr expr) { + (void)boundaryLenExprHashMap.insert(std::make_pair(hash, std::move(expr))); + } + + UniqueFEIRExpr GetBoundaryLenExprFromMap(uint32 hash) { + auto iter = boundaryLenExprHashMap.find(hash); + if (iter != boundaryLenExprHashMap.end()) { + return iter->second->Clone(); + } + return nullptr; + } + + void InsertOwnedNonnullFieldStructSet(const TyIdx &tyidx) { + (void)ownedNonnullFieldStructSet.insert(tyidx); + } + + bool IsOwnedNonnullFieldStructSet(const TyIdx &tyidx) { + auto iter = ownedNonnullFieldStructSet.find(tyidx); + if (iter != ownedNonnullFieldStructSet.end()) { + return true; + } + return false; + } + + private: + void UpdateStructNameTypeMapFromTypeTable(const std::string &mpltName, FETypeFlag flag); + void UpdateNameFuncMapFromTypeTable(); + void UpdateDupTypes(const GStrIdx &nameIdx, bool isInterface, + const std::unordered_map::iterator &importedTypeIt); + + // MCC function + void InitFuncMCCGetOrInsertLiteral(); + using mirFuncPair = std::pair; + + MIRModule &module; + MemPool *mp; + MapleAllocator allocator; + MIRBuilder builder; + // map + std::unordered_map structNameTypeMap; + // map + std::unordered_map structNameSrcMap; + // list> + std::list> structSameNameSrcList; + FETypeSameNamePolicy sameNamePolicy; + MIRSrcLang srcLang; + + // ---------- class name ---> type id map info ---------- + using classNameTypeIDMapT = std::unordered_map; + std::map classNameTypeIDMapAllDex; // dexFileHashCode className classTpyeID + // ---------- struct elem info ---------- + std::map mapStructElemInfo; + + // ---------- function list ---------- + std::unordered_map nameFuncMap; + std::unordered_map nameStaticFuncMap; + std::unordered_map mpltNameFuncMap; + std::unordered_map mpltNameStaticFuncMap; + + // ---------- FEIRType list ---------- + std::unordered_map nameFEIRTypeMap; + std::list nameFEIRTypeList; + + // ---------- MCC function list ---------- + std::unordered_map nameMCCFuncMap; + MIRFunction *funcMCCGetOrInsertLiteral; + + // ---------- Enhance C ---------- + std::unordered_map boundaryLenExprHashMap; + std::unordered_set ownedNonnullFieldStructSet; + + MIRFunction *funcMCCStaticFieldGetBool = nullptr; + MIRFunction *funcMCCStaticFieldGetByte = nullptr; + MIRFunction *funcMCCStaticFieldGetShort = nullptr; + MIRFunction *funcMCCStaticFieldGetChar = nullptr; + MIRFunction *funcMCCStaticFieldGetInt = nullptr; + MIRFunction *funcMCCStaticFieldGetLong = nullptr; + MIRFunction *funcMCCStaticFieldGetFloat = nullptr; + MIRFunction *funcMCCStaticFieldGetDouble = nullptr; + MIRFunction *funcMCCStaticFieldGetObject = nullptr; + + MIRFunction *funcMCCStaticFieldSetBool = nullptr; + MIRFunction *funcMCCStaticFieldSetByte = nullptr; + MIRFunction *funcMCCStaticFieldSetShort = nullptr; + MIRFunction *funcMCCStaticFieldSetChar = nullptr; + MIRFunction *funcMCCStaticFieldSetInt = nullptr; + MIRFunction *funcMCCStaticFieldSetLong = nullptr; + MIRFunction *funcMCCStaticFieldSetFloat = nullptr; + MIRFunction *funcMCCStaticFieldSetDouble = nullptr; + MIRFunction *funcMCCStaticFieldSetObject = nullptr; + + // ---------- antiproguard ---------- + std::set setAntiProguardFieldStructIdx; + mutable std::mutex feTypeManagerMtx; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FE_TYPE_MANAGER_H diff --git a/src/hir2mpl/common/include/fe_utils.h b/src/hir2mpl/common/include/fe_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..e932fbf80775bdd2b023afdbf3799a86419c6391 --- /dev/null +++ b/src/hir2mpl/common/include/fe_utils.h @@ -0,0 +1,365 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FE_UTILS_H +#define HIR2MPL_INCLUDE_FE_UTILS_H +#include +#include +#include +#include "mpl_logging.h" +#include "prim_types.h" +#include "mir_type.h" +#include "global_tables.h" +#include "mempool.h" +#include "mir_nodes.h" + +namespace maple { +class FEUtils { + public: + FEUtils() = default; + ~FEUtils() = default; + static std::vector Split(const std::string &str, char delim); + static uint8 GetWidth(PrimType primType); + static bool IsInteger(PrimType primType); + static bool IsSignedInteger(PrimType primType); + static bool IsUnsignedInteger(PrimType primType); + static PrimType MergePrimType(PrimType primType1, PrimType primType2); + static uint8 GetDim(const std::string &typeName); + static std::string GetBaseTypeName(const std::string &typeName); + static PrimType GetPrimType(const GStrIdx &typeNameIdx); + static uint32 GetSequentialNumber(); + static std::string GetFileNameHashStr(const std::string &fileName, uint32 seed = 211); + static std::string GetSequentialName0(const std::string &prefix, uint32_t num); + static std::string GetSequentialName(const std::string &prefix); + static std::string CreateLabelName(); + static FieldID GetStructFieldID(MIRStructType *base, const std::string &fieldName); + static bool TraverseToNamedField(MIRStructType &structType, const GStrIdx &nameIdx, FieldID &fieldID, + bool isTopLevel = true); + static MIRType *GetStructFieldType(const MIRStructType *type, FieldID feildID); + static const MIRFuncType *GetFuncPtrType(const MIRType &type); + static MIRConst *CreateImplicitConst(MIRType *type); + static PrimType GetVectorElementPrimType(PrimType vectorPrimType); + static bool EndsWith(const std::string &value, const std::string &ending); + static MIRConst *TraverseToMIRConst(MIRAggConst *aggConst, const MIRStructType &structType, FieldID &fieldID); + + static const std::string kBoolean; + static const std::string kByte; + static const std::string kShort; + static const std::string kChar; + static const std::string kInt; + static const std::string kLong; + static const std::string kFloat; + static const std::string kDouble; + static const std::string kVoid; + static const std::string kThis; + static const std::string kMCCStaticFieldGetBool; + static const std::string kMCCStaticFieldGetByte; + static const std::string kMCCStaticFieldGetChar; + static const std::string kMCCStaticFieldGetShort; + static const std::string kMCCStaticFieldGetInt; + static const std::string kMCCStaticFieldGetLong; + static const std::string kMCCStaticFieldGetFloat; + static const std::string kMCCStaticFieldGetDouble; + static const std::string kMCCStaticFieldGetObject; + + static const std::string kMCCStaticFieldSetBool; + static const std::string kMCCStaticFieldSetByte; + static const std::string kMCCStaticFieldSetChar; + static const std::string kMCCStaticFieldSetShort; + static const std::string kMCCStaticFieldSetInt; + static const std::string kMCCStaticFieldSetLong; + static const std::string kMCCStaticFieldSetFloat; + static const std::string kMCCStaticFieldSetDouble; + static const std::string kMCCStaticFieldSetObject; + + static inline MemPool *NewMempool(const std::string &name, bool isLocalPool) { + return memPoolCtrler.NewMemPool(name, isLocalPool); + } + + static inline void DeleteMempoolPtr(MemPool *memPoolPtr) { + memPoolCtrler.DeleteMemPool(memPoolPtr); + } + + static inline GStrIdx &GetBooleanIdx() { + static GStrIdx booleanIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kBoolean); + return booleanIdx; + } + + static inline GStrIdx &GetByteIdx() { + static GStrIdx byteIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kByte); + return byteIdx; + } + + static inline GStrIdx &GetShortIdx() { + static GStrIdx shortIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kShort); + return shortIdx; + } + + static inline GStrIdx &GetCharIdx() { + static GStrIdx charIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kChar); + return charIdx; + } + + static inline GStrIdx &GetIntIdx() { + static GStrIdx intIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kInt); + return intIdx; + } + + static inline GStrIdx &GetLongIdx() { + static GStrIdx longIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kLong); + return longIdx; + } + + static inline GStrIdx &GetFloatIdx() { + static GStrIdx floatIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kFloat); + return floatIdx; + } + + static inline GStrIdx &GetDoubleIdx() { + static GStrIdx doubleIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kDouble); + return doubleIdx; + } + + static inline GStrIdx &GetVoidIdx() { + static GStrIdx voidIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kVoid); + return voidIdx; + } + + static inline GStrIdx &GetThisIdx() { + static GStrIdx thisIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kThis); + return thisIdx; + } + + static inline GStrIdx &GetMCCStaticFieldGetBoolIdx() { + static GStrIdx mccStaticFieldGetBoolIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldGetBool); + return mccStaticFieldGetBoolIdx; + } + + static inline GStrIdx &GetMCCStaticFieldGetByteIdx() { + static GStrIdx mccStaticFieldGetByteIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldGetByte); + return mccStaticFieldGetByteIdx; + } + + static inline GStrIdx &GetMCCStaticFieldGetShortIdx() { + static GStrIdx mccStaticFieldGetShortIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldGetShort); + return mccStaticFieldGetShortIdx; + } + + static inline GStrIdx &GetMCCStaticFieldGetCharIdx() { + static GStrIdx mccStaticFieldGetCharIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldGetChar); + return mccStaticFieldGetCharIdx; + } + + static inline GStrIdx &GetMCCStaticFieldGetIntIdx() { + static GStrIdx mccStaticFieldGetIntIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldGetInt); + return mccStaticFieldGetIntIdx; + } + + static inline GStrIdx &GetMCCStaticFieldGetLongIdx() { + static GStrIdx mccStaticFieldGetLongIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldGetLong); + return mccStaticFieldGetLongIdx; + } + + static inline GStrIdx &GetMCCStaticFieldGetFloatIdx() { + static GStrIdx mccStaticFieldGetFloatIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldGetFloat); + return mccStaticFieldGetFloatIdx; + } + + static inline GStrIdx &GetMCCStaticFieldGetDoubleIdx() { + static GStrIdx mccStaticFieldGetDoubleIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldGetDouble); + return mccStaticFieldGetDoubleIdx; + } + + static inline GStrIdx &GetMCCStaticFieldGetObjectIdx() { + static GStrIdx mccStaticFieldGetObjectIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldGetObject); + return mccStaticFieldGetObjectIdx; + } + + static inline GStrIdx &GetMCCStaticFieldSetBoolIdx() { + static GStrIdx mccStaticFieldSetBoolIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldSetBool); + return mccStaticFieldSetBoolIdx; + } + + static inline GStrIdx &GetMCCStaticFieldSetByteIdx() { + static GStrIdx mccStaticFieldSetByteIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldSetByte); + return mccStaticFieldSetByteIdx; + } + + static inline GStrIdx &GetMCCStaticFieldSetShortIdx() { + static GStrIdx mccStaticFieldSetShortIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldSetShort); + return mccStaticFieldSetShortIdx; + } + + static inline GStrIdx &GetMCCStaticFieldSetCharIdx() { + static GStrIdx mccStaticFieldSetCharIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldSetChar); + return mccStaticFieldSetCharIdx; + } + + static inline GStrIdx &GetMCCStaticFieldSetIntIdx() { + static GStrIdx mccStaticFieldSetIntIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldSetInt); + return mccStaticFieldSetIntIdx; + } + + static inline GStrIdx &GetMCCStaticFieldSetLongIdx() { + static GStrIdx mccStaticFieldSetLongIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldSetLong); + return mccStaticFieldSetLongIdx; + } + + static inline GStrIdx &GetMCCStaticFieldSetFloatIdx() { + static GStrIdx mccStaticFieldSetFloatIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldSetFloat); + return mccStaticFieldSetFloatIdx; + } + + static inline GStrIdx &GetMCCStaticFieldSetDoubleIdx() { + static GStrIdx mccStaticFieldSetDoubleIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldSetDouble); + return mccStaticFieldSetDoubleIdx; + } + + static inline GStrIdx &GetMCCStaticFieldSetObjectIdx() { + static GStrIdx mccStaticFieldSetObjectIdx = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kMCCStaticFieldSetObject); + return mccStaticFieldSetObjectIdx; + } + + private: + static bool LogicXOR(bool v1, bool v2) { + return (v1 && !v2) || (!v1 && v2); + } +}; + +class FELinkListNode { + public: + FELinkListNode(); + virtual ~FELinkListNode(); + void InsertBefore(FELinkListNode *ins); + void InsertAfter(FELinkListNode *ins); + static void InsertBefore(FELinkListNode *ins, FELinkListNode *pos); + static void InsertAfter(FELinkListNode *ins, FELinkListNode *pos); + static void SpliceNodes(FELinkListNode *head, FELinkListNode *tail, FELinkListNode *newTail); + FELinkListNode *GetPrev() const { + return prev; + } + + void SetPrev(FELinkListNode *node) { + CHECK_NULL_FATAL(node); + prev = node; + } + + void SetPrevNull() { + prev = nullptr; + } + + FELinkListNode *GetNext() const { + return next; + } + + void SetNextNull() { + next = nullptr; + } + + void SetNext(FELinkListNode *node) { + CHECK_NULL_FATAL(node); + next = node; + } + + protected: + FELinkListNode *prev; + FELinkListNode *next; +}; + +class AstSwitchUtil { + public: + static AstSwitchUtil &Instance() { + static AstSwitchUtil local; + return local; + } + std::string CreateEndOrExitLabelName() const; + void MarkLabelUsed(const std::string &label); + void MarkLabelUnUsed(const std::string &label); + void PushNestedBreakLabels(const std::string &label); + void PopNestedBreakLabels(); + void PushNestedCaseVectors(const std::pair &caseVec); + void PopNestedCaseVectors(); + bool CheckLabelUsed(const std::string &label); + const std::pair &GetTopOfNestedCaseVectors() const; + const std::string &GetTopOfBreakLabels() const; + std::map &GetLabelUseMap() { + return labelUsed; + } + static uint32_t tempVarNo; + static const char *cleanLabel; + static const char *exitLabel; + static const char *blockLabel; + static const char *caseLabel; + static const char *catchLabel; + static const char *endehLabel; + + private: + AstSwitchUtil() = default; + ~AstSwitchUtil() = default; + std::map labelUsed = std::map(); + std::stack nestedBreakLabels = std::stack(); // loop and switch blocks + std::stack nestedContinueLabels = std::stack(); // loop blocks only + std::stack> nestedCaseVectors = std::stack>(); +}; // end of AstSwitchUtil + +class AstLoopUtil { + public: + static AstLoopUtil &Instance() { + static AstLoopUtil local; + return local; + } + + ~AstLoopUtil() = default; + void PushBreak(std::string labelPair); + std::string GetCurrentBreak(); + void PopCurrentBreak(); + bool IsBreakLabelsEmpty() const; + void PushContinue(std::string label); + std::string GetCurrentContinue(); + bool IsContinueLabelsEmpty() const; + void PopCurrentContinue(); + + bool IsCurrentBreakLabelUsed() { + return breakLabels.top().second; + } + + bool IsCurrentContinueLabelUsed() { + return continueLabels.top().second; + } + + private: + AstLoopUtil() = default; + std::stack> breakLabels = std::stack>(); + std::stack> continueLabels = std::stack>(); +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_FE_UTILS_H diff --git a/src/hir2mpl/common/include/fe_utils_ast.h b/src/hir2mpl/common/include/fe_utils_ast.h new file mode 100644 index 0000000000000000000000000000000000000000..8591fb5a7a0317c3ae40cb8ed53480643106f2db --- /dev/null +++ b/src/hir2mpl/common/include/fe_utils_ast.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FE_UTILS_AST_H +#define HIR2MPL_INCLUDE_FE_UTILS_AST_H +#include +#include +#include "types_def.h" +#include "cfg_primitive_types.h" +#include "mempool.h" +#include "opcodes.h" +#include "mir_const.h" + +namespace maple { +class FEUtilAST { + public: + static PrimType GetTypeFromASTTypeName(const std::string &typeName); + static const std::string Type2Label(PrimType primType); + + private: + FEUtilAST() = default; + ~FEUtilAST() = default; +}; + +template +std::function OpGenerator(Opcode op, T p0, T p1, bool isSigned) { + switch (op) { + case OP_add: { + return [p0, p1]() { return p0 + p1; }; + } + case OP_sub: { + return [p0, p1]() { return p0 - p1; }; + } + case OP_mul: { + return [p0, p1]() { return p0 * p1; }; + } + case OP_div: { + if (isSigned) { + return [p0, p1]() { return static_cast(p0) / static_cast(p1); }; + } else { + return [p0, p1]() { return static_cast(p0) / static_cast(p1); }; + } + } + case OP_rem: { + if (isSigned) { + return [p0, p1]() { return static_cast(p0) % static_cast(p1); }; + } else { + return [p0, p1]() { return static_cast(p0) % static_cast(p1); }; + } + } + case OP_shl: { + if (isSigned) { + return [p0, p1]() { return static_cast(p0) << static_cast(p1); }; + } else { + return [p0, p1]() { return static_cast(p0) << static_cast(p1); }; + } + } + case OP_lshr: + case OP_ashr: { + if (isSigned) { + return [p0, p1]() { return static_cast(p0) >> static_cast(p1); }; + } else { + return [p0, p1]() { return static_cast(p0) >> static_cast(p1); }; + } + } + case OP_bior: { + if (isSigned) { + return [p0, p1]() { return static_cast(p0) | static_cast(p1); }; + } else { + return [p0, p1]() { return static_cast(p0) | static_cast(p1); }; + } + } + case OP_band: { + if (isSigned) { + return [p0, p1]() { return static_cast(p0) & static_cast(p1); }; + } else { + return [p0, p1]() { return static_cast(p0) & static_cast(p1); }; + } + } + case OP_bxor: { + if (isSigned) { + return [p0, p1]() { return static_cast(p0) ^ static_cast(p1); }; + } else { + return [p0, p1]() { return static_cast(p0) ^ static_cast(p1); }; + } + } + case OP_land: { + return [p0, p1]() { + if (!p0) { + return static_cast(0); + } else if (!p1) { + return static_cast(0); + } else { + return static_cast(1); + } + }; + } + case OP_lior: { + return [p0, p1]() { + if (p0) { + return static_cast(1); + } else if (p1) { + return static_cast(1); + } else { + return static_cast(0); + } + }; + } + case OP_cand: { + return [p0, p1]() { + if (!p0) { + return static_cast(0); + } else if (!p1) { + return static_cast(0); + } else { + return static_cast(1); + } + }; + } + case OP_cior: { + return [p0, p1]() { + if (p0) { + return static_cast(1); + } else if (p1) { + return static_cast(1); + } else { + return static_cast(0); + } + }; + } + default: { + return nullptr; + } + } + return nullptr; +} + +template +T *MIRConstGenerator(MemPool *mp, T *konst0, T *konst1, Opcode op) { + bool isSigned = IsSignedInteger(konst0->GetType().GetPrimType()) && IsSignedInteger(konst1->GetType().GetPrimType()); + return mp->New(OpGenerator(op, konst0->GetValue(), konst1->GetValue(), isSigned)(), konst0->GetType()); +} +} // namespace maple +#endif // HIR2MPL_INCLUDE_FE_UTILS_AST_H diff --git a/src/hir2mpl/common/include/fe_utils_java.h b/src/hir2mpl/common/include/fe_utils_java.h new file mode 100644 index 0000000000000000000000000000000000000000..e914e6ff4c5a9e9bd739d798de1135d841599ffa --- /dev/null +++ b/src/hir2mpl/common/include/fe_utils_java.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FE_UTILS_JAVA_H +#define HIR2MPL_INCLUDE_FE_UTILS_JAVA_H +#include +#include +#include "feir_type.h" + +namespace maple { +class FEUtilJava { + public: + static std::vector SolveMethodSignature(const std::string &signature); + static std::string SolveParamNameInJavaFormat(const std::string &signature); + + private: + FEUtilJava() = default; + ~FEUtilJava() = default; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_FE_UTILS_JAVA_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/feir_builder.h b/src/hir2mpl/common/include/feir_builder.h new file mode 100644 index 0000000000000000000000000000000000000000..bdf4f1b8b8fe854846bfef8993d203565c13b0a6 --- /dev/null +++ b/src/hir2mpl/common/include/feir_builder.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FEIR_BUILDER_H +#define HIR2MPL_INCLUDE_COMMON_FEIR_BUILDER_H +#include +#include "mir_function.h" +#include "mpl_logging.h" +#include "feir_var.h" +#include "feir_stmt.h" + +namespace maple { +class FEIRBuilder { + public: + FEIRBuilder() = default; + ~FEIRBuilder() = default; + // Type + static UniqueFEIRType CreateType(PrimType basePty, const GStrIdx &baseNameIdx, uint32 dim); + static UniqueFEIRType CreateArrayElemType(const UniqueFEIRType &arrayType); + static UniqueFEIRType CreateRefType(const GStrIdx &baseNameIdx, uint32 dim); + static UniqueFEIRType CreateTypeByJavaName(const std::string &typeName, bool inMpl); + // Var + static UniqueFEIRVar CreateVarReg(uint32 regNum, PrimType primType, bool isGlobal = false); + static UniqueFEIRVar CreateVarReg(uint32 regNum, UniqueFEIRType type, bool isGlobal = false); + static UniqueFEIRVar CreateVarName(GStrIdx nameIdx, PrimType primType, bool isGlobal = false, + bool withType = false); + static UniqueFEIRVar CreateVarName(const std::string &name, PrimType primType, bool isGlobal = false, + bool withType = false); + static UniqueFEIRVar CreateVarNameForC(GStrIdx nameIdx, MIRType &mirType, bool isGlobal = false, + bool withType = false); + static UniqueFEIRVar CreateVarNameForC(const std::string &name, MIRType &mirType, bool isGlobal = false, + bool withType = false); + static UniqueFEIRVar CreateVarNameForC(const std::string &name, UniqueFEIRType type, + bool isGlobal = false, bool withType = false); + // Expr + static UniqueFEIRExpr CreateExprSizeOfType(UniqueFEIRType ty); + static UniqueFEIRExpr CreateExprDRead(UniqueFEIRVar srcVar); + static UniqueFEIRExpr CreateExprDReadAggField(UniqueFEIRVar srcVar, FieldID fieldID, UniqueFEIRType fieldType); + static UniqueFEIRExpr CreateExprAddrofLabel(const std::string &lbName, UniqueFEIRType exprTy); + static UniqueFEIRExpr CreateExprAddrofVar(UniqueFEIRVar srcVar); + static UniqueFEIRExpr CreateExprAddrofFunc(const std::string &addr); + static UniqueFEIRExpr CreateExprAddrofArray(UniqueFEIRType argTypeNativeArray, + UniqueFEIRExpr argExprArray, std::string argArrayName, + std::list &argExprIndexs); + static UniqueFEIRExpr CreateExprIRead(UniqueFEIRType returnType, UniqueFEIRType ptrType, + UniqueFEIRExpr expr, FieldID id = 0); + static UniqueFEIRExpr CreateExprTernary(Opcode op, UniqueFEIRType type, UniqueFEIRExpr cExpr, + UniqueFEIRExpr tExpr, UniqueFEIRExpr fExpr); + static UniqueFEIRExpr CreateExprConstRefNull(); + static UniqueFEIRExpr CreateExprConstPtrNull(); + static UniqueFEIRExpr CreateExprConstI8(int8 val); + static UniqueFEIRExpr CreateExprConstI16(int16 val); + static UniqueFEIRExpr CreateExprConstI32(int32 val); + static UniqueFEIRExpr CreateExprConstU32(uint32 val); + static UniqueFEIRExpr CreateExprConstI64(int64 val); + static UniqueFEIRExpr CreateExprConstU64(uint64 val); + static UniqueFEIRExpr CreateExprConstF32(float val); + static UniqueFEIRExpr CreateExprConstF64(double val); + static UniqueFEIRExpr CreateExprConstPtr(int64 val); + static UniqueFEIRExpr CreateExprConstAnyScalar(PrimType primType, int64 val); + static UniqueFEIRExpr CreateExprVdupAnyVector(PrimType primtype, int64 val); + static UniqueFEIRExpr CreateExprMathUnary(Opcode op, UniqueFEIRVar var0); + static UniqueFEIRExpr CreateExprMathUnary(Opcode op, UniqueFEIRExpr expr); + static UniqueFEIRExpr CreateExprZeroCompare(Opcode op, UniqueFEIRExpr expr); + static UniqueFEIRExpr CreateExprMathBinary(Opcode op, UniqueFEIRVar var0, UniqueFEIRVar var1); + static UniqueFEIRExpr CreateExprMathBinary(Opcode op, UniqueFEIRExpr expr0, UniqueFEIRExpr expr1); + static UniqueFEIRExpr CreateExprBinary(Opcode op, UniqueFEIRExpr expr0, UniqueFEIRExpr expr1); + static UniqueFEIRExpr CreateExprBinary(UniqueFEIRType exprType, Opcode op, + UniqueFEIRExpr expr0, UniqueFEIRExpr expr1); + static UniqueFEIRExpr CreateExprSExt(UniqueFEIRVar srcVar); + static UniqueFEIRExpr CreateExprSExt(UniqueFEIRExpr srcExpr, PrimType dstType); + static UniqueFEIRExpr CreateExprZExt(UniqueFEIRVar srcVar); + static UniqueFEIRExpr CreateExprZExt(UniqueFEIRExpr srcExpr, PrimType dstType); + static UniqueFEIRExpr CreateExprCvtPrim(UniqueFEIRVar srcVar, PrimType dstType); + static UniqueFEIRExpr CreateExprCvtPrim(UniqueFEIRExpr srcExpr, PrimType dstType); + static UniqueFEIRExpr CreateExprCvtPrim(UniqueFEIRExpr srcExpr, PrimType srcType, PrimType dstType); + static UniqueFEIRExpr CreateExprCvtPrim(Opcode argOp, UniqueFEIRExpr srcExpr, PrimType dstType); + static UniqueFEIRExpr CreateExprCastPrim(UniqueFEIRExpr srcExpr, PrimType dstType); + static UniqueFEIRExpr CreateExprJavaNewInstance(UniqueFEIRType type); + static UniqueFEIRExpr CreateExprJavaNewInstance(UniqueFEIRType type, uint32 argTypeID); + static UniqueFEIRExpr CreateExprJavaNewInstance(UniqueFEIRType type, uint32 argTypeID, bool isRcPermanent); + static UniqueFEIRExpr CreateExprJavaNewArray(UniqueFEIRType type, UniqueFEIRExpr exprSize); + static UniqueFEIRExpr CreateExprJavaNewArray(UniqueFEIRType type, UniqueFEIRExpr exprSize, uint32 typeID); + static UniqueFEIRExpr CreateExprJavaNewArray(UniqueFEIRType type, UniqueFEIRExpr exprSize, uint32 typeID, + bool isRcPermanent); + static UniqueFEIRExpr CreateExprJavaArrayLength(UniqueFEIRExpr exprArray); + + // Stmt + static UniqueFEIRStmt CreateStmtDAssign(UniqueFEIRVar dstVar, UniqueFEIRExpr srcExpr, bool hasException = false); + static UniqueFEIRStmt CreateStmtDAssignAggField(UniqueFEIRVar dstVar, UniqueFEIRExpr srcExpr, FieldID fieldID); + static UniqueFEIRStmt CreateStmtIAssign(UniqueFEIRType dstType, UniqueFEIRExpr dstExpr, + UniqueFEIRExpr srcExpr, FieldID fieldID = 0); + static UniqueFEIRStmt CreateStmtGoto(uint32 targetLabelIdx); + static UniqueFEIRStmt CreateStmtGoto(const std::string &labelName); + static UniqueFEIRStmt CreateStmtIGoto(UniqueFEIRExpr targetExpr); + static UniqueFEIRStmt CreateStmtCondGoto(uint32 targetLabelIdx, Opcode op, UniqueFEIRExpr expr); + static UniqueFEIRStmt CreateStmtSwitch(UniqueFEIRExpr expr); + static UniqueFEIRStmt CreateStmtIfWithoutElse(UniqueFEIRExpr cond, std::list &thenStmts); + static UniqueFEIRStmt CreateStmtIf(UniqueFEIRExpr cond, std::list &thenStmts, + std::list &elseStmts); + static UniqueFEIRStmt CreateStmtJavaConstClass(UniqueFEIRVar dstVar, UniqueFEIRType type); + static UniqueFEIRStmt CreateStmtJavaConstString(UniqueFEIRVar dstVar, const std::string &strVal); + static UniqueFEIRStmt CreateStmtJavaCheckCast(UniqueFEIRVar dstVar, UniqueFEIRVar srcVar, UniqueFEIRType type); + static UniqueFEIRStmt CreateStmtJavaCheckCast(UniqueFEIRVar dstVar, UniqueFEIRVar srcVar, UniqueFEIRType type, + uint32 argTypeID); + static UniqueFEIRStmt CreateStmtJavaInstanceOf(UniqueFEIRVar dstVar, UniqueFEIRVar srcVar, UniqueFEIRType type); + static UniqueFEIRStmt CreateStmtJavaInstanceOf(UniqueFEIRVar dstVar, UniqueFEIRVar srcVar, UniqueFEIRType type, + uint32 argTypeID); + static UniqueFEIRStmt CreateStmtJavaFillArrayData(UniqueFEIRVar argVar, const int8 *arrayData, + uint32 size, const std::string &arrayName); + static std::list CreateStmtArrayStore(UniqueFEIRVar varElem, UniqueFEIRVar varArray, + UniqueFEIRVar varIndex); + static UniqueFEIRStmt CreateStmtArrayStoreOneStmt(UniqueFEIRVar varElem, UniqueFEIRVar varArray, + UniqueFEIRExpr exprIndex); + static UniqueFEIRStmt CreateStmtArrayStoreOneStmtForC(UniqueFEIRExpr exprElem, UniqueFEIRExpr exprArray, + UniqueFEIRExpr exprIndex, UniqueFEIRType arrayType); + static UniqueFEIRStmt CreateStmtArrayStoreOneStmtForC(UniqueFEIRExpr exprElem, UniqueFEIRExpr exprArray, + UniqueFEIRExpr exprIndex, UniqueFEIRType arrayType, + const std::string &argArrayName); + static UniqueFEIRStmt CreateStmtArrayStoreOneStmtForC(UniqueFEIRExpr exprElem, UniqueFEIRExpr exprArray, + std::list exprIndexs, + UniqueFEIRType arrayType, const std::string &argArrayName); + static UniqueFEIRStmt CreateStmtArrayStoreOneStmtForC(UniqueFEIRExpr exprElem, UniqueFEIRExpr exprArray, + UniqueFEIRExpr exprIndex, UniqueFEIRType arrayType, + UniqueFEIRType elemType, const std::string &argArrayName); + static std::list CreateStmtArrayLoad(UniqueFEIRVar varElem, UniqueFEIRVar varArray, + UniqueFEIRVar varIndex); + static UniqueFEIRStmt CreateStmtArrayLength(UniqueFEIRVar varLength, UniqueFEIRVar varArray); + static UniqueFEIRStmt CreateStmtRetype(UniqueFEIRVar varDst, const UniqueFEIRVar &varSrc); + static UniqueFEIRStmt CreateStmtComment(const std::string &comment); + static UniqueFEIRExpr ReadExprField(UniqueFEIRExpr expr, FieldID fieldID, UniqueFEIRType fieldType); + static UniqueFEIRStmt AssginStmtField(const UniqueFEIRExpr &addrExpr, UniqueFEIRExpr srcExpr, FieldID fieldID); + static bool IsZeroConstExpr(const UniqueFEIRExpr &expr); +}; // class FEIRBuilder +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FEIR_BUILDER_H diff --git a/src/hir2mpl/common/include/feir_node_kind.def b/src/hir2mpl/common/include/feir_node_kind.def new file mode 100644 index 0000000000000000000000000000000000000000..42d9797447be5639f57e569b28b2a089a4b39c9b --- /dev/null +++ b/src/hir2mpl/common/include/feir_node_kind.def @@ -0,0 +1,87 @@ +// FEIR_NODE_KIND (kind, description) +FEIR_NODE_KIND(Stmt, "Stmt") +FEIR_NODE_KIND(StmtNary, "StmtNary") +FEIR_NODE_KIND(StmtAssign, "StmtAssign") +FEIR_NODE_KIND(StmtNonAssign, "StmtNonAssign") +FEIR_NODE_KIND(StmtPesudo, "StmtPesudo") +FEIR_NODE_KIND(StmtDAssign, "StmtDAssign") +FEIR_NODE_KIND(StmtJavaTypeCheck, "StmtJavaTypeCheck") +FEIR_NODE_KIND(StmtJavaConstClass, "StmtJavaConstClass") +FEIR_NODE_KIND(StmtJavaConstString, "StmtJavaConstString") +FEIR_NODE_KIND(StmtJavaMultiANewArray, "StmtJavaMultiANewArray") +FEIR_NODE_KIND(StmtCallAssign, "StmtCallAssign") +FEIR_NODE_KIND(StmtICallAssign, "StmtICallAssign") +FEIR_NODE_KIND(StmtJavaDynamicCallAssign, "StmtJavaDynamicCallAssign") +FEIR_NODE_KIND(StmtIntrinsicCallAssign, "StmtIntrinsicCallAssign") +FEIR_NODE_KIND(StmtIAssign, "StmtIAssign") +FEIR_NODE_KIND(StmtUseOnly, "StmtUseOnly") +FEIR_NODE_KIND(StmtReturn, "StmtReturn") +FEIR_NODE_KIND(StmtBranch, "StmtBranch") +FEIR_NODE_KIND(StmtGoto, "StmtGoto") +FEIR_NODE_KIND(StmtIGoto, "StmtIGoto") +FEIR_NODE_KIND(StmtCondGoto, "StmtCondGoto") +FEIR_NODE_KIND(StmtSwitch, "StmtSwitch") +FEIR_NODE_KIND(StmtArrayStore, "StmtArrayStore") +FEIR_NODE_KIND(StmtFieldStore, "StmtFieldStore") +FEIR_NODE_KIND(StmtFieldLoad, "StmtFieldLoad") +FEIR_NODE_KIND(StmtFieldStoreForC, "StmtFieldStoreForC") +FEIR_NODE_KIND(ExprFieldLoadForC, "ExprFieldLoadForC") +FEIR_NODE_KIND(Expr, "Expr") +FEIR_NODE_KIND(ExprNestable, "ExprNestable") +FEIR_NODE_KIND(ExprNonNestable, "ExprNonNestable") +FEIR_NODE_KIND(ExprConst, "ExprConst") +FEIR_NODE_KIND(ExprSizeOfType, "ExprSizeOfType") +FEIR_NODE_KIND(ExprDRead, "ExprDRead") +FEIR_NODE_KIND(ExprIRead, "ExprIRead") +FEIR_NODE_KIND(ExprRegRead, "ExprRegRead") +FEIR_NODE_KIND(ExprConvert, "ExprConvert") +FEIR_NODE_KIND(ExprIntExt, "ExprIntExt") +FEIR_NODE_KIND(ExprRetype, "ExprRetype") +FEIR_NODE_KIND(ExprCompare, "ExprCompare") +FEIR_NODE_KIND(ExprUnary, "ExprUnary") +FEIR_NODE_KIND(ExprBinary, "ExprBinary") +FEIR_NODE_KIND(ExprTernary, "ExprTernary") +FEIR_NODE_KIND(ExprNary, "ExprNary") +FEIR_NODE_KIND(ExprArray, "ExprArray") +FEIR_NODE_KIND(ExprAddrof, "ExprAddrof") +FEIR_NODE_KIND(ExprAddrofLabel, "ExprAddrofLabel") +FEIR_NODE_KIND(ExprIAddrof, "ExprIAddrof") +FEIR_NODE_KIND(ExprAddrofVar, "ExprAddrofVar") +FEIR_NODE_KIND(ExprAddrofFunc, "ExprAddrofFunc") +FEIR_NODE_KIND(ExprAddrofArray, "ExprAddrofArray") +FEIR_NODE_KIND(ExprAddrofStruct, "ExprAddrofStruct") +FEIR_NODE_KIND(ExprIntrinsicop, "ExprIntrinsicop") +FEIR_NODE_KIND(FEIRExprJavaMerge, "FEIRExprJavaMerge") +FEIR_NODE_KIND(ExprTypeCvt, "ExprTypeCvt") +FEIR_NODE_KIND(ExprJavaNewInstance, "ExprJavaNewInstance") +FEIR_NODE_KIND(ExprJavaNewArray, "ExprJavaNewArray") +FEIR_NODE_KIND(ExprJavaArrayLength, "ExprJavaArrayLength") +FEIR_NODE_KIND(ExprJavaInstanceOf, "ExprJavaInstanceOf") +FEIR_NODE_KIND(ExprArrayStoreForC, "ExprArrayStoreForC") +FEIR_NODE_KIND(ExprArrayLoad, "ExprArrayLoad") +FEIR_NODE_KIND(ExprCStyleCast, "ExprCStyleCast") +FEIR_NODE_KIND(ExprAtomic, "ExprAtomic") +FEIR_NODE_KIND(StmtJavaFillArrayData, "StmtJavaFillArrayData") +FEIR_NODE_KIND(StmtPesudoFuncStart, "StmtPesudoFuncStart") +FEIR_NODE_KIND(StmtPesudoFuncEnd, "StmtPesudoFuncEnd") +FEIR_NODE_KIND(StmtCheckPoint, "StmtCheckPoint") +FEIR_NODE_KIND(StmtPesudoLOC, "StmtPesudoLOC") +FEIR_NODE_KIND(StmtPesudoLabel, "StmtPesudoLabel") +FEIR_NODE_KIND(StmtPesudoJavaTry, "StmtPesudoJavaTry") +FEIR_NODE_KIND(StmtPesudoEndTry, "StmtPesudoEndTry") +FEIR_NODE_KIND(StmtPesudoJavaCatch, "StmtPesudoJavaCatch") +FEIR_NODE_KIND(StmtPesudoSafe, "StmtPesudoSafe") +FEIR_NODE_KIND(StmtPesudoUnsafe, "StmtPesudoUnsafe") +FEIR_NODE_KIND(StmtPesudoComment, "StmtPesudoComment") +FEIR_NODE_KIND(StmtPesudoCommentForInst, "StmtPesudoCommentForInst") +FEIR_NODE_KIND(StmtCaseForC, "StmtCaseForC") +FEIR_NODE_KIND(StmtDefaultForC, "StmtDefaultForC") +FEIR_NODE_KIND(StmtIf, "StmtIf") +FEIR_NODE_KIND(StmtDoWhile, "StmtDoWhile") +FEIR_NODE_KIND(StmtBreak, "StmtBreak") +FEIR_NODE_KIND(StmtContinue, "StmtContinue") +FEIR_NODE_KIND(StmtLabel, "StmtLabel") +FEIR_NODE_KIND(StmtAtomic, "StmtAtomic") +FEIR_NODE_KIND(StmtGCCAsm, "StmtGCCAsm") +FEIR_NODE_KIND(StmtPesudoHead, "StmtPesudoHead") +FEIR_NODE_KIND(StmtPesudoTail, "StmtPesudoTail") diff --git a/src/hir2mpl/common/include/feir_stmt.h b/src/hir2mpl/common/include/feir_stmt.h new file mode 100755 index 0000000000000000000000000000000000000000..aebaa12dea6226208079467acae9977d29158b63 --- /dev/null +++ b/src/hir2mpl/common/include/feir_stmt.h @@ -0,0 +1,2865 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_FEIR_STMT_H +#define HIR2MPL_INCLUDE_COMMON_FEIR_STMT_H +#include +#include +#include +#include +#include +#include +#include +#include +#include "types_def.h" +#include "mempool_allocator.h" +#include "mir_builder.h" +#include "factory.h" +#include "safe_ptr.h" +#include "fe_utils.h" +#include "feir_var.h" +#include "fe_struct_elem_info.h" +#include "feir_var_type_scatter.h" +#include "fe_options.h" +#include "feir_type_helper.h" +#include "feir_dfg.h" + +namespace maple { +class FEIRBuilder; + +enum FEIRNodeKind : uint8 { +#define FEIR_NODE_KIND(kind, description) \ + k##kind, +#include "feir_node_kind.def" +#undef FEIR_NODE_KIND +}; + +std::string GetFEIRNodeKindDescription(FEIRNodeKind kindArg); +constexpr uint32 kOpHashShift = 24; +constexpr uint32 kTypeHashShift = 8; +constexpr uint32 kOtherShift = 16; +constexpr uint32 kRandomNum = 0x9e3779b9; + +// ---------- FEIRNode ---------- +class FEIRNode { + public: + explicit FEIRNode(FEIRNodeKind argKind) + : kind(argKind) {} + virtual ~FEIRNode() = default; + + protected: + FEIRNodeKind kind; +}; // class FEIRNode + +// ---------- FEIRDFGNode ---------- +class FEIRDFGNode { + public: + explicit FEIRDFGNode(const UniqueFEIRVar &argVar) + : var(argVar) { + CHECK_NULL_FATAL(argVar); + } + + virtual ~FEIRDFGNode() = default; + bool operator==(const FEIRDFGNode &node) const { + return var->EqualsTo(node.var); + } + + size_t Hash() const { + return var->Hash(); + } + + std::string GetNameRaw() const { + return var->GetNameRaw(); + } + + private: + const UniqueFEIRVar &var; +}; + +class FEIRDFGNodeHash { + public: + std::size_t operator()(const FEIRDFGNode &node) const { + return node.Hash(); + } +}; + +using UniqueFEIRDFGNode = std::unique_ptr; + +class FEIRStmtCheckPoint; +// ---------- FEIRStmt ---------- +class FEIRStmt : public FELinkListNode { + public: + explicit FEIRStmt(FEIRNodeKind argKind) + : kind(argKind) {} + + FEIRStmt() + : kind(kStmt) {} // kStmt as default + + virtual ~FEIRStmt() = default; + void RegisterDFGNodes2CheckPoint(FEIRStmtCheckPoint &checkPoint) { + RegisterDFGNodes2CheckPointImpl(checkPoint); + } + + bool CalculateDefs4AllUses(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return CalculateDefs4AllUsesImpl(checkPoint, udChain); + } + + void InitTrans4AllVars() { + InitTrans4AllVarsImpl(); + } + + FEIRVarTypeScatter* GetTypeScatterDefVar() const { + return GetTypeScatterDefVarImpl(); + } + + std::list GenMIRStmts(MIRBuilder &mirBuilder) const { + std::list stmts = GenMIRStmtsImpl(mirBuilder); + SetMIRStmtSrcPos(stmts); + return stmts; + } + + FEIRNodeKind GetKind() const { + return kind; + } + + void SetKind(FEIRNodeKind argKind) { + kind = argKind; + } + + bool IsFallThru() const { + return IsFallThroughImpl(); + } + + void SetFallThru(bool arg) { + isFallThru = arg; + } + + bool IsBranch() const { + return IsBranchImpl(); + } + + bool IsStmtInst() const { + return IsStmtInstImpl(); + } + + bool IsTarget() const { + return IsTargetImpl(); + } + + bool IsThrowable() const { + return isThrowable; + } + + void SetThrowable(bool argIsThrowable) { + isThrowable = argIsThrowable; + } + + uint32 GetID() const { + return id; + } + + void SetID(uint32 arg) { + id = arg; + } + + bool IsAuxPre() const { + return isAuxPre; + } + + bool IsAuxPost() const { + return isAuxPost; + } + + bool IsAux() const { + return isAuxPre || isAuxPost; + } + + const std::vector &GetExtraPreds() const { + return extraPreds; + } + + const std::vector &GetExtraSuccs() const { + return extraSuccs; + } + + void AddExtraPred(FEIRStmt &stmt) { + extraPreds.push_back(&stmt); + } + + void AddExtraSucc(FEIRStmt &stmt) { + extraSuccs.push_back(&stmt); + } + + bool HasDef() const { + return HasDefImpl(); + } + + void SetHexPC(uint32 argHexPC) { + return SetHexPCImpl(argHexPC); + } + + uint32 GetHexPC(void) const { + return GetHexPCImpl(); + } + + bool IsStmtInstComment() const; + bool ShouldHaveLOC() const; + BaseNode *ReplaceAddrOfNode(BaseNode *node) const; + void SetSrcFileInfo(uint32 srcFileIdxIn, uint32 srcFileLineNumIn) { + srcFileIndex = srcFileIdxIn; + srcFileLineNum = srcFileLineNumIn; + } + + uint32 GetSrcFileIdx() const { + return srcFileIndex; + } + + uint32 GetSrcFileLineNum() const { + return srcFileLineNum; + } + + bool HasSetLOCInfo() const { + return (srcFileLineNum != 0 || srcFileIndex != 0); + } + + bool IsDummy() const { + return isDummy; + } + + void SetDummy() { + isDummy = true; + } + + std::string DumpDotString() const { + return DumpDotStringImpl(); + } + + void Dump(const std::string &prefix = "") const { + return DumpImpl(prefix); + } + + protected: + virtual std::string DumpDotStringImpl() const; + virtual void DumpImpl(const std::string &prefix) const; + virtual void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) {} + virtual bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return true; + } + + virtual FEIRVarTypeScatter* GetTypeScatterDefVarImpl() const { + return nullptr; + } + + virtual void InitTrans4AllVarsImpl() {} + virtual std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const; + virtual bool IsStmtInstImpl() const; + virtual bool IsFallThroughImpl() const { + return isFallThru; + } + + virtual bool IsBranchImpl() const { + return false; + } + + virtual bool IsTargetImpl() const { + return false; + } + + virtual bool HasDefImpl() const { + return false; + } + + void SetHexPCImpl(uint32 argHexPC) { + hexPC = argHexPC; + } + + uint32 GetHexPCImpl(void) const { + return hexPC; + } + + void SetMIRStmtSrcPos(std::list &stmts) const { + if (FEOptions::GetInstance().IsDumpLOC() && !stmts.empty()) { + (*stmts.begin())->GetSrcPos().SetFileNum(static_cast(srcFileIndex)); + (*stmts.begin())->GetSrcPos().SetLineNum(srcFileLineNum); + } + } + + FEIRNodeKind kind; + uint32 id = 0; + uint32 srcFileIndex = 0; + uint32 srcFileLineNum = 0; + uint32 hexPC = UINT32_MAX; + bool isDummy = false; + bool isFallThru = true; + bool isAuxPre = false; + bool isAuxPost = false; + bool isThrowable = false; + std::vector extraPreds; + std::vector extraSuccs; +}; + +using UniqueFEIRStmt = std::unique_ptr; + +// ---------- FEIRStmtCheckPoint ---------- +class FEIRStmtCheckPoint : public FEIRStmt { + public: + FEIRStmtCheckPoint() + : FEIRStmt(FEIRNodeKind::kStmtCheckPoint), + firstVisibleStmt(nullptr) {} + ~FEIRStmtCheckPoint() { + firstVisibleStmt = nullptr; + } + + void Reset(); + void RegisterDFGNode(UniqueFEIRVar &var); + void RegisterDFGNodes(const std::list &vars); + void RegisterDFGNodeFromAllVisibleStmts(); + void AddPredCheckPoint(FEIRStmtCheckPoint &stmtCheckPoint); + std::set &CalcuDef(UniqueFEIRVar &use); + void SetFirstVisibleStmt(FEIRStmt &stmt) { + CHECK_FATAL((stmt.GetKind() != FEIRNodeKind::kStmtCheckPoint), "check point should not be DFG Node."); + firstVisibleStmt = &stmt; + } + + protected: + std::string DumpDotStringImpl() const override; + + private: + void CalcuDefDFS(std::set &result, const UniqueFEIRVar &use, const FEIRStmtCheckPoint &cp, + std::set &visitSet) const; + std::set predCPs; + std::list defs; + std::list uses; + FEIRUseDefChain localUD; + std::unordered_map lastDef; + std::unordered_map, FEIRDFGNodeHash> cacheUD; + FEIRStmt *firstVisibleStmt; +}; + +// ---------- FEIRExpr ---------- +class FEIRExpr { + public: + explicit FEIRExpr(FEIRNodeKind argKind); + FEIRExpr(FEIRNodeKind argKind, std::unique_ptr argType); + virtual ~FEIRExpr() = default; + FEIRExpr(const FEIRExpr&) = delete; + FEIRExpr& operator=(const FEIRExpr&) = delete; + std::string DumpDotString() const; + std::unique_ptr Clone(); + + virtual bool operator==(const FEIRExpr &expr) const { + return false; + } + + virtual bool operator!=(const FEIRExpr &expr) const { + return true; + } + + BaseNode *GenMIRNode(MIRBuilder &mirBuilder) const { + return GenMIRNodeImpl(mirBuilder); + } + + std::vector GetVarUses() const { + return GetVarUsesImpl(); + } + + bool IsNestable() const { + return IsNestableImpl(); + } + + bool IsAddrof() const { + return IsAddrofImpl(); + } + + void SetAddrof(bool flag) { + isAddrof = flag; + } + + bool HasException() const { + return HasExceptionImpl(); + } + + void SetIsBoundaryChecking(bool flag) { + isBoundaryChecking = flag; + } + + bool IsBoundaryChecking() const { + return isBoundaryChecking; + } + + void SetType(std::unique_ptr argType) { + SetTypeImpl(std::move(argType)); + } + + FEIRNodeKind GetKind() const { + return kind; + } + + void SetKind(FEIRNodeKind specKind) { + kind = specKind; + } + + FEIRType *GetType() const { + return GetTypeImpl(); + } + + const FEIRType &GetTypeRef() const { + return GetTypeRefImpl(); + } + + PrimType GetPrimType() const { + return GetPrimTypeImpl(); + } + + FieldID GetFieldID() const { + return GetFieldIDImpl(); + } + + void SetFieldID(FieldID fieldID) { + return SetFieldIDImpl(fieldID); + } + + void SetFieldType(std::unique_ptr fieldType) { + return SetFieldTypeImpl(std::move(fieldType)); + } + + void RegisterDFGNodes2CheckPoint(FEIRStmtCheckPoint &checkPoint) { + RegisterDFGNodes2CheckPointImpl(checkPoint); + } + + bool CalculateDefs4AllUses(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return CalculateDefs4AllUsesImpl(checkPoint, udChain); + } + + uint32 Hash() const { + return HashImpl(); + } + + protected: + virtual std::unique_ptr CloneImpl() const = 0; + virtual BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const = 0; + virtual std::vector GetVarUsesImpl() const; + virtual void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) {} + virtual bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return true; + } + + virtual void SetTypeImpl(std::unique_ptr argType) { + ASSERT_NOT_NULL(argType); + type = std::move(argType); + } + + virtual PrimType GetPrimTypeImpl() const { + return type->GetPrimType(); + } + + virtual FEIRType *GetTypeImpl() const { + ASSERT(type != nullptr, "type is nullptr"); + return type.get(); + } + + virtual const FEIRType &GetTypeRefImpl() const { + ASSERT(GetTypeImpl() != nullptr, "type is nullptr"); + return *GetTypeImpl(); + } + + virtual FieldID GetFieldIDImpl() const { + CHECK_FATAL(false, "unsupported in base class"); + } + + virtual void SetFieldIDImpl(FieldID fieldID) { + CHECK_FATAL(false, "unsupported in base class"); + } + + virtual void SetFieldTypeImpl(std::unique_ptr fieldType) { + CHECK_FATAL(false, "unsupported in base class"); + } + + virtual uint32 HashImpl() const { + CHECK_FATAL(false, "unsupported in base class"); + return 0; + } + + virtual bool IsNestableImpl() const; + virtual bool IsAddrofImpl() const; + virtual bool HasExceptionImpl() const; + + FEIRNodeKind kind; + bool isNestable : 1; + bool isAddrof : 1; + bool hasException : 1; + bool isBoundaryChecking : 1; + std::unique_ptr type; +}; // class FEIRExpr + +using UniqueFEIRExpr = std::unique_ptr; + +// ---------- FEIRExprConst ---------- +union ConstExprValue { + bool b; + uint8 u8; + int8 i8; + uint16 u16; + int16 i16; + uint32 u32; + int32 i32; + float f32; + uint64 u64 = 0; + int64 i64; + double f64; +}; + +class FEIRExprConst : public FEIRExpr { + public: + FEIRExprConst(); + FEIRExprConst(int64 val, PrimType argType); + FEIRExprConst(uint64 val, PrimType argType); + explicit FEIRExprConst(uint32 val); + explicit FEIRExprConst(float val); + explicit FEIRExprConst(double val); + ~FEIRExprConst() = default; + FEIRExprConst(const FEIRExprConst&) = delete; + FEIRExprConst& operator=(const FEIRExprConst&) = delete; + + ConstExprValue GetValue() const { + return value; + } + + protected: + std::unique_ptr CloneImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + uint32 HashImpl() const override; + + private: + void CheckRawValue2SetZero(); + ConstExprValue value; +}; + +// ---------- FEIRExprSizeOfType ---------- +class FEIRExprSizeOfType : public FEIRExpr { + public: + explicit FEIRExprSizeOfType(UniqueFEIRType ty); + ~FEIRExprSizeOfType() = default; + + protected: + std::unique_ptr CloneImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + uint32 HashImpl() const override { + return (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + feirType->Hash(); + } + + private: + UniqueFEIRType feirType; +}; + +// ---------- FEIRExprDRead ---------- +class FEIRExprDRead : public FEIRExpr { + public: + explicit FEIRExprDRead(std::unique_ptr argVarSrc); + FEIRExprDRead(std::unique_ptr argType, std::unique_ptr argVarSrc); + ~FEIRExprDRead() = default; + void SetVarSrc(std::unique_ptr argVarSrc); + void SetTrans(UniqueFEIRVarTrans argTrans) { + varSrc->SetTrans(std::move(argTrans)); + } + + bool operator==(const FEIRExpr &expr) const override { + return expr.GetKind() == kExprDRead && *varSrc == *(expr.GetVarUses().front()) && fieldID == expr.GetFieldID(); + } + + bool operator!=(const FEIRExpr &expr) const override { + return expr.GetKind() != kExprDRead || *varSrc != *(expr.GetVarUses().front()) || fieldID != expr.GetFieldID(); + } + + UniqueFEIRVarTrans CreateTransDirect() { + UniqueFEIRVarTrans trans = std::make_unique(FEIRVarTransKind::kFEIRVarTransDirect, varSrc); + return trans; + } + + UniqueFEIRVarTrans CreateTransArrayDimDecr() { + UniqueFEIRVarTrans trans = std::make_unique(FEIRVarTransKind::kFEIRVarTransArrayDimDecr, varSrc); + return trans; + } + + UniqueFEIRVarTrans CreateTransArrayDimIncr() { + UniqueFEIRVarTrans trans = std::make_unique(FEIRVarTransKind::kFEIRVarTransArrayDimIncr, varSrc); + return trans; + } + + const UniqueFEIRVar &GetVar() const { + return varSrc; + } + + std::unique_ptr GetFieldType() const { + return fieldType->Clone(); + } + + protected: + std::unique_ptr CloneImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + std::vector GetVarUsesImpl() const override; + PrimType GetPrimTypeImpl() const override; + void SetTypeImpl(std::unique_ptr argType) override; + FEIRType *GetTypeImpl() const override; + const FEIRType &GetTypeRefImpl() const override; + + FieldID GetFieldIDImpl() const override { + return fieldID; + } + + void SetFieldTypeImpl(std::unique_ptr type) override { + fieldType = std::move(type); + } + + void SetFieldIDImpl(FieldID argFieldID) override { + fieldID = argFieldID; + } + + uint32 HashImpl() const override { + return (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + (static_cast(fieldID) << kOtherShift) + varSrc->Hash(); + } + + private: + std::unique_ptr varSrc; + FieldID fieldID = 0; + std::unique_ptr fieldType; +}; + +// ---------- FEIRExprRegRead ---------- +class FEIRExprRegRead : public FEIRExpr { + public: + FEIRExprRegRead(PrimType pty, int32 regNumIn); + ~FEIRExprRegRead() = default; + + protected: + std::unique_ptr CloneImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + PrimType prmType; + int32 regNum; +}; + +// ---------- FEIRExprAddrofConstArray ---------- +class FEIRExprAddrofConstArray : public FEIRExpr { + public: + FEIRExprAddrofConstArray(const std::vector &arrayIn, MIRType *typeIn, const std::string &strIn); + FEIRExprAddrofConstArray(const std::string &arrayNameIn, const std::vector &arrayIn, MIRType *typeIn, + const std::string &strIn) + : FEIRExpr(FEIRNodeKind::kExprAddrof, + FEIRTypeHelper::CreateTypeNative(*GlobalTables::GetTypeTable().GetPtrType())), + arrayName(arrayNameIn), + elemType(typeIn), + str(strIn) { + std::copy(arrayIn.begin(), arrayIn.end(), std::back_inserter(array)); + } + + ~FEIRExprAddrofConstArray() = default; + + uint32 GetStringLiteralSize() const { + return static_cast(array.size()); + } + + const MIRType *GetElemType() const { + return elemType; + } + + protected: + std::unique_ptr CloneImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + uint32 HashImpl() const override { + uint32 hash = (static_cast(kind) << kOpHashShift); + for (uint32 elem : array) { + hash += static_cast(std::hash{}(elem)); + } + std::size_t seed = array.size(); + for (uint32 elem : array) { + seed ^= elem + kRandomNum + (seed << 6) + (seed >> 2); + } + hash += static_cast(seed); + if (elemType != nullptr) { + hash += static_cast(elemType->GetHashIndex()); + } + return hash; + } + + private: + std::string arrayName; + std::vector array; + MIRType *elemType = nullptr; + std::string str; +}; + +// ---------- FEIRExprAddrOfLabel ---------- +class FEIRExprAddrOfLabel : public FEIRExpr { + public: + FEIRExprAddrOfLabel(const std::string &lbName, UniqueFEIRType exprType) + : FEIRExpr(FEIRNodeKind::kExprAddrofLabel, std::move(exprType)), labelName(lbName) {} + ~FEIRExprAddrOfLabel() = default; + + protected: + std::unique_ptr CloneImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + uint32 HashImpl() const override { + return (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + static_cast(std::hash{}(labelName)); + } + + private: + std::string labelName; +}; + +// ---------- FEIRExprAddrofVar ---------- +class FEIRExprAddrofVar : public FEIRExpr { + public: + explicit FEIRExprAddrofVar(std::unique_ptr argVarSrc) + : FEIRExpr(FEIRNodeKind::kExprAddrofVar, + FEIRTypeHelper::CreateTypeNative(*GlobalTables::GetTypeTable().GetPtrType())), + varSrc(std::move(argVarSrc)) {} + + FEIRExprAddrofVar(std::unique_ptr argVarSrc, FieldID id) + : FEIRExpr(FEIRNodeKind::kExprAddrofVar, + FEIRTypeHelper::CreateTypeNative(*GlobalTables::GetTypeTable().GetPtrType())), + varSrc(std::move(argVarSrc)), fieldID(id) {} + ~FEIRExprAddrofVar() = default; + + void SetVarValue(MIRConst *val) { + cst = val; + } + + MIRConst *GetVarValue() const { + return cst; + } + + protected: + std::unique_ptr CloneImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + std::vector GetVarUsesImpl() const override; + + FieldID GetFieldIDImpl() const override { + return fieldID; + } + + void SetFieldIDImpl(FieldID id) override { + fieldID = id; + } + + uint32 HashImpl() const override { + return (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + (static_cast(fieldID) << kOtherShift) + varSrc->Hash(); + } + + private: + std::unique_ptr varSrc; + FieldID fieldID = 0; + MIRConst *cst = nullptr; +}; + +// ---------- FEIRExprIAddrof ---------- +class FEIRExprIAddrof : public FEIRExpr { + public: + FEIRExprIAddrof(UniqueFEIRType pointeeType, FieldID id, UniqueFEIRExpr expr) + : FEIRExpr(FEIRNodeKind::kExprIAddrof, + FEIRTypeHelper::CreateTypeNative(*GlobalTables::GetTypeTable().GetPtrType())), + ptrType(std::move(pointeeType)), + fieldID(id), + subExpr(std::move(expr)) {} + ~FEIRExprIAddrof() = default; + + UniqueFEIRType GetClonedRetType() const { + return type->Clone(); + } + + UniqueFEIRExpr GetClonedOpnd() const { + return subExpr->Clone(); + } + + UniqueFEIRType GetClonedPtrType() const { + return ptrType->Clone(); + } + + protected: + std::unique_ptr CloneImpl() const override; + std::vector GetVarUsesImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + FieldID GetFieldIDImpl() const override { + return fieldID; + } + + void SetFieldIDImpl(FieldID argFieldID) override { + fieldID = argFieldID; + } + + uint32 HashImpl() const override { + return (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + (static_cast(fieldID) << kOtherShift) + ptrType->Hash() + subExpr->Hash(); + } + + private: + UniqueFEIRType ptrType; + FieldID fieldID = 0; + UniqueFEIRExpr subExpr; +}; + +// ---------- FEIRExprAddrofFunc ---------- +class FEIRExprAddrofFunc : public FEIRExpr { + public: + explicit FEIRExprAddrofFunc(const std::string &addr) + : FEIRExpr(FEIRNodeKind::kExprAddrofFunc, + FEIRTypeHelper::CreateTypeNative(*GlobalTables::GetTypeTable().GetPtrType())), + funcAddr(addr) {} + ~FEIRExprAddrofFunc() = default; + + const std::string &GetFuncAddr() const { + return funcAddr; + } + + protected: + std::unique_ptr CloneImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + uint32 HashImpl() const override { + return (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + static_cast(std::hash{}(funcAddr)); + } + + private: + std::string funcAddr; +}; + +// ---------- FEIRExprAddrofArray ---------- +class FEIRExprAddrofArray : public FEIRExpr { + public: + FEIRExprAddrofArray(UniqueFEIRType argTypeNativeArray, UniqueFEIRExpr argExprArray, const std::string &argArrayName, + std::list &argExprIndexs); + ~FEIRExprAddrofArray() = default; + + void SetIndexsExprs(std::list &exprs) { + exprIndexs.clear(); + for (auto &e : exprs) { + auto ue = e->Clone(); + exprIndexs.push_back(std::move(ue)); + } + } + + const UniqueFEIRType &GetTypeArray() const { + return typeNativeArray; + } + + const std::list &GetExprIndexs() const { + return exprIndexs; + } + + const UniqueFEIRExpr &GetExprArray() const { + return exprArray; + } + + protected: + std::unique_ptr CloneImpl() const override; + std::vector GetVarUsesImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + uint32 HashImpl() const override { + uint32 hash = (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + (static_cast(std::hash{}(arrayName)) << kOtherShift); + if (typeNativeArray != nullptr) { + hash += typeNativeArray->Hash(); + } + if (exprArray != nullptr) { + hash += exprArray->Hash(); + } + std::size_t seed = exprIndexs.size(); + for (auto &idx : exprIndexs) { + if (idx != nullptr) { + seed ^= idx->Hash() + kRandomNum + (seed << 6) + (seed >> 2); + } + } + return hash + static_cast(seed); + } + + private: + mutable std::list exprIndexs; + UniqueFEIRType typeNativeArray = nullptr; + UniqueFEIRExpr exprArray = nullptr; + std::string arrayName; +}; + +// ---------- FEIRExprUnary ---------- +class FEIRExprUnary : public FEIRExpr { + public: + FEIRExprUnary(Opcode argOp, std::unique_ptr argOpnd); + FEIRExprUnary(std::unique_ptr argType, Opcode argOp, std::unique_ptr argOpnd); + ~FEIRExprUnary() = default; + void SetOpnd(std::unique_ptr argOpnd); + const UniqueFEIRExpr &GetOpnd() const; + static std::map InitMapOpNestableForExprUnary(); + + Opcode GetOp() const { + return op; + } + + protected: + virtual std::unique_ptr CloneImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + virtual BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + std::vector GetVarUsesImpl() const override; + + uint32 HashImpl() const override { + return (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + (static_cast(op) << kOtherShift) + opnd->Hash(); + } + + Opcode op; + std::unique_ptr opnd; + + private: + void SetExprTypeByOp(); + + static std::map mapOpNestable; +}; // class FEIRExprUnary + +// ---------- FEIRExprTypeCvt ---------- +class FEIRExprTypeCvt : public FEIRExprUnary { + public: + FEIRExprTypeCvt(Opcode argOp, std::unique_ptr argOpnd); + FEIRExprTypeCvt(std::unique_ptr exprType, Opcode argOp, std::unique_ptr argOpnd); + ~FEIRExprTypeCvt() = default; + static std::map InitMapOpNestableForTypeCvt(); + static Opcode ChooseOpcodeByFromVarAndToVar(const FEIRVar &fromVar, const FEIRVar &toVar); + + void SetSrcPrimType(PrimType pty) { + srcPrimType = pty; + } + + protected: + std::unique_ptr CloneImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + uint32 HashImpl() const override { + return FEIRExprUnary::HashImpl() + static_cast(srcPrimType); + } + + private: + using FuncPtrGenMIRNode = BaseNode* (FEIRExprTypeCvt::*)(MIRBuilder &mirBuilder) const; + static std::map InitFuncPtrMapForParseExpr(); + + // GenMIRNodeMode1: + // MIR: op () + BaseNode *GenMIRNodeMode1(MIRBuilder &mirBuilder) const; + + // GenMIRNodeMode2: + // MIR: op () + BaseNode *GenMIRNodeMode2(MIRBuilder &mirBuilder) const; + + // GenMIRNodeMode3: + // MIR: retype () + BaseNode *GenMIRNodeMode3(MIRBuilder &mirBuilder) const; + + static std::map mapOpNestable; + static std::map funcPtrMapForParseExpr; + PrimType srcPrimType = PTY_unknown; +}; // FEIRExprTypeCvt + +// ---------- FEIRExprExtractBits ---------- +class FEIRExprExtractBits : public FEIRExprUnary { + public: + FEIRExprExtractBits(Opcode argOp, PrimType argPrimType, uint8 argBitOffset, uint8 argBitSize, + std::unique_ptr argOpnd); + FEIRExprExtractBits(Opcode argOp, PrimType argPrimType, std::unique_ptr argOpnd); + ~FEIRExprExtractBits() = default; + static std::map InitMapOpNestableForExtractBits(); + void SetBitOffset(uint8 offset) { + bitOffset = offset; + } + + void SetBitSize(uint8 size) { + bitSize = size; + } + + protected: + std::unique_ptr CloneImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + uint32 HashImpl() const override { + return FEIRExprUnary::HashImpl() + (static_cast(bitOffset) << 16) + static_cast(bitSize); + } + + private: + using FuncPtrGenMIRNode = BaseNode* (FEIRExprExtractBits::*)(MIRBuilder &mirBuilder) const; + static std::map InitFuncPtrMapForParseExpr(); + BaseNode *GenMIRNodeForExtrabits(MIRBuilder &mirBuilder) const; + BaseNode *GenMIRNodeForExt(MIRBuilder &mirBuilder) const; + + uint8 bitOffset; + uint8 bitSize; + static std::map mapOpNestable; + static std::map funcPtrMapForParseExpr; +}; // FEIRExprExtractBit + +// ---------- FEIRExprIRead ---------- +class FEIRExprIRead : public FEIRExpr { + public: + FEIRExprIRead(UniqueFEIRType returnType, UniqueFEIRType pointeeType, FieldID id, UniqueFEIRExpr expr) + : FEIRExpr(FEIRNodeKind::kExprIRead, std::move(returnType)), + ptrType(std::move(pointeeType)), + fieldID(id), + subExpr(std::move(expr)) {} + ~FEIRExprIRead() override = default; + + UniqueFEIRType GetClonedRetType() const { + return type->Clone(); + } + + UniqueFEIRExpr GetClonedOpnd() const { + return subExpr->Clone(); + } + + UniqueFEIRType GetClonedPtrType() const { + return ptrType->Clone(); + } + + protected: + std::unique_ptr CloneImpl() const override; + std::vector GetVarUsesImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + FieldID GetFieldIDImpl() const override { + return fieldID; + } + + void SetFieldIDImpl(FieldID argFieldID) override { + fieldID = argFieldID; + } + + void SetFieldTypeImpl(UniqueFEIRType argFieldType) override { + type = std::move(argFieldType); + } + + uint32 HashImpl() const override { + return (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + (static_cast(fieldID) << kOtherShift) + ptrType->Hash() + subExpr->Hash(); + } + + private: + UniqueFEIRType ptrType = nullptr; + FieldID fieldID = 0; + UniqueFEIRExpr subExpr = nullptr; +}; + +// ---------- FEIRExprBinary ---------- +class FEIRExprBinary : public FEIRExpr { + public: + FEIRExprBinary(Opcode argOp, std::unique_ptr argOpnd0, std::unique_ptr argOpnd1); + FEIRExprBinary(std::unique_ptr exprType, Opcode argOp, std::unique_ptr argOpnd0, + std::unique_ptr argOpnd1); + ~FEIRExprBinary() = default; + void SetOpnd0(std::unique_ptr argOpnd); + void SetOpnd1(std::unique_ptr argOpnd); + const std::unique_ptr &GetOpnd0() const; + const std::unique_ptr &GetOpnd1() const; + bool IsComparative() const; + + Opcode GetOp() const { + return op; + } + + protected: + std::unique_ptr CloneImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + std::vector GetVarUsesImpl() const override; + bool IsNestableImpl() const override; + bool IsAddrofImpl() const override; + + uint32 HashImpl() const override { + return (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + (static_cast(op) << kOtherShift) + (opnd0->Hash() << 8) + opnd1->Hash(); + } + + private: + using FuncPtrGenMIRNode = BaseNode* (FEIRExprBinary::*)(MIRBuilder &mirBuilder) const; + static std::map InitFuncPtrMapForGenMIRNode(); + BaseNode *GenMIRNodeNormal(MIRBuilder &mirBuilder) const; + BaseNode *GenMIRNodeCompare(MIRBuilder &mirBuilder) const; + BaseNode *GenMIRNodeCompareU1(MIRBuilder &mirBuilder) const; + void SetExprTypeByOp(); + void SetExprTypeByOpNormal(); + void SetExprTypeByOpShift(); + void SetExprTypeByOpLogic(); + void SetExprTypeByOpCompare(); + + Opcode op; + std::unique_ptr opnd0; + std::unique_ptr opnd1; + static std::map funcPtrMapForGenMIRNode; +}; // class FEIRExprUnary + +// ---------- FEIRExprTernary ---------- +class FEIRExprTernary : public FEIRExpr { + public: + FEIRExprTernary(Opcode argOp, std::unique_ptr argOpnd0, std::unique_ptr argOpnd1, + std::unique_ptr argOpnd2); + FEIRExprTernary(Opcode argOp, std::unique_ptr argType, std::unique_ptr argOpnd0, + std::unique_ptr argOpnd1, std::unique_ptr argOpnd2); + ~FEIRExprTernary() = default; + void SetOpnd(std::unique_ptr argOpnd, uint32 idx); + + protected: + std::unique_ptr CloneImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + std::vector GetVarUsesImpl() const override; + bool IsNestableImpl() const override; + bool IsAddrofImpl() const override; + + uint32 HashImpl() const override { + return (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + (static_cast(op) << kOtherShift) + (opnd0->Hash() << 8) + (opnd1->Hash() << 16) + opnd1->Hash(); + } + + private: + void SetExprTypeByOp(); + + Opcode op; + std::unique_ptr opnd0; + std::unique_ptr opnd1; + std::unique_ptr opnd2; +}; + +// ---------- FEIRExprNary ---------- +class FEIRExprNary : public FEIRExpr { + public: + explicit FEIRExprNary(Opcode argOp); + virtual ~FEIRExprNary() = default; + void AddOpnd(std::unique_ptr argOpnd); + void AddOpnds(const std::vector> &argOpnds); + void ResetOpnd(); + + protected: + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + std::vector GetVarUsesImpl() const override; + + uint32 HashImpl() const override { + uint32 hash = (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + (static_cast(op) << kOtherShift); + std::size_t seed = opnds.size(); + for (auto &opnd : opnds) { + seed ^= opnd->Hash() + kRandomNum + (seed << 6) + (seed >> 2); + } + hash += static_cast(seed); + return hash; + } + + Opcode op; + std::vector> opnds; +}; // class FEIRExprNary + +// ---------- FEIRExprArray ---------- +class FEIRExprArray : public FEIRExprNary { + public: + FEIRExprArray(Opcode argOp, std::unique_ptr argArray, std::unique_ptr argIndex); + ~FEIRExprArray() = default; + void SetOpndArray(std::unique_ptr opndArray); + void SetOpndIndex(std::unique_ptr opndIndex); + + protected: + std::unique_ptr CloneImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + bool IsNestableImpl() const override; + bool IsAddrofImpl() const override; +}; // class FEIRExprArray + +// ---------- FEIRExprIntrinsicop ---------- +class FEIRExprIntrinsicop : public FEIRExprNary { + public: + FEIRExprIntrinsicop(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID); + FEIRExprIntrinsicop(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID, + std::unique_ptr argParamType); + FEIRExprIntrinsicop(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID, + const std::vector> &argOpnds); + FEIRExprIntrinsicop(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID, + std::unique_ptr argParamType, uint32 argTypeID); + FEIRExprIntrinsicop(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID, + std::unique_ptr argParamType, + const std::vector> &argOpnds); + ~FEIRExprIntrinsicop() = default; + + protected: + std::unique_ptr CloneImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + bool IsNestableImpl() const override; + bool IsAddrofImpl() const override; + + uint32 HashImpl() const override { + uint32 hash = FEIRExprNary::HashImpl() + (static_cast(intrinsicID) << 16) + typeID; + if (paramType != nullptr) { + hash += paramType->Hash(); + } + return hash; + } + + private: + MIRIntrinsicID intrinsicID; + std::unique_ptr paramType; + uint32 typeID = UINT32_MAX; +}; // class FEIRExprIntrinsicop + +class FEIRExprIntrinsicopForC : public FEIRExprNary { + public: + FEIRExprIntrinsicopForC(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID, + const std::vector> &argOpnds); + ~FEIRExprIntrinsicopForC() = default; + + protected: + std::unique_ptr CloneImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + uint32 HashImpl() const override { + return FEIRExprNary::HashImpl() + static_cast(intrinsicID); + } + + private: + MIRIntrinsicID intrinsicID; +}; // class FEIRExprIntrinsicopForC + +class FEIRExprJavaMerge : public FEIRExprNary { + public: + FEIRExprJavaMerge(std::unique_ptr mergedTypeArg, const std::vector> &argOpnds); + ~FEIRExprJavaMerge() = default; + + protected: + std::unique_ptr CloneImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; +}; + +// ---------- FEIRExprJavaNewInstance ---------- +class FEIRExprJavaNewInstance : public FEIRExpr { + public: + explicit FEIRExprJavaNewInstance(UniqueFEIRType argType); + FEIRExprJavaNewInstance(UniqueFEIRType argType, uint32 argTypeID); + FEIRExprJavaNewInstance(UniqueFEIRType argType, uint32 argTypeID, bool argIsRcPermanent); + ~FEIRExprJavaNewInstance() = default; + + protected: + std::unique_ptr CloneImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + uint32 typeID = UINT32_MAX; + // isRcPermanent is true means the rc annotation @Permanent is used + bool isRcPermanent = false; +}; + +// ---------- FEIRExprJavaNewArray ---------- +class FEIRExprJavaNewArray : public FEIRExpr { + public: + FEIRExprJavaNewArray(UniqueFEIRType argArrayType, UniqueFEIRExpr argExprSize); + FEIRExprJavaNewArray(UniqueFEIRType argArrayType, UniqueFEIRExpr argExprSize, uint32 argTypeID); + FEIRExprJavaNewArray(UniqueFEIRType argArrayType, UniqueFEIRExpr argExprSize, uint32 argTypeID, + bool argIsRcPermanent); + ~FEIRExprJavaNewArray() = default; + void SetArrayType(UniqueFEIRType argArrayType) { + CHECK_NULL_FATAL(argArrayType); + arrayType = std::move(argArrayType); + } + + void SetExprSize(UniqueFEIRExpr argExprSize) { + CHECK_NULL_FATAL(argExprSize); + exprSize = std::move(argExprSize); + } + + protected: + std::unique_ptr CloneImpl() const override; + std::vector GetVarUsesImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + private: + UniqueFEIRType arrayType; + UniqueFEIRExpr exprSize; + uint32 typeID = UINT32_MAX; + // isRcPermanent is true means the rc annotation @Permanent is used + bool isRcPermanent = false; +}; + +// ---------- FEIRExprJavaArrayLength ---------- +class FEIRExprJavaArrayLength : public FEIRExpr { + public: + FEIRExprJavaArrayLength(UniqueFEIRExpr argExprArray); + ~FEIRExprJavaArrayLength() = default; + void SetExprArray(UniqueFEIRExpr argExprArray) { + CHECK_NULL_FATAL(argExprArray); + exprArray = std::move(argExprArray); + } + + protected: + std::unique_ptr CloneImpl() const override; + std::vector GetVarUsesImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + private: + UniqueFEIRExpr exprArray; +}; + +// ---------- FEIRExprArrayLoad ---------- +class FEIRExprArrayLoad : public FEIRExpr { + public: + FEIRExprArrayLoad(UniqueFEIRExpr argExprArray, UniqueFEIRExpr argExprIndex, UniqueFEIRType argTypeArray); + ~FEIRExprArrayLoad() = default; + const UniqueFEIRType GetElemType() const { + UniqueFEIRType typeElem = typeArray->Clone(); + (void)typeElem->ArrayDecrDim(); + return typeElem; + } + + UniqueFEIRVarTrans CreateTransArrayDimDecr() { + FEIRExprDRead *dRead = static_cast(exprArray.get()); + return dRead->CreateTransArrayDimDecr(); + } + + void SetTrans(UniqueFEIRVarTrans argTrans) { + CHECK_FATAL(argTrans->GetTransKind() == kFEIRVarTransArrayDimIncr, "ArrayLoad must hold DimIncr Transfer Function"); + FEIRExprDRead *dRead = static_cast(exprArray.get()); + dRead->SetTrans(std::move(argTrans)); + } + + protected: + std::unique_ptr CloneImpl() const override; + std::vector GetVarUsesImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + private: + UniqueFEIRExpr exprArray; + UniqueFEIRExpr exprIndex; + UniqueFEIRType typeArray; +}; + +class FEIRExprCStyleCast : public FEIRExpr { + public: + FEIRExprCStyleCast(MIRType *src, MIRType *dest, UniqueFEIRExpr sub, bool isArr2Pty); + ~FEIRExprCStyleCast() = default; + void SetArray2Pointer(bool isArr2Ptr) { + isArray2Pointer = isArr2Ptr; + } + + void SetRefName(const std::string &name) { + refName = name; + } + + const UniqueFEIRExpr &GetSubExpr() const { + return subExpr; + } + + MIRType *GetMIRType() const { + CHECK_NULL_FATAL(destType); + return destType; + } + + protected: + std::unique_ptr CloneImpl() const override; + std::vector GetVarUsesImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + private: + MIRType *srcType = nullptr; + MIRType *destType = nullptr; + UniqueFEIRExpr subExpr; + bool isArray2Pointer; + std::string refName; +}; + +enum ASTAtomicOp { + kAtomicOpUndefined, + kAtomicOpLoad, + kAtomicOpLoadN, + kAtomicOpStore, + kAtomicOpStoreN, + kAtomicOpExchange, + kAtomicOpExchangeN, + kAtomicOpAddFetch, + kAtomicOpSubFetch, + kAtomicOpAndFetch, + kAtomicOpXorFetch, + kAtomicOpOrFetch, + kAtomicOpNandFetch, + kAtomicOpFetchAdd, + kAtomicOpFetchSub, + kAtomicOpFetchAnd, + kAtomicOpFetchXor, + kAtomicOpFetchOr, + kAtomicOpFetchNand, +}; + +class FEIRExprAtomic : public FEIRExpr { + public: + FEIRExprAtomic(MIRType *ty, MIRType *ref, UniqueFEIRExpr obj, ASTAtomicOp atomOp); + ~FEIRExprAtomic() = default; + + void SetVal1Type(MIRType *ty) { + val1Type = ty; + } + + void SetVal1Expr(UniqueFEIRExpr expr) { + valExpr1 = std::move(expr); + } + + void SetVal2Type(MIRType *ty) { + val2Type = ty; + } + + void SetVal2Expr(UniqueFEIRExpr expr) { + valExpr2 = std::move(expr); + } + + void SetOrderExpr(UniqueFEIRExpr order) { + orderExpr = std::move(order); + } + + void SetValVar(UniqueFEIRVar value) { + val = std::move(value); + } + + protected: + std::unique_ptr CloneImpl() const override; + BaseNode *GenMIRNodeImpl(MIRBuilder &mirBuilder) const override; + + private: + MIRType *mirType = nullptr; + MIRType *refType = nullptr; + MIRType *ptrType = nullptr; + MIRType *val1Type = nullptr; + MIRType *val2Type = nullptr; + UniqueFEIRExpr objExpr; + UniqueFEIRExpr valExpr1; + UniqueFEIRExpr valExpr2; + UniqueFEIRExpr orderExpr; + ASTAtomicOp atomicOp; + UniqueFEIRVar val; +}; + +// ---------- FEIRStmtNary ---------- +class FEIRStmtNary : public FEIRStmt { + public: + FEIRStmtNary(Opcode opIn, std::list> argExprsIn); + virtual ~FEIRStmtNary() = default; + + void SetOP(Opcode opIn) { + op = opIn; + } + + Opcode GetOP() const { + return op; + } + + const std::list> &GetArgExprs() const { + return argExprs; + } + + protected: + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + Opcode op; + std::list> argExprs; +}; + +// ---------- FEIRStmtAssign ---------- +class FEIRStmtAssign : public FEIRStmt { + public: + FEIRStmtAssign(FEIRNodeKind argKind, std::unique_ptr argVar); + ~FEIRStmtAssign() = default; + FEIRVar *GetVar() const { + return var.get(); + } + + void SetVar(std::unique_ptr argVar) { + var = std::move(argVar); + var->SetDef(HasDef()); + } + + void AddExprArg(UniqueFEIRExpr exprArg) { + exprArgs.push_back(std::move(exprArg)); + } + + void AddExprArgReverse(UniqueFEIRExpr exprArg) { + exprArgs.push_front(std::move(exprArg)); + } + + bool HasException() const { + return hasException; + } + + void SetHasException(bool arg) { + hasException = arg; + } + + protected: + bool HasDefImpl() const override { + return ((var != nullptr) && (var.get() != nullptr)); + } + + FEIRVarTypeScatter* GetTypeScatterDefVarImpl() const override { + if (!HasDefImpl()) { + return nullptr; + } + if (var->GetKind() == kFEIRVarTypeScatter) { + FEIRVarTypeScatter *varTypeScatter = static_cast(var.get()); + return varTypeScatter; + } + return nullptr; + } + + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool hasException; + std::unique_ptr var = nullptr; + std::list exprArgs; +}; + +// ---------- FEIRStmtDAssign ---------- +class FEIRStmtDAssign : public FEIRStmtAssign { + public: + FEIRStmtDAssign(std::unique_ptr argVar, std::unique_ptr argExpr, int32 argFieldID = 0); + ~FEIRStmtDAssign() = default; + FEIRExpr *GetExpr() const { + return expr.get(); + } + + void SetExpr(std::unique_ptr argExpr) { + expr = std::move(argExpr); + } + + protected: + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + void InitTrans4AllVarsImpl() override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + void InsertNonnullChecking(MIRBuilder &mirBuilder, const MIRSymbol &dstSym, std::list &ans) const; + void AssignBoundaryVarAndChecking(MIRBuilder &mirBuilder, std::list &ans) const; + void CheckNonnullArgsAndRetForFuncPtr(const MIRBuilder &mirBuilder) const; + void CheckBoundaryArgsAndRetForFuncPtr(const MIRBuilder &mirBuilder) const; + + std::unique_ptr expr; + FieldID fieldID; +}; + +// ---------- FEIRStmtIAssign ---------- +class FEIRStmtIAssign : public FEIRStmt { + public: + FEIRStmtIAssign(UniqueFEIRType argAddrType, UniqueFEIRExpr argAddrExpr, UniqueFEIRExpr argBaseExpr, FieldID id) + : FEIRStmt(FEIRNodeKind::kStmtIAssign), + addrType(std::move(argAddrType)), + addrExpr(std::move(argAddrExpr)), + baseExpr(std::move(argBaseExpr)), + fieldID(id) {} + ~FEIRStmtIAssign() = default; + + protected: + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + void InsertNonnullChecking(MIRBuilder &mirBuilder, const MIRType &baseType, std::list &ans) const; + void CheckNonnullArgsAndRetForFuncPtr(const MIRBuilder &mirBuilder, const MIRType &baseType) const; + void CheckBoundaryArgsAndRetForFuncPtr(const MIRBuilder &mirBuilder, const MIRType &baseType) const; + void AssignBoundaryVarAndChecking(MIRBuilder &mirBuilder, std::list &ans) const; + + UniqueFEIRType addrType; + UniqueFEIRExpr addrExpr; + UniqueFEIRExpr baseExpr; + FieldID fieldID; +}; + +// ---------- FEIRStmtJavaTypeCheck ---------- +class FEIRStmtJavaTypeCheck : public FEIRStmtAssign { + public: + enum CheckKind { + kCheckCast, + kInstanceOf + }; + + FEIRStmtJavaTypeCheck(std::unique_ptr argVar, std::unique_ptr argExpr, + std::unique_ptr argType, CheckKind argCheckKind); + FEIRStmtJavaTypeCheck(std::unique_ptr argVar, std::unique_ptr argExpr, + std::unique_ptr argType, CheckKind argCheckKind, uint32 argTypeID); + ~FEIRStmtJavaTypeCheck() = default; + + protected: + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + CheckKind checkKind; + std::unique_ptr expr; + std::unique_ptr type; + uint32 typeID = UINT32_MAX; +}; + +// ---------- FEIRStmtJavaConstClass ---------- +class FEIRStmtJavaConstClass : public FEIRStmtAssign { + public: + FEIRStmtJavaConstClass(std::unique_ptr argVar, std::unique_ptr argType); + ~FEIRStmtJavaConstClass() = default; + + protected: + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + std::unique_ptr type; +}; + +// ---------- FEIRStmtJavaConstString ---------- +class FEIRStmtJavaConstString : public FEIRStmtAssign { + public: + FEIRStmtJavaConstString(std::unique_ptr argVar, const std::string &argStrVal, + uint32 argFileIdx, uint32 argStringID); + ~FEIRStmtJavaConstString() = default; + + protected: + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + std::string strVal; + uint32 fileIdx; + uint32 stringID = UINT32_MAX; +}; + +// ---------- FEIRStmtJavaFillArrayData ---------- +class FEIRStmtJavaFillArrayData : public FEIRStmtAssign { + public: + FEIRStmtJavaFillArrayData(std::unique_ptr arrayExprIn, const int8 *arrayDataIn, + uint32 sizeIn, const std::string &arrayNameIn); + ~FEIRStmtJavaFillArrayData() = default; + + protected: + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + LLT_PRIVATE: + PrimType ProcessArrayElemPrimType() const; + MIRSymbol *ProcessArrayElemData(MIRBuilder &mirBuilder, PrimType elemPrimType) const; + MIRAggConst *FillArrayElem(MIRBuilder &mirBuilder, PrimType elemPrimType, MIRType &arrayTypeWithSize, + uint32 elemSize) const; + + std::unique_ptr arrayExpr; + const int8 *arrayData = nullptr; + uint32 size = 0; + const std::string arrayName; +}; + +// ---------- FEIRStmtJavaMultiANewArray ---------- +class FEIRStmtJavaMultiANewArray : public FEIRStmtAssign { + public: + FEIRStmtJavaMultiANewArray(std::unique_ptr argVar, std::unique_ptr argElemType, + std::unique_ptr argArrayType); + ~FEIRStmtJavaMultiANewArray() = default; + void AddVarSize(std::unique_ptr argVarSize); + void AddVarSizeRev(std::unique_ptr argVarSize); + void SetArrayType(std::unique_ptr argArrayType) { + arrayType = std::move(argArrayType); + } + + protected: + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + static const UniqueFEIRVar &GetVarSize(); + static const UniqueFEIRVar &GetVarClass(); + static const UniqueFEIRType &GetTypeAnnotation(); + static FEStructMethodInfo &GetMethodInfoNewInstance(); + + std::unique_ptr elemType; + std::unique_ptr arrayType; + std::list> exprSizes; + static UniqueFEIRVar varSize; + static UniqueFEIRVar varClass; + static UniqueFEIRType typeAnnotation; + static FEStructMethodInfo *methodInfoNewInstance; +}; + +// ---------- FEIRStmtUseOnly ---------- +class FEIRStmtUseOnly : public FEIRStmt { + public: + FEIRStmtUseOnly(FEIRNodeKind argKind, Opcode argOp, std::unique_ptr argExpr); + FEIRStmtUseOnly(Opcode argOp, std::unique_ptr argExpr); + virtual ~FEIRStmtUseOnly() = default; + + const std::unique_ptr &GetExpr() const { + return expr; + } + + protected: + bool IsFallThroughImpl() const override { + if ((op == OP_return) || (op == OP_throw)) { + return false; + } + return true; + } + + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + bool SkipNonnullChecking(MIRBuilder &mirBuilder) const; + + Opcode op; + std::unique_ptr expr; +}; + +// ---------- FEIRStmtSafetyCallAssert ---------- +class FEIRStmtSafetyCallAssert { + public: + FEIRStmtSafetyCallAssert(const std::string &funcName, size_t paramIndex) + : funcNameIdx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcName)), paramIndex(paramIndex) {} + + virtual ~FEIRStmtSafetyCallAssert() = default; + + const std::string &GetFuncName() const { + return GlobalTables::GetStrTable().GetStringFromStrIdx(funcNameIdx); + } + + GStrIdx GetFuncNameIdx() const { + return funcNameIdx; + } + + size_t GetParamIndex() const { + return paramIndex; + } + + private: + GStrIdx funcNameIdx; + size_t paramIndex; +}; + +// ---------- FEIRStmtAssertNonnull ---------- +class FEIRStmtAssertNonnull : public FEIRStmtUseOnly { + public: + FEIRStmtAssertNonnull(Opcode argOp, std::unique_ptr argExpr) + : FEIRStmtUseOnly(argOp, std::move(argExpr)) {} + + ~FEIRStmtAssertNonnull() = default; + + protected: + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; +}; + +// ---------- FEIRStmtCallAssertNonnull ---------- +class FEIRStmtCallAssertNonnull : public FEIRStmtUseOnly, public FEIRStmtSafetyCallAssert { + public: + FEIRStmtCallAssertNonnull(Opcode argOp, std::unique_ptr argExpr, const std::string &funcName, + size_t paramIndex) + : FEIRStmtUseOnly(argOp, std::move(argExpr)), FEIRStmtSafetyCallAssert(funcName, paramIndex) {} + + ~FEIRStmtCallAssertNonnull() = default; + + protected: + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; +}; + +// ---------- FEIRStmtCallAssertBoundary ---------- +class FEIRStmtCallAssertBoundary : public FEIRStmtNary, public FEIRStmtSafetyCallAssert { + public: + FEIRStmtCallAssertBoundary(Opcode opIn, std::list> argExprsIn, const std::string &funcName, + size_t paramIndex) + : FEIRStmtNary(opIn, std::move(argExprsIn)), FEIRStmtSafetyCallAssert(funcName, paramIndex) {} + + ~FEIRStmtCallAssertBoundary() = default; + + protected: + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; +}; + +// ---------- FEIRStmtAssertBoundary ---------- +class FEIRStmtAssertBoundary : public FEIRStmtNary { + public: + FEIRStmtAssertBoundary(Opcode opIn, + std::list> argExprsIn) : FEIRStmtNary(opIn, std::move(argExprsIn)) {} + ~FEIRStmtAssertBoundary() = default; + + void SetIsComputable(bool flag) { + isComputable = flag; + } + + bool IsComputable() const { + return isComputable; + } + + protected: + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + bool isComputable = false; +}; + +// ---------- FEIRStmtReturn ---------- +class FEIRStmtReturn : public FEIRStmtUseOnly { + public: + explicit FEIRStmtReturn(std::unique_ptr argExpr); + ~FEIRStmtReturn() = default; + + protected: + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + void InsertNonnullChecking(MIRBuilder &mirBuilder, std::list &ans) const; +}; + +// ---------- FEIRStmtPesudoLabel ---------- +class FEIRStmtPesudoLabel : public FEIRStmt { + public: + FEIRStmtPesudoLabel(uint32 argLabelIdx); + ~FEIRStmtPesudoLabel() = default; + void GenerateLabelIdx(MIRBuilder &mirBuilder); + + uint32 GetLabelIdx() const { + return labelIdx; + } + + LabelIdx GetMIRLabelIdx() const { + return mirLabelIdx; + } + + protected: + bool IsTargetImpl() const override { + return true; + } + + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + uint32 labelIdx; + LabelIdx mirLabelIdx; +}; + +class FEIRStmtPesudoLabel2 : public FEIRStmt { + public: + FEIRStmtPesudoLabel2(uint32 qIdx0, uint32 qIdx1) + : FEIRStmt(FEIRNodeKind::kStmtPesudoLabel), labelIdxOuter(qIdx0), labelIdxInner(qIdx1) {} + + ~FEIRStmtPesudoLabel2() = default; + static LabelIdx GenMirLabelIdx(MIRBuilder &mirBuilder, uint32 qIdx0, uint32 qIdx1); + std::pair GetLabelIdx() const; + uint32 GetPos() const { + return labelIdxInner; + } + + protected: + bool IsTargetImpl() const override { + return true; + } + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + uint32 labelIdxOuter; + uint32 labelIdxInner; +}; + +// ---------- FEIRStmtGoto ---------- +class FEIRStmtGoto : public FEIRStmt { + public: + explicit FEIRStmtGoto(uint32 argLabelIdx); + virtual ~FEIRStmtGoto(); + void SetLabelIdx(uint32 argLabelIdx) { + labelIdx = argLabelIdx; + } + + uint32 GetLabelIdx() const { + return labelIdx; + } + + void SetStmtTarget(FEIRStmtPesudoLabel &argStmtTarget) { + stmtTarget = &argStmtTarget; + } + + const FEIRStmtPesudoLabel &GetStmtTargetRef() const { + CHECK_NULL_FATAL(stmtTarget); + return *stmtTarget; + } + + protected: + bool IsFallThroughImpl() const override { + return false; + } + + bool IsBranchImpl() const override { + return true; + } + + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + uint32 labelIdx; + FEIRStmtPesudoLabel *stmtTarget; +}; + +// ---------- FEIRStmtGoto2 ---------- +class FEIRStmtGoto2 : public FEIRStmt { + public: + FEIRStmtGoto2(uint32 qIdx0, uint32 qIdx1); + virtual ~FEIRStmtGoto2() = default; + std::pair GetLabelIdx() const; + uint32 GetTarget() const { + return labelIdxInner; + } + + void SetStmtTarget(FEIRStmtPesudoLabel2 &argStmtTarget) { + stmtTarget = &argStmtTarget; + } + + const FEIRStmtPesudoLabel2 &GetStmtTargetRef() const { + CHECK_NULL_FATAL(stmtTarget); + return *stmtTarget; + } + + protected: + bool IsFallThroughImpl() const override { + return false; + } + + bool IsBranchImpl() const override { + return true; + } + + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + uint32 labelIdxOuter; + uint32 labelIdxInner; + FEIRStmtPesudoLabel2 *stmtTarget = nullptr; +}; + +// ---------- FEIRStmtGoto ---------- +class FEIRStmtGotoForC : public FEIRStmt { + public: + explicit FEIRStmtGotoForC(const std::string &labelName); + virtual ~FEIRStmtGotoForC() = default; + void SetLabelName(const std::string &name) { + labelName = name; + } + + std::string GetLabelName() const { + return labelName; + } + + protected: + bool IsFallThroughImpl() const override { + return false; + } + + bool IsBranchImpl() const override { + return true; + } + + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + std::string labelName; +}; + +// ---------- FEIRStmtIGoto ---------- +class FEIRStmtIGoto : public FEIRStmt { + public: + explicit FEIRStmtIGoto(UniqueFEIRExpr expr); + virtual ~FEIRStmtIGoto() = default; + + protected: + bool IsFallThroughImpl() const override { + return false; + } + + bool IsBranchImpl() const override { + return true; + } + + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + UniqueFEIRExpr targetExpr; +}; + +// ---------- FEIRStmtCondGotoForC ---------- +class FEIRStmtCondGotoForC : public FEIRStmt { + public: + explicit FEIRStmtCondGotoForC(UniqueFEIRExpr argExpr, Opcode op, const std::string &name) + : FEIRStmt(FEIRNodeKind::kStmtCondGoto), expr(std::move(argExpr)), opCode(op), labelName(std::move(name)) {} + virtual ~FEIRStmtCondGotoForC() = default; + void SetLabelName(const std::string &name) { + labelName = name; + } + + std::string GetLabelName() const { + return labelName; + } + + protected: + bool IsBranchImpl() const override { + return true; + } + + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + UniqueFEIRExpr expr; + Opcode opCode; + std::string labelName; +}; + +// ---------- FEIRStmtCondGoto ---------- +class FEIRStmtCondGoto : public FEIRStmtGoto { + public: + FEIRStmtCondGoto(Opcode argOp, uint32 argLabelIdx, UniqueFEIRExpr argExpr); + ~FEIRStmtCondGoto() = default; + void SetOpcode(Opcode argOp) { + op = argOp; + } + + Opcode GetOpcode() const { + return op; + } + + void SetExpr(UniqueFEIRExpr argExpr) { + CHECK_NULL_FATAL(argExpr); + expr = std::move(argExpr); + } + + protected: + bool IsFallThroughImpl() const override { + return true; + } + + bool IsBranchImpl() const override { + return true; + } + + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + Opcode op; + UniqueFEIRExpr expr; +}; + +// ---------- FEIRStmtCondGoto2 ---------- +class FEIRStmtCondGoto2 : public FEIRStmtGoto2 { + public: + FEIRStmtCondGoto2(Opcode argOp, uint32 qIdx0, uint32 qIdx1, UniqueFEIRExpr argExpr); + ~FEIRStmtCondGoto2() = default; + + protected: + bool IsFallThroughImpl() const override { + return true; + } + + bool IsBranchImpl() const override { + return true; + } + + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + Opcode op; + UniqueFEIRExpr expr; +}; + +// ---------- FEIRStmtSwitch ---------- +class FEIRStmtSwitch : public FEIRStmt { + public: + explicit FEIRStmtSwitch(UniqueFEIRExpr argExpr); + ~FEIRStmtSwitch(); + void SetDefaultLabelIdx(uint32 labelIdx) { + defaultLabelIdx = labelIdx; + } + + uint32 GetDefaultLabelIdx() const { + return defaultLabelIdx; + } + + void SetDefaultTarget(FEIRStmtPesudoLabel &stmtTarget) { + defaultTarget = &stmtTarget; + } + + const FEIRStmtPesudoLabel &GetDefaultTarget() const { + return *defaultTarget; + } + + const std::map &GetMapValueLabelIdx() const { + return mapValueLabelIdx; + } + + const std::map &GetMapValueTargets() const { + return mapValueTargets; + } + + void AddTarget(int32 value, uint32 labelIdx) { + mapValueLabelIdx[value] = labelIdx; + } + + void AddTarget(int32 value, FEIRStmtPesudoLabel &target) { + mapValueTargets[value] = ⌖ + } + + void SetExpr(UniqueFEIRExpr argExpr) { + CHECK_NULL_FATAL(argExpr); + expr = std::move(argExpr); + } + + protected: + bool IsBranchImpl() const override { + return true; + } + + bool IsFallThroughImpl() const override; + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + uint32 defaultLabelIdx; + FEIRStmtPesudoLabel *defaultTarget; + std::map mapValueLabelIdx; + std::map mapValueTargets; + UniqueFEIRExpr expr; +}; + +// ---------- FEIRStmtSwitch2 ---------- +class FEIRStmtSwitch2 : public FEIRStmt { + public: + explicit FEIRStmtSwitch2(uint32 outerIdxIn, UniqueFEIRExpr argExpr); + ~FEIRStmtSwitch2(); + void SetDefaultLabelIdx(uint32 labelIdx) { + defaultLabelIdx = labelIdx; + } + + uint32 GetDefaultLabelIdx() const { + return defaultLabelIdx; + } + + void SetDefaultTarget(FEIRStmtPesudoLabel2 *stmtTarget) { + defaultTarget = stmtTarget; + } + + const FEIRStmtPesudoLabel2 &GetDefaultTarget() const { + return *defaultTarget; + } + + const std::map &GetMapValueLabelIdx() const { + return mapValueLabelIdx; + } + + const std::map &GetMapValueTargets() const { + return mapValueTargets; + } + + void AddTarget(int32 value, uint32 labelIdx) { + mapValueLabelIdx[value] = labelIdx; + } + + void AddTarget(int32 value, FEIRStmtPesudoLabel2 *target) { + mapValueTargets[value] = target; + } + + void SetExpr(UniqueFEIRExpr argExpr) { + CHECK_NULL_FATAL(argExpr); + expr = std::move(argExpr); + } + + protected: + bool IsBranchImpl() const override { + return true; + } + + bool IsFallThroughImpl() const override; + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + uint32 outerIdx; + uint32 defaultLabelIdx = UINT32_MAX; + FEIRStmtPesudoLabel2 *defaultTarget; + std::map mapValueLabelIdx; + std::map mapValueTargets; + UniqueFEIRExpr expr; +}; + +// ---------- FEIRStmtSwitchForC ---------- +class FEIRStmtSwitchForC : public FEIRStmt { + public: + FEIRStmtSwitchForC(UniqueFEIRExpr argCondExpr, bool argHasDefault); + ~FEIRStmtSwitchForC() = default; + void AddFeirStmt(UniqueFEIRStmt stmt) { + subStmts.emplace_back(std::move(stmt)); + } + + void SetExpr(UniqueFEIRExpr argExpr) { + CHECK_NULL_FATAL(argExpr); + expr = std::move(argExpr); + } + + void SetHasDefault(bool argHasDefault) { + hasDefault = argHasDefault; + } + + void SetBreakLabelName(std::string name) { + breakLabelName = std::move(name); + } + + protected: + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + UniqueFEIRExpr expr; + bool hasDefault = true; + std::list subStmts; + std::string breakLabelName; +}; + +// ---------- FEIRStmtCaseForC ---------- +class FEIRStmtCaseForC : public FEIRStmt { + public: + FEIRStmtCaseForC(int64 lCaseLabel); + void AddCaseTag2CaseVec(int64 lCaseTag, int64 rCaseTag); + ~FEIRStmtCaseForC() = default; + void AddFeirStmt(UniqueFEIRStmt stmt) { + subStmts.emplace_back(std::move(stmt)); + } + const std::map> &GetPesudoLabelMap() const { + return pesudoLabelMap; + } + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + int64 lCaseLabel; + std::map> pesudoLabelMap = + std::map>(); + std::list subStmts; +}; + +// ---------- FEIRStmtDefaultForC ---------- +class FEIRStmtDefaultForC : public FEIRStmt { + public: + explicit FEIRStmtDefaultForC(); + ~FEIRStmtDefaultForC() = default; + void AddFeirStmt(UniqueFEIRStmt stmt) { + subStmts.emplace_back(std::move(stmt)); + } + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + std::list subStmts; +}; + +// ---------- FEIRStmtArrayStore ---------- +class FEIRStmtArrayStore : public FEIRStmt { + public: + FEIRStmtArrayStore(UniqueFEIRExpr argExprElem, UniqueFEIRExpr argExprArray, UniqueFEIRExpr argExprIndex, + UniqueFEIRType argTypeArray); + + // for C + FEIRStmtArrayStore(UniqueFEIRExpr argExprElem, UniqueFEIRExpr argExprArray, UniqueFEIRExpr argExprIndex, + UniqueFEIRType argTypeArray, const std::string &argArrayName); + + // for C mul array + FEIRStmtArrayStore(UniqueFEIRExpr argExprElem, UniqueFEIRExpr argExprArray, UniqueFEIRExpr argExprIndex, + UniqueFEIRType argTypeArray, UniqueFEIRType argTypeElem, const std::string &argArrayName); + // for C mul array + FEIRStmtArrayStore(UniqueFEIRExpr argExprElem, UniqueFEIRExpr argExprArray, std::list &argExprIndexs, + UniqueFEIRType argTypeArray, const std::string &argArrayName); + + // for C array in struct + FEIRStmtArrayStore(UniqueFEIRExpr argExprElem, UniqueFEIRExpr argExprArray, std::list &argExprIndexs, + UniqueFEIRType argTypeArray, UniqueFEIRExpr argExprStruct, UniqueFEIRType argTypeStruct, + const std::string &argArrayName); + + ~FEIRStmtArrayStore() = default; + + void SetIndexsExprs(std::list &exprs) { + exprIndexs.clear(); + for (auto &e : exprs) { + auto ue = e->Clone(); + exprIndexs.push_back(std::move(ue)); + } + } + + protected: + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + void InitTrans4AllVarsImpl() override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + void GenMIRStmtsImplForCPart(MIRBuilder &mirBuilder, MIRType *ptrMIRArrayType, MIRType **mIRElemType, + BaseNode **arrayExpr) const; + + private: + UniqueFEIRExpr exprElem; + UniqueFEIRExpr exprArray; + UniqueFEIRExpr exprIndex; + // for C mul array + mutable std::list exprIndexs; + UniqueFEIRType typeArray; + mutable UniqueFEIRType typeElem = nullptr; + + // for C array in struct + UniqueFEIRExpr exprStruct; + UniqueFEIRType typeStruct; + std::string arrayName; +}; + +// ---------- FEIRStmtFieldStore ---------- +class FEIRStmtFieldStore : public FEIRStmt { + public: + FEIRStmtFieldStore(UniqueFEIRVar argVarObj, UniqueFEIRVar argVarField, FEStructFieldInfo &argFieldInfo, + bool argIsStatic); + FEIRStmtFieldStore(UniqueFEIRVar argVarObj, UniqueFEIRVar argVarField, FEStructFieldInfo &argFieldInfo, + bool argIsStatic, int32 argDexFileHashCode); + ~FEIRStmtFieldStore() = default; + + protected: + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + void RegisterDFGNodes2CheckPointForStatic(FEIRStmtCheckPoint &checkPoint); + void RegisterDFGNodes2CheckPointForNonStatic(FEIRStmtCheckPoint &checkPoint); + bool CalculateDefs4AllUsesForStatic(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain); + bool CalculateDefs4AllUsesForNonStatic(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain); + bool NeedMCCForStatic(uint32 &typeID) const; + void InitPrimTypeFuncNameIdxMap (std::map &primTypeFuncNameIdxMap) const; + std::list GenMIRStmtsImplForStatic(MIRBuilder &mirBuilder) const; + std::list GenMIRStmtsImplForNonStatic(MIRBuilder &mirBuilder) const; + + UniqueFEIRVar varObj; + UniqueFEIRVar varField; + FEStructFieldInfo &fieldInfo; + bool isStatic; + int32 dexFileHashCode = -1; +}; + +// ---------- FEIRStmtFieldLoad ---------- +class FEIRStmtFieldLoad : public FEIRStmtAssign { + public: + FEIRStmtFieldLoad(UniqueFEIRVar argVarObj, UniqueFEIRVar argVarField, FEStructFieldInfo &argFieldInfo, + bool argIsStatic); + FEIRStmtFieldLoad(UniqueFEIRVar argVarObj, UniqueFEIRVar argVarField, FEStructFieldInfo &argFieldInfo, + bool argIsStatic, int32 argDexFileHashCode); + ~FEIRStmtFieldLoad() = default; + + protected: + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + void RegisterDFGNodes2CheckPointForStatic(FEIRStmtCheckPoint &checkPoint); + void RegisterDFGNodes2CheckPointForNonStatic(FEIRStmtCheckPoint &checkPoint); + bool CalculateDefs4AllUsesForStatic(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain); + bool CalculateDefs4AllUsesForNonStatic(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain); + bool NeedMCCForStatic(uint32 &typeID) const; + std::list GenMIRStmtsImplForStatic(MIRBuilder &mirBuilder) const; + std::list GenMIRStmtsImplForNonStatic(MIRBuilder &mirBuilder) const; + + UniqueFEIRVar varObj; + FEStructFieldInfo &fieldInfo; + bool isStatic; + int32 dexFileHashCode = -1; +}; + +// ---------- FEIRStmtCallAssign ---------- +class FEIRStmtCallAssign : public FEIRStmtAssign { + public: + FEIRStmtCallAssign(FEStructMethodInfo &argMethodInfo, Opcode argMIROp, UniqueFEIRVar argVarRet, bool argIsStatic); + ~FEIRStmtCallAssign() = default; + + static std::map InitMapOpAssignToOp(); + static std::map InitMapOpToOpAssign(); + + protected: + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + std::list GenMIRStmtsUseZeroReturn(MIRBuilder &mirBuilder) const; + + private: + Opcode AdjustMIROp() const; + void InsertNonnullInRetVar(MIRSymbol &retVarSym) const; + void InsertNonnullCheckingInArgs(const UniqueFEIRExpr &expr, size_t index, MIRBuilder &mirBuilder, + std::list &ans, const std::string &funcName) const; + FEStructMethodInfo &methodInfo; + Opcode mirOp; + bool isStatic; + static std::map mapOpAssignToOp; + static std::map mapOpToOpAssign; +}; + +// ---------- FEIRStmtICallAssign ---------- +class FEIRStmtICallAssign : public FEIRStmtAssign { + public: + FEIRStmtICallAssign(); + ~FEIRStmtICallAssign() = default; + + protected: + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + bool CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) override; + + private: + void InsertNonnullCheckingInArgs(MIRBuilder &mirBuilder, std::list &ans) const; + void InsertNonnullInRetVar(MIRSymbol &retVarSym) const; +}; + +// ---------- FEIRStmtIntrinsicCallAssign ---------- +class FEIRStmtIntrinsicCallAssign : public FEIRStmtAssign { + public: + FEIRStmtIntrinsicCallAssign(MIRIntrinsicID id, UniqueFEIRType typeIn, UniqueFEIRVar argVarRet); + FEIRStmtIntrinsicCallAssign(MIRIntrinsicID id, UniqueFEIRType typeIn, UniqueFEIRVar argVarRet, + std::unique_ptr> exprListIn); + FEIRStmtIntrinsicCallAssign(MIRIntrinsicID id, const std::string &funcNameIn, const std::string &protoIN, + std::unique_ptr> argsIn); + FEIRStmtIntrinsicCallAssign(MIRIntrinsicID id, const std::string &funcNameIn, const std::string &protoIN, + std::unique_ptr> argsIn, uint32 callerClassTypeIDIn, + bool isInStaticFuncIn); + FEIRStmtIntrinsicCallAssign(MIRIntrinsicID id, UniqueFEIRType typeIn, UniqueFEIRVar argVarRet, + uint32 typeIDIn); + ~FEIRStmtIntrinsicCallAssign() = default; + + protected: + std::string DumpDotStringImpl() const override; + void RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + void ConstructArgsForInvokePolyMorphic(MIRBuilder &mirBuilder, MapleVector &intrnCallargs) const; + std::list GenMIRStmtsForInvokePolyMorphic(MIRBuilder &mirBuilder) const; + + MIRIntrinsicID intrinsicId; + UniqueFEIRType type; + std::unique_ptr> exprList; + // for polymorphic + const std::string funcName; + const std::string proto; + std::unique_ptr> polyArgs; + uint32 typeID = UINT32_MAX; + uint32 callerClassTypeID = UINT32_MAX; + bool isInStaticFunc = false; +}; + +// ---------- FEIRStmtPesudoLOC ---------- +class FEIRStmtPesudoLOC : public FEIRStmt { + public: + FEIRStmtPesudoLOC(uint32 argSrcFileIdx, uint32 argLineNumber); + ~FEIRStmtPesudoLOC() = default; + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; +}; + +// ---------- FEIRStmtPesudoJavaTry ---------- +class FEIRStmtPesudoJavaTry : public FEIRStmt { + public: + FEIRStmtPesudoJavaTry(); + ~FEIRStmtPesudoJavaTry() = default; + void AddCatchLabelIdx(uint32 labelIdx) { + catchLabelIdxVec.push_back(labelIdx); + } + + const std::vector GetCatchLabelIdxVec() const { + return catchLabelIdxVec; + } + + void AddCatchTarget(FEIRStmtPesudoLabel &stmtLabel) { + catchTargets.push_back(&stmtLabel); + } + + const std::vector &GetCatchTargets() const { + return catchTargets; + } + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + std::vector catchLabelIdxVec; + std::vector catchTargets; +}; + +// ---------- FEIRStmtPesudoJavaTry2 ---------- +class FEIRStmtPesudoJavaTry2 : public FEIRStmt { + public: + FEIRStmtPesudoJavaTry2(uint32 outerIdxIn); + ~FEIRStmtPesudoJavaTry2() = default; + void AddCatchLabelIdx(uint32 labelIdx) { + catchLabelIdxVec.push_back(labelIdx); + } + + const std::vector GetCatchLabelIdxVec() const { + return catchLabelIdxVec; + } + + void AddCatchTarget(FEIRStmtPesudoLabel2 *stmtLabel) { + catchTargets.push_back(stmtLabel); + } + + const std::vector &GetCatchTargets() const { + return catchTargets; + } + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + uint32 outerIdx; + std::vector catchLabelIdxVec; + std::vector catchTargets; +}; + +// ---------- FEIRStmtPesudoEndTry ---------- +class FEIRStmtPesudoEndTry : public FEIRStmt { + public: + FEIRStmtPesudoEndTry(); + ~FEIRStmtPesudoEndTry() = default; + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; +}; + +// ---------- FEIRStmtPesudoCatch ---------- +class FEIRStmtPesudoCatch : public FEIRStmtPesudoLabel { + public: + explicit FEIRStmtPesudoCatch(uint32 argLabelIdx); + ~FEIRStmtPesudoCatch() = default; + void AddCatchTypeNameIdx(GStrIdx typeNameIdx); + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + std::list catchTypes; +}; + +// ---------- FEIRStmtPesudoCatch2 ---------- +class FEIRStmtPesudoCatch2 : public FEIRStmtPesudoLabel2 { + public: + explicit FEIRStmtPesudoCatch2(uint32 qIdx0, uint32 qIdx1); + ~FEIRStmtPesudoCatch2() = default; + void AddCatchTypeNameIdx(GStrIdx typeNameIdx); + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + std::list catchTypes; +}; + +class FEIRStmtPesudoSafe : public FEIRStmt { + public: + FEIRStmtPesudoSafe(bool isEnd); + ~FEIRStmtPesudoSafe() = default; + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + bool end = false; +}; + +class FEIRStmtPesudoUnsafe : public FEIRStmt { + public: + FEIRStmtPesudoUnsafe(bool isEnd); + ~FEIRStmtPesudoUnsafe() = default; + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + bool end = false; +}; + +// ---------- FEIRStmtPesudoComment ---------- +class FEIRStmtPesudoComment : public FEIRStmt { + public: + explicit FEIRStmtPesudoComment(FEIRNodeKind argKind = kStmtPesudoComment); + explicit FEIRStmtPesudoComment(const std::string &argContent); + ~FEIRStmtPesudoComment() = default; + void SetContent(const std::string &argContent) { + content = argContent; + } + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + std::string content = ""; +}; + +// ---------- FEIRStmtPesudoCommentForInst ---------- +class FEIRStmtPesudoCommentForInst : public FEIRStmtPesudoComment { + public: + FEIRStmtPesudoCommentForInst(); + ~FEIRStmtPesudoCommentForInst() = default; + void SetFileIdx(uint32 argFileIdx) { + fileIdx = argFileIdx; + } + + void SetLineNum(uint32 argLineNum) { + lineNum = argLineNum; + } + + void SetPC(uint32 argPC) { + pc = argPC; + } + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + constexpr static uint32 invalid = 0xFFFFFFFF; + uint32 fileIdx = invalid; + uint32 lineNum = invalid; + uint32 pc = invalid; +}; + +// ---------- FEIRStmtIf ---------- +class FEIRStmtIf : public FEIRStmt { + public: + FEIRStmtIf(UniqueFEIRExpr argCondExpr, std::list &argThenStmts); + FEIRStmtIf(UniqueFEIRExpr argCondExpr, + std::list &argThenStmts, + std::list &argElseStmts); + ~FEIRStmtIf() = default; + + void SetCondExpr(UniqueFEIRExpr argCondExpr) { + CHECK_NULL_FATAL(argCondExpr); + condExpr = std::move(argCondExpr); + } + + const UniqueFEIRExpr &GetCondExpr() const { + return condExpr; + } + + void SetHasElse(bool argHasElse) { + hasElse = argHasElse; + } + + void SetThenStmts(std::list &stmts) { + std::move(begin(stmts), end(stmts), std::inserter(thenStmts, end(thenStmts))); + } + + void SetElseStmts(std::list &stmts) { + std::move(begin(stmts), end(stmts), std::inserter(elseStmts, end(elseStmts))); + } + + std::list &GetThenStmt() { + return thenStmts; + } + + std::list &GetElseStmt() { + return elseStmts; + } + + protected: + std::string DumpDotStringImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + bool IsFallThroughImpl() const override; + + bool IsBranchImpl() const override { + return true; + } + + private: + UniqueFEIRExpr condExpr; + bool hasElse = false; + std::list thenStmts; + std::list elseStmts; +}; + +class FEIRStmtDoWhile : public FEIRStmt { + public: + FEIRStmtDoWhile(Opcode argOpcode, UniqueFEIRExpr argCondExpr, std::list argBodyStmts) + : FEIRStmt(FEIRNodeKind::kStmtDoWhile), + opcode(argOpcode), + condExpr(std::move(argCondExpr)), + bodyStmts(std::move(argBodyStmts)) {} + ~FEIRStmtDoWhile() = default; + + protected: + bool IsBranchImpl() const override { + return true; + } + + bool IsFallThroughImpl() const override; + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + Opcode opcode; + UniqueFEIRExpr condExpr; + std::list bodyStmts; +}; + +class FEIRStmtBreak : public FEIRStmt { + public: + FEIRStmtBreak(): FEIRStmt(FEIRNodeKind::kStmtBreak) {} + ~FEIRStmtBreak() = default; + + void SetBreakLabelName(std::string name) { + breakLabelName = std::move(name); + } + + protected: + bool IsBranchImpl() const override { + return true; + } + + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + std::string breakLabelName; +}; + +class FEIRStmtContinue : public FEIRStmt { + public: + FEIRStmtContinue(): FEIRStmt(FEIRNodeKind::kStmtContinue) {} + ~FEIRStmtContinue() = default; + + void SetLabelName(std::string name){ + labelName = std::move(name); + } + + protected: + bool IsBranchImpl() const override { + return true; + } + + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + private: + std::string labelName; +}; + +class FEIRStmtLabel : public FEIRStmt { + public: + explicit FEIRStmtLabel(const std::string &name) : FEIRStmt(FEIRNodeKind::kStmtLabel), labelName(name) {} + ~FEIRStmtLabel() = default; + + const std::string &GetLabelName() const { + return labelName; + } + + protected: + bool IsBranchImpl() const override { + return true; + } + + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + + private: + std::string labelName; +}; + +class FEIRStmtAtomic : public FEIRStmt { + public: + FEIRStmtAtomic(UniqueFEIRExpr expr); + ~FEIRStmtAtomic() = default; + + protected: + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + UniqueFEIRExpr atomicExpr; +}; + +class FEIRStmtGCCAsm : public FEIRStmt { + public: + FEIRStmtGCCAsm(const std::string &str, bool isGotoArg, bool isVolatileArg) + : FEIRStmt(FEIRNodeKind::kStmtGCCAsm), asmStr(str), isGoto(isGotoArg), isVolatile(isVolatileArg) {} + ~FEIRStmtGCCAsm() = default; + + void SetLabels(const std::vector &labelsArg) { + labels = labelsArg; + } + + void SetClobbers(const std::vector &clobbersArg) { + clobbers = clobbersArg; + } + + void SetInputs(const std::vector> &inputsArg) { + inputs = inputsArg; + } + + void SetInputsExpr(std::vector &expr) { + std::move(begin(expr), end(expr), std::inserter(inputsExprs, end(inputsExprs))); + } + + void SetOutputs(const std::vector> &outputsArg) { + outputs = outputsArg; + } + + void SetOutputsExpr(std::vector &expr) { + std::move(begin(expr), end(expr), std::inserter(outputsExprs, end(outputsExprs))); + } + + protected: + std::list GenMIRStmtsImpl(MIRBuilder &mirBuilder) const override; + bool HandleConstraintPlusQm(MIRBuilder &mirBuilder, AsmNode *asmNode, uint32 index) const; + + private: + std::vector> outputs; + std::vector outputsExprs; + std::vector> inputs; + std::vector inputsExprs; + std::vector clobbers; + std::vector labels; + std::string asmStr; + bool isGoto = false; + bool isVolatile = false; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_FEIR_STMT_H diff --git a/src/hir2mpl/common/include/feir_type.h b/src/hir2mpl/common/include/feir_type.h new file mode 100644 index 0000000000000000000000000000000000000000..9f64fe67496879b44f8ccf8c0f294907841b48fa --- /dev/null +++ b/src/hir2mpl/common/include/feir_type.h @@ -0,0 +1,423 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FEIR_TYPE_H +#define HIR2MPL_INCLUDE_FEIR_TYPE_H +#include +#include +#include +#include "prim_types.h" +#include "types_def.h" +#include "mir_type.h" +#include "global_tables.h" +#include "fe_configs.h" +#include "fe_utils_ast.h" + +namespace maple { +enum FEIRTypeKind { + kFEIRTypeDefault, + kFEIRTypeByName, + kFEIRTypePointer, + kFEIRTypeNative +}; + +class FEIRType { + public: + explicit FEIRType(FEIRTypeKind argKind); + virtual ~FEIRType() = default; + static std::unique_ptr NewType(FEIRTypeKind argKind = kFEIRTypeDefault); + static std::map> InitLangConfig(); + MIRType *GenerateMIRTypeAuto(MIRSrcLang argSrcLang) const; + MIRType *GenerateMIRTypeAuto() const { + return GenerateMIRTypeAutoImpl(); + } + + bool IsSameKind(const FEIRType &type) const { + return kind == type.kind; + } + + FEIRTypeKind GetKind() const { + return kind; + } + + PrimType GetPrimType() const { + return GetPrimTypeImpl(); + } + + void SetPrimType(PrimType pt) { + SetPrimTypeImpl(pt); + } + + MIRSrcLang GetSrcLang() const { + return srcLang; + } + + bool IsZero() const { + return isZero; + } + + void SetZero(bool arg) { + isZero = arg; + } + + void CopyFrom(const FEIRType &type) { + return CopyFromImpl(type); + } + + std::unique_ptr Clone() const { + return CloneImpl(); + } + + MIRType *GenerateMIRType(MIRSrcLang argSrcLang, bool usePtr) const { + return GenerateMIRType(usePtr); + } + + MIRType *GenerateMIRType() const { + return GenerateMIRType(false); + } + + bool IsPreciseRefType() const { + return IsPrecise() && IsRef(); + } + + bool IsScalar() const { + return IsScalarImpl(); + } + + bool IsRef() const { + return IsRefImpl(); + } + + bool IsArray() const { + return IsArrayImpl(); + } + + bool IsPrecise() const { + return IsPreciseImpl(); + } + + bool IsValid() const { + return IsValidImpl(); + } + + MIRType *GenerateMIRType(bool usePtr, PrimType ptyPtr = PTY_ref) const { + return GenerateMIRTypeImpl(usePtr, ptyPtr); + } + + TypeDim ArrayIncrDim(TypeDim delta = 1) { + return ArrayIncrDimImpl(delta); + } + + TypeDim ArrayDecrDim(TypeDim delta = 1) { + return ArrayDecrDimImpl(delta); + } + + bool IsEqualTo(const std::unique_ptr &argType) const { + return IsEqualToImpl(argType); + } + + bool IsEqualTo(const FEIRType &argType) const { + return IsEqualToImpl(argType); + } + + uint32 Hash() const { + return HashImpl(); + } + + std::string GetTypeName() const { + return GetTypeNameImpl(); + } + + static std::map> langConfig; + + protected: + virtual MIRType *GenerateMIRTypeAutoImpl() const { + return GenerateMIRTypeAuto(srcLang); + } + virtual MIRType *GenerateMIRTypeAutoImpl(MIRSrcLang argSrcLang) const; + virtual void CopyFromImpl(const FEIRType &type); + virtual std::unique_ptr CloneImpl() const = 0; + virtual MIRType *GenerateMIRTypeImpl(bool usePtr, PrimType ptyPtr) const = 0; + virtual bool IsScalarImpl() const = 0; + virtual TypeDim ArrayIncrDimImpl(TypeDim delta) = 0; + virtual TypeDim ArrayDecrDimImpl(TypeDim delta) = 0; + virtual bool IsEqualToImpl(const std::unique_ptr &argType) const; + virtual bool IsEqualToImpl(const FEIRType &argType) const; + virtual uint32 HashImpl() const = 0; + virtual PrimType GetPrimTypeImpl() const { + return PTY_begin; // Means no valid primtype + } + + virtual void SetPrimTypeImpl(PrimType pt) = 0; + virtual bool IsRefImpl() const = 0; + virtual bool IsArrayImpl() const = 0; + virtual bool IsPreciseImpl() const = 0; + virtual bool IsValidImpl() const = 0; + virtual std::string GetTypeNameImpl() const { + return ""; + } + + FEIRTypeKind kind : 7; + bool isZero : 1; + MIRSrcLang srcLang : 8; +}; // class FEIRType + +using UniqueFEIRType = std::unique_ptr; + +class FEIRTypeDefault : public FEIRType { + public: + FEIRTypeDefault(); + explicit FEIRTypeDefault(PrimType argPrimType); + FEIRTypeDefault(PrimType argPrimType, const GStrIdx &argTypeNameIdx); + FEIRTypeDefault(PrimType argPrimType, const GStrIdx &argTypeNameIdx, TypeDim argDim); + ~FEIRTypeDefault() = default; + FEIRTypeDefault(const FEIRTypeDefault&) = delete; + FEIRTypeDefault &operator=(const FEIRTypeDefault&) = delete; + void LoadFromJavaTypeName(const std::string &typeName, bool inMpl = true); + void LoadFromASTTypeName(const std::string &typeName); + MIRType *GenerateMIRTypeForPrim() const; + FEIRTypeDefault &SetTypeNameIdx(const GStrIdx &argTypeNameIdx) { + typeNameIdx = argTypeNameIdx; + return *this; + } + + FEIRTypeDefault &SetTypeName(const std::string &typeName) { + GStrIdx idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(typeName); + return SetTypeNameIdx(idx); + } + + FEIRTypeDefault &SetTypeNameWithoutCreate(const std::string &typeName) { + GStrIdx idx = GlobalTables::GetStrTable().GetStrIdxFromName(typeName); + CHECK_FATAL(idx.GetIdx() != 0, "typeNameIdx should be pre-created"); + return SetTypeNameIdx(idx); + } + + GStrIdx GetTypeNameIdx() const { + return typeNameIdx; + } + + TypeDim GetDim() const { + return dim; + } + + FEIRTypeDefault &SetDim(TypeDim argDim) { + dim = argDim; + return *this; + } + + LLT_PROTECTED: + void CopyFromImpl(const FEIRType &type) override; + std::unique_ptr CloneImpl() const override; + MIRType *GenerateMIRTypeImpl(bool usePtr, PrimType ptyPtr) const override; + TypeDim ArrayIncrDimImpl(TypeDim delta) override; + TypeDim ArrayDecrDimImpl(TypeDim delta) override; + bool IsEqualToImpl(const FEIRType &argType) const override; + bool IsEqualToImpl(const std::unique_ptr &argType) const override; + uint32 HashImpl() const override; + bool IsScalarImpl() const override; + PrimType GetPrimTypeImpl() const override; + void SetPrimTypeImpl(PrimType pt) override; + MIRType *GenerateMIRTypeInternal(const GStrIdx &argTypeNameIdx, bool usePtr) const; + MIRType *GenerateMIRTypeInternal(const GStrIdx &argTypeNameIdx, bool usePtr, PrimType ptyPtr) const; + std::string GetTypeNameImpl() const override; + + bool IsRefImpl() const override { + return dim > 0 || !IsScalarPrimType(primType); + } + + bool IsArrayImpl() const override { + return dim > 0; + } + + bool IsPreciseImpl() const override { + return IsScalarPrimType(primType) || typeNameIdx != 0; + } + + bool IsValidImpl() const override { + return !IsScalarPrimType(primType) || typeNameIdx == 0; + } + + static bool IsScalarPrimType(PrimType pty) { + return pty != PTY_ref && (IsPrimitiveInteger(pty) || IsPrimitiveFloat(pty) || IsAddress(pty) || pty == PTY_void); + } + + PrimType primType; + GStrIdx typeNameIdx; + TypeDim dim = 0; +}; + +// ---------- FEIRTypeByName ---------- +class FEIRTypeByName : public FEIRTypeDefault { + public: + FEIRTypeByName(PrimType argPrimType, const std::string &argTypeName, TypeDim argDim = 0); + ~FEIRTypeByName() = default; + FEIRTypeByName(const FEIRTypeByName&) = delete; + FEIRTypeByName &operator=(const FEIRTypeByName&) = delete; + + protected: + std::unique_ptr CloneImpl() const override; + MIRType *GenerateMIRTypeImpl(bool usePtr, PrimType ptyPtr) const override; + bool IsEqualToImpl(const FEIRType &argType) const override; + uint32 HashImpl() const override; + bool IsScalarImpl() const override; + bool IsPreciseImpl() const override { + return IsScalarPrimType(primType) || !typeName.empty(); + } + + bool IsValidImpl() const override { + return !IsScalarPrimType(primType) || typeName.empty(); + } + + private: + std::string typeName; +}; + + +// ---------- FEIRTypeNative ---------- +// MIRType is enclosed directly in FEIRTypeNative. +// Right now, FEIRTypeNative is only used for c-language. +// Because var type is translated as MIRType directly in stage of ast parse. +class FEIRTypeNative : public FEIRType { + public: + explicit FEIRTypeNative(MIRType &argMIRType); + ~FEIRTypeNative() = default; + FEIRTypeNative(const FEIRTypeNative&) = delete; + FEIRTypeNative &operator=(const FEIRTypeNative&) = delete; + + protected: + MIRType *GenerateMIRTypeAutoImpl() const override; + PrimType GetPrimTypeImpl() const override; + void SetPrimTypeImpl(PrimType pt) override; + void CopyFromImpl(const FEIRType &type) override; + std::unique_ptr CloneImpl() const override; + MIRType *GenerateMIRTypeImpl(bool usePtr, PrimType ptyPtr) const override; + bool IsEqualToImpl(const FEIRType &argType) const override; + uint32 HashImpl() const override; + std::string GetTypeNameImpl() const override; + bool IsScalarImpl() const override; + bool IsRefImpl() const override; + bool IsArrayImpl() const override; + + bool IsPreciseImpl() const override { + return true; + } + + bool IsValidImpl() const override { + return true; + } + + TypeDim ArrayIncrDimImpl(TypeDim delta) override; + TypeDim ArrayDecrDimImpl(TypeDim delta) override; + + private: + MIRType &mirType; +}; + +// ---------- FEIRTypePointer ---------- +class FEIRTypePointer : public FEIRType { + public: + explicit FEIRTypePointer(std::unique_ptr argBaseType, PrimType argPrimType = PTY_ref); + ~FEIRTypePointer() = default; + FEIRTypePointer(const FEIRTypePointer&) = delete; + FEIRTypePointer &operator=(const FEIRTypePointer&) = delete; + const UniqueFEIRType &GetBaseType() const { + return baseType; + } + + void SetBaseType(UniqueFEIRType argBaseType) { + CHECK_NULL_FATAL(argBaseType); + baseType = std::move(argBaseType); + } + + protected: + std::unique_ptr CloneImpl() const override; + MIRType *GenerateMIRTypeImpl(bool usePtr, PrimType ptyPtr) const override; + bool IsEqualToImpl(const FEIRType &argType) const override; + uint32 HashImpl() const override; + bool IsScalarImpl() const override; + TypeDim ArrayIncrDimImpl(TypeDim delta) override; + TypeDim ArrayDecrDimImpl(TypeDim delta) override; + virtual PrimType GetPrimTypeImpl() const override; + virtual void SetPrimTypeImpl(PrimType pt) override; + virtual bool IsRefImpl() const override { + return true; // pointer type is ref + } + + virtual bool IsArrayImpl() const override { + return baseType->IsArray(); + } + + virtual bool IsPreciseImpl() const override { + return baseType->IsPrecise(); + } + + virtual bool IsValidImpl() const override { + return baseType->IsValid(); + } + + private: + PrimType primType; + std::unique_ptr baseType; +}; + +// ---------- FEIRTypeKey ---------- +class FEIRTypeKey { + public: + explicit FEIRTypeKey(const UniqueFEIRType &argType) { + ASSERT(argType != nullptr, "nullptr check"); + type = argType->Clone(); + } + + explicit FEIRTypeKey(const FEIRTypeKey &key) { + ASSERT(key.type != nullptr, "nullptr check"); + type = key.type->Clone(); + } + + ~FEIRTypeKey() = default; + FEIRTypeKey &operator=(const FEIRTypeKey &key) { + if (&key != this) { + CHECK_NULL_FATAL(key.type); + SetType(key.type->Clone()); + } + return *this; + } + + bool operator==(const FEIRTypeKey &key) const { + return type->IsEqualTo(key.type); + } + + size_t Hash() const { + return type->Hash(); + } + + const UniqueFEIRType &GetType() const { + return type; + } + + void SetType(UniqueFEIRType argType) { + CHECK_NULL_FATAL(argType); + type = std::move(argType); + } + + private: + UniqueFEIRType type; +}; + +struct FEIRTypeKeyHash { + size_t operator()(const FEIRTypeKey &key) const { + return key.Hash(); + } +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_FEIR_TYPE_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/feir_type_helper.h b/src/hir2mpl/common/include/feir_type_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..ded22389501e8199c883cf7a4a6336fe9250d668 --- /dev/null +++ b/src/hir2mpl/common/include/feir_type_helper.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FEIR_TYPE_HELPER_H +#define HIR2MPL_INCLUDE_FEIR_TYPE_HELPER_H +#include +#include +#include "fe_configs.h" +#include "feir_type.h" + +namespace maple { +class FEIRTypeHelper { + public: + static UniqueFEIRType CreateTypeByPrimType(PrimType primType, TypeDim dim = 0, bool usePtr = false); + static UniqueFEIRType CreateTypeByJavaName(const std::string &typeName, bool inMpl, bool usePtr); + static UniqueFEIRType CreatePointerType(UniqueFEIRType baseType, PrimType primType = PTY_ptr); + static UniqueFEIRType CreateTypeByDimIncr(const UniqueFEIRType &srcType, uint8 delta, bool usePtr = false, + PrimType primType = PTY_ptr); + static UniqueFEIRType CreateTypeByDimDecr(const UniqueFEIRType &srcType, uint8 delta); + static UniqueFEIRType CreateTypeByGetAddress(const UniqueFEIRType &srcType, PrimType primType = PTY_ptr); + static UniqueFEIRType CreateTypeByDereferrence(const UniqueFEIRType &srcType); + static UniqueFEIRType CreateTypeDefault(PrimType primType, const GStrIdx &typeNameIdx, TypeDim dim); + static UniqueFEIRType CreateTypeNative(MIRType &mirType); + + private: + FEIRTypeHelper() = default; + ~FEIRTypeHelper() = default; + static UniqueFEIRType CreateTypeByJavaNamePrim(char primTypeFlag, uint8 dim8); +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_FEIR_TYPE_HELPER_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/feir_type_infer.h b/src/hir2mpl/common/include/feir_type_infer.h new file mode 100644 index 0000000000000000000000000000000000000000..22333623c117bb4135d68339660f3e6329b4c47e --- /dev/null +++ b/src/hir2mpl/common/include/feir_type_infer.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FEIR_TYPE_INFER_H +#define HIR2MPL_INCLUDE_FEIR_TYPE_INFER_H +#include "fe_configs.h" +#include "feir_type.h" +#include "feir_var.h" +#include "feir_dfg.h" + +namespace maple { +class FEIRTypeMergeHelper { + public: + FEIRTypeMergeHelper(); + explicit FEIRTypeMergeHelper(const UniqueFEIRType &argTypeDefault); + ~FEIRTypeMergeHelper() = default; + void Reset(); + void ResetTypeDefault(const UniqueFEIRType &argTypeDefault); + bool MergeType(const UniqueFEIRType &argType, bool parent = true); + UniqueFEIRType GetResult() const; + const std::string &GetError() const { + return error; + } + + const UniqueFEIRType &GetType() const { + return type; + } + + UniqueFEIRType GetTypeClone() const { + return type->Clone(); + } + + LLT_PRIVATE: + UniqueFEIRType typeDefault; + UniqueFEIRType type; + std::string error; + bool firstType; + void SetDefaultType(UniqueFEIRType &typeDst); + void SetType(UniqueFEIRType &typeDst, const UniqueFEIRType &typeSrc); + bool MergeType(UniqueFEIRType &typeDst, const UniqueFEIRType &typeSrc, bool parent = true); +}; + +class FEIRTypeInfer { + public: + FEIRTypeInfer(MIRSrcLang argSrcLang, const FEIRDefUseChain &argMapDefUse); + ~FEIRTypeInfer() = default; + void LoadTypeDefault(); + void Reset(); + UniqueFEIRType GetTypeForVarUse(const UniqueFEIRVar &varUse); + UniqueFEIRType GetTypeForVarDef(UniqueFEIRVar &varDef); + UniqueFEIRType GetTypeByTransForVarUse(const UniqueFEIRVar &varUse); + void ProcessVarDef(UniqueFEIRVar &varDef); + + private: + MIRSrcLang srcLang; + UniqueFEIRType typeDefault; + FEIRTypeMergeHelper mergeHelper; + const FEIRDefUseChain &mapDefUse; + std::set visitVars; + bool withCircle = false; + bool first = false; +}; + +class FEIRTypeCvtHelper { + public: + static Opcode ChooseCvtOpcodeByFromTypeAndToType(const FEIRType &fromType, const FEIRType &toType); + + private: + static bool IsRetypeable(const FEIRType &fromType, const FEIRType &toType); + static bool IsIntCvt2Ref(const FEIRType &fromType, const FEIRType &toType); +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_FEIR_TYPE_INFER_H diff --git a/src/hir2mpl/common/include/feir_var.h b/src/hir2mpl/common/include/feir_var.h new file mode 100644 index 0000000000000000000000000000000000000000..98322da484ba4986b15d0db8fbfbc530d03e3ad1 --- /dev/null +++ b/src/hir2mpl/common/include/feir_var.h @@ -0,0 +1,210 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FEIR_VAR_H +#define HIR2MPL_INCLUDE_FEIR_VAR_H +#include +#include "mir_type.h" +#include "mir_symbol.h" +#include "mir_module.h" +#include "mir_builder.h" +#include "feir_type.h" +#include "generic_attrs.h" + +namespace maple { +enum FEIRVarTransKind : uint8 { + kFEIRVarTransDefault = 0, + kFEIRVarTransDirect, + kFEIRVarTransArrayDimIncr, + kFEIRVarTransArrayDimDecr, +}; + +class FEIRVar; +class FEIRVarTrans { + public: + FEIRVarTrans(FEIRVarTransKind argKind, std::unique_ptr &argVar); + FEIRVarTrans(FEIRVarTransKind argKind, std::unique_ptr &argVar, uint8 dimDelta); + ~FEIRVarTrans() = default; + UniqueFEIRType GetType(const UniqueFEIRType &type, PrimType primType = PTY_ref, bool usePtr = true); + std::unique_ptr &GetVar() const { + return var; + } + + void SetTransKind(FEIRVarTransKind argKind) { + kind = argKind; + } + + FEIRVarTransKind GetTransKind() const { + return kind; + } + + private: + FEIRVarTransKind kind; + std::unique_ptr &var; + union { + uint8 dimDelta; + } param; +}; + +using UniqueFEIRVarTrans = std::unique_ptr; + +enum FEIRVarKind : uint8 { + kFEIRVarDefault = 0, + kFEIRVarReg, + kFEIRVarAccumulator, + kFEIRVarName, + kFEIRVarTypeScatter, +}; + +// forward declaration for smart pointers +class FEIRExpr; +class FEIRVar { + public: + FEIRVar(FEIRVarKind argKind); + FEIRVar(FEIRVarKind argKind, std::unique_ptr argType); + virtual ~FEIRVar(); + void SetType(std::unique_ptr argType); + FEIRVarKind GetKind() const { + return kind; + } + + bool operator==(const FEIRVar &var) const { + return GetNameRaw() == var.GetNameRaw(); + } + + bool operator!=(const FEIRVar &var) const { + return GetNameRaw() != var.GetNameRaw(); + } + + const UniqueFEIRType &GetType() const { + return type; + } + + const FEIRType &GetTypeRef() const { + ASSERT(type != nullptr, "type is nullptr"); + return *type.get(); + } + + bool IsGlobal() const { + return isGlobal; + } + + void SetGlobal(bool arg) { + isGlobal = arg; + } + + bool IsDef() const { + return isDef; + } + + void SetDef(bool arg) { + isDef = std::move(arg); + } + + void SetTrans(UniqueFEIRVarTrans argTrans) { + trans = std::move(argTrans); + } + + const UniqueFEIRVarTrans &GetTrans() const { + return trans; + } + + MIRSymbol *GenerateGlobalMIRSymbol(MIRBuilder &builder) const { + MIRSymbol *mirSym = GenerateGlobalMIRSymbolImpl(builder); + mirSym->GetSrcPosition().SetFileNum(static_cast(srcFileIdx)); + mirSym->GetSrcPosition().SetLineNum(srcFileLineNum); + builder.GetMirModule().InsertInlineGlobal(mirSym->GetStIdx().Idx()); + return mirSym; + } + + MIRSymbol *GenerateLocalMIRSymbol(MIRBuilder &builder) const { + MIRSymbol *mirSym = GenerateLocalMIRSymbolImpl(builder); + mirSym->GetSrcPosition().SetFileNum(static_cast(srcFileIdx)); + mirSym->GetSrcPosition().SetLineNum(srcFileLineNum); + return mirSym; + } + + MIRSymbol *GenerateMIRSymbol(MIRBuilder &builder) const { + return GenerateMIRSymbolImpl(builder); + } + + std::string GetName(const MIRType &mirType) const { + return GetNameImpl(mirType); + } + + std::string GetNameRaw() const { + return GetNameRawImpl(); + } + + std::unique_ptr Clone() const { + return CloneImpl(); + } + + bool EqualsTo(const std::unique_ptr &var) const { + return EqualsToImpl(var); + } + + uint32 Hash() const { + return HashImpl(); + } + + void SetAttrs(const GenericAttrs &argGenericAttrs) { + genAttrs = argGenericAttrs; + } + + void SetSectionAttr(const std::string &str) { + sectionAttr = str; + } + + void SetSrcLOC(uint32 fileIdx, uint32 lineNum) { + srcFileIdx = fileIdx; + srcFileLineNum = lineNum; + } + + uint32 GetSrcFileIdx() const { + return srcFileIdx; + } + + uint32 GetSrcFileLineNum() const { + return srcFileLineNum; + } + + void SetBoundaryLenExpr(std::unique_ptr expr); + const std::unique_ptr &GetBoundaryLenExpr() const; + + protected: + virtual MIRSymbol *GenerateGlobalMIRSymbolImpl(MIRBuilder &builder) const; + virtual MIRSymbol *GenerateLocalMIRSymbolImpl(MIRBuilder &builder) const; + virtual MIRSymbol *GenerateMIRSymbolImpl(MIRBuilder &builder) const; + virtual std::string GetNameImpl(const MIRType &mirType) const = 0; + virtual std::string GetNameRawImpl() const = 0; + virtual std::unique_ptr CloneImpl() const = 0; + virtual bool EqualsToImpl(const std::unique_ptr &var) const = 0; + virtual uint32 HashImpl() const = 0; + + FEIRVarKind kind : 6; + bool isGlobal : 1; + bool isDef : 1; + UniqueFEIRType type; + UniqueFEIRVarTrans trans; + GenericAttrs genAttrs; + uint32 srcFileIdx = 0; + uint32 srcFileLineNum = 0; + std::string sectionAttr; + std::unique_ptr boundaryLenExpr; +}; + +using UniqueFEIRVar = std::unique_ptr; +} // namespace maple +#endif // HIR2MPL_INCLUDE_FEIR_VAR_H diff --git a/src/hir2mpl/common/include/feir_var_name.h b/src/hir2mpl/common/include/feir_var_name.h new file mode 100644 index 0000000000000000000000000000000000000000..b7c79a3042efec91894bf77d5fd778aee6001665 --- /dev/null +++ b/src/hir2mpl/common/include/feir_var_name.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FEIR_VAR_NAME_H +#define HIR2MPL_INCLUDE_FEIR_VAR_NAME_H +#include +#include "mir_symbol.h" +#include "types_def.h" +#include "global_tables.h" +#include "feir_var.h" + +namespace maple { +// ---------- FEIRVarName ---------- +class FEIRVarName : public FEIRVar { + public: + FEIRVarName(const GStrIdx &argNameIdx, bool argWithType = false) + : FEIRVar(FEIRVarKind::kFEIRVarName), + nameIdx(argNameIdx), + withType(argWithType) {} + + FEIRVarName(const GStrIdx &argNameIdx, std::unique_ptr argType, bool argWithType = false) + : FEIRVar(FEIRVarKind::kFEIRVarName, std::move(argType)), + nameIdx(argNameIdx), + withType(argWithType) {} + + FEIRVarName(const std::string &argName, std::unique_ptr argType, bool argWithType = false) + : FEIRVarName(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(argName), std::move(argType), argWithType) {} + + virtual ~FEIRVarName() = default; + + protected: + std::string GetNameImpl(const MIRType &mirType) const override; + std::string GetNameRawImpl() const override; + std::unique_ptr CloneImpl() const override; + bool EqualsToImpl(const std::unique_ptr &var) const override; + uint32 HashImpl() const override; + + GStrIdx nameIdx; + // means emit this symbol with type + bool withType : 1; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_FEIR_VAR_REG_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/feir_var_reg.h b/src/hir2mpl/common/include/feir_var_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..55cbaec0bf3ca09b7468431c29792df14aaf230a --- /dev/null +++ b/src/hir2mpl/common/include/feir_var_reg.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_FEIR_VAR_REG_H +#define HIR2MPL_INCLUDE_FEIR_VAR_REG_H +#include "mir_symbol.h" +#include "feir_var.h" + +namespace maple { +class FEIRVarReg : public FEIRVar { + public: + FEIRVarReg(uint32 argRegNum, FEIRVarKind kind = FEIRVarKind::kFEIRVarReg) + : FEIRVar(kind), + regNum(argRegNum) {} + + FEIRVarReg(uint32 argRegNum, PrimType argPrimType) + : FEIRVarReg(argRegNum) { + type->SetPrimType(argPrimType); + } + + FEIRVarReg(uint32 argRegNum, std::unique_ptr argType, FEIRVarKind kind = FEIRVarKind::kFEIRVarReg) + : FEIRVar(kind, std::move(argType)), + regNum(argRegNum) {} + + ~FEIRVarReg() = default; + uint32 GetRegNum() const { + return regNum; + } + + protected: + std::string GetNameImpl(const MIRType &mirType) const override; + std::string GetNameRawImpl() const override; + MIRSymbol *GenerateLocalMIRSymbolImpl(MIRBuilder &builder) const override; + std::unique_ptr CloneImpl() const override; + bool EqualsToImpl(const std::unique_ptr &var) const override; + uint32 HashImpl() const override; + uint32 regNum; +}; + +class FEIRVarAccumulator : public FEIRVarReg { + public: + FEIRVarAccumulator(uint32 argRegNum) + : FEIRVarReg(argRegNum, FEIRVarKind::kFEIRVarAccumulator) {} + + FEIRVarAccumulator(uint32 argRegNum, PrimType argPrimType) + : FEIRVarAccumulator(argRegNum) { + type->SetPrimType(argPrimType); + } + + FEIRVarAccumulator(uint32 argRegNum, std::unique_ptr argType) + : FEIRVarReg(argRegNum, std::move(argType), FEIRVarKind::kFEIRVarAccumulator) {} + + ~FEIRVarAccumulator() = default; + + protected: + std::string GetNameImpl(const MIRType &mirType) const override; + std::string GetNameRawImpl() const override; + std::unique_ptr CloneImpl() const override; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_FEIR_VAR_REG_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/feir_var_type_scatter.h b/src/hir2mpl/common/include/feir_var_type_scatter.h new file mode 100644 index 0000000000000000000000000000000000000000..10db374fc4a11d2f5e4832ebfb292f8870814ee4 --- /dev/null +++ b/src/hir2mpl/common/include/feir_var_type_scatter.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef FEIR_VAR_TYPE_SCATTER_H +#define FEIR_VAR_TYPE_SCATTER_H +#include +#include "feir_var.h" +#include "feir_type.h" + +namespace maple { +class FEIRVarTypeScatter : public FEIRVar { + public: + FEIRVarTypeScatter(UniqueFEIRVar argVar); + ~FEIRVarTypeScatter() = default; + void AddScatterType(const UniqueFEIRType &type); + const std::unordered_set &GetScatterTypes() const { + return scatterTypes; + } + + const UniqueFEIRVar &GetVar() const { + return var; + } + + protected: + MIRSymbol *GenerateGlobalMIRSymbolImpl(MIRBuilder &builder) const override; + MIRSymbol *GenerateLocalMIRSymbolImpl(MIRBuilder &builder) const override; + MIRSymbol *GenerateMIRSymbolImpl(MIRBuilder &builder) const override; + std::string GetNameImpl(const MIRType &mirType) const override; + std::string GetNameRawImpl() const override; + std::unique_ptr CloneImpl() const override; + bool EqualsToImpl(const std::unique_ptr &argVar) const override; + uint32 HashImpl() const override; + + private: + UniqueFEIRVar var; + std::unordered_set scatterTypes; +}; // class FEIRVarTypeScatter +} // namespace maple +#endif // FEIR_VAR_TYPE_SCATTER_H diff --git a/src/hir2mpl/common/include/generic_attrs.h b/src/hir2mpl/common/include/generic_attrs.h new file mode 100644 index 0000000000000000000000000000000000000000..9f49d370c70c5e0ba8deb2d10487adf4d9acfc0c --- /dev/null +++ b/src/hir2mpl/common/include/generic_attrs.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef GENERIC_ATTRS_H +#define GENERIC_ATTRS_H +#include +#include +#include "mir_type.h" + +namespace maple { +using AttrContent = std::variant; +// only for internal use, not emitted +enum GenericAttrKind { +#define FUNC_ATTR +#define TYPE_ATTR +#define FIELD_ATTR +#define ATTR(STR) GENATTR_##STR, +#include "all_attributes.def" +#undef ATTR +#undef FUNC_ATTR +#undef TYPE_ATTR +#undef FIELD_ATTR +}; + +class GenericAttrs { + public: + GenericAttrs() = default; + GenericAttrs(const GenericAttrs &ta) = default; + GenericAttrs &operator=(const GenericAttrs &p) = default; + ~GenericAttrs() = default; + + void SetAttr(GenericAttrKind x) { + attrFlag.set(x); + } + + bool GetAttr(GenericAttrKind x) const { + return attrFlag[x]; + } + + bool operator==(const GenericAttrs &tA) const { + return attrFlag == tA.attrFlag; + } + + bool operator!=(const GenericAttrs &tA) const { + return !(*this == tA); + } + + void InsertIntContentMap(GenericAttrKind key, int val) { + contentMap.insert(std::make_pair(key, val)); + } + + void InsertStrIdxContentMap(GenericAttrKind key, GStrIdx nameIdx) { + contentMap.insert(std::make_pair(key, nameIdx)); + } + + FieldAttrs ConvertToFieldAttrs(); + TypeAttrs ConvertToTypeAttrs(); + FuncAttrs ConvertToFuncAttrs(); + + private: + std::bitset<128> attrFlag = 0; + std::map contentMap; +}; +} +#endif // GENERIC_ATTRS_H \ No newline at end of file diff --git a/src/hir2mpl/common/include/hir2mpl_compiler.h b/src/hir2mpl/common/include/hir2mpl_compiler.h new file mode 100644 index 0000000000000000000000000000000000000000..3645e767a062616ce53de8fb59bdf45e2ad9f4c9 --- /dev/null +++ b/src/hir2mpl/common/include/hir2mpl_compiler.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_HIR2MPL_COMPILER_NEW_H +#define HIR2MPL_INCLUDE_COMMON_HIR2MPL_COMPILER_NEW_H +#include +#include +#include "fe_macros.h" +#include "hir2mpl_compiler_component.h" +#include "mpl_logging.h" +#include "hir2mpl_options.h" +#include "jbc_compiler_component.h" +#include "fe_options.h" +#include "bc_compiler_component.h" +#include "ark_annotation_processor.h" +#include "dex_reader.h" +#include "ast_compiler_component.h" +#include "ast_parser.h" +#ifdef ENABLE_MAST +#include "maple_ast_parser.h" +#endif +#include "mpl_timer.h" +#include "hir2mpl_env.h" +#include "fe_manager.h" +#include "fe_type_hierarchy.h" + +namespace maple { +class HIR2MPLCompiler { + public: + explicit HIR2MPLCompiler(MIRModule &argModule); + ~HIR2MPLCompiler(); + // common process + int Run(); + void Init(); + void Release(); + void CheckInput(); + void SetupOutputPathAndName(); + bool LoadMplt(); + void ExportMpltFile(); + void ExportMplFile(); + + // component process + void RegisterCompilerComponent(std::unique_ptr comp); + void ParseInputs(); + void LoadOnDemandTypes(); + void PreProcessDecls(); + void ProcessDecls(); + void ProcessPragmas(); + void ProcessFunctions(); + + private: + void RegisterCompilerComponent(); + inline void InsertImportInMpl(const std::list &mplt) const; + void FindMinCompileFailedFEFunctions(); + MIRModule &module; + MIRSrcLang srcLang; + MemPool *mp; + MapleAllocator allocator; + std::string firstInputName; + std::string outputPath; + std::string outputName; + std::string outNameWithoutType; + std::list> components; + std::set compileFailedFEFunctions; +}; +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_HIR2MPL_COMPILER_NEW_H diff --git a/src/hir2mpl/common/include/hir2mpl_compiler_component.h b/src/hir2mpl/common/include/hir2mpl_compiler_component.h new file mode 100644 index 0000000000000000000000000000000000000000..5a9d4479be2a33ed78401f32ed41339789c356b3 --- /dev/null +++ b/src/hir2mpl/common/include/hir2mpl_compiler_component.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_HIR2MPL_COMPILER_COMPONENT_H +#define HIR2MPL_INCLUDE_COMMON_HIR2MPL_COMPILER_COMPONENT_H +#include +#include +#include "mir_module.h" +#include "hir2mpl_options.h" +#include "fe_function.h" +#include "fe_input.h" +#include "fe_input_helper.h" +#include "mpl_scheduler.h" + +namespace maple { +class FEFunctionProcessTask : public MplTask { + public: + FEFunctionProcessTask(std::unique_ptr argFunction); + virtual ~FEFunctionProcessTask() = default; + + protected: + int RunImpl(MplTaskParam *param) override; + int FinishImpl(MplTaskParam *param) override; + + private: + std::unique_ptr function; +}; + +class FEFunctionProcessSchedular : public MplScheduler { + public: + FEFunctionProcessSchedular(const std::string &name) + : MplScheduler(name) {} + virtual ~FEFunctionProcessSchedular() = default; + void AddFunctionProcessTask(std::unique_ptr function); + void SetDumpTime(bool arg) { + dumpTime = arg; + } + + protected: + void CallbackThreadMainStart() override; + + private: + std::list> tasks; +}; + +class HIR2MPLCompilerComponent { + public: + HIR2MPLCompilerComponent(MIRModule &argModule, MIRSrcLang argSrcLang); + virtual ~HIR2MPLCompilerComponent() = default; + bool ParseInput() { + return ParseInputImpl(); + } + + bool LoadOnDemandType() { + return LoadOnDemandTypeImpl(); + } + + bool PreProcessDecl() { + return PreProcessDeclImpl(); + } + + bool ProcessDecl() { + return ProcessDeclImpl(); + } + + void ProcessPragma() { + ProcessPragmaImpl(); + } + + std::unique_ptr CreatFEFunction(FEInputMethodHelper *methodHelper) { + return CreatFEFunctionImpl(methodHelper); + } + + bool ProcessFunctionSerial() { + return ProcessFunctionSerialImpl(); + } + + bool ProcessFunctionParallel(uint32 nthreads) { + return ProcessFunctionParallelImpl(nthreads); + } + + std::string GetComponentName() const { + return GetComponentNameImpl(); + } + + bool Parallelable() const { + return ParallelableImpl(); + } + + void DumpPhaseTimeTotal() const { + DumpPhaseTimeTotalImpl(); + } + + uint32 GetFunctionsSize() const { + return funcSize; + } + + const std::set &GetCompileFailedFEFunctions() const { + return compileFailedFEFunctions; + } + + void ReleaseMemPool() { + ReleaseMemPoolImpl(); + } + + protected: + virtual bool ParseInputImpl() = 0; + virtual bool LoadOnDemandTypeImpl(); + virtual bool PreProcessDeclImpl(); + virtual bool ProcessDeclImpl(); + virtual void ProcessPragmaImpl() {}; + virtual std::unique_ptr CreatFEFunctionImpl(FEInputMethodHelper *methodHelper) = 0; + virtual bool ProcessFunctionSerialImpl(); + virtual bool ProcessFunctionParallelImpl(uint32 nthreads); + virtual std::string GetComponentNameImpl() const; + virtual bool ParallelableImpl() const; + virtual void DumpPhaseTimeTotalImpl() const; + virtual void ReleaseMemPoolImpl() = 0; + + uint32 funcSize; + MIRModule &module; + MIRSrcLang srcLang; + std::list> fieldHelpers; + std::list> methodHelpers; + std::list structHelpers; + std::list globalFuncHelpers; + std::list globalVarHelpers; + std::list globalFileScopeAsmHelpers; + std::unique_ptr phaseResultTotal; + std::set compileFailedFEFunctions; +}; +} // namespace maple +#endif diff --git a/src/hir2mpl/common/include/hir2mpl_env.h b/src/hir2mpl/common/include/hir2mpl_env.h new file mode 100644 index 0000000000000000000000000000000000000000..4d5069893c32407952ad03baaa712c68c82f282e --- /dev/null +++ b/src/hir2mpl/common/include/hir2mpl_env.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_HIR2MPL_ENV_H +#define HIR2MPL_INCLUDE_COMMON_HIR2MPL_ENV_H +#include +#include +#include +#include "mir_module.h" + +namespace maple { +class HIR2MPLEnv { + public: + void Init(); + void Finish(); + uint32 NewSrcFileIdx(const GStrIdx &nameIdx); + GStrIdx GetFileNameIdx(uint32 fileIdx) const; + std::string GetFileName(uint32 fileIdx) const; + static HIR2MPLEnv &GetInstance() { + return instance; + } + + uint32 GetGlobalLabelIdx() const { + return globalLabelIdx; + } + + void IncrGlobalLabelIdx() { + globalLabelIdx++; + } + + private: + static HIR2MPLEnv instance; + std::map srcFileIdxNameMap; + uint32 globalLabelIdx = GStrIdx(0); + HIR2MPLEnv() = default; + ~HIR2MPLEnv() = default; +}; // class HIR2MPLEnv +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_HIR2MPL_ENV_H diff --git a/src/hir2mpl/common/include/hir2mpl_options.h b/src/hir2mpl/common/include/hir2mpl_options.h new file mode 100644 index 0000000000000000000000000000000000000000..bbfe437c9b53e1181ae15cd33d5c5dc33a2c5e48 --- /dev/null +++ b/src/hir2mpl/common/include/hir2mpl_options.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_COMMON_HIR2MPL_OPTIONS_H +#define HIR2MPL_INCLUDE_COMMON_HIR2MPL_OPTIONS_H +#include +#include +#include "factory.h" +#include "parser_opt.h" +#include "option_parser.h" +#include "types_def.h" +#include "driver_option_common.h" + +namespace maple { +class HIR2MPLOptions : public maple::MapleDriverOptionBase { + public: + static inline HIR2MPLOptions &GetInstance() { + static HIR2MPLOptions options; + return options; + } + void Init(); + static bool InitFactory(); + bool SolveOptions(const std::deque &opts, bool isDebug); + bool SolveArgs(int argc, char **argv); + void DumpUsage() const; + void DumpVersion() const; + template + static void Split(const std::string &s, char delim, Out result); + static std::list SplitByComma(const std::string &s); + + // non-option process + void ProcessInputFiles(const std::vector &inputs); + + private: + using OptionProcessFactory = FunctionFactory; + + HIR2MPLOptions(); + ~HIR2MPLOptions() = default; + + // option process + bool ProcessHelp(const mapleOption::Option &opt); + bool ProcessVersion(const mapleOption::Option &opt); + + // input control options + bool ProcessInClass(const mapleOption::Option &opt); + bool ProcessInJar(const mapleOption::Option &opt); + bool ProcessInDex(const mapleOption::Option &opt); + bool ProcessInAST(const mapleOption::Option &opt); + bool ProcessInMAST(const mapleOption::Option &opt); + bool ProcessInputMplt(const mapleOption::Option &opt); + bool ProcessInputMpltFromSys(const mapleOption::Option &opt); + bool ProcessInputMpltFromApk(const mapleOption::Option &opt); + + // output control options + bool ProcessOutputPath(const mapleOption::Option &opt); + bool ProcessOutputName(const mapleOption::Option &opt); + bool ProcessGenMpltOnly(const mapleOption::Option &opt); + bool ProcessGenAsciiMplt(const mapleOption::Option &opt); + bool ProcessDumpInstComment(const mapleOption::Option &opt); + bool ProcessNoMplFile(const mapleOption::Option &opt); + + // debug info control options + bool ProcessDumpLevel(const mapleOption::Option &opt); + bool ProcessDumpTime(const mapleOption::Option &opt); + bool ProcessDumpComment(const mapleOption::Option &opt); + bool ProcessDumpLOC(const mapleOption::Option &opt); + bool ProcessDumpPhaseTime(const mapleOption::Option &opt); + bool ProcessDumpPhaseTimeDetail(const mapleOption::Option &opt); + + // java compiler options + bool ProcessModeForJavaStaticFieldName(const mapleOption::Option &opt); + bool ProcessJBCInfoUsePathName(const mapleOption::Option &opt); + bool ProcessDumpJBCStmt(const mapleOption::Option &opt); + bool ProcessDumpJBCAll(const mapleOption::Option &opt); + bool ProcessDumpJBCErrorOnly(const mapleOption::Option &opt); + bool ProcessDumpJBCFuncName(const mapleOption::Option &opt); + bool ProcessEmitJBCLocalVarInfo(const mapleOption::Option &opt); + + // bc compiler options + bool ProcessRC(const mapleOption::Option &opt); + bool ProcessNoBarrier(const mapleOption::Option &opt); + bool ProcessO2(const mapleOption::Option &opt); + bool ProcessSimplifyShortCircuit(const mapleOption::Option &opt); + bool ProcessEnableVariableArray(const mapleOption::Option &opt); + bool ProcessFuncInlineSize(const mapleOption::Option &opt); + bool ProcessWPAA(const mapleOption::Option &opt); + + // ast compiler options + bool ProcessUseSignedChar(const mapleOption::Option &opt); + bool ProcessBigEndian(const mapleOption::Option &opt); + + // general stmt/bb/cfg options + bool ProcessDumpFEIRBB(const mapleOption::Option &opt); + bool ProcessDumpFEIRCFGGraph(const mapleOption::Option &opt); + + // multi-thread control options + bool ProcessNThreads(const mapleOption::Option &opt); + bool ProcessDumpThreadTime(const mapleOption::Option &opt); + bool ProcessReleaseAfterEmit(const mapleOption::Option &opt); + + // On Demand Type Creation + bool ProcessXbootclasspath(const mapleOption::Option &opt); + bool ProcessClassLoaderContext(const mapleOption::Option &opt); + bool ProcessCompilefile(const mapleOption::Option &opt); + bool ProcessCollectDepTypes(const mapleOption::Option &opt); + bool ProcessDepSameNamePolicy(const mapleOption::Option &opt); + + // EnhanceC + bool ProcessNpeCheckDynamic(const mapleOption::Option &opt); + bool ProcessBoundaryCheckDynamic(const mapleOption::Option &opt); + bool ProcessSafeRegion(const mapleOption::Option &opt); + + // symbol resolve + bool ProcessAOT(const mapleOption::Option &opt); +}; // class HIR2MPLOptions +} // namespace maple +#endif // HIR2MPL_INCLUDE_COMMON_HIR2MPL_OPTIONS_H diff --git a/src/hir2mpl/common/include/simple_xml.h b/src/hir2mpl/common/include/simple_xml.h new file mode 100644 index 0000000000000000000000000000000000000000..090dbd09d48fcf772b47087a40db6d2c5f6a2dff --- /dev/null +++ b/src/hir2mpl/common/include/simple_xml.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef HIR2MPL_INCLUDE_SIMPLE_XML_H +#define HIR2MPL_INCLUDE_SIMPLE_XML_H +#include +#include +#include +#include "types_def.h" +#include "mempool_allocator.h" +#include "maple_string.h" + +namespace maple { +enum SimpleXMLElemIdTag { + kXMLIDNone, + kXMLID, +}; + +enum SimpleXMLElemValueTag { + kXMLValueNone, + kXMLValueI8, + kXMLValueU8, + kXMLValueI16, + kXMLValueU16, + kXMLValueI32, + kXMLValueU32, + kXMLValueI64, + kXMLValueU64, + kXMLValueFloat, + kXMLValueDouble, + kXMLValueString, +}; + +class SimpleXMLElem { + public: + SimpleXMLElem(MapleAllocator &alloc, const std::string &cat); + SimpleXMLElem(MapleAllocator &alloc, const std::string &cat, uint32 argID); + virtual ~SimpleXMLElem() = default; + void AddElement(SimpleXMLElem &elem); + SimpleXMLElem *AddNewElement(const std::string &cat); + SimpleXMLElem *AddNewElement(const std::string &cat, uint32 argID); + void SetValue(int8 v); + void SetValue(uint8 v); + void SetValue(int16 v); + void SetValue(uint16 v); + void SetValue(int32 v); + void SetValue(uint32 v); + void SetValue(int64 v); + void SetValue(uint64 v); + void SetValue(float v); + void SetValue(double v); + void SetValue(const std::string &str); + void SetContent(const std::string &str); + static std::string XMLString(const std::string &strIn); + void Dump(std::ostream &os, const std::string &prefix = "") const { + return DumpImpl(os, prefix); + } + + protected: + virtual void DumpImpl(std::ostream &os, const std::string &prefix) const; + void DumpHead(std::ostream &os, const std::string &prefix = "") const; + void DumpTail(std::ostream &os, const std::string &prefix = "") const; + + SimpleXMLElemIdTag tagID; + SimpleXMLElemValueTag tagValue; + MapleAllocator &allocator; + std::string catalog; + uint32 id; + union { + int8 i8; + uint8 u8; + int16 i16; + uint16 u16; + int32 i32; + uint32 u32; + int64 i64; + uint64 u64; + float f; + double d; + uint64 raw; + } value; + std::string valueString; + std::string content; + MapleList elems; +}; + +class SimpleXMLElemMultiLine : public SimpleXMLElem { + public: + SimpleXMLElemMultiLine(MapleAllocator &alloc, const std::string &cat); + SimpleXMLElemMultiLine(MapleAllocator &alloc, const std::string &cat, uint32 argID); + ~SimpleXMLElemMultiLine() = default; + void AddLine(const std::string &line); + + protected: + void DumpImpl(std::ostream &os, const std::string &prefix) const override; + + private: + MapleList lines; +}; + +class SimpleXML { + public: + SimpleXML(MapleAllocator &alloc); + ~SimpleXML() = default; + void AddRoot(SimpleXMLElem &elem); + + protected: + void DumpImpl(std::ostream &os) const; + + private: + MapleAllocator &allocator; + MapleList roots; +}; +} // namespace maple +#endif diff --git a/src/hir2mpl/common/include/simple_zip.h b/src/hir2mpl/common/include/simple_zip.h new file mode 100644 index 0000000000000000000000000000000000000000..19efa5b4cebef98f5aebe3d7c54730d0f43b01c2 --- /dev/null +++ b/src/hir2mpl/common/include/simple_zip.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +// ref: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT +#ifndef HIR2MPL_INCLUDE_SIMPLE_ZIP_H +#define HIR2MPL_INCLUDE_SIMPLE_ZIP_H +#include +#include +#include +#include "types_def.h" +#include "basic_io.h" + +namespace maple { +static const uint32 kZipSigLocalFile = 0x04034B50; +static const uint32 kZipSigDataDescriptor = 0x08074B50; +static const uint32 kZipSigCentralDir = 0x02014B50; + +class ZipLocalFileHeader { + public: + ZipLocalFileHeader() = default; + ~ZipLocalFileHeader(); + static std::unique_ptr Parse(BasicIORead &io); + uint16 GetGPFlag() const { + return gpFlag; + } + + std::string GetFileName() const { + return fileName; + } + + private: + uint32 signature = 0; + uint16 minVersion = 0; + uint16 gpFlag = 0; + uint16 compMethod = 0; + uint16 rawTime = 0; + uint16 rawDate = 0; + uint32 crc32 = 0; + uint32 compSize = 0; + uint32 unCompSize = 0; + uint16 lengthFileName = 0; + uint16 lengthExtraField = 0; + std::string fileName = ""; + uint8 *extraField = nullptr; +}; + +class ZipDataDescriptor { + public: + ZipDataDescriptor() = default; + ~ZipDataDescriptor() = default; + static std::unique_ptr Parse(BasicIORead &io); + uint32 GetSignature() const { + return signature; + } + + uint32 GetCRC32() const { + return crc32; + } + + uint32 GetCompSize() const { + return compSize; + } + + uint32 GetUnCompSize() const { + return unCompSize; + } + + private: + uint32 signature = 0; + uint32 crc32 = 0; + uint32 compSize = 0; + uint32 unCompSize = 0; +}; + +class ZipLocalFile { + public: + ZipLocalFile() = default; + ~ZipLocalFile(); + static std::unique_ptr Parse(BasicIORead &io); + std::string GetFileName() const { + return header->GetFileName(); + } + + const uint8 *GetUnCompData() const { + return unCompData; + } + + uint32 GetUnCompDataSize() const { + return unCompDataSize; + } + + private: + uint32 GetDataEndPos(const BasicIORead &io); + void ProcessUncompressedFile(BasicIORead &io, uint32 start, uint32 end); + void ProcessCompressedFile(BasicIORead &io, uint32 start, uint32 end); + + std::unique_ptr header; + uint8 *compData = nullptr; + uint8 *unCompData = nullptr; + uint32 unCompDataSize = 0; + std::unique_ptr dataDesc; + bool isCompressed = false; +}; + +class SimpleZip : public BasicIORead { + public: + SimpleZip(BasicIOMapFile &file); + ~SimpleZip(); + void ParseFile(); + + const std::list> &GetFiles() const { + return files; + } + + private: + std::list> files; +}; +} // namespace maple +#endif diff --git a/src/hir2mpl/common/src/base64.cpp b/src/hir2mpl/common/src/base64.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c84a071692028eecac0e6f5bcc8f0ab3512a8edd --- /dev/null +++ b/src/hir2mpl/common/src/base64.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "base64.h" +#include +#include +#include "types_def.h" +#include "mpl_logging.h" + +namespace maple { +namespace { +const std::string kBase64IdxStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +const uint32 kBase64IdxStrLength = 64; +const uint8 kBase64MaskEncode = 0x3F; +const uint8 kBase64MaskDecode = 0xFF; +const uint32 kBase64Shift0 = 0; +const uint32 kBase64Shift8 = 8; +const uint32 kBase64Shift16 = 16; +const uint32 kBase64Shift6 = 6; +const uint32 kBase64Shift12 = 12; +const uint32 kBase64Shift18 = 18; +const size_t kBase64EncodeBaseLen = 3; +const size_t kBase64DecodeBaseLen = 4; +} + +std::map Base64::encodeMap = Base64::InitEncodeMap(); +std::map Base64::decodeMap = Base64::InitDecodeMap(); + +std::map Base64::InitEncodeMap() { + // init encode map + std::map ans; + CHECK_FATAL(kBase64IdxStr.length() == kBase64IdxStrLength, "length of base64_idx_str_ must be 64"); + for (size_t i = 0; i < kBase64IdxStr.length(); i++) { + CHECK_FATAL(ans.insert(std::make_pair(i, kBase64IdxStr[i])).second, "encodeMap insert failed"); + } + return ans; +} + +std::map Base64::InitDecodeMap() { + // init decode map + std::map ans; + CHECK_FATAL(kBase64IdxStr.length() == kBase64IdxStrLength, "length of base64_idx_str_ must be 64"); + for (uint32 i = 0; i < kBase64IdxStr.length(); i++) { + CHECK_FATAL(ans.insert(std::make_pair(kBase64IdxStr[i], i)).second, "decodeMap insert failed"); + } + CHECK_FATAL(ans.insert(std::make_pair('=', 0)).second, "decodeMap insert failed"); + return ans; +} + +std::string Base64::Encode(const uint8 *input, size_t length) { + // process input + std::string strEncoded; + uint32 temp; + size_t offset; + while (length > 0) { + temp = 0; + if (length >= 1) { + temp |= (input[0] << kBase64Shift16); + } + if (length >= 2) { + temp |= (input[1] << kBase64Shift8); + } + if (length >= 3) { + temp |= (input[2] << kBase64Shift0); + } + + // encoded code 0 + strEncoded.push_back(encodeMap[static_cast((temp >> kBase64Shift18) & kBase64MaskEncode)]); + // encoded code 1 + strEncoded.push_back(encodeMap[static_cast((temp >> kBase64Shift12) & kBase64MaskEncode)]); + + if (length < 2) { + strEncoded.push_back('='); + } else { + // encoded code 2 + strEncoded.push_back(encodeMap[static_cast((temp >> kBase64Shift6) & kBase64MaskEncode)]); + } + + if (length < kBase64EncodeBaseLen) { + strEncoded.push_back('='); + } else { + // encoded code 3 + strEncoded.push_back(encodeMap[static_cast((temp >> kBase64Shift0) & kBase64MaskEncode)]); + } + + offset = (length >= kBase64EncodeBaseLen) ? kBase64EncodeBaseLen : length; + length -= offset; + input += offset; + } + return strEncoded; +} + +size_t Base64::DecodeLength(const std::string &input) { + // length calculation + size_t length; + const char *inputBuf = input.c_str(); + size_t inputLength = input.length(); + if (inputLength == 0) { + return 0; + } + CHECK_FATAL(inputLength % kBase64DecodeBaseLen == 0, "input.length must be factor of 4"); + length = inputLength * kBase64EncodeBaseLen / kBase64DecodeBaseLen; + if (inputBuf[inputLength - 1] == '=') { + length--; + } + if (inputBuf[inputLength - 2] == '=') { + length--; + } + return length; +} + +uint8 *Base64::Decode(const std::string &input, size_t &lengthRet) { + size_t inputLength = input.length(); + lengthRet = DecodeLength(input); + if (lengthRet == 0) { + return nullptr; + } + size_t idx = 0; + const char *inputBuf = input.c_str(); + uint8 *buf = static_cast(malloc(sizeof(uint8) * lengthRet)); + CHECK_FATAL(buf != nullptr, "malloc failed"); + uint32 temp; + while (inputLength > 0) { + auto it0 = decodeMap.find(inputBuf[0]); + auto it1 = decodeMap.find(inputBuf[1]); + auto it2 = decodeMap.find(inputBuf[2]); + auto it3 = decodeMap.find(inputBuf[3]); + if (it0 == decodeMap.end() || it1 == decodeMap.end() || it2 == decodeMap.end() || it3 == decodeMap.end()) { + CHECK_FATAL(false, "invalid input"); + } + temp = (it0->second << kBase64Shift18) | (it1->second << kBase64Shift12) | (it2->second << kBase64Shift6) | + (it3->second << kBase64Shift0); + uint8 c0 = (temp >> kBase64Shift16) & kBase64MaskDecode; + uint8 c1 = (temp >> kBase64Shift8) & kBase64MaskDecode; + uint8 c2 = (temp >> kBase64Shift0) & kBase64MaskDecode; + if (inputBuf[2] == '=') { + CHECK_FATAL(inputLength == kBase64DecodeBaseLen, "'=' must be in last package"); + CHECK_FATAL(inputBuf[3] == '=', "'=' must be in last package"); + buf[idx++] = c0; + } else if (inputBuf[3] == '=') { + CHECK_FATAL(inputLength == kBase64DecodeBaseLen, "'=' must be in last package"); + buf[idx++] = c0; + buf[idx++] = c1; + } else { + buf[idx++] = c0; + buf[idx++] = c1; + buf[idx++] = c2; + } + inputLength -= kBase64DecodeBaseLen; + inputBuf += kBase64DecodeBaseLen; + } + return buf; +} +} // namespace maple diff --git a/src/hir2mpl/common/src/basic_io.cpp b/src/hir2mpl/common/src/basic_io.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c8849c7d5d93adeb36897149b8e7976983ad84e3 --- /dev/null +++ b/src/hir2mpl/common/src/basic_io.cpp @@ -0,0 +1,330 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "basic_io.h" +#include +#include +#include +#include +#include +#include +#include +#include "mpl_logging.h" + +namespace maple { +BasicIOMapFile::BasicIOMapFile(const std::string &name) + : fd(-1), ptr(nullptr), ptrMemMap(nullptr), length(0), fileName(name) {} + +BasicIOMapFile::BasicIOMapFile(const std::string &name, const uint8 *ptrIn, long lengthIn) + : fd(-1), ptr(ptrIn), ptrMemMap(nullptr), length(lengthIn), fileName(name) {} + +BasicIOMapFile::~BasicIOMapFile() { + ptr = nullptr; + ptrMemMap = nullptr; +} + +bool BasicIOMapFile::OpenAndMapImpl() { + fd = -1; + fd = open(fileName.c_str(), O_RDONLY); + if (fd < 0) { + ERR(kLncErr, "Unable to open %s.\nError %d in open()", fileName.c_str(), errno); + return false; + } + long start = lseek(fd, 0L, SEEK_SET); + long end = lseek(fd, 0L, SEEK_END); + if (end > start) { + length = static_cast(end - start); + ptrMemMap = static_cast(mmap(NULL, length, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, start)); + ptr = ptrMemMap; + return true; + } else { + length = 0; + ptrMemMap = nullptr; + ptr = nullptr; + if (close(fd) != 0) { + FATAL(kLncFatal, "close error"); + } + return false; + } +} + +void BasicIOMapFile::Close() { + if (fd > 0) { + if (munmap(ptrMemMap, length) != 0) { + FATAL(kLncFatal, "munmap error"); + } + ptrMemMap = nullptr; + ptr = nullptr; + if (close(fd) != 0) { + FATAL(kLncFatal, "close error"); + } + } + fd = -1; +} + +std::unique_ptr BasicIOMapFile::GenFileInMemory(const std::string &name, const uint8 *buf, size_t len) { + std::unique_ptr file = std::make_unique(name); + file->ptr = buf; + file->length = len; + return file; +} + +BasicIORead::BasicIORead(BasicIOMapFile &f, bool bigEndian) : file(f), isBigEndian(bigEndian), pos(0) {} + +uint8 BasicIORead::ReadUInt8() { + const uint8 *p = GetSafeBuffer(BasicIOEndian::kLengthByte); + pos += BasicIOEndian::kLengthByte; + return p[0]; +} + +uint8 BasicIORead::ReadUInt8(bool &success) { + const uint8 *p = GetBuffer(BasicIOEndian::kLengthByte); + if (p == nullptr) { + success = false; + return 0; + } + pos += BasicIOEndian::kLengthByte; + success = true; + return p[0]; +} + +int8 BasicIORead::ReadInt8() { + return static_cast(ReadUInt8()); +} + +int8 BasicIORead::ReadInt8(bool &success) { + return static_cast(ReadUInt8(success)); +} + +char BasicIORead::ReadChar() { + return static_cast(ReadUInt8()); +} + +char BasicIORead::ReadChar(bool &success) { + return static_cast(ReadUInt8(success)); +} + +uint16 BasicIORead::ReadUInt16() { + const uint8 *p = GetSafeBuffer(BasicIOEndian::kLengthWord); + pos += BasicIOEndian::kLengthWord; + if (isBigEndian) { + return BasicIOEndian::GetUInt16BigEndian(p); + } else { + return BasicIOEndian::GetUInt16LittleEndian(p); + } +} + +uint16 BasicIORead::ReadUInt16(bool &success) { + const uint8 *p = GetBuffer(BasicIOEndian::kLengthWord); + if (p == nullptr) { + success = false; + return 0; + } + pos += BasicIOEndian::kLengthWord; + success = true; + if (isBigEndian) { + return BasicIOEndian::GetUInt16BigEndian(p); + } else { + return BasicIOEndian::GetUInt16LittleEndian(p); + } +} + +int16 BasicIORead::ReadInt16() { + return static_cast(ReadUInt16()); +} + +int16 BasicIORead::ReadInt16(bool &success) { + return static_cast(ReadUInt16(success)); +} + +uint32 BasicIORead::ReadUInt32() { + const uint8 *p = GetSafeBuffer(BasicIOEndian::kLengthDWord); + pos += BasicIOEndian::kLengthDWord; + if (isBigEndian) { + return BasicIOEndian::GetUInt32BigEndian(p); + } else { + return BasicIOEndian::GetUInt32LittleEndian(p); + } +} + +uint32 BasicIORead::ReadUInt32(bool &success) { + const uint8 *p = GetBuffer(BasicIOEndian::kLengthDWord); + if (p == nullptr) { + success = false; + return 0; + } + pos += BasicIOEndian::kLengthDWord; + success = true; + if (isBigEndian) { + return BasicIOEndian::GetUInt32BigEndian(p); + } else { + return BasicIOEndian::GetUInt32LittleEndian(p); + } +} + +int32 BasicIORead::ReadInt32() { + return static_cast(ReadUInt32()); +} + +int32 BasicIORead::ReadInt32(bool &success) { + return static_cast(ReadUInt32(success)); +} + +uint64 BasicIORead::ReadUInt64() { + const uint8 *p = GetSafeBuffer(BasicIOEndian::kLengthQWord); + pos += BasicIOEndian::kLengthQWord; + if (isBigEndian) { + return BasicIOEndian::GetUInt64BigEndian(p); + } else { + return BasicIOEndian::GetUInt64LittleEndian(p); + } +} + +uint64 BasicIORead::ReadUInt64(bool &success) { + const uint8 *p = GetBuffer(BasicIOEndian::kLengthQWord); + if (p == nullptr) { + success = false; + return 0; + } + pos += BasicIOEndian::kLengthQWord; + success = true; + if (isBigEndian) { + return BasicIOEndian::GetUInt64BigEndian(p); + } else { + return BasicIOEndian::GetUInt64LittleEndian(p); + } +} + +int64 BasicIORead::ReadInt64() { + return static_cast(ReadUInt64()); +} + +int64 BasicIORead::ReadInt64(bool &success) { + return static_cast(ReadUInt64(success)); +} + +float BasicIORead::ReadFloat() { + union { + uint32 iv; + float fv; + } v; + v.iv = ReadUInt32(); + return v.fv; +} + +float BasicIORead::ReadFloat(bool &success) { + union { + uint32 iv; + float fv; + } v; + v.iv = ReadUInt32(success); + return v.fv; +} + +double BasicIORead::ReadDouble() { + union { + uint64 lv; + double dv; + } v; + v.lv = ReadUInt64(); + return v.dv; +} + +double BasicIORead::ReadDouble(bool &success) { + union { + uint64 lv; + double dv; + } v; + v.lv = ReadUInt64(success); + return v.dv; +} + +void BasicIORead::ReadBufferUInt8(uint8 *dst, uint32 length) { + const uint8 *p = GetSafeBuffer(length); + pos += length; + errno_t err = memcpy_s(dst, length, p, length); + CHECK_FATAL(err == EOK, "memcpy_s failed"); +} + +void BasicIORead::ReadBufferUInt8(uint8 *dst, uint32 length, bool &success) { + const uint8 *p = GetBuffer(length); + if (p == nullptr) { + success = false; + return; + } + pos += length; + success = true; + errno_t err = memcpy_s(dst, length, p, length); + CHECK_FATAL(err == EOK, "memcpy_s failed"); +} + +void BasicIORead::ReadBufferInt8(int8 *dst, uint32 length) { + CHECK_NULL_FATAL(dst); + const uint8 *p = GetSafeBuffer(length); + pos += length; + errno_t err = memcpy_s(dst, length, p, length); + CHECK_FATAL(err == EOK, "memcpy_s failed"); +} + +void BasicIORead::ReadBufferInt8(int8 *dst, uint32 length, bool &success) { + CHECK_NULL_FATAL(dst); + const uint8 *p = GetBuffer(length); + if (p == nullptr) { + success = false; + return; + } + pos += length; + success = true; + errno_t err = memcpy_s(dst, length, p, length); + CHECK_FATAL(err == EOK, "memcpy_s failed"); +} + +void BasicIORead::ReadBufferChar(char *dst, uint32 length) { + const uint8 *p = GetSafeBuffer(length); + pos += length; + errno_t err = memcpy_s(dst, length, p, length); + CHECK_FATAL(err == EOK, "memcpy_s failed"); +} + +void BasicIORead::ReadBufferChar(char *dst, uint32 length, bool &success) { + const uint8 *p = GetBuffer(length); + if (p == nullptr) { + success = false; + return; + } + pos += length; + success = true; + errno_t err = memcpy_s(dst, length, p, length); + CHECK_FATAL(err == EOK, "memcpy_s failed"); +} + +std::string BasicIORead::ReadString(uint32 length) { + const void *p = GetSafeBuffer(length); + const char *pchar = static_cast(p); + pos += length; + return std::string(pchar, length); +} + +std::string BasicIORead::ReadString(uint32 length, bool &success) { + const void *p = GetBuffer(length); + const char *pchar = static_cast(p); + if (p == nullptr) { + success = false; + return ""; + } + pos += length; + success = true; + return std::string(pchar, length); +} +} // namespace maple diff --git a/src/hir2mpl/common/src/enhance_c_checker.cpp b/src/hir2mpl/common/src/enhance_c_checker.cpp new file mode 100755 index 0000000000000000000000000000000000000000..7ed04feb4a5e140c5a10acbee0cdd0c247893ef0 --- /dev/null +++ b/src/hir2mpl/common/src/enhance_c_checker.cpp @@ -0,0 +1,2193 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "enhance_c_checker.h" +#include "ast_parser.h" +#include "ast_expr.h" +#include "ast_stmt.h" +#include "ast_decl_builder.h" +#include "feir_builder.h" +#include "fe_manager.h" +#include "fe_macros.h" + +namespace maple { +void ASTParser::ProcessNonnullFuncPtrAttrs(const clang::ValueDecl &valueDecl, ASTDecl &astVar) { + const MIRFuncType *funcType = FEUtils::GetFuncPtrType(*astVar.GetTypeDesc().front()); + if (funcType == nullptr) { + return; + } + std::vector attrsVec = funcType->GetParamAttrsList(); + TypeAttrs retAttr = funcType->GetRetAttrs(); + // nonnull with args in function type pointers need marking nonnull arg + for (const auto *nonNull : valueDecl.specific_attrs()) { + if (!nonNull->args_size()) { + continue; + } + for (const clang::ParamIdx ¶mIdx : nonNull->args()) { + // The clang ensures that nonnull attribute only applies to pointer parameter + unsigned int idx = paramIdx.getASTIndex(); + if (idx >= attrsVec.size()) { + continue; + } + attrsVec[idx].SetAttr(ATTR_nonnull); + } + } + if (valueDecl.hasAttr()) { + retAttr.SetAttr(ATTR_nonnull); + } + MIRType *newFuncType = GlobalTables::GetTypeTable().GetOrCreateFunctionType( + funcType->GetRetTyIdx(), funcType->GetParamTypeList(), attrsVec, funcType->IsVarargs(), retAttr); + astVar.SetTypeDesc(std::vector{GlobalTables::GetTypeTable().GetOrCreatePointerType( + *GlobalTables::GetTypeTable().GetOrCreatePointerType(*newFuncType))}); +} + +bool ENCChecker::HasNonnullAttrInExpr(MIRBuilder &mirBuilder, const UniqueFEIRExpr &expr, bool isNested) { + if (expr->GetKind() == kExprDRead) { + if (isNested) { // skip multi-dimensional pointer + return true; + } + FEIRExprDRead *dread = static_cast(expr.get()); + MIRSymbol *symbol = dread->GetVar()->GenerateMIRSymbol(mirBuilder); + if (expr->GetFieldID() == 0) { + return symbol->GetAttr(ATTR_nonnull); + } else { + FieldID fieldID = expr->GetFieldID(); + CHECK_FATAL(symbol->GetType()->IsStructType(), "basetype must be StructType"); + FieldPair fieldPair = static_cast(symbol->GetType())->TraverseToFieldRef(fieldID); + return fieldPair.second.second.GetAttr(FLDATTR_nonnull); + } + } else if (expr->GetKind() == kExprIRead) { + FEIRExprIRead *iread = static_cast(expr.get()); + FieldID fieldID = expr->GetFieldID(); + if (fieldID == 0) { + return HasNonnullAttrInExpr(mirBuilder, iread->GetClonedOpnd(), true); + } + MIRType *pointerType = iread->GetClonedPtrType()->GenerateMIRTypeAuto(); + CHECK_FATAL(pointerType->IsMIRPtrType(), "Must be ptr type!"); + MIRType *baseType = static_cast(pointerType)->GetPointedType(); + CHECK_FATAL(baseType->IsStructType(), "basetype must be StructType"); + FieldPair fieldPair = static_cast(baseType)->TraverseToFieldRef(fieldID); + return fieldPair.second.second.GetAttr(FLDATTR_nonnull); + } else if (isNested && expr->GetKind() == kExprAddrofArray) { + return false; + } else { + return true; + } +} + +bool ENCChecker::HasNullExpr(const UniqueFEIRExpr &expr) { + if (expr == nullptr || expr->GetKind() != kExprUnary || expr->GetPrimType() != PTY_ptr) { + return false; + } + const UniqueFEIRExpr &cstExpr = static_cast(expr.get())->GetOpnd(); + return FEIRBuilder::IsZeroConstExpr(cstExpr); +} + +void ENCChecker::CheckNonnullGlobalVarInit(const MIRSymbol &sym, const MIRConst *cst) { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || !sym.GetAttr(ATTR_nonnull)) { + return; + } + if (cst == nullptr) { + FE_ERR(kLncErr, "%s:%d error: nonnull parameter is uninitialized when defined", + FEManager::GetModule().GetFileNameFromFileNum(sym.GetSrcPosition().FileNum()).c_str(), + sym.GetSrcPosition().LineNum()); + return; + } + if (cst->IsZero()) { + FE_ERR(kLncErr, "%s:%d error: null assignment of nonnull pointer", + FEManager::GetModule().GetFileNameFromFileNum(sym.GetSrcPosition().FileNum()).c_str(), + sym.GetSrcPosition().LineNum()); + return; + } +} + +void ENCChecker::CheckNullFieldInGlobalStruct(MIRType &type, MIRAggConst &cst, const std::vector &initExprs) { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || !ENCChecker::HasNonnullFieldInStruct(type)) { + return; + } + auto &structType = static_cast(type); + for (size_t i = 0; i < structType.GetFieldsSize(); ++i) { + if (!structType.GetFieldsElemt(i).second.second.GetAttr(FLDATTR_nonnull)) { + continue; + } + size_t idx = structType.GetKind() == kTypeUnion ? 0 : i; // union only is one element + if (idx < cst.GetConstVec().size() && cst.GetConstVecItem(idx) != nullptr && cst.GetConstVecItem(idx)->IsZero()) { + FE_ERR(kLncErr, "%s:%d error: null assignment of nonnull field pointer. [field name: %s]", + FEManager::GetModule().GetFileNameFromFileNum(initExprs[idx]->GetSrcFileIdx()).c_str(), + initExprs[idx]->GetSrcFileLineNum(), + GlobalTables::GetStrTable().GetStringFromStrIdx(structType.GetFieldsElemt(i).first).c_str()); + } + } +} + +void ENCChecker::CheckNonnullLocalVarInit(const MIRSymbol &sym, const ASTExpr *initExpr) { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || !sym.GetAttr(ATTR_nonnull)) { + return; + } + if (initExpr == nullptr) { + FE_ERR(kLncErr, "%s:%d error: nonnull parameter is uninitialized when defined", + FEManager::GetModule().GetFileNameFromFileNum(sym.GetSrcPosition().FileNum()).c_str(), + sym.GetSrcPosition().LineNum()); + return; + } +} + +void ENCChecker::CheckNonnullLocalVarInit(const MIRSymbol &sym, const UniqueFEIRExpr &initFEExpr, + std::list &stmts) { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || !sym.GetAttr(ATTR_nonnull)) { + return; + } + if (HasNullExpr(initFEExpr)) { + FE_ERR(kLncErr, "%s:%d error: null assignment of nonnull pointer", + FEManager::GetModule().GetFileNameFromFileNum(sym.GetSrcPosition().FileNum()).c_str(), + sym.GetSrcPosition().LineNum()); + return; + } + if (initFEExpr->GetPrimType() == PTY_ptr) { + UniqueFEIRStmt stmt = std::make_unique(OP_assignassertnonnull, initFEExpr->Clone()); + stmt->SetSrcFileInfo(sym.GetSrcPosition().FileNum(), sym.GetSrcPosition().LineNum()); + stmts.emplace_back(std::move(stmt)); + } +} + +std::string ENCChecker::GetNthStr(size_t index) { + switch (index) { + case 0: + return "1st"; + case 1: + return "2nd"; + case 2: + return "3rd"; + default: { + std::ostringstream oss; + oss << index + 1 << "th"; + return oss.str(); + } + } +} + +std::string ENCChecker::PrintParamIdx(const std::list &idxs) { + std::ostringstream os; + for (auto iter = idxs.begin(); iter != idxs.end(); ++iter) { + if (iter != idxs.begin()) { + os << ", "; + } + os << GetNthStr(*iter); + } + return os.str(); +} + +void ENCChecker::CheckNonnullArgsAndRetForFuncPtr(const MIRType &dstType, const UniqueFEIRExpr &srcExpr, + uint32 fileNum, uint32 fileLine) { + if (!FEOptions::GetInstance().IsNpeCheckDynamic()) { + return; + } + const MIRFuncType *funcType = FEUtils::GetFuncPtrType(dstType); + if (funcType == nullptr) { + return; + } + if (srcExpr->GetKind() == kExprAddrofFunc) { // check func ptr l-value and &func decl r-value + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + static_cast(srcExpr.get())->GetFuncAddr()); + MIRFunction *srcFunc = FEManager::GetTypeManager().GetMIRFunction(strIdx, false); + CHECK_FATAL(srcFunc != nullptr, "can not get MIRFunction"); + std::list errIdxs; + for (size_t i = 0; i < srcFunc->GetParamSize() && i < funcType->GetParamAttrsList().size(); ++i) { + if (srcFunc->GetNthParamAttr(i).GetAttr(ATTR_nonnull) != funcType->GetNthParamAttrs(i).GetAttr(ATTR_nonnull)) { + errIdxs.emplace_back(i); + } + } + if (!errIdxs.empty()) { + FE_ERR(kLncErr, "%s:%d error: function pointer and target function's nonnull attributes are mismatched " + "for the %s argument", FEManager::GetModule().GetFileNameFromFileNum(fileNum).c_str(), fileLine, + PrintParamIdx(errIdxs).c_str()); + } + if (srcFunc->GetFuncAttrs().GetAttr(FUNCATTR_nonnull) != funcType->GetRetAttrs().GetAttr(ATTR_nonnull)) { + FE_ERR(kLncErr, "%s:%d error: function pointer and target function's nonnull attributes are mismatched for" + " the return value", FEManager::GetModule().GetFileNameFromFileNum(fileNum).c_str(), fileLine); + } + } + const MIRFuncType *srcFuncType = FEUtils::GetFuncPtrType(*srcExpr->GetType()->GenerateMIRTypeAuto()); + if (srcFuncType != nullptr) { // check func ptr l-value and func ptr r-value + std::list errIdxs; + for (size_t i = 0; i < srcFuncType->GetParamAttrsList().size() && i < funcType->GetParamAttrsList().size(); ++i) { + if (srcFuncType->GetNthParamAttrs(i).GetAttr(ATTR_nonnull) != + funcType->GetNthParamAttrs(i).GetAttr(ATTR_nonnull)) { + errIdxs.emplace_back(i); + } + } + if (!errIdxs.empty()) { + FE_ERR(kLncErr, "%s:%d error: function pointer's nonnull attributes are mismatched for the %s argument", + FEManager::GetModule().GetFileNameFromFileNum(fileNum).c_str(), fileLine, PrintParamIdx(errIdxs).c_str()); + } + if (srcFuncType->GetRetAttrs().GetAttr(ATTR_nonnull) != funcType->GetRetAttrs().GetAttr(ATTR_nonnull)) { + FE_ERR(kLncErr, "%s:%d error: function pointer's nonnull attributes are mismatched for the return value", + FEManager::GetModule().GetFileNameFromFileNum(fileNum).c_str(), fileLine); + } + } +} + +void FEIRStmtDAssign::CheckNonnullArgsAndRetForFuncPtr(const MIRBuilder &mirBuilder) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || ENCChecker::IsUnsafeRegion(mirBuilder)) { + return; + } + MIRType *baseType = var->GetType()->GenerateMIRTypeAuto(); + if (fieldID != 0) { + baseType = FEUtils::GetStructFieldType(static_cast(baseType), fieldID); + } + ENCChecker::CheckNonnullArgsAndRetForFuncPtr(*baseType, expr, srcFileIndex, srcFileLineNum); +} + +void FEIRStmtIAssign::CheckNonnullArgsAndRetForFuncPtr(const MIRBuilder &mirBuilder, const MIRType &baseType) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || ENCChecker::IsUnsafeRegion(mirBuilder)) { + return; + } + MIRType *fieldType = FEUtils::GetStructFieldType(static_cast(&baseType), fieldID); + ENCChecker::CheckNonnullArgsAndRetForFuncPtr(*fieldType, baseExpr, srcFileIndex, srcFileLineNum); +} + +bool ENCChecker::HasNonnullFieldInStruct(const MIRType &mirType) { + if (mirType.IsStructType() && FEManager::GetTypeManager().IsOwnedNonnullFieldStructSet(mirType.GetTypeIndex())) { + return true; + } + return false; +} + +bool ENCChecker::HasNonnullFieldInPtrStruct(const MIRType &mirType) { + if (mirType.IsMIRPtrType()) { + MIRType *structType = static_cast(mirType).GetPointedType(); + if (structType != nullptr && HasNonnullFieldInStruct(*structType)) { + return true; + } + } + return false; +} + +void ASTCallExpr::CheckNonnullFieldInStruct() const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic()) { + return; + } + std::list nullStmts; + UniqueFEIRExpr baseExpr = nullptr; + if (funcName == "bzero" && args.size() == 2) { + baseExpr = args[0]->Emit2FEExpr(nullStmts); + } else if (funcName == "memset" && args.size() == 3 && + FEIRBuilder::IsZeroConstExpr(args[1]->Emit2FEExpr(nullStmts))) { + baseExpr = args[0]->Emit2FEExpr(nullStmts); + } + if (baseExpr != nullptr && (baseExpr->GetKind() == kExprDRead || baseExpr->GetKind() == kExprIRead) && + baseExpr->GetType() != nullptr) { + MIRType *mirType = baseExpr->GetType()->GenerateMIRTypeAuto(); + if (ENCChecker::HasNonnullFieldInPtrStruct(*mirType)) { + FE_ERR(kLncErr, "%s:%d error: null assignment of nonnull structure field pointer in %s", + FEManager::GetModule().GetFileNameFromFileNum(srcFileIdx).c_str(), srcFileLineNum, funcName.c_str()); + } + } +} + +void ASTCastExpr::CheckNonnullFieldInStruct() const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || dst->GetTypeIndex() == src->GetTypeIndex()) { + return; + } + if (ENCChecker::HasNonnullFieldInPtrStruct(*dst)) { + FE_ERR(kLncErr, "%s:%d error: null assignment risk of nonnull field pointer", + FEManager::GetModule().GetFileNameFromFileNum(srcFileIdx).c_str(), srcFileLineNum); + } +} + +// --------------------------- +// process boundary attr +// --------------------------- +void ASTParser::ProcessBoundaryFuncAttrs(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, + ASTFunc &astFunc) { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic()) { + return; + } + for (const auto *returnsCountAttr : funcDecl.specific_attrs()) { + clang::Expr *expr = returnsCountAttr->getLenExpr(); + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (lenExpr == nullptr) { + continue; + } + ProcessBoundaryLenExprInFunc(allocator, funcDecl, static_cast(-1), astFunc, lenExpr, true); + } + for (const auto *countAttr : funcDecl.specific_attrs()) { + clang::Expr *expr = countAttr->getLenExpr(); + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (lenExpr == nullptr) { + continue; + } + if (!countAttr->index_size()) { + // Lack of attribute index parameters means that only one pointer parameter is + // implicitly marked as boundary var in func. + for (unsigned int i = 0; i < astFunc.GetParamDecls().size(); ++i) { + if (astFunc.GetParamDecls()[i]->GetTypeDesc().front()->IsMIRPtrType()) { + ProcessBoundaryLenExprInFunc(allocator, funcDecl, i, astFunc, lenExpr, true); + } + } + break; + } + for (const clang::ParamIdx ¶mIdx : countAttr->index()) { + // The clang ensures that the attribute only applies to pointer parameter + unsigned int idx = paramIdx.getASTIndex(); + if (idx >= astFunc.GetParamDecls().size()) { + continue; + } + ProcessBoundaryLenExprInFunc(allocator, funcDecl, idx, astFunc, lenExpr, true); + } + } + ProcessByteBoundaryFuncAttrs(allocator, funcDecl, astFunc); + ProcessBoundaryFuncAttrsByIndex(allocator, funcDecl, astFunc); +} + +void ASTParser::ProcessByteBoundaryFuncAttrs(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, + ASTFunc &astFunc) { + for (const auto *returnsCountAttr : funcDecl.specific_attrs()) { + clang::Expr *expr = returnsCountAttr->getLenExpr(); + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (lenExpr == nullptr) { + continue; + } + ProcessBoundaryLenExprInFunc(allocator, funcDecl, static_cast(-1), astFunc, lenExpr, false); + } + for (const auto *countAttr : funcDecl.specific_attrs()) { + clang::Expr *expr = countAttr->getLenExpr(); + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (lenExpr == nullptr) { + continue; + } + if (!countAttr->index_size()) { + // Lack of attribute index parameters means that only one pointer parameter is + // implicitly marked as boundary var in func. + for (unsigned int i = 0; i < astFunc.GetParamDecls().size(); ++i) { + if (astFunc.GetParamDecls()[i]->GetTypeDesc().front()->IsMIRPtrType()) { + ProcessBoundaryLenExprInFunc(allocator, funcDecl, i, astFunc, lenExpr, false); + } + } + break; + } + for (const clang::ParamIdx ¶mIdx : countAttr->index()) { + // The clang ensures that the attribute only applies to pointer parameter + unsigned int idx = paramIdx.getASTIndex(); + if (idx >= astFunc.GetParamDecls().size()) { + continue; + } + ProcessBoundaryLenExprInFunc(allocator, funcDecl, idx, astFunc, lenExpr, false); + } + } +} + +void ASTParser::ProcessBoundaryFuncAttrsByIndex(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, + ASTFunc &astFunc) { + for (const auto *countIndexAttr : funcDecl.specific_attrs()) { + unsigned int lenIdx = countIndexAttr->getLenVarIndex().getASTIndex(); + for (const clang::ParamIdx ¶mIdx : countIndexAttr->index()) { + unsigned int idx = paramIdx.getASTIndex(); + if (idx >= astFunc.GetParamDecls().size()) { + continue; + } + ProcessBoundaryLenExprInFunc(allocator, funcDecl, idx, astFunc, lenIdx, true); + } + } + for (const auto *returnsCountIndexAttr : funcDecl.specific_attrs()) { + unsigned int retLenIdx = returnsCountIndexAttr->getLenVarIndex().getASTIndex(); + ProcessBoundaryLenExprInFunc(allocator, funcDecl, static_cast(-1), astFunc, retLenIdx, true); + } + for (const auto *byteCountIndexAttr : funcDecl.specific_attrs()) { + unsigned int lenIdx = byteCountIndexAttr->getLenVarIndex().getASTIndex(); + for (const clang::ParamIdx ¶mIdx : byteCountIndexAttr->index()) { + unsigned int idx = paramIdx.getASTIndex(); + if (idx >= astFunc.GetParamDecls().size()) { + continue; + } + ProcessBoundaryLenExprInFunc(allocator, funcDecl, idx, astFunc, lenIdx, false); + } + } + for (const auto *returnsByteCountIndexAttr : funcDecl.specific_attrs()) { + unsigned int retLenIdx = returnsByteCountIndexAttr->getLenVarIndex().getASTIndex(); + ProcessBoundaryLenExprInFunc(allocator, funcDecl, static_cast(-1), astFunc, retLenIdx, false); + } +} + +void ASTParser::ProcessBoundaryParamAttrs(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, + ASTFunc &astFunc) { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic()) { + return; + } + for (unsigned int i = 0; i < funcDecl.getNumParams(); ++i) { + const clang::ParmVarDecl *parmDecl = funcDecl.getParamDecl(i); + if (parmDecl->getKind() == clang::Decl::Function) { + continue; + } + for (const auto *countAttr : parmDecl->specific_attrs()) { + clang::Expr *expr = countAttr->getLenExpr(); + if (countAttr->index_size()) { + continue; // boundary attrs with index args are only marked function pointers + } + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (lenExpr == nullptr) { + continue; + } + ProcessBoundaryLenExprInFunc(allocator, funcDecl, i, astFunc, lenExpr, true); + } + for (const auto *byteCountAttr : parmDecl->specific_attrs()) { + clang::Expr *expr = byteCountAttr->getLenExpr(); + if (byteCountAttr->index_size()) { + continue; // boundary attrs with index args are only marked function pointers + } + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (lenExpr == nullptr) { + continue; + } + ProcessBoundaryLenExprInFunc(allocator, funcDecl, i, astFunc, lenExpr, false); + } + } + ProcessBoundaryParamAttrsByIndex(allocator, funcDecl, astFunc); +} + +void ASTParser::ProcessBoundaryParamAttrsByIndex(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, + ASTFunc &astFunc) { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic()) { + return; + } + for (unsigned int i = 0; i < funcDecl.getNumParams(); ++i) { + const clang::ParmVarDecl *parmDecl = funcDecl.getParamDecl(i); + for (const auto *countIndexAttr : parmDecl->specific_attrs()) { + if (countIndexAttr->index_size()) { + continue; // boundary attrs with index args are only marked function pointers + } + unsigned int lenIdx = countIndexAttr->getLenVarIndex().getASTIndex(); + ProcessBoundaryLenExprInFunc(allocator, funcDecl, i, astFunc, lenIdx, true); + } + for (const auto *byteCountIndexAttr : parmDecl->specific_attrs()) { + if (byteCountIndexAttr->index_size()) { + continue; // boundary attrs with index args are only marked function pointers + } + unsigned int lenIdx = byteCountIndexAttr->getLenVarIndex().getASTIndex(); + ProcessBoundaryLenExprInFunc(allocator, funcDecl, i, astFunc, lenIdx, false); + } + } +} + +void ASTParser::ProcessBoundaryVarAttrs(MapleAllocator &allocator, const clang::VarDecl &varDecl, ASTVar &astVar) { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic()) { + return; + } + for (const auto *countAttr : varDecl.specific_attrs()) { + clang::Expr *expr = countAttr->getLenExpr(); + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (lenExpr == nullptr) { + continue; + } + if (countAttr->index_size()) { + continue; // boundary attrs with index args are only marked function pointers + } + ProcessBoundaryLenExprInVar(allocator, astVar, varDecl, lenExpr, true); + } + for (const auto *byteCountAttr : varDecl.specific_attrs()) { + clang::Expr *expr = byteCountAttr->getLenExpr(); + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (lenExpr == nullptr) { + continue; + } + if (byteCountAttr->index_size()) { + continue; // boundary attrs with index args are only marked function pointers + } + ProcessBoundaryLenExprInVar(allocator, astVar, varDecl, lenExpr, false); + } +} + +void ASTParser::ProcessBoundaryFuncPtrAttrs(MapleAllocator &allocator, const clang::ValueDecl &valueDecl, + ASTDecl &astDecl) { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic()) { + return; + } + const MIRFuncType *funcType = FEUtils::GetFuncPtrType(*astDecl.GetTypeDesc().front()); + if (funcType == nullptr || !valueDecl.getType()->isFunctionPointerType()) { + return; + } + clang::QualType qualType = valueDecl.getType()->getPointeeType(); + const clang::FunctionType *clangFuncType = qualType->getAs(); + if (clangFuncType == nullptr) { + return; + } + const clang::FunctionProtoType *proto = llvm::dyn_cast(clangFuncType); + if (proto == nullptr) { + return; + } + std::vector attrsVec = funcType->GetParamAttrsList(); + TypeAttrs retAttr = funcType->GetRetAttrs(); + bool isUpdated = false; + for (const auto *countAttr : valueDecl.specific_attrs()) { + if (ProcessBoundaryFuncPtrAttrsForParams(countAttr, allocator, *funcType, *proto, attrsVec)) { + isUpdated = true; + } + } + for (const auto *byteCountAttr : valueDecl.specific_attrs()) { + if (ProcessBoundaryFuncPtrAttrsForParams(byteCountAttr, allocator, *funcType, *proto, attrsVec)) { + isUpdated = true; + } + } + for (const auto *returnsCountAttr : valueDecl.specific_attrs()) { + if (ProcessBoundaryFuncPtrAttrsForRet(returnsCountAttr, allocator, *funcType, *clangFuncType, retAttr)) { + isUpdated = true; + } + } + for (const auto *returnsByteCountAttr : valueDecl.specific_attrs()) { + if (ProcessBoundaryFuncPtrAttrsForRet(returnsByteCountAttr, allocator, *funcType, *clangFuncType, retAttr)) { + isUpdated = true; + } + } + if (isUpdated) { + MIRType *newFuncType = GlobalTables::GetTypeTable().GetOrCreateFunctionType( + funcType->GetRetTyIdx(), funcType->GetParamTypeList(), attrsVec, funcType->IsVarargs(), retAttr); + astDecl.SetTypeDesc(std::vector{GlobalTables::GetTypeTable().GetOrCreatePointerType( + *GlobalTables::GetTypeTable().GetOrCreatePointerType(*newFuncType))}); + } + ProcessBoundaryFuncPtrAttrsByIndex(valueDecl, astDecl, *funcType); +} + +template +bool ASTParser::ProcessBoundaryFuncPtrAttrsForParams(T *attr, MapleAllocator &allocator, const MIRFuncType &funcType, + const clang::FunctionProtoType &proto, + std::vector &attrsVec) { + bool isUpdated = false; + clang::Expr *expr = attr->getLenExpr(); + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (!attr->index_size() || lenExpr == nullptr) { + return isUpdated; + } + std::vector typesVec = funcType.GetParamTypeList(); + for (const clang::ParamIdx ¶mIdx : attr->index()) { + unsigned int idx = paramIdx.getASTIndex(); + if (idx >= attrsVec.size() || idx >= typesVec.size()) { + continue; + } + MIRType *ptrType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(typesVec[idx]); + ASTVar *tmpDecl = ASTDeclsBuilder::ASTVarBuilder( + allocator, "", "tmpVar", std::vector{ptrType}, GenericAttrs()); + bool isByte = std::is_same::type, clang::ByteCountAttr>::value; + ProcessBoundaryLenExprInVar(allocator, *tmpDecl, proto.getParamType(idx), lenExpr, !isByte); + ENCChecker::InsertBoundaryInAtts(attrsVec[idx], tmpDecl->GetBoundaryInfo()); + isUpdated = true; + } + return isUpdated; +} + +template +bool ASTParser::ProcessBoundaryFuncPtrAttrsForRet(T *attr, MapleAllocator &allocator, const MIRFuncType &funcType, + const clang::FunctionType &clangFuncType, TypeAttrs &retAttr) { + clang::Expr *expr = attr->getLenExpr(); + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (lenExpr == nullptr) { + return false; + } + MIRType *ptrType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(funcType.GetRetTyIdx()); + ASTVar *tmpRetDecl = ASTDeclsBuilder::ASTVarBuilder( + allocator, "", "tmpRetVar", std::vector{ptrType}, GenericAttrs()); + bool isByte = std::is_same::type, clang::ReturnsByteCountAttr>::value; + ProcessBoundaryLenExprInVar(allocator, *tmpRetDecl, clangFuncType.getReturnType(), lenExpr, !isByte); + ENCChecker::InsertBoundaryInAtts(retAttr, tmpRetDecl->GetBoundaryInfo()); + return true; +} + +void ASTParser::ProcessBoundaryFuncPtrAttrsByIndex(const clang::ValueDecl &valueDecl, ASTDecl &astDecl, + const MIRFuncType &funcType) { + std::vector attrsVec = funcType.GetParamAttrsList(); + TypeAttrs retAttr = funcType.GetRetAttrs(); + bool isUpdated = false; + for (const auto *countAttr : valueDecl.specific_attrs()) { + if (ProcessBoundaryFuncPtrAttrsByIndexForParams(countAttr, astDecl, funcType, attrsVec)) { + isUpdated = true; + } + } + for (const auto *byteCountAttr : valueDecl.specific_attrs()) { + if (ProcessBoundaryFuncPtrAttrsByIndexForParams(byteCountAttr, astDecl, funcType, attrsVec)) { + isUpdated = true; + } + } + for (const auto *returnsCountIndexAttr : valueDecl.specific_attrs()) { + unsigned int lenIdx = returnsCountIndexAttr->getLenVarIndex().getASTIndex(); + retAttr.GetAttrBoundary().SetLenParamIdx(static_cast(lenIdx)); + isUpdated = true; + } + for (const auto *returnsByteCountIndexAttr : valueDecl.specific_attrs()) { + unsigned int lenIdx = returnsByteCountIndexAttr->getLenVarIndex().getASTIndex(); + retAttr.GetAttrBoundary().SetLenParamIdx(static_cast(lenIdx)); + retAttr.GetAttrBoundary().SetIsBytedLen(true); + isUpdated = true; + } + if (isUpdated) { + MIRType *newFuncType = GlobalTables::GetTypeTable().GetOrCreateFunctionType( + funcType.GetRetTyIdx(), funcType.GetParamTypeList(), attrsVec, funcType.IsVarargs(), retAttr); + astDecl.SetTypeDesc(std::vector{GlobalTables::GetTypeTable().GetOrCreatePointerType( + *GlobalTables::GetTypeTable().GetOrCreatePointerType(*newFuncType))}); + } +} + +template +bool ASTParser::ProcessBoundaryFuncPtrAttrsByIndexForParams(T *attr, ASTDecl &astDecl, const MIRFuncType &funcType, + std::vector &attrsVec) { + bool isUpdated = false; + std::vector typesVec = funcType.GetParamTypeList(); + unsigned int lenIdx = attr->getLenVarIndex().getASTIndex(); + if (!attr->index_size() || lenIdx >= typesVec.size()) { + return isUpdated; + } + MIRType *lenType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(typesVec[lenIdx]); + if (lenType == nullptr || !FEUtils::IsInteger(lenType->GetPrimType())) { + FE_ERR(kLncErr, "%s:%d error: The boundary length var by the %s argument is not an integer type", + FEManager::GetModule().GetFileNameFromFileNum(astDecl.GetSrcFileIdx()).c_str(), + astDecl.GetSrcFileLineNum(), ENCChecker::GetNthStr(lenIdx).c_str()); + return isUpdated; + } + for (const clang::ParamIdx ¶mIdx : attr->index()) { + unsigned int idx = paramIdx.getASTIndex(); + if (idx >= attrsVec.size() || idx >= typesVec.size()) { + continue; + } + attrsVec[idx].GetAttrBoundary().SetLenParamIdx(static_cast(lenIdx)); + if (std::is_same::type, clang::ByteCountIndexAttr>::value) { + attrsVec[idx].GetAttrBoundary().SetIsBytedLen(true); + } + isUpdated = true; + } + return isUpdated; +} + +void ASTParser::ProcessBoundaryFieldAttrs(MapleAllocator &allocator, const ASTStruct &structDecl, + const clang::RecordDecl &recDecl) { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic()) { + return; + } + const auto *declContext = llvm::dyn_cast(&recDecl); + if (declContext == nullptr) { + return; + } + for (auto *loadDecl : declContext->decls()) { + if (loadDecl == nullptr) { + continue; + } + auto *fieldDecl = llvm::dyn_cast(loadDecl); + if (fieldDecl == nullptr) { + continue; + } + ASTDecl *astField = ASTDeclsBuilder::GetASTDecl(fieldDecl->getID()); + if (astField == nullptr) { + continue; + } + for (const auto *countAttr : fieldDecl->specific_attrs()) { + clang::Expr *expr = countAttr->getLenExpr(); + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (lenExpr == nullptr) { + continue; + } + if (!countAttr->index_size()) { + ProcessBoundaryLenExprInField(allocator, *astField, structDecl, fieldDecl->getType(), lenExpr, true); + } + } + for (const auto *byteCountAttr : fieldDecl->specific_attrs()) { + clang::Expr *expr = byteCountAttr->getLenExpr(); + ASTExpr *lenExpr = ProcessExpr(allocator, expr); + if (lenExpr == nullptr) { + continue; + } + if (!byteCountAttr->index_size()) { + ProcessBoundaryLenExprInField(allocator, *astField, structDecl, fieldDecl->getType(), lenExpr, false); + } + } + } +} + +// --------------------------- +// process boundary length expr in attr +// --------------------------- +void ASTParser::ProcessBoundaryLenExpr(MapleAllocator &allocator, ASTDecl &ptrDecl, const clang::QualType &qualType, + const std::function &getLenExprFromStringLiteral, + ASTExpr *lenExpr, bool isSize) { + if (!qualType->isPointerType()) { + FE_ERR(kLncErr, "%s:%d error: The variable modified by the boundary attribute should be a pointer type", + FEManager::GetModule().GetFileNameFromFileNum(lenExpr->GetSrcFileIdx()).c_str(), + lenExpr->GetSrcFileLineNum()); + return; + } + // Check lenExpr kind from: length stringLiteral or constant value/var expression + if (lenExpr->GetASTOp() == kASTStringLiteral) { + // boundary length stringLiteral -> real length decl expr + lenExpr = getLenExprFromStringLiteral(); + if (lenExpr == nullptr) { + return; + } + } else if (lenExpr->GetType() == nullptr || !FEUtils::IsInteger(lenExpr->GetType()->GetPrimType())) { + FE_ERR(kLncErr, "%s:%d error: The boundary length expr is not an integer type", + FEManager::GetModule().GetFileNameFromFileNum(lenExpr->GetSrcFileIdx()).c_str(), + lenExpr->GetSrcFileLineNum()); + return; + } + if (isSize) { + // The type size can only be obtained from ClangDecl instead of ASTDecl, + // because the field of mir struct type has not yet been initialized at this time + uint32 lenSize = GetSizeFromQualType(qualType->getPointeeType()); + MIRType *pointedType = static_cast(ptrDecl.GetTypeDesc().front())->GetPointedType(); + if (pointedType->GetPrimType() == PTY_f64) { + lenSize = 8; // 8 is f64 byte num, because now f128 also cvt to f64 + } + lenExpr = GetAddrShiftExpr(allocator, lenExpr, lenSize); + } + ptrDecl.SetBoundaryLenExpr(lenExpr); + ptrDecl.SetIsBytedLen(!isSize); +} + +void ASTParser::ProcessBoundaryLenExprInFunc(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, + unsigned int idx, ASTFunc &astFunc, ASTExpr *lenExpr, bool isSize) { + ASTDecl *ptrDecl = nullptr; + clang::QualType qualType; + if (idx == static_cast(-1)) { // return boundary attr + ptrDecl = &astFunc; + qualType = funcDecl.getReturnType(); + } else if (idx < astFunc.GetParamDecls().size()) { + ptrDecl = astFunc.GetParamDecls()[idx]; + qualType = funcDecl.getParamDecl(idx)->getType(); + } else { + FE_ERR(kLncErr, "%s:%d error: The parameter annotated boundary attr [the %s argument] is not found" + "in the function [%s]", FEManager::GetModule().GetFileNameFromFileNum(lenExpr->GetSrcFileIdx()).c_str(), + lenExpr->GetSrcFileLineNum(), ENCChecker::GetNthStr(idx).c_str(), astFunc.GetName().c_str()); + return; + } + // parameter stringLiteral -> real parameter decl + auto getLenExprFromStringLiteral = [&]() -> ASTExpr* { + ASTStringLiteral *strExpr = static_cast(lenExpr); + std::string lenName(strExpr->GetCodeUnits().begin(), strExpr->GetCodeUnits().end()); + for (size_t i = 0; i < astFunc.GetParamDecls().size(); ++i) { + if (astFunc.GetParamDecls()[i]->GetName() != lenName) { + continue; + } + MIRType *lenType = astFunc.GetParamDecls()[i]->GetTypeDesc().front(); + if (lenType == nullptr || !FEUtils::IsInteger(lenType->GetPrimType())) { + FE_ERR(kLncErr, "%s:%d error: The parameter [%s] specified as boundary length var is not an integer type " + "in the function [%s]", FEManager::GetModule().GetFileNameFromFileNum(lenExpr->GetSrcFileIdx()).c_str(), + lenExpr->GetSrcFileLineNum(), lenName.c_str(), astFunc.GetName().c_str()); + return nullptr; + } + ASTDeclRefExpr *lenRefExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + lenRefExpr->SetASTDecl(astFunc.GetParamDecls()[i]); + lenRefExpr->SetType(astFunc.GetParamDecls()[i]->GetTypeDesc().front()); + ptrDecl->SetBoundaryLenParamIdx(static_cast(i)); + return lenRefExpr; + } + FE_ERR(kLncErr, "%s:%d error: The parameter [%s] specified as boundary length var is not found " + "in the function [%s]", FEManager::GetModule().GetFileNameFromFileNum(lenExpr->GetSrcFileIdx()).c_str(), + lenExpr->GetSrcFileLineNum(), lenName.c_str(), astFunc.GetName().c_str()); + return nullptr; + }; + ProcessBoundaryLenExpr(allocator, *ptrDecl, qualType, getLenExprFromStringLiteral, lenExpr, isSize); +} + +void ASTParser::ProcessBoundaryLenExprInFunc(MapleAllocator &allocator, const clang::FunctionDecl &funcDecl, + unsigned int idx, ASTFunc &astFunc, unsigned int lenIdx, bool isSize) { + if (lenIdx > astFunc.GetParamDecls().size()) { + FE_ERR(kLncErr, "error: The %s parameter specified as boundary length var is not found " + "in the function [%s]", ENCChecker::GetNthStr(lenIdx).c_str(), astFunc.GetName().c_str()); + return; + } + ASTDecl *lenDecl = astFunc.GetParamDecls()[lenIdx]; + MIRType *lenType = lenDecl->GetTypeDesc().front(); + if (lenType == nullptr || !FEUtils::IsInteger(lenType->GetPrimType())) { + FE_ERR(kLncErr, "error: The %s parameter specified as boundary length var is not an integer type " + "in the function [%s]", ENCChecker::GetNthStr(lenIdx).c_str(), astFunc.GetName().c_str()); + return; + } + ASTDeclRefExpr *lenRefExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + lenRefExpr->SetASTDecl(lenDecl); + lenRefExpr->SetType(lenType); + + ASTDecl *ptrDecl = nullptr; + if (idx == static_cast(-1)) { // return boundary attr + ptrDecl = &astFunc; + } else if (idx < astFunc.GetParamDecls().size()) { + ptrDecl = astFunc.GetParamDecls()[idx]; + } else { + FE_ERR(kLncErr, "error: The %s parameter annotated boundary attr is not found in the function [%s]", + ENCChecker::GetNthStr(idx).c_str(), astFunc.GetName().c_str()); + return; + } + ptrDecl->SetBoundaryLenParamIdx(static_cast(lenIdx)); + ProcessBoundaryLenExprInFunc(allocator, funcDecl, idx, astFunc, lenRefExpr, isSize); +} + +void ASTParser::ProcessBoundaryLenExprInVar(MapleAllocator &allocator, ASTDecl &ptrDecl, + const clang::VarDecl &varDecl, ASTExpr *lenExpr, bool isSize) { + if (!varDecl.isLocalVarDeclOrParm()) { + ASTDecl *lenDecl = lenExpr->GetASTDecl(); + if (lenDecl != nullptr && FEUtils::IsInteger(lenDecl->GetTypeDesc().front()->GetPrimType())) { + lenDecl->SetAttr(GENATTR_final_boundary_size); + } + } + ProcessBoundaryLenExprInVar(allocator, ptrDecl, varDecl.getType(), lenExpr, isSize); +} + +void ASTParser::ProcessBoundaryLenExprInVar(MapleAllocator &allocator, ASTDecl &ptrDecl, + const clang::QualType &qualType, ASTExpr *lenExpr, bool isSize) { + // The StringLiteral is not allowed to use as boundary length of var + auto getLenExprFromStringLiteral = [&]() -> ASTExpr* { + FE_ERR(kLncErr, "%s:%d error: The StringLiteral is not allowed to use as boundary length of var", + FEManager::GetModule().GetFileNameFromFileNum(lenExpr->GetSrcFileIdx()).c_str(), + lenExpr->GetSrcFileLineNum()); + return nullptr; + }; + ProcessBoundaryLenExpr(allocator, ptrDecl, qualType, getLenExprFromStringLiteral, lenExpr, isSize); +} + +void ASTParser::ProcessBoundaryLenExprInField(MapleAllocator &allocator, ASTDecl &ptrDecl, const ASTStruct &structDecl, + const clang::QualType &qualType, ASTExpr *lenExpr, bool isSize) { + // boundary length stringLiteral in field -> real field decl + auto getLenExprFromStringLiteral = [&]() -> ASTExpr* { + ASTStringLiteral *strExpr = static_cast(lenExpr); + std::string lenName(strExpr->GetCodeUnits().begin(), strExpr->GetCodeUnits().end()); + for (ASTField *fieldDecl: structDecl.GetFields()) { + if (lenName != fieldDecl->GetName()) { + continue; + } + MIRType *lenType = fieldDecl->GetTypeDesc().front(); + if (lenType == nullptr || !FEUtils::IsInteger(lenType->GetPrimType())) { + FE_ERR(kLncErr, "%s:%d error: The field [%s] specified as boundary length var is not an integer type " + "in the struct [%s]", FEManager::GetModule().GetFileNameFromFileNum(lenExpr->GetSrcFileIdx()).c_str(), + lenExpr->GetSrcFileLineNum(), lenName.c_str(), structDecl.GetName().c_str()); + return nullptr; + } + fieldDecl->SetAttr(GENATTR_final_boundary_size); + ASTDeclRefExpr *lenRefExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + lenRefExpr->SetASTDecl(fieldDecl); + lenRefExpr->SetType(fieldDecl->GetTypeDesc().front()); + return lenRefExpr; + } + FE_ERR(kLncErr, "%s:%d error: The StringLiteral [%s] as boundary length var is not found " + "in the struct [%s]", FEManager::GetModule().GetFileNameFromFileNum(lenExpr->GetSrcFileIdx()).c_str(), + lenExpr->GetSrcFileLineNum(), lenName.c_str(), structDecl.GetName().c_str()); + return nullptr; + }; + ProcessBoundaryLenExpr(allocator, ptrDecl, qualType, getLenExprFromStringLiteral, lenExpr, isSize); +} + +// --------------------------- +// process boundary var +// --------------------------- +UniqueFEIRExpr ENCChecker::FindBaseExprInPointerOperation(const UniqueFEIRExpr &expr, bool isIncludingAddrof) { + if (expr == nullptr) { + return nullptr; + } + UniqueFEIRExpr baseExpr = nullptr; + if (expr->GetKind() == kExprBinary) { + FEIRExprBinary *binExpr = static_cast(expr.get()); + if (binExpr->IsComparative()) { + return nullptr; + } + baseExpr = FindBaseExprInPointerOperation(binExpr->GetOpnd0()); + if (baseExpr != nullptr) { + return baseExpr; + } + baseExpr = FindBaseExprInPointerOperation(binExpr->GetOpnd1()); + if (baseExpr != nullptr) { + return baseExpr; + } + } + if (expr->GetKind() == kExprUnary) { + FEIRExprUnary *cvtExpr = static_cast(expr.get()); + baseExpr = FindBaseExprInPointerOperation(cvtExpr->GetOpnd()); + } else if (expr->GetKind() == kExprAddrofArray) { + FEIRExprAddrofArray *arrExpr = static_cast(expr.get()); + baseExpr = FindBaseExprInPointerOperation(arrExpr->GetExprArray()); + } else if ((expr->GetKind() == kExprDRead && expr->GetPrimType() == PTY_ptr) || + (expr->GetKind() == kExprIRead && expr->GetPrimType() == PTY_ptr && expr->GetFieldID() != 0) || + GetArrayTypeFromExpr(expr) != nullptr) { + baseExpr = expr->Clone(); + } else if (isIncludingAddrof && GetTypeFromAddrExpr(expr) != nullptr) { // addrof as 1-sized array + baseExpr = expr->Clone(); + } + return baseExpr; +} + +MIRType *ENCChecker::GetTypeFromAddrExpr(const UniqueFEIRExpr &expr) { + if (expr->GetKind() == kExprAddrofVar) { + MIRType *type = expr->GetVarUses().front()->GetType()->GenerateMIRTypeAuto(); + if (expr->GetFieldID() == 0) { + return type; + } else { + CHECK_FATAL(type->IsStructType(), "basetype must be StructType"); + FieldID fieldID = expr->GetFieldID(); + FieldPair fieldPair = static_cast(type)->TraverseToFieldRef(fieldID); + return GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldPair.second.first); + } + } else if (expr->GetKind() == kExprIAddrof) { + FEIRExprIAddrof *iaddrof = static_cast(expr.get()); + MIRType *pointerType = iaddrof->GetClonedPtrType()->GenerateMIRTypeAuto(); + CHECK_FATAL(pointerType->IsMIRPtrType(), "Must be ptr type!"); + MIRType *baseType = static_cast(pointerType)->GetPointedType(); + CHECK_FATAL(baseType->IsStructType(), "basetype must be StructType"); + FieldID fieldID = iaddrof->GetFieldID(); + FieldPair fieldPair = static_cast(baseType)->TraverseToFieldRef(fieldID); + return GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldPair.second.first); + } else { + return nullptr; + } +} + +MIRType *ENCChecker::GetArrayTypeFromExpr(const UniqueFEIRExpr &expr) { + MIRType *arrType = GetTypeFromAddrExpr(expr); + if (arrType != nullptr && arrType->GetKind() == kTypeArray && + !static_cast(arrType)->GetTypeAttrs().GetAttr(ATTR_incomplete_array)) { + return arrType; + } + if (expr->GetKind() == kExprAddrof) { // local char* value size + auto *constArr = static_cast(expr.get()); + return GlobalTables::GetTypeTable().GetOrCreateArrayType( + *constArr->GetElemType(), constArr->GetStringLiteralSize() + 1); // including the end character with string + } else if (expr->GetKind() == kExprDRead || expr->GetKind() == kExprIRead) { // global char* value size + MIRType *type = expr->GetType()->GenerateMIRTypeAuto(); + if (type->IsMIRPtrType() && static_cast(type)->GetPointedType()->GetPrimType() == PTY_u8) { + MIRConst *cst = GetMIRConstFromExpr(expr); + if (cst != nullptr && cst->GetKind() == kConstStrConst) { + size_t size = GlobalTables::GetUStrTable().GetStringFromStrIdx( + static_cast(cst)->GetValue()).size() + 1; // including the end character with string + return GlobalTables::GetTypeTable().GetOrCreateArrayType( + *GlobalTables::GetTypeTable().GetUInt8(), static_cast(size)); + } + } + return nullptr; + } + return nullptr; +} + +MIRConst *ENCChecker::GetMIRConstFromExpr(const UniqueFEIRExpr &expr) { + if (expr == nullptr || expr->GetVarUses().size() != 1) { + return nullptr; + } + MIRSymbol *sym = expr->GetVarUses().front()->GenerateMIRSymbol(FEManager::GetMIRBuilder()); + if (!sym->IsGlobal() || sym->GetKonst() == nullptr) { + return nullptr; + } + if (expr->GetKind() == kExprDRead || expr->GetKind() == kExprAddrofVar) { + if (expr->GetFieldID() == 0) { + return sym->GetKonst(); + } else if (expr->GetFieldID() != 0 && sym->GetKonst()->GetKind() == kConstAggConst) { + MIRAggConst *aggConst = static_cast(sym->GetKonst()); + FieldID tmpID = expr->GetFieldID(); + MIRConst *cst = FEUtils::TraverseToMIRConst(aggConst, *static_cast(sym->GetType()), tmpID); + return cst; + } + return nullptr; + } else if (expr->GetKind() == kExprIRead) { + auto *iread = static_cast(expr.get()); + MIRConst *cst = GetMIRConstFromExpr(iread->GetClonedOpnd()); + if (expr->GetFieldID() != 0 && cst != nullptr && sym->GetKonst()->GetKind() == kConstAggConst) { + MIRType *pointType = static_cast(iread->GetClonedPtrType()->GenerateMIRTypeAuto())->GetPointedType(); + FieldID tmpID = expr->GetFieldID(); + cst = FEUtils::TraverseToMIRConst(static_cast(cst), *static_cast(pointType), tmpID); + } + return cst; + } else if (expr->GetKind() == kExprAddrofArray) { + FEIRExprAddrofArray *arrExpr = static_cast(expr.get()); + MIRConst *cst = GetMIRConstFromExpr(arrExpr->GetExprArray()); + if (cst != nullptr && cst->GetKind() == kConstAggConst) { + for (const auto & idxExpr : arrExpr->GetExprIndexs()) { + MIRAggConst *aggConst = static_cast(cst); + if (idxExpr->GetKind() != kExprConst) { + return nullptr; + } + uint64 idx = static_cast(idxExpr.get())->GetValue().u64; + if (idx >= aggConst->GetConstVec().size()) { + return nullptr; + } + cst = aggConst->GetConstVecItem(idx); + } + return cst; + } + return nullptr; + } + return nullptr; +} + +void ENCChecker::AssignBoundaryVar(MIRBuilder &mirBuilder, const UniqueFEIRExpr &dstExpr, const UniqueFEIRExpr &srcExpr, + const UniqueFEIRExpr &lRealLenExpr, std::list &ans) { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || + srcExpr->GetPrimType() != PTY_ptr || dstExpr->GetPrimType() != PTY_ptr) { + return; + } + if (lRealLenExpr == nullptr && IsGlobalVarInExpr(dstExpr)) { + return; // skip boundary assignment for global var whithout boundary attr + } + // Avoid inserting redundant boundary vars + const std::string prefix = "_boundary."; + if (dstExpr->GetKind() == kExprDRead && + static_cast(dstExpr.get())->GetVar()->GetNameRaw().compare(0, prefix.size(), prefix) == 0) { + return; + } + MIRFunction *curFunction = mirBuilder.GetCurrentFunctionNotNull(); + FEFunction &curFEFunction = FEManager::GetCurrentFEFunction(); + UniqueFEIRExpr baseExpr = FindBaseExprInPointerOperation(srcExpr, true); + if (baseExpr == nullptr) { + return; + } + if (dstExpr->Hash() == baseExpr->Hash()) { // skip self-assignment, e.g. p++; + return; + } + // Check if the l-value has a boundary var + std::pair lBoundaryVarStIdx = std::make_pair(StIdx(0), StIdx(0)); + auto lIt = curFEFunction.GetBoundaryMap().find(dstExpr->Hash()); + if (lIt != curFEFunction.GetBoundaryMap().end()) { // The boundary var exists on the l-value + lBoundaryVarStIdx = lIt->second; + } else { + if (lRealLenExpr != nullptr) { // init boundary in func body if a field/global var l-value with boundary attr + std::list stmts; + lBoundaryVarStIdx = InitBoundaryVar(*curFunction, dstExpr, lRealLenExpr->Clone(), stmts); + for (const auto &stmt : stmts) { + std::list stmtNodes = stmt->GenMIRStmts(mirBuilder); + for (auto stmtNode : stmtNodes) { + curFunction->GetBody()->InsertFirst(stmtNode); + } + } + } + } + // Check if the r-value has a boundary var or an array or a global var/field with boundary attr + std::pair rBoundaryVarStIdx = std::make_pair(StIdx(0), StIdx(0)); + MIRType *arrType = nullptr; + UniqueFEIRExpr rRealLenExpr = nullptr; + auto rIt = curFEFunction.GetBoundaryMap().find(baseExpr->Hash()); + if (rIt != curFEFunction.GetBoundaryMap().end()) { // Assgin when the boundary var exists on the r-value + rBoundaryVarStIdx = rIt->second; + } else { + arrType = GetArrayTypeFromExpr(baseExpr); + if (arrType == nullptr) { + rRealLenExpr = GetGlobalOrFieldLenExprInExpr(mirBuilder, baseExpr); + } + } + // insert L-value bounary and assign boundary var + // when r-value with a boundary var, or with a sized array, a global var/field r-value with boundary attr + bool isSizedArray = (arrType != nullptr && arrType->GetSize() > 0); + if (lBoundaryVarStIdx.first == StIdx(0) && + (rBoundaryVarStIdx.first != StIdx(0) || isSizedArray || rRealLenExpr != nullptr)) { + lBoundaryVarStIdx = ENCChecker::InsertBoundaryVar(mirBuilder, dstExpr); + } + if (lBoundaryVarStIdx.first != StIdx(0)) { + MIRSymbol *lLowerSym = curFunction->GetLocalOrGlobalSymbol(lBoundaryVarStIdx.first); + CHECK_NULL_FATAL(lLowerSym); + MIRSymbol *lUpperSym = curFunction->GetLocalOrGlobalSymbol(lBoundaryVarStIdx.second); + CHECK_NULL_FATAL(lUpperSym); + StmtNode *lowerStmt = nullptr; + StmtNode *upperStmt = nullptr; + if (rBoundaryVarStIdx.first != StIdx(0)) { + MIRSymbol *rLowerSym = curFunction->GetLocalOrGlobalSymbol(rBoundaryVarStIdx.first); + CHECK_NULL_FATAL(rLowerSym); + lowerStmt = mirBuilder.CreateStmtDassign(*lLowerSym, 0, mirBuilder.CreateExprDread(*rLowerSym)); + + MIRSymbol *rUpperSym = curFunction->GetLocalOrGlobalSymbol(rBoundaryVarStIdx.second); + CHECK_NULL_FATAL(rUpperSym); + upperStmt = mirBuilder.CreateStmtDassign(*lUpperSym, 0, mirBuilder.CreateExprDread(*rUpperSym)); + } else if (isSizedArray) { + lowerStmt = mirBuilder.CreateStmtDassign(*lLowerSym, 0, baseExpr->GenMIRNode(mirBuilder)); + UniqueFEIRExpr binExpr = FEIRBuilder::CreateExprBinary( + OP_add, baseExpr->Clone(), std::make_unique(arrType->GetSize(), PTY_ptr)); + upperStmt = mirBuilder.CreateStmtDassign(*lUpperSym, 0, binExpr->GenMIRNode(mirBuilder)); + } else if (rRealLenExpr != nullptr) { + lowerStmt = mirBuilder.CreateStmtDassign(*lLowerSym, 0, baseExpr->GenMIRNode(mirBuilder)); + UniqueFEIRExpr binExpr = FEIRBuilder::CreateExprBinary(OP_add, baseExpr->Clone(), rRealLenExpr->Clone()); + upperStmt = mirBuilder.CreateStmtDassign(*lUpperSym, 0, binExpr->GenMIRNode(mirBuilder)); + } else { + MIRType *addrofType = GetTypeFromAddrExpr(baseExpr); + if (addrofType != nullptr) { // addrof as 1-sized array, if l-value with boundary and r-value is addrof non-array + lowerStmt = mirBuilder.CreateStmtDassign(*lLowerSym, 0, baseExpr->GenMIRNode(mirBuilder)); + UniqueFEIRExpr binExpr = FEIRBuilder::CreateExprBinary( + OP_add, baseExpr->Clone(), std::make_unique(addrofType->GetSize(), PTY_ptr)); + upperStmt = mirBuilder.CreateStmtDassign(*lUpperSym, 0, binExpr->GenMIRNode(mirBuilder)); + } else { + // Insert a undef boundary r-value + // when there is a l-value boundary var and r-value without a boundary var + lowerStmt = mirBuilder.CreateStmtDassign(*lLowerSym, 0, baseExpr->GenMIRNode(mirBuilder)); + UniqueFEIRExpr undef = std::make_unique(kUndefValue, PTY_ptr); + upperStmt = mirBuilder.CreateStmtDassign(*lUpperSym, 0, undef->GenMIRNode(mirBuilder)); + } + } + if (lowerStmt == nullptr || upperStmt == nullptr) { + return; + } + if (lRealLenExpr != nullptr) { // use l-vaule own boundary(use r-base + offset) when l-value has a boundary attr + BaseNode *binExpr = mirBuilder.CreateExprBinary( + OP_add, *lLowerSym->GetType(), srcExpr->GenMIRNode(mirBuilder), lRealLenExpr->GenMIRNode(mirBuilder)); + upperStmt = mirBuilder.CreateStmtDassign(*lUpperSym, 0, binExpr); + } + ans.emplace_back(lowerStmt); + ans.emplace_back(upperStmt); + } +} + +bool ENCChecker::IsGlobalVarInExpr(const UniqueFEIRExpr &expr) { + bool isGlobal = false; + auto vars = expr->GetVarUses(); + if (!vars.empty() && vars.front() != nullptr) { + isGlobal = vars.front()->IsGlobal(); + } + return isGlobal; +} + +std::pair ENCChecker::InsertBoundaryVar(MIRBuilder &mirBuilder, const UniqueFEIRExpr &expr) { + std::pair boundaryVarStIdx = std::make_pair(StIdx(0), StIdx(0)); + std::string boundaryName = GetBoundaryName(expr); + if (boundaryName.empty()) { + return boundaryVarStIdx; + } + MIRType *boundaryType = expr->GetType()->GenerateMIRTypeAuto(); + MIRSymbol *lowerSrcSym = mirBuilder.GetOrCreateLocalDecl(boundaryName + ".lower", *boundaryType); + MIRSymbol *upperSrcSym = mirBuilder.GetOrCreateLocalDecl(boundaryName + ".upper", *boundaryType); + // assign undef val to boundary var in func body head + AssignUndefVal(mirBuilder, *upperSrcSym); + AssignUndefVal(mirBuilder, *lowerSrcSym); + // update BoundaryMap + boundaryVarStIdx = std::make_pair(lowerSrcSym->GetStIdx(), upperSrcSym->GetStIdx()); + FEManager::GetCurrentFEFunction().SetBoundaryMap(expr->Hash(), boundaryVarStIdx); + return boundaryVarStIdx; +} + +std::string ENCChecker::GetBoundaryName(const UniqueFEIRExpr &expr) { + std::string boundaryName; + if (expr == nullptr) { + return boundaryName; + } + if (expr->GetKind() == kExprDRead) { + const FEIRExprDRead *dread = static_cast(expr.get()); + // Naming format for var boundary: _boundary.[varname]_[fieldID].[exprHash].lower/upper + boundaryName = "_boundary." + dread->GetVar()->GetNameRaw() + "." + std::to_string(expr->GetFieldID()) + "." + + std::to_string(expr->Hash()); + } else if (expr->GetKind() == kExprIRead) { + const FEIRExprIRead *iread = static_cast(expr.get()); + MIRType *pointerType = iread->GetClonedPtrType()->GenerateMIRTypeAuto(); + CHECK_FATAL(pointerType->IsMIRPtrType(), "Must be ptr type!"); + MIRType *structType = static_cast(pointerType)->GetPointedType(); + std::string structName = GlobalTables::GetStrTable().GetStringFromStrIdx(structType->GetNameStrIdx()); + FieldID fieldID = iread->GetFieldID(); + FieldPair rFieldPair = static_cast(structType)->TraverseToFieldRef(fieldID); + std::string fieldName = GlobalTables::GetStrTable().GetStringFromStrIdx(rFieldPair.first); + // Naming format for field var boundary: _boundary.[sturctname]_[fieldname].[exprHash].lower/upper + boundaryName = "_boundary." + structName + "_" + fieldName + "." + std::to_string(iread->Hash()); + } + return boundaryName; +} + +void ENCChecker::AssignUndefVal(MIRBuilder &mirBuilder, MIRSymbol &sym) { + if (sym.IsGlobal()) { + MIRIntConst *cst = FEManager::GetModule().GetMemPool()->New( + kUndefValue, *GlobalTables::GetTypeTable().GetPrimType(PTY_ptr)); + sym.SetKonst(cst); + } else { + BaseNode *undef = mirBuilder.CreateIntConst(kUndefValue, PTY_ptr); + StmtNode *assign = mirBuilder.CreateStmtDassign(sym, 0, undef); + MIRFunction *curFunction = mirBuilder.GetCurrentFunctionNotNull(); + curFunction->GetBody()->InsertFirst(assign); + } +} + +void ENCChecker::InitBoundaryVarFromASTDecl(const MapleAllocator &allocator, ASTDecl *ptrDecl, ASTExpr *lenExpr, + std::list &stmts) { + MIRType *ptrType = ptrDecl->GetTypeDesc().front(); + // insert lower boundary stmt + ASTDeclRefExpr *lowerRefExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + lowerRefExpr->SetASTDecl(ptrDecl); + std::string lowerVarName = "_boundary." + ptrDecl->GetName() + ".lower"; + ASTVar *lowerDecl = ASTDeclsBuilder::ASTVarBuilder( + allocator, "", lowerVarName, std::vector{ptrType}, GenericAttrs()); + lowerDecl->SetIsParam(true); + lowerDecl->SetInitExpr(lowerRefExpr); + ASTDeclStmt *lowerStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + lowerStmt->SetSubDecl(lowerDecl); + // insert upper boundary stmt + ASTDeclRefExpr *upperRefExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + upperRefExpr->SetASTDecl(ptrDecl); + ASTBinaryOperatorExpr *upperBinExpr = ASTDeclsBuilder::ASTExprBuilder(allocator); + upperBinExpr->SetLeftExpr(upperRefExpr); + upperBinExpr->SetRightExpr(lenExpr); + upperBinExpr->SetOpcode(OP_add); + upperBinExpr->SetRetType(ptrType); + upperBinExpr->SetCvtNeeded(true); + std::string upperVarName = "_boundary." + ptrDecl->GetName() + ".upper"; + ASTVar *upperDecl = ASTDeclsBuilder::ASTVarBuilder( + allocator, "", upperVarName, std::vector{ptrType}, GenericAttrs()); + upperDecl->SetIsParam(true); + upperDecl->SetInitExpr(upperBinExpr); + ASTDeclStmt *upperStmt = ASTDeclsBuilder::ASTStmtBuilder(allocator); + upperStmt->SetSubDecl(upperDecl); + stmts.emplace_back(lowerStmt); + stmts.emplace_back(upperStmt); +} + +void ENCChecker::InitBoundaryVar(MIRFunction &curFunction, const ASTDecl &ptrDecl, + UniqueFEIRExpr lenExpr, std::list &stmts) { + std::string ptrName = ptrDecl.GenerateUniqueVarName(); + MIRType *ptrType = ptrDecl.GetTypeDesc().front(); + UniqueFEIRExpr ptrExpr = FEIRBuilder::CreateExprDRead(FEIRBuilder::CreateVarNameForC(ptrName, *ptrType)); + // insert lower boundary stmt + std::string lowerVarName = "_boundary." + ptrName + ".lower"; + UniqueFEIRVar lowerVar = FEIRBuilder::CreateVarNameForC(lowerVarName, *ptrType); + UniqueFEIRStmt lowerStmt = FEIRBuilder::CreateStmtDAssign(std::move(lowerVar), ptrExpr->Clone()); + // insert upper boundary stmt + UniqueFEIRExpr binExpr = FEIRBuilder::CreateExprBinary(OP_add, ptrExpr->Clone(), std::move(lenExpr)); + std::string upperVarName = "_boundary." + ptrName + ".upper"; + UniqueFEIRVar upperVar = FEIRBuilder::CreateVarNameForC(upperVarName, *ptrType); + UniqueFEIRStmt upperStmt = FEIRBuilder::CreateStmtDAssign(std::move(upperVar), std::move(binExpr)); + if (ptrDecl.GetSrcFileLineNum() != 0) { + lowerStmt->SetSrcFileInfo(ptrDecl.GetSrcFileIdx(), ptrDecl.GetSrcFileLineNum()); + upperStmt->SetSrcFileInfo(ptrDecl.GetSrcFileIdx(), ptrDecl.GetSrcFileLineNum()); + } + stmts.emplace_back(std::move(lowerStmt)); + stmts.emplace_back(std::move(upperStmt)); + // update BoundaryMap + MIRSymbol *lowerSym = nullptr; + MIRSymbol *upperSym = nullptr; + if (ptrDecl.IsGlobal()) { + lowerSym = FEManager::GetMIRBuilder().GetOrCreateGlobalDecl(lowerVarName, *ptrType); + upperSym = FEManager::GetMIRBuilder().GetOrCreateGlobalDecl(upperVarName, *ptrType); + } else { + lowerSym = FEManager::GetMIRBuilder().GetOrCreateDeclInFunc(lowerVarName, *ptrType, curFunction); + upperSym = FEManager::GetMIRBuilder().GetOrCreateDeclInFunc(upperVarName, *ptrType, curFunction); + } + FEManager::GetCurrentFEFunction().SetBoundaryMap( + ptrExpr->Hash(), std::make_pair(lowerSym->GetStIdx(), upperSym->GetStIdx())); +} + +void ENCChecker::InitBoundaryVar(MIRFunction &curFunction, const std::string &ptrName, MIRType &ptrType, + UniqueFEIRExpr lenExpr, std::list &stmts) { + UniqueFEIRExpr ptrExpr = FEIRBuilder::CreateExprDRead(FEIRBuilder::CreateVarNameForC(ptrName, ptrType)); + // insert lower boundary stmt + std::string lowerVarName = "_boundary." + ptrName + ".lower"; + UniqueFEIRVar lowerVar = FEIRBuilder::CreateVarNameForC(lowerVarName, ptrType); + UniqueFEIRStmt lowerStmt = FEIRBuilder::CreateStmtDAssign(std::move(lowerVar), ptrExpr->Clone()); + stmts.emplace_back(std::move(lowerStmt)); + // insert upper boundary stmt + UniqueFEIRExpr binExpr = FEIRBuilder::CreateExprBinary(OP_add, ptrExpr->Clone(), std::move(lenExpr)); + std::string upperVarName = "_boundary." + ptrName + ".upper"; + UniqueFEIRVar upperVar = FEIRBuilder::CreateVarNameForC(upperVarName, ptrType); + UniqueFEIRStmt upperStmt = FEIRBuilder::CreateStmtDAssign(std::move(upperVar), std::move(binExpr)); + stmts.emplace_back(std::move(upperStmt)); + // update BoundaryMap + MIRSymbol *lowerSym = FEManager::GetMIRBuilder().GetOrCreateDeclInFunc(lowerVarName, ptrType, curFunction); + MIRSymbol *upperSym = FEManager::GetMIRBuilder().GetOrCreateDeclInFunc(upperVarName, ptrType, curFunction); + FEManager::GetCurrentFEFunction().SetBoundaryMap( + ptrExpr->Hash(), std::make_pair(lowerSym->GetStIdx(), upperSym->GetStIdx())); +} + +std::pair ENCChecker::InitBoundaryVar(MIRFunction &curFunction, const UniqueFEIRExpr &ptrExpr, + UniqueFEIRExpr lenExpr, std::list &stmts) { + std::string ptrName = GetBoundaryName(ptrExpr); + if (ptrName.empty()) { + return std::make_pair(StIdx(0), StIdx(0)); + } + MIRType *ptrType = ptrExpr->GetType()->GenerateMIRTypeAuto(); + // insert lower boundary stmt + std::string lowerVarName = ptrName + ".lower"; + UniqueFEIRVar lowerVar = FEIRBuilder::CreateVarNameForC(lowerVarName, *ptrType); + UniqueFEIRStmt lowerStmt = FEIRBuilder::CreateStmtDAssign(std::move(lowerVar), ptrExpr->Clone()); + stmts.emplace_back(std::move(lowerStmt)); + // insert upper boundary stmt + UniqueFEIRExpr binExpr = FEIRBuilder::CreateExprBinary(OP_add, ptrExpr->Clone(), std::move(lenExpr)); + std::string upperVarName = ptrName + ".upper"; + UniqueFEIRVar upperVar = FEIRBuilder::CreateVarNameForC(upperVarName, *ptrType); + UniqueFEIRStmt upperStmt = FEIRBuilder::CreateStmtDAssign(std::move(upperVar), std::move(binExpr)); + stmts.emplace_back(std::move(upperStmt)); + // update BoundaryMap + MIRSymbol *lowerSym = FEManager::GetMIRBuilder().GetOrCreateDeclInFunc(lowerVarName, *ptrType, curFunction); + MIRSymbol *upperSym = FEManager::GetMIRBuilder().GetOrCreateDeclInFunc(upperVarName, *ptrType, curFunction); + auto stIdxs = std::make_pair(lowerSym->GetStIdx(), upperSym->GetStIdx()); + FEManager::GetCurrentFEFunction().SetBoundaryMap(ptrExpr->Hash(), stIdxs); + return stIdxs; +} + + +UniqueFEIRExpr ENCChecker::GetGlobalOrFieldLenExprInExpr(MIRBuilder &mirBuilder, const UniqueFEIRExpr &expr) { + UniqueFEIRExpr lenExpr = nullptr; + if (expr->GetKind() == kExprDRead && expr->GetFieldID() == 0) { + FEIRVar *var = expr->GetVarUses().front(); + MIRSymbol *symbol = var->GenerateMIRSymbol(mirBuilder); + if (!symbol->IsGlobal()) { + return nullptr; + } + // Get the boundary attr(i.e. boundary length expr cache) + lenExpr = GetBoundaryLenExprCache(symbol->GetAttrs()); + } else if ((expr->GetKind() == kExprDRead || expr->GetKind() == kExprIRead) && expr->GetFieldID() != 0) { + MIRStructType *structType = nullptr; + if (expr->GetKind() == kExprDRead) { + structType = static_cast(expr->GetVarUses().front()->GetType()->GenerateMIRTypeAuto()); + } else { + FEIRExprIRead *iread = static_cast(expr.get()); + MIRType *baseType = static_cast(iread->GetClonedPtrType()->GenerateMIRTypeAuto())->GetPointedType(); + structType = static_cast(baseType); + } + FieldID tmpID = expr->GetFieldID(); + FieldPair fieldPair = structType->TraverseToFieldRef(tmpID); + // Get the boundary attr(i.e. boundary length expr cache) of field + lenExpr = GetBoundaryLenExprCache(fieldPair.second.second); + if (lenExpr == nullptr) { + return nullptr; + } + UniqueFEIRExpr realExpr = ENCChecker::GetRealBoundaryLenExprInField( + lenExpr->Clone(), *structType, expr); // lenExpr needs to be cloned + if (realExpr != nullptr) { + lenExpr = std::move(realExpr); + } + } else { + return nullptr; + } + return lenExpr; +} + +bool ENCChecker::IsConstantIndex(const UniqueFEIRExpr &expr) { + if (expr->GetKind() != kExprAddrofArray) { + return false; + } + FEIRExprAddrofArray *arrExpr = static_cast(expr.get()); + // nested array + if (arrExpr->GetExprArray()->GetKind() == kExprAddrofArray) { + if (!IsConstantIndex(arrExpr->GetExprArray()->Clone())) { + return false; + } + } + for (const auto &idxExpr : arrExpr->GetExprIndexs()) { + if (idxExpr->GetKind() != kExprConst) { + return false; + } + } + return true; +} + +void ENCChecker::PeelNestedBoundaryChecking(std::list &stmts, const UniqueFEIRExpr &baseExpr) { + std::list::iterator i = stmts.begin(); + while (i != stmts.end()) { + bool flag = ((*i)->GetKind() == kStmtNary); + if (flag) { + FEIRStmtNary *nary = static_cast((*i).get()); + flag = kOpcodeInfo.IsAssertBoundary(nary->GetOP()) && + nary->GetArgExprs().back()->Hash() == baseExpr->Hash(); + } + if (flag) { + i = stmts.erase(i); + } else { + ++i; + } + } +} + +UniqueFEIRExpr ENCChecker::GetRealBoundaryLenExprInFuncByIndex(const TypeAttrs &typeAttrs, const MIRType &type, + const ASTCallExpr &astCallExpr) { + int8 idx = typeAttrs.GetAttrBoundary().GetLenParamIdx(); + if (idx >= 0) { + ASTExpr *astLenExpr = astCallExpr.GetArgsExpr()[idx]; + if (!typeAttrs.GetAttrBoundary().IsBytedLen()) { + CHECK_FATAL(type.IsMIRPtrType(), "Must be ptr type!"); + size_t lenSize = static_cast(type).GetPointedType()->GetSize(); + MapleAllocator &allocator = FEManager::GetModule().GetMPAllocator(); + astLenExpr = ASTParser::GetAddrShiftExpr(allocator, astCallExpr.GetArgsExpr()[idx], static_cast(lenSize)); + } + std::list nullStmts; + return astLenExpr->Emit2FEExpr(nullStmts); + } else if (typeAttrs.GetAttrBoundary().GetLenExprHash() != 0) { + return ENCChecker::GetBoundaryLenExprCache(typeAttrs); + } + return nullptr; +} + +UniqueFEIRExpr ENCChecker::GetRealBoundaryLenExprInFunc(const UniqueFEIRExpr &lenExpr, const ASTFunc &astFunc, + const ASTCallExpr &astCallExpr) { + if (lenExpr == nullptr) { + return nullptr; + } + if (lenExpr->GetKind() == kExprBinary) { + FEIRExprBinary *mulExpr = static_cast(lenExpr.get()); + UniqueFEIRExpr leftExpr = GetRealBoundaryLenExprInFunc(mulExpr->GetOpnd0(), astFunc, astCallExpr); + if (leftExpr != nullptr) { + mulExpr->SetOpnd0(std::move(leftExpr)); + } else { + return nullptr; + } + UniqueFEIRExpr rightExpr = GetRealBoundaryLenExprInFunc(mulExpr->GetOpnd1(), astFunc, astCallExpr); + if (rightExpr != nullptr) { + mulExpr->SetOpnd1(std::move(rightExpr)); + } else { + return nullptr; + } + } + if (lenExpr->GetKind() == kExprUnary) { + FEIRExprUnary *cvtExpr = static_cast(lenExpr.get()); + UniqueFEIRExpr subExpr = GetRealBoundaryLenExprInFunc(cvtExpr->GetOpnd(), astFunc, astCallExpr); + if (subExpr != nullptr) { + cvtExpr->SetOpnd(std::move(subExpr)); + } else { + return nullptr; + } + } + // formal parameter length expr -> actual parameter expr + std::list nullStmts; + if (lenExpr->GetKind() == kExprDRead) { + std::string lenName = lenExpr->GetVarUses().front()->GetNameRaw(); + for (size_t i = 0; i < astFunc.GetParamDecls().size(); ++i) { + if (lenName == astFunc.GetParamDecls()[i]->GetName()) { + return astCallExpr.GetArgsExpr()[i]->Emit2FEExpr(nullStmts); + } + } + // the var may be a global var + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "%s:%d EnhanceC warning: The var [%s] as boundary length var " + "is not found in the caller func [%s], check the caller whether the var is the actual parameter", + FEManager::GetModule().GetFileNameFromFileNum(astCallExpr.GetSrcFileIdx()).c_str(), + astCallExpr.GetSrcFileLineNum(), lenName.c_str(), astFunc.GetName().c_str()); + } + return lenExpr->Clone(); +} + +UniqueFEIRExpr ENCChecker::GetRealBoundaryLenExprInField(const UniqueFEIRExpr &lenExpr, MIRStructType &baseType, + const UniqueFEIRExpr &dstExpr) { + if (lenExpr == nullptr) { + return nullptr; + } + if (lenExpr->GetKind() == kExprBinary) { + FEIRExprBinary *mulExpr = static_cast(lenExpr.get()); + UniqueFEIRExpr leftExpr = GetRealBoundaryLenExprInField(mulExpr->GetOpnd0(), baseType, dstExpr); + if (leftExpr != nullptr) { + mulExpr->SetOpnd0(std::move(leftExpr)); + } else { + return nullptr; + } + UniqueFEIRExpr rightExpr = GetRealBoundaryLenExprInField(mulExpr->GetOpnd1(), baseType, dstExpr); + if (rightExpr != nullptr) { + mulExpr->SetOpnd1(std::move(rightExpr)); + } else { + return nullptr; + } + } + if (lenExpr->GetKind() == kExprUnary) { + FEIRExprUnary *cvtExpr = static_cast(lenExpr.get()); + UniqueFEIRExpr subExpr = GetRealBoundaryLenExprInField(cvtExpr->GetOpnd(), baseType, dstExpr); + if (subExpr != nullptr) { + cvtExpr->SetOpnd(std::move(subExpr)); + } else { + return nullptr; + } + } + // boundary length expr -> actual dread/iread length field expr + if (lenExpr->GetKind() == kExprDRead) { + std::string lenName = lenExpr->GetVarUses().front()->GetNameRaw(); + uint32 fieldID = 0; + bool flag = FEManager::GetMIRBuilder().TraverseToNamedField( + baseType, GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(lenName), fieldID); + if (!flag) { + return nullptr; + } + MIRType *reType = FEUtils::GetStructFieldType(&baseType, static_cast(fieldID)); + UniqueFEIRType reFEType = FEIRTypeHelper::CreateTypeNative(*reType); + if (dstExpr->GetKind() == kExprDRead) { + return FEIRBuilder::CreateExprDReadAggField( + dstExpr->GetVarUses().front()->Clone(), static_cast(fieldID), std::move(reFEType)); + } else if (dstExpr->GetKind() == kExprIRead) { + FEIRExprIRead *iread = static_cast(dstExpr.get()); + return FEIRBuilder::CreateExprIRead( + std::move(reFEType), iread->GetClonedPtrType(), iread->GetClonedOpnd(), static_cast(fieldID)); + } else { + return nullptr; + } + } + return lenExpr->Clone(); +} + +// --------------------------- +// process boundary var and checking for ast func arg and return +// --------------------------- +std::list ASTFunc::InitArgsBoundaryVar(MIRFunction &mirFunc) const { + std::list stmts; + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || compound == nullptr) { + return stmts; + } + for (auto paramDecl : paramDecls) { + ASTExpr *lenExpr = paramDecl->GetBoundaryLenExpr(); + if (lenExpr == nullptr) { + continue; + } + UniqueFEIRExpr lenFEExpr = lenExpr->Emit2FEExpr(stmts); + ENCChecker::InitBoundaryVar(mirFunc, *paramDecl, std::move(lenFEExpr), stmts); + } + return stmts; +} + +void ASTFunc::InsertBoundaryCheckingInRet(std::list &stmts) const { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || boundary.lenExpr == nullptr || + stmts.size() == 0 || stmts.back()->GetKind() != kStmtReturn) { + return; + } + std::list nullStmts; + const UniqueFEIRExpr &retExpr = static_cast(stmts.back().get())->GetExpr(); + UniqueFEIRExpr baseExpr = ENCChecker::FindBaseExprInPointerOperation(retExpr); + if (baseExpr == nullptr) { + return; + } + std::list exprs; + UniqueFEIRExpr lenExpr = boundary.lenExpr->Emit2FEExpr(nullStmts); + if (boundary.lenParamIdx != -1) { // backup return boundary size in head func body + UniqueFEIRVar retSizeVar = FEIRBuilder::CreateVarNameForC("_boundary.return.size", lenExpr->GetType()->Clone()); + UniqueFEIRStmt lenStmt = FEIRBuilder::CreateStmtDAssign(retSizeVar->Clone(), lenExpr->Clone()); + stmts.emplace_front(std::move(lenStmt)); + lenExpr = FEIRBuilder::CreateExprDRead(std::move(retSizeVar)); + } + lenExpr = FEIRBuilder::CreateExprBinary(OP_add, retExpr->Clone(), std::move(lenExpr)); + exprs.emplace_back(std::move(lenExpr)); + exprs.emplace_back(std::move(baseExpr)); + UniqueFEIRStmt stmt = std::make_unique(OP_returnassertle, std::move(exprs)); + stmt->SetSrcFileInfo(stmts.back()->GetSrcFileIdx(), stmts.back()->GetSrcFileLineNum()); + stmts.insert(--stmts.end(), std::move(stmt)); +} + +void ENCChecker::InsertBoundaryAssignChecking(MIRBuilder &mirBuilder, std::list &ans, + const UniqueFEIRExpr &srcExpr, uint32 fileIdx, uint32 fileLine) { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || srcExpr == nullptr || srcExpr->GetPrimType() != PTY_ptr || + srcExpr->GetKind() != kExprBinary) { // pointer computed assignment + return; + } + if (srcExpr->IsBoundaryChecking()) { // skip if boundary checking has been generated + return; + } + UniqueFEIRExpr baseExpr = FindBaseExprInPointerOperation(srcExpr); + if (baseExpr == nullptr) { + return; + } + srcExpr->SetIsBoundaryChecking(true); + // insert l-value lower boundary chencking + std::list lowerExprs; + lowerExprs.emplace_back(srcExpr->Clone()); + lowerExprs.emplace_back(baseExpr->Clone()); + UniqueFEIRStmt lowerStmt = std::make_unique(OP_calcassertge, std::move(lowerExprs)); + lowerStmt->SetSrcFileInfo(fileIdx, fileLine); + std::list lowerStmts = lowerStmt->GenMIRStmts(mirBuilder); + ans.splice(ans.end(), lowerStmts); + // insert l-value upper boundary chencking + std::list upperExprs; + upperExprs.emplace_back(srcExpr->Clone()); + upperExprs.emplace_back(baseExpr->Clone()); + UniqueFEIRStmt upperStmt = std::make_unique(OP_calcassertlt, std::move(upperExprs)); + upperStmt->SetSrcFileInfo(fileIdx, fileLine); + std::list upperStmts = upperStmt->GenMIRStmts(mirBuilder); + ans.splice(ans.end(), upperStmts); +} + +UniqueFEIRStmt ENCChecker::InsertBoundaryLEChecking(UniqueFEIRExpr lenExpr, const UniqueFEIRExpr &srcExpr, + const UniqueFEIRExpr &dstExpr) { + UniqueFEIRExpr baseExpr = ENCChecker::FindBaseExprInPointerOperation(srcExpr); + if (baseExpr == nullptr) { + return nullptr; + } + if (dstExpr->Hash() == baseExpr->Hash()) { // skip self-assignment, e.g. p++; + return nullptr; + } + UniqueFEIRExpr boundaryExpr = FEIRBuilder::CreateExprBinary( // use r-value base + offset + OP_add, srcExpr->Clone(), std::move(lenExpr)); + std::list exprs; + exprs.emplace_back(std::move(boundaryExpr)); + exprs.emplace_back(std::move(baseExpr)); + return std::make_unique(OP_assignassertle, std::move(exprs)); +} + +UniqueFEIRExpr ENCChecker::GetBoundaryLenExprCache(uint32 hash) { + if (hash == 0) { + return nullptr; + } else { + return FEManager::GetTypeManager().GetBoundaryLenExprFromMap(hash); + } +} + +UniqueFEIRExpr ENCChecker::GetBoundaryLenExprCache(const TypeAttrs &attr) { + return GetBoundaryLenExprCache(attr.GetAttrBoundary().GetLenExprHash()); +} + +UniqueFEIRExpr ENCChecker::GetBoundaryLenExprCache(const FieldAttrs &attr) { + return GetBoundaryLenExprCache(attr.GetAttrBoundary().GetLenExprHash()); +} + +void ENCChecker::InsertBoundaryInAtts(TypeAttrs &attr, const BoundaryInfo &boundary) { + attr.GetAttrBoundary().SetIsBytedLen(boundary.isBytedLen); + if (boundary.lenParamIdx != -1) { + attr.GetAttrBoundary().SetLenParamIdx(boundary.lenParamIdx); + } + if (boundary.lenExpr == nullptr) { + return; + } + std::list nullStmts; + UniqueFEIRExpr lenExpr = boundary.lenExpr->Emit2FEExpr(nullStmts); + InsertBoundaryLenExprInAtts(attr, lenExpr); +} + +void ENCChecker::InsertBoundaryLenExprInAtts(TypeAttrs &attr, const UniqueFEIRExpr &expr) { + if (expr == nullptr) { + return; + } + uint32 hash = expr->Hash(); + FEManager::GetTypeManager().InsertBoundaryLenExprHashMap(hash, expr->Clone()); // save expr cache + attr.GetAttrBoundary().SetLenExprHash(hash); +} + +void ENCChecker::InsertBoundaryInAtts(FieldAttrs &attr, const BoundaryInfo &boundary) { + attr.GetAttrBoundary().SetIsBytedLen(boundary.isBytedLen); + if (boundary.lenParamIdx != -1) { + attr.GetAttrBoundary().SetLenParamIdx(boundary.lenParamIdx); + } + if (boundary.lenExpr == nullptr) { + return; + } + std::list nullStmts; + UniqueFEIRExpr lenExpr = boundary.lenExpr->Emit2FEExpr(nullStmts); + uint32 hash = lenExpr->Hash(); + FEManager::GetTypeManager().InsertBoundaryLenExprHashMap(hash, std::move(lenExpr)); // save expr cache + attr.GetAttrBoundary().SetLenExprHash(hash); +} + +void ENCChecker::InsertBoundaryInAtts(FuncAttrs &attr, const BoundaryInfo &boundary) { + attr.GetAttrBoundary().SetIsBytedLen(boundary.isBytedLen); + if (boundary.lenParamIdx != -1) { + attr.GetAttrBoundary().SetLenParamIdx(boundary.lenParamIdx); + } + if (boundary.lenExpr == nullptr) { + return; + } + std::list nullStmts; + UniqueFEIRExpr lenExpr = boundary.lenExpr->Emit2FEExpr(nullStmts); + uint32 hash = lenExpr->Hash(); + FEManager::GetTypeManager().InsertBoundaryLenExprHashMap(hash, std::move(lenExpr)); // save expr cache + attr.GetAttrBoundary().SetLenExprHash(hash); +} + +// --------------------------- +// process boundary var and checking in stmt of ast func +// --------------------------- +void FEIRStmtDAssign::AssignBoundaryVarAndChecking(MIRBuilder &mirBuilder, std::list &ans) const { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || expr->GetPrimType() != PTY_ptr) { + return; + } + const std::string prefix = "_boundary."; + if (var->GetNameRaw().compare(0, prefix.size(), prefix) == 0) { + return; + } + // insert assign boundary checking for computed r-value + ENCChecker::InsertBoundaryAssignChecking(mirBuilder, ans, expr, srcFileIndex, srcFileLineNum); + + UniqueFEIRExpr dstExpr = nullptr; + UniqueFEIRExpr lenExpr = nullptr; + if (fieldID == 0) { + dstExpr = FEIRBuilder::CreateExprDRead(var->Clone()); + MIRSymbol *dstSym = var->GenerateMIRSymbol(mirBuilder); + // Get the boundary attr(i.e. boundary length expr cache) of var + lenExpr = ENCChecker::GetBoundaryLenExprCache(dstSym->GetAttrs()); + } else { + FieldID tmpID = fieldID; + MIRStructType *structType = static_cast(var->GetType()->GenerateMIRTypeAuto()); + FieldPair fieldPair = structType->TraverseToFieldRef(tmpID); + UniqueFEIRType fieldType = FEIRTypeHelper::CreateTypeNative( + *GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldPair.second.first)); + dstExpr = FEIRBuilder::CreateExprDReadAggField(var->Clone(), fieldID, std::move(fieldType)); + // Get the boundary attr(i.e. boundary length expr cache) of field + lenExpr = ENCChecker::GetBoundaryLenExprCache(fieldPair.second.second); + if (lenExpr != nullptr) { + UniqueFEIRExpr realLenExpr = ENCChecker::GetRealBoundaryLenExprInField( + lenExpr->Clone(), *structType, dstExpr); // lenExpr needs to be cloned + if (realLenExpr != nullptr) { + lenExpr = std::move(realLenExpr); + } + } + } + if (lenExpr != nullptr) { + UniqueFEIRStmt stmt = ENCChecker::InsertBoundaryLEChecking(lenExpr->Clone(), expr, dstExpr); + if (stmt != nullptr) { + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + std::list stmtnodes = stmt->GenMIRStmts(mirBuilder); + ans.insert(ans.end(), stmtnodes.begin(), stmtnodes.end()); + } + } + ENCChecker::AssignBoundaryVar(mirBuilder, dstExpr, expr, lenExpr, ans); +} + +void FEIRStmtIAssign::AssignBoundaryVarAndChecking(MIRBuilder &mirBuilder, std::list &ans) const { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || fieldID == 0 || baseExpr->GetPrimType() != PTY_ptr) { + return; + } + // insert assign boundary checking for computed r-value + ENCChecker::InsertBoundaryAssignChecking(mirBuilder, ans, baseExpr, srcFileIndex, srcFileLineNum); + + MIRType *baseType = static_cast(addrType->GenerateMIRTypeAuto())->GetPointedType(); + FieldID tmpID = fieldID; + FieldPair fieldPair = static_cast(baseType)->TraverseToFieldRef(tmpID); + MIRType *dstType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldPair.second.first); + UniqueFEIRExpr dstExpr = FEIRBuilder::CreateExprIRead( + FEIRTypeHelper::CreateTypeNative(*dstType), addrType->Clone(), addrExpr->Clone(), fieldID); + // Get the boundary attr (i.e. boundary length expr cache) of field + UniqueFEIRExpr lenExpr = ENCChecker::GetBoundaryLenExprCache(fieldPair.second.second); + if (lenExpr != nullptr) { + UniqueFEIRExpr realLenExpr = ENCChecker::GetRealBoundaryLenExprInField( + lenExpr->Clone(), *static_cast(baseType), dstExpr); // lenExpr needs to be cloned + if (realLenExpr != nullptr) { + lenExpr = std::move(realLenExpr); + } + UniqueFEIRStmt stmt = ENCChecker::InsertBoundaryLEChecking(lenExpr->Clone(), baseExpr, dstExpr); + if (stmt != nullptr) { + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + std::list stmtnodes = stmt->GenMIRStmts(mirBuilder); + ans.insert(ans.end(), stmtnodes.begin(), stmtnodes.end()); + } + } + ENCChecker::AssignBoundaryVar(mirBuilder, dstExpr, baseExpr, lenExpr, ans); +} + +void ENCChecker::CheckBoundaryLenFinalAssign(MIRBuilder &mirBuilder, const UniqueFEIRVar &var, FieldID fieldID, + uint32 fileIdx, uint32 fileLine) { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || !FEOptions::GetInstance().IsEnableSafeRegion()) { + return; + } + bool isUnsafe = mirBuilder.GetCurrentFunctionNotNull()->GetAttr(FUNCATTR_unsafed); + if (!FEManager::GetCurrentFEFunction().GetSafeRegionFlag().empty()) { + isUnsafe = !FEManager::GetCurrentFEFunction().GetSafeRegionFlag().top(); + } + if (isUnsafe) { // not warning in unsafe region + return; + } + if (fieldID == 0) { + MIRSymbol *dstSym = var->GenerateMIRSymbol(mirBuilder); + if (dstSym->GetAttr(ATTR_final_boundary_size)) { + WARN(kLncWarn, "%s:%d warning: this var specified as the global or field boundary length is " + "assigned or token address. [Use __Unsafe__ to eliminate the warning]", + FEManager::GetModule().GetFileNameFromFileNum(fileIdx).c_str(), fileLine); + } + } else { + FieldID tmpID = fieldID; + MIRStructType *structType = static_cast(var->GetType()->GenerateMIRTypeAuto()); + FieldPair fieldPair = structType->TraverseToFieldRef(tmpID); + if (fieldPair.second.second.GetAttr(FLDATTR_final_boundary_size)) { + WARN(kLncWarn, "%s:%d warning: this field specified as the global or field boundary length is " + "assigned or token address. [Use __Unsafe__ to eliminate the warning]", + FEManager::GetModule().GetFileNameFromFileNum(fileIdx).c_str(), fileLine); + } + } +} + +void ENCChecker::CheckBoundaryLenFinalAssign(MIRBuilder &mirBuilder, const UniqueFEIRType &addrType, FieldID fieldID, + uint32 fileIdx, uint32 fileLine) { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || !FEOptions::GetInstance().IsEnableSafeRegion() || + fieldID == 0) { + return; + } + bool isUnsafe = mirBuilder.GetCurrentFunctionNotNull()->GetAttr(FUNCATTR_unsafed); + if (!FEManager::GetCurrentFEFunction().GetSafeRegionFlag().empty()) { + isUnsafe = !FEManager::GetCurrentFEFunction().GetSafeRegionFlag().top(); + } + if (isUnsafe) { // not warning in unsafe region + return; + } + MIRType *baseType = static_cast(addrType->GenerateMIRTypeAuto())->GetPointedType(); + FieldID tmpID = fieldID; + FieldPair fieldPair = static_cast(baseType)->TraverseToFieldRef(tmpID); + if (fieldPair.second.second.GetAttr(FLDATTR_final_boundary_size)) { + WARN(kLncWarn, "%s:%d warning: this field specified as the global or field boundary length is " + "assigned or token address. [Use __Unsafe__ to eliminate the warning]", + FEManager::GetModule().GetFileNameFromFileNum(fileIdx).c_str(), fileLine); + } +} + +void ENCChecker::CheckBoundaryLenFinalAddr(MIRBuilder &mirBuilder, const UniqueFEIRExpr &expr, + uint32 fileIdx, uint32 fileLine) { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || !FEOptions::GetInstance().IsEnableSafeRegion()) { + return; + } + if (expr->GetKind() == kExprAddrofVar) { + UniqueFEIRVar var = expr->GetVarUses().front()->Clone(); + CheckBoundaryLenFinalAssign(mirBuilder, var, expr->GetFieldID(), fileIdx, fileLine); + } else if (expr->GetKind() == kExprIAddrof) { + auto *iaddrof = static_cast(expr.get()); + CheckBoundaryLenFinalAssign(mirBuilder, iaddrof->GetClonedPtrType(), expr->GetFieldID(), fileIdx, fileLine); + } +} + +MapleVector ENCChecker::ReplaceBoundaryChecking(MIRBuilder &mirBuilder, const FEIRStmtNary *stmt) { + MIRFunction *curFunction = mirBuilder.GetCurrentFunctionNotNull(); + UniqueFEIRExpr leftExpr = stmt->GetArgExprs().front()->Clone(); + UniqueFEIRExpr rightExpr = stmt->GetArgExprs().back()->Clone(); + BaseNode *leftNode = nullptr; + BaseNode *rightNode = nullptr; + MIRType *arrType = ENCChecker::GetArrayTypeFromExpr(stmt->GetArgExprs().back()); + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + Opcode op = stmt->GetOP(); + if (arrType != nullptr) { // var must be array type by the previous checking + if (arrType->GetSize() == 0) { // unsized array + return args; + } + // Convert to the following node for array: + // assertge/assertlt lnode: addrofarray + index; assertle lnode: (attributed upper boundary) addrofarray + len expr + // assertge rnode: addrof array; assertlt/assertle rnode: addrof array + sizeof expr + if (kOpcodeInfo.IsAssertUpperBoundary(op)) { + rightExpr = FEIRBuilder::CreateExprBinary( + OP_add, std::move(rightExpr), std::make_unique(arrType->GetSize(), PTY_ptr)); + } + leftNode = leftExpr->GenMIRNode(mirBuilder); + rightNode = rightExpr->GenMIRNode(mirBuilder); + } else { + // Convert to the following node for expr with boundary var: + // assertge/assertlt lnode: addrof base + index; assertle lnode: (attributed upper boundary) addrof base + len expr + // assertge rnode: lower boundary; assertlt/assertle rnode: upper boundary + auto it = FEManager::GetCurrentFEFunction().GetBoundaryMap().find(rightExpr->Hash()); + UniqueFEIRExpr lenExpr = ENCChecker::GetGlobalOrFieldLenExprInExpr(mirBuilder, rightExpr); + if (it != FEManager::GetCurrentFEFunction().GetBoundaryMap().end()) { + if (lenExpr == nullptr && IsGlobalVarInExpr(rightExpr)) { + return args; // skip boundary checking for global var whithout boundary attr, + } // because the lack of global variable boundary analysis capabilities in mapleall + StIdx boundaryStIdx = kOpcodeInfo.IsAssertLowerBoundary(op) ? it->second.first : it->second.second; + MIRSymbol *boundarySym = curFunction->GetLocalOrGlobalSymbol(boundaryStIdx); + CHECK_NULL_FATAL(boundarySym); + rightNode = mirBuilder.CreateExprDread(*boundarySym); + } else { + if (lenExpr != nullptr) { // a global var or field with boundary attr + if (kOpcodeInfo.IsAssertUpperBoundary(op)) { + rightExpr = FEIRBuilder::CreateExprBinary(OP_add, std::move(rightExpr), std::move(lenExpr)); + } + rightNode = rightExpr->GenMIRNode(mirBuilder); + } else { + if (ENCChecker::IsUnsafeRegion(mirBuilder)) { + return args; + } + if (op == OP_callassertle) { + auto callAssert = static_cast(stmt); + FE_ERR(kLncErr, "%s:%d error: boundaryless pointer passed to %s that requires a boundary pointer for the %s" + " argument", FEManager::GetModule().GetFileNameFromFileNum(stmt->GetSrcFileIdx()).c_str(), + stmt->GetSrcFileLineNum(), callAssert->GetFuncName().c_str(), + ENCChecker::GetNthStr(callAssert->GetParamIndex()).c_str()); + } else if (op == OP_returnassertle) { + if (curFunction->GetName().compare(kBoundsBuiltFunc) != 0) { + FE_ERR(kLncErr, "%s:%d error: boundaryless pointer returned from %s that requires a boundary pointer", + FEManager::GetModule().GetFileNameFromFileNum(stmt->GetSrcFileIdx()).c_str(), + stmt->GetSrcFileLineNum(), curFunction->GetName().c_str()); + } + } else if (op == OP_assignassertle) { + FE_ERR(kLncErr, "%s:%d error: r-value requires a boundary pointer", + FEManager::GetModule().GetFileNameFromFileNum(stmt->GetSrcFileIdx()).c_str(), stmt->GetSrcFileLineNum()); + } else if (ENCChecker::IsSafeRegion(mirBuilder) && + (op == OP_calcassertge || + (op == OP_assertge && static_cast(stmt)->IsComputable()))) { + FE_ERR(kLncErr, "%s:%d error: calculation with pointer requires bounds in safe region", + FEManager::GetModule().GetFileNameFromFileNum(stmt->GetSrcFileIdx()).c_str(), stmt->GetSrcFileLineNum()); + } + return args; + } + } + leftNode = leftExpr->GenMIRNode(mirBuilder); + } + args.emplace_back(leftNode); + args.emplace_back(rightNode); + return args; +} + +bool ASTArraySubscriptExpr::InsertBoundaryChecking(std::list &stmts, + UniqueFEIRExpr indexExpr, UniqueFEIRExpr baseAddrFEExpr) const { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic()) { + return false; + } + if (arrayType->GetKind() == MIRTypeKind::kTypeArray) { + if (ENCChecker::IsConstantIndex(indexExpr)) { + return false; // skip checking when all indexes are constants + } + while (baseAddrFEExpr != nullptr && baseAddrFEExpr->GetKind() == kExprAddrofArray) { + baseAddrFEExpr = static_cast(baseAddrFEExpr.get())->GetExprArray()->Clone(); + } + } else { + baseAddrFEExpr = ENCChecker::FindBaseExprInPointerOperation(baseAddrFEExpr); + if (baseAddrFEExpr == nullptr) { + return false; + } + } + // peel nested boundary checking in a multi-dimensional array + ENCChecker::PeelNestedBoundaryChecking(stmts, baseAddrFEExpr); + // insert lower boundary chencking, baseExpr will be replace by lower boundary var when FEIRStmtNary GenMIRStmts + std::list lowerExprs; + lowerExprs.emplace_back(indexExpr->Clone()); + lowerExprs.emplace_back(baseAddrFEExpr->Clone()); + auto lowerStmt = std::make_unique(OP_assertge, std::move(lowerExprs)); + lowerStmt->SetIsComputable(true); + lowerStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(lowerStmt)); + // insert upper boundary chencking, baseExpr will be replace by upper boundary var when FEIRStmtNary GenMIRStmts + std::list upperExprs; + upperExprs.emplace_back(std::move(indexExpr)); + upperExprs.emplace_back(std::move(baseAddrFEExpr)); + auto upperStmt = std::make_unique(OP_assertlt, std::move(upperExprs)); + upperStmt->SetIsComputable(true); + upperStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(upperStmt)); + return true; +} + +bool ASTUODerefExpr::InsertBoundaryChecking(std::list &stmts, UniqueFEIRExpr expr) const { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic()) { + return false; + } + UniqueFEIRExpr baseExpr = ENCChecker::FindBaseExprInPointerOperation(expr); + if (baseExpr == nullptr) { + return false; + } + // peel nested boundary checking in a multi-dereference + ENCChecker::PeelNestedBoundaryChecking(stmts, baseExpr); + // insert lower boundary chencking, baseExpr will be replace by lower boundary var when FEIRStmtNary GenMIRStmts + std::list lowerExprs; + lowerExprs.emplace_back(expr->Clone()); + lowerExprs.emplace_back(baseExpr->Clone()); + auto lowerStmt = std::make_unique(OP_assertge, std::move(lowerExprs)); + lowerStmt->SetIsComputable(expr->GetKind() == kExprBinary); + lowerStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(lowerStmt)); + // insert upper boundary chencking, baseExpr will be replace by upper boundary var when FEIRStmtNary GenMIRStmts + std::list upperExprs; + upperExprs.emplace_back(expr->Clone()); + upperExprs.emplace_back(std::move(baseExpr)); + auto upperStmt = std::make_unique(OP_assertlt, std::move(upperExprs)); + upperStmt->SetIsComputable(expr->GetKind() == kExprBinary); + upperStmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(upperStmt)); + return true; +} + +void ENCChecker::ReduceBoundaryChecking(std::list &stmts, const UniqueFEIRExpr &expr) { + // assert* --> calcassert*, when addrof the dereference, e.g. &arr[i] + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic()) { + return; + } + std::list::iterator iter = stmts.begin(); + for (; iter != stmts.end(); ++iter) { + if ((*iter)->GetKind() != kStmtNary) { + continue; + } + FEIRStmtNary *nary = static_cast((*iter).get()); + if (nary->GetOP() != OP_assertge || + nary->GetArgExprs().front()->Hash() != expr->Hash()) { // addrof expr and index expr of checking are consistent + continue; + } + nary->SetOP(OP_calcassertge); + std::list::iterator nextedIter = std::next(iter, 1); + if (nextedIter != stmts.end() && (*nextedIter)->GetKind() == kStmtNary) { + FEIRStmtNary *nextedNary = static_cast((*nextedIter).get()); + if (nextedNary->GetOP() == OP_assertlt) { + nextedNary->SetOP(OP_calcassertlt); + } + } + break; + } +} + +// --------------------------- +// caller boundary inserting and checking +// --------------------------- +void ASTCallExpr::InsertBoundaryCheckingInArgs(std::list &stmts) const { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || funcDecl == nullptr) { + return; + } + std::list nullStmts; + for (size_t i = 0; i < funcDecl->GetParamDecls().size(); ++i) { + ASTDecl *paramDecl = funcDecl->GetParamDecls()[i]; + ASSERT_NOT_NULL(paramDecl); + if (paramDecl->GetBoundaryLenExpr() == nullptr) { + continue; + } + UniqueFEIRExpr realLenExpr = ENCChecker::GetRealBoundaryLenExprInFunc( + paramDecl->GetBoundaryLenExpr()->Emit2FEExpr(stmts), *funcDecl, *this); + if (realLenExpr == nullptr) { + continue; + } + UniqueFEIRExpr argExpr = args[i]->Emit2FEExpr(nullStmts); + UniqueFEIRExpr baseExpr = ENCChecker::FindBaseExprInPointerOperation(argExpr); + if (baseExpr == nullptr) { + continue; + } + std::list exprs; + realLenExpr = FEIRBuilder::CreateExprBinary(OP_add, std::move(argExpr), std::move(realLenExpr)); + exprs.emplace_back(std::move(realLenExpr)); + exprs.emplace_back(std::move(baseExpr)); + UniqueFEIRStmt stmt = std::make_unique(OP_callassertle, std::move(exprs), + GetFuncName(), i); + stmt->SetSrcFileInfo(GetSrcFileIdx(), GetSrcFileLineNum()); + stmts.emplace_back(std::move(stmt)); + } +} + +void ASTCallExpr::InsertBoundaryCheckingInArgsForICall(std::list &stmts, + const UniqueFEIRExpr &calleeFEExpr) const { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || calleeFEExpr == nullptr) { + return; + } + const MIRFuncType *funcType = FEUtils::GetFuncPtrType(*calleeFEExpr->GetType()->GenerateMIRType()); + if (funcType == nullptr) { + return; + } + const std::vector &attrsVec = funcType->GetParamAttrsList(); + const std::vector typesVec = funcType->GetParamTypeList(); + std::list nullStmts; + for (size_t i = 0; i < attrsVec.size() && i < typesVec.size() && i < args.size(); ++i) { + MIRType *ptrType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(typesVec[i]); + UniqueFEIRExpr lenExpr = ENCChecker::GetRealBoundaryLenExprInFuncByIndex(attrsVec[i], *ptrType, *this); + if (lenExpr == nullptr) { + continue; + } + UniqueFEIRExpr argExpr = args[i]->Emit2FEExpr(nullStmts); + UniqueFEIRExpr baseExpr = ENCChecker::FindBaseExprInPointerOperation(argExpr); + if (baseExpr == nullptr) { + continue; + } + std::list exprs; + lenExpr = FEIRBuilder::CreateExprBinary(OP_add, std::move(argExpr), std::move(lenExpr)); + exprs.emplace_back(std::move(lenExpr)); + exprs.emplace_back(std::move(baseExpr)); + UniqueFEIRStmt stmt = std::make_unique( + OP_callassertle, std::move(exprs), "function_pointer", i); + stmt->SetSrcFileInfo(srcFileIdx, srcFileLineNum); + stmts.emplace_back(std::move(stmt)); + } +} + +void ASTCallExpr::InsertBoundaryVarInRet(std::list &stmts) const { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || !IsNeedRetExpr()) { + return; + } + std::list nullStmts; + UniqueFEIRExpr realLenExpr = nullptr; + if (funcDecl != nullptr && funcDecl->GetBoundaryLenExpr() != nullptr) { // call + realLenExpr = ENCChecker::GetRealBoundaryLenExprInFunc( + funcDecl->GetBoundaryLenExpr()->Emit2FEExpr(stmts), *funcDecl, *this); + } else if (isIcall && calleeExpr != nullptr) { // icall + const MIRFuncType *funcType = FEUtils::GetFuncPtrType( + *calleeExpr->Emit2FEExpr(nullStmts)->GetType()->GenerateMIRType()); + if (funcType != nullptr) { + MIRType *ptrType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(funcType->GetRetTyIdx()); + if (ptrType != nullptr) { + realLenExpr = ENCChecker::GetRealBoundaryLenExprInFuncByIndex(funcType->GetRetAttrs(), *ptrType, *this); + } + } + } + if (realLenExpr == nullptr) { + return; + } + // GetCurrentFunction need to be optimized when parallel features + MIRFunction *curFunction = FEManager::GetMIRBuilder().GetCurrentFunctionNotNull(); + ENCChecker::InitBoundaryVar(*curFunction, varName, *retType, std::move(realLenExpr), stmts); +} + +bool ENCChecker::IsSameBoundary(const AttrBoundary &arg1, const AttrBoundary &arg2) { + if (arg1.IsBytedLen() != arg2.IsBytedLen()) { + return false; + } + if (arg1.GetLenExprHash() != 0 && arg1.GetLenExprHash() == arg2.GetLenExprHash()) { + return true; + } + if (arg1.GetLenParamIdx() != -1 && arg1.GetLenParamIdx() == arg2.GetLenParamIdx()) { + return true; + } + if (arg1.GetLenExprHash() == arg2.GetLenExprHash() && arg1.GetLenParamIdx() == arg2.GetLenParamIdx()) { + return true; + } + return false; +} + +void ENCChecker::CheckBoundaryArgsAndRetForFuncPtr(const MIRType &dstType, const UniqueFEIRExpr &srcExpr, + uint32 fileNum, uint32 fileLine) { + const MIRFuncType *funcType = FEUtils::GetFuncPtrType(dstType); + if (funcType == nullptr) { + return; + } + if (srcExpr->GetKind() == kExprAddrofFunc) { // check func ptr l-value and &func decl r-value + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + static_cast(srcExpr.get())->GetFuncAddr()); + MIRFunction *srcFunc = FEManager::GetTypeManager().GetMIRFunction(strIdx, false); + CHECK_FATAL(srcFunc != nullptr, "can not get MIRFunction"); + std::list errIdxs; + for (size_t i = 0; i < srcFunc->GetParamSize() && i < funcType->GetParamAttrsList().size(); ++i) { + if (!IsSameBoundary( + srcFunc->GetNthParamAttr(i).GetAttrBoundary(), funcType->GetNthParamAttrs(i).GetAttrBoundary())) { + errIdxs.emplace_back(i); + } + } + if (!errIdxs.empty()) { + FE_ERR(kLncErr, "%s:%d error: function pointer and target function's boundary attributes are mismatched " + "for the %s argument", FEManager::GetModule().GetFileNameFromFileNum(fileNum).c_str(), fileLine, + PrintParamIdx(errIdxs).c_str()); + } + if (!IsSameBoundary(srcFunc->GetFuncAttrs().GetAttrBoundary(), funcType->GetRetAttrs().GetAttrBoundary())) { + FE_ERR(kLncErr, "%s:%d error: function pointer and target function's boundary attributes are mismatched " + "for the return value", FEManager::GetModule().GetFileNameFromFileNum(fileNum).c_str(), fileLine); + } + } + const MIRFuncType *srcFuncType = FEUtils::GetFuncPtrType(*srcExpr->GetType()->GenerateMIRTypeAuto()); + if (srcFuncType != nullptr) { // check func ptr l-value and func ptr r-value + std::list errIdxs; + for (size_t i = 0; i < srcFuncType->GetParamAttrsList().size() && i < funcType->GetParamAttrsList().size(); ++i) { + if (!IsSameBoundary( + srcFuncType->GetNthParamAttrs(i).GetAttrBoundary(), funcType->GetNthParamAttrs(i).GetAttrBoundary())) { + errIdxs.emplace_back(i); + } + } + if (!errIdxs.empty()) { + FE_ERR(kLncErr, "%s:%d error: function pointer's boundary attributes are mismatched for the %s argument", + FEManager::GetModule().GetFileNameFromFileNum(fileNum).c_str(), fileLine, PrintParamIdx(errIdxs).c_str()); + } + if (!IsSameBoundary(srcFuncType->GetRetAttrs().GetAttrBoundary(), funcType->GetRetAttrs().GetAttrBoundary())) { + FE_ERR(kLncErr, "%s:%d error: function pointer's boundary attributes are mismatched for the return value", + FEManager::GetModule().GetFileNameFromFileNum(fileNum).c_str(), fileLine); + } + } +} + +void FEIRStmtDAssign::CheckBoundaryArgsAndRetForFuncPtr(const MIRBuilder &mirBuilder) const { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || ENCChecker::IsUnsafeRegion(mirBuilder)) { + return; + } + MIRType *baseType = var->GetType()->GenerateMIRTypeAuto(); + if (fieldID != 0) { + baseType = FEUtils::GetStructFieldType(static_cast(baseType), fieldID); + } + ENCChecker::CheckBoundaryArgsAndRetForFuncPtr(*baseType, expr, srcFileIndex, srcFileLineNum); +} + +void FEIRStmtIAssign::CheckBoundaryArgsAndRetForFuncPtr(const MIRBuilder &mirBuilder, const MIRType &baseType) const { + if (!FEOptions::GetInstance().IsBoundaryCheckDynamic() || ENCChecker::IsUnsafeRegion(mirBuilder)) { + return; + } + MIRType *fieldType = FEUtils::GetStructFieldType(static_cast(&baseType), fieldID); + ENCChecker::CheckBoundaryArgsAndRetForFuncPtr(*fieldType, baseExpr, srcFileIndex, srcFileLineNum); +} + +// --------------------------- +// process safe region +// --------------------------- +bool ENCChecker::IsSafeRegion(const MIRBuilder &mirBuilder) { + bool isSafe = false; + if (FEOptions::GetInstance().IsEnableSafeRegion()) { + isSafe = mirBuilder.GetCurrentFunctionNotNull()->GetAttr(FUNCATTR_safed); + if (!FEManager::GetCurrentFEFunction().GetSafeRegionFlag().empty()) { + isSafe = FEManager::GetCurrentFEFunction().GetSafeRegionFlag().top(); + } + } + return isSafe; +} + +bool ENCChecker::IsUnsafeRegion(const MIRBuilder &mirBuilder) { + bool isUnsafe = false; + if (FEOptions::GetInstance().IsEnableSafeRegion()) { + isUnsafe = mirBuilder.GetCurrentFunctionNotNull()->GetAttr(FUNCATTR_unsafed); + if (!FEManager::GetCurrentFEFunction().GetSafeRegionFlag().empty()) { + isUnsafe = !FEManager::GetCurrentFEFunction().GetSafeRegionFlag().top(); + } + } + return isUnsafe; +} +} diff --git a/src/hir2mpl/common/src/fe_config_parallel.cpp b/src/hir2mpl/common/src/fe_config_parallel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..889adda306f987ab124843def932a89249401633 --- /dev/null +++ b/src/hir2mpl/common/src/fe_config_parallel.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_config_parallel.h" +#include "mpl_logging.h" + +namespace maple { +FEConfigParallel FEConfigParallel::instance; + +FEConfigParallel::FEConfigParallel() + : nThread(0), enableParallel(false) {} +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/common/src/fe_diag_manager.cpp b/src/hir2mpl/common/src/fe_diag_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4115610378a54d23681d2c3c738f03c9e2c386c8 --- /dev/null +++ b/src/hir2mpl/common/src/fe_diag_manager.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_diag_manager.h" +#include "mpl_logging.h" + +namespace maple { +void FEDiagManager::IncErrNum() { + std::lock_guard lk(errNumMtx); + ++errNum; +} + +int FEDiagManager::GetDiagRes() const { + if (errNum > 0) { + INFO(kLncInfo, "%d error generated.", errNum); + return FEErrno::kFEError; + } + return FEErrno::kNoError; +} + +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/common/src/fe_file_ops.cpp b/src/hir2mpl/common/src/fe_file_ops.cpp new file mode 100644 index 0000000000000000000000000000000000000000..067071980a47957c9928fa98b35f550dc32b4a11 --- /dev/null +++ b/src/hir2mpl/common/src/fe_file_ops.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_file_ops.h" + +namespace maple { +std::string FEFileOps::GetFilePath(const std::string &pathName) { + size_t pos = pathName.find_last_of('/'); + if (pos == std::string::npos) { + return ""; + } else { + return pathName.substr(0, pos + 1); + } +} + +std::string FEFileOps::GetFileNameWithExt(const std::string &pathName) { + size_t pos = pathName.find_last_of('/'); + if (pos == std::string::npos) { + return pathName; + } else { + return pathName.substr(pos + 1); + } +} + +std::string FEFileOps::GetFileName(const std::string &pathName) { + std::string nameWithExt = GetFileNameWithExt(pathName); + size_t pos = nameWithExt.find_last_of("."); + if (pos == std::string::npos) { + return nameWithExt; + } else { + return nameWithExt.substr(0, pos); + } +} + +std::string FEFileOps::GetFileExtName(const std::string &pathName) { + std::string nameWithExt = GetFileNameWithExt(pathName); + size_t pos = nameWithExt.find_last_of("."); + if (pos == std::string::npos) { + return ""; + } else { + return nameWithExt.substr(pos + 1); + } +} +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/common/src/fe_file_type.cpp b/src/hir2mpl/common/src/fe_file_type.cpp new file mode 100644 index 0000000000000000000000000000000000000000..65e4a594e8b2e06e5ca70bf547af2703a713b9c4 --- /dev/null +++ b/src/hir2mpl/common/src/fe_file_type.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_file_type.h" +#include +#include "mpl_logging.h" + +namespace maple { +FEFileType FEFileType::fileType; + +FEFileType::FEFileType() { + LoadDefault(); +} + +FEFileType::FileType FEFileType::GetFileTypeByExtName(const std::string &extName) const { + if (extName.empty()) { + WARN(kLncWarn, "Empty input for GetFileTypeByExtName()...skipped"); + return kUnknownType; + } + auto itExtNameType = mapExtNameType.find(extName); + if (itExtNameType == mapExtNameType.end()) { + WARN(kLncWarn, "Unknown file extension name %s...skipped", extName.c_str()); + return kUnknownType; + } + return itExtNameType->second; +} + +FEFileType::FileType FEFileType::GetFileTypeByPathName(const std::string &pathName) const { + std::string extName = GetExtName(pathName); + return GetFileTypeByExtName(extName); +} + +FEFileType::FileType FEFileType::GetFileTypeByMagicNumber(const std::string &pathName) const { + std::ifstream file(pathName); + if (!file.is_open()) { + ERR(kLncErr, "unable to open file %s", pathName.c_str()); + return kUnknownType; + } + uint32 magic = 0; + int lenght = static_cast(sizeof(uint32)); + (void)file.read(reinterpret_cast(&magic), lenght); + file.close(); + return GetFileTypeByMagicNumber(magic); +} + +FEFileType::FileType FEFileType::GetFileTypeByMagicNumber(BasicIOMapFile &file) const { + BasicIORead fileReader(file); + bool success = false; + uint32 magic = fileReader.ReadUInt32(success); + if (!success) { + ERR(kLncErr, "unable to open file %s", file.GetFileName().c_str()); + return kUnknownType; + } + return GetFileTypeByMagicNumber(magic); +} + +FEFileType::FileType FEFileType::GetFileTypeByMagicNumber(uint32 magic) const { + std::map::const_iterator it = mapMagicType.find(magic); + if (it != mapMagicType.end()) { + return it->second; + } else { + return kUnknownType; + } +} + +void FEFileType::Reset() { + mapExtNameType.clear(); + mapTypeMagic.clear(); + mapMagicType.clear(); +} + +void FEFileType::LoadDefault() { + Reset(); + RegisterExtName(kClass, "class"); + RegisterMagicNumber(kClass, kMagicClass); + RegisterExtName(kJar, "jar"); + RegisterMagicNumber(kJar, kMagicZip); + RegisterExtName(kDex, "dex"); + RegisterMagicNumber(kDex, kMagicDex); + RegisterExtName(kAST, "ast"); + RegisterMagicNumber(kAST, kMagicAST); + RegisterExtName(kMAST, "mast"); + RegisterMagicNumber(kMAST, kMagicMAST); +} + +void FEFileType::RegisterExtName(FileType argFileType, const std::string &extName) { + if (extName.empty() || argFileType == kUnknownType) { + WARN(kLncWarn, "Invalid input for RegisterMagicNumber()...skipped"); + return; + } + mapExtNameType[extName] = argFileType; + mapTypeMagic[argFileType] = 0; +} + +void FEFileType::RegisterMagicNumber(FileType argFileType, uint32 magicNumber) { + if (magicNumber == 0 || argFileType == kUnknownType) { + WARN(kLncWarn, "Invalid input for RegisterMagicNumber()...skipped"); + return; + } + mapTypeMagic[argFileType] = magicNumber; + mapMagicType[magicNumber] = argFileType; +} + +std::string FEFileType::GetPath(const std::string &pathName) { + size_t pos = pathName.find_last_of('/'); + if (pos != std::string::npos) { + return pathName.substr(0, pos + 1); + } else { + return ""; + } +} + +std::string FEFileType::GetName(const std::string &pathName, bool withExt) { + size_t pos = pathName.find_last_of('/'); + std::string name = ""; + if (pos != std::string::npos) { + name = pathName.substr(pos + 1); + } else { + name = pathName; + } + if (withExt) { + return name; + } + size_t posDot = name.find_last_of('.'); + if (posDot != std::string::npos) { + return name.substr(0, posDot); + } else { + return name; + } +} + +std::string FEFileType::GetExtName(const std::string &pathName) { + std::string name = GetName(pathName, true); + size_t pos = name.find_last_of('.'); + if (pos != std::string::npos) { + return name.substr(pos + 1); + } else { + return ""; + } +} +} // namespace maple diff --git a/src/hir2mpl/common/src/fe_function.cpp b/src/hir2mpl/common/src/fe_function.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3da74fcd73cc329d83b4bf126cd4c46ce0322844 --- /dev/null +++ b/src/hir2mpl/common/src/fe_function.cpp @@ -0,0 +1,796 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_function.h" +#include "feir_bb.h" +#include "mpl_logging.h" +#include "fe_options.h" +#include "fe_manager.h" +#include "feir_var_name.h" +#include "feir_var_reg.h" +#include "hir2mpl_env.h" +#include "feir_builder.h" +#include "feir_dfg.h" +#include "feir_type_helper.h" +#include "feir_var_type_scatter.h" +#include "fe_options.h" + +namespace maple { +FEFunction::FEFunction(MIRFunction &argMIRFunction, const std::unique_ptr &argPhaseResultTotal) + : genStmtHead(nullptr), + genStmtTail(nullptr), + genBBHead(nullptr), + genBBTail(nullptr), + feirStmtHead(nullptr), + feirStmtTail(nullptr), + feirBBHead(nullptr), + feirBBTail(nullptr), + phaseResult(FEOptions::GetInstance().IsDumpPhaseTimeDetail() || FEOptions::GetInstance().IsDumpPhaseTime()), + phaseResultTotal(argPhaseResultTotal), + mirFunction(argMIRFunction) { +} + +FEFunction::~FEFunction() { + genStmtHead = nullptr; + genStmtTail = nullptr; + genBBHead = nullptr; + genBBTail = nullptr; + feirStmtHead = nullptr; + feirStmtTail = nullptr; + feirBBHead = nullptr; + feirBBTail = nullptr; +} + +void FEFunction::InitImpl() { + // feir stmt/bb + feirStmtHead = RegisterFEIRStmt(std::make_unique(FEIRNodeKind::kStmtPesudoFuncStart)); + feirStmtTail = RegisterFEIRStmt(std::make_unique(FEIRNodeKind::kStmtPesudoFuncEnd)); + feirStmtHead->SetNext(feirStmtTail); + feirStmtTail->SetPrev(feirStmtHead); + feirBBHead = RegisterFEIRBB(std::make_unique(FEIRBBKind::kBBKindPesudoHead)); + feirBBTail = RegisterFEIRBB(std::make_unique(FEIRBBKind::kBBKindPesudoTail)); + feirBBHead->SetNext(feirBBTail); + feirBBTail->SetPrev(feirBBHead); +} + +void FEFunction::AppendFEIRStmts(std::list &stmts) { + ASSERT_NOT_NULL(feirStmtTail); + InsertFEIRStmtsBefore(*feirStmtTail, stmts); +} + +void FEFunction::InsertFEIRStmtsBefore(FEIRStmt &pos, std::list &stmts) { + while (stmts.size() > 0) { + FEIRStmt *ptrFEIRStmt = RegisterFEIRStmt(std::move(stmts.front())); + stmts.pop_front(); + pos.InsertBefore(ptrFEIRStmt); + } +} + +FEIRStmt *FEFunction::RegisterGeneralStmt(std::unique_ptr stmt) { + genStmtList.push_back(std::move(stmt)); + return genStmtList.back().get(); +} + +const std::unique_ptr &FEFunction::RegisterGeneralStmtUniqueReturn(std::unique_ptr stmt) { + genStmtList.push_back(std::move(stmt)); + return genStmtList.back(); +} + +FEIRStmt *FEFunction::RegisterFEIRStmt(UniqueFEIRStmt stmt) { + feirStmtList.push_back(std::move(stmt)); + return feirStmtList.back().get(); +} + +FEIRBB *FEFunction::RegisterFEIRBB(std::unique_ptr bb) { + feirBBList.push_back(std::move(bb)); + return feirBBList.back().get(); +} + +void FEFunction::DumpGeneralStmts() { + FELinkListNode *nodeStmt = genStmtHead; + while (nodeStmt != nullptr) { + FEIRStmt *stmt = static_cast(nodeStmt); + stmt->Dump(); + nodeStmt = nodeStmt->GetNext(); + } +} + +bool FEFunction::LowerFunc(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + if (feirLower == nullptr) { + feirLower = std::make_unique(*this); + feirLower->LowerFunc(); + feirStmtHead = feirLower->GetlowerStmtHead(); + feirStmtTail = feirLower->GetlowerStmtTail(); + } + return phaseResult.Finish(); +} + +bool FEFunction::DumpFEIRBBs(const std::string &phaseName) { + HIR2MPL_PARALLEL_FORBIDDEN(); + phaseResult.RegisterPhaseNameAndStart(phaseName); + if (feirCFG == nullptr) { + feirCFG = std::make_unique(feirStmtHead, feirStmtTail); + feirCFG->GenerateCFG(); + } + std::cout << "****** CFG built by FEIR for " << GetGeneralFuncName() << " *******\n"; + feirCFG->DumpBBs(); + std::cout << "****** END CFG built for " << GetGeneralFuncName() << " *******\n\n"; + return phaseResult.Finish(); +} + +bool FEFunction::DumpFEIRCFGGraph(const std::string &phaseName) { + HIR2MPL_PARALLEL_FORBIDDEN(); + phaseResult.RegisterPhaseNameAndStart(phaseName); + std::string outName = FEManager::GetModule().GetFileName(); + size_t lastDot = outName.find_last_of("."); + if (lastDot != std::string::npos) { + outName = outName.substr(0, lastDot); + } + CHECK_FATAL(!outName.empty(), "General CFG Graph FileName is empty"); + std::string fileName = outName + "." + GetGeneralFuncName() + ".dot"; + std::ofstream file(fileName); + CHECK_FATAL(file.is_open(), "Failed to open General CFG Graph FileName: %s", fileName.c_str()); + if (feirCFG == nullptr) { + feirCFG = std::make_unique(feirStmtHead, feirStmtTail); + feirCFG->GenerateCFG(); + } + file << "digraph {" << std::endl; + file << " label=\"" << GetGeneralFuncName() << "\"\n"; + file << " labelloc=t\n"; + feirCFG->DumpCFGGraph(file); + file.close(); + return phaseResult.Finish(); +} + +void FEFunction::DumpFEIRCFGGraphForDFGEdge(std::ofstream &file) { + file << " subgraph cfg_edges {" << std::endl; + file << " edge [color=\"#00FF00\",weight=0.3,len=3];" << std::endl; + file << " }" << std::endl; +} + +bool FEFunction::BuildGeneralStmtBBMap(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + FELinkListNode *nodeBB = genBBHead->GetNext(); + while (nodeBB != nullptr && nodeBB != genBBTail) { + FEIRBB *bb = static_cast(nodeBB); + const FELinkListNode *nodeStmt = bb->GetStmtHead(); + while (nodeStmt != nullptr) { + const FEIRStmt *stmt = static_cast(nodeStmt); + genStmtBBMap[stmt] = bb; + if (nodeStmt == bb->GetStmtTail()) { + break; + } + nodeStmt = nodeStmt->GetNext(); + } + nodeBB = nodeBB->GetNext(); + } + return phaseResult.Finish(); +} + +bool FEFunction::LabelGeneralStmts(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + uint32 idx = 0; + FELinkListNode *nodeStmt = genStmtHead; + while (nodeStmt != nullptr) { + FEIRStmt *stmt = static_cast(nodeStmt); + stmt->SetID(idx); + idx++; + nodeStmt = nodeStmt->GetNext(); + } + return phaseResult.Finish(); +} + +bool FEFunction::LabelFEIRBBs(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + uint32 idx = 0; + FELinkListNode *nodeBB = genBBHead->GetNext(); + while (nodeBB != nullptr && nodeBB != genBBTail) { + FEIRBB *bb = static_cast(nodeBB); + bb->SetID(idx); + idx++; + nodeBB = nodeBB->GetNext(); + } + return phaseResult.Finish(); +} + +std::string FEFunction::GetGeneralFuncName() const { + return mirFunction.GetName(); +} + +void FEFunction::PhaseTimerStart(FETimerNS &timer) { + if (!FEOptions::GetInstance().IsDumpPhaseTime()) { + return; + } + timer.Start(); +} + +void FEFunction::PhaseTimerStopAndDump(FETimerNS &timer, const std::string &label) { + if (!FEOptions::GetInstance().IsDumpPhaseTime()) { + return; + } + timer.Stop(); + INFO(kLncInfo, "[PhaseTime] %s: %lld ns", label.c_str(), timer.GetTimeNS()); +} + +bool FEFunction::UpdateFormal(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + HIR2MPL_PARALLEL_FORBIDDEN(); + uint32 idx = 0; + mirFunction.ClearFormals(); + FEManager::GetMIRBuilder().SetCurrentFunction(mirFunction); + for (const std::unique_ptr &argVar : argVarList) { + MIRSymbol *sym = argVar->GenerateMIRSymbol(FEManager::GetMIRBuilder()); + sym->SetStorageClass(kScFormal); + mirFunction.AddArgument(sym); + idx++; + } + return phaseResult.Finish(); +} + +std::string FEFunction::GetDescription() { + std::stringstream ss; + std::string oriFuncName = GetGeneralFuncName(); + std::string mplFuncName = namemangler::EncodeName(oriFuncName); + ss << "ori function name: " << oriFuncName << std::endl; + ss << "mpl function name: " << mplFuncName << std::endl; + ss << "parameter list:" << "("; + for (const std::unique_ptr &argVar : argVarList) { + ss << argVar->GetNameRaw() << ", "; + } + ss << ") {" << std::endl; + FELinkListNode *node = feirStmtHead->GetNext(); + while (node != feirStmtTail) { + FEIRStmt *currStmt = static_cast(node); + ss << currStmt->DumpDotString() << std::endl; + node = node->GetNext(); + } + ss << "}" << std::endl; + return ss.str(); +} + +bool FEFunction::EmitToMIR(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + mirFunction.NewBody(); + FEManager::GetMIRBuilder().SetCurrentFunction(mirFunction); + FEManager::SetCurrentFEFunction(*this); + BuildMapLabelIdx(); + EmitToMIRStmt(); + return phaseResult.Finish(); +} + +const FEIRStmtPesudoLOC *FEFunction::GetLOCForStmt(const FEIRStmt &feIRStmt) const { + if (!feIRStmt.ShouldHaveLOC()) { + return nullptr; + } + FELinkListNode *prevNode = static_cast(feIRStmt.GetPrev()); + while (prevNode != nullptr) { + if ((*static_cast(prevNode)).ShouldHaveLOC()) { + return nullptr; + } + FEIRStmt *stmt = static_cast(prevNode); + if (stmt->GetKind() == kStmtPesudoLOC) { + FEIRStmtPesudoLOC *loc = static_cast(stmt); + return loc; + } + prevNode = prevNode->GetPrev(); + } + return nullptr; +} + +void FEFunction::BuildMapLabelIdx() { + FELinkListNode *nodeStmt = feirStmtHead->GetNext(); + while (nodeStmt != nullptr && nodeStmt != feirStmtTail) { + FEIRStmt *stmt = static_cast(nodeStmt); + if (stmt->GetKind() == FEIRNodeKind::kStmtPesudoLabel) { + FEIRStmtPesudoLabel *stmtLabel = static_cast(stmt); + stmtLabel->GenerateLabelIdx(FEManager::GetMIRBuilder()); + mapLabelIdx[stmtLabel->GetLabelIdx()] = stmtLabel->GetMIRLabelIdx(); + } + nodeStmt = nodeStmt->GetNext(); + } +} + +bool FEFunction::CheckPhaseResult(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + bool success = phaseResult.IsSuccess(); + return phaseResult.Finish(success); +} + +bool FEFunction::ProcessFEIRFunction() { + bool success = true; + success = success && BuildMapLabelStmt("fe/build map label stmt"); + success = success && SetupFEIRStmtJavaTry("fe/setup stmt javatry"); + success = success && SetupFEIRStmtBranch("fe/setup stmt branch"); + success = success && UpdateRegNum2This("fe/update reg num to this pointer"); + return success; +} + +bool FEFunction::BuildMapLabelStmt(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + FELinkListNode *nodeStmt = feirStmtHead->GetNext(); + while (nodeStmt != nullptr && nodeStmt != feirStmtTail) { + FEIRStmt *stmt = static_cast(nodeStmt); + FEIRNodeKind kind = stmt->GetKind(); + switch (kind) { + case FEIRNodeKind::kStmtPesudoLabel: + case FEIRNodeKind::kStmtPesudoJavaCatch: { + FEIRStmtPesudoLabel *stmtLabel = static_cast(stmt); + mapLabelStmt[stmtLabel->GetLabelIdx()] = stmtLabel; + break; + } + default: + break; + } + nodeStmt = nodeStmt->GetNext(); + } + return phaseResult.Finish(); +} + +bool FEFunction::SetupFEIRStmtJavaTry(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + FELinkListNode *nodeStmt = feirStmtHead->GetNext(); + while (nodeStmt != nullptr && nodeStmt != feirStmtTail) { + FEIRStmt *stmt = static_cast(nodeStmt); + if (stmt->GetKind() == FEIRNodeKind::kStmtPesudoJavaTry) { + FEIRStmtPesudoJavaTry *stmtJavaTry = static_cast(stmt); + for (uint32 labelIdx : stmtJavaTry->GetCatchLabelIdxVec()) { + auto it = mapLabelStmt.find(labelIdx); + CHECK_FATAL(it != mapLabelStmt.end(), "label is not found"); + stmtJavaTry->AddCatchTarget(*(it->second)); + } + } + nodeStmt = nodeStmt->GetNext(); + } + return phaseResult.Finish(); +} + +bool FEFunction::SetupFEIRStmtBranch(const std::string &phaseName) { + phaseResult.RegisterPhaseNameAndStart(phaseName); + bool success = true; + FELinkListNode *nodeStmt = feirStmtHead->GetNext(); + while (nodeStmt != nullptr && nodeStmt != feirStmtTail) { + FEIRStmt *stmt = static_cast(nodeStmt); + FEIRNodeKind kind = stmt->GetKind(); + switch (kind) { + case FEIRNodeKind::kStmtGoto: + case FEIRNodeKind::kStmtCondGoto: + success = success && SetupFEIRStmtGoto(*(static_cast(stmt))); + break; + case FEIRNodeKind::kStmtSwitch: + success = success && SetupFEIRStmtSwitch(*(static_cast(stmt))); + break; + default: + break; + } + nodeStmt = nodeStmt->GetNext(); + } + return phaseResult.Finish(success); +} + +bool FEFunction::SetupFEIRStmtGoto(FEIRStmtGoto &stmt) { + auto it = mapLabelStmt.find(stmt.GetLabelIdx()); + if (it == mapLabelStmt.end()) { + ERR(kLncErr, "target not found for stmt goto"); + return false; + } + stmt.SetStmtTarget(*(it->second)); + return true; +} + +bool FEFunction::SetupFEIRStmtSwitch(FEIRStmtSwitch &stmt) { + // default target + auto itDefault = mapLabelStmt.find(stmt.GetDefaultLabelIdx()); + if (itDefault == mapLabelStmt.end()) { + ERR(kLncErr, "target not found for stmt goto"); + return false; + } + stmt.SetDefaultTarget(*(itDefault->second)); + + // value targets + for (const auto &itItem : stmt.GetMapValueLabelIdx()) { + auto itTarget = mapLabelStmt.find(itItem.second); + if (itTarget == mapLabelStmt.end()) { + ERR(kLncErr, "target not found for stmt goto"); + return false; + } + stmt.AddTarget(itItem.first, *(itTarget->second)); + } + return true; +} + +bool FEFunction::UpdateRegNum2This(const std::string &phaseName) { + bool success = CheckPhaseResult(phaseName); + if (!success) { + return success; + } + if (!HasThis()) { + return success; + } + const std::unique_ptr &firstArg = argVarList.front(); + std::unique_ptr varReg = firstArg->Clone(); + GStrIdx thisNameIdx = FEUtils::GetThisIdx(); + std::unique_ptr varThisAsParam = std::make_unique(thisNameIdx, varReg->GetType()->Clone()); + if (!IsNative()) { + std::unique_ptr varThisAsLocalVar = std::make_unique(thisNameIdx, varReg->GetType()->Clone()); + std::unique_ptr dReadThis = std::make_unique(std::move(varThisAsLocalVar)); + std::unique_ptr daStmt = std::make_unique(std::move(varReg), std::move(dReadThis)); + FEIRStmt *stmt = RegisterFEIRStmt(std::move(daStmt)); + FELinkListNode::InsertAfter(stmt, feirStmtHead); + } + argVarList[0].reset(varThisAsParam.release()); + return success; +} + +void FEFunction::OutputStmts() { + FELinkListNode *node = feirStmtHead->GetNext(); + while (node != feirStmtTail) { + FEIRStmt *currStmt = static_cast(node); + LogInfo::MapleLogger() << currStmt->DumpDotString() << "\n"; + node = node->GetNext(); + } +} + +void FEFunction::LabelFEIRStmts() { + // stmt idx start from 1 + FELinkListNode *node = feirStmtHead->GetNext(); + uint32 id = 1; + while (node != feirStmtTail) { + FEIRStmt *currStmt = static_cast(node); + currStmt->SetID(id++); + node = node->GetNext(); + } + stmtCount = --id; +} + +bool FEFunction::ShouldNewBB(const FEIRBB *currBB, const FEIRStmt &currStmt) const { + if (currBB == nullptr) { + return true; + } + if (currStmt.IsTarget()) { + if (currBB->GetStmtNoAuxTail() != nullptr) { + return true; + } + } + return false; +} + +bool FEFunction::IsBBEnd(const FEIRStmt &stmt) const { + bool currStmtMayBeBBEnd = MayBeBBEnd(stmt); + if (currStmtMayBeBBEnd) { + FELinkListNode *node = stmt.GetNext(); + FEIRStmt *nextStmt = static_cast(node); + if (nextStmt->IsAuxPost()) { // if curr stmt my be BB end, but next stmt is AuxPost + return false; // curr stmt should not be BB end + } + return true; + } + if (stmt.IsAuxPost()) { + FELinkListNode *node = stmt.GetPrev(); + FEIRStmt *prevStmt = static_cast(node); + bool prevStmtMayBeBBEnd = MayBeBBEnd(*prevStmt); // if curr stmt is AuxPost, and prev stmt my be BB end + return prevStmtMayBeBBEnd; // return prev stmt my be BB end as result + } + return currStmtMayBeBBEnd; +} + +bool FEFunction::MayBeBBEnd(const FEIRStmt &stmt) const { + return (stmt.IsBranch() || !stmt.IsFallThru()); +} + +void FEFunction::LinkFallThroughBBAndItsNext(FEIRBB &bb) { + if (!CheckBBsStmtNoAuxTail(bb)) { + return; + } + if (!bb.IsFallThru()) { + return; + } + FELinkListNode *node = bb.GetNext(); + FEIRBB *nextBB = static_cast(node); + if (nextBB != feirBBTail) { + LinkBB(bb, *nextBB); + } +} + +void FEFunction::LinkBranchBBAndItsTargets(FEIRBB &bb) { + if (!CheckBBsStmtNoAuxTail(bb)) { + return; + } + if (!bb.IsBranch()) { + return; + } + const FEIRStmt *stmtTail = bb.GetStmtNoAuxTail(); + FEIRNodeKind nodeKind = stmtTail->GetKind(); + switch (nodeKind) { + case FEIRNodeKind::kStmtCondGoto: + // should fallthrough + [[fallthrough]]; + case FEIRNodeKind::kStmtGoto: { + LinkGotoBBAndItsTarget(bb, *stmtTail); + break; + } + case FEIRNodeKind::kStmtSwitch: { + LinkSwitchBBAndItsTargets(bb, *stmtTail); + break; + } + default: { + CHECK_FATAL(false, "nodeKind %u is not branch", nodeKind); + break; + } + } +} + +void FEFunction::LinkGotoBBAndItsTarget(FEIRBB &bb, const FEIRStmt &stmtTail) { + const FEIRStmtGoto2 &gotoStmt = static_cast(stmtTail); + const FEIRStmtPesudoLabel2 &targetStmt = gotoStmt.GetStmtTargetRef(); + FEIRBB &targetBB = GetFEIRBBByStmt(targetStmt); + LinkBB(bb, targetBB); +} + +void FEFunction::LinkSwitchBBAndItsTargets(FEIRBB &bb, const FEIRStmt &stmtTail) { + const FEIRStmtSwitch2 &switchStmt = static_cast(stmtTail); + const std::map &mapValueTargets = switchStmt.GetMapValueTargets(); + for (auto it : mapValueTargets) { + FEIRStmtPesudoLabel2 *pesudoLabel = it.second; + FEIRBB &targetBB = GetFEIRBBByStmt(*pesudoLabel); + LinkBB(bb, targetBB); + } + FEIRBB &targetBB = GetFEIRBBByStmt(switchStmt.GetDefaultTarget()); + LinkBB(bb, targetBB); +} + +void FEFunction::LinkBB(FEIRBB &predBB, FEIRBB &succBB) { + predBB.AddSuccBB(&succBB); + succBB.AddPredBB(&predBB); +} + +FEIRBB &FEFunction::GetFEIRBBByStmt(const FEIRStmt &stmt) { + auto it = feirStmtBBMap.find(&stmt); + return *(it->second); +} + +bool FEFunction::CheckBBsStmtNoAuxTail(const FEIRBB &bb) { + bool bbHasStmtNoAuxTail = (bb.GetStmtNoAuxTail() != nullptr); + CHECK_FATAL(bbHasStmtNoAuxTail, "Error accured in BuildFEIRBB phase, bb.GetStmtNoAuxTail() should not be nullptr"); + return true; +} + +void FEFunction::InsertCheckPointForBBs() { + FELinkListNode *node = feirBBHead->GetNext(); + while (node != feirBBTail) { + FEIRBB *currBB = static_cast(node); // get currBB + // create chekPointIn + std::unique_ptr chekPointIn = std::make_unique(); + currBB->SetCheckPointIn(std::move(chekPointIn)); // set to currBB's checkPointIn + FEIRStmtCheckPoint &cpIn = currBB->GetCheckPointIn(); + currBB->InsertAndUpdateNewHead(&cpIn); // insert and update new head to chekPointIn + (void)feirStmtBBMap.insert(std::make_pair(&cpIn, currBB)); // add pair to feirStmtBBMap + // create chekPointOut + std::unique_ptr chekPointOut = std::make_unique(); + currBB->SetCheckPointOut(std::move(chekPointOut)); // set to currBB's checkPointOut + FEIRStmtCheckPoint &cpOut = currBB->GetCheckPointOut(); + currBB->InsertAndUpdateNewTail(&cpOut); // insert and update new tail to chekPointOut + (void)feirStmtBBMap.insert(std::make_pair(&cpOut, currBB)); // add pair to feirStmtBBMap + // get next BB + node = node->GetNext(); + } +} + +void FEFunction::InsertCheckPointForTrys() { + FEIRStmtPesudoJavaTry2 *currTry = nullptr; + FEIRStmtCheckPoint *checkPointInTry = nullptr; + FELinkListNode *node = feirStmtHead->GetNext(); + while (node != feirStmtTail) { + FEIRStmt *currStmt = static_cast(node); + if (currStmt->GetKind() == FEIRNodeKind::kStmtPesudoJavaTry) { + currTry = static_cast(currStmt); + checkPointInTry = nullptr; + } + if ((currTry != nullptr) && + (currStmt->IsThrowable()) && + ((checkPointInTry == nullptr) || currStmt->HasDef())) { + FEIRBB &currBB = GetFEIRBBByStmt(*currStmt); + if (currStmt == currBB.GetStmtNoAuxHead()) { + checkPointInTry = &(currBB.GetCheckPointIn()); + (void)checkPointJavaTryMap.insert(std::make_pair(checkPointInTry, currTry)); + if (currStmt == currBB.GetStmtHead()) { + currBB.SetStmtHead(currStmt); + } + node = node->GetNext(); + continue; + } + std::unique_ptr newCheckPoint = std::make_unique(); + currBB.AddCheckPoint(std::move(newCheckPoint)); + checkPointInTry = currBB.GetLatestCheckPoint(); + CHECK_NULL_FATAL(checkPointInTry); + FELinkListNode::InsertBefore(checkPointInTry, currStmt); + (void)feirStmtBBMap.insert(std::make_pair(checkPointInTry, &currBB)); + (void)checkPointJavaTryMap.insert(std::make_pair(checkPointInTry, currTry)); + if (currStmt == currBB.GetStmtHead()) { + currBB.SetStmtHead(currStmt); + } + } + if (currStmt->GetKind() == FEIRNodeKind::kStmtPesudoEndTry) { + currTry = nullptr; + } + node = node->GetNext(); + } +} + +void FEFunction::InitTrans4AllVars() { + FELinkListNode *node = feirStmtHead->GetNext(); + while (node != feirStmtTail) { + FEIRStmt *currStmt = static_cast(node); + currStmt->InitTrans4AllVars(); + node = node->GetNext(); + } +} + +FEIRStmtPesudoJavaTry2 &FEFunction::GetJavaTryByCheckPoint(FEIRStmtCheckPoint &checkPoint) { + auto it = checkPointJavaTryMap.find(&checkPoint); + return *(it->second); +} + +FEIRStmtCheckPoint &FEFunction::GetCheckPointByFEIRStmt(const FEIRStmt &stmt) { + auto it = feirStmtCheckPointMap.find(&stmt); + return *(it->second); +} + +void FEFunction::SetUpDefVarTypeScatterStmtMap() { + FELinkListNode *node = feirStmtHead->GetNext(); + while (node != feirStmtTail) { + FEIRStmt *currStmt = static_cast(node); + FEIRVarTypeScatter *defVarTypeScatter = currStmt->GetTypeScatterDefVar(); + if (defVarTypeScatter != nullptr) { + (void)defVarTypeScatterStmtMap.insert(std::make_pair(defVarTypeScatter, currStmt)); + } + node = node->GetNext(); + } +} + +void FEFunction::InsertRetypeStmtsAfterDef(const UniqueFEIRVar& def) { + bool defIsTypeScatter = (def->GetKind() == kFEIRVarTypeScatter); + if (!defIsTypeScatter) { + return; + } + FEIRVarTypeScatter &fromVar = *(static_cast(def.get())); + const std::unordered_set &scatterTypes = fromVar.GetScatterTypes(); + for (auto &it : scatterTypes) { + const maple::FEIRTypeKey &typeKey = it; + FEIRType &toType = *(typeKey.GetType()); + FEIRType &fromType = *(fromVar.GetType()); + Opcode opcode = FEIRTypeCvtHelper::ChooseCvtOpcodeByFromTypeAndToType(fromType, toType); + if (opcode == OP_retype) { + InsertRetypeStmt(fromVar, toType); + } else if (opcode == OP_cvt) { + InsertCvtStmt(fromVar, toType); + } else { + InsertJavaMergeStmt(fromVar, toType); + } + } +} + +void FEFunction::InsertRetypeStmt(const FEIRVarTypeScatter &fromVar, const FEIRType &toType) { + // create DRead Expr + std::unique_ptr exprDRead = std::make_unique(fromVar.GetVar()->Clone()); + std::unique_ptr typeDst = FEIRTypeHelper::CreatePointerType(toType.Clone(), toType.GetPrimType()); + // create expr for retype + std::unique_ptr expr = std::make_unique(std::move(typeDst), OP_retype, + std::move(exprDRead)); + // after expr created, insert dassign stmt + InsertDAssignStmt4TypeCvt(fromVar, toType, std::move(expr)); +} + +void FEFunction::InsertCvtStmt(const FEIRVarTypeScatter &fromVar, const FEIRType &toType) { + // create DRead Expr + std::unique_ptr exprDRead = std::make_unique(fromVar.GetVar()->Clone()); + // create expr for type cvt + std::unique_ptr expr = std::make_unique(OP_cvt, std::move(exprDRead)); + expr->GetType()->SetPrimType(toType.GetPrimType()); + // after expr created, insert dassign stmt + InsertDAssignStmt4TypeCvt(fromVar, toType, std::move(expr)); +} + +void FEFunction::InsertJavaMergeStmt(const FEIRVarTypeScatter &fromVar, const FEIRType &toType) { + // create DRead Expr + std::unique_ptr exprDRead = std::make_unique(fromVar.GetVar()->Clone()); + // create expr for java merge + std::vector> argOpnds; + argOpnds.push_back(std::move(exprDRead)); + std::unique_ptr javaMergeExpr = std::make_unique(toType.Clone(), argOpnds); + // after expr created, insert dassign stmt + InsertDAssignStmt4TypeCvt(fromVar, toType, std::move(javaMergeExpr)); +} + +void FEFunction::InsertDAssignStmt4TypeCvt(const FEIRVarTypeScatter &fromVar, const FEIRType &toType, + UniqueFEIRExpr expr) { + FEIRVar *var = fromVar.GetVar().get(); + CHECK_FATAL((var->GetKind() == FEIRVarKind::kFEIRVarReg), "fromVar's inner var must be var reg kind"); + FEIRVarReg *varReg = static_cast(var); + uint32 regNum = varReg->GetRegNum(); + UniqueFEIRVar toVar = FEIRBuilder::CreateVarReg(regNum, toType.Clone()); + std::unique_ptr daStmt = std::make_unique(std::move(toVar), std::move(expr)); + FEIRStmt *insertedStmt = RegisterFEIRStmt(std::move(daStmt)); + FEIRStmt &stmt = GetStmtByDefVarTypeScatter(fromVar); + FELinkListNode::InsertAfter(insertedStmt, &stmt); +} + +FEIRStmt &FEFunction::GetStmtByDefVarTypeScatter(const FEIRVarTypeScatter &varTypeScatter) { + auto it = defVarTypeScatterStmtMap.find(&varTypeScatter); + return *(it->second); +} + +bool FEFunction::WithFinalFieldsNeedBarrier(MIRClassType *classType, bool isStatic) const { + // final field + if (isStatic) { + // final static fields with non-primitive types + // the one with primitive types are all inlined + for (auto it : classType->GetStaticFields()) { + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(it.second.first); + if (it.second.second.GetAttr(FLDATTR_final) && type->GetPrimType() == PTY_ref) { + return true; + } + } + } else { + for (auto it : classType->GetFields()) { + if (it.second.second.GetAttr(FLDATTR_final)) { + return true; + } + } + } + return false; +} + +bool FEFunction::IsNeedInsertBarrier() { + if (mirFunction.GetAttr(FUNCATTR_constructor) || + mirFunction.GetName().find("_7Cclone_7C") != std::string::npos || + mirFunction.GetName().find("_7CcopyOf_7C") != std::string::npos) { + const std::string &className = mirFunction.GetBaseClassName(); + MIRType *type = FEManager::GetTypeManager().GetClassOrInterfaceType(className); + if (type->GetKind() == kTypeClass) { + MIRClassType *currClass = static_cast(type); + if (!mirFunction.GetAttr(FUNCATTR_constructor) || + WithFinalFieldsNeedBarrier(currClass, mirFunction.GetAttr(FUNCATTR_static))) { + return true; + } + } + } + return false; +} + +void FEFunction::EmitToMIRStmt() { + MIRBuilder &builder = FEManager::GetMIRBuilder(); + FELinkListNode *nodeStmt = feirStmtHead->GetNext(); + while (nodeStmt != nullptr && nodeStmt != feirStmtTail) { + FEIRStmt *stmt = static_cast(nodeStmt); + std::list mirStmts = stmt->GenMIRStmts(builder); +#ifdef DEBUG + // LOC info has been recorded in FEIRStmt already, this could be removed later. + AddLocForStmt(*stmt, mirStmts); +#endif + for (StmtNode *mirStmt : mirStmts) { + builder.AddStmtInCurrentFunctionBody(*mirStmt); + } + nodeStmt = nodeStmt->GetNext(); + } +} + +void FEFunction::AddLocForStmt(const FEIRStmt &stmt, std::list &mirStmts) const { + const FEIRStmtPesudoLOC *pesudoLoc = GetLOCForStmt(stmt); + if (pesudoLoc != nullptr) { + mirStmts.front()->GetSrcPos().SetFileNum(static_cast(pesudoLoc->GetSrcFileIdx())); + mirStmts.front()->GetSrcPos().SetLineNum(pesudoLoc->GetSrcFileLineNum()); + } +} +} // namespace maple diff --git a/src/hir2mpl/common/src/fe_function_phase_result.cpp b/src/hir2mpl/common/src/fe_function_phase_result.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bb11b77f15f6cc0680034cc8c9dbb687980990bb --- /dev/null +++ b/src/hir2mpl/common/src/fe_function_phase_result.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_function_phase_result.h" +#include "mpl_logging.h" + +namespace maple { +void FEFunctionPhaseResult::Combine(const FEFunctionPhaseResult &result) { + for (const std::string &name : result.phaseNames) { + auto itResult = result.phaseTimes.find(name); + CHECK_FATAL(itResult != result.phaseTimes.end(), "invalid result: without time recorded"); + int64 t = itResult->second; + auto itLocal = phaseTimes.find(name); + if (itLocal == phaseTimes.end()) { + phaseNames.push_back(name); + phaseTimes[name] = t; + } else { + phaseTimes[name] = itLocal->second + t; + } + } +} + +void FEFunctionPhaseResult::Dump() { + for (const std::string &name :phaseNames) { + auto it = phaseTimes.find(name); + CHECK_FATAL(it != phaseTimes.end(), "phase time is undefined for %s", name.c_str()); + INFO(kLncInfo, "[PhaseTime] %s: %lld ns", name.c_str(), it->second); + } +} + +void FEFunctionPhaseResult::DumpMS() { + for (const std::string &name :phaseNames) { + auto it = phaseTimes.find(name); + CHECK_FATAL(it != phaseTimes.end(), "phase time is undefined for %s", name.c_str()); + INFO(kLncInfo, "[PhaseTime] %s: %.2lf ms", name.c_str(), it->second / 1000000.0); // 1ms = 1000000 ns + } +} + +bool FEFunctionPhaseResult::Finish(bool isSuccess) { + success = isSuccess; + if (enable && recordTime) { + timer.Stop(); + CHECK_FATAL(!currPhaseName.empty(), "Phase Name is empty"); + int64 t = timer.GetTimeNS(); + phaseTimes[currPhaseName] = t; + } + return success; +} +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/common/src/fe_input_helper.cpp b/src/hir2mpl/common/src/fe_input_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71d21bb6534058abc0da97975d4d9508b31e2b4c --- /dev/null +++ b/src/hir2mpl/common/src/fe_input_helper.cpp @@ -0,0 +1,358 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_input_helper.h" +#include "fe_options.h" +#include "fe_manager.h" + +namespace maple { +#define SET_CLASS_INFO_PAIR(A, B, C, D) \ + A->PushbackMIRInfo(MIRInfoPair(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(B), C)); \ + A->PushbackIsString(D) + +std::string FEInputStructHelper::GetSrcFileNameImpl() const { + return "unknown"; +} + +MIRStructType *FEInputStructHelper::GetContainerImpl() { + return mirStructType; +} + +bool FEInputStructHelper::PreProcessDeclImpl() { + bool error = false; + MIRStructType *structType = CreateMIRStructType(error); + if (error) { + return false; + } + isSkipped = (structType == nullptr); + mirStructType = structType; + if (structType != nullptr) { + FETypeManager::SetComplete(*structType); + FEManager::GetTypeManager().AddClassToModule(*structType); + } + return true; +} + +bool FEInputStructHelper::ProcessDeclImpl() { + if (isSkipped) { + return true; + } + if (mirStructType == nullptr) { + return false; + } + if (!FEOptions::GetInstance().IsGenMpltOnly() && !isOnDemandLoad) { + CreateSymbol(); + } + ProcessDeclSuperClass(); + ProcessDeclImplements(); + ProcessDeclDefInfo(); + // Process Fields + InitFieldHelpers(); + ProcessFieldDef(); + ProcessExtraFields(); + if (!FEOptions::GetInstance().IsGenMpltOnly() && !isOnDemandLoad) { + ProcessStaticFields(); + } + // Process Methods + InitMethodHelpers(); + ProcessMethodDef(); + return true; +} + +void FEInputStructHelper::CreateSymbol() { + std::string structNameMpl = GetStructNameMpl(); + mirSymbol = FEManager::GetMIRBuilder().GetOrCreateGlobalDecl(structNameMpl.c_str(), *mirStructType); + switch (mirStructType->GetKind()) { + case kTypeClass: + case kTypeClassIncomplete: + mirSymbol->SetSKind(kStJavaClass); + break; + case kTypeInterface: + case kTypeInterfaceIncomplete: + mirSymbol->SetSKind(kStJavaInterface); + break; + default: + break; + } + mirSymbol->SetAttrs(GetStructAttributeFromInput()); +} + +void FEInputStructHelper::ProcessDeclSuperClass() { + ProcessDeclSuperClassForJava(); +} + +void FEInputStructHelper::ProcessDeclSuperClassForJava() { + const std::list &superNames = GetSuperClassNames(); + ASSERT(superNames.size() <= 1, "there must be zero or one super class for java class: %s", + GetStructNameOrin().c_str()); + if (superNames.size() == 1) { + const std::string &superNameMpl = namemangler::EncodeName(superNames.front()); + bool isCreate = false; + MIRStructType *superType = FEManager::GetTypeManager().GetOrCreateClassOrInterfaceType(superNameMpl, false, + FETypeFlag::kSrcExtern, + isCreate); + if (isCreate) { + // Mark incomplete + } + switch (mirStructType->GetKind()) { + case kTypeClass: + case kTypeClassIncomplete: { + MIRClassType *thisType = static_cast(mirStructType); + thisType->SetParentTyIdx(superType->GetTypeIndex()); + break; + } + case kTypeInterface: + case kTypeInterfaceIncomplete: { + MIRInterfaceType *thisType = static_cast(mirStructType); + if (superType->GetKind() == kTypeInterface) { + thisType->GetParentsTyIdx().push_back(superType->GetTypeIndex()); + } + break; + } + default: + break; + } + } +} + +void FEInputStructHelper::ProcessDeclImplements() { + const std::vector &interfaceNames = GetInterfaceNames(); + std::vector interfaceTypes; + for (const std::string &name : interfaceNames) { + const std::string &interfaceNameMpl = namemangler::EncodeName(name); + bool isCreate = false; + MIRStructType *interfaceType = FEManager::GetTypeManager().GetOrCreateClassOrInterfaceType(interfaceNameMpl, true, + FETypeFlag::kSrcExtern, + isCreate); + if (isCreate) { + // Mark incomplete + } + interfaceTypes.push_back(interfaceType); + } + if (interfaceTypes.size() > 0) { + switch (mirStructType->GetKind()) { + case kTypeClass: + case kTypeClassIncomplete: { + MIRClassType *thisType = static_cast(mirStructType); + for (MIRStructType *type : interfaceTypes) { + thisType->GetInterfaceImplemented().push_back(type->GetTypeIndex()); + } + break; + } + case kTypeInterface: + case kTypeInterfaceIncomplete: { + MIRInterfaceType *thisType = static_cast(mirStructType); + for (MIRStructType *type : interfaceTypes) { + thisType->GetParentsTyIdx().push_back(type->GetTypeIndex()); + } + break; + } + default: + break; + } + } +} + +void FEInputStructHelper::ProcessDeclDefInfo() { + // INFO_srcfile + std::string srcFileName = GetSourceFileName(); + if (!srcFileName.empty()) { + GStrIdx srcFileNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(srcFileName); + SET_CLASS_INFO_PAIR(mirStructType, "INFO_srcfile", srcFileNameIdx.GetIdx(), true); + } + // INFO_classname + std::string classNameMpl = GetStructNameMpl(); + GStrIdx classNameMplIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(classNameMpl); + SET_CLASS_INFO_PAIR(mirStructType, "INFO_classname", classNameMplIdx.GetIdx(), true); + // INFO_classnameorig + std::string classNameOrig = GetStructNameOrin(); + GStrIdx classNameOrigIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(classNameOrig); + SET_CLASS_INFO_PAIR(mirStructType, "INFO_classnameorig", classNameOrigIdx.GetIdx(), true); + if (srcLang == kSrcLangJava) { + // INFO_superclassname + ProcessDeclDefInfoSuperNameForJava(); + // INFO_implements + ProcessDeclDefInfoImplementNameForJava(); + } + // INFO_attribute_string + TypeAttrs attrs = GetStructAttributeFromInput(); + std::string attrsName = FETypeManager::TypeAttrsToString(attrs); + GStrIdx attrsNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(attrsName); + SET_CLASS_INFO_PAIR(mirStructType, "INFO_attribute_string", attrsNameIdx.GetIdx(), true); + // INFO_access_flags + SET_CLASS_INFO_PAIR(mirStructType, "INFO_access_flags", GetRawAccessFlags(), false); + // INFO_ir_srcfile_signature + SET_CLASS_INFO_PAIR(mirStructType, "INFO_ir_srcfile_signature", GetIRSrcFileSigIdx(), true); +} + +void FEInputStructHelper::ProcessDeclDefInfoSuperNameForJava() { + std::list superNames = GetSuperClassNames(); + if (superNames.size() > 1) { + ASSERT(false, "There is one super class at most in java"); + return; + } + std::string superName = superNames.size() == 0 ? "unknown" : superNames.front(); + std::string superNameMpl = namemangler::EncodeName(superName); + GStrIdx superNameMplIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(superNameMpl.c_str()); + SET_CLASS_INFO_PAIR(mirStructType, "INFO_superclassname", superNameMplIdx.GetIdx(), true); +} + +void FEInputStructHelper::ProcessDeclDefInfoImplementNameForJava() { + MIRTypeKind kind = mirStructType->GetKind(); + if (kind == kTypeInterface || kind == kTypeInterfaceIncomplete) { + return; + } + std::vector implementNames = GetInterfaceNames(); + for (const std::string &name : implementNames) { + if (!name.empty()) { + std::string nameMpl = namemangler::EncodeName(name); + GStrIdx nameMplIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(nameMpl.c_str()); + SET_CLASS_INFO_PAIR(mirStructType, "INFO_implements", nameMplIdx.GetIdx(), true); + } + } +} + +void FEInputStructHelper::ProcessStaticFields() { + uint32 i = 0; + FieldVector::iterator it; + for (it = mirStructType->GetStaticFields().begin(); it != mirStructType->GetStaticFields().end(); ++i, ++it) { + StIdx stIdx = GlobalTables::GetGsymTable().GetStIdxFromStrIdx(it->first); + const std::string &fieldName = GlobalTables::GetStrTable().GetStringFromStrIdx(it->first); + MIRConst *cst = nullptr; + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(it->second.first); + MapleAllocator &alloc = FEManager::GetModule().GetMPAllocator(); + if (i < staticFieldsConstVal.size()) { + cst = staticFieldsConstVal[i]; + if (cst != nullptr && cst->GetKind() == kConstStr16Const) { + std::u16string str16 = + GlobalTables::GetU16StrTable().GetStringFromStrIdx(static_cast(cst)->GetValue()); + MIRSymbol *literalVar = FEManager::GetJavaStringManager().GetLiteralVar(str16); + if (literalVar == nullptr) { + literalVar = FEManager::GetJavaStringManager().CreateLiteralVar(FEManager::GetMIRBuilder(), str16, true); + } + AddrofNode *expr = FEManager::GetMIRBuilder().CreateExprAddrof(0, *literalVar, + FEManager::GetModule().GetMemPool()); + MIRType *ptrType = GlobalTables::GetTypeTable().GetTypeTable()[PTY_ptr]; + cst = alloc.GetMemPool()->New(expr->GetStIdx(), expr->GetFieldID(), *ptrType); + } + } + MIRSymbol *fieldVar = GlobalTables::GetGsymTable().GetSymbolFromStidx(stIdx.Idx()); + if (fieldVar == nullptr) { + fieldVar = FEManager::GetMIRBuilder().GetOrCreateGlobalDecl(fieldName, *type); + fieldVar->SetAttrs(it->second.second.ConvertToTypeAttrs()); + } + if (cst != nullptr) { + fieldVar->SetKonst(cst); + } + } +} + +void FEInputStructHelper::ProcessFieldDef() { + for (FEInputFieldHelper *fieldHelper : fieldHelpers) { + bool success = fieldHelper->ProcessDeclWithContainer(allocator); + if (success) { + if (fieldHelper->IsStatic()) { + mirStructType->GetStaticFields().push_back(fieldHelper->GetMIRFieldPair()); + } else { + mirStructType->GetFields().push_back(fieldHelper->GetMIRFieldPair()); + } + } else { + ERR(kLncErr, "Error occurs in ProcessFieldDef for %s", GetStructNameOrin().c_str()); + } + } +} + +void FEInputStructHelper::ProcessExtraFields() { + // add to this set to add extrafield into a class, in this format: classname, fieldname, type, attributes + std::vector extraFields = { + { "Lcom_2Fandroid_2Finternal_2Fos_2FBinderCallsStats_3B", "mCallSessionsPoolSize", "i32", "private" }, + { "Ljava_2Flang_2FObject_3B", "shadow_24__klass__", "Ljava_2Flang_2FClass_3B", "private transient final" }, + }; + for (auto it = extraFields.begin(); it != extraFields.end(); ++it) { + bool isCreat = false; + MIRStructType *structType = FEManager::GetTypeManager().GetOrCreateClassOrInterfaceType(it->klass, + false, FETypeFlag::kSrcUnknown, isCreat); + if (structType->IsImported()) { + continue; + } + GStrIdx fieldStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(it->field); + MIRType *fieldType = FEManager::GetTypeManager().GetOrCreateTypeFromName(it->type, FETypeFlag::kSrcUnknown, true); + std::vector attrs = FEUtils::Split(it->attr, ' '); + FieldAttrs typeAttrs; + for (auto ait = attrs.begin(); ait != attrs.end(); ++ait) { + FEInputFieldHelper::SetFieldAttribute(*ait, typeAttrs); + } + for (auto fit = structType->GetFields().begin(); fit != structType->GetFields().end(); ++fit) { + if (fit->first == fieldStrIdx) { + (void)structType->GetFields().erase(fit); + break; + } + } + // insert at the beginning + structType->GetFields().insert(structType->GetFields().begin(), + FieldPair(fieldStrIdx, TyIdxFieldAttrPair(fieldType->GetTypeIndex(), typeAttrs))); + } +} + +void FEInputStructHelper::ProcessMethodDef() { + for (FEInputMethodHelper *methodHelper : methodHelpers) { + bool success = methodHelper->ProcessDecl(allocator); + if (success) { + mirStructType->GetMethods().push_back(methodHelper->GetMIRMethodPair()); + methodHelper->SetClassTypeInfo(*mirStructType); + } else { + ERR(kLncErr, "Error occurs in ProcessMethodDef for %s", GetStructNameOrin().c_str()); + } + } +} + +void FEInputStructHelper::ProcessPragma() { + if (isSkipped) { + return; + } + std::vector pragmas = pragmaHelper->GenerateMIRPragmas(); + std::vector &pragmaVec = mirStructType->GetPragmaVec(); + for (MIRPragma *pragma : pragmas) { + pragmaVec.push_back(pragma); + } +} + +// ---------- FEInputMethodHelper ---------- +bool FEInputMethodHelper::ProcessDeclImpl(MapleAllocator &allocatorIn) { + (void)allocatorIn; + CHECK_FATAL(false, "NYI"); + return true; +} + +// ---------- FEInputHelper ---------- +bool FEInputHelper::PreProcessDecl() { + bool success = true; + for (FEInputStructHelper *helper : structHelpers) { + success = helper->PreProcessDecl() ? success : false; + } + return success; +} + +bool FEInputHelper::ProcessDecl() { + bool success = true; + for (FEInputStructHelper *helper : structHelpers) { + success = helper->ProcessDecl() ? success : false; + } + return success; +} + +bool FEInputHelper::ProcessImpl() const { + return true; +} +} diff --git a/src/hir2mpl/common/src/fe_java_string_manager.cpp b/src/hir2mpl/common/src/fe_java_string_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a1f5c6817a5fcd9edb7bcd10f49713a88cd62e5 --- /dev/null +++ b/src/hir2mpl/common/src/fe_java_string_manager.cpp @@ -0,0 +1,291 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_java_string_manager.h" +#include +#include "global_tables.h" +#include "namemangler.h" +#include "muid.h" +#include "literalstrname.h" +#include "fe_config_parallel.h" +#include "feir_type.h" +#include "fe_manager.h" +#include "fe_options.h" + +namespace maple { +FEJavaStringManager::FEJavaStringManager(MIRModule &argModule, MIRBuilder &mirBuilderIn) + : module(argModule), mirBuilder(mirBuilderIn) { +} + +FEJavaStringManager::~FEJavaStringManager() { + typeString = nullptr; +} + +void FEJavaStringManager::LoadProfilingData(const std::string &profileFileName) { + std::ifstream inFile(profileFileName); + if (!inFile.is_open()) { + WARN(kLncWarn, "Cannot open literal profile data file %s", profileFileName.c_str()); + return; + } + std::string literalName; + while (std::getline(inFile, literalName)) { + if (!literalName.empty()) { + (void)preloadSet.insert(literalName); + } + } + inFile.close(); +} + +MIRSymbol *FEJavaStringManager::GetLiteralPtrVar(const MIRSymbol *var) const { + auto it = literalMap.find(var); + if (it != literalMap.end()) { + return it->second; + } else { + return nullptr; + } +} + +MIRSymbol *FEJavaStringManager::GetLiteralPtrVar(const std::string &str) const { + MIRSymbol *literalVar = GetLiteralVar(str); + return GetLiteralPtrVar(literalVar); +} + +MIRSymbol *FEJavaStringManager::GetLiteralPtrVar(const std::u16string &strU16) const { + MIRSymbol *literalVar = GetLiteralVar(strU16); + return GetLiteralPtrVar(literalVar); +} + +MIRSymbol *FEJavaStringManager::CreateLiteralVar(MIRBuilder &mirBuilderIn, const std::string &str, bool isFieldValue) { + std::u16string strU16; + (void)namemangler::UTF8ToUTF16(strU16, str); + return CreateLiteralVar(mirBuilderIn, strU16, isFieldValue); +} + +MIRSymbol *FEJavaStringManager::CreateLiteralVar(MIRBuilder &mirBuilderIn, const std::u16string &strU16, + bool isFieldValue) { + HIR2MPL_PARALLEL_FORBIDDEN(); + if (typeString == nullptr) { + FEIRTypeDefault type(PTY_ref); + type.LoadFromJavaTypeName("Ljava/lang/String;", false); + typeString = type.GenerateMIRTypeAuto(kSrcLangJava); + } + MIRSymbol *literalVar = GetLiteralVar(strU16); + if (literalVar != nullptr) { + return literalVar; + } + std::string literalGlobalName = GetLiteralGlobalName(strU16); + bool compress = useCompressedJavaString && IsAllASCII(strU16); + MIRArrayType *byteArrayType = ConstructArrayType4Str(strU16, compress); + literalVar = mirBuilderIn.GetOrCreateGlobalDecl(literalGlobalName.c_str(), *byteArrayType); + MIRAggConst *strConst = CreateByteArrayConst(strU16, *byteArrayType, compress); + literalVar->SetKonst(strConst); + literalVar->SetAttr(ATTR_readonly); + literalVar->SetStorageClass(kScFstatic); + bool isHotLiteral = false; + if (preloadSet.find(literalGlobalName) != preloadSet.end()) { + isHotLiteral = true; + (void)literalSet.insert(literalVar); + } + if (isFieldValue) { + (void)fieldValueSet.insert(literalVar); + } + if ((isFieldValue || isHotLiteral) && (!FEOptions::GetInstance().IsAOT())) { + std::string literalGlobalPtrName = namemangler::kPtrPrefixStr + literalGlobalName; + MIRSymbol *literalVarPtr = mirBuilderIn.GetOrCreateGlobalDecl(literalGlobalPtrName.c_str(), *typeString); + literalVarPtr->SetStorageClass(literalVar->GetStorageClass()); + AddrofNode *expr = mirBuilderIn.CreateExprAddrof(0, *literalVar, module.GetMemPool()); + MIRConst *cst = module.GetMemPool()->New( + expr->GetStIdx(), expr->GetFieldID(), *GlobalTables::GetTypeTable().GetPtr()); + literalVarPtr->SetKonst(cst); + literalVarPtr->SetAttr(ATTR_readonly); + literalMap[literalVar] = literalVarPtr; + } + (void)GlobalTables::GetConstPool().GetConstU16StringPool().insert(std::make_pair(strU16, literalVar)); + return literalVar; +} + +MIRSymbol *FEJavaStringManager::GetLiteralVar(const std::string &str) const { + std::u16string strU16; + (void)namemangler::UTF8ToUTF16(strU16, str); + return GetLiteralVar(strU16); +} + +MIRSymbol *FEJavaStringManager::GetLiteralVar(const std::u16string &strU16) const { + auto it = GlobalTables::GetConstPool().GetConstU16StringPool().find(strU16); + if (it != GlobalTables::GetConstPool().GetConstU16StringPool().end()) { + return it->second; + } + return nullptr; +} + +std::string FEJavaStringManager::GetLiteralGlobalName(const std::u16string &strU16) { + std::string literalGlobalName; + std::vector swapped = SwapBytes(strU16); + if (strU16.length() == 0) { + literalGlobalName = LiteralStrName::GetLiteralStrName(swapped.data(), 0); + } else { + literalGlobalName = LiteralStrName::GetLiteralStrName(swapped.data(), static_cast(strU16.length() << 1)); + } + return literalGlobalName; +} + +// Valid ASCII characters are in range 1..0x7f. Zero is not considered ASCII +// because it would complicate the detection of ASCII strings in Modified-UTF8. +bool FEJavaStringManager::IsAllASCII(const std::u16string &strU16) { + if (strU16.length() == 0) { + return false; + } + for (size_t i = 0; i < strU16.length(); ++i) { + uint16 val = ExchangeBytesPosition(strU16[i]); + if ((val - 1u) >= 0x7fu) { + return false; + } + } + return true; +} + +MIRArrayType *FEJavaStringManager::ConstructArrayType4Str(const std::u16string &strU16, bool compressible) const { + HIR2MPL_PARALLEL_FORBIDDEN(); + uint32 arraySize[1]; + // use 2 bytes per char in uncompress mode + uint32 length = compressible ? static_cast(strU16.length()) : static_cast(strU16.length() * 2); +#ifdef JAVA_OBJ_IN_MFILE +#ifdef USE_32BIT_REF + uint32 sizeInBytes = 16 + length; // shadow(4B)+monitor(4B)+count(4B)+hash(4B)+content +#else // !USE_32BIT_REF + uint32 sizeInBytes = 20 + length; // shadow(8B)+monitor(4B)+count(4B)+hash(4B)+content +#endif // USE_32BIT_REF +#else // !JAVA_OBJ_IN_MFILE + uint32 sizeInBytes = 8 + length; // count(4B)+hash(4B)+content +#endif // JAVA_OBJ_IN_MFILE + uint32 sizeInLongs = (sizeInBytes - 1) / 8 + 1; // round up to 8B units + arraySize[0] = sizeInLongs; + MIRArrayType *byteArrayType = static_cast( + GlobalTables::GetTypeTable().GetOrCreateArrayType(*GlobalTables::GetTypeTable().GetUInt64(), 1, arraySize)); + return byteArrayType; +} + +MIRAggConst *FEJavaStringManager::CreateByteArrayConst(const std::u16string &strU16, MIRArrayType &byteArrayType, + bool compressible) const { + MIRAggConst *newconst = module.GetMemPool()->New(module, byteArrayType); + MIRType *uInt64 = GlobalTables::GetTypeTable().GetUInt64(); + MemPool *mp = module.GetMemPool(); + DWBuffer currData = { 0, 0 }; + +#ifdef JAVA_OBJ_IN_MFILE + // @shadow + // To avoid linker touch cold pages, the classinfo is not set ready in file. + // It will be set at runtime +#ifdef USE_32BIT_REF + AddDataIntoByteArray(*newconst, *mp, currData, static_cast(0), *uInt64); +#else + AddDataIntoByteArray(*newconst, *mp, currData, static_cast(0), *uInt64); +#endif // USE_32BIT_REF + // @monitor + AddDataIntoByteArray(*newconst, *mp, currData, static_cast(0), *uInt64); +#endif // JAVA_OBJ_IN_MFILE + + // @count + uint32 strCount = strU16.length() ? static_cast((strU16.length() * 2) | compressible) : 0; + AddDataIntoByteArray(*newconst, *mp, currData, strCount, *uInt64); + + // @hash + uint32 hash = static_cast( + LiteralStrName::CalculateHashSwapByte(strU16.data(), static_cast(strU16.length()))); + AddDataIntoByteArray(*newconst, *mp, currData, hash, *uInt64); + + // @content + if (compressible) { + for (size_t i = 0; i < strU16.size(); i++) { + AddDataIntoByteArray(*newconst, *mp, currData, static_cast(ExchangeBytesPosition(strU16[i])), *uInt64); + } + } else { + for (size_t i = 0; i < strU16.size(); i++) { + AddDataIntoByteArray(*newconst, *mp, currData, static_cast(ExchangeBytesPosition(strU16[i])), *uInt64); + } + } + // in case there're remaining data in the buffer + FinishByteArray(*newconst, *mp, currData, *uInt64); + return newconst; +} + +std::vector FEJavaStringManager::SwapBytes(const std::u16string &strU16) { + std::vector out; + for (size_t i = 0; i < strU16.length(); ++i) { + uint16 c16 = strU16[i]; + out.push_back((c16 & 0xFF00) >> 8); + out.push_back(c16 & 0xFF); + } + out.push_back(0); + out.push_back(0); + return out; +} + +uint16 FEJavaStringManager::ExchangeBytesPosition(uint16 input) { + uint16 lowerByte = input << 8; + uint16 higherByte = input >> 8; + return lowerByte | higherByte; +} + +template +void FEJavaStringManager::AddDataIntoByteArray(MIRAggConst &newConst, MemPool &mp, DWBuffer &buf, T data, + MIRType &uInt64) { + if (buf.pos == 8) { // buffer is already full + newConst.PushBack(mp.New(buf.data, uInt64)); + buf.data = 0; + buf.pos = 0; + } + CHECK_FATAL(((buf.pos + sizeof(T)) <= 8), "inserted data exceeds current buffer capacity"); + buf.data |= ((static_cast(data)) << (buf.pos * 8)); + buf.pos += sizeof(T); +} + +void FEJavaStringManager::FinishByteArray(MIRAggConst &newConst, MemPool &mp, DWBuffer &buf, MIRType &uInt64) { + if (buf.pos > 0) { // there're data inside buffer + newConst.PushBack(mp.New(buf.data, uInt64)); + buf.data = 0; + buf.pos = 0; + } +} + +void FEJavaStringManager::GenStringMetaClassVar() { + std::unique_ptr metaClassType = std::make_unique(kTypeStruct); + + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("dummy"); + metaClassType->GetFields().emplace_back( + strIdx, TyIdxFieldAttrPair(GlobalTables::GetTypeTable().GetVoidPtr()->GetTypeIndex(), FieldAttrs())); + + GStrIdx metaStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(namemangler::kClassMetadataTypeName); + TyIdx tyIdx = GlobalTables::GetTypeTable().GetOrCreateMIRType(metaClassType.get()); + // Global? + module.GetTypeNameTab()->SetGStrIdxToTyIdx(metaStrIdx, tyIdx); + CHECK_FATAL(GlobalTables::GetTypeTable().GetTypeTable().size() > tyIdx, "empty check"); + if (GlobalTables::GetTypeTable().GetTypeTable()[tyIdx]->GetNameStrIdx() == 0) { + GlobalTables::GetTypeTable().GetTypeTable()[tyIdx]->SetNameStrIdx(metaStrIdx); + } + metaClassType->SetTypeIndex(tyIdx); + module.AddClass(tyIdx); + std::string buf(CLASSINFO_PREFIX_STR); + (void)buf.append("Ljava_2Flang_2FString_3B"); + stringMetaClassSymbol = mirBuilder.GetOrCreateGlobalDecl(buf.c_str(), *metaClassType); + GStrIdx typeNameIdxForString = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("Ljava_2Flang_2FString_3B"); + if (FEManager::GetTypeManager().IsImportedType(typeNameIdxForString)) { + stringMetaClassSymbol->SetStorageClass(kScExtern); + } +} + +void FEJavaStringManager::ClearStringMetaClassSymbolExternFlag() { + stringMetaClassSymbol->SetStorageClass(kScGlobal); +} +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/common/src/fe_manager.cpp b/src/hir2mpl/common/src/fe_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dec5dc361dbcbdc89049cedbbd6ed27228549345 --- /dev/null +++ b/src/hir2mpl/common/src/fe_manager.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_manager.h" + +namespace maple { +FEManager *FEManager::manager = nullptr; +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/common/src/fe_options.cpp b/src/hir2mpl/common/src/fe_options.cpp new file mode 100644 index 0000000000000000000000000000000000000000..848f0a03719f6121ef415d2a6a2241aa135645e2 --- /dev/null +++ b/src/hir2mpl/common/src/fe_options.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_options.h" +#include "fe_file_type.h" +namespace maple { +FEOptions FEOptions::options; +FEOptions::FEOptions() + : isGenMpltOnly(false), + isGenAsciiMplt(false), + outputPath(""), + outputName(""), + dumpLevel(kDumpLevelDisable), + isDumpTime(false), + nthreads(0), + dumpThreadTime(false) {} + +void FEOptions::AddInputClassFile(const std::string &fileName) { + FEFileType::FileType type = FEFileType::GetInstance().GetFileTypeByMagicNumber(fileName); + if (type == FEFileType::FileType::kClass) { + inputClassFiles.push_back(fileName); + } else { + WARN(kLncWarn, "invalid input class file %s...skipped", fileName.c_str()); + } +} + +void FEOptions::AddInputJarFile(const std::string &fileName) { + FEFileType::FileType type = FEFileType::GetInstance().GetFileTypeByMagicNumber(fileName); + if (type == FEFileType::FileType::kJar) { + inputJarFiles.push_back(fileName); + } else { + WARN(kLncWarn, "invalid input jar file %s...skipped", fileName.c_str()); + } +} + +void FEOptions::AddInputDexFile(const std::string &fileName) { + FEFileType::FileType type = FEFileType::GetInstance().GetFileTypeByMagicNumber(fileName); + if (type == FEFileType::FileType::kDex) { + inputDexFiles.push_back(fileName); + } else { + WARN(kLncWarn, "invalid input dex file %s...skipped", fileName.c_str()); + } +} + +void FEOptions::AddInputASTFile(const std::string &fileName) { + FEFileType::FileType type = FEFileType::GetInstance().GetFileTypeByMagicNumber(fileName); + if (type == FEFileType::FileType::kAST) { + inputASTFiles.push_back(fileName); + } else { + WARN(kLncWarn, "invalid input AST file %s...skipped", fileName.c_str()); + } +} + +void FEOptions::AddInputMASTFile(const std::string &fileName) { + FEFileType::FileType type = FEFileType::GetInstance().GetFileTypeByMagicNumber(fileName); + if (type == FEFileType::FileType::kMAST) { + inputMASTFiles.push_back(fileName); + } else { + WARN(kLncWarn, "invalid input MAST file %s...skipped", fileName.c_str()); + } +} +} // namespace maple diff --git a/src/hir2mpl/common/src/fe_struct_elem_info.cpp b/src/hir2mpl/common/src/fe_struct_elem_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..82584923eb08608b000be43cebeea4b9c9fe758d --- /dev/null +++ b/src/hir2mpl/common/src/fe_struct_elem_info.cpp @@ -0,0 +1,448 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_struct_elem_info.h" +#include "global_tables.h" +#include "mpl_logging.h" +#include "namemangler.h" +#include "feir_builder.h" +#include "feir_var_name.h" +#include "fe_utils.h" +#include "fe_manager.h" +#include "jbc_util.h" +#include "fe_options.h" +#include "bc_util.h" + +namespace maple { +// ---------- FEStructElemInfo ---------- +FEStructElemInfo::FEStructElemInfo(MapleAllocator &allocatorIn, const StructElemNameIdx &argStructElemNameIdx, + MIRSrcLang argSrcLang, bool argIsStatic) + : isStatic(argIsStatic), + isMethod(false), + isDefined(false), + isFromDex(false), + isPrepared(false), + srcLang(argSrcLang), + allocator(allocatorIn), + structElemNameIdx(argStructElemNameIdx), + actualContainer(allocator.GetMemPool()) { +} + +UniqueFEIRType FEStructElemInfo::GetActualContainerType() const { + // Invokable after prepared + return FEIRBuilder::CreateTypeByJavaName(actualContainer.c_str(), true); +} + +// ---------- FEStructFieldInfo ---------- +FEStructFieldInfo::FEStructFieldInfo(MapleAllocator &allocatorIn, const StructElemNameIdx &argStructElemNameIdx, + MIRSrcLang argSrcLang, bool argIsStatic) + : FEStructElemInfo(allocatorIn, argStructElemNameIdx, argSrcLang, argIsStatic), + fieldType(nullptr), + fieldNameIdx(0), + fieldID(0), + isVolatile(false) { + isMethod = false; + LoadFieldType(); +} + +void FEStructFieldInfo::PrepareImpl(MIRBuilder &mirBuilder, bool argIsStatic) { + if (isPrepared && argIsStatic == isStatic) { + return; + } + // Prepare + actualContainer = GetStructName(); + const std::string stdActualContainer = actualContainer.c_str(); + std::string rawName = stdActualContainer + namemangler::kNameSplitterStr + GetElemName(); + if (isStatic && + FEOptions::GetInstance().GetModeJavaStaticFieldName() != FEOptions::ModeJavaStaticFieldName::kNoType) { + rawName = rawName + namemangler::kNameSplitterStr + GetSignatureName(); + } + fieldNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(rawName); + MIRStructType *structType = FEManager::GetTypeManager().GetStructTypeFromName(stdActualContainer); + if (structType == nullptr) { + isDefined = false; + isPrepared = true; + return; + } + isDefined = SearchStructFieldJava(*structType, mirBuilder, argIsStatic); + if (isDefined) { + return; + } + WARN(kLncErr, "use undefined %s field %s", argIsStatic ? "static" : "", rawName.c_str()); + isPrepared = true; + isStatic = argIsStatic; + return; +} + +void FEStructFieldInfo::LoadFieldType() { + switch (srcLang) { + case kSrcLangJava: + LoadFieldTypeJava(); + break; + case kSrcLangC: + WARN(kLncWarn, "kSrcLangC LoadFieldType NYI"); + break; + default: + WARN(kLncWarn, "unsupported language"); + break; + } +} + +void FEStructFieldInfo::LoadFieldTypeJava() { + fieldType = allocator.GetMemPool()->New(PTY_unknown); + static_cast(fieldType)->LoadFromJavaTypeName(GetSignatureName(), true); +} + +void FEStructFieldInfo::PrepareStaticField(const MIRStructType &structType) { + std::string ownerStructName = structType.GetName(); + const std::string &fieldName = GetElemName(); + std::string fullName = ownerStructName + namemangler::kNameSplitterStr + fieldName; + if (FEOptions::GetInstance().GetModeJavaStaticFieldName() != FEOptions::ModeJavaStaticFieldName::kNoType) { + fullName += namemangler::kNameSplitterStr + GetSignatureName(); + } + fieldNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fullName); + isPrepared = true; + isStatic = true; +} + +void FEStructFieldInfo::PrepareNonStaticField(MIRBuilder &mirBuilder) { + FEIRTypeDefault feType(PTY_unknown); + feType.LoadFromJavaTypeName(GetSignatureName(), true); + MIRType *fieldMIRType = feType.GenerateMIRTypeAuto(srcLang); + uint32 idx = 0; + uint32 idx1 = 0; + MIRStructType *structType = FEManager::GetTypeManager().GetStructTypeFromName(GetStructName()); + mirBuilder.TraverseToNamedFieldWithType(*structType, structElemNameIdx.elem, fieldMIRType->GetTypeIndex(), idx1, idx); + fieldID = static_cast(idx); + isPrepared = true; + isStatic = false; +} + +bool FEStructFieldInfo::SearchStructFieldJava(MIRStructType &structType, MIRBuilder &mirBuilder, bool argIsStatic, + bool allowPrivate) { + if (structType.IsIncomplete()) { + return false; + } + GStrIdx nameIdx = structElemNameIdx.elem; + if (argIsStatic) { + // suppose anti-proguard is off in jbc. + // Turn on anti-proguard in jbc: -java-staticfield-name=smart && JBCClass2FEHelper::isStaticFieldProguard(false) + // Turn on anti-proguard in BC: -java-staticfield-name=smart + std::string fullName = structType.GetCompactMplTypeName() + namemangler::kNameSplitterStr + GetElemName(); + if (FEOptions::GetInstance().GetModeJavaStaticFieldName() != FEOptions::ModeJavaStaticFieldName::kNoType) { + fullName += namemangler::kNameSplitterStr + GetSignatureName(); + } + nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fullName); + } + actualContainer = structType.GetCompactMplTypeName(); + const FieldVector &fields = argIsStatic ? structType.GetStaticFields() : structType.GetFields(); + for (const FieldPair &fieldPair : fields) { + if (fieldPair.first != nameIdx) { + continue; + } + if (fieldPair.second.second.GetAttr(FLDATTR_private) && !allowPrivate) { + continue; + } + if (CompareFieldType(fieldPair)) { + if (argIsStatic) { + PrepareStaticField(structType); + } else { + PrepareNonStaticField(mirBuilder); + } + isVolatile = fieldPair.second.second.GetAttr(FLDATTR_volatile); + return true; + } + } + // search parent + bool found = false; + if (structType.GetKind() == kTypeClass) { + MIRClassType &classType = static_cast(structType); + // implemented + for (const TyIdx &tyIdx : classType.GetInterfaceImplemented()) { + found = found || SearchStructFieldJava(tyIdx, mirBuilder, argIsStatic, false); + } + // parent + found = found || SearchStructFieldJava(classType.GetParentTyIdx(), mirBuilder, argIsStatic, false); + } else if (structType.GetKind() == kTypeInterface) { + // parent + MIRInterfaceType &interfaceType = static_cast(structType); + for (const TyIdx &tyIdx : interfaceType.GetParentsTyIdx()) { + found = found || SearchStructFieldJava(tyIdx, mirBuilder, argIsStatic, false); + } + } else { + CHECK_FATAL(false, "not supported yet"); + } + return found; +} + +bool FEStructFieldInfo::SearchStructFieldJava(const TyIdx &tyIdx, MIRBuilder &mirBuilder, bool argIsStatic, + bool allowPrivate) { + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + if (type == nullptr) { + return false; + } + if (type->IsIncomplete()) { + return false; + } + if (type->GetKind() == kTypeClass || type->GetKind() == kTypeInterface) { + MIRStructType *structType = static_cast(type); + return SearchStructFieldJava(*structType, mirBuilder, argIsStatic, allowPrivate); + } else { + ERR(kLncErr, "parent type should be StructType"); + return false; + } +} + +bool FEStructFieldInfo::CompareFieldType(const FieldPair &fieldPair) const { + MIRType *fieldMIRType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldPair.second.first); + std::string typeName = fieldMIRType->GetCompactMplTypeName(); + if (GetSignatureName().compare(typeName) == 0) { + return true; + } else { + return false; + } +} + +// ---------- FEStructMethodInfo ---------- +FEStructMethodInfo::FEStructMethodInfo(MapleAllocator &allocatorIn, const StructElemNameIdx &argStructElemNameIdx, + MIRSrcLang argSrcLang, bool argIsStatic) + : FEStructElemInfo(allocatorIn, argStructElemNameIdx, argSrcLang, argIsStatic), + isReturnVoid(false), + isJavaPolymorphicCall(false), + isJavaDynamicCall(false), + methodNameIdx(argStructElemNameIdx.full), + retType(nullptr), + ownerType(nullptr), + mirFunc(nullptr), + argTypes(allocator.Adapter()) { + isMethod = true; + LoadMethodType(); +} + +FEStructMethodInfo::~FEStructMethodInfo() { + mirFunc = nullptr; + retType = nullptr; + ownerType = nullptr; +} + +PUIdx FEStructMethodInfo::GetPuIdx() const { + CHECK_NULL_FATAL(mirFunc); + return mirFunc->GetPuidx(); +} + +void FEStructMethodInfo::PrepareImpl(MIRBuilder &mirBuilder, bool argIsStatic) { + if (isPrepared && argIsStatic == isStatic) { + return; + } + switch (srcLang) { + case kSrcLangJava: + PrepareImplJava(mirBuilder, argIsStatic); + break; + case kSrcLangC: + PrepareMethodC(); + return; + default: + CHECK_FATAL(false, "unsupported src lang"); + } + PrepareMethod(); +} + +void FEStructMethodInfo::PrepareImplJava(MIRBuilder &mirBuilder, bool argIsStatic) { + // Prepare + actualContainer = GetStructName(); + MIRStructType *structType = nullptr; + if (!actualContainer.empty() && actualContainer[0] == 'A') { + structType = FEManager::GetTypeManager().GetStructTypeFromName("Ljava_2Flang_2FObject_3B"); + } else { + structType = FEManager::GetTypeManager().GetStructTypeFromName(actualContainer.c_str()); + } + isStatic = argIsStatic; + isDefined = false; + if (structType != nullptr) { + isDefined = SearchStructMethodJava(*structType, mirBuilder, argIsStatic); + if (isDefined) { + return; + } + } else if (isJavaDynamicCall) { + methodNameIdx = structElemNameIdx.full; + isDefined = true; + PrepareMethod(); + return; + } + std::string methodName = GlobalTables::GetStrTable().GetStringFromStrIdx(structElemNameIdx.full); + WARN(kLncWarn, "undefined %s method: %s", isStatic ? "static" : "", methodName.c_str()); +} + +void FEStructMethodInfo::LoadMethodType() { + switch (srcLang) { + case kSrcLangJava: + LoadMethodTypeJava(); + break; + case kSrcLangC: + break; + default: + WARN(kLncWarn, "unsupported language"); + break; + } +} + +void FEStructMethodInfo::LoadMethodTypeJava() { + std::string signatureJava = + namemangler::DecodeName(GlobalTables::GetStrTable().GetStringFromStrIdx(structElemNameIdx.full)); + std::vector typeNames = jbc::JBCUtil::SolveMethodSignature(signatureJava); + CHECK_FATAL(typeNames.size() > 0, "invalid method signature: %s", signatureJava.c_str()); + // constructor check + const std::string &funcName = GetElemName(); + isConstructor = (funcName.find("init_28") == 0); + // return type + retType = allocator.GetMemPool()->New(PTY_unknown); + if (typeNames[0].compare("V") == 0) { + isReturnVoid = true; + } + static_cast(retType)->LoadFromJavaTypeName(typeNames[0], false); + // argument types + argTypes.clear(); + for (size_t i = 1; i < typeNames.size(); i++) { + FEIRType *argType = allocator.GetMemPool()->New(PTY_unknown); + static_cast(argType)->LoadFromJavaTypeName(typeNames[i], false); + argTypes.push_back(argType); + } + // owner type + ownerType = allocator.GetMemPool()->New(PTY_unknown); + static_cast(ownerType)->LoadFromJavaTypeName(GetStructName(), true); +} + +void FEStructMethodInfo::PrepareMethodC() { + mirFunc = FEManager::GetTypeManager().GetMIRFunction(methodNameIdx, isStatic); + if (mirFunc == nullptr) { + MIRType *mirRetType = retType->GenerateMIRTypeAuto(srcLang); + std::vector argsTypeIdx; + for (const FEIRType *argType : argTypes) { + MIRType *mirArgType = argType->GenerateMIRTypeAuto(srcLang); + argsTypeIdx.push_back(mirArgType->GetTypeIndex()); + } + mirFunc = FEManager::GetTypeManager().CreateFunction(methodNameIdx, mirRetType->GetTypeIndex(), + argsTypeIdx, false, isStatic); + mirFunc->SetFuncAttrs(funcAttrs); + } + isPrepared = true; +} + +void FEStructMethodInfo::PrepareMethod() { + mirFunc = FEManager::GetTypeManager().GetMIRFunction(methodNameIdx, isStatic); + if (mirFunc == nullptr) { + MIRType *mirRetType = retType->GenerateMIRTypeAuto(srcLang); + // args type + std::vector> argVarList; + std::vector argsTypeIdx; + if (!isStatic) { + UniqueFEIRVar regVar = std::make_unique(FEUtils::GetThisIdx(), ownerType->Clone(), false); + argVarList.emplace_back(std::move(regVar)); + argsTypeIdx.emplace_back(ownerType->GenerateMIRType(srcLang, true)->GetTypeIndex()); + } + uint8 regNum = 1; + for (const FEIRType *argType : argTypes) { + UniqueFEIRVar regVar = FEIRBuilder::CreateVarReg(regNum, argType->Clone(), false); + ++regNum; + argVarList.emplace_back(std::move(regVar)); + MIRType *mirArgType = argType->GenerateMIRTypeAuto(srcLang); + argsTypeIdx.push_back(mirArgType->GetTypeIndex()); + } + mirFunc = FEManager::GetTypeManager().CreateFunction(methodNameIdx, mirRetType->GetTypeIndex(), argsTypeIdx, false, + isStatic); + // Update formals for external function, + // defined function will be update formals later in FEFunction::UpdateFormal + for (const std::unique_ptr &argVar : argVarList) { + MIRType *mirTy = argVar->GetType()->GenerateMIRTypeAuto(); + std::string name = argVar->GetName(*mirTy); + MIRSymbol *sym = FEManager::GetMIRBuilder().GetOrCreateDeclInFunc(name, *mirTy, *mirFunc); + sym->SetStorageClass(kScFormal); + mirFunc->AddArgument(sym); + } + } + isPrepared = true; +} + +bool FEStructMethodInfo::SearchStructMethodJava(MIRStructType &structType, MIRBuilder &mirBuilder, bool argIsStatic, + bool allowPrivate) { + if (structType.IsIncomplete()) { + return false; + } + actualContainer = structType.GetCompactMplTypeName(); + std::string fullName = structType.GetCompactMplTypeName() + namemangler::kNameSplitterStr + GetElemName() + + namemangler::kNameSplitterStr + GetSignatureName(); + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(fullName); + for (const MethodPair &methodPair : structType.GetMethods()) { + if (methodPair.second.second.GetAttr(FUNCATTR_private) && !allowPrivate) { + continue; + } + if (methodPair.second.second.GetAttr(FUNCATTR_static) != argIsStatic) { + continue; + } + const MIRSymbol *sym = GlobalTables::GetGsymTable().GetSymbolFromStidx(methodPair.first.Idx(), true); + CHECK_NULL_FATAL(sym); + if (sym->GetNameStrIdx() == nameIdx) { + isStatic = argIsStatic; + if (isStatic) { + methodNameIdx = nameIdx; + } + PrepareMethod(); + return true; + } + } + // search parent + return SearchStructMethodJavaInParent(structType, mirBuilder, argIsStatic); +} + +bool FEStructMethodInfo::SearchStructMethodJavaInParent(MIRStructType &structType, MIRBuilder &mirBuilder, + bool argIsStatic) { + bool found = false; + if (structType.GetKind() == kTypeClass) { + // parent + MIRClassType &classType = static_cast(structType); + found = SearchStructMethodJava(classType.GetParentTyIdx(), mirBuilder, argIsStatic, false); + // implemented + for (const TyIdx &tyIdx : classType.GetInterfaceImplemented()) { + found = found || SearchStructMethodJava(tyIdx, mirBuilder, argIsStatic, false); + } + } else if (structType.GetKind() == kTypeInterface) { + // parent + MIRInterfaceType &interfaceType = static_cast(structType); + for (const TyIdx &tyIdx : interfaceType.GetParentsTyIdx()) { + found = found || SearchStructMethodJava(tyIdx, mirBuilder, argIsStatic, false); + } + } else { + CHECK_FATAL(false, "not supported yet"); + } + return found; +} + +bool FEStructMethodInfo::SearchStructMethodJava(const TyIdx &tyIdx, MIRBuilder &mirBuilder, bool argIsStatic, + bool allowPrivate) { + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + if (type == nullptr) { + return false; + } + if (type->IsIncomplete()) { + return false; + } + if (type->GetKind() == kTypeClass || type->GetKind() == kTypeInterface) { + MIRStructType *structType = static_cast(type); + return SearchStructMethodJava(*structType, mirBuilder, argIsStatic, allowPrivate); + } else { + ERR(kLncErr, "parent type should be StructType"); + return false; + } +} +} // namespace maple diff --git a/src/hir2mpl/common/src/fe_timer_ns.cpp b/src/hir2mpl/common/src/fe_timer_ns.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6efff93a79b1ea5ef48cf0b21b4f758660d119eb --- /dev/null +++ b/src/hir2mpl/common/src/fe_timer_ns.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_timer_ns.h" +#include "types_def.h" + +namespace maple { +void FETimerNS::Start() { + (void)clock_gettime(CLOCK_REALTIME, &timeStart); +} + +void FETimerNS::Stop() { + (void)clock_gettime(CLOCK_REALTIME, &timeEnd); +} + +int64_t FETimerNS::GetTimeNS() const { + const int64 nsInS = 1000000000; + return nsInS * (timeEnd.tv_sec - timeStart.tv_sec) + (timeEnd.tv_nsec - timeStart.tv_nsec); +} +} // namespace maple diff --git a/src/hir2mpl/common/src/fe_type_hierarchy.cpp b/src/hir2mpl/common/src/fe_type_hierarchy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c51ae341d0f19d7e8ecedeb2d838f412e0fd21d3 --- /dev/null +++ b/src/hir2mpl/common/src/fe_type_hierarchy.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_type_hierarchy.h" +#include "global_tables.h" +#include "fe_config_parallel.h" + +namespace maple { +FETypeHierarchy FETypeHierarchy::instance; + +void FETypeHierarchy::InitByGlobalTable() { + HIR2MPL_PARALLEL_FORBIDDEN(); + mapIdxChildParent.clear(); + for (const MIRType *type : GlobalTables::GetTypeTable().GetTypeTable()) { + if (type == nullptr) { + continue; + } + switch (type->GetKind()) { + case kTypeClass: { + const MIRClassType *typeClass = static_cast(type); + AddMIRType(*typeClass); + break; + } + case kTypeInterface: { + const MIRInterfaceType *typeInterface = static_cast(type); + AddMIRType(*typeInterface); + break; + } + default: + break; + } + } +} + +void FETypeHierarchy::AddMIRType(const MIRClassType &type) { + MIRType *parentType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(type.GetParentTyIdx()); + if (parentType != nullptr) { + CHECK_FATAL(parentType->IsStructType(), "parent must be struct type"); + AddParentChildRelation(parentType->GetNameStrIdx(), type.GetNameStrIdx()); + } + for (TyIdx tyIdx : type.GetInterfaceImplemented()) { + MIRType *implType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + CHECK_FATAL(implType->IsStructType(), "parent must be struct type"); + AddParentChildRelation(implType->GetNameStrIdx(), type.GetNameStrIdx()); + } +} + +void FETypeHierarchy::AddMIRType(const MIRInterfaceType &type) { + for (TyIdx tyIdx : type.GetParentsTyIdx()) { + MIRType *parentType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + CHECK_FATAL(parentType->IsStructType(), "parent must be struct type"); + AddParentChildRelation(parentType->GetNameStrIdx(), type.GetNameStrIdx()); + } +} + +bool FETypeHierarchy::IsParentOf(const GStrIdx &parentIdx, const GStrIdx &childIdx) { + if (parentIdx == childIdx) { + return true; + } + if (cache.find(std::make_pair(childIdx, parentIdx)) != cache.end()) { + return true; + } + auto it = mapIdxChildParent.find(childIdx); + if (it == mapIdxChildParent.end()) { + return false; + } + for (GStrIdx idx : it->second) { + if (IsParentOf(parentIdx, idx)) { + std::pair item = std::make_pair(childIdx, parentIdx); + if (cache.find(item) == cache.end()) { + CHECK_FATAL(cache.insert(item).second, "cache insert failed"); + } + return true; + } + } + return false; +} + +void FETypeHierarchy::AddParentChildRelation(const GStrIdx &parentIdx, const GStrIdx &childIdx) { + if (mapIdxChildParent[childIdx].find(parentIdx) == mapIdxChildParent[childIdx].end()) { + CHECK_FATAL(mapIdxChildParent[childIdx].insert(parentIdx).second, "mapIdxChildParent insert failed"); + } +} +} // namespace maple diff --git a/src/hir2mpl/common/src/fe_type_manager.cpp b/src/hir2mpl/common/src/fe_type_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ec9a40f6cbfd2f66ebb4ccf4e03e8125cd1aa60 --- /dev/null +++ b/src/hir2mpl/common/src/fe_type_manager.cpp @@ -0,0 +1,736 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_type_manager.h" +#include +#include +#include "mir_parser.h" +#include "bin_mplt.h" +#include "global_tables.h" +#include "fe_timer.h" +#include "fe_config_parallel.h" +#include "feir_type_helper.h" +#include "fe_macros.h" +#include "types_def.h" +#include "fe_utils_ast.h" + +namespace maple { +const UniqueFEIRType FETypeManager::kPrimFEIRTypeUnknown = std::make_unique(PTY_unknown); +const UniqueFEIRType FETypeManager::kPrimFEIRTypeU1 = std::make_unique(PTY_u1); +const UniqueFEIRType FETypeManager::kPrimFEIRTypeI8 = std::make_unique(PTY_i8); +const UniqueFEIRType FETypeManager::kPrimFEIRTypeU8 = std::make_unique(PTY_u8); +const UniqueFEIRType FETypeManager::kPrimFEIRTypeI16 = std::make_unique(PTY_i16); +const UniqueFEIRType FETypeManager::kPrimFEIRTypeU16 = std::make_unique(PTY_u16); +const UniqueFEIRType FETypeManager::kPrimFEIRTypeI32 = std::make_unique(PTY_i32); +const UniqueFEIRType FETypeManager::kPrimFEIRTypeU32 = std::make_unique(PTY_u32); +const UniqueFEIRType FETypeManager::kPrimFEIRTypeI64 = std::make_unique(PTY_i64); +const UniqueFEIRType FETypeManager::kPrimFEIRTypeU64 = std::make_unique(PTY_u64); +const UniqueFEIRType FETypeManager::kPrimFEIRTypeF32 = std::make_unique(PTY_f32); +const UniqueFEIRType FETypeManager::kPrimFEIRTypeF64 = std::make_unique(PTY_f64); +const UniqueFEIRType FETypeManager::kFEIRTypeJavaObject = std::make_unique(PTY_ref); +const UniqueFEIRType FETypeManager::kFEIRTypeJavaClass = std::make_unique(PTY_ref); +const UniqueFEIRType FETypeManager::kFEIRTypeJavaString = std::make_unique(PTY_ref); + +FETypeManager::FETypeManager(MIRModule &moduleIn) + : module(moduleIn), + mp(FEUtils::NewMempool("mempool for FETypeManager", false /* isLcalPool */)), + allocator(mp), + builder(&module), + srcLang(kSrcLangJava), + funcMCCGetOrInsertLiteral(nullptr) { + static_cast(kFEIRTypeJavaObject.get())->LoadFromJavaTypeName("Ljava/lang/Object;", false); + static_cast(kFEIRTypeJavaClass.get())->LoadFromJavaTypeName("Ljava/lang/Class;", false); + static_cast(kFEIRTypeJavaString.get())->LoadFromJavaTypeName("Ljava/lang/String;", false); + sameNamePolicy.SetFlag(FETypeSameNamePolicy::kFlagUseLastest); +} + +FETypeManager::~FETypeManager() { + mp = nullptr; + funcMCCGetOrInsertLiteral = nullptr; + + funcMCCStaticFieldGetBool = nullptr; + funcMCCStaticFieldGetByte = nullptr; + funcMCCStaticFieldGetShort = nullptr; + funcMCCStaticFieldGetChar = nullptr; + funcMCCStaticFieldGetInt = nullptr; + funcMCCStaticFieldGetLong = nullptr; + funcMCCStaticFieldGetFloat = nullptr; + funcMCCStaticFieldGetDouble = nullptr; + funcMCCStaticFieldGetObject = nullptr; + + funcMCCStaticFieldSetBool = nullptr; + funcMCCStaticFieldSetByte = nullptr; + funcMCCStaticFieldSetShort = nullptr; + funcMCCStaticFieldSetChar = nullptr; + funcMCCStaticFieldSetInt = nullptr; + funcMCCStaticFieldSetLong = nullptr; + funcMCCStaticFieldSetFloat = nullptr; + funcMCCStaticFieldSetDouble = nullptr; + funcMCCStaticFieldSetObject = nullptr; +} + +void FETypeManager::ReleaseMemPool() { + FEUtils::DeleteMempoolPtr(mp); +} + +bool FETypeManager::LoadMplts(const std::list &mpltNames, FETypeFlag flag, const std::string &phaseName) { + FETimer timer; + timer.StartAndDump(phaseName); + bool success = true; + for (const std::string &fileName : mpltNames) { + success = success && LoadMplt(fileName, flag); + } + timer.StopAndDumpTimeMS(phaseName); + return success; +} + +bool FETypeManager::LoadMplt(const std::string &mpltName, FETypeFlag flag) { + BinaryMplt binMplt(module); + if (!binMplt.Import(mpltName)) { + // not a binary mplt + std::ifstream file(mpltName); + if (!file.is_open()) { + ERR(kLncErr, "unable to open mplt file %s", mpltName.c_str()); + return false; + } + MIRParser parser(module); + if (!parser.ParseMPLTStandalone(file, mpltName)) { + ERR(kLncErr, "Failed to parser mplt file %s\n%s", mpltName.c_str(), parser.GetError().c_str()); + file.close(); + return false; + } + file.close(); + } + UpdateStructNameTypeMapFromTypeTable(mpltName, flag); + UpdateNameFuncMapFromTypeTable(); + return true; +} + +void FETypeManager::UpdateStructNameTypeMapFromTypeTable(const std::string &mpltName, FETypeFlag flag) { + bool sameNameUseLastest = sameNamePolicy.IsUseLastest(); + GStrIdx mpltNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(mpltName); + for (MIRType *type : GlobalTables::GetTypeTable().GetTypeTable()) { + if ((type != nullptr) && IsStructType(*type)) { + MIRStructType *structType = static_cast(type); + auto it = structNameTypeMap.insert(std::make_pair(structType->GetNameStrIdx(), std::make_pair(structType, flag))); + if (it.second == false) { + // type is existed + structSameNameSrcList.push_back(std::make_pair(structType->GetNameStrIdx(), + structNameSrcMap[structType->GetNameStrIdx()])); + structSameNameSrcList.push_back(std::make_pair(structType->GetNameStrIdx(), mpltNameIdx)); + if (sameNameUseLastest) { + structNameTypeMap[structType->GetNameStrIdx()] = std::make_pair(structType, flag); + structNameSrcMap[structType->GetNameStrIdx()] = mpltNameIdx; + } + } else { + // type is not existed + structNameSrcMap[structType->GetNameStrIdx()] = mpltNameIdx; + } + } + } +} + +void FETypeManager::SetMirImportedTypes(FETypeFlag flag) { + for (auto &item : structNameTypeMap) { + MIRStructType *type = item.second.first; + if ((type != nullptr) && FETypeManager::IsStructType(*type)) { + type->SetIsImported(true); + item.second.second = flag; + } + } +} + +void FETypeManager::UpdateNameFuncMapFromTypeTable() { + for (uint32 i = 1; i < GlobalTables::GetGsymTable().GetSymbolTableSize(); i++) { + MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbolFromStidx(i); + CHECK_FATAL(symbol, "Symbol is null"); + if (symbol->GetSKind() == kStFunc) { + CHECK_FATAL(symbol->GetFunction(), "Function in symbol is null"); + MIRFunction *func = symbol->GetFunction(); + if (func->GetAttr(FUNCATTR_static)) { + mpltNameStaticFuncMap[symbol->GetNameStrIdx()] = symbol->GetFunction(); + } else { + mpltNameFuncMap[symbol->GetNameStrIdx()] = symbol->GetFunction(); + } + } + } +} + +void FETypeManager::CheckSameNamePolicy() const { + std::unordered_map, GStrIdxHash> result; + for (const std::pair &item : structSameNameSrcList) { + result[item.first].push_back(item.second); + } + if (result.size() > 0) { + WARN(kLncWarn, "========== Structs list with the same name =========="); + } + for (const std::pair> &item : result) { + std::string typeName = GlobalTables::GetStrTable().GetStringFromStrIdx(item.first); + WARN(kLncWarn, "Type: %s", typeName.c_str()); + for (const GStrIdx &mpltNameIdx : item.second) { + std::string mpltName = GlobalTables::GetStrTable().GetStringFromStrIdx(mpltNameIdx); + WARN(kLncWarn, " Defined in %s", mpltName.c_str()); + } + } + if (result.size() > 0 && sameNamePolicy.IsFatal()) { + FATAL(kLncFatal, "Structs with the same name exsited. Exit."); + } +} + +MIRStructType *FETypeManager::CreateStructType(const std::string &name) { + MIRStructType type(kTypeStruct); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + TyIdx tyIdx = GlobalTables::GetTypeTable().GetOrCreateMIRType(&type); + module.GetTypeNameTab()->SetGStrIdxToTyIdx(strIdx, tyIdx); + if (GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx.GetIdx())->GetNameStrIdx() == 0) { + GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx.GetIdx())->SetNameStrIdx(strIdx); + } + auto *structType = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx.GetIdx())); + structNameTypeMap[strIdx] = std::make_pair(structType, FETypeFlag::kSrcInput); + return structType; +} + +MIRStructType *FETypeManager::GetOrCreateStructType(const std::string &name) { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + const std::unordered_map::iterator &it = structNameTypeMap.find(nameIdx); + if (it != structNameTypeMap.end()) { + return it->second.first; + } + MIRStructType *structType = CreateStructType(name); + module.PushbackTypeDefOrder(nameIdx); + CHECK_NULL_FATAL(structType); + return structType; +} + +/* + * create MIRStructType for complex number, e.g. + * type $Complex|F + */ +MIRType *FETypeManager::GetOrCreateComplexStructType(const MIRType &elemType) { + const std::string typeName = "Complex|" + FEUtilAST::Type2Label(elemType.GetPrimType()); + MIRStructType *structType = GetOrCreateStructType(typeName); + if (structType->GetFields().size() == 0) { + GStrIdx realStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("real"); + GStrIdx imagStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("imag"); + FieldAttrs fieldAttrs; + TyIdxFieldAttrPair pair(elemType.GetTypeIndex(), fieldAttrs); + FieldPair realPair(realStrIdx, pair); + FieldPair imagePair(imagStrIdx, pair); + structType->GetFields().push_back(realPair); + structType->GetFields().push_back(imagePair); + } + return structType; +} + +MIRStructType *FETypeManager::GetClassOrInterfaceType(const GStrIdx &nameIdx) const { + auto it = structNameTypeMap.find(nameIdx); + if (it == structNameTypeMap.end()) { + return nullptr; + } else { + return it->second.first; + } +} + +FETypeFlag FETypeManager::GetClassOrInterfaceTypeFlag(const GStrIdx &nameIdx) const { + auto it = structNameTypeMap.find(nameIdx); + if (it == structNameTypeMap.end()) { + return FETypeFlag::kDefault; + } else { + return it->second.second; + } +} + +MIRStructType *FETypeManager::CreateClassOrInterfaceType(const GStrIdx &nameIdx, bool isInterface, + FETypeFlag typeFlag) { + MIRType *type = nullptr; + std::string name = GlobalTables::GetStrTable().GetStringFromStrIdx(nameIdx); + if (isInterface) { + type = GlobalTables::GetTypeTable().GetOrCreateInterfaceType(name.c_str(), module); + } else { + type = GlobalTables::GetTypeTable().GetOrCreateClassType(name.c_str(), module); + } + CHECK_NULL_FATAL(type); + ASSERT(IsStructType(*type), "type is not struct type"); + MIRStructType *structType = static_cast(type); + structNameTypeMap[nameIdx] = std::make_pair(structType, typeFlag); + return structType; +} + +MIRStructType *FETypeManager::GetOrCreateClassOrInterfaceType(const GStrIdx &nameIdx, bool isInterface, + FETypeFlag typeFlag, bool &isCreate) { + // same name policy: mpltSys > dex > mpltApk > mplt + const std::unordered_map::iterator &it = structNameTypeMap.find(nameIdx); + if (it != structNameTypeMap.end()) { + uint16 flagExist = it->second.second & FETypeFlag::kSrcMask; + uint16 flagNew = typeFlag & FETypeFlag::kSrcMask; + // type is existed, use existed type + if (flagNew > flagExist) { + isCreate = false; + return it->second.first; + } + // type is existed when src input, replace with new type + if (typeFlag == FETypeFlag::kSrcInput && it->second.second != FETypeFlag::kSrcMpltApk) { + UpdateDupTypes(nameIdx, isInterface, it); + } + } + MIRStructType *structType = CreateClassOrInterfaceType(nameIdx, isInterface, typeFlag); + isCreate = true; + CHECK_NULL_FATAL(structType); + return structType; +} + +void FETypeManager::UpdateDupTypes(const GStrIdx &nameIdx, bool isInterface, + const std::unordered_map::iterator &importedTypeIt) { + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "duplicated type %s from src", + GlobalTables::GetStrTable().GetStringFromStrIdx(nameIdx).c_str()); + MIRStructType *importedType = importedTypeIt->second.first; + MIRStructType *newType = nullptr; + // If locally defined type and imported type have the same name, but one is of interface and another one + // is of class type, we need to update the type + if ((importedType->IsMIRClassType() && isInterface) || + (importedType->IsMIRInterfaceType() && !isInterface)) { + if (isInterface) { + newType = new MIRInterfaceType(kTypeInterfaceIncomplete); + } else { + newType = new MIRClassType(kTypeClassIncomplete); + } + newType->SetTypeIndex(importedType->GetTypeIndex()); + importedType->SetTypeIndex(TyIdx(-1)); + newType->SetNameStrIdx(importedType->GetNameStrIdx()); + importedType->SetNameStrIdxItem(0); + CHECK_FATAL(newType->GetTypeIndex() < GlobalTables::GetTypeTable().GetTypeTable().size(), + "newType->_ty_idx >= GlobalTables::GetTypeTable().type_table_.size()"); + GlobalTables::GetTypeTable().GetTypeTable()[newType->GetTypeIndex()] = newType; + } else { + importedType->ClearContents(); + } + (void)structNameTypeMap.erase(importedTypeIt); + auto it = structNameSrcMap.find(nameIdx); + if (it != structNameSrcMap.end()) { + (void)structNameSrcMap.erase(it); + } +} + +MIRType *FETypeManager::GetOrCreateClassOrInterfacePtrType(const GStrIdx &nameIdx, bool isInterface, + FETypeFlag typeFlag, bool &isCreate) { + MIRStructType *structType = GetOrCreateClassOrInterfaceType(nameIdx, isInterface, typeFlag, isCreate); + MIRType *ptrType = GetOrCreatePointerType(*structType); + CHECK_NULL_FATAL(ptrType); + return ptrType; +} + +MIRStructType *FETypeManager::GetStructTypeFromName(const std::string &name) { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + return GetStructTypeFromName(nameIdx); +} + +MIRStructType *FETypeManager::GetStructTypeFromName(const GStrIdx &nameIdx) { + auto it = structNameTypeMap.find(nameIdx); + if (it == structNameTypeMap.end()) { + return nullptr; + } else { + return it->second.first; + } +} + +uint32 FETypeManager::GetTypeIDFromMplClassName(const std::string &mplClassName, int32 dexFileHashCode) const { + auto const &itMap = classNameTypeIDMapAllDex.find(dexFileHashCode); + if (itMap != classNameTypeIDMapAllDex.end()) { + auto const &thisDexClassNameTypeIDMap = itMap->second; + auto const &it = thisDexClassNameTypeIDMap.find(mplClassName); + if (it != thisDexClassNameTypeIDMap.end()) { + return it->second; + } + return UINT32_MAX; + } + return UINT32_MAX; // some type id not in the dex file, give UINT32_MAX +} + +MIRType *FETypeManager::GetOrCreateTypeFromName(const std::string &name, FETypeFlag typeFlag, bool usePtr) { + CHECK_FATAL(!name.empty(), "type name is empty"); + PrimType pty = GetPrimType(name); + if (pty != kPtyInvalid) { + return GlobalTables::GetTypeTable().GetTypeTable().at(pty); + } + switch (name[0]) { + case 'L': { + bool isCreate = false; + MIRStructType *structType = GetOrCreateClassOrInterfaceType(name, false, typeFlag, isCreate); + if (usePtr) { + return GetOrCreatePointerType(*structType); + } else { + return structType; + } + } + case 'A': { + uint32 dim = 0; + bool isCreate = false; + const std::string &elemTypeName = GetBaseTypeName(name, dim, true); + MIRType *elemType = GetMIRTypeForPrim(elemTypeName); + if (elemType == nullptr) { + elemType = GetOrCreateClassOrInterfaceType(elemTypeName, false, typeFlag, isCreate); + CHECK_NULL_FATAL(elemType); + elemType = GetOrCreatePointerType(*elemType); + } + CHECK_FATAL(dim <= UINT8_MAX, "array dimension (%u) is out of range", dim); + MIRType *type = GetOrCreateArrayType(*elemType, static_cast(dim)); + ASSERT(type != nullptr, "Array type is null"); + if (usePtr) { + return GetOrCreatePointerType(*type); + } else { + return type; + } + } + default: + MIRType *type = GetMIRTypeForPrim(name[0]); + CHECK_FATAL(type, "Unresolved type %s", name.c_str()); + return type; + } +} + +MIRType *FETypeManager::GetOrCreatePointerType(const MIRType &type, PrimType ptyPtr) { + MIRType *retType = GlobalTables::GetTypeTable().GetOrCreatePointerType(type, ptyPtr); + CHECK_NULL_FATAL(retType); + return retType; +} + +MIRType *FETypeManager::GetOrCreateArrayType(MIRType &elemType, uint8 dim, PrimType ptyPtr) { + switch (srcLang) { + case kSrcLangJava: + case kSrcLangC: // Need to be optimized + return GetOrCreateJArrayType(elemType, dim, ptyPtr); + default: + CHECK_FATAL(false, "unsupported src lang: %d", srcLang); + return nullptr; + } +} + +MIRType *FETypeManager::GetOrCreateJArrayType(MIRType &elem, uint8 dim, PrimType ptyPtr) { + MIRType *type = &elem; + for (uint8 i = 0; i < dim; i++) { + type = GlobalTables::GetTypeTable().GetOrCreateJarrayType(*type); + CHECK_NULL_FATAL(type); + if (i != dim - 1) { + type = GetOrCreatePointerType(*type, ptyPtr); + CHECK_NULL_FATAL(type); + } + } + CHECK_NULL_FATAL(type); + return type; +} + +void FETypeManager::AddClassToModule(const MIRStructType &structType) { + module.AddClass(structType.GetTypeIndex()); +} + +FEStructElemInfo *FETypeManager::RegisterStructFieldInfo( + const StructElemNameIdx &structElemNameIdx, MIRSrcLang argSrcLang, bool isStatic) { + std::lock_guard lk(feTypeManagerMtx); + FEStructElemInfo *ptrInfo = GetStructElemInfo(structElemNameIdx.full); + if (ptrInfo != nullptr) { + return ptrInfo; + } + ptrInfo = allocator.GetMemPool()->New(allocator, structElemNameIdx, argSrcLang, isStatic); + CHECK_FATAL(mapStructElemInfo.insert(std::make_pair(structElemNameIdx.full, ptrInfo)).second == true, + "register struct elem info failed"); + return ptrInfo; +} + +FEStructElemInfo *FETypeManager::RegisterStructMethodInfo( + const StructElemNameIdx &structElemNameIdx, MIRSrcLang argSrcLang, bool isStatic) { + std::lock_guard lk(feTypeManagerMtx); + FEStructElemInfo *ptrInfo = GetStructElemInfo(structElemNameIdx.full); + if (ptrInfo != nullptr) { + return ptrInfo; + } + ptrInfo = allocator.GetMemPool()->New(allocator, structElemNameIdx, argSrcLang, isStatic); + CHECK_FATAL(mapStructElemInfo.insert(std::make_pair(structElemNameIdx.full, ptrInfo)).second == true, + "register struct elem info failed"); + return ptrInfo; +} + +FEStructElemInfo *FETypeManager::GetStructElemInfo(const GStrIdx &fullNameIdx) const { + auto it = mapStructElemInfo.find(fullNameIdx); + if (it == mapStructElemInfo.end()) { + return nullptr; + } + return it->second; +} + +MIRFunction *FETypeManager::GetMIRFunction(const std::string &classMethodName, bool isStatic){ + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(classMethodName); + return GetMIRFunction(nameIdx, isStatic); +} + +MIRFunction *FETypeManager::GetMIRFunction(const GStrIdx &nameIdx, bool isStatic) { + const std::unordered_map &funcMap = isStatic ? nameStaticFuncMap : nameFuncMap; + auto it = funcMap.find(nameIdx); + if (it != funcMap.end()) { + return it->second; + } + const std::unordered_map &mpltFuncMap = isStatic ? mpltNameStaticFuncMap : + mpltNameFuncMap; + auto it2 = mpltFuncMap.find(nameIdx); + if (it2 != mpltFuncMap.end()) { + return it2->second; + } + return nullptr; +} + +MIRFunction *FETypeManager::CreateFunction(const GStrIdx &nameIdx, const TyIdx &retTypeIdx, + const std::vector &argsTypeIdx, bool isVarg, bool isStatic) { + HIR2MPL_PARALLEL_FORBIDDEN(); + MIRFunction *mirFunc = GetMIRFunction(nameIdx, isStatic); + if (mirFunc != nullptr) { + return mirFunc; + } + MIRSymbol *funcSymbol = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal); + funcSymbol->SetNameStrIdx(nameIdx); + bool added = GlobalTables::GetGsymTable().AddToStringSymbolMap(*funcSymbol); + if (!added) { + funcSymbol = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(nameIdx); + mirFunc = funcSymbol->GetFunction(); + if (mirFunc != nullptr) { + return mirFunc; + } + } + funcSymbol->SetStorageClass(kScText); + funcSymbol->SetSKind(kStFunc); + MemPool *mpModule = module.GetMemPool(); + ASSERT(mpModule, "mem pool is nullptr"); + mirFunc = mpModule->New(&module, funcSymbol->GetStIdx()); + mirFunc->AllocSymTab(); + size_t idx = GlobalTables::GetFunctionTable().GetFuncTable().size(); + CHECK_FATAL(idx < UINT32_MAX, "PUIdx is out of range"); + mirFunc->SetPuidx(static_cast(idx)); + mirFunc->SetPuidxOrigin(mirFunc->GetPuidx()); + GlobalTables::GetFunctionTable().GetFuncTable().push_back(mirFunc); + std::vector argsAttr; + for (uint32_t i = 0; i < argsTypeIdx.size(); i++) { + argsAttr.emplace_back(TypeAttrs()); + } + mirFunc->SetBaseClassFuncNames(nameIdx); + funcSymbol->SetTyIdx(GlobalTables::GetTypeTable().GetOrCreateFunctionType(retTypeIdx, argsTypeIdx, argsAttr, + isVarg)->GetTypeIndex()); + funcSymbol->SetFunction(mirFunc); + MIRFuncType *functype = static_cast(funcSymbol->GetType()); + mirFunc->SetMIRFuncType(functype); + mirFunc->SetReturnTyIdx(retTypeIdx); + if (isStatic) { + mirFunc->SetAttr(FUNCATTR_static); + CHECK_FATAL(nameStaticFuncMap.insert(std::make_pair(nameIdx, mirFunc)).second, "nameStaticFuncMap insert failed"); + } else { + CHECK_FATAL(nameFuncMap.insert(std::make_pair(nameIdx, mirFunc)).second, "nameFuncMap insert failed"); + } + return mirFunc; +} + +MIRFunction *FETypeManager::CreateFunction(const std::string &methodName, const std::string &returnTypeName, + const std::vector &argTypeNames, bool isVarg, bool isStatic) { + HIR2MPL_PARALLEL_FORBIDDEN(); + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(methodName); + MIRFunction *mirFunc = GetMIRFunction(nameIdx, isStatic); + if (mirFunc != nullptr) { + return mirFunc; + } + MIRType *returnType = GetOrCreateTypeFromName(returnTypeName, FETypeFlag::kSrcUnknown, true); + std::vector argsTypeIdx; + for (const std::string &typeName : argTypeNames) { + MIRType *argType = GetOrCreateTypeFromName(typeName, FETypeFlag::kSrcUnknown, true); + argsTypeIdx.push_back(argType->GetTypeIndex()); + } + return CreateFunction(nameIdx, returnType->GetTypeIndex(), argsTypeIdx, isVarg, isStatic); +} + +const FEIRType *FETypeManager::GetOrCreateFEIRTypeByName(const std::string &typeName, const GStrIdx &typeNameIdx, + MIRSrcLang argSrcLang) { + const FEIRType *feirType = GetFEIRTypeByName(typeName); + if (feirType != nullptr) { + return feirType; + } + HIR2MPL_PARALLEL_FORBIDDEN(); + UniqueFEIRType uniType; + switch (argSrcLang) { + case kSrcLangJava: + uniType = FEIRTypeHelper::CreateTypeByJavaName(typeName, true, false); + break; + case kSrcLangC: + WARN(kLncWarn, "kSrcLangC GetOrCreateFEIRTypeByName NYI"); + break; + default: + CHECK_FATAL(false, "unsupported language"); + return nullptr; + } + feirType = uniType.get(); + nameFEIRTypeList.push_back(std::move(uniType)); + if (typeNameIdx == 0) { + nameFEIRTypeMap[GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(typeName)] = feirType; + } else { + nameFEIRTypeMap[typeNameIdx] = feirType; + } + return feirType; +} + +const FEIRType *FETypeManager::GetOrCreateFEIRTypeByName(const GStrIdx &typeNameIdx, MIRSrcLang argSrcLang) { + const std::string &typeName = GlobalTables::GetStrTable().GetStringFromStrIdx(typeNameIdx); + return GetOrCreateFEIRTypeByName(typeName, typeNameIdx, argSrcLang); +} + +const FEIRType *FETypeManager::GetFEIRTypeByName(const std::string &typeName) const { + GStrIdx typeNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(typeName); + return GetFEIRTypeByName(typeNameIdx); +} + +const FEIRType *FETypeManager::GetFEIRTypeByName(const GStrIdx &typeNameIdx) const { + auto it = nameFEIRTypeMap.find(typeNameIdx); + if (it == nameFEIRTypeMap.end()) { + return nullptr; + } else { + return it->second; + } +} + +bool FETypeManager::IsAntiProguardFieldStruct(const GStrIdx &structNameIdx) { + return setAntiProguardFieldStructIdx.find(structNameIdx) != setAntiProguardFieldStructIdx.end(); +} + +bool FETypeManager::IsStructType(const MIRType &type) { + MIRTypeKind kind = type.GetKind(); + return kind == kTypeStruct || kind == kTypeStructIncomplete || + kind == kTypeClass || kind == kTypeClassIncomplete || + kind == kTypeInterface || kind == kTypeInterfaceIncomplete || + kind == kTypeUnion; +} + +PrimType FETypeManager::GetPrimType(const std::string &name) { +#define LOAD_ALGO_PRIMARY_TYPE +#define PRIMTYPE(P) \ + if (name.compare(#P) == 0) { \ + return PTY_##P; \ + } +#include "prim_types.def" +#undef PRIMTYPE + return kPtyInvalid; +} + +MIRType *FETypeManager::GetMIRTypeForPrim(char c) { + switch (c) { + case 'B': + return GlobalTables::GetTypeTable().GetInt8(); + case 'C': + return GlobalTables::GetTypeTable().GetUInt16(); + case 'S': + return GlobalTables::GetTypeTable().GetInt16(); + case 'Z': + return GlobalTables::GetTypeTable().GetUInt1(); + case 'I': + return GlobalTables::GetTypeTable().GetInt32(); + case 'J': + return GlobalTables::GetTypeTable().GetInt64(); + case 'F': + return GlobalTables::GetTypeTable().GetFloat(); + case 'D': + return GlobalTables::GetTypeTable().GetDouble(); + case 'V': + return GlobalTables::GetTypeTable().GetVoid(); + case 'R': + return GlobalTables::GetTypeTable().GetRef(); + default: + return nullptr; + } +} + +std::string FETypeManager::GetBaseTypeName(const std::string &name, uint32 &dim, bool inMpl) { + dim = 0; + char prefix = inMpl ? 'A' : '['; + while (name[dim] == prefix) { + dim++; + } + return name.substr(dim); +} + +void FETypeManager::SetComplete(MIRStructType &structType) { + switch (structType.GetKind()) { + case kTypeClassIncomplete: + structType.SetMIRTypeKind(kTypeClass); + break; + case kTypeInterfaceIncomplete: + structType.SetMIRTypeKind(kTypeInterface); + break; + case kTypeStructIncomplete: + structType.SetMIRTypeKind(kTypeStruct); + break; + default: + break; + } +} + +std::string FETypeManager::TypeAttrsToString(const TypeAttrs &attrs) { + std::stringstream ss; +#define TYPE_ATTR +#define ATTR(A) \ + if (attrs.GetAttr(ATTR_##A)) \ + ss << " " << #A; +#include "all_attributes.def" +#undef ATTR +#undef TYPE_ATTR + ss << " "; + return ss.str(); +} + +void FETypeManager::MarkExternStructType() { + for (auto elem : structNameTypeMap) { + if (elem.second.second != FETypeFlag::kSrcInput && + elem.second.second != FETypeFlag::kSrcMplt && + elem.second.second != FETypeFlag::kSrcMpltSys && + elem.second.second != FETypeFlag::kSrcMpltApk) { + module.AddExternStructType(elem.second.first); + } + } +} + +void FETypeManager::InitMCCFunctions() { + if (srcLang == kSrcLangJava) { + InitFuncMCCGetOrInsertLiteral(); + } +} + +void FETypeManager::InitFuncMCCGetOrInsertLiteral() { + std::string funcName = "MCC_GetOrInsertLiteral"; + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcName); + MIRType *typeString = kFEIRTypeJavaString->GenerateMIRTypeAuto(kSrcLangJava); + std::vector argsType; + funcMCCGetOrInsertLiteral = CreateFunction(nameIdx, typeString->GetTypeIndex(), argsType, false, false); + funcMCCGetOrInsertLiteral->SetAttr(FUNCATTR_pure); + funcMCCGetOrInsertLiteral->SetAttr(FUNCATTR_nosideeffect); + funcMCCGetOrInsertLiteral->SetAttr(FUNCATTR_noprivate_defeffect); + nameMCCFuncMap[nameIdx] = funcMCCGetOrInsertLiteral; +} + +MIRFunction *FETypeManager::GetMCCFunction(const std::string &funcName) const { + GStrIdx funcNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcName); + return GetMCCFunction(funcNameIdx); +} + +MIRFunction *FETypeManager::GetMCCFunction(const GStrIdx &funcNameIdx) const { + auto it = nameMCCFuncMap.find(funcNameIdx); + if (it == nameMCCFuncMap.end()) { + return nullptr; + } else { + return it->second; + } +} +} // namespace maple diff --git a/src/hir2mpl/common/src/fe_utils.cpp b/src/hir2mpl/common/src/fe_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31c17b6590983a46e1f19eed2c350fdc59c5c3fd --- /dev/null +++ b/src/hir2mpl/common/src/fe_utils.cpp @@ -0,0 +1,569 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_utils.h" +#include +#include "mpl_logging.h" +#include "mir_type.h" +#include "mir_builder.h" +#include "fe_manager.h" +namespace maple { +// ---------- FEUtils ---------- +const std::string FEUtils::kBoolean = "Z"; +const std::string FEUtils::kByte = "B"; +const std::string FEUtils::kShort = "S"; +const std::string FEUtils::kChar = "C"; +const std::string FEUtils::kInt = "I"; +const std::string FEUtils::kLong = "J"; +const std::string FEUtils::kFloat = "F"; +const std::string FEUtils::kDouble = "D"; +const std::string FEUtils::kVoid = "V"; +const std::string FEUtils::kThis = "_this"; +const std::string FEUtils::kMCCStaticFieldGetBool = "MCC_StaticFieldGetBool"; +const std::string FEUtils::kMCCStaticFieldGetByte = "MCC_StaticFieldGetByte"; +const std::string FEUtils::kMCCStaticFieldGetShort = "MCC_StaticFieldGetShort"; +const std::string FEUtils::kMCCStaticFieldGetChar = "MCC_StaticFieldGetChar"; +const std::string FEUtils::kMCCStaticFieldGetInt = "MCC_StaticFieldGetInt"; +const std::string FEUtils::kMCCStaticFieldGetLong = "MCC_StaticFieldGetLong"; +const std::string FEUtils::kMCCStaticFieldGetFloat = "MCC_StaticFieldGetFloat"; +const std::string FEUtils::kMCCStaticFieldGetDouble = "MCC_StaticFieldGetDouble"; +const std::string FEUtils::kMCCStaticFieldGetObject = "MCC_StaticFieldGetObject"; + +const std::string FEUtils::kMCCStaticFieldSetBool = "MCC_StaticFieldSetBool"; +const std::string FEUtils::kMCCStaticFieldSetByte = "MCC_StaticFieldSetByte"; +const std::string FEUtils::kMCCStaticFieldSetShort = "MCC_StaticFieldSetShort"; +const std::string FEUtils::kMCCStaticFieldSetChar = "MCC_StaticFieldSetChar"; +const std::string FEUtils::kMCCStaticFieldSetInt = "MCC_StaticFieldSetInt"; +const std::string FEUtils::kMCCStaticFieldSetLong = "MCC_StaticFieldSetLong"; +const std::string FEUtils::kMCCStaticFieldSetFloat = "MCC_StaticFieldSetFloat"; +const std::string FEUtils::kMCCStaticFieldSetDouble = "MCC_StaticFieldSetDouble"; +const std::string FEUtils::kMCCStaticFieldSetObject = "MCC_StaticFieldSetObject"; + +std::vector FEUtils::Split(const std::string &str, char delim) { + std::vector ans; + std::stringstream ss; + ss.str(str); + std::string item; + while (std::getline(ss, item, delim)) { + ans.push_back(item); + } + return ans; +} + +uint8 FEUtils::GetWidth(PrimType primType) { + switch (primType) { + case PTY_u1: + return 1; + case PTY_i8: + case PTY_u8: + return 8; + case PTY_i16: + case PTY_u16: + return 16; + case PTY_i32: + case PTY_u32: + case PTY_f32: + return 32; + case PTY_i64: + case PTY_u64: + case PTY_f64: + return 64; + default: + CHECK_FATAL(false, "unsupported type %d", primType); + return 0; + } +} + +bool FEUtils::IsInteger(PrimType primType) { + return (primType == PTY_i8) || (primType == PTY_u8) || + (primType == PTY_i16) || (primType == PTY_u16) || + (primType == PTY_i32) || (primType == PTY_u32) || + (primType == PTY_i64) || (primType == PTY_u64); +} + +bool FEUtils::IsSignedInteger(PrimType primType) { + return (primType == PTY_i8) || (primType == PTY_i16) || (primType == PTY_i32) || (primType == PTY_i64); +} + +bool FEUtils::IsUnsignedInteger(PrimType primType) { + return (primType == PTY_u8) || (primType == PTY_u16) || (primType == PTY_u32) || (primType == PTY_u64); +} + +PrimType FEUtils::MergePrimType(PrimType primType1, PrimType primType2) { + if (primType1 == primType2) { + return primType1; + } + // merge signed integer + CHECK_FATAL(LogicXOR(IsSignedInteger(primType1), IsSignedInteger(primType2)) == false, + "can not merge type %s and %s", GetPrimTypeName(primType1), GetPrimTypeName(primType2)); + if (IsSignedInteger(primType1)) { + return GetPrimTypeSize(primType1) >= GetPrimTypeSize(primType2) ? primType1 : primType2; + } + + // merge unsigned integer + CHECK_FATAL(LogicXOR(IsUnsignedInteger(primType1), IsUnsignedInteger(primType2)) == false, + "can not merge type %s and %s", GetPrimTypeName(primType1), GetPrimTypeName(primType2)); + if (IsUnsignedInteger(primType1)) { + if (GetPrimTypeSize(primType1) == GetPrimTypeSize(primType2) && GetPrimTypeSize(primType1) == 1) { + return PTY_u8; + } else { + return GetPrimTypeSize(primType1) >= GetPrimTypeSize(primType2) ? primType1 : primType2; + } + } + + // merge float + CHECK_FATAL(LogicXOR(IsPrimitiveFloat(primType1), IsPrimitiveFloat(primType2)) == false, + "can not merge type %s and %s", GetPrimTypeName(primType1), GetPrimTypeName(primType2)); + if (IsPrimitiveFloat(primType1)) { + return GetPrimTypeSize(primType1) >= GetPrimTypeSize(primType2) ? primType1 : primType2; + } + + CHECK_FATAL(false, "can not merge type %s and %s", GetPrimTypeName(primType1), GetPrimTypeName(primType2)); + return PTY_unknown; +} + +uint8 FEUtils::GetDim(const std::string &typeName) { + uint8 dim = 0; + for (size_t i = 0; i < typeName.length(); ++i) { + if (typeName.at(i) == 'A') { + dim++; + } else { + break; + } + } + return dim; +} + +std::string FEUtils::GetBaseTypeName(const std::string &typeName) { + return typeName.substr(GetDim(typeName)); +} + +PrimType FEUtils::GetPrimType(const GStrIdx &typeNameIdx) { + if (typeNameIdx == GetBooleanIdx()) { + return PTY_u1; + } + if (typeNameIdx == GetByteIdx()) { + return PTY_i8; + } + if (typeNameIdx == GetShortIdx()) { + return PTY_i16; + } + if (typeNameIdx == GetCharIdx()) { + return PTY_u16; + } + if (typeNameIdx == GetIntIdx()) { + return PTY_i32; + } + if (typeNameIdx == GetLongIdx()) { + return PTY_i64; + } + if (typeNameIdx == GetFloatIdx()) { + return PTY_f32; + } + if (typeNameIdx == GetDoubleIdx()) { + return PTY_f64; + } + if (typeNameIdx == GetVoidIdx()) { + return PTY_void; + } + return PTY_ref; +} + +std::string FEUtils::GetSequentialName0(const std::string &prefix, uint32_t num) { + std::stringstream ss; + ss << prefix << num; + return ss.str(); +} + +uint32 FEUtils::GetSequentialNumber() { + static uint32 unnamedSymbolIdx = 1; + return unnamedSymbolIdx++; +} + +std::string FEUtils::GetFileNameHashStr(const std::string &fileName, uint32 seed) { + const char *name = fileName.c_str(); + uint32 hash = 0; + while (*name) { + uint8_t uName = *name++; + hash = hash * seed + uName; + } + return kRenameKeyWord + std::to_string(hash); +} + +std::string FEUtils::GetSequentialName(const std::string &prefix) { + std::string name = GetSequentialName0(prefix, GetSequentialNumber()); + return name; +} + +std::string FEUtils::CreateLabelName() { + static uint32 unnamedSymbolIdx = 1; + return "L." + std::to_string(unnamedSymbolIdx++); +} + +bool FEUtils::TraverseToNamedField(MIRStructType &structType, const GStrIdx &nameIdx, FieldID &fieldID, + bool isTopLevel) { + for (uint32 fieldIdx = 0; fieldIdx < structType.GetFieldsSize(); ++fieldIdx) { + ++fieldID; + TyIdx fieldTyIdx = structType.GetFieldsElemt(fieldIdx).second.first; + MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx); + ASSERT(fieldType != nullptr, "fieldType is null"); + if (isTopLevel && structType.GetFieldsElemt(fieldIdx).first == nameIdx) { + return true; + } + // The fields of an embedded structure array are assigned fieldIDs + if (fieldType->GetKind() == kTypeArray) { + fieldType = fieldType->EmbeddedStructType(); + } + if (fieldType != nullptr && fieldType->IsStructType()) { + auto *subStructType = static_cast(fieldType); + if (TraverseToNamedField(*subStructType, nameIdx, fieldID, false)) { + return true; + } + } + } + return false; +} + +FieldID FEUtils::GetStructFieldID(MIRStructType *base, const std::string &fieldName) { + MIRStructType *type = base; + std::vector fieldNames = FEUtils::Split(fieldName, '.'); + std::reverse(fieldNames.begin(), fieldNames.end()); + FieldID fieldID = 0; + for (const auto &f: fieldNames) { + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(f); + CHECK_FATAL(type->IsStructType(), "Must be struct type!"); + if (TraverseToNamedField(*type, strIdx, fieldID)) { + type = static_cast(base->GetFieldType(fieldID)); + } + } + return fieldID; +} + +MIRType *FEUtils::GetStructFieldType(const MIRStructType *type, FieldID fieldID) { + FieldID tmpID = fieldID; + FieldPair fieldPair = type->TraverseToFieldRef(tmpID); + MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldPair.second.first); + return fieldType; +} + +const MIRFuncType *FEUtils::GetFuncPtrType(const MIRType &type) { + const MIRType *mirType = &type; + if (mirType->GetKind() != kTypePointer) { + return nullptr; + } + mirType = static_cast(mirType)->GetPointedType(); + if (mirType->GetKind() != kTypePointer) { + return nullptr; + } + mirType = static_cast(mirType)->GetPointedType(); + if (mirType->GetKind() != kTypeFunction) { + return nullptr; + } + return static_cast(mirType); +} + +MIRConst *FEUtils::CreateImplicitConst(MIRType *type) { + switch (type->GetPrimType()) { + case PTY_u1: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_u1)); + } + case PTY_u8: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_u8)); + } + case PTY_u16: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_u16)); + } + case PTY_u32: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_u32)); + } + case PTY_u64: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_u64)); + } + case PTY_i8: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_i8)); + } + case PTY_i16: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_i16)); + } + case PTY_i32: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_i32)); + } + case PTY_i64: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_i64)); + } + case PTY_f32: { + return FEManager::GetModule().GetMemPool()->New( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_f32)); + } + case PTY_f64: { + return FEManager::GetModule().GetMemPool()->New( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_f64)); + } + case PTY_ptr: { + return GlobalTables::GetIntConstTable().GetOrCreateIntConst( + 0, *GlobalTables::GetTypeTable().GetPrimType(PTY_i64)); + } + case PTY_agg: { + auto *aggConst = FEManager::GetModule().GetMemPool()->New(FEManager::GetModule(), *type); + if (type->IsStructType()) { + auto structType = static_cast(type); + FieldID fieldID = 0; + for (auto &f:structType->GetFields()) { + fieldID++; + auto fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(f.second.first); + aggConst->AddItem(CreateImplicitConst(fieldType), fieldID); + } + } else if (type->GetKind() == kTypeArray) { + auto arrayType = static_cast(type); + MIRConst *elementConst; + if (arrayType->GetDim() > 1) { + uint32 subSizeArray[arrayType->GetDim()]; + for (int dim = 1; dim < arrayType->GetDim(); ++dim) { + subSizeArray[dim - 1] = arrayType->GetSizeArrayItem(dim); + } + auto subArrayType = GlobalTables::GetTypeTable().GetOrCreateArrayType( + *arrayType->GetElemType(), static_cast(arrayType->GetDim() - 1), subSizeArray); + elementConst = CreateImplicitConst(subArrayType); + } else { + elementConst = CreateImplicitConst(arrayType->GetElemType()); + } + for (uint32 i = 0; i < arrayType->GetSizeArrayItem(0); ++i) { + aggConst->AddItem(elementConst, 0); + } + } + return aggConst; + } + default: { + CHECK_FATAL(false, "Unsupported Primitive type: %d", type->GetPrimType()); + } + } +} + +PrimType FEUtils::GetVectorElementPrimType(PrimType vectorPrimType) { + switch (vectorPrimType) { + case PTY_v2i64: + return PTY_i64; + case PTY_v4i32: + case PTY_v2i32: + return PTY_i32; + case PTY_v8i16: + case PTY_v4i16: + return PTY_i16; + case PTY_v16i8: + case PTY_v8i8: + return PTY_i8; + case PTY_v2u64: + return PTY_u64; + case PTY_v4u32: + case PTY_v2u32: + return PTY_u32; + case PTY_v8u16: + case PTY_v4u16: + return PTY_u16; + case PTY_v16u8: + case PTY_v8u8: + return PTY_u8; + case PTY_v2f64: + return PTY_f64; + case PTY_v4f32: + case PTY_v2f32: + return PTY_f32; + default: + return PTY_unknown; + } +} + +bool FEUtils::EndsWith(const std::string &value, const std::string &ending) { + if (ending.size() > value.size()) { + return false; + } + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +} + +// in the search, curfieldid is being decremented until it reaches 1 +MIRConst *FEUtils::TraverseToMIRConst(MIRAggConst *aggConst, const MIRStructType &structType, FieldID &fieldID) { + if (aggConst == nullptr || !aggConst->GetConstVec().size()) { + return nullptr; + } + uint32 fieldIdx = 0; + FieldPair curPair = structType.GetFields()[0]; + MIRConst *curConst = aggConst->GetConstVec()[0]; + while (fieldID > 1) { + --fieldID; + MIRType *curFieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(curPair.second.first); + MIRStructType *subStructTy = curFieldType->EmbeddedStructType(); + if (subStructTy != nullptr && curConst->GetKind() == kConstAggConst) { + curConst = TraverseToMIRConst(static_cast(curConst), *subStructTy, fieldID); + if (fieldID == 1 && curConst != nullptr) { + return curConst; + } + } + ++fieldIdx; + if (fieldIdx == structType.GetFields().size()) { + return nullptr; + } + if (structType.GetKind() == kTypeUnion) { + curConst = aggConst->GetConstVec()[0]; // union only is one element + } else { + curConst = aggConst->GetConstVec()[fieldIdx]; + } + curPair = structType.GetFields()[fieldIdx]; + } + return curConst; +} + +// ---------- FELinkListNode ---------- +FELinkListNode::FELinkListNode() + : prev(nullptr), next(nullptr) {} + +FELinkListNode::~FELinkListNode() { + prev = nullptr; + next = nullptr; +} + +void FELinkListNode::InsertBefore(FELinkListNode *ins) { + InsertBefore(ins, this); +} + +void FELinkListNode::InsertAfter(FELinkListNode *ins) { + InsertAfter(ins, this); +} + +void FELinkListNode::InsertBefore(FELinkListNode *ins, FELinkListNode *pos) { + // pos_p -- ins -- pos + if (pos == nullptr || pos->prev == nullptr || ins == nullptr) { + CHECK_FATAL(false, "invalid input"); + } + FELinkListNode *posPrev = pos->prev; + posPrev->next = ins; + pos->prev = ins; + ins->prev = posPrev; + ins->next = pos; +} + +void FELinkListNode::InsertAfter(FELinkListNode *ins, FELinkListNode *pos) { + // pos -- ins -- pos_n + if (pos == nullptr || pos->next == nullptr || ins == nullptr) { + CHECK_FATAL(false, "invalid input"); + } + FELinkListNode *posNext = pos->next; + pos->next = ins; + posNext->prev = ins; + ins->prev = pos; + ins->next = posNext; +} + +void FELinkListNode::SpliceNodes(FELinkListNode *head, FELinkListNode *tail, FELinkListNode *newTail) { + FELinkListNode *stmt = head->GetNext(); + FELinkListNode *nextStmt = stmt; + do { + stmt = nextStmt; + nextStmt = stmt->GetNext(); + newTail->InsertBefore(stmt); + } while (nextStmt != nullptr && nextStmt != tail); +} + +uint32_t AstSwitchUtil::tempVarNo = 0; +const char *AstSwitchUtil::cleanLabel = "clean"; +const char *AstSwitchUtil::exitLabel = "exit"; +const char *AstSwitchUtil::blockLabel = "blklbl"; +const char *AstSwitchUtil::caseLabel = "case"; +const char *AstSwitchUtil::catchLabel = "catch"; +const char *AstSwitchUtil::endehLabel = "endeh"; + +std::string AstSwitchUtil::CreateEndOrExitLabelName() const { + std::string labelName = FEUtils::GetSequentialName0(blockLabel, tempVarNo); + ++tempVarNo; + return labelName; +} + +void AstSwitchUtil::MarkLabelUsed(const std::string &label) { + labelUsed[label] = true; +} + +void AstSwitchUtil::MarkLabelUnUsed(const std::string &label) { + labelUsed[label] = false; +} + +void AstSwitchUtil::PushNestedBreakLabels(const std::string &label) { + nestedBreakLabels.push(label); +} + +void AstSwitchUtil::PopNestedBreakLabels() { + nestedBreakLabels.pop(); +} + +void AstSwitchUtil::PushNestedCaseVectors(const std::pair &caseVec) { + nestedCaseVectors.push(caseVec); +} + +void AstSwitchUtil::PopNestedCaseVectors() { + nestedCaseVectors.pop(); +} + +bool AstSwitchUtil::CheckLabelUsed(const std::string &label) { + return labelUsed[label]; +} + +const std::pair &AstSwitchUtil::GetTopOfNestedCaseVectors() const { + return nestedCaseVectors.top(); +} + +const std::string &AstSwitchUtil::GetTopOfBreakLabels() const { + return nestedBreakLabels.top(); +} + +void AstLoopUtil::PushBreak(std::string label) { + breakLabels.push(std::make_pair(label, false)); +} + +std::string AstLoopUtil::GetCurrentBreak() { + breakLabels.top().second = true; + return breakLabels.top().first; +} + +bool AstLoopUtil::IsBreakLabelsEmpty() const { + return breakLabels.empty(); +} + +void AstLoopUtil::PopCurrentBreak() { + breakLabels.pop(); +} + +void AstLoopUtil::PushContinue(std::string label) { + continueLabels.push(std::make_pair(label, false)); +} + +std::string AstLoopUtil::GetCurrentContinue() { + continueLabels.top().second = true; + return continueLabels.top().first; +} + +bool AstLoopUtil::IsContinueLabelsEmpty() const { + return continueLabels.empty(); +} + +void AstLoopUtil::PopCurrentContinue() { + continueLabels.pop(); +} +} // namespace maple diff --git a/src/hir2mpl/common/src/fe_utils_ast.cpp b/src/hir2mpl/common/src/fe_utils_ast.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c10ca129c5da7473f6b1b288e1ec002aa43f6a9b --- /dev/null +++ b/src/hir2mpl/common/src/fe_utils_ast.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_utils_ast.h" +#include +#include "mpl_logging.h" + +namespace maple { +PrimType FEUtilAST::GetTypeFromASTTypeName(const std::string &typeName) { + const static std::map mapASTTypeNameToType = { + {"bool", PTY_u1}, + {"uint8", PTY_u8}, + {"uint16", PTY_u16}, + {"uint32", PTY_u32}, + {"uint64", PTY_u64}, + {"int8", PTY_i8}, + {"int16", PTY_i16}, + {"int32", PTY_i32}, + {"int64", PTY_i64}, + {"float", PTY_f32}, + {"double", PTY_f64}, + {"void", PTY_void} + }; + auto it = mapASTTypeNameToType.find(typeName); + CHECK_FATAL(it != mapASTTypeNameToType.end(), "Can not find typeName %s", typeName.c_str()); + return it->second; +} + +const std::string FEUtilAST::Type2Label(PrimType primType) { + switch (primType) { + case PTY_u1: + return "B"; + case PTY_i8: + return "A"; + case PTY_u8: + return "C"; + case PTY_i16: + return "S"; + case PTY_u16: + return "T"; + case PTY_i32: + return "I"; + case PTY_u32: + return "M"; + case PTY_i64: + return "O"; + case PTY_u64: + return "Q"; + case PTY_f32: + return "F"; + case PTY_f64: + return "D"; + case PTY_void: + return "V"; + default: + return "R"; + } +} +} // namespace maple diff --git a/src/hir2mpl/common/src/fe_utils_java.cpp b/src/hir2mpl/common/src/fe_utils_java.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4b363d9453e0697c49804f452aaa3fa188168759 --- /dev/null +++ b/src/hir2mpl/common/src/fe_utils_java.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "fe_utils_java.h" +#include "namemangler.h" + +namespace maple { +std::vector FEUtilJava::SolveMethodSignature(const std::string &signature) { + std::vector ans; + size_t pos1 = signature.find('('); + size_t pos2 = signature.find(')'); + if (pos1 == std::string::npos || pos2 == std::string::npos || pos1 > pos2) { + CHECK_FATAL(false, "invalid method signature %s", signature.c_str()); + } + std::string paramTypeNames = signature.substr(pos1 + 1, pos2 - pos1 - 1); + std::string retTypeName = signature.substr(pos2 + 1); + ans.push_back(retTypeName); + while (paramTypeNames.length() > 0) { + std::string typeName = SolveParamNameInJavaFormat(paramTypeNames); + ans.push_back(typeName); + paramTypeNames = paramTypeNames.substr(typeName.length()); + } + return ans; +} + +std::string FEUtilJava::SolveParamNameInJavaFormat(const std::string &signature) { + if (signature.empty()) { + return ""; + } + char c = signature[0]; + switch (c) { + case '[': + return "[" + SolveParamNameInJavaFormat(signature.substr(1)); + case 'L': { + size_t pos = signature.find(';'); + CHECK_FATAL(pos != std::string::npos, "invalid type %s", signature.c_str()); + return signature.substr(0, pos + 1); + } + default: { + std::string ans = ""; + ans.push_back(c); + return ans; + } + } +} +} // namespace maple diff --git a/src/hir2mpl/common/src/feir_builder.cpp b/src/hir2mpl/common/src/feir_builder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc9890620a63a6c9641e646df55a117a4189c8e8 --- /dev/null +++ b/src/hir2mpl/common/src/feir_builder.cpp @@ -0,0 +1,721 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "feir_builder.h" +#include "mpl_logging.h" +#include "global_tables.h" +#include "feir_var_reg.h" +#include "feir_var_name.h" +#include "fe_type_manager.h" +#include "feir_type_helper.h" + +namespace maple { +UniqueFEIRType FEIRBuilder::CreateType(PrimType basePty, const GStrIdx &baseNameIdx, uint32 dim) { + UniqueFEIRType type = std::make_unique(basePty, baseNameIdx, dim); + CHECK_NULL_FATAL(type); + return type; +} + +UniqueFEIRType FEIRBuilder::CreateArrayElemType(const UniqueFEIRType &arrayType) { + std::string typeName = arrayType->GetTypeName(); + ASSERT(typeName.length() > 1 && typeName.at(0) == 'A', "Invalid array type: %s", typeName.c_str()); + std::unique_ptr type = std::make_unique(); + type->LoadFromJavaTypeName(typeName.substr(1), true); + return type; +} + +UniqueFEIRType FEIRBuilder::CreateRefType(const GStrIdx &baseNameIdx, uint32 dim) { + return CreateType(PTY_ref, baseNameIdx, dim); +} + +UniqueFEIRType FEIRBuilder::CreateTypeByJavaName(const std::string &typeName, bool inMpl) { + UniqueFEIRType type = std::make_unique(PTY_ref); + CHECK_NULL_FATAL(type); + FEIRTypeDefault *ptrType = static_cast(type.get()); + ptrType->LoadFromJavaTypeName(typeName, inMpl); + return type; +} + +UniqueFEIRVar FEIRBuilder::CreateVarReg(uint32 regNum, PrimType primType, bool isGlobal) { + UniqueFEIRVar var = std::make_unique(regNum, primType); + CHECK_NULL_FATAL(var); + var->SetGlobal(isGlobal); + return var; +} + +UniqueFEIRVar FEIRBuilder::CreateVarReg(uint32 regNum, UniqueFEIRType type, bool isGlobal) { + UniqueFEIRVar var = std::make_unique(regNum, std::move(type)); + CHECK_NULL_FATAL(var); + var->SetGlobal(isGlobal); + return var; +} + +UniqueFEIRVar FEIRBuilder::CreateVarName(GStrIdx nameIdx, PrimType primType, bool isGlobal, bool withType) { + UniqueFEIRVar var = std::make_unique(nameIdx, withType); + CHECK_NULL_FATAL(var); + var->GetType()->SetPrimType(primType); + var->SetGlobal(isGlobal); + return var; +} + +UniqueFEIRVar FEIRBuilder::CreateVarName(const std::string &name, PrimType primType, bool isGlobal, + bool withType) { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + return CreateVarName(nameIdx, primType, isGlobal, withType); +} + +UniqueFEIRVar FEIRBuilder::CreateVarNameForC(GStrIdx nameIdx, MIRType &mirType, bool isGlobal, bool withType) { + UniqueFEIRType type = std::make_unique(mirType); + UniqueFEIRVar var = std::make_unique(nameIdx, std::move(type), withType); + var->SetGlobal(isGlobal); + return var; +} + +UniqueFEIRVar FEIRBuilder::CreateVarNameForC(const std::string &name, MIRType &mirType, bool isGlobal, bool withType) { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + return CreateVarNameForC(nameIdx, mirType, isGlobal, withType); +} + +UniqueFEIRVar FEIRBuilder::CreateVarNameForC(const std::string &name, UniqueFEIRType type, + bool isGlobal, bool withType) { + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + UniqueFEIRVar var = std::make_unique(nameIdx, std::move(type), withType); + var->SetGlobal(isGlobal); + return var; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprSizeOfType(UniqueFEIRType ty) { + UniqueFEIRExpr expr = std::make_unique(std::move(ty)); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprDRead(UniqueFEIRVar srcVar) { + UniqueFEIRExpr expr = std::make_unique(std::move(srcVar)); + CHECK_NULL_FATAL(expr); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprDReadAggField(UniqueFEIRVar srcVar, FieldID fieldID, UniqueFEIRType fieldType) { + CHECK_FATAL(srcVar != nullptr && srcVar->GetType()->GetPrimType() == PTY_agg, + "var type must be struct type, %u", srcVar->GetType()->GetPrimType()); + UniqueFEIRExpr expr = std::make_unique(std::move(srcVar)); + expr->SetFieldID(fieldID); + expr->SetFieldType(std::move(fieldType)); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprIRead(UniqueFEIRType returnType, UniqueFEIRType ptrType, + UniqueFEIRExpr expr, FieldID id /* optional parameters */) { + UniqueFEIRExpr feirExpr = std::make_unique(std::move(returnType), std::move(ptrType), + id, std::move(expr)); + return feirExpr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprAddrofLabel(const std::string &lbName, UniqueFEIRType exprTy) { + UniqueFEIRExpr expr = std::make_unique(lbName, std::move(exprTy)); + CHECK_NULL_FATAL(expr); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprAddrofVar(UniqueFEIRVar srcVar) { + UniqueFEIRExpr expr = std::make_unique(std::move(srcVar)); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprAddrofFunc(const std::string &addr) { + UniqueFEIRExpr expr = std::make_unique(addr); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprAddrofArray(UniqueFEIRType argTypeNativeArray, + UniqueFEIRExpr argExprArray, std::string argArrayName, + std::list &argExprIndexs) { + UniqueFEIRExpr expr = std::make_unique(std::move(argTypeNativeArray), + std::move(argExprArray), argArrayName, argExprIndexs); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprTernary(Opcode op, UniqueFEIRType type, UniqueFEIRExpr cExpr, + UniqueFEIRExpr tExpr, UniqueFEIRExpr fExpr) { + UniqueFEIRExpr expr = std::make_unique(op, std::move(type), std::move(cExpr), + std::move(tExpr), std::move(fExpr)); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprConstRefNull() { + return std::make_unique(int64{ 0 }, PTY_ref); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprConstPtrNull() { + return std::make_unique(int64{ 0 }, PTY_ptr); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprConstI8(int8 val) { + return std::make_unique(int64{ val }, PTY_i8); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprConstI16(int16 val) { + return std::make_unique(int64{ val }, PTY_i16); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprConstI32(int32 val) { + return std::make_unique(int64{ val }, PTY_i32); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprConstU32(uint32 val) { + return std::make_unique(val); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprConstI64(int64 val) { + return std::make_unique(val, PTY_i64); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprConstU64(uint64 val) { + return std::make_unique(val, PTY_u64); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprConstF32(float val) { + return std::make_unique(val); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprConstF64(double val) { + return std::make_unique(val); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprConstPtr(int64 val) { + return std::make_unique(val, PTY_ptr); +} + +// Create a const expr of specified prime type with fixed value. +// Note that loss of precision, byte value is only supported. +UniqueFEIRExpr FEIRBuilder::CreateExprConstAnyScalar(PrimType primType, int64 val) { + switch (primType) { + case PTY_u1: + case PTY_u8: + case PTY_u16: + case PTY_u32: + case PTY_u64: + case PTY_i8: + case PTY_i16: + case PTY_i32: + case PTY_i64: + case PTY_ptr: + case PTY_a64: + return std::make_unique(val, primType); + case PTY_f128: + // Not Implemented + CHECK_FATAL(false, "Not Implemented"); + return nullptr; + case PTY_f32: + return CreateExprConstF32(static_cast(val)); + case PTY_f64: + return CreateExprConstF64(static_cast(val)); + default: + if (IsPrimitiveVector(primType)) { + return CreateExprVdupAnyVector(primType, val); + } + CHECK_FATAL(false, "unsupported const prime type"); + return nullptr; + } +} + +UniqueFEIRExpr FEIRBuilder::CreateExprVdupAnyVector(PrimType primtype, int64 val) { +MIRIntrinsicID intrinsic; + switch (primtype) { +#define SET_VDUP(TY) \ + case PTY_##TY: \ + intrinsic = INTRN_vector_from_scalar_##TY; \ + break; + + SET_VDUP(v2i64) + SET_VDUP(v4i32) + SET_VDUP(v8i16) + SET_VDUP(v16i8) + SET_VDUP(v2u64) + SET_VDUP(v4u32) + SET_VDUP(v8u16) + SET_VDUP(v16u8) + SET_VDUP(v2f64) + SET_VDUP(v4f32) + SET_VDUP(v2i32) + SET_VDUP(v4i16) + SET_VDUP(v8i8) + SET_VDUP(v2u32) + SET_VDUP(v4u16) + SET_VDUP(v8u8) + SET_VDUP(v2f32) + default: + CHECK_FATAL(false, "Unhandled vector type in CreateExprVdupAnyVector"); + } + UniqueFEIRType feType = FEIRTypeHelper::CreateTypeNative(*GlobalTables::GetTypeTable().GetPrimType(primtype)); + UniqueFEIRExpr valExpr = CreateExprConstAnyScalar(FEUtils::GetVectorElementPrimType(primtype), val); + std::vector> argOpnds; + argOpnds.push_back(std::move(valExpr)); + return std::make_unique(std::move(feType), intrinsic, argOpnds); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprMathUnary(Opcode op, UniqueFEIRVar var0) { + UniqueFEIRExpr opnd0 = CreateExprDRead(std::move(var0)); + return std::make_unique(op, std::move(opnd0)); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprMathUnary(Opcode op, UniqueFEIRExpr expr) { + return std::make_unique(op, std::move(expr)); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprZeroCompare(Opcode op, UniqueFEIRExpr expr) { + CHECK_FATAL(op == OP_ne || op == OP_eq, "Unsupported op in CreateExprZeroCompare."); + if (op == OP_ne && expr->GetKind() == kExprBinary && static_cast(expr.get())->IsComparative()) { + return expr; + } + if (expr->GetKind() == kExprConst) { + FEIRExprConst *constExpr = static_cast(expr.get()); + int64 val; + if (op == OP_ne) { + val = constExpr->GetValue().u64 == 0 ? 0 : 1; + } else { + val = constExpr->GetValue().u64 == 0 ? 1 : 0; + } + return std::make_unique(val, PTY_u1); + } + UniqueFEIRExpr zeroExpr = (expr->GetPrimType() == PTY_ptr) ? CreateExprConstPtrNull() : + CreateExprConstAnyScalar(expr->GetPrimType(), 0); + return CreateExprMathBinary(op, std::move(expr), std::move(zeroExpr)); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprMathBinary(Opcode op, UniqueFEIRVar var0, UniqueFEIRVar var1) { + UniqueFEIRExpr opnd0 = CreateExprDRead(std::move(var0)); + UniqueFEIRExpr opnd1 = CreateExprDRead(std::move(var1)); + return std::make_unique(op, std::move(opnd0), std::move(opnd1)); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprMathBinary(Opcode op, UniqueFEIRExpr expr0, UniqueFEIRExpr expr1) { + return std::make_unique(op, std::move(expr0), std::move(expr1)); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprBinary(UniqueFEIRType exprType, Opcode op, + UniqueFEIRExpr expr0, UniqueFEIRExpr expr1) { + return std::make_unique(std::move(exprType), op, std::move(expr0), std::move(expr1)); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprBinary(Opcode op, UniqueFEIRExpr expr0, UniqueFEIRExpr expr1) { + return std::make_unique(op, std::move(expr0), std::move(expr1)); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprSExt(UniqueFEIRVar srcVar) { + return std::make_unique(OP_sext, PTY_i32, + std::make_unique(std::move(srcVar))); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprSExt(UniqueFEIRExpr srcExpr, PrimType dstType) { + return std::make_unique(OP_sext, dstType, std::move(srcExpr)); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprZExt(UniqueFEIRVar srcVar) { + return std::make_unique(OP_zext, PTY_i32, + std::make_unique(std::move(srcVar))); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprZExt(UniqueFEIRExpr srcExpr, PrimType dstType) { + return std::make_unique(OP_zext, dstType, std::move(srcExpr)); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprCvtPrim(UniqueFEIRVar srcVar, PrimType dstType) { + return CreateExprCastPrim(CreateExprDRead(std::move(srcVar)), dstType); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprCvtPrim(UniqueFEIRExpr srcExpr, PrimType dstType) { + UniqueFEIRExpr expr = std::make_unique(OP_cvt, std::move(srcExpr)); + CHECK_NULL_FATAL(expr); + FEIRExprTypeCvt *ptrExpr = static_cast(expr.get()); + ptrExpr->GetType()->SetPrimType(dstType); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprCvtPrim(UniqueFEIRExpr srcExpr, PrimType srcType, PrimType dstType) { + UniqueFEIRExpr expr = std::make_unique(OP_cvt, std::move(srcExpr)); + CHECK_NULL_FATAL(expr); + FEIRExprTypeCvt *ptrExpr = static_cast(expr.get()); + ptrExpr->SetSrcPrimType(srcType); + ptrExpr->GetType()->SetPrimType(dstType); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprCvtPrim(Opcode argOp, UniqueFEIRExpr srcExpr, PrimType dstType) { + UniqueFEIRExpr expr = std::make_unique(argOp, std::move(srcExpr)); + CHECK_NULL_FATAL(expr); + FEIRExprTypeCvt *ptrExpr = static_cast(expr.get()); + ptrExpr->GetType()->SetPrimType(dstType); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprCastPrim(UniqueFEIRExpr srcExpr, PrimType dstType) { + // Handle the case separately for future optimization and deletion. + // bool u1 + if (srcExpr->GetPrimType() == PTY_u1) { + if (IsPrimitiveFloat(dstType)) { + return CreateExprCvtPrim(std::move(srcExpr), PTY_u32, dstType); + } + return srcExpr; + } + + if (dstType == PTY_u1) { + return FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(srcExpr)); + } + + // Integer to Integer : 8, 16, 32, 64 bits Integer + auto createExprExt = [&]() { + if (FEUtils::IsUnsignedInteger(dstType)) { + return CreateExprZExt(std::move(srcExpr), dstType); + } else { + return CreateExprSExt(std::move(srcExpr), dstType); + } + }; + + if (FEUtils::IsInteger(srcExpr->GetPrimType()) && FEUtils::IsInteger(dstType)) { + // avoid using OP_cvt for integer types less than 32 bits + if (GetPrimTypeBitSize(dstType) < 32) { + return createExprExt(); + } + + if (GetPrimTypeBitSize(dstType) > GetPrimTypeBitSize(srcExpr->GetPrimType())) { + PrimType srcRegPty = GetRegPrimType(srcExpr->GetPrimType()); + if (srcRegPty == dstType) { + // avoid using OP_cvt for integer types less than 32 bits, but need to explicit transformation + if (GetPrimTypeBitSize(srcExpr->GetPrimType()) < 32) { + return createExprExt(); + } + return srcExpr; + } + return CreateExprCvtPrim(std::move(srcExpr), srcRegPty, dstType); + } + } + + // others + return CreateExprCvtPrim(std::move(srcExpr), dstType); +} + +UniqueFEIRExpr FEIRBuilder::CreateExprJavaNewInstance(UniqueFEIRType type) { + UniqueFEIRExpr expr = std::make_unique(std::move(type)); + CHECK_NULL_FATAL(expr); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprJavaNewInstance(UniqueFEIRType type, uint32 argTypeID) { + UniqueFEIRExpr expr = std::make_unique(std::move(type), argTypeID); + CHECK_NULL_FATAL(expr); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprJavaNewInstance(UniqueFEIRType type, uint32 argTypeID, bool isRcPermanent) { + UniqueFEIRExpr expr = std::make_unique(std::move(type), argTypeID, isRcPermanent); + CHECK_NULL_FATAL(expr); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprJavaNewArray(UniqueFEIRType type, UniqueFEIRExpr exprSize) { + UniqueFEIRExpr expr = std::make_unique(std::move(type), std::move(exprSize)); + CHECK_NULL_FATAL(expr); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprJavaNewArray(UniqueFEIRType type, UniqueFEIRExpr exprSize, uint32 typeID) { + UniqueFEIRExpr expr = std::make_unique(std::move(type), std::move(exprSize), typeID); + CHECK_NULL_FATAL(expr); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprJavaNewArray(UniqueFEIRType type, UniqueFEIRExpr exprSize, uint32 typeID, + bool isRcPermanent) { + UniqueFEIRExpr expr = std::make_unique( + std::move(type), std::move(exprSize), typeID, isRcPermanent); + CHECK_NULL_FATAL(expr); + return expr; +} + +UniqueFEIRExpr FEIRBuilder::CreateExprJavaArrayLength(UniqueFEIRExpr exprArray) { + UniqueFEIRExpr expr = std::make_unique(std::move(exprArray)); + CHECK_NULL_FATAL(expr); + return expr; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtDAssign(UniqueFEIRVar dstVar, UniqueFEIRExpr srcExpr, bool hasException) { + std::unique_ptr stmt = std::make_unique(std::move(dstVar), std::move(srcExpr)); + stmt->SetHasException(hasException); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtDAssignAggField(UniqueFEIRVar dstVar, UniqueFEIRExpr srcExpr, FieldID fieldID) { + UniqueFEIRStmt stmt = std::make_unique(std::move(dstVar), std::move(srcExpr), fieldID); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtIAssign(UniqueFEIRType dstType, UniqueFEIRExpr dstExpr, + UniqueFEIRExpr srcExpr, FieldID fieldID /* optional parameters */) { + UniqueFEIRStmt stmt = std::make_unique( + std::move(dstType), std::move(dstExpr), std::move(srcExpr), fieldID); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtGoto(uint32 targetLabelIdx) { + UniqueFEIRStmt stmt = std::make_unique(targetLabelIdx); + CHECK_NULL_FATAL(stmt); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtGoto(const std::string &labelName) { + UniqueFEIRStmt stmt = std::make_unique(labelName); + CHECK_NULL_FATAL(stmt); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtIGoto(UniqueFEIRExpr targetExpr) { + UniqueFEIRStmt stmt = std::make_unique(std::move(targetExpr)); + CHECK_NULL_FATAL(stmt); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtCondGoto(uint32 targetLabelIdx, Opcode op, UniqueFEIRExpr expr) { + UniqueFEIRStmt stmt = std::make_unique(op, targetLabelIdx, std::move(expr)); + CHECK_NULL_FATAL(stmt); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtSwitch(UniqueFEIRExpr expr) { + UniqueFEIRStmt stmt = std::make_unique(std::move(expr)); + CHECK_NULL_FATAL(stmt); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtIfWithoutElse(UniqueFEIRExpr cond, std::list &thenStmts) { + UniqueFEIRStmt stmt = std::make_unique(std::move(cond), thenStmts); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtIf(UniqueFEIRExpr cond, + std::list &thenStmts, + std::list &elseStmts) { + UniqueFEIRStmt stmt = std::make_unique(std::move(cond), thenStmts, elseStmts); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtJavaConstClass(UniqueFEIRVar dstVar, UniqueFEIRType type) { + UniqueFEIRType dstType = FETypeManager::kFEIRTypeJavaClass->Clone(); + dstVar->SetType(std::move(dstType)); + UniqueFEIRStmt stmt = std::make_unique(std::move(dstVar), std::move(type)); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtJavaConstString(UniqueFEIRVar dstVar, const std::string &strVal) { + UniqueFEIRType dstType = FETypeManager::kFEIRTypeJavaString->Clone(); + dstVar->SetType(std::move(dstType)); + UniqueFEIRStmt stmt = std::make_unique(std::move(dstVar), strVal, + 0, GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(strVal)); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtJavaCheckCast(UniqueFEIRVar dstVar, UniqueFEIRVar srcVar, UniqueFEIRType type) { + UniqueFEIRExpr expr = CreateExprDRead(std::move(srcVar)); + UniqueFEIRStmt stmt = std::make_unique(std::move(dstVar), std::move(expr), std::move(type), + FEIRStmtJavaTypeCheck::CheckKind::kCheckCast); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtJavaCheckCast(UniqueFEIRVar dstVar, UniqueFEIRVar srcVar, UniqueFEIRType type, + uint32 argTypeID) { + UniqueFEIRExpr expr = CreateExprDRead(std::move(srcVar)); + UniqueFEIRStmt stmt = std::make_unique(std::move(dstVar), std::move(expr), std::move(type), + FEIRStmtJavaTypeCheck::CheckKind::kCheckCast, + argTypeID); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtJavaInstanceOf(UniqueFEIRVar dstVar, UniqueFEIRVar srcVar, UniqueFEIRType type) { + UniqueFEIRExpr expr = CreateExprDRead(std::move(srcVar)); + UniqueFEIRStmt stmt = std::make_unique(std::move(dstVar), std::move(expr), std::move(type), + FEIRStmtJavaTypeCheck::CheckKind::kInstanceOf); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtJavaInstanceOf(UniqueFEIRVar dstVar, UniqueFEIRVar srcVar, UniqueFEIRType type, + uint32 argTypeID) { + UniqueFEIRExpr expr = CreateExprDRead(std::move(srcVar)); + UniqueFEIRStmt stmt = std::make_unique(std::move(dstVar), std::move(expr), std::move(type), + FEIRStmtJavaTypeCheck::CheckKind::kInstanceOf, + argTypeID); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtJavaFillArrayData(UniqueFEIRVar srcVar, const int8 *arrayData, + uint32 size, const std::string &arrayName) { + UniqueFEIRExpr expr = CreateExprDRead(std::move(srcVar)); + UniqueFEIRStmt stmt = std::make_unique(std::move(expr), arrayData, size, arrayName); + return stmt; +} + +std::list FEIRBuilder::CreateStmtArrayStore(UniqueFEIRVar varElem, UniqueFEIRVar varArray, + UniqueFEIRVar varIndex) { + std::list ans; + UniqueFEIRType arrayType = varElem->GetType()->Clone(); + (void)arrayType->ArrayIncrDim(); + UniqueFEIRExpr exprElem = CreateExprDRead(std::move(varElem)); + UniqueFEIRExpr exprArray = CreateExprDRead(std::move(varArray)); + UniqueFEIRExpr exprIndex = CreateExprDRead(std::move(varIndex)); + UniqueFEIRStmt stmt = std::make_unique(std::move(exprElem), std::move(exprArray), + std::move(exprIndex), std::move(arrayType)); + ans.push_back(std::move(stmt)); + return ans; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtArrayStoreOneStmt(UniqueFEIRVar varElem, UniqueFEIRVar varArray, + UniqueFEIRExpr exprIndex) { + UniqueFEIRType arrayType = varElem->GetType()->Clone(); + (void)arrayType->ArrayIncrDim(); + UniqueFEIRExpr exprElem = CreateExprDRead(std::move(varElem)); + UniqueFEIRExpr exprArray = CreateExprDRead(std::move(varArray)); + UniqueFEIRStmt stmt = std::make_unique(std::move(exprElem), std::move(exprArray), + std::move(exprIndex), std::move(arrayType)); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtArrayStoreOneStmtForC(UniqueFEIRExpr exprElem, UniqueFEIRExpr exprArray, + UniqueFEIRExpr exprIndex, UniqueFEIRType arrayType) { + UniqueFEIRStmt stmt = std::make_unique(std::move(exprElem), std::move(exprArray), + std::move(exprIndex), std::move(arrayType)); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtArrayStoreOneStmtForC(UniqueFEIRExpr exprElem, UniqueFEIRExpr exprArray, + UniqueFEIRExpr exprIndex, UniqueFEIRType arrayType, + const std::string &argArrayName) { + UniqueFEIRStmt stmt = std::make_unique(std::move(exprElem), std::move(exprArray), + std::move(exprIndex), std::move(arrayType), + argArrayName); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtArrayStoreOneStmtForC(UniqueFEIRExpr exprElem, UniqueFEIRExpr exprArray, + std::list exprIndexs, + UniqueFEIRType arrayType, const std::string &argArrayName) { + UniqueFEIRStmt stmt = std::make_unique(std::move(exprElem), std::move(exprArray), + exprIndexs, std::move(arrayType), + argArrayName); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtArrayStoreOneStmtForC(UniqueFEIRExpr exprElem, UniqueFEIRExpr exprArray, + UniqueFEIRExpr exprIndex, UniqueFEIRType arrayType, + UniqueFEIRType elemType, const std::string &argArrayName) { + UniqueFEIRStmt stmt = std::make_unique(std::move(exprElem), std::move(exprArray), + std::move(exprIndex), std::move(arrayType), + std::move(elemType), argArrayName); + return stmt; +} + +std::list FEIRBuilder::CreateStmtArrayLoad(UniqueFEIRVar varElem, UniqueFEIRVar varArray, + UniqueFEIRVar varIndex) { + std::list ans; + UniqueFEIRExpr exprArray = CreateExprDRead(std::move(varArray)); + UniqueFEIRExpr exprIndex = CreateExprDRead(std::move(varIndex)); + UniqueFEIRType arrayType = varElem->GetType()->Clone(); + (void)arrayType->ArrayIncrDim(); + UniqueFEIRExpr expr = std::make_unique(std::move(exprArray), std::move(exprIndex), + std::move(arrayType)); + UniqueFEIRStmt stmt = CreateStmtDAssign(std::move(varElem), std::move(expr), true); + ans.push_back(std::move(stmt)); + return ans; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtArrayLength(UniqueFEIRVar varLength, UniqueFEIRVar varArray) { + UniqueFEIRExpr exprArray = CreateExprDRead(std::move(varArray)); + UniqueFEIRExpr exprIntriOp = CreateExprJavaArrayLength(std::move(exprArray)); + UniqueFEIRStmt stmt = std::make_unique(std::move(varLength), std::move(exprIntriOp)); + return stmt; +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtRetype(UniqueFEIRVar varDst, const UniqueFEIRVar &varSrc) { + // ref -> ref : retype + // primitive + // short -> long : cvt GetPrimTypeSize + // long -> short : JAVAMERGE + PrimType dstType = varDst->GetType()->GetPrimType(); + PrimType srcType = varSrc->GetType()->GetPrimType(); + uint32 srcPrmTypeSize = GetPrimTypeSize(varSrc->GetType()->GetPrimType()); + uint32 dstPrmTypeSize = GetPrimTypeSize(dstType); + UniqueFEIRExpr dreadExpr = std::make_unique(varSrc->Clone()); + if (dstType == PTY_ref && srcType == PTY_ref) { + std::unique_ptr ptrTy = FEIRTypeHelper::CreatePointerType(varDst->GetType()->Clone(), PTY_ref); + UniqueFEIRExpr expr = std::make_unique(std::move(ptrTy), OP_retype, std::move(dreadExpr)); + return FEIRBuilder::CreateStmtDAssign(std::move(varDst), std::move(expr), false); + } else if (srcPrmTypeSize < dstPrmTypeSize || (IsPrimitiveFloat(srcType) && IsPrimitiveInteger(dstType)) || + dstType == PTY_ref) { + UniqueFEIRExpr expr = std::make_unique(varDst->GetType()->Clone(), OP_cvt, std::move(dreadExpr)); + return FEIRBuilder::CreateStmtDAssign(std::move(varDst), std::move(expr), false); + } else if (((IsPrimitiveInteger(dstType) || IsPrimitiveFloat(dstType)) && + (IsPrimitiveInteger(srcType) || IsPrimitiveFloat(srcType)) && + IsPrimitiveInteger(srcType) && IsPrimitiveFloat(dstType) && + GetPrimTypeBitSize(srcType) <= GetPrimTypeBitSize(dstType)) || + (IsPrimitiveInteger(srcType) && IsPrimitiveInteger(dstType))) { + std::vector> exprs; + exprs.emplace_back(std::move(dreadExpr)); + UniqueFEIRExpr javaMerge = std::make_unique(varDst->GetType()->Clone(), exprs); + return std::make_unique(std::move(varDst), std::move(javaMerge)); + } else { + WARN(kLncWarn, "Unsafe convert %s to %s", GetPrimTypeName(srcType), GetPrimTypeName(dstType)); + UniqueFEIRExpr expr = std::make_unique(varDst->GetType()->Clone(), OP_cvt, std::move(dreadExpr)); + return FEIRBuilder::CreateStmtDAssign(std::move(varDst), std::move(expr), false); + } + return nullptr; // Cannot retype, maybe introduced by redundant phi. +} + +UniqueFEIRStmt FEIRBuilder::CreateStmtComment(const std::string &comment) { + UniqueFEIRStmt stmt = std::make_unique(comment); + return stmt; +} + +UniqueFEIRExpr FEIRBuilder::ReadExprField(UniqueFEIRExpr expr, FieldID fieldID, UniqueFEIRType fieldType) { + FieldID baseID = expr->GetFieldID(); + expr->SetFieldID(baseID + fieldID); + expr->SetFieldType(std::move(fieldType)); + return expr; +} + +UniqueFEIRStmt FEIRBuilder::AssginStmtField(const UniqueFEIRExpr &addrExpr, UniqueFEIRExpr srcExpr, FieldID fieldID) { + UniqueFEIRStmt stmt; + FieldID baseID = addrExpr->GetFieldID(); + if (addrExpr->GetKind() == kExprDRead) { + stmt = CreateStmtDAssignAggField( + static_cast(addrExpr.get())->GetVar()->Clone(), std::move(srcExpr), baseID + fieldID); + } else if (addrExpr->GetKind() == kExprIRead) { + auto ireadExpr = static_cast(addrExpr.get()); + stmt = CreateStmtIAssign(ireadExpr->GetClonedPtrType(), ireadExpr->GetClonedOpnd(), + std::move(srcExpr), baseID + fieldID); + } else if (addrExpr->GetKind() == kExprIAddrof) { + auto iaddrofExpr = static_cast(addrExpr.get()); + stmt = CreateStmtIAssign(iaddrofExpr->GetClonedPtrType(), iaddrofExpr->GetClonedOpnd(), + std::move(srcExpr), baseID + fieldID); + } else { + CHECK_FATAL(false, "unsupported expr in AssginStmtField"); + } + return stmt; +} + +bool FEIRBuilder::IsZeroConstExpr(const std::unique_ptr &expr) { + if (expr != nullptr && expr->GetKind() == kExprConst && + static_cast(expr.get())->GetValue().u64 == 0) { + return true; + } + return false; +} +} // namespace maple diff --git a/src/hir2mpl/common/src/feir_stmt.cpp b/src/hir2mpl/common/src/feir_stmt.cpp new file mode 100755 index 0000000000000000000000000000000000000000..9d83f63c1cb14b3cb2b30b8f45fa8567dbc10417 --- /dev/null +++ b/src/hir2mpl/common/src/feir_stmt.cpp @@ -0,0 +1,4361 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "feir_stmt.h" +#include "opcode_info.h" +#include "literalstrname.h" +#include "mir_type.h" +#include "feir_builder.h" +#include "feir_var_reg.h" +#include "feir_var_name.h" +#include "fe_manager.h" +#include "hir2mpl_env.h" +#include "feir_var_type_scatter.h" +#include "fe_options.h" +#include "feir_type_helper.h" +#include "bc_util.h" +#include "rc_setter.h" +#include "fe_utils.h" +#include "enhance_c_checker.h" +#include "fe_macros.h" + +namespace maple { +std::string GetFEIRNodeKindDescription(FEIRNodeKind kindArg) { + switch (kindArg) { +#define FEIR_NODE_KIND(kind, description) \ + case k##kind: { \ + return description; \ + } +#include "feir_node_kind.def" +#undef FEIR_NODE_KIND + default: { + CHECK_FATAL(false, "Undefined FEIRNodeKind %u", static_cast(kindArg)); + return ""; + } + } +} + +// ---------- FEIRStmt ---------- +std::list FEIRStmt::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + return std::list(); +} + +bool FEIRStmt::IsStmtInstImpl() const { + switch (kind) { + case kStmtAssign: + case kStmtNonAssign: + case kStmtDAssign: + case kStmtJavaTypeCheck: + case kStmtJavaConstClass: + case kStmtJavaConstString: + case kStmtJavaMultiANewArray: + case kStmtCallAssign: + case kStmtJavaDynamicCallAssign: + case kStmtIAssign: + case kStmtUseOnly: + case kStmtReturn: + case kStmtBranch: + case kStmtGoto: + case kStmtCondGoto: + case kStmtSwitch: + case kStmtArrayStore: + case kStmtFieldStore: + case kStmtFieldLoad: + return true; + default: + return false; + } +} + +bool FEIRStmt::IsStmtInstComment() const { + return (kind == kStmtPesudoComment); +} + +bool FEIRStmt::ShouldHaveLOC() const { + return (IsStmtInstImpl() || IsStmtInstComment()); +} + +BaseNode *FEIRStmt::ReplaceAddrOfNode(BaseNode *node) const { + switch (node->GetOpCode()) { + case OP_dread: + node->SetOpCode(OP_addrof); + node->SetPrimType(PTY_ptr); + return node; + case OP_iread: + node->SetOpCode(OP_iaddrof); + node->SetPrimType(PTY_ptr); + return node; + default: + return node; + } +} + +std::string FEIRStmt::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +void FEIRStmt::DumpImpl(const std::string &prefix) const { + std::cout << prefix << "FEIRStmt" << id << "(kind=" << GetFEIRNodeKindDescription(kind) << ")\n"; +} + +// ---------- FEIRStmtCheckPoint ---------- +void FEIRStmtCheckPoint::Reset() { + predCPs.clear(); + localUD.clear(); + lastDef.clear(); + cacheUD.clear(); + defs.clear(); + uses.clear(); +} + +void FEIRStmtCheckPoint::RegisterDFGNode(UniqueFEIRVar &var) { + CHECK_NULL_FATAL(var); + if (var->IsDef()) { + defs.push_back(&var); + lastDef[FEIRDFGNode(var)] = &var; + } else { + uses.push_back(&var); + auto it = lastDef.find(FEIRDFGNode(var)); + if (it != lastDef.end()) { + CHECK_FATAL(localUD[&var].insert(it->second).second, "localUD insert failed"); + } + } +} + +void FEIRStmtCheckPoint::RegisterDFGNodes(const std::list &vars) { + for (UniqueFEIRVar *var : vars) { + CHECK_NULL_FATAL(var); + RegisterDFGNode(*var); + } +} + +void FEIRStmtCheckPoint::RegisterDFGNodeFromAllVisibleStmts() { + if (firstVisibleStmt == nullptr) { + return; + } + FELinkListNode *node = static_cast(firstVisibleStmt); + while (node != this) { + FEIRStmt *stmt = static_cast(node); + stmt->RegisterDFGNodes2CheckPoint(*this); + node = node->GetNext(); + } +} + +void FEIRStmtCheckPoint::AddPredCheckPoint(FEIRStmtCheckPoint &stmtCheckPoint) { + if (predCPs.find(&stmtCheckPoint) == predCPs.end()) { + CHECK_FATAL(predCPs.insert(&stmtCheckPoint).second, "pred checkpoints insert error"); + } +} + +std::set &FEIRStmtCheckPoint::CalcuDef(UniqueFEIRVar &use) { + CHECK_NULL_FATAL(use); + auto itLocal = localUD.find(&use); + // search localUD + if (itLocal != localUD.end()) { + return itLocal->second; + } + // search cacheUD + auto itCache = cacheUD.find(FEIRDFGNode(use)); + if (itCache != cacheUD.end()) { + return itCache->second; + } + // search by DFS + std::set visitSet; + std::set &result = cacheUD[FEIRDFGNode(use)]; + CalcuDefDFS(result, use, *this, visitSet); + if (result.size() == 0) { + WARN(kLncWarn, "use var %s without def", use->GetNameRaw().c_str()); + } + return result; +} + +void FEIRStmtCheckPoint::CalcuDefDFS(std::set &result, const UniqueFEIRVar &use, + const FEIRStmtCheckPoint &cp, + std::set &visitSet) const { + CHECK_NULL_FATAL(use); + if (visitSet.find(&cp) != visitSet.end()) { + return; + } + CHECK_FATAL(visitSet.insert(&cp).second, "visitSet insert failed"); + auto itLast = cp.lastDef.find(FEIRDFGNode(use)); + if (itLast != cp.lastDef.end()) { + CHECK_FATAL(result.insert(itLast->second).second, "def insert failed"); + return; + } + // optimization by cacheUD + auto itCache = cp.cacheUD.find(FEIRDFGNode(use)); + if (itCache != cp.cacheUD.end()) { + for (UniqueFEIRVar *def : itCache->second) { + CHECK_FATAL(result.insert(def).second, "def insert failed"); + } + if (itCache->second.size() > 0) { + return; + } + } + // optimization by cacheUD (end) + for (const FEIRStmtCheckPoint *pred : cp.predCPs) { + CHECK_NULL_FATAL(pred); + CalcuDefDFS(result, use, *pred, visitSet); + } +} + +std::string FEIRStmtCheckPoint::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind) << " preds: [ "; + for (FEIRStmtCheckPoint *pred : predCPs) { + ss << pred->GetID() << ", "; + } + ss << " ]"; + return ss.str(); +} + +// ---------- FEIRStmtNary ---------- +FEIRStmtNary::FEIRStmtNary(Opcode opIn, std::list> argExprsIn) + : FEIRStmt(kStmtNary), op(opIn), argExprs(std::move(argExprsIn)) {} + +std::list FEIRStmtNary::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list stmts; + StmtNode *stmt = nullptr; + if (argExprs.size() > 1) { + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + for (const auto &arg : argExprs) { + BaseNode *node = arg->GenMIRNode(mirBuilder); + args.push_back(node); + } + stmt = mirBuilder.CreateStmtNary(op, std::move(args)); + } else if (argExprs.size() == 1) { + BaseNode *node = argExprs.front()->GenMIRNode(mirBuilder); + if (op == OP_eval && argExprs.front()->IsAddrof()) { + node = ReplaceAddrOfNode(node); // addrof va_list + } + stmt = mirBuilder.CreateStmtNary(op, node); + } else { + CHECK_FATAL(false, "Invalid arg size for MIR StmtNary"); + } + if (stmt != nullptr) { + stmts.emplace_back(stmt); + } + return stmts; +} + +// ---------- FEStmtAssign ---------- +FEIRStmtAssign::FEIRStmtAssign(FEIRNodeKind argKind, std::unique_ptr argVar) + : FEIRStmt(argKind), + hasException(false), + var(std::move(argVar)) {} + +void FEIRStmtAssign::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + if (var != nullptr) { + var->SetDef(true); + checkPoint.RegisterDFGNode(var); + } +} + +std::string FEIRStmtAssign::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEStmtDAssign ---------- +FEIRStmtDAssign::FEIRStmtDAssign(std::unique_ptr argVar, std::unique_ptr argExpr, int32 argFieldID) + : FEIRStmtAssign(FEIRNodeKind::kStmtDAssign, std::move(argVar)), + fieldID(argFieldID) { + SetExpr(std::move(argExpr)); +} + +void FEIRStmtDAssign::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + expr->RegisterDFGNodes2CheckPoint(checkPoint); + var->SetDef(true); + checkPoint.RegisterDFGNode(var); +} + +bool FEIRStmtDAssign::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return expr->CalculateDefs4AllUses(checkPoint, udChain); +} + +void FEIRStmtDAssign::InitTrans4AllVarsImpl() { + switch (expr->GetKind()) { + case FEIRNodeKind::kExprDRead: { + FEIRExprDRead *dRead = static_cast(expr.get()); + UniqueFEIRVarTrans trans1 = std::make_unique(FEIRVarTransKind::kFEIRVarTransDirect, var); + dRead->SetTrans(std::move(trans1)); + var->SetTrans(dRead->CreateTransDirect()); + break; + } + case FEIRNodeKind::kExprArrayLoad: { + FEIRExprArrayLoad *arrayLoad = static_cast(expr.get()); + UniqueFEIRVarTrans trans1 = std::make_unique(FEIRVarTransKind::kFEIRVarTransArrayDimIncr, var); + arrayLoad->SetTrans(std::move(trans1)); + var->SetTrans(arrayLoad->CreateTransArrayDimDecr()); + break; + } + default: + break; + } +} + +std::list FEIRStmtDAssign::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + ASSERT(var != nullptr, "dst var is nullptr"); + ASSERT(expr != nullptr, "src expr is nullptr"); + MIRSymbol *dstSym = var->GenerateMIRSymbol(mirBuilder); + BaseNode *srcNode = expr->GenMIRNode(mirBuilder); + if (fieldID != 0) { + MIRType *mirType = var->GetType()->GenerateMIRTypeAuto(); + CHECK_FATAL((mirType->GetKind() == MIRTypeKind::kTypeStruct || mirType->GetKind() == MIRTypeKind::kTypeUnion), + "If fieldID is not 0, then the variable must be a structure"); + } + InsertNonnullChecking(mirBuilder, *dstSym, ans); + CheckNonnullArgsAndRetForFuncPtr(mirBuilder); + AssignBoundaryVarAndChecking(mirBuilder, ans); + CheckBoundaryArgsAndRetForFuncPtr(mirBuilder); + StmtNode *mirStmt = mirBuilder.CreateStmtDassign(*dstSym, fieldID, srcNode); + ans.push_back(mirStmt); + ENCChecker::CheckBoundaryLenFinalAssign(mirBuilder, var, fieldID, srcFileIndex, srcFileLineNum); + ENCChecker::CheckBoundaryLenFinalAddr(mirBuilder, expr, srcFileIndex, srcFileLineNum); + return ans; +} + +void FEIRStmtDAssign::InsertNonnullChecking(MIRBuilder &mirBuilder, const MIRSymbol &dstSym, + std::list &ans) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic()) { + return; + } + if (fieldID == 0) { + if (!dstSym.GetAttr(ATTR_nonnull)) { + return; + } + } else { + FieldID tmpID = fieldID; + FieldPair fieldPair = static_cast(dstSym.GetType())->TraverseToFieldRef(tmpID); + if (!fieldPair.second.second.GetAttr(FLDATTR_nonnull)) { + return; + } + } + if (ENCChecker::HasNullExpr(expr)) { + FE_ERR(kLncErr, "%s:%d error: null assignment of nonnull pointer", + FEManager::GetModule().GetFileNameFromFileNum(srcFileIndex).c_str(), srcFileLineNum); + return; + } + UniqueFEIRStmt stmt = std::make_unique(OP_assignassertnonnull, expr->Clone()); + std::list stmts = stmt->GenMIRStmts(mirBuilder); + ans.splice(ans.end(), stmts); +} + +std::string FEIRStmtDAssign::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + ss << " def : " << var->GetNameRaw() << ", uses : " << expr->DumpDotString() << std::endl; + return ss.str(); +} + +// ---------- FEIRStmtJavaTypeCheck ---------- +FEIRStmtJavaTypeCheck::FEIRStmtJavaTypeCheck(std::unique_ptr argVar, std::unique_ptr argExpr, + std::unique_ptr argType, + FEIRStmtJavaTypeCheck::CheckKind argCheckKind) + : FEIRStmtAssign(FEIRNodeKind::kStmtJavaTypeCheck, std::move(argVar)), + checkKind(argCheckKind), + expr(std::move(argExpr)), + type(std::move(argType)) {} + +FEIRStmtJavaTypeCheck::FEIRStmtJavaTypeCheck(std::unique_ptr argVar, std::unique_ptr argExpr, + std::unique_ptr argType, + FEIRStmtJavaTypeCheck::CheckKind argCheckKind, + uint32 argTypeID) + : FEIRStmtAssign(FEIRNodeKind::kStmtJavaTypeCheck, std::move(argVar)), + checkKind(argCheckKind), + expr(std::move(argExpr)), + type(std::move(argType)), + typeID(argTypeID) {} + +void FEIRStmtJavaTypeCheck::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + expr->RegisterDFGNodes2CheckPoint(checkPoint); + var->SetDef(true); + checkPoint.RegisterDFGNode(var); +} + +bool FEIRStmtJavaTypeCheck::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return expr->CalculateDefs4AllUses(checkPoint, udChain); +} + +std::list FEIRStmtJavaTypeCheck::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + CHECK_FATAL(expr->GetKind() == FEIRNodeKind::kExprDRead, "only support expr dread"); + BaseNode *objNode = expr->GenMIRNode(mirBuilder); + MIRSymbol *ret = var->GenerateLocalMIRSymbol(mirBuilder); + MIRType *mirType = type->GenerateMIRType(); + MIRType *mirPtrType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*mirType, PTY_ref); + MapleVector arguments(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + arguments.push_back(objNode); + if (FEOptions::GetInstance().IsAOT()) { + arguments.push_back(mirBuilder.CreateIntConst(typeID, PTY_i32)); + } + if (checkKind == kCheckCast) { + StmtNode *callStmt = mirBuilder.CreateStmtIntrinsicCallAssigned(INTRN_JAVA_CHECK_CAST, std::move(arguments), ret, + mirPtrType->GetTypeIndex()); + ans.push_back(callStmt); + } else { + BaseNode *instanceOf = mirBuilder.CreateExprIntrinsicop(INTRN_JAVA_INSTANCE_OF, OP_intrinsicopwithtype, *mirPtrType, + std::move(arguments)); + instanceOf->SetPrimType(PTY_u1); + DassignNode *stmt = mirBuilder.CreateStmtDassign(*ret, 0, instanceOf); + ans.push_back(stmt); + } + return ans; +} + +std::string FEIRStmtJavaTypeCheck::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + ss << "uses :" << expr->DumpDotString(); + return ss.str(); +} + +// ---------- FEIRStmtJavaConstClass ---------- +FEIRStmtJavaConstClass::FEIRStmtJavaConstClass(std::unique_ptr argVar, std::unique_ptr argType) + : FEIRStmtAssign(FEIRNodeKind::kStmtJavaConstClass, std::move(argVar)), + type(std::move(argType)) {} + +void FEIRStmtJavaConstClass::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + var->SetDef(true); + checkPoint.RegisterDFGNode(var); +} + +std::list FEIRStmtJavaConstClass::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + MIRSymbol *varSym = var->GenerateLocalMIRSymbol(mirBuilder); + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + MIRType *ptrType = type->GenerateMIRTypeAuto(kSrcLangJava); + BaseNode *expr = + mirBuilder.CreateExprIntrinsicop(INTRN_JAVA_CONST_CLASS, OP_intrinsicopwithtype, *ptrType, std::move(args)); + StmtNode *stmt = mirBuilder.CreateStmtDassign(*varSym, 0, expr); + ans.push_back(stmt); + return ans; +} + +// ---------- FEIRStmtJavaConstString ---------- +FEIRStmtJavaConstString::FEIRStmtJavaConstString(std::unique_ptr argVar, const std::string &argStrVal, + uint32 argFileIdx, uint32 argStringID) + : FEIRStmtAssign(FEIRNodeKind::kStmtJavaConstString, std::move(argVar)), + strVal(argStrVal), fileIdx(argFileIdx), stringID(argStringID) {} + +void FEIRStmtJavaConstString::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + var->SetDef(true); + checkPoint.RegisterDFGNode(var); +} + +std::list FEIRStmtJavaConstString::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + MIRSymbol *literalVal = FEManager::GetJavaStringManager().GetLiteralVar(strVal); + if (literalVal == nullptr) { + literalVal = FEManager::GetJavaStringManager().CreateLiteralVar(mirBuilder, strVal, false); + } + MIRSymbol *literalValPtr = FEManager::GetJavaStringManager().GetLiteralPtrVar(literalVal); + if (literalValPtr == nullptr) { + std::string localStrName = kLocalStringPrefix + std::to_string(fileIdx) + "_" + std::to_string(stringID); + MIRType *typeString = FETypeManager::kFEIRTypeJavaString->GenerateMIRTypeAuto(kSrcLangJava); + MIRSymbol *symbolLocal = mirBuilder.GetOrCreateLocalDecl(localStrName.c_str(), *typeString); + if (!FEOptions::GetInstance().IsAOT()) { + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + args.push_back(mirBuilder.CreateExprAddrof(0, *literalVal)); + StmtNode *stmtCreate = mirBuilder.CreateStmtCallAssigned( + FEManager::GetTypeManager().GetPuIdxForMCCGetOrInsertLiteral(), std::move(args), symbolLocal, + OP_callassigned); + + ans.push_back(stmtCreate); + } + literalValPtr = symbolLocal; + } + MIRSymbol *varDst = var->GenerateLocalMIRSymbol(mirBuilder); + AddrofNode *node = mirBuilder.CreateDread(*literalValPtr, PTY_ptr); + StmtNode *stmt = mirBuilder.CreateStmtDassign(*varDst, 0, node); + ans.push_back(stmt); + return ans; +} + +// ---------- FEIRStmtJavaFillArrayData ---------- +FEIRStmtJavaFillArrayData::FEIRStmtJavaFillArrayData(std::unique_ptr arrayExprIn, const int8 *arrayDataIn, + uint32 sizeIn, const std::string &arrayNameIn) + : FEIRStmtAssign(FEIRNodeKind::kStmtJavaFillArrayData, nullptr), + arrayExpr(std::move(arrayExprIn)), + arrayData(arrayDataIn), + size(sizeIn), + arrayName(arrayNameIn) {} + +void FEIRStmtJavaFillArrayData::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + arrayExpr->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRStmtJavaFillArrayData::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return arrayExpr->CalculateDefs4AllUses(checkPoint, udChain); +} + +std::list FEIRStmtJavaFillArrayData::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + PrimType elemPrimType = ProcessArrayElemPrimType(); + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + BaseNode *nodeArray = arrayExpr->GenMIRNode(mirBuilder); + args.push_back(nodeArray); + MIRSymbol *elemDataVar = ProcessArrayElemData(mirBuilder, elemPrimType); + BaseNode *nodeAddrof = mirBuilder.CreateExprAddrof(0, *elemDataVar); + args.push_back(nodeAddrof); + uint64 elemPrimTypeSize = GetPrimTypeSize(elemPrimType); + uint64 val = elemPrimTypeSize * size; + BaseNode *nodebytes = mirBuilder.CreateIntConst(static_cast(val), PTY_i32); + args.push_back(nodebytes); + StmtNode *stmt = mirBuilder.CreateStmtIntrinsicCallAssigned(INTRN_JAVA_ARRAY_FILL, std::move(args), nullptr); + ans.push_back(stmt); + return ans; +} + +PrimType FEIRStmtJavaFillArrayData::ProcessArrayElemPrimType() const { + const FEIRType &arrayType = arrayExpr->GetTypeRef(); + CHECK_FATAL(arrayType.IsArray(), "var should be array type"); + UniqueFEIRType elemType = arrayType.Clone(); + (void)elemType->ArrayDecrDim(); + PrimType elemPrimType = elemType->GetPrimType(); + return elemPrimType; +} + +MIRSymbol *FEIRStmtJavaFillArrayData::ProcessArrayElemData(MIRBuilder &mirBuilder, PrimType elemPrimType) const { + // specify size for const array + uint32 sizeIn = size; + MIRType *arrayTypeWithSize = GlobalTables::GetTypeTable().GetOrCreateArrayType( + *GlobalTables::GetTypeTable().GetPrimType(elemPrimType), 1, &sizeIn); + MIRSymbol *arrayVar = mirBuilder.GetOrCreateGlobalDecl(arrayName, *arrayTypeWithSize); + arrayVar->SetAttr(ATTR_readonly); + arrayVar->SetStorageClass(kScFstatic); + MIRAggConst *val = FillArrayElem(mirBuilder, elemPrimType, *arrayTypeWithSize, size); + arrayVar->SetKonst(val); + return arrayVar; +} + +MIRAggConst *FEIRStmtJavaFillArrayData::FillArrayElem(MIRBuilder &mirBuilder, PrimType elemPrimType, + MIRType &arrayTypeWithSize, uint32 elemSize) const { + MemPool *mp = mirBuilder.GetMirModule().GetMemPool(); + MIRModule &module = mirBuilder.GetMirModule(); + MIRAggConst *val = module.GetMemPool()->New(module, arrayTypeWithSize); + MIRConst *cst = nullptr; + for (uint32 i = 0; i < elemSize; ++i) { + MIRType &elemType = *GlobalTables::GetTypeTable().GetPrimType(elemPrimType); + switch (elemPrimType) { + case PTY_u1: + cst = mp->New((reinterpret_cast(arrayData))[i], elemType); + break; + case PTY_i8: + cst = mp->New((reinterpret_cast(arrayData))[i], elemType); + break; + case PTY_u8: + cst = mp->New((reinterpret_cast(arrayData))[i], elemType); + break; + case PTY_i16: + cst = mp->New((reinterpret_cast(arrayData))[i], elemType); + break; + case PTY_u16: + cst = mp->New((reinterpret_cast(arrayData))[i], elemType); + break; + case PTY_i32: + cst = mp->New((reinterpret_cast(arrayData))[i], elemType); + break; + case PTY_u32: + cst = mp->New((reinterpret_cast(arrayData))[i], elemType); + break; + case PTY_i64: + cst = mp->New((reinterpret_cast(arrayData))[i], elemType); + break; + case PTY_u64: + cst = mp->New((reinterpret_cast(arrayData))[i], elemType); + break; + case PTY_f32: + cst = mp->New((reinterpret_cast(arrayData))[i], elemType); + break; + case PTY_f64: + cst = mp->New((reinterpret_cast(arrayData))[i], elemType); + break; + default: + CHECK_FATAL(false, "Unsupported primitive type"); + break; + } + val->PushBack(cst); + } + return val; +} + +// ---------- FEIRStmtJavaMultiANewArray ---------- +UniqueFEIRVar FEIRStmtJavaMultiANewArray::varSize = nullptr; +UniqueFEIRVar FEIRStmtJavaMultiANewArray::varClass = nullptr; +UniqueFEIRType FEIRStmtJavaMultiANewArray::typeAnnotation = nullptr; +FEStructMethodInfo *FEIRStmtJavaMultiANewArray::methodInfoNewInstance = nullptr; + +FEIRStmtJavaMultiANewArray::FEIRStmtJavaMultiANewArray(std::unique_ptr argVar, + std::unique_ptr argElemType, + std::unique_ptr argArrayType) + : FEIRStmtAssign(FEIRNodeKind::kStmtJavaMultiANewArray, std::move(argVar)), + elemType(std::move(argElemType)), + arrayType(std::move(argArrayType)) {} + +void FEIRStmtJavaMultiANewArray::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + for (const UniqueFEIRExpr &expr : exprSizes) { + expr->RegisterDFGNodes2CheckPoint(checkPoint); + } + var->SetDef(true); + checkPoint.RegisterDFGNode(var); +} + +bool FEIRStmtJavaMultiANewArray::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + bool success = true; + for (const UniqueFEIRExpr &expr : exprSizes) { + success = success && expr->CalculateDefs4AllUses(checkPoint, udChain); + } + return success; +} + +void FEIRStmtJavaMultiANewArray::AddVarSize(std::unique_ptr argVarSize) { + argVarSize->SetType(FETypeManager::kPrimFEIRTypeI32->Clone()); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(argVarSize)); + exprSizes.push_back(std::move(expr)); +} + +void FEIRStmtJavaMultiANewArray::AddVarSizeRev(std::unique_ptr argVarSize) { + argVarSize->SetType(FETypeManager::kPrimFEIRTypeI32->Clone()); + UniqueFEIRExpr expr = FEIRBuilder::CreateExprDRead(std::move(argVarSize)); + exprSizes.push_front(std::move(expr)); +} + +std::list FEIRStmtJavaMultiANewArray::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + // size array fill + MapleVector argsSizeArrayFill(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + for (const UniqueFEIRExpr &expr : exprSizes) { + BaseNode *node = expr->GenMIRNode(mirBuilder); + argsSizeArrayFill.push_back(node); + } + MIRSymbol *symSize = GetVarSize()->GenerateLocalMIRSymbol(mirBuilder); + StmtNode *stmtSizeArrayFill = mirBuilder.CreateStmtIntrinsicCallAssigned(INTRN_JAVA_FILL_NEW_ARRAY, + std::move(argsSizeArrayFill), symSize, TyIdx(PTY_i32)); + ans.push_back(stmtSizeArrayFill); + // const class + FEIRStmtJavaConstClass feStmtConstClass(GetVarClass()->Clone(), elemType->Clone()); + std::list stmtsConstClass = feStmtConstClass.GenMIRStmts(mirBuilder); + (void)ans.insert(ans.end(), stmtsConstClass.begin(), stmtsConstClass.end()); + // invoke newInstance + UniqueFEIRVar varRetCall = var->Clone(); + varRetCall->SetType(FETypeManager::kFEIRTypeJavaObject->Clone()); + FEIRStmtCallAssign feStmtCall(GetMethodInfoNewInstance(), OP_callassigned, varRetCall->Clone(), true); + feStmtCall.AddExprArg(FEIRBuilder::CreateExprDRead(GetVarClass()->Clone())); + feStmtCall.AddExprArg(FEIRBuilder::CreateExprDRead(GetVarSize()->Clone())); + std::list stmtsCall = feStmtCall.GenMIRStmts(mirBuilder); + (void)ans.insert(ans.end(), stmtsCall.begin(), stmtsCall.end()); + // check cast + var->SetType(arrayType->Clone()); + UniqueFEIRExpr expr = std::make_unique(std::move(varRetCall)); + FEIRStmtJavaTypeCheck feStmtCheck(var->Clone(), std::move(expr), arrayType->Clone(), + FEIRStmtJavaTypeCheck::kCheckCast); + std::list stmtsCheck = feStmtCheck.GenMIRStmts(mirBuilder); + (void)ans.insert(ans.end(), stmtsCheck.begin(), stmtsCheck.end()); + return ans; +} + +const UniqueFEIRVar &FEIRStmtJavaMultiANewArray::GetVarSize() { + if (varSize != nullptr) { + return varSize; + } + HIR2MPL_PARALLEL_FORBIDDEN(); + GStrIdx varNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("tmpsize"); + UniqueFEIRType varSizeType = FETypeManager::kPrimFEIRTypeI32->Clone(); + (void)varSizeType->ArrayIncrDim(); + varSize = std::make_unique(varNameIdx, std::move(varSizeType), true); + return varSize; +} + +const UniqueFEIRVar &FEIRStmtJavaMultiANewArray::GetVarClass() { + if (varClass != nullptr) { + return varClass; + } + HIR2MPL_PARALLEL_FORBIDDEN(); + GStrIdx varNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("tmpclass"); + varClass = std::make_unique(varNameIdx, FETypeManager::kFEIRTypeJavaClass->Clone(), true); + return varClass; +} + +const UniqueFEIRType &FEIRStmtJavaMultiANewArray::GetTypeAnnotation() { + if (typeAnnotation != nullptr) { + return typeAnnotation; + } + HIR2MPL_PARALLEL_FORBIDDEN(); + typeAnnotation = std::make_unique(PTY_ref); + static_cast(typeAnnotation.get())->LoadFromJavaTypeName("Ljava/lang/annotation/Annotation;", false); + return typeAnnotation; +} + +FEStructMethodInfo &FEIRStmtJavaMultiANewArray::GetMethodInfoNewInstance() { + if (methodInfoNewInstance != nullptr) { + return *methodInfoNewInstance; + } + StructElemNameIdx structElemNameIdx(bc::BCUtil::GetMultiANewArrayClassIdx(), + bc::BCUtil::GetMultiANewArrayElemIdx(), + bc::BCUtil::GetMultiANewArrayTypeIdx(), + bc::BCUtil::GetMultiANewArrayFullIdx()); + methodInfoNewInstance = static_cast(FEManager::GetTypeManager().RegisterStructMethodInfo( + structElemNameIdx, kSrcLangJava, true)); + return *methodInfoNewInstance; +} + +std::string FEIRStmtJavaMultiANewArray::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtUseOnly ---------- +FEIRStmtUseOnly::FEIRStmtUseOnly(FEIRNodeKind argKind, Opcode argOp, std::unique_ptr argExpr) + : FEIRStmt(argKind), + op(argOp) { + if (argExpr != nullptr) { + expr = std::move(argExpr); + } +} + +FEIRStmtUseOnly::FEIRStmtUseOnly(Opcode argOp, std::unique_ptr argExpr) + : FEIRStmtUseOnly(FEIRNodeKind::kStmtUseOnly, argOp, std::move(argExpr)) {} + +void FEIRStmtUseOnly::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + if (expr != nullptr) { + expr->RegisterDFGNodes2CheckPoint(checkPoint); + } +} + +bool FEIRStmtUseOnly::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + if (expr != nullptr) { + return expr->CalculateDefs4AllUses(checkPoint, udChain); + } + return true; +} + +std::list FEIRStmtUseOnly::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + ASSERT_NOT_NULL(expr); + if (SkipNonnullChecking(mirBuilder)) { + return ans; + } + BaseNode *srcNode = expr->GenMIRNode(mirBuilder); + StmtNode *mirStmt = mirBuilder.CreateStmtNary(op, srcNode); + ans.push_back(mirStmt); + return ans; +} + +bool FEIRStmtUseOnly::SkipNonnullChecking(MIRBuilder &mirBuilder) const { + if (!kOpcodeInfo.IsAssertNonnull(op)) { + return false; + } + return ENCChecker::HasNonnullAttrInExpr(mirBuilder, expr); +} + +std::string FEIRStmtUseOnly::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + if (expr != nullptr) { + ss << expr->DumpDotString(); + } + return ss.str(); +} + +std::list FEIRStmtAssertNonnull::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + ASSERT_NOT_NULL(expr); + if (SkipNonnullChecking(mirBuilder)) { + return ans; + } + BaseNode *srcNode = expr->GenMIRNode(mirBuilder); + StmtNode *mirStmt = mirBuilder.CreateStmtAssertNonnull(op, srcNode, mirBuilder.GetCurrentFunction()->GetNameStrIdx()); + ans.push_back(mirStmt); + return ans; +} + +// ---------- FEIRStmtCallAssertNonnull ---------- +std::list FEIRStmtCallAssertNonnull::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + ASSERT_NOT_NULL(expr); + if (SkipNonnullChecking(mirBuilder)) { + return ans; + } + BaseNode *srcNode = expr->GenMIRNode(mirBuilder); + GStrIdx stridx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(GetFuncName()); + StmtNode *mirStmt = mirBuilder.CreateStmtCallAssertNonnull(op, srcNode, stridx, GetParamIndex(), + mirBuilder.GetCurrentFunction()->GetNameStrIdx()); + ans.push_back(mirStmt); + return ans; +} + +// ---------- FEIRStmtCallAssertBoundary ---------- +std::list FEIRStmtCallAssertBoundary::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list stmts; + StmtNode *stmt = nullptr; + auto args = ENCChecker::ReplaceBoundaryChecking(mirBuilder, this); + if (args.size() > 0) { + GStrIdx stridx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(GetFuncName()); + stmt = mirBuilder.CreateStmtCallAssertBoundary(op, std::move(args), stridx, GetParamIndex(), + mirBuilder.GetCurrentFunction()->GetNameStrIdx()); + } + if (stmt != nullptr) { + stmts.emplace_back(stmt); + } + return stmts; +} + +// ---------- FEIRStmtAssertBoundary ---------- +std::list FEIRStmtAssertBoundary::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list stmts; + StmtNode *stmt = nullptr; + auto args = ENCChecker::ReplaceBoundaryChecking(mirBuilder, this); + if (args.size() > 0) { + stmt = mirBuilder.CreateStmtAssertBoundary(op, std::move(args), mirBuilder.GetCurrentFunction()->GetNameStrIdx()); + } + if (stmt != nullptr) { + stmts.emplace_back(stmt); + } + return stmts; +} + +// ---------- FEIRStmtReturn ---------- +FEIRStmtReturn::FEIRStmtReturn(std::unique_ptr argExpr) + : FEIRStmtUseOnly(FEIRNodeKind::kStmtReturn, OP_return, std::move(argExpr)) { + isFallThru = true; + } + +std::list FEIRStmtReturn::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + StmtNode *mirStmt = nullptr; + if (expr == nullptr) { + mirStmt = mirBuilder.CreateStmtReturn(nullptr); + } else { + BaseNode *srcNode = expr->GenMIRNode(mirBuilder); + if (mirBuilder.GetCurrentFunction()->IsFirstArgReturn()) { + MIRSymbol *firstArgRetSym = mirBuilder.GetCurrentFunction()->GetFormal(0); + BaseNode *addrNode = mirBuilder.CreateDread(*firstArgRetSym, PTY_ptr); + StmtNode *iNode = mirBuilder.CreateStmtIassign(*firstArgRetSym->GetType(), 0, addrNode, srcNode); + ans.emplace_back(iNode); + mirStmt = mirBuilder.CreateStmtReturn(nullptr); + } else { + InsertNonnullChecking(mirBuilder, ans); + ENCChecker::InsertBoundaryAssignChecking(mirBuilder, ans, expr, srcFileIndex, srcFileLineNum); + ENCChecker::CheckBoundaryLenFinalAddr(mirBuilder, expr, srcFileIndex, srcFileLineNum); + mirStmt = mirBuilder.CreateStmtReturn(srcNode); + } + } + ans.emplace_back(mirStmt); + return ans; +} + +void FEIRStmtReturn::InsertNonnullChecking(MIRBuilder &mirBuilder, std::list &ans) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || expr == nullptr) { + return; + } + if (!mirBuilder.GetCurrentFunction()->GetAttrs().GetAttr(FUNCATTR_nonnull)) { + return; + } + if (ENCChecker::HasNullExpr(expr)) { + FE_ERR(kLncErr, "%s:%d error: %s return nonnull but got null pointer", + FEManager::GetModule().GetFileNameFromFileNum(srcFileIndex).c_str(), srcFileLineNum, + mirBuilder.GetCurrentFunction()->GetName().c_str()); + return; + } + if (expr->GetPrimType() == PTY_ptr) { + UniqueFEIRStmt stmt = std::make_unique(OP_returnassertnonnull, expr->Clone()); + std::list stmts = stmt->GenMIRStmts(mirBuilder); + ans.splice(ans.end(), stmts); + } +} + +// ---------- FEIRStmtGoto ---------- +FEIRStmtGoto::FEIRStmtGoto(uint32 argLabelIdx) + : FEIRStmt(FEIRNodeKind::kStmtGoto), + labelIdx(argLabelIdx), + stmtTarget(nullptr) {} + +FEIRStmtGoto::~FEIRStmtGoto() { + stmtTarget = nullptr; +} + +std::list FEIRStmtGoto::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + CHECK_NULL_FATAL(stmtTarget); + GotoNode *gotoNode = mirBuilder.CreateStmtGoto(OP_goto, stmtTarget->GetMIRLabelIdx()); + ans.push_back(gotoNode); + return ans; +} + +std::string FEIRStmtGoto::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtGoto2 ---------- +FEIRStmtGoto2::FEIRStmtGoto2(uint32 qIdx0, uint32 qIdx1) + : FEIRStmt(FEIRNodeKind::kStmtGoto), labelIdxOuter(qIdx0), labelIdxInner(qIdx1) {} + +std::list FEIRStmtGoto2::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list stmts; + GotoNode *gotoNode = mirBuilder.CreateStmtGoto( + OP_goto, FEIRStmtPesudoLabel2::GenMirLabelIdx(mirBuilder, labelIdxOuter, labelIdxInner)); + stmts.push_back(gotoNode); + return stmts; +} + +std::pair FEIRStmtGoto2::GetLabelIdx() const { + return std::make_pair(labelIdxOuter, labelIdxInner); +} + +FEIRStmtGotoForC::FEIRStmtGotoForC(const std::string &name) + : FEIRStmt(FEIRNodeKind::kStmtGoto), + labelName(name) {} + +std::list FEIRStmtGotoForC::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + LabelIdx label = mirBuilder.GetOrCreateMIRLabel(labelName); + GotoNode *gotoNode = mirBuilder.CreateStmtGoto(OP_goto, label); + ans.push_back(gotoNode); + return ans; +} + +std::string FEIRStmtGotoForC::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtIGoto ---------- +FEIRStmtIGoto::FEIRStmtIGoto(UniqueFEIRExpr expr) : FEIRStmt(kStmtIGoto), targetExpr(std::move(expr)) {} + +std::list FEIRStmtIGoto::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list stmts; + stmts.emplace_back(mirBuilder.CreateStmtUnary(OP_igoto, targetExpr->GenMIRNode(mirBuilder))); + return stmts; +} + +// ---------- FEIRStmtCondGotoForC ---------- +std::list FEIRStmtCondGotoForC::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + LabelIdx labelID = mirBuilder.GetOrCreateMIRLabel(labelName); + BaseNode *condNode = expr->GenMIRNode(mirBuilder); + CondGotoNode *gotoNode = mirBuilder.CreateStmtCondGoto(condNode, opCode, labelID); + ans.push_back(gotoNode); + return ans; +} + +std::string FEIRStmtCondGotoForC::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtCondGoto ---------- +FEIRStmtCondGoto::FEIRStmtCondGoto(Opcode argOp, uint32 argLabelIdx, UniqueFEIRExpr argExpr) + : FEIRStmtGoto(argLabelIdx), + op(argOp) { + kind = FEIRNodeKind::kStmtCondGoto; + SetExpr(std::move(argExpr)); +} + +void FEIRStmtCondGoto::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + expr->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRStmtCondGoto::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return expr->CalculateDefs4AllUses(checkPoint, udChain); +} + +std::list FEIRStmtCondGoto::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + BaseNode *condNode = expr->GenMIRNode(mirBuilder); + CHECK_NULL_FATAL(stmtTarget); + CondGotoNode *gotoNode = mirBuilder.CreateStmtCondGoto(condNode, op, stmtTarget->GetMIRLabelIdx()); + ans.push_back(gotoNode); + return ans; +} + +std::string FEIRStmtCondGoto::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtCondGoto2 ---------- +FEIRStmtCondGoto2::FEIRStmtCondGoto2(Opcode argOp, uint32 qIdx0, uint32 qIdx1, UniqueFEIRExpr argExpr) + : FEIRStmtGoto2(qIdx0, qIdx1), op(argOp), expr(std::move(argExpr)) {} + +std::list FEIRStmtCondGoto2::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list stmts; + BaseNode *condNode = expr->GenMIRNode(mirBuilder); + CondGotoNode *gotoNode = mirBuilder.CreateStmtCondGoto( + condNode, op, FEIRStmtPesudoLabel2::GenMirLabelIdx(mirBuilder, labelIdxOuter, labelIdxInner)); + stmts.push_back(gotoNode); + return stmts; +} + +// ---------- FEIRStmtSwitch ---------- +FEIRStmtSwitch::FEIRStmtSwitch(UniqueFEIRExpr argExpr) + : FEIRStmt(FEIRNodeKind::kStmtSwitch), + defaultLabelIdx(0), + defaultTarget(nullptr) { + SetExpr(std::move(argExpr)); +} + +FEIRStmtSwitch::~FEIRStmtSwitch() { + defaultTarget = nullptr; +} + +void FEIRStmtSwitch::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + expr->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRStmtSwitch::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return expr->CalculateDefs4AllUses(checkPoint, udChain); +} + +bool FEIRStmtSwitch::IsFallThroughImpl() const { + WARN(kLncWarn, "%s:%d stmt[%s] need to be lowed when building bb", + FEManager::GetModule().GetFileNameFromFileNum(srcFileIndex).c_str(), srcFileLineNum, + GetFEIRNodeKindDescription(kind).c_str()); + return false; +} + +std::list FEIRStmtSwitch::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + CaseVector switchTable(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + for (const std::pair &targetPair : mapValueTargets) { + CHECK_NULL_FATAL(targetPair.second); + switchTable.push_back(std::make_pair(targetPair.first, targetPair.second->GetMIRLabelIdx())); + } + BaseNode *exprNode = expr->GenMIRNode(mirBuilder); + CHECK_NULL_FATAL(defaultTarget); + SwitchNode *switchNode = mirBuilder.CreateStmtSwitch(exprNode, defaultTarget->GetMIRLabelIdx(), switchTable); + ans.push_back(switchNode); + return ans; +} + +std::string FEIRStmtSwitch::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtSwitch2 ---------- +FEIRStmtSwitch2::FEIRStmtSwitch2(uint32 outerIdxIn, UniqueFEIRExpr argExpr) + : FEIRStmt(FEIRNodeKind::kStmtSwitch), + outerIdx(outerIdxIn), + defaultLabelIdx(0), + defaultTarget(nullptr) { + SetExpr(std::move(argExpr)); +} + +FEIRStmtSwitch2::~FEIRStmtSwitch2() { + defaultTarget = nullptr; +} + +bool FEIRStmtSwitch2::IsFallThroughImpl() const { + WARN(kLncWarn, "%s:%d stmt[%s] need to be lowed when building bb", + FEManager::GetModule().GetFileNameFromFileNum(srcFileIndex).c_str(), srcFileLineNum, + GetFEIRNodeKindDescription(kind).c_str()); + return false; +} + +std::list FEIRStmtSwitch2::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + CaseVector switchTable(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + for (const std::pair &valueLabelPair : mapValueLabelIdx) { + switchTable.emplace_back(valueLabelPair.first, + FEIRStmtPesudoLabel2::GenMirLabelIdx(mirBuilder, outerIdx, valueLabelPair.second)); + } + BaseNode *exprNode = expr->GenMIRNode(mirBuilder); + SwitchNode *switchNode = mirBuilder.CreateStmtSwitch(exprNode, + FEIRStmtPesudoLabel2::GenMirLabelIdx(mirBuilder, outerIdx, defaultLabelIdx), switchTable); + ans.push_back(switchNode); + return ans; +} + +std::string FEIRStmtSwitch2::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtIf ---------- +FEIRStmtIf::FEIRStmtIf(UniqueFEIRExpr argCondExpr, std::list &argThenStmts) + : FEIRStmt(FEIRNodeKind::kStmtIf) { + SetCondExpr(std::move(argCondExpr)); + hasElse = false; + SetThenStmts(argThenStmts); +} + +FEIRStmtIf::FEIRStmtIf(UniqueFEIRExpr argCondExpr, + std::list &argThenStmts, + std::list &argElseStmts) + : FEIRStmt(FEIRNodeKind::kStmtIf) { + SetCondExpr(std::move(argCondExpr)); + SetThenStmts(argThenStmts); + if (argElseStmts.empty()) { + hasElse = false; + } else { + hasElse = true; + SetElseStmts(argElseStmts); + } +} + +bool FEIRStmtIf::IsFallThroughImpl() const { + WARN(kLncWarn, "%s:%d stmt[%s] need to be lowed when building bb", + FEManager::GetModule().GetFileNameFromFileNum(srcFileIndex).c_str(), srcFileLineNum, + GetFEIRNodeKindDescription(kind).c_str()); + return false; +} + +std::list FEIRStmtIf::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + BaseNode *condBase = condExpr->GenMIRNode(mirBuilder); + IfStmtNode *stmt = nullptr; + if (hasElse) { + stmt = mirBuilder.CreateStmtIfThenElse(condBase); + } else { + stmt = mirBuilder.CreateStmtIf(condBase); + } + for (const auto &thenStmt : thenStmts) { + for(auto thenNode : thenStmt->GenMIRStmts(mirBuilder)) { + stmt->GetThenPart()->AddStatement(thenNode); + } + } + if (hasElse) { + for (const auto &elseStmt : elseStmts) { + for(auto elseNode : elseStmt->GenMIRStmts(mirBuilder)) { + stmt->GetElsePart()->AddStatement(elseNode); + } + } + } + return std::list({ stmt }); +} + +std::string FEIRStmtIf::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtSwitchForC ---------- +FEIRStmtSwitchForC::FEIRStmtSwitchForC(UniqueFEIRExpr argCondExpr, bool argHasDefault) + : FEIRStmt(FEIRNodeKind::kStmtSwitch), + expr(std::move(argCondExpr)), + hasDefault(argHasDefault) {} + +void FEIRStmtSwitchForC::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + expr->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRStmtSwitchForC::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return expr->CalculateDefs4AllUses(checkPoint, udChain); +} + +std::list FEIRStmtSwitchForC::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + MIRModule &module = mirBuilder.GetMirModule(); + CaseVector *caseVec = module.CurFuncCodeMemPool()->New(module.CurFuncCodeMemPoolAllocator()->Adapter()); + std::string endName = AstSwitchUtil::Instance().CreateEndOrExitLabelName(); + LabelIdx swDefaultLabel = mirBuilder.GetOrCreateMIRLabel(endName); // end label + AstSwitchUtil::Instance().PushNestedCaseVectors(std::pair(caseVec, swDefaultLabel)); + BaseNode *exprNode = expr->GenMIRNode(mirBuilder); + BlockNode *tempBlock = module.CurFuncCodeMemPool()->New(); + CaseVector &switchTable = *AstSwitchUtil::Instance().GetTopOfNestedCaseVectors().first; + for (auto &sub : subStmts) { + for (auto mirStmt : sub->GenMIRStmts(mirBuilder)) { + tempBlock->AddStatement(mirStmt); + } + } + SwitchNode *mirSwitchStmt = mirBuilder.CreateStmtSwitch(exprNode, swDefaultLabel, switchTable); + ans.push_back(mirSwitchStmt); + for (auto &it : tempBlock->GetStmtNodes()) { + ans.emplace_back(&it); + } + if (!hasDefault) { + LabelIdx endLab = mirBuilder.GetOrCreateMIRLabel(endName); + StmtNode *mirSwExitLabelStmt = mirBuilder.CreateStmtLabel(endLab); + ans.push_back(mirSwExitLabelStmt); + } + LabelIdx exitLab = mirBuilder.GetOrCreateMIRLabel(breakLabelName); + StmtNode *mirSwExitLabelStmt = mirBuilder.CreateStmtLabel(exitLab); + ans.push_back(mirSwExitLabelStmt); + AstSwitchUtil::Instance().PopNestedCaseVectors(); + return ans; +} + +std::string FEIRStmtSwitchForC::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +FEIRStmtCaseForC::FEIRStmtCaseForC(int64 label) + : FEIRStmt(FEIRNodeKind::kStmtCaseForC), + lCaseLabel(label) {} + +void FEIRStmtCaseForC::AddCaseTag2CaseVec(int64 lCaseTag, int64 rCaseTag) { + auto pLabel = std::make_unique(lCaseLabel); + for (int64 csTag = lCaseTag; csTag <= rCaseTag; ++csTag) { + pesudoLabelMap.insert(std::make_pair(csTag, std::move(pLabel))); + } +} + +std::list FEIRStmtCaseForC::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + CaseVector &caseVec = *AstSwitchUtil::Instance().GetTopOfNestedCaseVectors().first; + StmtNode *mirLabelStmt = nullptr; + for (auto &targetPair : GetPesudoLabelMap()) { + targetPair.second->GenerateLabelIdx(mirBuilder); + caseVec.push_back(std::make_pair(targetPair.first, targetPair.second->GetMIRLabelIdx())); + } + for (auto it : caseVec) { + if (lCaseLabel == it.first) { + mirLabelStmt = mirBuilder.CreateStmtLabel(it.second); + ans.emplace_back(mirLabelStmt); + } + } + for (auto &sub : subStmts) { + ans.splice(ans.end(), sub.get()->GenMIRStmts(mirBuilder)); + } + return ans; +} + +std::string FEIRStmtCaseForC::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +FEIRStmtDefaultForC::FEIRStmtDefaultForC() + : FEIRStmt(FEIRNodeKind::kStmtDefaultForC) {} + +std::list FEIRStmtDefaultForC::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + StmtNode *mirLabelStmt = mirBuilder.CreateStmtLabel(AstSwitchUtil::Instance().GetTopOfNestedCaseVectors().second); + ans.emplace_back(mirLabelStmt); + for (auto &sub : subStmts) { + ans.splice(ans.end(), sub.get()->GenMIRStmts(mirBuilder)); + } + return ans; +} + +std::string FEIRStmtDefaultForC::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtArrayStore ---------- +FEIRStmtArrayStore::FEIRStmtArrayStore(UniqueFEIRExpr argExprElem, UniqueFEIRExpr argExprArray, + UniqueFEIRExpr argExprIndex, UniqueFEIRType argTypeArray) + : FEIRStmt(FEIRNodeKind::kStmtArrayStore), + exprElem(std::move(argExprElem)), + exprArray(std::move(argExprArray)), + exprIndex(std::move(argExprIndex)), + typeArray(std::move(argTypeArray)) {} + +FEIRStmtArrayStore::FEIRStmtArrayStore(UniqueFEIRExpr argExprElem, UniqueFEIRExpr argExprArray, + UniqueFEIRExpr argExprIndex, UniqueFEIRType argTypeArray, + const std::string &argArrayName) + : FEIRStmt(FEIRNodeKind::kStmtArrayStore), + exprElem(std::move(argExprElem)), + exprArray(std::move(argExprArray)), + exprIndex(std::move(argExprIndex)), + typeArray(std::move(argTypeArray)), + arrayName(argArrayName) {} + +FEIRStmtArrayStore::FEIRStmtArrayStore(UniqueFEIRExpr argExprElem, UniqueFEIRExpr argExprArray, + UniqueFEIRExpr argExprIndex, UniqueFEIRType argTypeArray, + UniqueFEIRType argTypeElem, const std::string &argArrayName) + : FEIRStmt(FEIRNodeKind::kStmtArrayStore), + exprElem(std::move(argExprElem)), + exprArray(std::move(argExprArray)), + exprIndex(std::move(argExprIndex)), + typeArray(std::move(argTypeArray)), + typeElem(std::move(argTypeElem)), + arrayName(argArrayName) {} + +FEIRStmtArrayStore::FEIRStmtArrayStore(UniqueFEIRExpr argExprElem, UniqueFEIRExpr argExprArray, + std::list &argExprIndexs, UniqueFEIRType argTypeArray, + const std::string &argArrayName) + : FEIRStmt(FEIRNodeKind::kStmtArrayStore), + exprElem(std::move(argExprElem)), + exprArray(std::move(argExprArray)), + typeArray(std::move(argTypeArray)), + arrayName(argArrayName) { + SetIndexsExprs(argExprIndexs); +} + +FEIRStmtArrayStore::FEIRStmtArrayStore(UniqueFEIRExpr argExprElem, UniqueFEIRExpr argExprArray, + std::list &argExprIndexs, UniqueFEIRType argTypeArray, + UniqueFEIRExpr argExprStruct, UniqueFEIRType argTypeStruct, + const std::string &argArrayName) + : FEIRStmt(FEIRNodeKind::kStmtArrayStore), + exprElem(std::move(argExprElem)), + exprArray(std::move(argExprArray)), + typeArray(std::move(argTypeArray)), + exprStruct(std::move(argExprStruct)), + typeStruct(std::move(argTypeStruct)), + arrayName(argArrayName) { + SetIndexsExprs(argExprIndexs); +} + +void FEIRStmtArrayStore::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + exprArray->RegisterDFGNodes2CheckPoint(checkPoint); + exprIndex->RegisterDFGNodes2CheckPoint(checkPoint); + exprElem->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRStmtArrayStore::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + bool success = true; + success = success && exprArray->CalculateDefs4AllUses(checkPoint, udChain); + success = success && exprIndex->CalculateDefs4AllUses(checkPoint, udChain); + success = success && exprElem->CalculateDefs4AllUses(checkPoint, udChain); + return success; +} + +void FEIRStmtArrayStore::InitTrans4AllVarsImpl() { + CHECK_FATAL(exprArray->GetKind() == kExprDRead, "only support dread expr for exprArray"); + CHECK_FATAL(exprIndex->GetKind() == kExprDRead, "only support dread expr for exprIndex"); + CHECK_FATAL(exprElem->GetKind() == kExprDRead, "only support dread expr for exprElem"); + FEIRExprDRead *exprArrayDRead = static_cast(exprArray.get()); + FEIRExprDRead *exprElemDRead = static_cast(exprElem.get()); + exprArrayDRead->SetTrans(exprElemDRead->CreateTransArrayDimIncr()); + exprElemDRead->SetTrans(exprArrayDRead->CreateTransArrayDimDecr()); +} + +std::list FEIRStmtArrayStore::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + CHECK_FATAL(((exprIndex == nullptr) && (exprIndexs.size() != 0))|| + (exprIndex->GetKind() == kExprDRead) || + (exprIndex->GetKind() == kExprConst), "only support dread/const expr for exprIndex"); + MIRType *ptrMIRArrayType = typeArray->GenerateMIRType(false); + BaseNode *arrayExpr = nullptr; + MIRType *mIRElemType = nullptr; + if (FEManager::GetModule().GetSrcLang() == kSrcLangC) { + GenMIRStmtsImplForCPart(mirBuilder, ptrMIRArrayType, &mIRElemType, &arrayExpr); + } else { + BaseNode *addrBase = exprArray->GenMIRNode(mirBuilder); + BaseNode *indexBn = exprIndex->GenMIRNode(mirBuilder); + arrayExpr = mirBuilder.CreateExprArray(*ptrMIRArrayType, addrBase, indexBn); + UniqueFEIRType typeArrayCloned = typeArray->Clone(); + if ((exprIndex->GetKind() != kExprConst) || (!FEOptions::GetInstance().IsAOT())) { + (void)typeArrayCloned->ArrayDecrDim(); + } + mIRElemType = typeArrayCloned->GenerateMIRType(true); + } + BaseNode *elemBn = exprElem->GenMIRNode(mirBuilder); + IassignNode *stmt = nullptr; + if ((FEManager::GetModule().GetSrcLang() == kSrcLangC) || + (exprIndex->GetKind() != kExprConst) || (!FEOptions::GetInstance().IsAOT())) { + MIRType *ptrMIRElemType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*mIRElemType, PTY_ptr); + stmt = mirBuilder.CreateStmtIassign(*ptrMIRElemType, 0, arrayExpr, elemBn); + } else { + reinterpret_cast(arrayExpr)->SetBoundsCheck(false); + stmt = mirBuilder.CreateStmtIassign(*mIRElemType, 0, arrayExpr, elemBn); + } + return std::list({ stmt }); +} + +void FEIRStmtArrayStore::GenMIRStmtsImplForCPart(MIRBuilder &mirBuilder, MIRType *ptrMIRArrayType, + MIRType **mIRElemType, BaseNode **arrayExpr) const { + if (typeElem == nullptr) { + typeElem = std::make_unique(*static_cast(ptrMIRArrayType)->GetElemType()); + } + FieldID fieldID = 0; + // array in struct + if (typeStruct != nullptr) { + fieldID = static_cast(exprArray.get())->GetFieldID(); + MIRType *ptrMIRStructType = typeStruct->GenerateMIRType(false); + MIRStructType* mirStructType = static_cast(ptrMIRStructType); + // for no init, create the struct symbol + (void)mirBuilder.GetOrCreateLocalDecl(arrayName, *mirStructType); + } + + *mIRElemType = typeElem->GenerateMIRType(true); + BaseNode *arrayAddrOfExpr = nullptr; + MIRSymbol *mirSymbol = exprArray->GetVarUses().front()->GenerateMIRSymbol(mirBuilder); + auto mirtype = mirSymbol->GetType(); + if (mirtype->GetKind() == kTypePointer) { + arrayAddrOfExpr = exprArray->GenMIRNode(mirBuilder); + } else { + arrayAddrOfExpr = mirBuilder.CreateExprAddrof(fieldID, *mirSymbol); + } + if (exprIndex == nullptr) { + std::vector nds; + nds.push_back(arrayAddrOfExpr); + for (auto &e : exprIndexs) { + BaseNode *no = e->GenMIRNode(mirBuilder); + nds.push_back(no); + } + *arrayExpr = mirBuilder.CreateExprArray(*ptrMIRArrayType, nds); + } else { + BaseNode *indexBn = exprIndex->GenMIRNode(mirBuilder); + *arrayExpr = mirBuilder.CreateExprArray(*ptrMIRArrayType, arrayAddrOfExpr, indexBn); + } +} + +std::string FEIRStmtArrayStore::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + ss << " def : {"; + ss << " exprArray : " << exprArray->DumpDotString(); + ss << " exprIndex : " << exprIndex->DumpDotString(); + ss << " exprElem kind : " << GetFEIRNodeKindDescription(exprElem->GetKind()) << " " << exprElem->DumpDotString(); + ss << " } "; + return ss.str(); +} + +// ---------- FEIRStmtFieldStore ---------- +FEIRStmtFieldStore::FEIRStmtFieldStore(UniqueFEIRVar argVarObj, UniqueFEIRVar argVarField, + FEStructFieldInfo &argFieldInfo, bool argIsStatic) + : FEIRStmt(FEIRNodeKind::kStmtFieldStore), + varObj(std::move(argVarObj)), + varField(std::move(argVarField)), + fieldInfo(argFieldInfo), + isStatic(argIsStatic) {} +FEIRStmtFieldStore::FEIRStmtFieldStore(UniqueFEIRVar argVarObj, UniqueFEIRVar argVarField, + FEStructFieldInfo &argFieldInfo, bool argIsStatic, int32 argDexFileHashCode) + : FEIRStmt(FEIRNodeKind::kStmtFieldStore), + varObj(std::move(argVarObj)), + varField(std::move(argVarField)), + fieldInfo(argFieldInfo), + isStatic(argIsStatic), + dexFileHashCode(argDexFileHashCode) {} + +void FEIRStmtFieldStore::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + if (isStatic) { + RegisterDFGNodes2CheckPointForStatic(checkPoint); + } else { + RegisterDFGNodes2CheckPointForNonStatic(checkPoint); + } +} + +void FEIRStmtFieldStore::RegisterDFGNodes2CheckPointForStatic(FEIRStmtCheckPoint &checkPoint) { + checkPoint.RegisterDFGNode(varField); +} + +void FEIRStmtFieldStore::RegisterDFGNodes2CheckPointForNonStatic(FEIRStmtCheckPoint &checkPoint) { + checkPoint.RegisterDFGNode(varObj); + checkPoint.RegisterDFGNode(varField); +} + +bool FEIRStmtFieldStore::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + if (isStatic) { + return CalculateDefs4AllUsesForStatic(checkPoint, udChain); + } else { + return CalculateDefs4AllUsesForNonStatic(checkPoint, udChain); + } +} + +bool FEIRStmtFieldStore::CalculateDefs4AllUsesForStatic(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + std::set &defs4VarField = checkPoint.CalcuDef(varField); + (void)udChain.insert(std::make_pair(&varField, defs4VarField)); + return (defs4VarField.size() > 0); +} + +bool FEIRStmtFieldStore::CalculateDefs4AllUsesForNonStatic(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + std::set &defs4VarObj = checkPoint.CalcuDef(varObj); + (void)udChain.insert(std::make_pair(&varObj, defs4VarObj)); + std::set &defs4VarField = checkPoint.CalcuDef(varField); + (void)udChain.insert(std::make_pair(&varField, defs4VarField)); + return ((defs4VarObj.size() > 0) && (defs4VarField.size() > 0)); +} + +std::list FEIRStmtFieldStore::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + // prepare and find root + fieldInfo.Prepare(mirBuilder, isStatic); + if (isStatic) { + return GenMIRStmtsImplForStatic(mirBuilder); + } else { + return GenMIRStmtsImplForNonStatic(mirBuilder); + } +} + +bool FEIRStmtFieldStore::NeedMCCForStatic(uint32 &typeID) const { + // check type first + const std::string &actualContainerName = fieldInfo.GetActualContainerName(); + typeID = FEManager::GetTypeManager().GetTypeIDFromMplClassName(actualContainerName, dexFileHashCode); + if(typeID == UINT32_MAX) { + return true; + } + + // check type field second + const std::string &fieldName = GlobalTables::GetStrTable().GetStringFromStrIdx(fieldInfo.GetFieldNameIdx()); + MIRStructType *currStructType = FEManager::GetTypeManager().GetStructTypeFromName(actualContainerName); + const auto &fields = currStructType->GetStaticFields(); + for (auto f : fields) { + const std::string &fieldNameIt = GlobalTables::GetStrTable().GetStringFromStrIdx(f.first); + if(fieldName.compare(fieldNameIt) == 0) { + return false; + } + } + return true; +} + +void FEIRStmtFieldStore::InitPrimTypeFuncNameIdxMap (std::map &primTypeFuncNameIdxMap) const { + primTypeFuncNameIdxMap = { + { PTY_u1, FEUtils::GetMCCStaticFieldSetBoolIdx() }, + { PTY_i8, FEUtils::GetMCCStaticFieldSetByteIdx() }, + { PTY_i16, FEUtils::GetMCCStaticFieldSetShortIdx() }, + { PTY_u16, FEUtils::GetMCCStaticFieldSetCharIdx() }, + { PTY_i32, FEUtils::GetMCCStaticFieldSetIntIdx() }, + { PTY_i64, FEUtils::GetMCCStaticFieldSetLongIdx() }, + { PTY_f32, FEUtils::GetMCCStaticFieldSetFloatIdx() }, + { PTY_f64, FEUtils::GetMCCStaticFieldSetDoubleIdx() }, + { PTY_ref, FEUtils::GetMCCStaticFieldSetObjectIdx() }, + }; +} +std::list FEIRStmtFieldStore::GenMIRStmtsImplForStatic(MIRBuilder &mirBuilder) const { + CHECK_FATAL(fieldInfo.GetFieldNameIdx() != 0, "invalid name idx"); + std::list mirStmts; + UniqueFEIRVar varTarget = std::make_unique(fieldInfo.GetFieldNameIdx(), fieldInfo.GetType()->Clone()); + varTarget->SetGlobal(true); + MIRSymbol *symSrc = varTarget->GenerateGlobalMIRSymbol(mirBuilder); + UniqueFEIRExpr exprDRead = FEIRBuilder::CreateExprDRead(varField->Clone()); + UniqueFEIRStmt stmtDAssign = FEIRBuilder::CreateStmtDAssign(std::move(varTarget), std::move(exprDRead)); + mirStmts = stmtDAssign->GenMIRStmts(mirBuilder); + if (!FEOptions::GetInstance().IsNoBarrier() && fieldInfo.IsVolatile()) { + StmtNode *barrier = mirBuilder.GetMirModule().CurFuncCodeMemPool()->New(OP_membarrelease); + mirStmts.emplace_front(barrier); + barrier = mirBuilder.GetMirModule().CurFuncCodeMemPool()->New(OP_membarstoreload); + mirStmts.emplace_back(barrier); + } + TyIdx containerTyIdx = fieldInfo.GetActualContainerType()->GenerateMIRType()->GetTypeIndex(); + if (!mirBuilder.GetCurrentFunction()->IsClinit() || + mirBuilder.GetCurrentFunction()->GetClassTyIdx() != containerTyIdx) { + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + uint32 typeID = UINT32_MAX; + bool needMCCForStatic = false; + if (FEOptions::GetInstance().IsAOT()) { + needMCCForStatic = NeedMCCForStatic(typeID); + if (!needMCCForStatic) { + BaseNode *argNumExpr = mirBuilder.CreateIntConst(static_cast(typeID), PTY_i32); + args.push_back(argNumExpr); + } else { + const auto &pt = fieldInfo.GetType()->GetPrimType(); + std::map primTypeFuncNameIdxMap; + InitPrimTypeFuncNameIdxMap(primTypeFuncNameIdxMap); + const auto &itorFunc = primTypeFuncNameIdxMap.find(pt); + CHECK_FATAL(itorFunc != primTypeFuncNameIdxMap.end(), "java type not support %d", pt); + args.push_back(mirBuilder.CreateIntConst(static_cast(fieldInfo.GetFieldID()), PTY_i32)); + BaseNode *nodeSrc = mirBuilder.CreateExprDread(*symSrc); + args.push_back(nodeSrc); + MIRSymbol *retVarSym = nullptr; + retVarSym = varField->GenerateLocalMIRSymbol(mirBuilder); + StmtNode *stmtMCC = mirBuilder.CreateStmtCallAssigned( + FEManager::GetTypeManager().GetMCCFunction(itorFunc->second)->GetPuidx(), MapleVector(args), + retVarSym, + OP_callassigned); + mirStmts.clear(); + mirStmts.emplace_front(stmtMCC); + } + } + if (!needMCCForStatic) { + StmtNode *stmtClinitCheck = mirBuilder.CreateStmtIntrinsicCall(INTRN_JAVA_CLINIT_CHECK, std::move(args), + containerTyIdx); + mirStmts.emplace_front(stmtClinitCheck); + } + } + return mirStmts; +} + +std::list FEIRStmtFieldStore::GenMIRStmtsImplForNonStatic(MIRBuilder &mirBuilder) const { + std::list ans; + FieldID fieldID = fieldInfo.GetFieldID(); + ASSERT(fieldID != 0, "invalid field ID"); + MIRStructType *structType = FEManager::GetTypeManager().GetStructTypeFromName(fieldInfo.GetStructName()); + CHECK_NULL_FATAL(structType); + MIRType *ptrStructType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*structType, PTY_ref); + UniqueFEIRExpr exprDReadObj = FEIRBuilder::CreateExprDRead(varObj->Clone()); + UniqueFEIRExpr exprDReadField = FEIRBuilder::CreateExprDRead(varField->Clone()); + BaseNode *nodeObj = exprDReadObj->GenMIRNode(mirBuilder); + BaseNode *nodeField = exprDReadField->GenMIRNode(mirBuilder); + StmtNode *stmt = mirBuilder.CreateStmtIassign(*ptrStructType, fieldID, nodeObj, nodeField); + if (FEOptions::GetInstance().IsRC()) { + bc::RCSetter::GetRCSetter().CollectInputStmtField(stmt, fieldInfo.GetElemNameIdx()); + } + ans.emplace_back(stmt); + if (!FEOptions::GetInstance().IsNoBarrier() && fieldInfo.IsVolatile()) { + StmtNode *barrier = mirBuilder.GetMirModule().CurFuncCodeMemPool()->New(OP_membarrelease); + ans.emplace_front(barrier); + barrier = mirBuilder.GetMirModule().CurFuncCodeMemPool()->New(OP_membarstoreload); + ans.emplace_back(barrier); + } + return ans; +} + +std::string FEIRStmtFieldStore::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtFieldLoad ---------- +FEIRStmtFieldLoad::FEIRStmtFieldLoad(UniqueFEIRVar argVarObj, UniqueFEIRVar argVarField, + FEStructFieldInfo &argFieldInfo, bool argIsStatic) + : FEIRStmtAssign(FEIRNodeKind::kStmtFieldLoad, std::move(argVarField)), + varObj(std::move(argVarObj)), + fieldInfo(argFieldInfo), + isStatic(argIsStatic) {} + +FEIRStmtFieldLoad::FEIRStmtFieldLoad(UniqueFEIRVar argVarObj, UniqueFEIRVar argVarField, + FEStructFieldInfo &argFieldInfo, + bool argIsStatic, int32 argDexFileHashCode) + : FEIRStmtAssign(FEIRNodeKind::kStmtFieldLoad, std::move(argVarField)), + varObj(std::move(argVarObj)), + fieldInfo(argFieldInfo), + isStatic(argIsStatic), + dexFileHashCode(argDexFileHashCode) {} + +void FEIRStmtFieldLoad::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + if (isStatic) { + RegisterDFGNodes2CheckPointForStatic(checkPoint); + } else { + RegisterDFGNodes2CheckPointForNonStatic(checkPoint); + } +} + +bool FEIRStmtFieldLoad::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + if (!isStatic) { + std::set &defs = checkPoint.CalcuDef(varObj); + (void)udChain.insert(std::make_pair(&varObj, defs)); + if (defs.size() == 0) { + return false; + } + } + return true; +} + +void FEIRStmtFieldLoad::RegisterDFGNodes2CheckPointForStatic(FEIRStmtCheckPoint &checkPoint) { + var->SetDef(true); + checkPoint.RegisterDFGNode(var); +} + +void FEIRStmtFieldLoad::RegisterDFGNodes2CheckPointForNonStatic(FEIRStmtCheckPoint &checkPoint) { + checkPoint.RegisterDFGNode(varObj); + var->SetDef(true); + checkPoint.RegisterDFGNode(var); +} + +std::list FEIRStmtFieldLoad::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + // prepare and find root + fieldInfo.Prepare(mirBuilder, isStatic); + if (isStatic) { + return GenMIRStmtsImplForStatic(mirBuilder); + } else { + return GenMIRStmtsImplForNonStatic(mirBuilder); + } +} + +bool FEIRStmtFieldLoad::NeedMCCForStatic(uint32 &typeID) const { + // check type first + const std::string &actualContainerName = fieldInfo.GetActualContainerName(); + typeID = FEManager::GetTypeManager().GetTypeIDFromMplClassName(actualContainerName, dexFileHashCode); + if(typeID == UINT32_MAX) { + return true; + } + + // check type field second + const std::string &fieldName = GlobalTables::GetStrTable().GetStringFromStrIdx(fieldInfo.GetFieldNameIdx()); + MIRStructType *currStructType = FEManager::GetTypeManager().GetStructTypeFromName(actualContainerName); + if (currStructType == nullptr) { + return true; + } + const auto &fields = currStructType->GetStaticFields(); + if (fields.size() == 0) { + return true; + } + for (auto f : fields) { + const std::string &fieldNameIt = GlobalTables::GetStrTable().GetStringFromStrIdx(f.first); + if(fieldName.compare(fieldNameIt) == 0) { + return false; + } + } + return true; +} + +std::list FEIRStmtFieldLoad::GenMIRStmtsImplForStatic(MIRBuilder &mirBuilder) const { + UniqueFEIRVar varTarget = std::make_unique(fieldInfo.GetFieldNameIdx(), fieldInfo.GetType()->Clone()); + varTarget->SetGlobal(true); + UniqueFEIRExpr exprDRead = FEIRBuilder::CreateExprDRead(std::move(varTarget)); + UniqueFEIRStmt stmtDAssign = FEIRBuilder::CreateStmtDAssign(var->Clone(), std::move(exprDRead)); + std::list mirStmts = stmtDAssign->GenMIRStmts(mirBuilder); + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + + bool needMCCForStatic = false; + if (FEOptions::GetInstance().IsAOT()) { + uint32 typeID = UINT32_MAX; + needMCCForStatic = NeedMCCForStatic(typeID); + if (!needMCCForStatic) { + BaseNode *argNumExpr = mirBuilder.CreateIntConst(static_cast(typeID), PTY_i32); + args.push_back(argNumExpr); + } else { + auto pt = fieldInfo.GetType()->GetPrimType(); + std::map primTypeFuncNameIdxMap = { + { PTY_u1, FEUtils::GetMCCStaticFieldGetBoolIdx() }, + { PTY_i8, FEUtils::GetMCCStaticFieldGetByteIdx() }, + { PTY_i16, FEUtils::GetMCCStaticFieldGetShortIdx() }, + { PTY_u16, FEUtils::GetMCCStaticFieldGetCharIdx() }, + { PTY_i32, FEUtils::GetMCCStaticFieldGetIntIdx() }, + { PTY_i64, FEUtils::GetMCCStaticFieldGetLongIdx() }, + { PTY_f32, FEUtils::GetMCCStaticFieldGetFloatIdx() }, + { PTY_f64, FEUtils::GetMCCStaticFieldGetDoubleIdx() }, + { PTY_ref, FEUtils::GetMCCStaticFieldGetObjectIdx() }, + }; + auto itorFunc = primTypeFuncNameIdxMap.find(pt); + CHECK_FATAL(itorFunc != primTypeFuncNameIdxMap.end(), "java type not support %d", pt); + args.push_back(mirBuilder.CreateIntConst(static_cast(fieldInfo.GetFieldID()), PTY_i32)); + MIRSymbol *retVarSym = nullptr; + retVarSym = var->GenerateLocalMIRSymbol(mirBuilder); + StmtNode *stmtMCC = mirBuilder.CreateStmtCallAssigned( + FEManager::GetTypeManager().GetMCCFunction(itorFunc->second)->GetPuidx(), MapleVector(args), + retVarSym, OP_callassigned); + mirStmts.clear(); + mirStmts.emplace_front(stmtMCC); + } + } + if (!needMCCForStatic) { + TyIdx containerTyIdx = fieldInfo.GetActualContainerType()->GenerateMIRType()->GetTypeIndex(); + if (!mirBuilder.GetCurrentFunction()->IsClinit() || + mirBuilder.GetCurrentFunction()->GetClassTyIdx() != containerTyIdx) { + StmtNode *stmtClinitCheck = mirBuilder.CreateStmtIntrinsicCall(INTRN_JAVA_CLINIT_CHECK, std::move(args), + containerTyIdx); + mirStmts.emplace_front(stmtClinitCheck); + } + } + if (!FEOptions::GetInstance().IsNoBarrier() && fieldInfo.IsVolatile()) { + StmtNode *barrier = mirBuilder.GetMirModule().CurFuncCodeMemPool()->New(OP_membaracquire); + mirStmts.emplace_back(barrier); + } + return mirStmts; +} + +std::list FEIRStmtFieldLoad::GenMIRStmtsImplForNonStatic(MIRBuilder &mirBuilder) const { + std::list ans; + FieldID fieldID = fieldInfo.GetFieldID(); + ASSERT(fieldID != 0, "invalid field ID"); + MIRStructType *structType = FEManager::GetTypeManager().GetStructTypeFromName(fieldInfo.GetStructName()); + CHECK_NULL_FATAL(structType); + MIRType *ptrStructType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*structType, PTY_ref); + MIRType *fieldType = fieldInfo.GetType()->GenerateMIRTypeAuto(fieldInfo.GetSrcLang()); + UniqueFEIRExpr exprDReadObj = FEIRBuilder::CreateExprDRead(varObj->Clone()); + BaseNode *nodeObj = exprDReadObj->GenMIRNode(mirBuilder); + BaseNode *nodeVal = mirBuilder.CreateExprIread(*fieldType, *ptrStructType, fieldID, nodeObj); + MIRSymbol *valRet = var->GenerateLocalMIRSymbol(mirBuilder); + StmtNode *stmt = mirBuilder.CreateStmtDassign(*valRet, 0, nodeVal); + ans.emplace_back(stmt); + if (!FEOptions::GetInstance().IsNoBarrier() && fieldInfo.IsVolatile()) { + StmtNode *barrier = mirBuilder.GetMirModule().CurFuncCodeMemPool()->New(OP_membaracquire); + ans.emplace_back(barrier); + } + return ans; +} + +std::string FEIRStmtFieldLoad::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtCallAssign ---------- +std::map FEIRStmtCallAssign::mapOpAssignToOp = FEIRStmtCallAssign::InitMapOpAssignToOp(); +std::map FEIRStmtCallAssign::mapOpToOpAssign = FEIRStmtCallAssign::InitMapOpToOpAssign(); + +FEIRStmtCallAssign::FEIRStmtCallAssign(FEStructMethodInfo &argMethodInfo, Opcode argMIROp, UniqueFEIRVar argVarRet, + bool argIsStatic) + : FEIRStmtAssign(FEIRNodeKind::kStmtCallAssign, std::move(argVarRet)), + methodInfo(argMethodInfo), + mirOp(argMIROp), + isStatic(argIsStatic) {} + +std::map FEIRStmtCallAssign::InitMapOpAssignToOp() { + std::map ans; + ans[OP_callassigned] = OP_call; + ans[OP_virtualcallassigned] = OP_virtualcall; + ans[OP_superclasscallassigned] = OP_superclasscall; + ans[OP_interfacecallassigned] = OP_interfacecall; + return ans; +} + +std::map FEIRStmtCallAssign::InitMapOpToOpAssign() { + std::map ans; + ans[OP_call] = OP_callassigned; + ans[OP_virtualcall] = OP_virtualcallassigned; + ans[OP_superclasscall] = OP_superclasscallassigned; + ans[OP_interfacecall] = OP_interfacecallassigned; + return ans; +} + +void FEIRStmtCallAssign::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + for (const UniqueFEIRExpr &exprArg : exprArgs) { + exprArg->RegisterDFGNodes2CheckPoint(checkPoint); + } + if (!methodInfo.IsReturnVoid() && (var != nullptr)) { + var->SetDef(true); + checkPoint.RegisterDFGNode(var); + } +} + +bool FEIRStmtCallAssign::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + bool success = true; + for (const UniqueFEIRExpr &exprArg : exprArgs) { + success = success && exprArg->CalculateDefs4AllUses(checkPoint, udChain); + } + return success; +} + +std::list FEIRStmtCallAssign::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + // If the struct is a class, we check it if external type directly. + // If the struct is a array type, we check its baseType if external type. + // FEUtils::GetBaseTypeName returns a class type itself or an arrayType's base type. + if (methodInfo.GetSrcLang() == kSrcLangJava) { + std::string baseStructName = FEUtils::GetBaseTypeName(methodInfo.GetStructName()); + bool isCreate = false; + (void)FEManager::GetTypeManager().GetOrCreateClassOrInterfaceType( + baseStructName, false, FETypeFlag::kSrcExtern, isCreate); + } + std::list ans; + StmtNode *stmtCall = nullptr; + // prepare and find root + methodInfo.Prepare(mirBuilder, isStatic); + if (methodInfo.IsJavaPolymorphicCall() || methodInfo.IsJavaDynamicCall()) { + return GenMIRStmtsUseZeroReturn(mirBuilder); + } + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + args.reserve(exprArgs.size()); + size_t index = 0; + const std::string funcName = methodInfo.GetMirFunc()->GetName(); + for (const UniqueFEIRExpr &exprArg : exprArgs) { + InsertNonnullCheckingInArgs(exprArg, index++, mirBuilder, ans, funcName); + ENCChecker::InsertBoundaryAssignChecking(mirBuilder, ans, exprArg, srcFileIndex, srcFileLineNum); + ENCChecker::CheckBoundaryLenFinalAddr(mirBuilder, exprArg, srcFileIndex, srcFileLineNum); + BaseNode *node = exprArg->GenMIRNode(mirBuilder); + args.push_back(node); + } + PUIdx puIdx = methodInfo.GetPuIdx(); + // for inline optimize + if (FEManager::GetModule().IsOptFunc(mirBuilder.GetCurrentFunction()) || + mirBuilder.GetCurrentFunction()->GetAttr(FUNCATTR_static)) { + FEManager::GetModule().InsertInlineGlobal(puIdx); + } + MIRSymbol *retVarSym = nullptr; + if (!methodInfo.IsReturnVoid() && var != nullptr) { + retVarSym = var->GenerateLocalMIRSymbol(mirBuilder); + InsertNonnullInRetVar(*retVarSym); + } + if (retVarSym == nullptr) { + stmtCall = mirBuilder.CreateStmtCall(puIdx, std::move(args), mirOp); + } else { + stmtCall = mirBuilder.CreateStmtCallAssigned(puIdx, std::move(args), retVarSym, mirOp); + } + ans.push_back(stmtCall); + return ans; +} + + +void FEIRStmtCallAssign::InsertNonnullInRetVar(MIRSymbol &retVarSym) const { + if (methodInfo.GetMirFunc()->GetFuncAttrs().GetAttr(FUNCATTR_nonnull)) { + TypeAttrs attrs = TypeAttrs(); + attrs.SetAttr(ATTR_nonnull); + retVarSym.AddAttrs(attrs); + } +} + +void FEIRStmtCallAssign::InsertNonnullCheckingInArgs(const UniqueFEIRExpr &expr, size_t index, MIRBuilder &mirBuilder, + std::list &ans, const std::string& funcName) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic()) { + return; + } + if (index >= methodInfo.GetMirFunc()->GetParamSize()) { // Skip variable parameter + return; + } + if (!methodInfo.GetMirFunc()->GetNthParamAttr(index).GetAttr(ATTR_nonnull)) { + return; + } + if (ENCChecker::HasNullExpr(expr)) { + FE_ERR(kLncErr, "%s:%d error: null passed to a callee that requires a nonnull argument[the %s argument]", + FEManager::GetModule().GetFileNameFromFileNum(srcFileIndex).c_str(), srcFileLineNum, + ENCChecker::GetNthStr(index).c_str()); + return; + } + if (expr->GetPrimType() == PTY_ptr) { + UniqueFEIRStmt stmt = std::make_unique(OP_callassertnonnull, expr->Clone(), + funcName, index); + std::list stmts = stmt->GenMIRStmts(mirBuilder); + ans.splice(ans.end(), stmts); + } +} + +std::list FEIRStmtCallAssign::GenMIRStmtsUseZeroReturn(MIRBuilder &mirBuilder) const { + std::list ans; + if (methodInfo.IsReturnVoid()) { + return ans; + } + const FEIRType *retType = methodInfo.GetReturnType(); + MIRType *mirRetType = retType->GenerateMIRTypeAuto(kSrcLangJava); + MIRSymbol *mirRetSym = var->GenerateLocalMIRSymbol(mirBuilder); + BaseNode *nodeZero; + if (mirRetType->IsScalarType()) { + switch (mirRetType->GetPrimType()) { + case PTY_u1: + case PTY_i8: + case PTY_i16: + case PTY_u16: + case PTY_i32: + nodeZero = mirBuilder.CreateIntConst(0, PTY_i32); + break; + case PTY_i64: + nodeZero = mirBuilder.CreateIntConst(0, PTY_i64); + break; + case PTY_f32: + nodeZero = mirBuilder.CreateFloatConst(0.0f); + break; + case PTY_f64: + nodeZero = mirBuilder.CreateDoubleConst(0.0); + break; + default: + nodeZero = mirBuilder.CreateIntConst(0, PTY_i32); + break; + } + } else { + nodeZero = mirBuilder.CreateIntConst(0, PTY_ref); + } + StmtNode *stmt = mirBuilder.CreateStmtDassign(mirRetSym->GetStIdx(), 0, nodeZero); + ans.push_back(stmt); + return ans; +} + +Opcode FEIRStmtCallAssign::AdjustMIROp() const { + if (methodInfo.IsReturnVoid()) { + auto it = mapOpAssignToOp.find(mirOp); + if (it != mapOpAssignToOp.end()) { + return it->second; + } + } else { + auto it = mapOpToOpAssign.find(mirOp); + if (it != mapOpToOpAssign.end()) { + return it->second; + } + } + return mirOp; +} + +std::string FEIRStmtCallAssign::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + if (var != nullptr) { + ss << " def : " << var->GetNameRaw() << ", "; + } + if (exprArgs.size() > 0) { + ss << " uses : "; + for (const UniqueFEIRExpr &exprArg : exprArgs) { + ss << exprArg->DumpDotString() << ", "; + } + } + return ss.str(); +} + +// ---------- FEIRStmtICallAssign ---------- +FEIRStmtICallAssign::FEIRStmtICallAssign() + : FEIRStmtAssign(FEIRNodeKind::kStmtICallAssign, nullptr) {} + +void FEIRStmtICallAssign::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + CHECK_FATAL(false, "NYI"); +} + +bool FEIRStmtICallAssign::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + bool success = true; + for (const UniqueFEIRExpr &exprArg : exprArgs) { + success = success && exprArg->CalculateDefs4AllUses(checkPoint, udChain); + } + return success; +} + +void FEIRStmtICallAssign::InsertNonnullCheckingInArgs(MIRBuilder &mirBuilder, std::list &ans) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || exprArgs.size() <= 1) { + return; + } + const MIRFuncType *funcType = FEUtils::GetFuncPtrType(*exprArgs.front()->GetType()->GenerateMIRType()); + if (funcType == nullptr) { + return; + } + int idx = -2; // the first arg is function pointer + size_t size = funcType->GetParamAttrsList().size(); + for (const auto &expr : exprArgs) { + ++idx; + if (idx < 0 || idx >= static_cast(size) || !funcType->GetNthParamAttrs(idx).GetAttr(ATTR_nonnull)) { + continue; + } + if (ENCChecker::HasNullExpr(expr)) { + FE_ERR(kLncErr, "%s:%d error: null passed to a callee that requires a nonnull argument[the %s argument]", + FEManager::GetModule().GetFileNameFromFileNum(srcFileIndex).c_str(), srcFileLineNum, + ENCChecker::GetNthStr(idx).c_str()); + continue; + } + if (expr->GetPrimType() == PTY_ptr) { + UniqueFEIRStmt stmt = std::make_unique( + OP_callassertnonnull, expr->Clone(), "function_pointer", idx); + std::list stmts = stmt->GenMIRStmts(mirBuilder); + ans.splice(ans.end(), stmts); + } + } +} + +void FEIRStmtICallAssign::InsertNonnullInRetVar(MIRSymbol &retVarSym) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic() || exprArgs.size() < 1) { + return; + } + const MIRFuncType *funcType = FEUtils::GetFuncPtrType(*exprArgs.front()->GetType()->GenerateMIRType()); + if (funcType == nullptr) { + return; + } + if (funcType->GetRetAttrs().GetAttr(ATTR_nonnull)) { + TypeAttrs attrs = TypeAttrs(); + attrs.SetAttr(ATTR_nonnull); + retVarSym.AddAttrs(attrs); + } +} + +std::list FEIRStmtICallAssign::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + StmtNode *stmtICall = nullptr; + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + args.reserve(exprArgs.size()); + for (const UniqueFEIRExpr &exprArg : exprArgs) { + BaseNode *node = exprArg->GenMIRNode(mirBuilder); + ENCChecker::InsertBoundaryAssignChecking(mirBuilder, ans, exprArg, srcFileIndex, srcFileLineNum); + ENCChecker::CheckBoundaryLenFinalAddr(mirBuilder, exprArg, srcFileIndex, srcFileLineNum); + args.push_back(node); + } + InsertNonnullCheckingInArgs(mirBuilder, ans); + MIRSymbol *retVarSym = nullptr; + if (var != nullptr) { + retVarSym = var->GenerateLocalMIRSymbol(mirBuilder); + InsertNonnullInRetVar(*retVarSym); + stmtICall = mirBuilder.CreateStmtIcallAssigned(std::move(args), *retVarSym); + } else { + stmtICall = mirBuilder.CreateStmtIcall(std::move(args)); + } + ans.push_back(stmtICall); + return ans; +} + +std::string FEIRStmtICallAssign::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + if (var != nullptr) { + ss << " def : " << var->GetNameRaw() << ", "; + } + if (exprArgs.size() > 0) { + ss << " uses : "; + for (const UniqueFEIRExpr &exprArg : exprArgs) { + ss << exprArg->DumpDotString() << ", "; + } + } + return ss.str(); +} + +// ---------- FEIRStmtIntrinsicCallAssign ---------- +FEIRStmtIntrinsicCallAssign::FEIRStmtIntrinsicCallAssign(MIRIntrinsicID id, UniqueFEIRType typeIn, + UniqueFEIRVar argVarRet) + : FEIRStmtAssign(FEIRNodeKind::kStmtIntrinsicCallAssign, std::move(argVarRet)), + intrinsicId(id), + type(std::move(typeIn)) {} + +FEIRStmtIntrinsicCallAssign::FEIRStmtIntrinsicCallAssign(MIRIntrinsicID id, UniqueFEIRType typeIn, + UniqueFEIRVar argVarRet, + std::unique_ptr> exprListIn) + : FEIRStmtAssign(FEIRNodeKind::kStmtIntrinsicCallAssign, std::move(argVarRet)), + intrinsicId(id), + type(std::move(typeIn)), + exprList(std::move(exprListIn)) {} + +FEIRStmtIntrinsicCallAssign::FEIRStmtIntrinsicCallAssign(MIRIntrinsicID id, const std::string &funcNameIn, + const std::string &protoIN, + std::unique_ptr> argsIn) + : FEIRStmtAssign(FEIRNodeKind::kStmtIntrinsicCallAssign, nullptr), + intrinsicId(id), + funcName(funcNameIn), + proto(protoIN), + polyArgs(std::move(argsIn)) {} +FEIRStmtIntrinsicCallAssign::FEIRStmtIntrinsicCallAssign(MIRIntrinsicID id, const std::string &funcNameIn, + const std::string &protoIN, + std::unique_ptr> argsIn, + uint32 callerClassTypeIDIn, bool isInStaticFuncIn) + : FEIRStmtAssign(FEIRNodeKind::kStmtIntrinsicCallAssign, nullptr), + intrinsicId(id), + funcName(funcNameIn), + proto(protoIN), + polyArgs(std::move(argsIn)), + callerClassTypeID(callerClassTypeIDIn), + isInStaticFunc(isInStaticFuncIn) {} + +FEIRStmtIntrinsicCallAssign::FEIRStmtIntrinsicCallAssign(MIRIntrinsicID id, UniqueFEIRType typeIn, + UniqueFEIRVar argVarRet, uint32 typeIDIn) + : FEIRStmtAssign(FEIRNodeKind::kStmtIntrinsicCallAssign, std::move(argVarRet)), + intrinsicId(id), + type(std::move(typeIn)), + typeID(typeIDIn) {} + +std::string FEIRStmtIntrinsicCallAssign::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +void FEIRStmtIntrinsicCallAssign::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + if ((var != nullptr) && (var.get() != nullptr)) { + var->SetDef(true); + checkPoint.RegisterDFGNode(var); + } +} + +std::list FEIRStmtIntrinsicCallAssign::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + StmtNode *stmtCall = nullptr; + if (intrinsicId == INTRN_JAVA_CLINIT_CHECK) { + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + if (FEOptions::GetInstance().IsAOT()) { + BaseNode *argNumExpr = mirBuilder.CreateIntConst(static_cast(typeID), PTY_i32); + args.push_back(argNumExpr); + } + stmtCall = mirBuilder.CreateStmtIntrinsicCall(INTRN_JAVA_CLINIT_CHECK, std::move(args), + type->GenerateMIRType()->GetTypeIndex()); + } else if (intrinsicId == INTRN_JAVA_FILL_NEW_ARRAY) { + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + if (exprList != nullptr) { + for (const auto &expr : *exprList) { + BaseNode *node = expr->GenMIRNode(mirBuilder); + args.push_back(node); + } + } + MIRSymbol *retVarSym = nullptr; + if ((var != nullptr) && (var.get() != nullptr)) { + retVarSym = var->GenerateLocalMIRSymbol(mirBuilder); + } + stmtCall = mirBuilder.CreateStmtIntrinsicCallAssigned(INTRN_JAVA_FILL_NEW_ARRAY, std::move(args), retVarSym, + type->GenerateMIRType(true)->GetTypeIndex()); + } else if (intrinsicId == INTRN_JAVA_POLYMORPHIC_CALL) { + return GenMIRStmtsForInvokePolyMorphic(mirBuilder); + } else if (intrinsicId == INTRN_C_va_start || intrinsicId == INTRN_C_memcpy) { + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + if (exprList != nullptr) { + for (const auto &expr : *exprList) { + BaseNode *node = expr->GenMIRNode(mirBuilder); + if (expr->IsAddrof()) { + node = ReplaceAddrOfNode(node); // addrof va_list + } + args.push_back(node); + } + } + MIRSymbol *retVarSym = nullptr; + if (var != nullptr) { + retVarSym = var->GenerateLocalMIRSymbol(mirBuilder); + stmtCall = mirBuilder.CreateStmtIntrinsicCallAssigned(intrinsicId, std::move(args), retVarSym); + } else { + stmtCall = mirBuilder.CreateStmtIntrinsicCall(intrinsicId, std::move(args), TyIdx(0)); + } + } else if (intrinsicId == INTRN_C_memset || intrinsicId == INTRN_C_memmove || + intrinsicId == INTRN_C_strcpy || intrinsicId == INTRN_C_strncpy || + intrinsicId == INTRN_C_memcpy) { + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + if (exprList != nullptr) { + for (const auto &expr : *exprList) { + BaseNode *node = expr->GenMIRNode(mirBuilder); + args.push_back(node); + } + } + MIRSymbol *retVarSym = nullptr; + if (var != nullptr) { + retVarSym = var->GenerateLocalMIRSymbol(mirBuilder); + stmtCall = mirBuilder.CreateStmtIntrinsicCallAssigned(intrinsicId, std::move(args), retVarSym); + } else { + stmtCall = mirBuilder.CreateStmtIntrinsicCall(intrinsicId, std::move(args), TyIdx(0)); + } + } else if (intrinsicId >= INTRN_vector_zip_v2i32 && intrinsicId <= INTRN_vector_zip_v2f32) { + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + if (exprList != nullptr) { + for (const auto &expr : *exprList) { + BaseNode *node = expr->GenMIRNode(mirBuilder); + args.push_back(node); + } + } + MIRSymbol *retVarSym = nullptr; + if ((var != nullptr) && (var.get() != nullptr)) { + retVarSym = var->GenerateLocalMIRSymbol(mirBuilder); + } + stmtCall = mirBuilder.CreateStmtIntrinsicCallAssigned(intrinsicId, std::move(args), retVarSym); + } + // other intrinsic call should be implemented + ans.emplace_back(stmtCall); + return ans; +} + +std::list FEIRStmtIntrinsicCallAssign::GenMIRStmtsForInvokePolyMorphic(MIRBuilder &mirBuilder) const { + std::list ans; + StmtNode *stmtCall = nullptr; + UniqueFEIRVar tmpVar; + bool needRetypeRet = false; + MIRSymbol *retVarSym = nullptr; + if ((var != nullptr) && (var.get() != nullptr)) { + PrimType ptyRet = var->GetTypeRef().GetPrimType(); + needRetypeRet = (ptyRet == PTY_f32 || ptyRet == PTY_f64); + tmpVar = var->Clone(); + if (ptyRet == PTY_f32) { + tmpVar->SetType(std::make_unique(PTY_i32, + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("I"))); + } else if (ptyRet == PTY_f64) { + tmpVar->SetType(std::make_unique(PTY_i64, + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("J"))); + } + retVarSym = tmpVar->GenerateLocalMIRSymbol(mirBuilder); + } + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + ConstructArgsForInvokePolyMorphic(mirBuilder, args); + stmtCall = mirBuilder.CreateStmtIntrinsicCallAssigned(INTRN_JAVA_POLYMORPHIC_CALL, std::move(args), retVarSym); + ans.emplace_back(stmtCall); + if (needRetypeRet) { + UniqueFEIRStmt retypeStmt = FEIRBuilder::CreateStmtRetype(var->Clone(), std::move(tmpVar)); + std::list retypeMirStmts = retypeStmt->GenMIRStmts(mirBuilder); + for (auto elem : retypeMirStmts) { + ans.emplace_back(elem); + } + } + return ans; +} + +void FEIRStmtIntrinsicCallAssign::ConstructArgsForInvokePolyMorphic(MIRBuilder &mirBuilder, + MapleVector &intrnCallargs) const { + MIRSymbol *funcNameVal = FEManager::GetJavaStringManager().GetLiteralVar(funcName); + if (funcNameVal == nullptr) { + funcNameVal = FEManager::GetJavaStringManager().CreateLiteralVar(mirBuilder, funcName, false); + } + BaseNode *dreadExprFuncName = mirBuilder.CreateExprAddrof(0, *funcNameVal); + dreadExprFuncName->SetPrimType(PTY_ptr); + intrnCallargs.push_back(dreadExprFuncName); + + MIRSymbol *protoNameVal = FEManager::GetJavaStringManager().GetLiteralVar(proto); + if (protoNameVal == nullptr) { + protoNameVal = FEManager::GetJavaStringManager().CreateLiteralVar(mirBuilder, proto, false); + } + BaseNode *dreadExprProtoName = mirBuilder.CreateExprAddrof(0, *protoNameVal); + dreadExprProtoName->SetPrimType(PTY_ptr); + intrnCallargs.push_back(dreadExprProtoName); + + BaseNode *argNumExpr = mirBuilder.CreateIntConst(static_cast(polyArgs->size() - 1), PTY_i32); + intrnCallargs.push_back(argNumExpr); + + bool isAfterMethodHandle = true; + for (const auto &arg : *polyArgs) { + intrnCallargs.push_back(mirBuilder.CreateExprDread(*(arg->GenerateMIRSymbol(mirBuilder)))); + if (FEOptions::GetInstance().IsAOT() && isAfterMethodHandle) { + if (isInStaticFunc) { + intrnCallargs.push_back(mirBuilder.CreateIntConst(static_cast(callerClassTypeID), PTY_i32)); + } else { + std::unique_ptr varThisAsLocalVar = std::make_unique(FEUtils::GetThisIdx(), + FEIRTypeDefault(PTY_ref).Clone()); + intrnCallargs.push_back(mirBuilder.CreateExprDread(*(varThisAsLocalVar->GenerateMIRSymbol(mirBuilder)))); + } + isAfterMethodHandle = false; + } + } +} + +// ---------- FEIRExpr ---------- +FEIRExpr::FEIRExpr(FEIRNodeKind argKind) + : kind(argKind), + isNestable(true), + isAddrof(false), + hasException(false), + isBoundaryChecking(false) { + type = std::make_unique(); +} + +FEIRExpr::FEIRExpr(FEIRNodeKind argKind, std::unique_ptr argType) + : kind(argKind), + isNestable(true), + isAddrof(false), + hasException(false), + isBoundaryChecking(false) { + SetType(std::move(argType)); +} + +std::unique_ptr FEIRExpr::Clone() { + auto expr = CloneImpl(); + expr->isNestable = IsNestable(); + expr->isAddrof = IsAddrof(); + expr->hasException = HasException(); + expr->isBoundaryChecking = IsBoundaryChecking(); + return expr; +} + +bool FEIRExpr::IsNestableImpl() const { + return isNestable; +} + +bool FEIRExpr::IsAddrofImpl() const { + return isAddrof; +} + +bool FEIRExpr::HasExceptionImpl() const { + return hasException; +} + +std::vector FEIRExpr::GetVarUsesImpl() const { + return std::vector(); +} + +std::string FEIRExpr::DumpDotString() const { + std::stringstream ss; + if (kind == FEIRNodeKind::kExprArrayLoad) { + ss << " kExprArrayLoad: "; + } + std::vector varUses = GetVarUses(); + ss << "[ "; + for (FEIRVar *use : varUses) { + ss << use->GetNameRaw() << ", "; + } + ss << "] "; + return ss.str(); +} + +// ---------- FEIRExprConst ---------- +FEIRExprConst::FEIRExprConst() + : FEIRExpr(FEIRNodeKind::kExprConst) { + ASSERT(type != nullptr, "type is nullptr"); + type->SetPrimType(PTY_i32); + value.u64 = 0; +} + +FEIRExprConst::FEIRExprConst(int64 val, PrimType argType) + : FEIRExpr(FEIRNodeKind::kExprConst) { + ASSERT(type != nullptr, "type is nullptr"); + type->SetPrimType(argType); + value.i64 = val; + CheckRawValue2SetZero(); +} + +FEIRExprConst::FEIRExprConst(uint64 val, PrimType argType) + : FEIRExpr(FEIRNodeKind::kExprConst) { + ASSERT(type != nullptr, "type is nullptr"); + type->SetPrimType(argType); + value.u64 = val; + CheckRawValue2SetZero(); +} + +FEIRExprConst::FEIRExprConst(uint32 val) + : FEIRExpr(FEIRNodeKind::kExprConst) { + type->SetPrimType(PTY_u32); + value.u32 = val; + CheckRawValue2SetZero(); +} + +FEIRExprConst::FEIRExprConst(float val) + : FEIRExpr(FEIRNodeKind::kExprConst) { + ASSERT(type != nullptr, "type is nullptr"); + type->SetPrimType(PTY_f32); + value.f32 = val; + CheckRawValue2SetZero(); +} + +FEIRExprConst::FEIRExprConst(double val) + : FEIRExpr(FEIRNodeKind::kExprConst) { + ASSERT(type != nullptr, "type is nullptr"); + type->SetPrimType(PTY_f64); + value.f64 = val; + CheckRawValue2SetZero(); +} + +std::unique_ptr FEIRExprConst::CloneImpl() const { + std::unique_ptr expr = std::make_unique(); + FEIRExprConst *exprConst = static_cast(expr.get()); + exprConst->value.u64 = value.u64; + ASSERT(type != nullptr, "type is nullptr"); + exprConst->type->SetPrimType(type->GetPrimType()); + exprConst->CheckRawValue2SetZero(); + return expr; +} + +BaseNode *FEIRExprConst::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + PrimType primType = GetPrimType(); + switch (primType) { + case PTY_u1: + case PTY_u8: + case PTY_u16: + case PTY_u32: + return mirBuilder.CreateIntConst(value.u32, primType); + case PTY_u64: + case PTY_i8: + case PTY_i16: + case PTY_i32: + case PTY_i64: + case PTY_i128: + case PTY_u128: + case PTY_ref: + case PTY_ptr: + return mirBuilder.CreateIntConst(value.i64, primType); + case PTY_f32: + return mirBuilder.CreateFloatConst(value.f32); + case PTY_f64: + return mirBuilder.CreateDoubleConst(value.f64); + default: + ERR(kLncErr, "unsupported const kind"); + return nullptr; + } +} + +uint32 FEIRExprConst::HashImpl() const { + return (static_cast(kind) << kOpHashShift) + (type->Hash() << kTypeHashShift) + + static_cast(std::hash{}(value.u64)); +} + +void FEIRExprConst::CheckRawValue2SetZero() { + if (value.u64 == 0) { + type->SetZero(true); + } +} + +// ---------- FEIRExprSizeOfType ---------- +FEIRExprSizeOfType::FEIRExprSizeOfType(UniqueFEIRType ty) + : FEIRExpr(FEIRNodeKind::kExprSizeOfType, + FEIRTypeHelper::CreateTypeNative(*GlobalTables::GetTypeTable().GetPrimType(PTY_u32))), + feirType(std::move(ty)) {} + +std::unique_ptr FEIRExprSizeOfType::CloneImpl() const { + std::unique_ptr expr = std::make_unique(feirType->Clone()); + return expr; +} + +BaseNode *FEIRExprSizeOfType::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + return mirBuilder.CreateExprSizeoftype(*(feirType->GenerateMIRTypeAuto())); +} + +// ---------- FEIRExprDRead ---------- +FEIRExprDRead::FEIRExprDRead(std::unique_ptr argVarSrc) + : FEIRExpr(FEIRNodeKind::kExprDRead) { + SetVarSrc(std::move(argVarSrc)); +} + +FEIRExprDRead::FEIRExprDRead(std::unique_ptr argType, std::unique_ptr argVarSrc) + : FEIRExpr(FEIRNodeKind::kExprDRead, std::move(argType)) { + SetVarSrc(std::move(argVarSrc)); +} + +std::unique_ptr FEIRExprDRead::CloneImpl() const { + UniqueFEIRExpr expr = std::make_unique(type->Clone(), varSrc->Clone()); + if (fieldType != nullptr) { + expr->SetFieldType(fieldType->Clone()); + } + expr->SetFieldID(fieldID); + return expr; +} + +BaseNode *FEIRExprDRead::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MIRType *type = varSrc->GetType()->GenerateMIRTypeAuto(); + MIRSymbol *symbol = varSrc->GenerateMIRSymbol(mirBuilder); + ASSERT(type != nullptr, "type is nullptr"); + PrimType regType = GetRegPrimType(type->GetPrimType()); + if (regType != type->GetPrimType()) { + type = GlobalTables::GetTypeTable().GetPrimType(regType); + } + AddrofNode *node = mirBuilder.CreateExprDread(*type, *symbol); + if (fieldID != 0) { + CHECK_FATAL((type->GetKind() == MIRTypeKind::kTypeStruct || type->GetKind() == MIRTypeKind::kTypeUnion), + "If fieldID is not 0, then the variable must be a structure"); + CHECK_NULL_FATAL(fieldType); + MIRType *fieldMIRType = fieldType->GenerateMIRTypeAuto(); + regType = GetRegPrimType(fieldMIRType->GetPrimType()); + if (regType != fieldMIRType->GetPrimType()) { + fieldMIRType = GlobalTables::GetTypeTable().GetPrimType(regType); + } + node = mirBuilder.CreateExprDread(*fieldMIRType, fieldID, *symbol); + } + return node; +} + +void FEIRExprDRead::SetVarSrc(std::unique_ptr argVarSrc) { + CHECK_FATAL(argVarSrc != nullptr, "input is nullptr"); + varSrc = std::move(argVarSrc); + SetType(varSrc->GetType()->Clone()); +} + +std::vector FEIRExprDRead::GetVarUsesImpl() const { + return std::vector({ varSrc.get() }); +} + +PrimType FEIRExprDRead::GetPrimTypeImpl() const { + PrimType primType = type->GetPrimType(); + if (primType == PTY_agg && fieldID != 0) { + CHECK_NULL_FATAL(fieldType); + return fieldType->GetPrimType(); + } + return primType; +} + +void FEIRExprDRead::SetTypeImpl(std::unique_ptr argType) { + if (fieldID != 0) { + fieldType = std::move(argType); + } else { + type = std::move(argType); + } +} + +FEIRType *FEIRExprDRead::GetTypeImpl() const { + if (fieldID != 0) { + CHECK_NULL_FATAL(fieldType); + return fieldType.get(); + } + return type.get(); +} + +const FEIRType &FEIRExprDRead::GetTypeRefImpl() const { + return *GetTypeImpl(); +} + +// ---------- FEIRExprIRead ---------- +std::unique_ptr FEIRExprIRead::CloneImpl() const { + std::unique_ptr expr = std::make_unique(type->Clone(), ptrType->Clone(), + fieldID, subExpr->Clone()); + return expr; +} + +std::vector FEIRExprIRead::GetVarUsesImpl() const { + return subExpr->GetVarUses(); +} + +BaseNode *FEIRExprIRead::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MIRType *returnType = type->GenerateMIRTypeAuto(); + MIRType *pointerType = ptrType->GenerateMIRTypeAuto(); + BaseNode *node = subExpr->GenMIRNode(mirBuilder); + CHECK_FATAL(pointerType->IsMIRPtrType(), "Must be ptr type!"); + MIRPtrType *mirPtrType = static_cast(pointerType); + MIRType *pointedMirType = mirPtrType->GetPointedType(); + if (fieldID != 0) { + CHECK_FATAL((pointedMirType->GetKind() == MIRTypeKind::kTypeStruct || + pointedMirType->GetKind() == MIRTypeKind::kTypeUnion), + "If fieldID is not 0, then type must specify pointer to a structure"); + } + return mirBuilder.CreateExprIread(*returnType, *mirPtrType, fieldID, node); +} + +// ---------- FEIRExprAddrofConstArray ---------- +FEIRExprAddrofConstArray::FEIRExprAddrofConstArray(const std::vector &arrayIn, MIRType *typeIn, + const std::string &strIn) + : FEIRExpr(FEIRNodeKind::kExprAddrof, FEIRTypeHelper::CreateTypeNative(*GlobalTables::GetTypeTable().GetPtrType())), + arrayName(FEOptions::GetInstance().GetFuncInlineSize() != 0 ? FEUtils::GetSequentialName("const_array_") + + FEUtils::GetFileNameHashStr(FEManager::GetModule().GetFileName()) : + FEUtils::GetSequentialName("const_array_")), + elemType(typeIn), + str(strIn) { + std::copy(arrayIn.begin(), arrayIn.end(), std::back_inserter(array)); +} + +std::unique_ptr FEIRExprAddrofConstArray::CloneImpl() const { + std::unique_ptr expr = std::make_unique(arrayName, array, elemType, str); + return expr; +} + +BaseNode *FEIRExprAddrofConstArray::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + if (!str.empty()) { + MIRModule &module = mirBuilder.GetMirModule(); + UStrIdx StrIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(str); + return module.GetMemPool()->New(PTY_ptr, StrIdx); + } + MIRType *arrayTypeWithSize = GlobalTables::GetTypeTable().GetOrCreateArrayType( + *elemType,static_cast(array.size())); + MIRSymbol *arrayVar = mirBuilder.GetOrCreateGlobalDecl(arrayName, *arrayTypeWithSize); + arrayVar->SetAttr(ATTR_readonly); + arrayVar->SetStorageClass(kScFstatic); + FEManager::GetModule().InsertInlineGlobal(arrayVar->GetStIdx().Idx()); + MIRModule &module = mirBuilder.GetMirModule(); + MIRAggConst *val = module.GetMemPool()->New(module, *arrayTypeWithSize); + for (uint32 i = 0; i < array.size(); ++i) { + MIRConst *cst = module.GetMemPool()->New(array[i], *elemType); + val->PushBack(cst); + } + // This interface is only for string literal, 0 is added to the end of the string. + MIRConst *cst0 = module.GetMemPool()->New(0, *elemType); + val->PushBack(cst0); + arrayVar->SetKonst(val); + BaseNode *nodeAddrof = mirBuilder.CreateExprAddrof(0, *arrayVar); + return nodeAddrof; +} + +// ---------- FEIRExprAddrOfLabel --------- +std::unique_ptr FEIRExprAddrOfLabel::CloneImpl() const { + std::unique_ptr expr = std::make_unique(labelName, type->Clone()); + return expr; +} + +BaseNode *FEIRExprAddrOfLabel::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + LabelIdx lbIdx = mirBuilder.GetOrCreateMIRLabel(labelName); + BaseNode *mirNode = mirBuilder.GetCurrentFuncCodeMp()->New(static_cast(lbIdx)); + mirNode->SetPrimType(PTY_ptr); + return mirNode; +} + +// ---------- FEIRExprIAddrof ---------- +std::unique_ptr FEIRExprIAddrof::CloneImpl() const { + return std::make_unique(ptrType->Clone(), fieldID, subExpr->Clone()); +} + +std::vector FEIRExprIAddrof::GetVarUsesImpl() const { + return subExpr->GetVarUses(); +} + +BaseNode *FEIRExprIAddrof::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MIRType *returnType = GlobalTables::GetTypeTable().GetPtrType(); + MIRType *pointerType = ptrType->GenerateMIRTypeAuto(); + BaseNode *node = subExpr->GenMIRNode(mirBuilder); + CHECK_FATAL(pointerType->IsMIRPtrType(), "Must be ptr type!"); + MIRPtrType *mirPtrType = static_cast(pointerType); + MIRType *pointedMirType = mirPtrType->GetPointedType(); + if (fieldID != 0) { + CHECK_FATAL((pointedMirType->GetKind() == MIRTypeKind::kTypeStruct || + pointedMirType->GetKind() == MIRTypeKind::kTypeUnion), + "If fieldID is not 0, then type must specify pointer to a structure"); + } + return mirBuilder.CreateExprIaddrof(*returnType, *mirPtrType, fieldID, node); +} + +// ---------- FEIRExprAddrofVar ---------- +std::unique_ptr FEIRExprAddrofVar::CloneImpl() const { + UniqueFEIRExpr expr = std::make_unique(varSrc->Clone()); + expr->SetFieldID(fieldID); + return expr; +} + +BaseNode *FEIRExprAddrofVar::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MIRSymbol *varSymbol = varSrc->GenerateMIRSymbol(mirBuilder); + if (cst != nullptr) { + varSymbol->SetKonst(cst); + } + MIRType *type = varSrc->GetType()->GenerateMIRTypeAuto(); + if (fieldID != 0) { + CHECK_FATAL((type->IsMIRStructType() || type->GetKind() == MIRTypeKind::kTypeUnion), + "if fieldID is not 0, then the variable must be a structure"); + } + AddrofNode *node = mirBuilder.CreateExprAddrof(fieldID, *varSymbol); + return node; +} + +std::vector FEIRExprAddrofVar::GetVarUsesImpl() const { + return std::vector({ varSrc.get() }); +} + +// ---------- FEIRExprAddrofFunc ---------- +std::unique_ptr FEIRExprAddrofFunc::CloneImpl() const { + auto expr = std::make_unique(funcAddr); + return expr; +} + +BaseNode *FEIRExprAddrofFunc::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + GStrIdx strIdx = GlobalTables::GetStrTable().GetStrIdxFromName(funcAddr); + MIRFunction *mirFunc = FEManager::GetTypeManager().GetMIRFunction(strIdx, false); + CHECK_FATAL(mirFunc != nullptr, "can not get MIRFunction"); + if (FEManager::GetModule().IsOptFunc(mirBuilder.GetCurrentFunction()) || + mirBuilder.GetCurrentFunction()->GetAttr(FUNCATTR_static)) { + mirBuilder.GetMirModule().InsertInlineGlobal(mirFunc->GetPuidx()); + } + return mirBuilder.CreateExprAddroffunc(mirFunc->GetPuidx(), + mirBuilder.GetMirModule().GetMemPool()); +} + +// ---------- FEIRExprAddrofArray ---------- +FEIRExprAddrofArray::FEIRExprAddrofArray(UniqueFEIRType argTypeNativeArray, UniqueFEIRExpr argExprArray, + const std::string &argArrayName, std::list &argExprIndexs) + : FEIRExpr(FEIRNodeKind::kExprAddrofArray, + FEIRTypeHelper::CreateTypeNative(*GlobalTables::GetTypeTable().GetPtrType())), + typeNativeArray(std::move(argTypeNativeArray)), + exprArray(std::move(argExprArray)), + arrayName(argArrayName) { + SetIndexsExprs(argExprIndexs); +} + +std::unique_ptr FEIRExprAddrofArray::CloneImpl() const { + UniqueFEIRType uTypeNativeArray = typeNativeArray->Clone(); + UniqueFEIRExpr uExprArray = exprArray->Clone(); + auto feirExprAddrofArray = std::make_unique(std::move(uTypeNativeArray), + std::move(uExprArray), arrayName, + exprIndexs); + feirExprAddrofArray->SetIndexsExprs(exprIndexs); + return feirExprAddrofArray; +} + +std::vector FEIRExprAddrofArray::GetVarUsesImpl() const { + return exprArray->GetVarUses(); +} + +BaseNode *FEIRExprAddrofArray::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MIRType *ptrMIRArrayType = typeNativeArray->GenerateMIRType(false); + BaseNode *nodeAddrof = nullptr; + std::vector nds; + if (!arrayName.empty()) { + std::unique_ptr arrayVar = exprArray->GetVarUses().front()->Clone(); + MIRSymbol *mirSymbol = arrayVar->GenerateMIRSymbol(mirBuilder); + if (ptrMIRArrayType->GetKind() == kTypeArray) { + mirSymbol->SetTyIdx(ptrMIRArrayType->GetTypeIndex()); + nodeAddrof = mirBuilder.CreateExprAddrof(0, *mirSymbol); + } else { + nodeAddrof = mirBuilder.CreateDread(*mirSymbol, PTY_ptr); + } + } else { + nodeAddrof = exprArray->GenMIRNode(mirBuilder); + } + nds.push_back(nodeAddrof); + for (auto &e : exprIndexs) { + BaseNode *no = e->GenMIRNode(mirBuilder); + nds.push_back(no); + } + BaseNode *arrayExpr = mirBuilder.CreateExprArray(*ptrMIRArrayType, nds); + return arrayExpr; +} + +// ---------- FEIRExprRegRead ---------- +FEIRExprRegRead::FEIRExprRegRead(PrimType pty, int32 regNumIn) + : FEIRExpr(FEIRNodeKind::kExprRegRead), prmType(pty), regNum(regNumIn) {} + +std::unique_ptr FEIRExprRegRead::CloneImpl() const { + std::unique_ptr expr = std::make_unique(prmType, regNum); + return expr; +} + +BaseNode *FEIRExprRegRead::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + RegreadNode *node = mirBuilder.CreateExprRegread(prmType, regNum); + return node; +} + +void FEIRExprDRead::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + checkPoint.RegisterDFGNode(varSrc); +} + +bool FEIRExprDRead::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + std::set defs = checkPoint.CalcuDef(varSrc); + (void)udChain.insert(std::make_pair(&varSrc, defs)); + return (defs.size() > 0); +} + +// ---------- FEIRExprUnary ---------- +std::map FEIRExprUnary::mapOpNestable = FEIRExprUnary::InitMapOpNestableForExprUnary(); + +FEIRExprUnary::FEIRExprUnary(Opcode argOp, std::unique_ptr argOpnd) + : FEIRExpr(kExprUnary), + op(argOp) { + SetOpnd(std::move(argOpnd)); + SetExprTypeByOp(); +} + +FEIRExprUnary::FEIRExprUnary(std::unique_ptr argType, Opcode argOp, std::unique_ptr argOpnd) + : FEIRExpr(kExprUnary, std::move(argType)), + op(argOp) { + SetOpnd(std::move(argOpnd)); +} + +std::map FEIRExprUnary::InitMapOpNestableForExprUnary() { + std::map ans; + ans[OP_abs] = true; + ans[OP_bnot] = true; + ans[OP_lnot] = true; + ans[OP_neg] = true; + ans[OP_recip] = true; + ans[OP_sqrt] = true; + ans[OP_gcmallocjarray] = false; + return ans; +} + +std::unique_ptr FEIRExprUnary::CloneImpl() const { + std::unique_ptr expr = std::make_unique(type->Clone(), op, opnd->Clone()); + return expr; +} + +BaseNode *FEIRExprUnary::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MIRType *mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx( + TyIdx(static_cast(GetTypeRef().GetPrimType()))); + ASSERT(mirType != nullptr, "mir type is nullptr"); + BaseNode *nodeOpnd = opnd->GenMIRNode(mirBuilder); + BaseNode *expr = mirBuilder.CreateExprUnary(op, *mirType, nodeOpnd); + return expr; +} + +void FEIRExprUnary::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + opnd->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRExprUnary::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return opnd->CalculateDefs4AllUses(checkPoint, udChain); +} + +std::vector FEIRExprUnary::GetVarUsesImpl() const { + return opnd->GetVarUses(); +} + +void FEIRExprUnary::SetOpnd(std::unique_ptr argOpnd) { + CHECK_FATAL(argOpnd != nullptr, "opnd is nullptr"); + opnd = std::move(argOpnd); +} + +const UniqueFEIRExpr &FEIRExprUnary::GetOpnd() const { + return opnd; +} + +void FEIRExprUnary::SetExprTypeByOp() { + switch (op) { + case OP_neg: + case OP_bnot: + case OP_lnot: + type->SetPrimType(opnd->GetPrimType()); + break; + default: + break; + } +} + +// ---------- FEIRExprTypeCvt ---------- +std::map FEIRExprTypeCvt::mapOpNestable = FEIRExprTypeCvt::InitMapOpNestableForTypeCvt(); +std::map FEIRExprTypeCvt::funcPtrMapForParseExpr = + FEIRExprTypeCvt::InitFuncPtrMapForParseExpr(); + +FEIRExprTypeCvt::FEIRExprTypeCvt(Opcode argOp, std::unique_ptr argOpnd) + : FEIRExprUnary(argOp, std::move(argOpnd)) {} + +FEIRExprTypeCvt::FEIRExprTypeCvt(std::unique_ptr exprType, Opcode argOp, std::unique_ptr argOpnd) + : FEIRExprUnary(std::move(exprType), argOp, std::move(argOpnd)) {} + +std::unique_ptr FEIRExprTypeCvt::CloneImpl() const { + std::unique_ptr expr = std::make_unique(type->Clone(), op, opnd->Clone()); + static_cast(expr.get())->SetSrcPrimType(srcPrimType); + return expr; +} + +BaseNode *FEIRExprTypeCvt::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + auto ptrFunc = funcPtrMapForParseExpr.find(op); + ASSERT(ptrFunc != funcPtrMapForParseExpr.end(), "unsupported op: %s", kOpcodeInfo.GetName(op).c_str()); + return (this->*(ptrFunc->second))(mirBuilder); +} + +void FEIRExprTypeCvt::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + opnd->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRExprTypeCvt::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return opnd->CalculateDefs4AllUses(checkPoint, udChain); +} + +Opcode FEIRExprTypeCvt::ChooseOpcodeByFromVarAndToVar(const FEIRVar &fromVar, const FEIRVar &toVar) { + if ((fromVar.GetType()->IsRef()) && (toVar.GetType()->IsRef())) { + return OP_retype; + } + return OP_retype; +} + +BaseNode *FEIRExprTypeCvt::GenMIRNodeMode1(MIRBuilder &mirBuilder) const { + // MIR: op () + MIRType *mirTypeDst = + GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(static_cast(GetTypeRef().GetPrimType()))); + MIRType *mirTypeSrc = nullptr; + if (srcPrimType == PTY_unknown) { + mirTypeSrc = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(static_cast(opnd->GetPrimType()))); + } else { + mirTypeSrc = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(static_cast(srcPrimType))); + } + BaseNode *nodeOpnd = opnd->GenMIRNode(mirBuilder); + BaseNode *expr = mirBuilder.CreateExprTypeCvt(op, *mirTypeDst, *mirTypeSrc, nodeOpnd); + return expr; +} + +BaseNode *FEIRExprTypeCvt::GenMIRNodeMode2(MIRBuilder &mirBuilder) const { + // MIR: op () + PrimType primTypeSrc = opnd->GetPrimType(); + CHECK_FATAL(IsPrimitiveFloat(primTypeSrc), "from type must be float type"); + return GenMIRNodeMode1(mirBuilder); +} + +BaseNode *FEIRExprTypeCvt::GenMIRNodeMode3(MIRBuilder &mirBuilder) const { + // MIR: retype () + MIRType *mirTypeDst = GetTypeRef().GenerateMIRType(); + MIRType *mirTypeSrc = opnd->GetTypeRef().GenerateMIRTypeAuto(); + BaseNode *nodeOpnd = opnd->GenMIRNode(mirBuilder); + BaseNode *expr = mirBuilder.CreateExprRetype(*mirTypeDst, *mirTypeSrc, nodeOpnd); + return expr; +} + +std::map FEIRExprTypeCvt::InitMapOpNestableForTypeCvt() { + std::map ans; + ans[OP_ceil] = true; + ans[OP_cvt] = true; + ans[OP_floor] = true; + ans[OP_retype] = true; + ans[OP_round] = true; + ans[OP_trunc] = true; + return ans; +} + +std::map FEIRExprTypeCvt::InitFuncPtrMapForParseExpr() { + std::map ans; + ans[OP_ceil] = &FEIRExprTypeCvt::GenMIRNodeMode2; + ans[OP_cvt] = &FEIRExprTypeCvt::GenMIRNodeMode1; + ans[OP_floor] = &FEIRExprTypeCvt::GenMIRNodeMode2; + ans[OP_retype] = &FEIRExprTypeCvt::GenMIRNodeMode3; + ans[OP_round] = &FEIRExprTypeCvt::GenMIRNodeMode2; + ans[OP_trunc] = &FEIRExprTypeCvt::GenMIRNodeMode2; + return ans; +} + +// ---------- FEIRExprExtractBits ---------- +std::map FEIRExprExtractBits::mapOpNestable = FEIRExprExtractBits::InitMapOpNestableForExtractBits(); +std::map FEIRExprExtractBits::funcPtrMapForParseExpr = + FEIRExprExtractBits::InitFuncPtrMapForParseExpr(); + +FEIRExprExtractBits::FEIRExprExtractBits(Opcode argOp, PrimType argPrimType, uint8 argBitOffset, uint8 argBitSize, + std::unique_ptr argOpnd) + : FEIRExprUnary(argOp, std::move(argOpnd)), + bitOffset(argBitOffset), + bitSize(argBitSize) { + CHECK_FATAL(IsPrimitiveInteger(argPrimType), "only integer type is supported"); + type->SetPrimType(argPrimType); +} + +FEIRExprExtractBits::FEIRExprExtractBits(Opcode argOp, PrimType argPrimType, std::unique_ptr argOpnd) + : FEIRExprExtractBits(argOp, argPrimType, 0, 0, std::move(argOpnd)) {} + +std::unique_ptr FEIRExprExtractBits::CloneImpl() const { + std::unique_ptr expr = std::make_unique(op, type->GetPrimType(), bitOffset, bitSize, + opnd->Clone()); + return expr; +} + +BaseNode *FEIRExprExtractBits::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + auto ptrFunc = funcPtrMapForParseExpr.find(op); + ASSERT(ptrFunc != funcPtrMapForParseExpr.end(), "unsupported op: %s", kOpcodeInfo.GetName(op).c_str()); + return (this->*(ptrFunc->second))(mirBuilder); +} + +void FEIRExprExtractBits::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + opnd->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRExprExtractBits::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return opnd->CalculateDefs4AllUses(checkPoint, udChain); +} + +std::map FEIRExprExtractBits::InitMapOpNestableForExtractBits() { + std::map ans; + ans[OP_extractbits] = true; + ans[OP_sext] = true; + ans[OP_zext] = true; + return ans; +} + +std::map FEIRExprExtractBits::InitFuncPtrMapForParseExpr() { + std::map ans; + ans[OP_extractbits] = &FEIRExprExtractBits::GenMIRNodeForExtrabits; + ans[OP_sext] = &FEIRExprExtractBits::GenMIRNodeForExt; + ans[OP_zext] = &FEIRExprExtractBits::GenMIRNodeForExt; + return ans; +} + +BaseNode *FEIRExprExtractBits::GenMIRNodeForExtrabits(MIRBuilder &mirBuilder) const { + ASSERT(opnd != nullptr, "nullptr check"); + PrimType primTypeDst = GetTypeRef().GetPrimType(); + PrimType primTypeSrc = opnd->GetPrimType(); + CHECK_FATAL(FEUtils::IsInteger(primTypeDst), "dst type of extrabits must integer"); + CHECK_FATAL(FEUtils::IsInteger(primTypeSrc), "src type of extrabits must integer"); + uint8 widthDst = FEUtils::GetWidth(primTypeDst); + uint8 widthSrc = FEUtils::GetWidth(primTypeSrc); + CHECK_FATAL(widthDst >= bitSize, "dst width is not enough"); + CHECK_FATAL(widthSrc >= bitOffset + bitSize, "src width is not enough"); + MIRType *mirTypeDst = GetTypeRef().GenerateMIRTypeAuto(); + BaseNode *nodeOpnd = opnd->GenMIRNode(mirBuilder); + BaseNode *expr = mirBuilder.CreateExprExtractbits(op, *mirTypeDst, bitOffset, bitSize, nodeOpnd); + return expr; +} + +BaseNode *FEIRExprExtractBits::GenMIRNodeForExt(MIRBuilder &mirBuilder) const { + ASSERT(opnd != nullptr, "nullptr check"); + PrimType primTypeDst = GetTypeRef().GetPrimType(); + CHECK_FATAL(FEUtils::IsInteger(primTypeDst), "dst type of sext/zext must integer"); + uint8 widthDst = FEUtils::GetWidth(primTypeDst); + // The bit size must be smaller than 32. This parameter is used only when the value of src or dst is smaller than 32. + if (widthDst >= 32) { + widthDst = FEUtils::GetWidth(opnd->GetPrimType()); + } + BaseNode *nodeOpnd = opnd->GenMIRNode(mirBuilder); + PrimType extPty; + if (op == OP_zext) { + extPty = GetUnsignedPrimType(GetRegPrimType(nodeOpnd->GetPrimType())); + } else { + extPty = GetSignedPrimType(GetRegPrimType(nodeOpnd->GetPrimType())); + } + MIRType *mirTypeDst = GlobalTables::GetTypeTable().GetPrimType(extPty); + BaseNode *expr = mirBuilder.CreateExprExtractbits(op, *mirTypeDst, 0, widthDst, nodeOpnd); + return expr; +} + +// ---------- FEIRExprBinary ---------- +std::map FEIRExprBinary::funcPtrMapForGenMIRNode = + FEIRExprBinary::InitFuncPtrMapForGenMIRNode(); + +FEIRExprBinary::FEIRExprBinary(Opcode argOp, std::unique_ptr argOpnd0, std::unique_ptr argOpnd1) + : FEIRExpr(FEIRNodeKind::kExprBinary), + op(argOp) { + SetOpnd0(std::move(argOpnd0)); + SetOpnd1(std::move(argOpnd1)); + SetExprTypeByOp(); +} + +FEIRExprBinary::FEIRExprBinary(std::unique_ptr exprType, Opcode argOp, std::unique_ptr argOpnd0, + std::unique_ptr argOpnd1) + : FEIRExpr(FEIRNodeKind::kExprBinary, std::move(exprType)), + op(argOp) { + SetOpnd0(std::move(argOpnd0)); + SetOpnd1(std::move(argOpnd1)); + if (FEManager::GetModule().GetSrcLang() != kSrcLangC) { + SetExprTypeByOp(); + } +} + +std::unique_ptr FEIRExprBinary::CloneImpl() const { + std::unique_ptr expr = std::make_unique(type->Clone(), op, opnd0->Clone(), opnd1->Clone()); + return expr; +} + +BaseNode *FEIRExprBinary::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + auto ptrFunc = funcPtrMapForGenMIRNode.find(op); + ASSERT(ptrFunc != funcPtrMapForGenMIRNode.end(), "unsupported op: %s", kOpcodeInfo.GetName(op).c_str()); + return (this->*(ptrFunc->second))(mirBuilder); +} + +void FEIRExprBinary::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + opnd0->RegisterDFGNodes2CheckPoint(checkPoint); + opnd1->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRExprBinary::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + bool success = true; + success = success && opnd0->CalculateDefs4AllUses(checkPoint, udChain); + success = success && opnd1->CalculateDefs4AllUses(checkPoint, udChain); + return success; +} + +std::vector FEIRExprBinary::GetVarUsesImpl() const { + std::vector ans; + for (FEIRVar *var : opnd0->GetVarUses()) { + ans.push_back(var); + } + for (FEIRVar *var : opnd1->GetVarUses()) { + ans.push_back(var); + } + return ans; +} + +bool FEIRExprBinary::IsNestableImpl() const { + return true; +} + +bool FEIRExprBinary::IsAddrofImpl() const { + return false; +} + +void FEIRExprBinary::SetOpnd0(std::unique_ptr argOpnd) { + CHECK_FATAL(argOpnd != nullptr, "input is nullptr"); + opnd0 = std::move(argOpnd); +} + +void FEIRExprBinary::SetOpnd1(std::unique_ptr argOpnd) { + CHECK_FATAL(argOpnd != nullptr, "input is nullptr"); + opnd1 = std::move(argOpnd); +} + +const std::unique_ptr &FEIRExprBinary::GetOpnd0() const { + return opnd0; +} + +const std::unique_ptr &FEIRExprBinary::GetOpnd1() const { + return opnd1; +} + +bool FEIRExprBinary::IsComparative() const { + switch (op) { + case OP_cmp: + case OP_cmpl: + case OP_cmpg: + case OP_eq: + case OP_ge: + case OP_gt: + case OP_le: + case OP_lt: + case OP_ne: + // Cand and cior do not need to be converted to comparison. + case OP_cand: + case OP_cior: + return true; + default: + return false; + } +} + +std::map FEIRExprBinary::InitFuncPtrMapForGenMIRNode() { + std::map ans; + ans[OP_add] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_ashr] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_band] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_bior] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_bxor] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_cand] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_cior] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_cmp] = &FEIRExprBinary::GenMIRNodeCompare; + ans[OP_cmpg] = &FEIRExprBinary::GenMIRNodeCompare; + ans[OP_cmpl] = &FEIRExprBinary::GenMIRNodeCompare; + ans[OP_div] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_eq] = &FEIRExprBinary::GenMIRNodeCompareU1; + ans[OP_ge] = &FEIRExprBinary::GenMIRNodeCompareU1; + ans[OP_gt] = &FEIRExprBinary::GenMIRNodeCompareU1; + ans[OP_land] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_lior] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_le] = &FEIRExprBinary::GenMIRNodeCompareU1; + ans[OP_lshr] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_lt] = &FEIRExprBinary::GenMIRNodeCompareU1; + ans[OP_max] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_min] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_mul] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_ne] = &FEIRExprBinary::GenMIRNodeCompareU1; + ans[OP_rem] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_shl] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_sub] = &FEIRExprBinary::GenMIRNodeNormal; + ans[OP_ror] = &FEIRExprBinary::GenMIRNodeNormal; + return ans; +} + +BaseNode *FEIRExprBinary::GenMIRNodeNormal(MIRBuilder &mirBuilder) const { + MIRType *mirTypeDst = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(static_cast(type->GetPrimType()))); + UniqueFEIRExpr opnd0FEExpr = opnd0->Clone(); + UniqueFEIRExpr opnd1FEExpr = opnd1->Clone(); + if (op == OP_cand || op == OP_cior) { + opnd0FEExpr = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(opnd0FEExpr)); + opnd1FEExpr = FEIRBuilder::CreateExprZeroCompare(OP_ne, std::move(opnd1FEExpr)); + } + BaseNode *nodeOpnd0 = opnd0FEExpr->GenMIRNode(mirBuilder); + BaseNode *nodeOpnd1 = opnd1FEExpr->GenMIRNode(mirBuilder); + BaseNode *expr = mirBuilder.CreateExprBinary(op, *mirTypeDst, nodeOpnd0, nodeOpnd1); + return expr; +} + +BaseNode *FEIRExprBinary::GenMIRNodeCompare(MIRBuilder &mirBuilder) const { + BaseNode *nodeOpnd0 = opnd0->GenMIRNode(mirBuilder); + BaseNode *nodeOpnd1 = opnd1->GenMIRNode(mirBuilder); + MIRType *mirTypeSrc = GlobalTables::GetTypeTable().GetTypeFromTyIdx( + TyIdx(static_cast(nodeOpnd0->GetPrimType()))); + MIRType *mirTypeDst = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(static_cast(type->GetPrimType()))); + BaseNode *expr = mirBuilder.CreateExprCompare(op, *mirTypeDst, *mirTypeSrc, nodeOpnd0, nodeOpnd1); + return expr; +} + +BaseNode *FEIRExprBinary::GenMIRNodeCompareU1(MIRBuilder &mirBuilder) const { + BaseNode *nodeOpnd0 = opnd0->GenMIRNode(mirBuilder); + BaseNode *nodeOpnd1 = opnd1->GenMIRNode(mirBuilder); + PrimType srcType0 = nodeOpnd0->GetPrimType(); + PrimType srcType1 = nodeOpnd1->GetPrimType(); + // We take the bigger one as srcType + PrimType srcType = GetPrimTypeActualBitSize(srcType0) > GetPrimTypeActualBitSize(srcType1) ? srcType0 : srcType1; + MIRType *mirTypeSrc = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(static_cast(srcType))); + // If the src type is a vector type, there is no need to use u1 to replace + MIRType *mirTypeDst = type->GenerateMIRTypeAuto(); + if (!PrimitiveType(mirTypeDst->GetPrimType()).IsVector()) { + mirTypeDst = GlobalTables::GetTypeTable().GetUInt1(); + } + BaseNode *expr = mirBuilder.CreateExprCompare(op, *mirTypeDst, *mirTypeSrc, nodeOpnd0, nodeOpnd1); + return expr; +} + +void FEIRExprBinary::SetExprTypeByOp() { + switch (op) { + // Normal + case OP_add: + case OP_div: + case OP_max: + case OP_min: + case OP_mul: + case OP_rem: + case OP_sub: + SetExprTypeByOpNormal(); + break; + // Shift + case OP_ashr: + case OP_lshr: + case OP_shl: + case OP_ror: + SetExprTypeByOpShift(); + break; + // Logic + case OP_band: + case OP_bior: + case OP_bxor: + case OP_cand: + case OP_cior: + case OP_land: + case OP_lior: + SetExprTypeByOpLogic(); + break; + // Compare + case OP_cmp: + case OP_cmpl: + case OP_cmpg: + case OP_eq: + case OP_ge: + case OP_gt: + case OP_le: + case OP_lt: + case OP_ne: + SetExprTypeByOpCompare(); + break; + default: + break; + } +} + +void FEIRExprBinary::SetExprTypeByOpNormal() { + PrimType primTypeOpnd0 = opnd0->GetPrimType(); + PrimType primTypeOpnd1 = opnd1->GetPrimType(); + // primTypeOpnd0 == PTY_void for addrof add + if (primTypeOpnd0 == PTY_ptr || primTypeOpnd1 == PTY_ptr || primTypeOpnd0 == PTY_void) { + type->SetPrimType(PTY_ptr); + return; + } + type->SetPrimType(primTypeOpnd0); +} + +void FEIRExprBinary::SetExprTypeByOpShift() { + PrimType primTypeOpnd0 = opnd0->GetPrimType(); + PrimType primTypeOpnd1 = opnd1->GetPrimType(); + CHECK_FATAL(IsPrimitiveInteger(primTypeOpnd0), "logic's opnd0 must be integer"); + CHECK_FATAL(IsPrimitiveInteger(primTypeOpnd1), "logic's opnd1 must be integer"); + type->SetPrimType(primTypeOpnd0); +} + +void FEIRExprBinary::SetExprTypeByOpLogic() { + PrimType primTypeOpnd0 = opnd0->GetPrimType(); + CHECK_FATAL(IsPrimitiveInteger(primTypeOpnd0), "logic's opnds must be integer"); + type->SetPrimType(primTypeOpnd0); +} + +void FEIRExprBinary::SetExprTypeByOpCompare() { + type->SetPrimType(PTY_i32); +} + +// ---------- FEIRExprTernary ---------- +FEIRExprTernary::FEIRExprTernary(Opcode argOp, std::unique_ptr argOpnd0, std::unique_ptr argOpnd1, + std::unique_ptr argOpnd2) + : FEIRExpr(FEIRNodeKind::kExprTernary), + op(argOp) { + SetOpnd(std::move(argOpnd0), 0); + SetOpnd(std::move(argOpnd1), 1); + SetOpnd(std::move(argOpnd2), 2); + SetExprTypeByOp(); +} + +FEIRExprTernary::FEIRExprTernary(Opcode argOp, std::unique_ptr argType, std::unique_ptr argOpnd0, + std::unique_ptr argOpnd1, std::unique_ptr argOpnd2) + : FEIRExpr(FEIRNodeKind::kExprTernary, std::move(argType)), + op(argOp) { + SetOpnd(std::move(argOpnd0), 0); + SetOpnd(std::move(argOpnd1), 1); + SetOpnd(std::move(argOpnd2), 2); +} + +std::unique_ptr FEIRExprTernary::CloneImpl() const { + std::unique_ptr expr = std::make_unique(op, type->Clone(), opnd0->Clone(), opnd1->Clone(), + opnd2->Clone()); + return expr; +} + +BaseNode *FEIRExprTernary::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MIRType *mirTypeDst = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(static_cast(type->GetPrimType()))); + BaseNode *nodeOpnd0 = opnd0->GenMIRNode(mirBuilder); + BaseNode *nodeOpnd1 = opnd1->GenMIRNode(mirBuilder); + BaseNode *nodeOpnd2 = opnd2->GenMIRNode(mirBuilder); + BaseNode *expr = mirBuilder.CreateExprTernary(op, *mirTypeDst, nodeOpnd0, nodeOpnd1, nodeOpnd2); + return expr; +} + +void FEIRExprTernary::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + opnd0->RegisterDFGNodes2CheckPoint(checkPoint); + opnd1->RegisterDFGNodes2CheckPoint(checkPoint); + opnd2->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRExprTernary::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + bool success = true; + success = success && opnd0->CalculateDefs4AllUses(checkPoint, udChain); + success = success && opnd1->CalculateDefs4AllUses(checkPoint, udChain); + success = success && opnd2->CalculateDefs4AllUses(checkPoint, udChain); + return success; +} + +std::vector FEIRExprTernary::GetVarUsesImpl() const { + std::vector ans; + for (FEIRVar *var : opnd0->GetVarUses()) { + ans.push_back(var); + } + for (FEIRVar *var : opnd1->GetVarUses()) { + ans.push_back(var); + } + for (FEIRVar *var : opnd2->GetVarUses()) { + ans.push_back(var); + } + return ans; +} + +bool FEIRExprTernary::IsNestableImpl() const { + return true; +} + +bool FEIRExprTernary::IsAddrofImpl() const { + return false; +} + +void FEIRExprTernary::SetOpnd(std::unique_ptr argOpnd, uint32 idx) { + CHECK_FATAL(argOpnd != nullptr, "input is nullptr"); + switch (idx) { + case 0: + opnd0 = std::move(argOpnd); + break; + case 1: + opnd1 = std::move(argOpnd); + break; + case 2: + opnd2 = std::move(argOpnd); + break; + default: + CHECK_FATAL(false, "index out of range"); + } +} + +void FEIRExprTernary::SetExprTypeByOp() { + PrimType primTypeOpnd1 = opnd1->GetPrimType(); + type->SetPrimType(primTypeOpnd1); +} + +// ---------- FEIRExprNary ---------- +FEIRExprNary::FEIRExprNary(Opcode argOp) + : FEIRExpr(FEIRNodeKind::kExprNary), + op(argOp) {} + +std::vector FEIRExprNary::GetVarUsesImpl() const { + std::vector ans; + for (const std::unique_ptr &opnd : opnds) { + for (FEIRVar *var : opnd->GetVarUses()) { + ans.push_back(var); + } + } + return ans; +} + +void FEIRExprNary::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + for (const std::unique_ptr &opnd : opnds) { + opnd->RegisterDFGNodes2CheckPoint(checkPoint); + } +} + +bool FEIRExprNary::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + bool success = true; + for (const std::unique_ptr &opnd : opnds) { + success = success && opnd->CalculateDefs4AllUses(checkPoint, udChain); + } + return success; +} + +void FEIRExprNary::AddOpnd(std::unique_ptr argOpnd) { + CHECK_FATAL(argOpnd != nullptr, "input opnd is nullptr"); + opnds.push_back(std::move(argOpnd)); +} + +void FEIRExprNary::AddOpnds(const std::vector> &argOpnds) { + for (const std::unique_ptr &opnd : argOpnds) { + ASSERT_NOT_NULL(opnd); + AddOpnd(opnd->Clone()); + } +} + +void FEIRExprNary::ResetOpnd() { + opnds.clear(); +} + +// ---------- FEIRExprIntrinsicop ---------- +FEIRExprIntrinsicop::FEIRExprIntrinsicop(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID) + : FEIRExprNary(OP_intrinsicop), + intrinsicID(argIntrinsicID) { + kind = FEIRNodeKind::kExprIntrinsicop; + SetType(std::move(exprType)); +} + +FEIRExprIntrinsicop::FEIRExprIntrinsicop(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID, + std::unique_ptr argParamType) + : FEIRExprNary(OP_intrinsicopwithtype), + intrinsicID(argIntrinsicID) { + kind = FEIRNodeKind::kExprIntrinsicop; + SetType(std::move(exprType)); + paramType = std::move(argParamType); +} + +FEIRExprIntrinsicop::FEIRExprIntrinsicop(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID, + const std::vector> &argOpnds) + : FEIRExprIntrinsicop(std::move(exprType), argIntrinsicID) { + AddOpnds(argOpnds); +} + +FEIRExprIntrinsicop::FEIRExprIntrinsicop(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID, + std::unique_ptr argParamType, + const std::vector> &argOpnds) + : FEIRExprIntrinsicop(std::move(exprType), argIntrinsicID, std::move(argParamType)) { + AddOpnds(argOpnds); +} + +FEIRExprIntrinsicop::FEIRExprIntrinsicop(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID, + std::unique_ptr argParamType, uint32 argTypeID) + : FEIRExprNary(OP_intrinsicopwithtype), + intrinsicID(argIntrinsicID), + typeID(argTypeID) { + kind = FEIRNodeKind::kExprIntrinsicop; + SetType(std::move(exprType)); + paramType = std::move(argParamType); +} + +std::unique_ptr FEIRExprIntrinsicop::CloneImpl() const { + if (op == OP_intrinsicop) { + return std::make_unique(type->Clone(), intrinsicID, opnds); + } else { + CHECK_FATAL(paramType != nullptr, "error: param type is not set"); + return std::make_unique(type->Clone(), intrinsicID, paramType->Clone(), opnds); + } +} + +BaseNode *FEIRExprIntrinsicop::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + for (const auto &e : opnds) { + BaseNode *node = e->GenMIRNode(mirBuilder); + args.emplace_back(node); + } + (void)typeID; + MIRType *ptrType = GlobalTables::GetTypeTable().GetOrCreatePointerType( + *(type->GenerateMIRType()), paramType->IsRef() ? PTY_ref : PTY_ptr); + BaseNode *expr = mirBuilder.CreateExprIntrinsicop(intrinsicID, op, *ptrType, std::move(args)); + return expr; +} + +void FEIRExprIntrinsicop::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + for (const std::unique_ptr &opnd : opnds) { + opnd->RegisterDFGNodes2CheckPoint(checkPoint); + } +} + +bool FEIRExprIntrinsicop::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + bool success = true; + for (const std::unique_ptr &opnd : opnds) { + success = success && opnd->CalculateDefs4AllUses(checkPoint, udChain); + } + return success; +} + +bool FEIRExprIntrinsicop::IsNestableImpl() const { + return false; +} + +bool FEIRExprIntrinsicop::IsAddrofImpl() const { + return false; +} + +// ---------- FEIRExprIntrinsicopForC ---------- +FEIRExprIntrinsicopForC::FEIRExprIntrinsicopForC(std::unique_ptr exprType, MIRIntrinsicID argIntrinsicID, + const std::vector> &argOpnds) + : FEIRExprNary(OP_intrinsicop), + intrinsicID(argIntrinsicID) { + kind = FEIRNodeKind::kExprIntrinsicop; + SetType(std::move(exprType)); + AddOpnds(argOpnds); +} + +std::unique_ptr FEIRExprIntrinsicopForC::CloneImpl() const { + return std::make_unique(type->Clone(), intrinsicID, opnds); +} + +BaseNode *FEIRExprIntrinsicopForC::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + for (const auto &e : opnds) { + BaseNode *node = e->GenMIRNode(mirBuilder); + args.emplace_back(node); + } + return mirBuilder.CreateExprIntrinsicop(intrinsicID, op, + *type->GenerateMIRTypeAuto(), MapleVector(args)); +} + +// ---------- FEIRExprJavaMerge ---------------- +FEIRExprJavaMerge::FEIRExprJavaMerge(std::unique_ptr mergedTypeArg, + const std::vector> &argOpnds) + : FEIRExprNary(OP_intrinsicop) { + SetType(std::move(mergedTypeArg)); + AddOpnds(argOpnds); +} + +std::unique_ptr FEIRExprJavaMerge::CloneImpl() const { + return std::make_unique(type->Clone(), opnds); +} + +void FEIRExprJavaMerge::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + for (const std::unique_ptr &opnd : opnds) { + opnd->RegisterDFGNodes2CheckPoint(checkPoint); + } +} + +bool FEIRExprJavaMerge::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + bool success = true; + for (const std::unique_ptr &opnd : opnds) { + success = success && opnd->CalculateDefs4AllUses(checkPoint, udChain); + } + return success; +} + +BaseNode *FEIRExprJavaMerge::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + args.reserve(opnds.size()); + for (const auto &e : opnds) { + BaseNode *node = e->GenMIRNode(mirBuilder); + args.emplace_back(node); + } + // (intrinsicop u1 JAVA_MERGE (dread i32 %Reg0_I)) + IntrinDesc *intrinDesc = &IntrinDesc::intrinTable[INTRN_JAVA_MERGE]; + MIRType *retType = intrinDesc->GetReturnType(); + BaseNode *intr = mirBuilder.CreateExprIntrinsicop(INTRN_JAVA_MERGE, op, *retType, std::move(args)); + intr->SetPrimType(type->GetPrimType()); + return intr; +} + +// ---------- FEIRExprJavaNewInstance ---------- +FEIRExprJavaNewInstance::FEIRExprJavaNewInstance(UniqueFEIRType argType) + : FEIRExpr(FEIRNodeKind::kExprJavaNewInstance) { + SetType(std::move(argType)); +} + +FEIRExprJavaNewInstance::FEIRExprJavaNewInstance(UniqueFEIRType argType, uint32 argTypeID) + : FEIRExpr(FEIRNodeKind::kExprJavaNewInstance), typeID(argTypeID) { + SetType(std::move(argType)); +} + +FEIRExprJavaNewInstance::FEIRExprJavaNewInstance(UniqueFEIRType argType, uint32 argTypeID, bool argIsRcPermanent) + : FEIRExpr(FEIRNodeKind::kExprJavaNewInstance), typeID(argTypeID), isRcPermanent(argIsRcPermanent) { + SetType(std::move(argType)); +} + +std::unique_ptr FEIRExprJavaNewInstance::CloneImpl() const { + std::unique_ptr expr = std::make_unique(type->Clone()); + CHECK_NULL_FATAL(expr); + return expr; +} + +BaseNode *FEIRExprJavaNewInstance::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MIRType *mirType = type->GenerateMIRType(kSrcLangJava, false); + BaseNode *expr = nullptr; + MIRType *ptrType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*mirType, PTY_ref); + Opcode opMalloc = isRcPermanent ? OP_gcpermalloc : OP_gcmalloc; + expr = mirBuilder.CreateExprGCMalloc(opMalloc, *ptrType, *mirType); + CHECK_NULL_FATAL(expr); + return expr; +} + +// ---------- FEIRExprJavaNewArray ---------- +FEIRExprJavaNewArray::FEIRExprJavaNewArray(UniqueFEIRType argArrayType, UniqueFEIRExpr argExprSize) + : FEIRExpr(FEIRNodeKind::kExprJavaNewArray) { + SetArrayType(std::move(argArrayType)); + SetExprSize(std::move(argExprSize)); +} + +FEIRExprJavaNewArray::FEIRExprJavaNewArray(UniqueFEIRType argArrayType, UniqueFEIRExpr argExprSize, uint32 argTypeID) + : FEIRExpr(FEIRNodeKind::kExprJavaNewArray), typeID(argTypeID) { + SetArrayType(std::move(argArrayType)); + SetExprSize(std::move(argExprSize)); +} + +FEIRExprJavaNewArray::FEIRExprJavaNewArray(UniqueFEIRType argArrayType, UniqueFEIRExpr argExprSize, uint32 argTypeID, + bool argIsRcPermanent) + : FEIRExpr(FEIRNodeKind::kExprJavaNewArray), typeID(argTypeID), isRcPermanent(argIsRcPermanent) { + SetArrayType(std::move(argArrayType)); + SetExprSize(std::move(argExprSize)); +} + +std::unique_ptr FEIRExprJavaNewArray::CloneImpl() const { + std::unique_ptr expr = std::make_unique(arrayType->Clone(), exprSize->Clone()); + CHECK_NULL_FATAL(expr); + return expr; +} + +std::vector FEIRExprJavaNewArray::GetVarUsesImpl() const { + return exprSize->GetVarUses(); +} + +BaseNode *FEIRExprJavaNewArray::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + UniqueFEIRType elemType = FEIRBuilder::CreateArrayElemType(arrayType); + MIRType *elemMirType = elemType->GenerateMIRType(kSrcLangJava, false); + if (!elemMirType->IsScalarType()) { + elemMirType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*elemMirType, PTY_ptr); + } + MIRType *jarrayType = GlobalTables::GetTypeTable().GetOrCreateJarrayType(*elemMirType); + (void)typeID; + MIRType *mirType = arrayType->GenerateMIRType(kSrcLangJava, false); + MIRType *ptrType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*mirType, PTY_ref); + BaseNode *sizeNode = exprSize->GenMIRNode(mirBuilder); + Opcode opMalloc = isRcPermanent ? OP_gcpermallocjarray : OP_gcmallocjarray; + BaseNode *expr = mirBuilder.CreateExprJarrayMalloc(opMalloc, *ptrType, *jarrayType, sizeNode); + CHECK_NULL_FATAL(expr); + return expr; +} + +void FEIRExprJavaNewArray::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + exprSize->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRExprJavaNewArray::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return exprSize->CalculateDefs4AllUses(checkPoint, udChain); +} + +// ---------- FEIRExprJavaArrayLength ---------- +FEIRExprJavaArrayLength::FEIRExprJavaArrayLength(UniqueFEIRExpr argExprArray) + : FEIRExpr(FEIRNodeKind::kExprJavaArrayLength) { + SetExprArray(std::move(argExprArray)); +} + +std::unique_ptr FEIRExprJavaArrayLength::CloneImpl() const { + UniqueFEIRExpr expr = std::make_unique(exprArray->Clone()); + CHECK_NULL_FATAL(expr); + return expr; +} + +std::vector FEIRExprJavaArrayLength::GetVarUsesImpl() const { + return exprArray->GetVarUses(); +} + +BaseNode *FEIRExprJavaArrayLength::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + BaseNode *arrayNode = exprArray->GenMIRNode(mirBuilder); + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + args.push_back(arrayNode); + MIRType *retType = GlobalTables::GetTypeTable().GetInt32(); + return mirBuilder.CreateExprIntrinsicop(INTRN_JAVA_ARRAY_LENGTH, OP_intrinsicop, *retType, std::move(args)); +} + +void FEIRExprJavaArrayLength::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + exprArray->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRExprJavaArrayLength::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + return exprArray->CalculateDefs4AllUses(checkPoint, udChain); +} + +// ---------- FEIRExprArrayLoad ---------- +FEIRExprArrayLoad::FEIRExprArrayLoad(UniqueFEIRExpr argExprArray, UniqueFEIRExpr argExprIndex, + UniqueFEIRType argTypeArray) + : FEIRExpr(FEIRNodeKind::kExprArrayLoad), + exprArray(std::move(argExprArray)), + exprIndex(std::move(argExprIndex)), + typeArray(std::move(argTypeArray)) {} + +std::unique_ptr FEIRExprArrayLoad::CloneImpl() const { + std::unique_ptr expr = std::make_unique(exprArray->Clone(), exprIndex->Clone(), + typeArray->Clone()); + return expr; +} + +BaseNode *FEIRExprArrayLoad::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + CHECK_FATAL(exprArray->GetKind() == kExprDRead, "only support dread expr for exprArray"); + CHECK_FATAL(exprIndex->GetKind() == kExprDRead, "only support dread expr for exprIndex"); + BaseNode *addrBase = exprArray->GenMIRNode(mirBuilder); + BaseNode *indexBn = exprIndex->GenMIRNode(mirBuilder); + MIRType *ptrMIRArrayType = typeArray->GenerateMIRType(false); + + BaseNode *arrayExpr = mirBuilder.CreateExprArray(*ptrMIRArrayType, addrBase, indexBn); + UniqueFEIRType typeElem = typeArray->Clone(); + (void)typeElem->ArrayDecrDim(); + + MIRType *mirElemType = typeElem->GenerateMIRType(true); + MIRType *ptrMIRElemType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*mirElemType, PTY_ptr); + BaseNode *elemBn = mirBuilder.CreateExprIread(*mirElemType, *ptrMIRElemType, 0, arrayExpr); + return elemBn; +} + +std::vector FEIRExprArrayLoad::GetVarUsesImpl() const { + std::vector ans; + for (FEIRVar *var : exprArray->GetVarUses()) { + ans.push_back(var); + } + for (FEIRVar *var : exprIndex->GetVarUses()) { + ans.push_back(var); + } + return ans; +} + +void FEIRExprArrayLoad::RegisterDFGNodes2CheckPointImpl(FEIRStmtCheckPoint &checkPoint) { + exprArray->RegisterDFGNodes2CheckPoint(checkPoint); + exprIndex->RegisterDFGNodes2CheckPoint(checkPoint); +} + +bool FEIRExprArrayLoad::CalculateDefs4AllUsesImpl(FEIRStmtCheckPoint &checkPoint, FEIRUseDefChain &udChain) { + bool success = true; + success = success && exprArray->CalculateDefs4AllUses(checkPoint, udChain); + success = success && exprIndex->CalculateDefs4AllUses(checkPoint, udChain); + return success; +} + +// ---------- FEIRExprCStyleCast ---------- +FEIRExprCStyleCast::FEIRExprCStyleCast(MIRType *src, + MIRType *dest, + UniqueFEIRExpr sub, + bool isArr2Pty) + : FEIRExpr(FEIRNodeKind::kExprCStyleCast), + srcType(src), + destType(dest), + subExpr(std::move(sub)), + isArray2Pointer(isArr2Pty) { + CHECK_NULL_FATAL(dest); + type = FEIRTypeHelper::CreateTypeNative(*dest); +} + +std::unique_ptr FEIRExprCStyleCast::CloneImpl() const { + auto expr = std::make_unique(srcType, destType, + subExpr->Clone(), isArray2Pointer); + expr->SetRefName(refName); + return expr; +} + +std::vector FEIRExprCStyleCast::GetVarUsesImpl() const { + return subExpr->GetVarUses(); +} + +BaseNode *FEIRExprCStyleCast::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + BaseNode *sub = subExpr.get()->GenMIRNode(mirBuilder); + BaseNode *cvt = nullptr; + if (isArray2Pointer) { + auto *arrayType = static_cast(srcType); + ASSERT(arrayType != nullptr, "ERROR:null pointer!"); + ArrayNode *arrayNode = mirBuilder.CreateExprArray(*arrayType); + MIRSymbol *var = subExpr->GetVarUses().front()->GenerateMIRSymbol(mirBuilder); + arrayNode->GetNopnd().push_back(mirBuilder.CreateExprAddrof(0, *var)); + for (uint8 i = 0; i < arrayType->GetDim(); ++i) { + arrayNode->GetNopnd().push_back(mirBuilder.CreateIntConst(0, PTY_i32)); + } + arrayNode->SetNumOpnds(static_cast(arrayType->GetDim() + 1)); + return arrayNode; + } + auto isCvtNeeded = [&](const MIRType &fromNode, const MIRType &toNode, const BaseNode &baseNode) { + if (fromNode.EqualTo(toNode)) { + return false; + } + return true; + }; + if (!isCvtNeeded(*srcType, *destType, *sub)) { + return sub; + } + if (sub != nullptr && srcType != nullptr && destType != nullptr) { + PrimType fromType = srcType->GetPrimType(); + PrimType toType = destType->GetPrimType(); + if (fromType == toType || toType == PTY_void || destType->GetKind() == kTypeUnion) { + return sub; + } + if (IsPrimitiveFloat(fromType) && IsPrimitiveInteger(toType)) { + if (toType == PTY_u1) { + MIRType *mirTypeU1 = GlobalTables::GetTypeTable().GetUInt1(); + BaseNode *zeroNode = (fromType == PTY_f32) ? mirBuilder.CreateFloatConst(0) : mirBuilder.CreateDoubleConst(0); + return mirBuilder.CreateExprCompare(OP_ne, *mirTypeU1, *srcType, sub, zeroNode); + } + cvt = mirBuilder.CreateExprTypeCvt(OP_trunc, *destType, *srcType, sub); + } else { + cvt = mirBuilder.CreateExprTypeCvt(OP_cvt, *destType, *srcType, sub); + } + } + return cvt; +} + +// ---------- FEIRExprAtomic ---------- +FEIRExprAtomic::FEIRExprAtomic(MIRType *ty, MIRType *ref, UniqueFEIRExpr obj, ASTAtomicOp atomOp) + : FEIRExpr(FEIRNodeKind::kExprAtomic), + mirType(ty), + refType(ref), + ptrType(GlobalTables::GetTypeTable().GetOrCreatePointerType(*refType)), + objExpr(std::move(obj)), + atomicOp(atomOp) {} + +std::unique_ptr FEIRExprAtomic::CloneImpl() const { + std::unique_ptr expr = std::make_unique(mirType, refType, objExpr->Clone(), atomicOp); + static_cast(expr.get())->SetVal1Type(val1Type); + if (valExpr1.get() != nullptr) { + static_cast(expr.get())->SetVal1Expr(valExpr1->Clone()); + } + static_cast(expr.get())->SetVal1Type(val2Type); + if (valExpr2.get() != nullptr) { + static_cast(expr.get())->SetVal1Expr(valExpr2->Clone()); + } + return expr; +} + +BaseNode *FEIRExprAtomic::GenMIRNodeImpl(MIRBuilder &mirBuilder) const { + MIRSymbol *retVar = nullptr; + if (atomicOp != kAtomicOpStore) { + retVar = val->GenerateMIRSymbol(mirBuilder); + } + MapleVector args(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + BaseNode *objNode = objExpr.get()->GenMIRNode(mirBuilder); + args.emplace_back(objNode); + bool retVoid = false; + if (atomicOp != kAtomicOpLoadN) { + args.emplace_back(valExpr1->GenMIRNode(mirBuilder)); + if (atomicOp == kAtomicOpExchange) { + args.emplace_back(valExpr2->GenMIRNode(mirBuilder)); + } + if (atomicOp == kAtomicOpExchangeN || + (atomicOp >= kAtomicOpAddFetch && atomicOp <= kAtomicOpFetchNand)) { + retVoid = false; + } else { + retVoid = true; + } + } + static std::unordered_map intrinsicIDMap = { + {kAtomicOpLoadN, INTRN_C___atomic_load_n}, + {kAtomicOpLoad, INTRN_C___atomic_load}, + {kAtomicOpStoreN, INTRN_C___atomic_store_n}, + {kAtomicOpStore, INTRN_C___atomic_store}, + {kAtomicOpExchangeN, INTRN_C___atomic_exchange_n}, + {kAtomicOpExchange, INTRN_C___atomic_exchange}, + {kAtomicOpAddFetch, INTRN_C___atomic_add_fetch}, + {kAtomicOpSubFetch, INTRN_C___atomic_sub_fetch}, + {kAtomicOpAndFetch, INTRN_C___atomic_and_fetch}, + {kAtomicOpXorFetch, INTRN_C___atomic_xor_fetch}, + {kAtomicOpOrFetch, INTRN_C___atomic_or_fetch}, + {kAtomicOpNandFetch, INTRN_C___atomic_nand_fetch}, + {kAtomicOpFetchAdd, INTRN_C___atomic_fetch_add}, + {kAtomicOpFetchSub, INTRN_C___atomic_fetch_sub}, + {kAtomicOpFetchAnd, INTRN_C___atomic_fetch_and}, + {kAtomicOpFetchXor, INTRN_C___atomic_fetch_xor}, + {kAtomicOpFetchOr, INTRN_C___atomic_fetch_or}, + {kAtomicOpFetchNand, INTRN_C___atomic_fetch_nand}, + }; + CHECK(intrinsicIDMap.find(atomicOp) != intrinsicIDMap.end(), "atomic opcode not yet supported!"); + MIRIntrinsicID intrinsicID = intrinsicIDMap[atomicOp]; + args.emplace_back(orderExpr->GenMIRNode(mirBuilder)); + StmtNode *stmt = nullptr; + if (!retVoid) { + stmt = mirBuilder.CreateStmtIntrinsicCallAssigned(intrinsicID, std::move(args), retVar); + } else { + stmt = mirBuilder.CreateStmtIntrinsicCall(intrinsicID, std::move(args), TyIdx(0)); + } + return stmt; +} + +// ---------- FEIRStmtPesudoLabel ---------- +FEIRStmtPesudoLabel::FEIRStmtPesudoLabel(uint32 argLabelIdx) + : FEIRStmt(kStmtPesudoLabel), + labelIdx(argLabelIdx), + mirLabelIdx(0) {} + +std::list FEIRStmtPesudoLabel::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + StmtNode *stmtLabel = mirBuilder.CreateStmtLabel(mirLabelIdx); + ans.push_back(stmtLabel); + return ans; +} + +void FEIRStmtPesudoLabel::GenerateLabelIdx(MIRBuilder &mirBuilder) { + std::stringstream ss; + ss << "label" << HIR2MPLEnv::GetInstance().GetGlobalLabelIdx(); + HIR2MPLEnv::GetInstance().IncrGlobalLabelIdx(); + mirLabelIdx = mirBuilder.GetOrCreateMIRLabel(ss.str()); +} + +std::string FEIRStmtPesudoLabel::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtPesudoLabel2 ---------- +LabelIdx FEIRStmtPesudoLabel2::GenMirLabelIdx(MIRBuilder &mirBuilder, uint32 qIdx0, uint32 qIdx1) { + std::string label = "L" + std::to_string(qIdx0) + "_" + std::to_string(qIdx1); + return mirBuilder.GetOrCreateMIRLabel(label); +} + +std::pair FEIRStmtPesudoLabel2::GetLabelIdx() const { + return std::make_pair(labelIdxOuter, labelIdxInner); +} + +std::list FEIRStmtPesudoLabel2::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + StmtNode *stmtLabel = mirBuilder.CreateStmtLabel(GenMirLabelIdx(mirBuilder, labelIdxOuter, labelIdxInner)); + ans.push_back(stmtLabel); + return ans; +} + +// ---------- FEIRStmtPesudoLOC ---------- +FEIRStmtPesudoLOC::FEIRStmtPesudoLOC(uint32 argSrcFileIdx, uint32 argLineNumber) + : FEIRStmt(kStmtPesudoLOC) { + isAuxPre = true; + SetSrcFileInfo(argSrcFileIdx, argLineNumber); +} + +std::list FEIRStmtPesudoLOC::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + return std::list(); +} + +std::string FEIRStmtPesudoLOC::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtPesudoJavaTry ---------- +FEIRStmtPesudoJavaTry::FEIRStmtPesudoJavaTry() + : FEIRStmt(kStmtPesudoJavaTry) {} + +std::list FEIRStmtPesudoJavaTry::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + MapleVector vec(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + for (FEIRStmtPesudoLabel *stmtLabel : catchTargets) { + vec.push_back(stmtLabel->GetMIRLabelIdx()); + } + StmtNode *stmtTry = mirBuilder.CreateStmtTry(vec); + ans.push_back(stmtTry); + return ans; +} + +std::string FEIRStmtPesudoJavaTry::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtPesudoJavaTry2 ---------- +FEIRStmtPesudoJavaTry2::FEIRStmtPesudoJavaTry2(uint32 outerIdxIn) + : FEIRStmt(kStmtPesudoJavaTry), outerIdx(outerIdxIn) {} + +std::list FEIRStmtPesudoJavaTry2::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + MapleVector vec(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + for (uint32 target : catchLabelIdxVec) { + vec.push_back(FEIRStmtPesudoLabel2::GenMirLabelIdx(mirBuilder, outerIdx, target)); + } + StmtNode *stmtTry = mirBuilder.CreateStmtTry(vec); + ans.push_back(stmtTry); + return ans; +} + +std::string FEIRStmtPesudoJavaTry2::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtPesudoEndTry ---------- +FEIRStmtPesudoEndTry::FEIRStmtPesudoEndTry() + : FEIRStmt(kStmtPesudoEndTry) { + isAuxPost = true; +} + +std::list FEIRStmtPesudoEndTry::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + MemPool *mp = mirBuilder.GetCurrentFuncCodeMp(); + ASSERT(mp != nullptr, "mempool is nullptr"); + StmtNode *stmt = mp->New(OP_endtry); + ans.push_back(stmt); + return ans; +} + +std::string FEIRStmtPesudoEndTry::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtPesudoCatch ---------- +FEIRStmtPesudoCatch::FEIRStmtPesudoCatch(uint32 argLabelIdx) + : FEIRStmtPesudoLabel(argLabelIdx) {} + +std::list FEIRStmtPesudoCatch::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + StmtNode *stmtLabel = mirBuilder.CreateStmtLabel(mirLabelIdx); + ans.push_back(stmtLabel); + MapleVector vec(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + for (const UniqueFEIRType &type : catchTypes) { + MIRType *mirType = type->GenerateMIRType(kSrcLangJava, true); + vec.push_back(mirType->GetTypeIndex()); + } + StmtNode *stmtCatch = mirBuilder.CreateStmtCatch(vec); + ans.push_back(stmtCatch); + return ans; +} + +void FEIRStmtPesudoCatch::AddCatchTypeNameIdx(GStrIdx typeNameIdx) { + UniqueFEIRType type = std::make_unique(PTY_ref, typeNameIdx); + catchTypes.push_back(std::move(type)); +} + +std::string FEIRStmtPesudoCatch::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtPesudoCatch2 ---------- +FEIRStmtPesudoCatch2::FEIRStmtPesudoCatch2(uint32 qIdx0, uint32 qIdx1) + : FEIRStmtPesudoLabel2(qIdx0, qIdx1) {} + +std::list FEIRStmtPesudoCatch2::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + StmtNode *stmtLabel = mirBuilder.CreateStmtLabel( + FEIRStmtPesudoLabel2::GenMirLabelIdx(mirBuilder, GetLabelIdx().first, GetLabelIdx().second)); + ans.push_back(stmtLabel); + MapleVector vec(mirBuilder.GetCurrentFuncCodeMpAllocator()->Adapter()); + for (const UniqueFEIRType &type : catchTypes) { + MIRType *mirType = type->GenerateMIRType(kSrcLangJava, true); + vec.push_back(mirType->GetTypeIndex()); + } + StmtNode *stmtCatch = mirBuilder.CreateStmtCatch(vec); + ans.push_back(stmtCatch); + return ans; +} + +void FEIRStmtPesudoCatch2::AddCatchTypeNameIdx(GStrIdx typeNameIdx) { + UniqueFEIRType type; + if (typeNameIdx == FEUtils::GetVoidIdx()) { + type = std::make_unique(PTY_ref, bc::BCUtil::GetJavaThrowableNameMplIdx()); + } else { + type = std::make_unique(PTY_ref, typeNameIdx); + } + catchTypes.push_back(std::move(type)); +} + +std::string FEIRStmtPesudoCatch2::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +FEIRStmtPesudoSafe::FEIRStmtPesudoSafe(bool isEnd) + : FEIRStmt(kStmtPesudoSafe), end(isEnd) {} + +std::list FEIRStmtPesudoSafe::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + MemPool *mp = mirBuilder.GetCurrentFuncCodeMp(); + ASSERT(mp != nullptr, "mempool is nullptr"); + Opcode op = end ? OP_endsafe : OP_safe; + StmtNode *stmt = mp->New(op); + ans.push_back(stmt); + FEFunction &curFEFunc = FEManager::GetCurrentFEFunction(); + if (end) { + if (curFEFunc.GetSafeRegionFlag().empty() || !curFEFunc.GetSafeRegionFlag().top()) { + CHECK_FATAL(false, "pop safe region error"); + } + curFEFunc.GetSafeRegionFlag().pop(); + } else { + curFEFunc.GetSafeRegionFlag().push(true); + } + return ans; +} + +std::string FEIRStmtPesudoSafe::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +FEIRStmtPesudoUnsafe::FEIRStmtPesudoUnsafe(bool isEnd) + : FEIRStmt(kStmtPesudoUnsafe), end(isEnd) {} + +std::list FEIRStmtPesudoUnsafe::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + MemPool *mp = mirBuilder.GetCurrentFuncCodeMp(); + ASSERT(mp != nullptr, "mempool is nullptr"); + Opcode op = end ? OP_endunsafe : OP_unsafe; + StmtNode *stmt = mp->New(op); + ans.push_back(stmt); + FEFunction &curFEFunc = FEManager::GetCurrentFEFunction(); + if (end) { + if (curFEFunc.GetSafeRegionFlag().empty() || curFEFunc.GetSafeRegionFlag().top()) { + CHECK_FATAL(false, "pop unsafe region error"); + } + curFEFunc.GetSafeRegionFlag().pop(); + } else { + curFEFunc.GetSafeRegionFlag().push(false); + } + return ans; +} + +std::string FEIRStmtPesudoUnsafe::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtPesudoComment ---------- +FEIRStmtPesudoComment::FEIRStmtPesudoComment(FEIRNodeKind argKind) + : FEIRStmt(argKind) { + isAuxPre = true; +} + +FEIRStmtPesudoComment::FEIRStmtPesudoComment(const std::string &argContent) + : FEIRStmt(kStmtPesudoComment), + content(argContent) { + isAuxPre = true; +} + +std::list FEIRStmtPesudoComment::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + StmtNode *stmt = mirBuilder.CreateStmtComment(content); + ans.push_back(stmt); + return ans; +} + +std::string FEIRStmtPesudoComment::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtPesudoCommentForInst ---------- +FEIRStmtPesudoCommentForInst::FEIRStmtPesudoCommentForInst() + : FEIRStmtPesudoComment(kStmtPesudoCommentForInst) { + isAuxPre = true; +} + +std::list FEIRStmtPesudoCommentForInst::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + return ans; +} + +std::string FEIRStmtPesudoCommentForInst::DumpDotStringImpl() const { + std::stringstream ss; + ss << " " << id << ": " << GetFEIRNodeKindDescription(kind); + return ss.str(); +} + +// ---------- FEIRStmtIAssign ---------- +std::list FEIRStmtIAssign::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list ans; + MIRType *mirType = addrType->GenerateMIRTypeAuto(); + CHECK_FATAL(mirType->IsMIRPtrType(), "Must be ptr type"); + BaseNode *addrNode = addrExpr->GenMIRNode(mirBuilder); + BaseNode *baseNode = baseExpr->GenMIRNode(mirBuilder); + if (fieldID != 0) { + MIRType * baseType = static_cast(mirType)->GetPointedType(); + CHECK_FATAL((baseType->GetKind() == MIRTypeKind::kTypeStruct || baseType->GetKind() == MIRTypeKind::kTypeUnion), + "If fieldID is not 0, then the computed address must correspond to a structure"); + InsertNonnullChecking(mirBuilder, *baseType, ans); + CheckNonnullArgsAndRetForFuncPtr(mirBuilder, *baseType); + CheckBoundaryArgsAndRetForFuncPtr(mirBuilder, *baseType); + } + AssignBoundaryVarAndChecking(mirBuilder, ans); + IassignNode *iAssignNode = mirBuilder.CreateStmtIassign(*mirType, fieldID, addrNode, baseNode); + ans.emplace_back(iAssignNode); + ENCChecker::CheckBoundaryLenFinalAssign(mirBuilder, addrType, fieldID, srcFileIndex, srcFileLineNum); + ENCChecker::CheckBoundaryLenFinalAddr(mirBuilder, addrExpr, srcFileIndex, srcFileLineNum); + return ans; +} + +void FEIRStmtIAssign::InsertNonnullChecking(MIRBuilder &mirBuilder, const MIRType &baseType, + std::list &ans) const { + if (!FEOptions::GetInstance().IsNpeCheckDynamic()) { + return; + } + FieldID tmpID = fieldID; + FieldPair fieldPair = static_cast(baseType).TraverseToFieldRef(tmpID); + if (fieldPair.second.second.GetAttr(FLDATTR_nonnull)) { + if (ENCChecker::HasNullExpr(baseExpr)) { + FE_ERR(kLncErr, "%s:%d error: null assignment of nonnull pointer", + FEManager::GetModule().GetFileNameFromFileNum(srcFileIndex).c_str(), srcFileLineNum); + return; + } + UniqueFEIRStmt stmt = std::make_unique(OP_assignassertnonnull, baseExpr->Clone()); + std::list stmts = stmt->GenMIRStmts(mirBuilder); + ans.splice(ans.end(), stmts); + } +} + +// ---------- FEIRStmtDoWhile ---------- +bool FEIRStmtDoWhile::IsFallThroughImpl() const { + WARN(kLncWarn, "%s:%d stmt[%s] need to be lowed when building bb", + FEManager::GetModule().GetFileNameFromFileNum(srcFileIndex).c_str(), srcFileLineNum, + GetFEIRNodeKindDescription(kind).c_str()); + return false; +} + +std::list FEIRStmtDoWhile::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list stmts; + auto *whileStmtNode = mirBuilder.GetCurrentFuncCodeMp()->New(opcode); + BaseNode *mirCond = condExpr->GenMIRNode(mirBuilder); + whileStmtNode->SetOpnd(mirCond, 0); + auto *bodyBlock = mirBuilder.GetCurrentFuncCodeMp()->New(); + for (auto &stmt : bodyStmts) { + for (auto mirStmt : stmt->GenMIRStmts(mirBuilder)) { + bodyBlock->AddStatement(mirStmt); + } + } + whileStmtNode->SetBody(bodyBlock); + stmts.emplace_back(whileStmtNode); + return stmts; +} + +std::list FEIRStmtBreak::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list stmts; + CHECK_FATAL(!breakLabelName.empty(), "labelName is null!"); + LabelIdx labelIdx = mirBuilder.GetOrCreateMIRLabel(breakLabelName); + GotoNode *gotoNode = mirBuilder.CreateStmtGoto(OP_goto, labelIdx); + stmts.emplace_back(gotoNode); + return stmts; +} + +std::list FEIRStmtContinue::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list stmts; + CHECK_FATAL(!labelName.empty(), "labelName is null!"); + LabelIdx labelIdx = mirBuilder.GetOrCreateMIRLabel(labelName); + GotoNode *gotoNode = mirBuilder.CreateStmtGoto(OP_goto, labelIdx); + stmts.emplace_back(gotoNode); + return stmts; +} + +std::list FEIRStmtLabel::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + return std::list{mirBuilder.CreateStmtLabel(mirBuilder.GetOrCreateMIRLabel(labelName))}; +} + +FEIRStmtAtomic::FEIRStmtAtomic(UniqueFEIRExpr expr) + : FEIRStmt(FEIRNodeKind::kStmtAtomic), + atomicExpr(std::move(expr)) {} + +std::list FEIRStmtAtomic::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list stmts; + FEIRExprAtomic *atom = static_cast(atomicExpr.get()); + auto stmt = static_cast(atom->GenMIRNode(mirBuilder)); + stmts.emplace_back(stmt); + return stmts; +} + +bool FEIRStmtGCCAsm::HandleConstraintPlusQm(MIRBuilder &mirBuilder, AsmNode *asmNode, uint32 index) const { + if (std::get<1>(outputs[index]) != "+Q" && std::get<1>(outputs[index]) != "+m") { + return false; + } + FieldID fieldID = outputsExprs[index]->GetFieldID(); + MIRSymbol *sym = outputsExprs[index]->GetVarUses().front()->GenerateMIRSymbol(mirBuilder); + + CallReturnPair retPair(sym->GetStIdx(), RegFieldPair(fieldID, 0)); + asmNode->asmOutputs.emplace_back(retPair); + UStrIdx strIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(std::get<1>(outputs[index])); + asmNode->outputConstraints.emplace_back(strIdx); + + BaseNode *node; + if (outputsExprs[index]->GetKind() == kExprDRead) { + node = static_cast(mirBuilder.CreateExprAddrof(fieldID, *sym)); + } else if (outputsExprs[index]->GetKind() == kExprIRead) { + FEIRExprIRead *iread = static_cast(outputsExprs[index].get()); + if (iread->GetFieldID() == 0) { + node = iread->GetClonedOpnd()->GenMIRNode(mirBuilder); + } else { + auto addrOfExpr = std::make_unique(iread->GetClonedPtrType(), iread->GetFieldID(), + iread->GetClonedOpnd()); + node = addrOfExpr->GenMIRNode(mirBuilder); + } + } else { + CHECK_FATAL(false, "FEIRStmtGCCAsm NYI."); + } + asmNode->PushOpnd(node); + asmNode->inputConstraints.emplace_back(strIdx); + return true; +} + +std::list FEIRStmtGCCAsm::GenMIRStmtsImpl(MIRBuilder &mirBuilder) const { + std::list stmts; + std::list initStmts; + MemPool *mp = mirBuilder.GetCurrentFuncCodeMp(); + AsmNode *asmNode = mp->New(mirBuilder.GetCurrentFuncCodeMpAllocator()); + asmNode->asmString = asmStr; + for (uint32 i = 0; i < inputs.size(); ++i) { + BaseNode *node = inputsExprs[i]->GenMIRNode(mirBuilder); + asmNode->PushOpnd(node); + UStrIdx strIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(inputs[i].second); + asmNode->inputConstraints.emplace_back(strIdx); + } + for (uint32 i = 0; i < outputs.size(); ++i) { + if (HandleConstraintPlusQm(mirBuilder, asmNode, i)) { + continue; + } + FieldID fieldID = 0; + MIRSymbol *sym = nullptr; + UniqueFEIRVar asmOut; + if (outputsExprs[i]->GetKind() == kExprDRead) { + FEIRExprDRead *dread = static_cast(outputsExprs[i].get()); + fieldID = dread->GetFieldID(); + sym = dread->GetVarUses().front()->GenerateMIRSymbol(mirBuilder); + asmOut = dread->GetVarUses().front()->Clone(); + } else if (outputsExprs[i]->GetKind() == kExprIRead) { + FEIRExprIRead *iread = static_cast(outputsExprs[i].get()); + fieldID = iread->GetFieldID(); + asmOut = FEIRBuilder::CreateVarNameForC(FEUtils::GetSequentialName("asm_out_"), iread->GetClonedRetType()); + sym = asmOut->GenerateLocalMIRSymbol(mirBuilder); + UniqueFEIRExpr srcExpr = FEIRBuilder::CreateExprDRead(asmOut->Clone()); + auto stmt = FEIRBuilder::CreateStmtIAssign(iread->GetClonedPtrType(), iread->GetClonedOpnd(), + std::move(srcExpr), fieldID); + std::list node = stmt->GenMIRStmts(mirBuilder); + stmts.splice(stmts.end(), node); + + // The field ID is set to zero when a temporary variable is created for iread and sym is not a struct or union. + if (!sym->GetType()->IsStructType()) { + fieldID = 0; + } + } else { + CHECK_FATAL(false, "FEIRStmtGCCAsm NYI."); + } + + CallReturnPair retPair(sym->GetStIdx(), RegFieldPair(fieldID, 0)); + asmNode->asmOutputs.emplace_back(retPair); + UStrIdx strIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(std::get<1>(outputs[i])); + asmNode->outputConstraints.emplace_back(strIdx); + + // If this is a read/write, copy the initial value into the temp before and added to the input list + if (std::get<2>(outputs[i])) { + auto stmt = FEIRBuilder::CreateStmtDAssign(asmOut->Clone(), outputsExprs[i]->Clone()); + std::list node = stmt->GenMIRStmts(mirBuilder); + initStmts.splice(initStmts.end(), node); + + AddrofNode *rNode = mirBuilder.CreateExprDread(*sym); + asmNode->PushOpnd(static_cast(rNode)); + asmNode->inputConstraints.emplace_back(strIdx); + } + } + for (uint32 i = 0; i < clobbers.size(); ++i) { + UStrIdx strIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(clobbers[i]); + asmNode->clobberList.emplace_back(strIdx); + } + for (uint32 i = 0; i < labels.size(); ++i) { + LabelIdx label = mirBuilder.GetOrCreateMIRLabel(labels[i]); + asmNode->gotoLabels.emplace_back(label); + } + if (isVolatile) { + asmNode->SetQualifier(kASMvolatile); + } + if (isGoto) { + asmNode->SetQualifier(kASMgoto); + } + stmts.emplace_front(asmNode); + if (!initStmts.empty()) { + stmts.splice(stmts.begin(), initStmts); + } + return stmts; +} +} // namespace maple diff --git a/src/hir2mpl/common/src/feir_type.cpp b/src/hir2mpl/common/src/feir_type.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9af32cf7a3bd62fc9dccfdab873e0e891337a07 --- /dev/null +++ b/src/hir2mpl/common/src/feir_type.cpp @@ -0,0 +1,518 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "feir_type.h" +#include +#include "global_tables.h" +#include "mpl_logging.h" +#include "fe_manager.h" +#include "fe_config_parallel.h" +#include "fe_utils.h" + +namespace maple { +// ---------- FEIRType ---------- +std::map> FEIRType::langConfig = FEIRType::InitLangConfig(); + +FEIRType::FEIRType(FEIRTypeKind argKind) + : kind(argKind), isZero(false), srcLang(kSrcLangJava) {} + +void FEIRType::CopyFromImpl(const FEIRType &type) { + kind = type.kind; +} + +bool FEIRType::IsEqualToImpl(const std::unique_ptr &argType) const { + CHECK_NULL_FATAL(argType.get()); + if (kind != argType.get()->kind) { + return false; + } + return IsEqualTo(*(argType.get())); +} + +bool FEIRType::IsEqualToImpl(const FEIRType &argType) const { + if (kind == argType.kind && isZero == argType.isZero) { + return true; + } else { + return false; + } +} + +std::unique_ptr FEIRType::NewType(FEIRTypeKind argKind) { + switch (argKind) { + case kFEIRTypeDefault: + return std::make_unique(); + default: + CHECK_FATAL(false, "unsupported FEIRType Kind"); + return std::make_unique(); + } +} + +std::map> FEIRType::InitLangConfig() { + std::map> ans; + ans[kSrcLangJava] = std::make_tuple(true, PTY_ref); + ans[kSrcLangC] = std::make_tuple(true, PTY_ref); + return ans; +} + +MIRType *FEIRType::GenerateMIRTypeAuto(MIRSrcLang argSrcLang) const { + return GenerateMIRTypeAutoImpl(argSrcLang); +} + +MIRType *FEIRType::GenerateMIRTypeAutoImpl(MIRSrcLang argSrcLang) const { + HIR2MPL_PARALLEL_FORBIDDEN(); + auto it = langConfig.find(argSrcLang); + if (it == langConfig.end()) { + CHECK_FATAL(false, "unsupported language"); + return nullptr; + } + PrimType pTy = GetPrimType(); + return GenerateMIRType(std::get<0>(it->second), pTy == PTY_begin ? std::get<1>(it->second) : pTy); +} + +// ---------- FEIRTypeDefault ---------- +FEIRTypeDefault::FEIRTypeDefault() + : FEIRTypeDefault(PTY_void, GStrIdx(0), 0) {} + +FEIRTypeDefault::FEIRTypeDefault(PrimType argPrimType) + : FEIRTypeDefault(argPrimType, GStrIdx(0), 0) {} + +FEIRTypeDefault::FEIRTypeDefault(PrimType argPrimType, const GStrIdx &argTypeNameIdx) + : FEIRTypeDefault(argPrimType, argTypeNameIdx, 0) { + std::string typeName = GlobalTables::GetStrTable().GetStringFromStrIdx(argTypeNameIdx); + uint8 typeDim = FEUtils::GetDim(typeName); + if (typeDim != 0) { + dim = typeDim; + typeName = typeName.substr(dim); + typeNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(typeName); + primType = FEUtils::GetPrimType(typeNameIdx); + } +} + +FEIRTypeDefault::FEIRTypeDefault(PrimType argPrimType, const GStrIdx &argTypeNameIdx, TypeDim argDim) + : FEIRType(kFEIRTypeDefault), + primType(argPrimType), + typeNameIdx(argTypeNameIdx), + dim(argDim) {} + +void FEIRTypeDefault::CopyFromImpl(const FEIRType &type) { + CHECK_FATAL(type.GetKind() == kFEIRTypeDefault, "invalid FEIRType Kind"); + FEIRType::CopyFromImpl(type); + const FEIRTypeDefault &typeDefault = static_cast(type); + typeNameIdx = typeDefault.typeNameIdx; + dim = typeDefault.dim; +} + +std::unique_ptr FEIRTypeDefault::CloneImpl() const { + std::unique_ptr type = std::make_unique(primType, typeNameIdx, dim); + return type; +} + +MIRType *FEIRTypeDefault::GenerateMIRTypeImpl(bool usePtr, PrimType ptyPtr) const { + HIR2MPL_PARALLEL_FORBIDDEN(); + return GenerateMIRTypeInternal(typeNameIdx, usePtr, ptyPtr); +} + +TypeDim FEIRTypeDefault::ArrayIncrDimImpl(TypeDim delta) { + CHECK_FATAL(FEConstants::kDimMax - dim >= delta, "dim delta is too large"); + dim += delta; + return dim; +} + +TypeDim FEIRTypeDefault::ArrayDecrDimImpl(TypeDim delta) { + CHECK_FATAL(dim >= delta, "dim delta is too large"); + dim -= delta; + return dim; +} + +bool FEIRTypeDefault::IsEqualToImpl(const FEIRType &argType) const { + if (!FEIRType::IsEqualToImpl(argType)) { + return false; + } + const FEIRTypeDefault &argTypeDefault = static_cast(argType); + if (typeNameIdx == argTypeDefault.typeNameIdx && dim == argTypeDefault.dim && primType == argTypeDefault.primType) { + return true; + } else { + return false; + } +} + +bool FEIRTypeDefault::IsEqualToImpl(const std::unique_ptr &argType) const { + CHECK_NULL_FATAL(argType.get()); + return IsEqualToImpl(*(argType.get())); +} + +uint32 FEIRTypeDefault::HashImpl() const { + return static_cast( + std::hash{}(primType) + std::hash{}(typeNameIdx) + std::hash{}(dim)); +} + +bool FEIRTypeDefault::IsScalarImpl() const { + return (primType != PTY_ref && IsPrimitiveScalar(primType) && dim == 0); +} + +PrimType FEIRTypeDefault::GetPrimTypeImpl() const { + if (dim == 0) { + return primType; + } else { + return PTY_ref; + } +} + +void FEIRTypeDefault::SetPrimTypeImpl(PrimType pt) { + if (dim == 0) { + primType = pt; + } else { + if (pt == PTY_ref) { + primType = pt; + } else { + WARN(kLncWarn, "dim is set to zero"); + dim = 0; + } + } +} + +void FEIRTypeDefault::LoadFromJavaTypeName(const std::string &typeName, bool inMpl) { + uint32 dimLocal = 0; + std::string baseName = FETypeManager::GetBaseTypeName(typeName, dimLocal, inMpl); + CHECK_FATAL(dimLocal <= FEConstants::kDimMax, "invalid array type %s (dim is too big)", typeName.c_str()); + dim = static_cast(dimLocal); + if (baseName.length() == 1) { + typeNameIdx = GStrIdx(0); + switch (baseName[0]) { + case 'I': + primType = PTY_i32; + break; + case 'J': + primType = PTY_i64; + break; + case 'F': + primType = PTY_f32; + break; + case 'D': + primType = PTY_f64; + break; + case 'Z': + primType = PTY_u1; + break; + case 'B': + primType = PTY_i8; + break; + case 'S': + primType = PTY_i16; + break; + case 'C': + primType = PTY_u16; + break; + case 'V': + primType = PTY_void; + break; + default: + CHECK_FATAL(false, "unsupported java type %s", typeName.c_str()); + } + } else if (baseName[0] == 'L') { + primType = PTY_ref; + baseName = inMpl ? baseName : namemangler::EncodeName(baseName); + typeNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(baseName); + } +} + +void FEIRTypeDefault::LoadFromASTTypeName(const std::string &typeName) { + const static std::map mapASTTypeNameToType = { + {"bool", PTY_u1}, + {"uint8", PTY_u8}, + {"uint16", PTY_u16}, + {"uint32", PTY_u32}, + {"uint64", PTY_u64}, + {"int8", PTY_i8}, + {"int16", PTY_i16}, + {"int32", PTY_i32}, + {"int64", PTY_i64}, + {"float", PTY_f32}, + {"double", PTY_f64}, + {"void", PTY_void} + }; + auto it = mapASTTypeNameToType.find(typeName); + if (it != mapASTTypeNameToType.end()) { + primType = it->second; + } else { + primType = PTY_ref; + typeNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(typeName); + } +} + +MIRType *FEIRTypeDefault::GenerateMIRTypeForPrim() const { + switch (primType) { + case PTY_i8: + return GlobalTables::GetTypeTable().GetInt8(); + case PTY_i16: + return GlobalTables::GetTypeTable().GetInt16(); + case PTY_i32: + return GlobalTables::GetTypeTable().GetInt32(); + case PTY_i64: + return GlobalTables::GetTypeTable().GetInt64(); + case PTY_f32: + return GlobalTables::GetTypeTable().GetFloat(); + case PTY_f64: + return GlobalTables::GetTypeTable().GetDouble(); + case PTY_u1: + return GlobalTables::GetTypeTable().GetUInt1(); + case PTY_u8: + return GlobalTables::GetTypeTable().GetUInt8(); + case PTY_u16: + return GlobalTables::GetTypeTable().GetUInt16(); + case PTY_u32: + return GlobalTables::GetTypeTable().GetUInt32(); + case PTY_u64: + return GlobalTables::GetTypeTable().GetUInt64(); + case PTY_void: + return GlobalTables::GetTypeTable().GetVoid(); + case PTY_a32: + return GlobalTables::GetTypeTable().GetAddr32(); + case PTY_ref: + return GlobalTables::GetTypeTable().GetRef(); + case PTY_ptr: + return GlobalTables::GetTypeTable().GetPtr(); + default: + CHECK_FATAL(false, "unsupported prim type"); + } + return GlobalTables::GetTypeTable().GetDynundef(); +} + +MIRType *FEIRTypeDefault::GenerateMIRTypeInternal(const GStrIdx &argTypeNameIdx, bool usePtr) const { + MIRType *baseType = nullptr; + MIRType *type = nullptr; + if (primType == PTY_ref) { + if (argTypeNameIdx.GetIdx() == 0) { + baseType = GlobalTables::GetTypeTable().GetRef(); + } else { + bool isCreate = false; + baseType = FEManager::GetTypeManager().GetOrCreateClassOrInterfaceType(GStrIdx(argTypeNameIdx), false, + FETypeFlag::kSrcUnknown, isCreate); + } + if (dim > 0) { + baseType = FEManager::GetTypeManager().GetOrCreatePointerType(*baseType); + } + type = FEManager::GetTypeManager().GetOrCreateArrayType(*baseType, dim); + } else { + baseType = GenerateMIRTypeForPrim(); + type = FEManager::GetTypeManager().GetOrCreateArrayType(*baseType, dim); + } + if (IsScalar() || !IsPreciseRefType()) { + return type; + } + return usePtr ? FEManager::GetTypeManager().GetOrCreatePointerType(*type) : type; +} + +MIRType *FEIRTypeDefault::GenerateMIRTypeInternal(const GStrIdx &argTypeNameIdx, bool usePtr, PrimType ptyPtr) const { + MIRType *baseType = nullptr; + MIRType *type = nullptr; + bool baseTypeUseNoPtr = (IsScalarPrimType(primType) || argTypeNameIdx == 0); + bool typeUseNoPtr = !IsRef() || (!IsArray() && !IsPrecise()); + if (baseTypeUseNoPtr) { + baseType = GenerateMIRTypeForPrim(); + type = FEManager::GetTypeManager().GetOrCreateArrayType(*baseType, dim, ptyPtr); + } else { + bool isCreate = false; + baseType = FEManager::GetTypeManager().GetOrCreateClassOrInterfaceType(argTypeNameIdx, false, + FETypeFlag::kSrcUnknown, isCreate); + if (dim > 0) { + baseType = FEManager::GetTypeManager().GetOrCreatePointerType(*baseType, ptyPtr); + } + type = FEManager::GetTypeManager().GetOrCreateArrayType(*baseType, dim, ptyPtr); + } + if (typeUseNoPtr) { + return type; + } + return usePtr ? FEManager::GetTypeManager().GetOrCreatePointerType(*type, ptyPtr) : type; +} + +std::string FEIRTypeDefault::GetTypeNameImpl() const { + if (dim == 0) { + return GlobalTables::GetStrTable().GetStringFromStrIdx(typeNameIdx); + } + std::string name; + switch (srcLang) { + case kSrcLangJava: { + for (TypeDim i = 0; i < dim; i++) { + (void)name.append("A"); + } + (void)name.append(GlobalTables::GetStrTable().GetStringFromStrIdx(typeNameIdx)); + return name; + } + default: + CHECK_FATAL(false, "undefined language"); + return ""; + } +} + +// ---------- FEIRTypeByName ---------- +FEIRTypeByName::FEIRTypeByName(PrimType argPrimType, const std::string &argTypeName, TypeDim argDim) + : FEIRTypeDefault(argPrimType, GStrIdx(0), argDim), + typeName(argTypeName) { + kind = kFEIRTypeByName; +} + +std::unique_ptr FEIRTypeByName::CloneImpl() const { + std::unique_ptr newType = std::make_unique(primType, typeName, dim); + return newType; +} + +MIRType *FEIRTypeByName::GenerateMIRTypeImpl(bool usePtr, PrimType ptyPtr) const { + HIR2MPL_PARALLEL_FORBIDDEN(); + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(typeName); + return GenerateMIRTypeInternal(nameIdx, usePtr, ptyPtr); +} + +bool FEIRTypeByName::IsEqualToImpl(const FEIRType &argType) const { + if (!FEIRTypeDefault::IsEqualToImpl(argType)) { + return false; + } + const FEIRTypeByName &argTypeName = static_cast(argType); + if (typeName.compare(argTypeName.typeName) == 0) { + return true; + } else { + return false; + } +} + +uint32 FEIRTypeByName::HashImpl() const { + return static_cast(std::hash{}(typeName)); +} + +bool FEIRTypeByName::IsScalarImpl() const { + return false; +} + +// ---------- FEIRTypePointer ---------- +FEIRTypePointer::FEIRTypePointer(std::unique_ptr argBaseType, PrimType argPrimType) + : FEIRType(kFEIRTypePointer), + primType(argPrimType) { + CHECK_FATAL(argBaseType != nullptr, "input type is nullptr"); + baseType = std::move(argBaseType); +} + +std::unique_ptr FEIRTypePointer::CloneImpl() const { + std::unique_ptr newType = std::make_unique(baseType->Clone(), primType); + return newType; +} + +MIRType *FEIRTypePointer::GenerateMIRTypeImpl(bool usePtr, PrimType ptyPtr) const { + MIRType *mirBaseType = baseType->GenerateMIRType(usePtr, ptyPtr); + return FEManager::GetTypeManager().GetOrCreatePointerType(*mirBaseType, ptyPtr); +} + +bool FEIRTypePointer::IsEqualToImpl(const FEIRType &argType) const { + const FEIRTypePointer &argTypePointer = static_cast(argType); + return baseType->IsEqualTo(argTypePointer.baseType); +} + +uint32 FEIRTypePointer::HashImpl() const { + ASSERT(baseType != nullptr, "base type is nullptr"); + return baseType->Hash(); +} + +bool FEIRTypePointer::IsScalarImpl() const { + return false; +} + +TypeDim FEIRTypePointer::ArrayIncrDimImpl(TypeDim delta) { + ASSERT(baseType != nullptr, "base type is nullptr"); + return baseType->ArrayIncrDim(delta); +} + +TypeDim FEIRTypePointer::ArrayDecrDimImpl(TypeDim delta) { + ASSERT(baseType != nullptr, "base type is nullptr"); + return baseType->ArrayDecrDim(delta); +} + +PrimType FEIRTypePointer::GetPrimTypeImpl() const { + return primType; +} + +void FEIRTypePointer::SetPrimTypeImpl(PrimType pt) { + CHECK_FATAL(false, "PrimType %d should not run here", pt); +} + +// ---------- FEIRTypeNative ---------- +FEIRTypeNative::FEIRTypeNative(MIRType &argMIRtype) + : FEIRType(kFEIRTypeNative), + mirType(argMIRtype) { + kind = kFEIRTypeNative; + // Right now, FEIRTypeNative is only used for c-language. + srcLang = kSrcLangC; +} + +PrimType FEIRTypeNative::GetPrimTypeImpl() const { + return mirType.GetPrimType(); +} + +void FEIRTypeNative::SetPrimTypeImpl(PrimType pt) { + mirType.SetPrimType(pt); +} + +void FEIRTypeNative::CopyFromImpl(const FEIRType &type) { + CHECK_FATAL(type.GetKind() == kFEIRTypeNative, "invalid opration"); + mirType = *(type.GenerateMIRTypeAuto()); +} + +MIRType *FEIRTypeNative::GenerateMIRTypeAutoImpl() const { + return &mirType; +} + +std::unique_ptr FEIRTypeNative::CloneImpl() const { + std::unique_ptr newType = std::make_unique(mirType); + return newType; +} + +MIRType *FEIRTypeNative::GenerateMIRTypeImpl(bool usePtr, PrimType ptyPtr) const { + return &mirType; +} + +bool FEIRTypeNative::IsEqualToImpl(const FEIRType &argType) const { + if (argType.GetKind() != kFEIRTypeNative) { + return false; + } + const FEIRTypeNative &argTypeNative = static_cast(argType); + return &argTypeNative.mirType == &mirType; +} + +uint32 FEIRTypeNative::HashImpl() const { + return static_cast(mirType.GetHashIndex()); +} + +std::string FEIRTypeNative::GetTypeNameImpl() const { + return mirType.GetName(); +} + +bool FEIRTypeNative::IsScalarImpl() const { + return mirType.IsScalarType(); +} + +bool FEIRTypeNative::IsRefImpl() const { + return mirType.GetPrimType() == PTY_ref; +} + +bool FEIRTypeNative::IsArrayImpl() const { + return mirType.GetKind() == kTypeArray; +} + +TypeDim FEIRTypeNative::ArrayIncrDimImpl(TypeDim delta) { + CHECK_FATAL(false, "Should not get here"); + return delta; +} + +TypeDim FEIRTypeNative::ArrayDecrDimImpl(TypeDim delta) { + CHECK_FATAL(false, "Should not get here"); + return delta; +} +} // namespace maple diff --git a/src/hir2mpl/common/src/feir_type_helper.cpp b/src/hir2mpl/common/src/feir_type_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..00bd483ebe5c281f7413e945456643bf6270e751 --- /dev/null +++ b/src/hir2mpl/common/src/feir_type_helper.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "feir_type_helper.h" +#include "fe_type_manager.h" + +namespace maple { +UniqueFEIRType FEIRTypeHelper::CreateTypeByPrimType(PrimType primType, TypeDim dim, bool usePtr) { + UniqueFEIRType type = std::make_unique(primType, GStrIdx(0), dim); + if (usePtr) { + return FEIRTypeHelper::CreatePointerType(std::move(type)); + } else { + return type; + } +} + +UniqueFEIRType FEIRTypeHelper::CreateTypeByJavaName(const std::string &typeName, bool inMpl, bool usePtr) { + uint32 dim = 0; + std::string baseName = FETypeManager::GetBaseTypeName(typeName, dim, inMpl); + CHECK_FATAL(dim <= FEConstants::kDimMax, "invalid array type %s (dim is too big)", typeName.c_str()); + uint8 dim8 = static_cast(dim); + UniqueFEIRType newType; + if (baseName.length() == 1) { + newType = CreateTypeByJavaNamePrim(baseName[0], dim8); + CHECK_FATAL(newType != nullptr, "unsupported java type name %s: ", typeName.c_str()); + } else if (baseName[0] == 'L') { + baseName = inMpl ? baseName : namemangler::EncodeName(baseName); + GStrIdx typeNameIdx = GlobalTables::GetStrTable().GetStrIdxFromName(baseName); + if (typeNameIdx == 0) { + newType = std::make_unique(PTY_ref, baseName, dim8); + } else { + newType = std::make_unique(PTY_ref, typeNameIdx, dim8); + } + } else { + CHECK_FATAL(false, "unsupported java type name %s: ", typeName.c_str()); + return nullptr; + } + if (usePtr) { + return FEIRTypeHelper::CreatePointerType(std::move(newType), PTY_ref); + } else { + return newType; + } +} + +UniqueFEIRType FEIRTypeHelper::CreatePointerType(UniqueFEIRType baseType, PrimType primType) { + UniqueFEIRType newType = std::make_unique(std::move(baseType), primType); + return newType; +} + +UniqueFEIRType FEIRTypeHelper::CreateTypeByJavaNamePrim(char primTypeFlag, uint8 dim8) { + PrimType primType = PTY_unknown; + switch (primTypeFlag) { + case 'I': + primType = PTY_i32; + break; + case 'J': + primType = PTY_i64; + break; + case 'F': + primType = PTY_f32; + break; + case 'D': + primType = PTY_f64; + break; + case 'Z': + primType = PTY_u1; + break; + case 'B': + primType = PTY_i8; + break; + case 'S': + primType = PTY_i16; + break; + case 'C': + primType = PTY_u16; + break; + case 'V': + primType = PTY_void; + break; + default: + return nullptr; + } + return std::make_unique(primType, GStrIdx(0), dim8); +} + +UniqueFEIRType FEIRTypeHelper::CreateTypeByDimIncr(const UniqueFEIRType &srcType, uint8 delta, bool usePtr, + PrimType primType) { + UniqueFEIRType type = srcType->Clone(); + (void)type->ArrayIncrDim(delta); + if (!usePtr || type->GetKind() == FEIRTypeKind::kFEIRTypePointer) { + return type; + } else { + return CreatePointerType(std::move(type), primType); + } +} + +UniqueFEIRType FEIRTypeHelper::CreateTypeByDimDecr(const UniqueFEIRType &srcType, uint8 delta) { + UniqueFEIRType type = srcType->Clone(); + uint8 dim = type->ArrayDecrDim(delta); + if (srcType->GetKind() == FEIRTypeKind::kFEIRTypePointer && dim == 0 && IsPrimitiveScalar(type->GetPrimType())) { + const FEIRTypePointer *ptrType = static_cast(type.get()); + ASSERT(ptrType != nullptr, "nullptr check"); + return ptrType->GetBaseType()->Clone(); + } else { + return type; + } +} + +UniqueFEIRType FEIRTypeHelper::CreateTypeByGetAddress(const UniqueFEIRType &srcType, PrimType primType) { + UniqueFEIRType type = std::make_unique(srcType->Clone(), primType); + return type; +} + +UniqueFEIRType FEIRTypeHelper::CreateTypeByDereferrence(const UniqueFEIRType &srcType) { + CHECK_FATAL(srcType->GetKind() == FEIRTypeKind::kFEIRTypePointer, "input is not pointer type"); + const FEIRTypePointer *ptrSrcType = static_cast(srcType.get()); + ASSERT(ptrSrcType != nullptr, "nullptr check"); + return ptrSrcType->GetBaseType()->Clone(); +} + +UniqueFEIRType FEIRTypeHelper::CreateTypeDefault(PrimType primType, const GStrIdx &typeNameIdx, TypeDim dim) { + UniqueFEIRType type = std::make_unique(primType, typeNameIdx, dim); + CHECK_FATAL(type->IsValid(), "invalid type"); + return type; +} + +UniqueFEIRType FEIRTypeHelper::CreateTypeNative(MIRType &mirType) { + UniqueFEIRType type = std::make_unique(mirType); + CHECK_FATAL(type->IsValid(), "invalid type"); + return type; +} +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/common/src/feir_type_infer.cpp b/src/hir2mpl/common/src/feir_type_infer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8fb89a50fccdf2d0b2ee25c6bebea344b39cc023 --- /dev/null +++ b/src/hir2mpl/common/src/feir_type_infer.cpp @@ -0,0 +1,299 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "feir_type_infer.h" +#include "fe_type_hierarchy.h" +#include "feir_type_helper.h" +#include "feir_var_type_scatter.h" +#include "feir_dfg.h" + +namespace maple { +// ---------- FEIRTypeMergeHelper ---------- +FEIRTypeMergeHelper::FEIRTypeMergeHelper() + : firstType(true) {} + +FEIRTypeMergeHelper::FEIRTypeMergeHelper(const UniqueFEIRType &argTypeDefault) + : firstType(true) { + CHECK_FATAL(argTypeDefault.get() != nullptr, "nullptr check"); + ResetTypeDefault(argTypeDefault); +} + +void FEIRTypeMergeHelper::Reset() { + firstType = true; + type.reset(); + error = ""; +} + +void FEIRTypeMergeHelper::ResetTypeDefault(const UniqueFEIRType &argTypeDefault) { + typeDefault = argTypeDefault->Clone(); +} + +bool FEIRTypeMergeHelper::MergeType(const UniqueFEIRType &argType, bool parent) { + if (firstType) { + type = argType->Clone(); + firstType = false; + return true; + } + return MergeType(type, argType, parent); +} + +UniqueFEIRType FEIRTypeMergeHelper::GetResult() const { + return type->Clone(); +} + +void FEIRTypeMergeHelper::SetDefaultType(UniqueFEIRType &typeDst) { + SetType(typeDst, typeDefault); +} + +void FEIRTypeMergeHelper::SetType(UniqueFEIRType &typeDst, const UniqueFEIRType &typeSrc) { + ASSERT(typeDst.get() != nullptr, "nullptr check for type dst"); + ASSERT(typeSrc.get() != nullptr, "nullptr check for type src"); + if (typeDst.get()->GetKind() == typeSrc.get()->GetKind()) { + typeDst.get()->CopyFrom(*(typeSrc.get())); + } else { + typeDst = typeSrc->Clone(); + } +} + +bool FEIRTypeMergeHelper::MergeType(UniqueFEIRType &typeDst, const UniqueFEIRType &typeSrc, bool parent) { + ASSERT(typeDst.get() != nullptr, "nullptr check for type dst"); + ASSERT(typeSrc.get() != nullptr, "nullptr check for type src"); + ASSERT(typeDefault.get() != nullptr, "nullptr check for type default"); + FEIRTypeKind kindDst = typeDst.get()->GetKind(); + FEIRTypeKind kindSrc = typeSrc.get()->GetKind(); + // boundary: equal + if (typeDst->IsEqualTo(typeSrc)) { + return true; + } + // boundary: zero + if (typeSrc->IsZero()) { + return true; + } + if (typeDst->IsZero()) { + SetType(typeDst, typeSrc); + return true; + } + if (kindDst == FEIRTypeKind::kFEIRTypePointer && kindSrc == FEIRTypeKind::kFEIRTypePointer) { + FEIRTypePointer *ptrTypeDst = static_cast(typeDst.get()); + FEIRTypePointer *ptrTypeSrc = static_cast(typeSrc.get()); + UniqueFEIRType mergedType = ptrTypeDst->Clone(); + bool success = MergeType(mergedType, ptrTypeSrc->GetBaseType(), parent); + if (success) { + ptrTypeDst->SetBaseType(std::move(mergedType)); + } + return success; + } + if (kindDst == FEIRTypeKind::kFEIRTypePointer && kindSrc != FEIRTypeKind::kFEIRTypePointer) { + return false; + } + if (kindDst != FEIRTypeKind::kFEIRTypePointer && kindSrc == FEIRTypeKind::kFEIRTypePointer) { + return false; + } + // boundary: default + if (typeSrc->IsEqualTo(typeDefault)) { + if (parent) { + SetDefaultType(typeDst); + } + return true; + } + if (typeDst->IsEqualTo(typeDefault)) { + if (!parent) { + SetType(typeDst, typeSrc); + } + return true; + } + // hierarchy check + FEIRTypeDefault *ptrTypeDst = static_cast(typeDst.get()); + FEIRTypeDefault *ptrTypeSrc = static_cast(typeSrc.get()); + GStrIdx idxDst = ptrTypeDst->GetTypeNameIdx(); + GStrIdx idxSrc = ptrTypeSrc->GetTypeNameIdx(); + if (ptrTypeDst->GetDim() != ptrTypeSrc->GetDim()) { + return false; + } + if (ptrTypeDst->GetPrimType() != ptrTypeSrc->GetPrimType()) { + return false; + } + if (FETypeHierarchy::GetInstance().IsParentOf(idxDst, idxSrc)) { + // dst is parent of src + if (!parent) { + (void)ptrTypeDst->SetTypeNameIdx(idxSrc); + } + } else if (FETypeHierarchy::GetInstance().IsParentOf(idxSrc, idxDst)) { + // src is parent of dst + if (parent) { + (void)ptrTypeDst->SetTypeNameIdx(idxSrc); + } + } else { + if (parent) { + SetDefaultType(typeDst); + } else { + return false; + } + } + return true; +} + +// ---------- FEIRTypeInfer ---------- +FEIRTypeInfer::FEIRTypeInfer(MIRSrcLang argSrcLang, const FEIRDefUseChain &argMapDefUse) + : srcLang(argSrcLang), + mapDefUse(argMapDefUse) { + LoadTypeDefault(); +} + +void FEIRTypeInfer::LoadTypeDefault() { + switch (srcLang) { + case kSrcLangJava: + typeDefault = FEIRTypeHelper::CreateTypeByJavaName("Ljava/lang/Object;", false, false); + mergeHelper.ResetTypeDefault(typeDefault); + break; + default: + typeDefault.reset(); + break; + } +} + +void FEIRTypeInfer::Reset() { + visitVars.clear(); + withCircle = false; + first = true; +} + +UniqueFEIRType FEIRTypeInfer::GetTypeForVarUse(const UniqueFEIRVar &varUse) { + CHECK_NULL_FATAL(varUse); + if (varUse->GetType()->IsPrecise()) { + return varUse->GetType()->Clone(); + } + if (varUse->GetTrans().get() == nullptr) { + return typeDefault->Clone(); + } + if (visitVars.find(&varUse) != visitVars.end()) { + withCircle = true; + return UniqueFEIRType(); + } + CHECK_FATAL(visitVars.insert(&varUse).second, "visitVars insert failed"); + bool isFirst = first; + first = false; + UniqueFEIRType ans = GetTypeByTransForVarUse(varUse); + if ((isFirst || (!withCircle)) && ans != nullptr) { + varUse->SetType(ans->Clone()); + return ans->Clone(); + } else { + return UniqueFEIRType(); + } +} + +UniqueFEIRType FEIRTypeInfer::GetTypeForVarDef(UniqueFEIRVar &varDef) { + CHECK_NULL_FATAL(varDef); + if (varDef->GetType()->IsPreciseRefType()) { + return varDef->GetType()->Clone(); + } + if (varDef->GetType()->IsZero()) { + return UniqueFEIRType(); + } + if (visitVars.find(&varDef) != visitVars.end()) { + withCircle = true; + return UniqueFEIRType(); + } + CHECK_FATAL(visitVars.insert(&varDef).second, "visitVars insert failed"); + auto it = mapDefUse.find(&varDef); + CHECK_FATAL(it != mapDefUse.end(), "use not found"); + std::unordered_set useTypes; + for (const UniqueFEIRVar *use : it->second) { + CHECK_NULL_FATAL(use); + UniqueFEIRType useType = GetTypeForVarUse(*use); + if (useType != nullptr && (!useType->IsEqualTo(varDef->GetType()))) { + FEIRTypeKey key(useType); + if (useTypes.find(key) == useTypes.end()) { + CHECK_FATAL(useTypes.insert(key).second, "useTypes insert failed"); + } + } + } + if (useTypes.size() > 0) { + FEIRTypeMergeHelper mh(typeDefault); + for (const FEIRTypeKey &typeKey : useTypes) { + UniqueFEIRType defType = typeKey.GetType()->Clone(); + bool success = mh.MergeType(defType, false); + CHECK_FATAL(success, "merge type error"); + } + return mh.GetTypeClone(); + } else { + return UniqueFEIRType(); + } +} + +void FEIRTypeInfer::ProcessVarDef(UniqueFEIRVar &varDef) { + CHECK_NULL_FATAL(varDef); + auto it = mapDefUse.find(&varDef); + if (it == mapDefUse.end()) { + return; + } + std::unordered_set useTypes; + for (const UniqueFEIRVar *use : it->second) { + CHECK_NULL_FATAL(use); + UniqueFEIRType useType = GetTypeForVarUse(*use); + if (useType != nullptr && (!useType->IsEqualTo(varDef->GetType()))) { + FEIRTypeKey key(useType); + if (useTypes.find(key) == useTypes.end()) { + CHECK_FATAL(useTypes.insert(key).second, "useTypes insert failed"); + } + } + } + if (useTypes.size() == 1 && !(varDef->GetType()->IsPrecise())) { + varDef->SetType((*(useTypes.begin())).GetType()->Clone()); + return; + } + if (useTypes.size() > 0) { + std::unique_ptr varNew = + std::make_unique(static_cast(varDef->Clone())); + FEIRVarTypeScatter *ptrVarNew = varNew.get(); + ptrVarNew->SetType(varDef->GetType()->Clone()); + for (const FEIRTypeKey &typeKey : useTypes) { + ptrVarNew->AddScatterType(typeKey.GetType()); + } + varDef.reset(varNew.release()); + } +} + +UniqueFEIRType FEIRTypeInfer::GetTypeByTransForVarUse(const UniqueFEIRVar &varUse) { + CHECK_NULL_FATAL(varUse); + FEIRVarTrans *ptrVarUseTrans = varUse->GetTrans().get(); + CHECK_NULL_FATAL(ptrVarUseTrans); + UniqueFEIRVar &varDef = ptrVarUseTrans->GetVar(); + CHECK_NULL_FATAL(varDef); + UniqueFEIRType defType = GetTypeForVarDef(varDef); + if (defType != nullptr) { + return ptrVarUseTrans->GetType(defType); + } else { + return defType; + } +} + +Opcode FEIRTypeCvtHelper::ChooseCvtOpcodeByFromTypeAndToType(const FEIRType &fromType, const FEIRType &toType) { + if (IsRetypeable(fromType, toType)) { + return OP_retype; + } else if (IsIntCvt2Ref(fromType, toType)) { + return OP_cvt; + } else { + return OP_undef; + } +} + +bool FEIRTypeCvtHelper::IsRetypeable(const FEIRType &fromType, const FEIRType &toType) { + return (fromType.GetPrimType() == toType.GetPrimType()); +} + +bool FEIRTypeCvtHelper::IsIntCvt2Ref(const FEIRType &fromType, const FEIRType &toType) { + return (IsPrimitiveInteger(fromType.GetPrimType()) && toType.IsPreciseRefType()); +} +} // namespace maple diff --git a/src/hir2mpl/common/src/feir_var.cpp b/src/hir2mpl/common/src/feir_var.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd26cc9bd52a112f96ac39fcc2892fb79e830806 --- /dev/null +++ b/src/hir2mpl/common/src/feir_var.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "feir_var.h" +#include "feir_stmt.h" +#include "global_tables.h" +#include "feir_type_helper.h" +#include "fe_config_parallel.h" +#include "enhance_c_checker.h" + +namespace maple { +// ---------- FEIRVarTrans ---------- +FEIRVarTrans::FEIRVarTrans(FEIRVarTransKind argKind, std::unique_ptr &argVar) + : kind(argKind), var(argVar) { + param.dimDelta = 0; + switch (kind) { + case kFEIRVarTransArrayDimIncr: + case kFEIRVarTransArrayDimDecr: + param.dimDelta = 1; + break; + default: + break; + } +} + +FEIRVarTrans::FEIRVarTrans(FEIRVarTransKind argKind, std::unique_ptr &argVar, uint8 dimDelta) + : kind(argKind), var(argVar) { + param.dimDelta = 0; + switch (kind) { + case kFEIRVarTransArrayDimIncr: + case kFEIRVarTransArrayDimDecr: + param.dimDelta = dimDelta; + break; + default: + break; + } +} + +UniqueFEIRType FEIRVarTrans::GetType(const UniqueFEIRType &type, PrimType primType, bool usePtr) { + ASSERT(type != nullptr, "nullptr check"); + UniqueFEIRType typeNew = type->Clone(); + switch (kind) { + case kFEIRVarTransDirect: + break; + case kFEIRVarTransArrayDimIncr: { + (void)typeNew->ArrayIncrDim(param.dimDelta); + if (typeNew->GetKind() != FEIRTypeKind::kFEIRTypePointer && usePtr) { + return FEIRTypeHelper::CreatePointerType(typeNew->Clone(), primType); + } else { + return typeNew; + } + } + case kFEIRVarTransArrayDimDecr: { + (void)typeNew->ArrayDecrDim(param.dimDelta); + if (typeNew->GetKind() == FEIRTypeKind::kFEIRTypePointer) { + FEIRTypePointer *ptrTypeNew = static_cast(typeNew.get()); + ASSERT(ptrTypeNew->GetBaseType() != nullptr, "nullptr check"); + if (ptrTypeNew->GetBaseType()->IsScalar()) { + return ptrTypeNew->GetBaseType()->Clone(); + } + } else if (usePtr && !typeNew->IsScalar()) { + return FEIRTypeHelper::CreatePointerType(typeNew->Clone(), primType); + } else { + return typeNew; + } + break; + } + default: + CHECK_FATAL(false, "unsupported trans kind"); + } + return typeNew; +} + +// ---------- FEIRVar ---------- +FEIRVar::FEIRVar(FEIRVarKind argKind) + : kind(argKind), + isGlobal(false), + isDef(false), + type(std::make_unique()) { + boundaryLenExpr = nullptr; +} + +FEIRVar::FEIRVar(FEIRVarKind argKind, std::unique_ptr argType) + : FEIRVar(argKind) { + boundaryLenExpr = nullptr; + SetType(std::move(argType)); +} + +FEIRVar::~FEIRVar() {} + +void FEIRVar::SetBoundaryLenExpr(std::unique_ptr expr) { + boundaryLenExpr = std::move(expr); +} + +const std::unique_ptr &FEIRVar::GetBoundaryLenExpr() const { + return boundaryLenExpr; +} + +MIRSymbol *FEIRVar::GenerateGlobalMIRSymbolImpl(MIRBuilder &builder) const { + HIR2MPL_PARALLEL_FORBIDDEN(); + MIRType *mirType = type->GenerateMIRTypeAuto(); + std::string name = GetName(*mirType); + GStrIdx nameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + MIRSymbol *gSymbol = builder.GetOrCreateGlobalDecl(name, *mirType); + auto attrs = const_cast(genAttrs).ConvertToTypeAttrs(); + ENCChecker::InsertBoundaryLenExprInAtts(attrs, boundaryLenExpr); + // do not allow extern var override global var + if (gSymbol->GetAttrs().GetAttrFlag() != 0 && attrs.GetAttr(ATTR_extern)) { + return gSymbol; + } + // Set global var attr once + std::size_t pos = name.find("_7C"); + if (pos != std::string::npos) { + std::string containerName = name.substr(0, pos); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(containerName); + TyIdx containerTypeIdx = GlobalTables::GetTypeNameTable().GetTyIdxFromGStrIdx(strIdx); + if (containerTypeIdx != TyIdx(0)) { + MIRType *containerType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(containerTypeIdx); + if (containerType->IsStructType()) { + // for external class + MIRStructType *mirContainer = static_cast(containerType); + if (!mirContainer->IsLocal()) { + gSymbol->SetStorageClass(kScExtern); + } + // for not defined field use + if (gSymbol->GetAttrs().GetAttrFlag() == 0) { + auto t = TypeAttrs(); + t.SetAttr(ATTR_static); + gSymbol->AddAttrs(t); + } + for (auto field : mirContainer->GetStaticFields()) { + if (field.first == nameIdx) { + gSymbol->AddAttrs(field.second.second.ConvertToTypeAttrs()); + } + } + } + } + } + if (attrs.GetAttr(ATTR_extern)) { + gSymbol->SetStorageClass(MIRStorageClass::kScExtern); + attrs.ResetAttr(AttrKind::ATTR_extern); + } else { + if (gSymbol->GetStorageClass() == MIRStorageClass::kScInvalid) { + gSymbol->SetStorageClass(MIRStorageClass::kScGlobal); + } + } + return gSymbol; +} + +MIRSymbol *FEIRVar::GenerateLocalMIRSymbolImpl(MIRBuilder &builder) const { + HIR2MPL_PARALLEL_FORBIDDEN(); + MIRType *mirType = type->GenerateMIRTypeAuto(); + std::string name = GetName(*mirType); + MIRSymbol *mirSymbol = builder.GetOrCreateLocalDecl(name, *mirType); + auto attrs = const_cast(genAttrs).ConvertToTypeAttrs(); + ENCChecker::InsertBoundaryLenExprInAtts(attrs, boundaryLenExpr); + if (attrs.GetAttr(ATTR_static)) { + attrs.ResetAttr(ATTR_static); + mirSymbol->SetStorageClass(MIRStorageClass::kScPstatic); + } + mirSymbol->AddAttrs(attrs); + return mirSymbol; +} + +MIRSymbol *FEIRVar::GenerateMIRSymbolImpl(MIRBuilder &builder) const { + if (isGlobal) { + return GenerateGlobalMIRSymbol(builder); + } else { + return GenerateLocalMIRSymbol(builder); + } +} + +void FEIRVar::SetType(std::unique_ptr argType) { + CHECK_FATAL(argType != nullptr, "input type is nullptr"); + type = std::move(argType); +} +} // namespace maple diff --git a/src/hir2mpl/common/src/feir_var_name.cpp b/src/hir2mpl/common/src/feir_var_name.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6bbbef253e791e53512bcfeb02e8293a1055a39 --- /dev/null +++ b/src/hir2mpl/common/src/feir_var_name.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "feir_var_name.h" +#include "feir_stmt.h" + +namespace maple { +// ---------- FEIRVarName ---------- +std::string FEIRVarName::GetNameImpl(const MIRType &mirType) const { + std::stringstream ss; + ASSERT(nameIdx.GetIdx() != 0, "invalid name idx"); + std::string name = GlobalTables::GetStrTable().GetStringFromStrIdx(nameIdx); + ss << name; + if (withType) { + ss << "_"; + if (type->IsScalar()) { + ss << GetPrimTypeName(type->GetPrimType()); + } else { + ss << "R" << mirType.GetTypeIndex().GetIdx(); + } + } + return ss.str(); +} + +std::string FEIRVarName::GetNameRawImpl() const { + return GlobalTables::GetStrTable().GetStringFromStrIdx(nameIdx); +} + +std::unique_ptr FEIRVarName::CloneImpl() const { + std::unique_ptr var = std::make_unique(nameIdx, type->Clone(), withType); + var->SetGlobal(isGlobal); + GenericAttrs attrs = genAttrs; + var->SetAttrs(attrs); + if (boundaryLenExpr != nullptr) { + var->SetBoundaryLenExpr(boundaryLenExpr->Clone()); + } + return var; +} + +bool FEIRVarName::EqualsToImpl(const std::unique_ptr &var) const { + if (var->GetKind() != kind) { + return false; + } + FEIRVarName *ptrVarName = static_cast(var.get()); + ASSERT(ptrVarName != nullptr, "ptr var is nullptr"); + return ptrVarName->nameIdx == nameIdx && GetType()->IsEqualTo(ptrVarName->GetType()); +} + +uint32 FEIRVarName::HashImpl() const { + return static_cast(std::hash{}(nameIdx)); +} +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/common/src/feir_var_reg.cpp b/src/hir2mpl/common/src/feir_var_reg.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42f937f1aaae6f65f79b0329c8ce880c6c60417d --- /dev/null +++ b/src/hir2mpl/common/src/feir_var_reg.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "feir_var_reg.h" +#include "fe_options.h" +#include +#include +#include "mir_type.h" + +namespace maple { +std::string FEIRVarReg::GetNameImpl(const MIRType &mirType) const { + thread_local static std::stringstream ss(""); + ss.str(""); + ss << "Reg"; + ss << regNum; + ss << "_"; + if (type->IsPreciseRefType()) { + ss << "R" << mirType.GetTypeIndex().GetIdx(); + } else { + if (type->GetSrcLang() == kSrcLangJava) { + ss << GetPrimTypeJavaName(type->GetPrimType()); + } else { + ss << GetPrimTypeName(type->GetPrimType()); + } + } + return ss.str(); +} + +std::string FEIRVarReg::GetNameRawImpl() const { + thread_local static std::stringstream ss(""); + ss.str(""); + ss << "Reg" << regNum; + return ss.str(); +} + +MIRSymbol *FEIRVarReg::GenerateLocalMIRSymbolImpl(MIRBuilder &builder) const { + HIR2MPL_PARALLEL_FORBIDDEN(); + MIRType *mirType = type->GenerateMIRTypeAuto(); + std::string name = GetName(*mirType); + MIRSymbol *ret = builder.GetOrCreateLocalDecl(name, *mirType); + return ret; +} + +std::unique_ptr FEIRVarReg::CloneImpl() const { + std::unique_ptr var = std::make_unique(regNum, type->Clone()); + return var; +} + +bool FEIRVarReg::EqualsToImpl(const std::unique_ptr &var) const { + if (var->GetKind() != kind) { + return false; + } + FEIRVarReg *ptrVarReg = static_cast(var.get()); + ASSERT(ptrVarReg != nullptr, "ptr var is nullptr"); + return ptrVarReg->regNum == regNum; +} + +uint32 FEIRVarReg::HashImpl() const { + return static_cast(std::hash{}(regNum)); +} + +// ========== FEIRVarAccumulator ========== +std::string FEIRVarAccumulator::GetNameImpl(const MIRType &mirType) const { + thread_local static std::stringstream ss(""); + ss.str(""); + ss << "Reg"; + ss << "_Accumulator"; + ss << "_"; + if (type->IsPreciseRefType()) { + ss << "R" << mirType.GetTypeIndex().GetIdx(); + } else { + if (type->GetSrcLang() == kSrcLangJava) { + ss << GetPrimTypeJavaName(type->GetPrimType()); + } else { + ss << GetPrimTypeName(type->GetPrimType()); + } + } + return ss.str(); +} + +std::string FEIRVarAccumulator::GetNameRawImpl() const { + thread_local static std::stringstream ss(""); + ss.str(""); + ss << "Reg_Accumulator"; + return ss.str(); +} + +std::unique_ptr FEIRVarAccumulator::CloneImpl() const { + std::unique_ptr var = std::make_unique(regNum, type->Clone()); + return var; +} +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/common/src/feir_var_type_scatter.cpp b/src/hir2mpl/common/src/feir_var_type_scatter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad4d77ab4830033d5011624a945f62069a7619fa --- /dev/null +++ b/src/hir2mpl/common/src/feir_var_type_scatter.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "feir_var_type_scatter.h" + +namespace maple { +FEIRVarTypeScatter::FEIRVarTypeScatter(UniqueFEIRVar argVar) + : FEIRVar(FEIRVarKind::kFEIRVarTypeScatter) { + ASSERT(argVar != nullptr, "nullptr check"); + ASSERT(argVar->GetKind() != FEIRVarKind::kFEIRVarTypeScatter, "invalid input var type"); + var = std::move(argVar); +} + +void FEIRVarTypeScatter::AddScatterType(const UniqueFEIRType &type) { + if (var->GetType()->IsEqualTo(type)) { + return; + } + FEIRTypeKey key(type); + if (scatterTypes.find(key) == scatterTypes.end()) { + CHECK_FATAL(scatterTypes.insert(key).second, "scatterTypes insert failed"); + } +} + +std::string FEIRVarTypeScatter::GetNameImpl(const MIRType &mirType) const { + return var->GetName(mirType); +} + +std::string FEIRVarTypeScatter::GetNameRawImpl() const { + return var->GetNameRaw(); +} + +std::unique_ptr FEIRVarTypeScatter::CloneImpl() const { + std::unique_ptr ans = std::make_unique(var->Clone()); + FEIRVarTypeScatter *ptrAns = static_cast(ans.get()); + ASSERT(ptrAns != nullptr, "nullptr check"); + for (const FEIRTypeKey &key : scatterTypes) { + ptrAns->AddScatterType(key.GetType()); + } + return std::unique_ptr(ans.release()); +} + +bool FEIRVarTypeScatter::EqualsToImpl(const std::unique_ptr &argVar) const { + return false; +} + +uint32 FEIRVarTypeScatter::HashImpl() const { + return 0; +} + +MIRSymbol *FEIRVarTypeScatter::GenerateGlobalMIRSymbolImpl(MIRBuilder &builder) const { + HIR2MPL_PARALLEL_FORBIDDEN(); + MIRType *mirType = var->GetType()->GenerateMIRTypeAuto(); + std::string name = GetName(*mirType); + return builder.GetOrCreateGlobalDecl(name, *mirType); +} + +MIRSymbol *FEIRVarTypeScatter::GenerateLocalMIRSymbolImpl(MIRBuilder &builder) const { + HIR2MPL_PARALLEL_FORBIDDEN(); + MIRType *mirType = var->GetType()->GenerateMIRTypeAuto(); + std::string name = GetName(*mirType); + return builder.GetOrCreateLocalDecl(name, *mirType); +} + +MIRSymbol *FEIRVarTypeScatter::GenerateMIRSymbolImpl(MIRBuilder &builder) const { + if (isGlobal) { + return GenerateGlobalMIRSymbol(builder); + } else { + return GenerateLocalMIRSymbol(builder); + } +} +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/common/src/generic_attrs.cpp b/src/hir2mpl/common/src/generic_attrs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b516283f9c2f0d111dbc3a7cd52f5adee60c350b --- /dev/null +++ b/src/hir2mpl/common/src/generic_attrs.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "generic_attrs.h" +#include "global_tables.h" + +namespace maple { +TypeAttrs GenericAttrs::ConvertToTypeAttrs() { + TypeAttrs attr; + constexpr uint32 maxAttrNum = 128; + for (uint32 i = 0; i < maxAttrNum; ++i) { + if (attrFlag[i] == 0) { + continue; + } + auto tA = static_cast(i); + switch (tA) { +#define TYPE_ATTR +#define ATTR(STR) \ + case GENATTR_##STR: \ + attr.SetAttr(ATTR_##STR); \ + break; +#include "all_attributes.def" +#undef ATTR +#undef TYPE_ATTR + default: + ASSERT(false, "unknown TypeAttrs"); + break; + } + } + for(auto iter = contentMap.begin(); iter != contentMap.end(); ++iter) { + if (iter->first == GENATTR_pack) { + attr.SetPack(static_cast(std::get(iter->second))); + } + } + return attr; +} + +FuncAttrs GenericAttrs::ConvertToFuncAttrs() { + FuncAttrs attr; + constexpr uint32 maxAttrNum = 128; + for (uint32 i = 0; i < maxAttrNum; ++i) { + if (attrFlag[i] == 0) { + continue; + } + auto tA = static_cast(i); + switch (tA) { +#define FUNC_ATTR +#define ATTR(STR) \ + case GENATTR_##STR: \ + attr.SetAttr(FUNCATTR_##STR); \ + break; +#include "all_attributes.def" +#undef ATTR +#undef FUNC_ATTR + default: + ASSERT(false, "unknown FuncAttrs"); + break; + } + } + for(auto iter = contentMap.begin(); iter != contentMap.end(); ++iter) { + if (iter->first == GENATTR_alias) { + std::string name = GlobalTables::GetStrTable().GetStringFromStrIdx(std::get(iter->second)); + attr.SetAliasFuncName(name); + } + if (iter->first == GENATTR_constructor_priority) { + attr.SetConstructorPriority(std::get(iter->second)); + } + if (iter->first == GENATTR_destructor_priority) { + attr.SetDestructorPriority(std::get(iter->second)); + } + } + return attr; +} + +FieldAttrs GenericAttrs::ConvertToFieldAttrs() { + FieldAttrs attr; + constexpr uint32 maxAttrNum = 128; + for (uint32 i = 0; i < maxAttrNum; ++i) { + if (attrFlag[i] == 0) { + continue; + } + auto tA = static_cast(i); + switch (tA) { +#define FIELD_ATTR +#define ATTR(STR) \ + case GENATTR_##STR: \ + attr.SetAttr(FLDATTR_##STR); \ + break; +#include "all_attributes.def" +#undef ATTR +#undef FIELD_ATTR + default: + ASSERT(false, "unknown FieldAttrs"); + break; + } + } + return attr; +} +} diff --git a/src/hir2mpl/common/src/hir2mpl.cpp b/src/hir2mpl/common/src/hir2mpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e72b42aff7d9c6405fee6861f32ddb1d8f10c979 --- /dev/null +++ b/src/hir2mpl/common/src/hir2mpl.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "hir2mpl_compiler.h" +#include "fe_utils.h" +using namespace maple; + +int main(int argc, char **argv) { + MPLTimer timer; + timer.Start(); + HIR2MPLOptions &options = HIR2MPLOptions::GetInstance(); + if (options.SolveArgs(argc, argv) == false) { + return static_cast(FEErrno::kCmdParseError); + } + HIR2MPLEnv::GetInstance().Init(); + MIRModule module; + HIR2MPLCompiler compiler(module); + int res = compiler.Run(); + // The MIRModule destructor does not release the pragma memory, add releasing for front-end debugging. + MemPool *pragmaMemPoolPtr = module.GetPragmaMemPool(); + FEUtils::DeleteMempoolPtr(pragmaMemPoolPtr); + timer.Stop(); + if (FEOptions::GetInstance().IsDumpTime()) { + INFO(kLncInfo, "hir2mpl time: %.2lfms", timer.ElapsedMilliseconds() / 1.0); + } + return res; +} diff --git a/src/hir2mpl/common/src/hir2mpl_compiler.cpp b/src/hir2mpl/common/src/hir2mpl_compiler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f586f2a2b24f8c7d0bf160b1fc6b7c454d0a4ca9 --- /dev/null +++ b/src/hir2mpl/common/src/hir2mpl_compiler.cpp @@ -0,0 +1,360 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "hir2mpl_compiler.h" +#include +#include "fe_manager.h" +#include "fe_file_type.h" +#include "fe_timer.h" +#include "rc_setter.h" + +namespace maple { +HIR2MPLCompiler::HIR2MPLCompiler(MIRModule &argModule) + : module(argModule), + srcLang(kSrcLangJava), + mp(FEUtils::NewMempool("MemPool for HIR2MPLCompiler", false /* isLcalPool */)), + allocator(mp) {} + +HIR2MPLCompiler::~HIR2MPLCompiler() { + mp = nullptr; +} + +void HIR2MPLCompiler::Init() { + FEManager::Init(module); + module.SetFlavor(maple::kFeProduced); + module.GetImportFiles().clear(); + if (FEOptions::GetInstance().IsRC()) { + bc::RCSetter::InitRCSetter(""); + } +} + +void HIR2MPLCompiler::Release() { + FEManager::Release(); + FEUtils::DeleteMempoolPtr(mp); +} + +int HIR2MPLCompiler::Run() { + bool success = true; + Init(); + CheckInput(); + RegisterCompilerComponent(); + success = success && LoadMplt(); + SetupOutputPathAndName(); + ParseInputs(); + if (!FEOptions::GetInstance().GetXBootClassPath().empty()) { + LoadOnDemandTypes(); + } + PreProcessDecls(); + ProcessDecls(); + ProcessPragmas(); + if (!FEOptions::GetInstance().IsGenMpltOnly()) { + FETypeHierarchy::GetInstance().InitByGlobalTable(); + ProcessFunctions(); + if (FEOptions::GetInstance().IsRC()) { + bc::RCSetter::GetRCSetter().MarkRCAttributes(); + } + } + bc::RCSetter::ReleaseRCSetter(); + FEManager::GetManager().ReleaseStructElemMempool(); + CHECK_FATAL(success, "Compile Error"); + ExportMpltFile(); + ExportMplFile(); + int res = FEManager::GetDiagManager().GetDiagRes(); + HIR2MPLEnv::GetInstance().Finish(); + Release(); + return res; +} + +void HIR2MPLCompiler::CheckInput() { + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process HIR2MPLCompiler::CheckInput() ====="); + size_t nInput = 0; + + // check input class files + const std::list &inputClassNames = FEOptions::GetInstance().GetInputClassFiles(); + if (!inputClassNames.empty()) { + nInput += inputClassNames.size(); + if (firstInputName.empty()) { + firstInputName = inputClassNames.front(); + } + } + + // check input jar files + const std::list &inputJarNames = FEOptions::GetInstance().GetInputJarFiles(); + if (!inputJarNames.empty()) { + nInput += inputJarNames.size(); + if (firstInputName.empty()) { + firstInputName = inputJarNames.front(); + } + } + + // check input dex files + const std::vector &inputDexNames = FEOptions::GetInstance().GetInputDexFiles(); + if (!inputDexNames.empty()) { + nInput += inputDexNames.size(); + if (firstInputName.empty()) { + firstInputName = inputDexNames[0]; + } + } + + // check input ast files + const std::vector &inputASTNames = FEOptions::GetInstance().GetInputASTFiles(); + if (!inputASTNames.empty()) { + nInput += inputASTNames.size(); + if (firstInputName.empty()) { + firstInputName = inputASTNames[0]; + } + } + + // check input mast files + const std::vector &inputMASTNames = FEOptions::GetInstance().GetInputMASTFiles(); + if (!inputMASTNames.empty()) { + nInput += inputMASTNames.size(); + if (firstInputName.empty()) { + firstInputName = inputMASTNames[0]; + } + } + + CHECK_FATAL(nInput > 0, "Error occurs: no inputs. exit."); +} + +void HIR2MPLCompiler::SetupOutputPathAndName() { + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process HIR2MPLCompiler::SetupOutputPathAndName() ====="); + // get outputName from option + const std::string &outputName0 = FEOptions::GetInstance().GetOutputName(); + if (!outputName0.empty()) { + outputName = outputName0; + } else { + // use default + outputName = FEFileType::GetName(firstInputName, true); + outputPath = FEFileType::GetPath(firstInputName); + } + const std::string &outputPath0 = FEOptions::GetInstance().GetOutputPath(); + if (!outputPath0.empty()) { + outputPath = outputPath0[outputPath0.size() - 1] == '/' ? outputPath0 : (outputPath0 + "/"); + } + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "OutputPath: %s", outputPath.c_str()); + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "OutputName: %s", outputName.c_str()); + std::string outName = ""; + if (outputPath.empty()) { + outName = outputName; + } else { + outName = outputPath + outputName; + } + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "OutputFullName: %s", outName.c_str()); + module.SetFileName(outName); + // mapleall need outName with type, but mplt file no need + size_t lastDot = outName.find_last_of("."); + if (lastDot == std::string::npos) { + outNameWithoutType = outName; + } else { + outNameWithoutType = outName.substr(0, lastDot); + } + std::string mpltName = outNameWithoutType + ".mplt"; + if (srcLang != kSrcLangC) { + GStrIdx strIdx = module.GetMIRBuilder()->GetOrCreateStringIndex(mpltName); + module.GetImportFiles().push_back(strIdx); + } +} + +inline void HIR2MPLCompiler::InsertImportInMpl(const std::list &mplt) const { + for (const std::string &fileName : mplt) { + GStrIdx strIdx = module.GetMIRBuilder()->GetOrCreateStringIndex(fileName); + module.GetImportFiles().push_back(strIdx); + } +} + +bool HIR2MPLCompiler::LoadMplt() { + bool success = true; + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process HIR2MPLCompiler::LoadMplt() ====="); + // load mplt from sys + const std::list &mpltsFromSys = FEOptions::GetInstance().GetInputMpltFilesFromSys(); + success = success && FEManager::GetTypeManager().LoadMplts(mpltsFromSys, FETypeFlag::kSrcMpltSys, + "Load mplt from sys"); + InsertImportInMpl(mpltsFromSys); + // load mplt + const std::list &mplts = FEOptions::GetInstance().GetInputMpltFiles(); + success = success && FEManager::GetTypeManager().LoadMplts(mplts, FETypeFlag::kSrcMplt, "Load mplt"); + InsertImportInMpl(mplts); + // load mplt from apk + const std::list &mpltsFromApk = FEOptions::GetInstance().GetInputMpltFilesFromApk(); + success = success && FEManager::GetTypeManager().LoadMplts(mpltsFromApk, FETypeFlag::kSrcMpltApk, + "Load mplt from apk"); + InsertImportInMpl(mpltsFromApk); + return success; +} + +void HIR2MPLCompiler::ExportMpltFile() { + if (!FEOptions::GetInstance().IsNoMplFile() && srcLang != kSrcLangC) { + FETimer timer; + timer.StartAndDump("Output mplt"); + module.DumpToHeaderFile(!FEOptions::GetInstance().IsGenAsciiMplt()); + timer.StopAndDumpTimeMS("Output mplt"); + } +} + +void HIR2MPLCompiler::ExportMplFile() { + if (!FEOptions::GetInstance().IsNoMplFile() && !FEOptions::GetInstance().IsGenMpltOnly()) { + FETimer timer; + timer.StartAndDump("Output mpl"); + bool emitStructureType = false; + // Currently, struct types cannot be dumped to mplt. + // After mid-end interfaces are optimized, the judgment can be deleted. + if (srcLang == kSrcLangC) { + emitStructureType = true; + } + module.OutputAsciiMpl("", ".mpl", nullptr, emitStructureType, false); + if (FEOptions::GetInstance().GetFuncInlineSize() != 0 && !FEOptions::GetInstance().GetWPAA()) { + module.DumpInlineCandidateToFile(outNameWithoutType + ".mplt_inline"); + } + timer.StopAndDumpTimeMS("Output mpl"); + } +} + +void HIR2MPLCompiler::RegisterCompilerComponent(std::unique_ptr comp) { + CHECK_FATAL(comp != nullptr, "input compiler component is nullptr"); + components.push_back(std::move(comp)); +} + +void HIR2MPLCompiler::ParseInputs() { + FETimer timer; + timer.StartAndDump("HIR2MPLCompiler::ParseInputs()"); + for (const std::unique_ptr &comp : components) { + CHECK_NULL_FATAL(comp); + bool success = comp->ParseInput(); + CHECK_FATAL(success, "Error occurs in HIR2MPLCompiler::ParseInputs(). exit."); + } + timer.StopAndDumpTimeMS("HIR2MPLCompiler::ParseInputs()"); +} + +void HIR2MPLCompiler::LoadOnDemandTypes() { + FETimer timer; + timer.StartAndDump("HIR2MPLCompiler::LoadOnDemandTypes()"); + for (const std::unique_ptr &comp : components) { + CHECK_NULL_FATAL(comp); + bool success = comp->LoadOnDemandType(); + CHECK_FATAL(success, "Error occurs in HIR2MPLCompiler::LoadOnDemandTypes(). exit."); + } + timer.StopAndDumpTimeMS("HIR2MPLCompiler::LoadOnDemandTypes()"); +} + +void HIR2MPLCompiler::PreProcessDecls() { + FETimer timer; + timer.StartAndDump("HIR2MPLCompiler::PreProcessDecls()"); + for (const std::unique_ptr &comp : components) { + ASSERT(comp != nullptr, "nullptr check"); + bool success = comp->PreProcessDecl(); + CHECK_FATAL(success, "Error occurs in HIR2MPLCompiler::PreProcessDecls(). exit."); + } + timer.StopAndDumpTimeMS("HIR2MPLCompiler::PreProcessDecl()"); +} + +void HIR2MPLCompiler::ProcessDecls() { + FETimer timer; + timer.StartAndDump("HIR2MPLCompiler::ProcessDecl()"); + for (const std::unique_ptr &comp : components) { + ASSERT(comp != nullptr, "nullptr check"); + bool success = comp->ProcessDecl(); + CHECK_FATAL(success, "Error occurs in HIR2MPLCompiler::ProcessDecls(). exit."); + } + timer.StopAndDumpTimeMS("HIR2MPLCompiler::ProcessDecl()"); +} + +void HIR2MPLCompiler::ProcessPragmas() { + FETimer timer; + timer.StartAndDump("HIR2MPLCompiler::ProcessPragmas()"); + for (const std::unique_ptr &comp : components) { + ASSERT_NOT_NULL(comp); + comp->ProcessPragma(); + } + timer.StopAndDumpTimeMS("HIR2MPLCompiler::ProcessPragmas()"); +} + +void HIR2MPLCompiler::ProcessFunctions() { + FETimer timer; + bool success = true; + timer.StartAndDump("HIR2MPLCompiler::ProcessFunctions()"); + uint32 funcSize = 0; + for (const std::unique_ptr &comp : components) { + ASSERT(comp != nullptr, "nullptr check"); + success = comp->ProcessFunctionSerial() && success; + funcSize += comp->GetFunctionsSize(); + if (!success) { + const std::set &failedFEFunctions = comp->GetCompileFailedFEFunctions(); + compileFailedFEFunctions.insert(failedFEFunctions.begin(), failedFEFunctions.end()); + } + if (FEOptions::GetInstance().IsDumpPhaseTime()) { + comp->DumpPhaseTimeTotal(); + } + comp->ReleaseMemPool(); + } + FEManager::GetTypeManager().MarkExternStructType(); + module.SetNumFuncs(funcSize); + FindMinCompileFailedFEFunctions(); + timer.StopAndDumpTimeMS("HIR2MPLCompiler::ProcessFunctions()"); + CHECK_FATAL(success, "ProcessFunction error"); +} + +void HIR2MPLCompiler::RegisterCompilerComponent() { + if (FEOptions::GetInstance().HasJBC()) { + FEOptions::GetInstance().SetTypeInferKind(FEOptions::TypeInferKind::kNo); + std::unique_ptr jbcCompilerComp = std::make_unique(module); + RegisterCompilerComponent(std::move(jbcCompilerComp)); + } + if (FEOptions::GetInstance().GetInputDexFiles().size() != 0) { + bc::ArkAnnotationProcessor::Process(); + std::unique_ptr bcCompilerComp = + std::make_unique>(module); + RegisterCompilerComponent(std::move(bcCompilerComp)); + } + if (FEOptions::GetInstance().GetInputASTFiles().size() != 0) { + srcLang = kSrcLangC; + std::unique_ptr astCompilerComp = + std::make_unique>(module); + RegisterCompilerComponent(std::move(astCompilerComp)); + } +#ifdef ENABLE_MAST + if (FEOptions::GetInstance().GetInputMASTFiles().size() != 0) { + srcLang = kSrcLangC; + std::unique_ptr mapleAstCompilerComp = + std::make_unique>(module); + RegisterCompilerComponent(std::move(mapleAstCompilerComp)); + } +#endif + module.SetSrcLang(srcLang); + FEManager::GetTypeManager().SetSrcLang(srcLang); +} + +void HIR2MPLCompiler::FindMinCompileFailedFEFunctions() { + if (compileFailedFEFunctions.size() == 0) { + return; + } + FEFunction *minCompileFailedFEFunction = nullptr; + uint32 minFailedStmtCount = 0; + for (FEFunction *feFunc : compileFailedFEFunctions) { + if (minCompileFailedFEFunction == nullptr) { + minCompileFailedFEFunction = feFunc; + minFailedStmtCount = minCompileFailedFEFunction->GetStmtCount(); + } + uint32 stmtCount = feFunc->GetStmtCount(); + if (stmtCount < minFailedStmtCount) { + minCompileFailedFEFunction = feFunc; + minFailedStmtCount = stmtCount; + } + } + if (minCompileFailedFEFunction != nullptr) { + INFO(kLncWarn, "function compile failed!!! the min function is :"); + INFO(kLncWarn, minCompileFailedFEFunction->GetDescription().c_str()); + } +} +} // namespace maple diff --git a/src/hir2mpl/common/src/hir2mpl_compiler_component.cpp b/src/hir2mpl/common/src/hir2mpl_compiler_component.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6aa4e58f5c44a2ce9a6969575900b782f9b2e239 --- /dev/null +++ b/src/hir2mpl/common/src/hir2mpl_compiler_component.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "hir2mpl_compiler_component.h" +#include +#include "fe_macros.h" +#include "fe_timer.h" +#include "fe_config_parallel.h" +#include "fe_manager.h" + +namespace maple { +// ---------- FEFunctionProcessTask ---------- +FEFunctionProcessTask::FEFunctionProcessTask(std::unique_ptr argFunction) + : function(std::move(argFunction)) {} + +int FEFunctionProcessTask::RunImpl(MplTaskParam *param) { + bool success = function->Process(); + if (success) { + return 1; + } else { + return 0; + } +} + +int FEFunctionProcessTask::FinishImpl(MplTaskParam *param) { + function->Finish(); + return 0; +} + +// ---------- FEFunctionProcessSchedular ---------- +void FEFunctionProcessSchedular::AddFunctionProcessTask(std::unique_ptr function) { + std::unique_ptr task = std::make_unique(std::move(function)); + AddTask(*task.get()); + tasks.push_back(std::move(task)); +} + +void FEFunctionProcessSchedular::CallbackThreadMainStart() { + std::thread::id tid = std::this_thread::get_id(); + if (FEOptions::GetInstance().GetDumpLevel() >= FEOptions::kDumpLevelInfoDebug) { + INFO(kLncInfo, "Start Run Thread (tid=%lx)", tid); + } + FEConfigParallel::GetInstance().RegisterRunThreadID(tid); +} + +// ---------- HIR2MPLCompilerComponent ---------- +HIR2MPLCompilerComponent::HIR2MPLCompilerComponent(MIRModule &argModule, MIRSrcLang argSrcLang) + : funcSize(0), + module(argModule), + srcLang(argSrcLang), + phaseResultTotal(std::make_unique(true)) {} + +bool HIR2MPLCompilerComponent::LoadOnDemandTypeImpl() { + return false; +} + +bool HIR2MPLCompilerComponent::PreProcessDeclImpl() { + FETimer timer; + timer.StartAndDump("HIR2MPLCompilerComponent::PreProcessDecl()"); + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process HIR2MPLCompilerComponent::PreProcessDecl() ====="); + bool success = true; + FEManager::GetJavaStringManager().GenStringMetaClassVar(); + for (FEInputStructHelper *helper : structHelpers) { + ASSERT_NOT_NULL(helper); + success = helper->PreProcessDecl() ? success : false; + } + FEManager::GetTypeManager().InitMCCFunctions(); + timer.StopAndDumpTimeMS("HIR2MPLCompilerComponent::PreProcessDecl()"); + return success; +} + +bool HIR2MPLCompilerComponent::ProcessDeclImpl() { + FETimer timer; + timer.StartAndDump("HIR2MPLCompilerComponent::ProcessDecl()"); + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process HIR2MPLCompilerComponent::ProcessDecl() ====="); + bool success = true; + for (FEInputStructHelper *helper : structHelpers) { + ASSERT_NOT_NULL(helper); + success = helper->ProcessDecl() ? success : false; + } + for (FEInputMethodHelper *helper : globalFuncHelpers) { + ASSERT_NOT_NULL(helper); + success = helper->ProcessDecl() ? success : false; + } + for (FEInputGlobalVarHelper *helper : globalVarHelpers) { + ASSERT_NOT_NULL(helper); + success = helper->ProcessDecl() ? success : false; + } + for (FEInputFileScopeAsmHelper *helper : globalFileScopeAsmHelpers) { + ASSERT_NOT_NULL(helper); + success = helper->ProcessDecl() ? success : false; + } + timer.StopAndDumpTimeMS("HIR2MPLCompilerComponent::ProcessDecl()"); + return success; +} + +bool HIR2MPLCompilerComponent::ProcessFunctionSerialImpl() { + std::stringstream ss; + ss << GetComponentName() << "::ProcessFunctionSerial()"; + FETimer timer; + timer.StartAndDump(ss.str()); + bool success = true; + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process %s =====", ss.str().c_str()); + for (FEInputStructHelper *structHelper : structHelpers) { + ASSERT_NOT_NULL(structHelper); + for (FEInputMethodHelper *methodHelper : structHelper->GetMethodHelpers()) { + ASSERT_NOT_NULL(methodHelper); + std::unique_ptr feFunction = CreatFEFunction(methodHelper); + feFunction->SetSrcFileName(structHelper->GetSrcFileName()); + bool processResult = feFunction->Process(); + if (!processResult) { + (void)compileFailedFEFunctions.insert(feFunction.get()); + } + success = success && processResult; + feFunction->Finish(); + funcSize++; + } + } + timer.StopAndDumpTimeMS(ss.str()); + return success; +} + +bool HIR2MPLCompilerComponent::ProcessFunctionParallelImpl(uint32 nthreads) { + std::stringstream ss; + ss << GetComponentName() << "::ProcessFunctionParallel()"; + FETimer timer; + timer.StartAndDump(ss.str()); + FE_INFO_LEVEL(FEOptions::kDumpLevelInfo, "===== Process %s =====", ss.str().c_str()); + FEFunctionProcessSchedular schedular(ss.str()); + schedular.Init(); + for (FEInputStructHelper *structHelper : structHelpers) { + ASSERT_NOT_NULL(structHelper); + for (FEInputMethodHelper *methodHelper : structHelper->GetMethodHelpers()) { + ASSERT_NOT_NULL(methodHelper); + std::unique_ptr feFunction = CreatFEFunction(methodHelper); + feFunction->SetSrcFileName(structHelper->GetSrcFileName()); + schedular.AddFunctionProcessTask(std::move(feFunction)); + funcSize++; + } + } + schedular.SetDumpTime(FEOptions::GetInstance().IsDumpThreadTime()); + (void)schedular.RunTask(nthreads, true); + timer.StopAndDumpTimeMS(ss.str()); + return true; +} + +std::string HIR2MPLCompilerComponent::GetComponentNameImpl() const { + return "HIR2MPLCompilerComponent"; +} + +bool HIR2MPLCompilerComponent::ParallelableImpl() const { + return false; +} + +void HIR2MPLCompilerComponent::DumpPhaseTimeTotalImpl() const { + CHECK_NULL_FATAL(phaseResultTotal); + phaseResultTotal->DumpMS(); +} +} // namespace maple \ No newline at end of file diff --git a/src/hir2mpl/common/src/hir2mpl_env.cpp b/src/hir2mpl/common/src/hir2mpl_env.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98eb5a29cf92ee1f1a6994ba7e507c649fb3c9be --- /dev/null +++ b/src/hir2mpl/common/src/hir2mpl_env.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "hir2mpl_env.h" +#include "global_tables.h" +#include "mpl_logging.h" +#include "fe_options.h" + +namespace maple { +HIR2MPLEnv HIR2MPLEnv::instance; + +void HIR2MPLEnv::Init() { + srcFileIdxNameMap.clear(); + srcFileIdxNameMap[0] = GStrIdx(0); + globalLabelIdx = 1; +} + +void HIR2MPLEnv::Finish() { + srcFileIdxNameMap.clear(); +} + +uint32 HIR2MPLEnv::NewSrcFileIdx(const GStrIdx &nameIdx) { + size_t idx = srcFileIdxNameMap.size() + 1; // 1: already occupied by VtableImpl.mpl + CHECK_FATAL(idx < UINT32_MAX, "idx is out of range"); + srcFileIdxNameMap[idx] = nameIdx; + return static_cast(idx); +} + +GStrIdx HIR2MPLEnv::GetFileNameIdx(uint32 fileIdx) const { + auto it = srcFileIdxNameMap.find(fileIdx); + if (it == srcFileIdxNameMap.end()) { + return GStrIdx(0); + } else { + return it->second; + } +} + +std::string HIR2MPLEnv::GetFileName(uint32 fileIdx) const { + auto it = srcFileIdxNameMap.find(fileIdx); + if (it == srcFileIdxNameMap.end() || it->second == 0) { + return "unknown"; + } else { + return GlobalTables::GetStrTable().GetStringFromStrIdx(it->second); + } +} +} // namespace maple diff --git a/src/hir2mpl/common/src/hir2mpl_options.cpp b/src/hir2mpl/common/src/hir2mpl_options.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aae8a15cdba3a181c97f36f10d696cf852f92e9d --- /dev/null +++ b/src/hir2mpl/common/src/hir2mpl_options.cpp @@ -0,0 +1,864 @@ +/* + * Copyright (c) [2020-2022] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "hir2mpl_options.h" +#include +#include +#include "fe_options.h" +#include "fe_macros.h" +#include "option_parser.h" +#include "parser_opt.h" +#include "fe_file_type.h" +#include "version.h" + +namespace maple { +using namespace mapleOption; + +enum OptionIndex : uint32 { + kHir2mplHelp = kCommonOptionEnd + 1, + // input control options + kMpltSys, + kMpltApk, + kInClass, + kInJar, + kInDex, + kInAST, + kInMAST, + // output control options + kOutputPath, + kOutputName, + kGenMpltOnly, + kGenAsciiMplt, + kDumpInstComment, + kNoMplFile, + // debug info control options + kDumpLevel, + kDumpTime, + kDumpComment, + kDumpLOC, + kDumpPhaseTime, + kDumpPhaseTimeDetail, + // bc bytecode compile options + kRC, + kNoBarrier, + // java bytecode compile options + kJavaStaticFieldName, + kJBCInfoUsePathName, + kDumpJBCStmt, + kDumpJBCAll, + kDumpJBCErrorOnly, + kDumpJBCFuncName, + kEmitJBCLocalVarInfo, + // ast compiler options + kUseSignedChar, + kFEBigEndian, + // general stmt/bb/cfg debug options + kDumpFEIRBB, + kDumpFEIRCFGGraph, + // multi-thread control options + kNThreads, + kDumpThreadTime, + // type-infer + kTypeInfer, + // On Demand Type Creation + kXBootClassPath, + kClassLoaderContext, + kInputFile, + kCollectDepTypes, + kDepSameNamePolicy, + // EnhanceC + kNpeCheckDynamic, + kBoundaryCheckDynamic, + kSafeRegion, + kO2, + kSimplifyShortCircuit, + kEnableVariableArray, + kFuncInlineSize, + kWPAA, +}; + +const Descriptor kUsage[] = { + { kUnknown, 0, "", "", + kBuildTypeAll, kArgCheckPolicyUnknown, + "\n====== Usage: hir2mpl [options] input1 input2 input3 ======\n" + " options:", "hir2mpl", {} }, + { kHir2mplHelp, 0, "h", "help", + kBuildTypeAll, kArgCheckPolicyNone, + " -h, -help : print usage and exit", "hir2mpl", {} }, + { kVersion, 0, "v", "version", + kBuildTypeAll, kArgCheckPolicyNone, + " -v, -version : print version and exit", "hir2mpl", {} }, + + // input control options + { kUnknown, 0, "", "", + kBuildTypeAll, kArgCheckPolicyUnknown, + "\n====== Input Control Options ======", "hir2mpl", {} }, + { kMpltSys, 0, "", "mplt-sys", + kBuildTypeAll, kArgCheckPolicyRequired, + " -mplt-sys sys1.mplt,sys2.mplt\n" + " : input sys mplt files", "hir2mpl", {} }, + { kMpltApk, 0, "", "mplt-apk", + kBuildTypeAll, kArgCheckPolicyRequired, + " -mplt-apk apk1.mplt,apk2.mplt\n" + " : input apk mplt files", "hir2mpl", {} }, + { kInMplt, 0, "", "mplt", + kBuildTypeAll, kArgCheckPolicyRequired, + " -mplt lib1.mplt,lib2.mplt\n" + " : input mplt files", "hir2mpl", {} }, + { kInClass, 0, "", "in-class", + kBuildTypeAll, kArgCheckPolicyRequired, + " -in-class file1.jar,file2.jar\n" + " : input class files", "hir2mpl", {} }, + { kInJar, 0, "", "in-jar", + kBuildTypeAll, kArgCheckPolicyRequired, + " -in-jar file1.jar,file2.jar\n" + " : input jar files", "hir2mpl", {} }, + { kInDex, 0, "", "in-dex", + kBuildTypeAll, kArgCheckPolicyRequired, + " -in-dex file1.dex,file2.dex\n" + " : input dex files", "hir2mpl", {} }, + { kInAST, 0, "", "in-ast", + kBuildTypeAll, kArgCheckPolicyRequired, + " -in-ast file1.ast,file2.ast\n" + " : input ast files", "hir2mpl", {} }, + { kInMAST, 0, "", "in-mast", + kBuildTypeAll, kArgCheckPolicyRequired, + " -in-mast file1.mast,file2.mast\n" + " : input mast files", "hir2mpl", {} }, + + // output control options + { kUnknown, 0, "", "", + kBuildTypeAll, kArgCheckPolicyUnknown, + "\n====== Output Control Options ======", "hir2mpl", {} }, + { kOutputPath, 0, "p", "output", + kBuildTypeAll, kArgCheckPolicyRequired, + " -p, -output : output path", "hir2mpl", {} }, + { kOutputName, 0, "o", "output-name", + kBuildTypeAll, kArgCheckPolicyRequired, + " -o, -output-name : output name", "hir2mpl", {} }, + { kGenMpltOnly, 0, "t", "", + kBuildTypeAll, kArgCheckPolicyNone, + " -t : generate mplt only", "hir2mpl", {} }, + { kGenAsciiMplt, 0, "", "asciimplt", + kBuildTypeAll, kArgCheckPolicyNone, + " -asciimplt : generate mplt in ascii format", "hir2mpl", {} }, + { kDumpInstComment, 0, "", "dump-inst-comment", + kBuildTypeAll, kArgCheckPolicyNone, + " -dump-inst-comment : dump instruction comment", "hir2mpl", {} }, + { kNoMplFile, 0, "", "no-mpl-file", + kBuildTypeAll, kArgCheckPolicyNone, + " -no-mpl-file : disable dump mpl file", "hir2mpl", {} }, + + // debug info control options + { kUnknown, 0, "", "", + kBuildTypeAll, kArgCheckPolicyUnknown, + "\n====== Debug Info Control Options ======", "hir2mpl", {} }, + { kDumpLevel, 0, "d", "dump-level", + kBuildTypeAll, kArgCheckPolicyNumeric, + " -d, -dump-level xx : debug info dump level\n" + " [0] disable\n" + " [1] dump simple info\n" + " [2] dump detail info\n" + " [3] dump debug info", "hir2mpl", {} }, + { kDumpTime, 0, "", "dump-time", + kBuildTypeAll, kArgCheckPolicyNone, + " -dump-time : dump time", "hir2mpl", {} }, + { kDumpComment, 0, "", "dump-comment", + kBuildTypeAll, kArgCheckPolicyNone, + " -dump-comment : gen comment stmt", "hir2mpl", {} }, + { kDumpLOC, 0, "", "dump-LOC", + kBuildTypeAll, kArgCheckPolicyNone, + " -dump-LOC : gen LOC", "hir2mpl", {} }, + { kDumpPhaseTime, 0, "", "dump-phase-time", + kBuildTypeAll, kArgCheckPolicyNone, + " -dump-phase-time : dump total phase time", "hir2mpl", {} }, + { kDumpPhaseTimeDetail, 0, "", "dump-phase-time-detail", + kBuildTypeAll, kArgCheckPolicyNone, + " -dump-phase-time-detail\n" \ + " : dump phase time for each method", "hir2mpl", {} }, + { kDumpFEIRBB, 0, "", "dump-bb", + kBuildTypeAll, kArgCheckPolicyNone, + " -dump-bb : dump basic blocks info", "hir2mpl", {} }, + { kDumpFEIRCFGGraph, 0, "", "dump-cfg", + kBuildTypeAll, kArgCheckPolicyRequired, + " -dump-cfg funcname1,funcname2\n"\ + " : dump cfg graph to dot file", "hir2mpl", {} }, + + // bc bytecode compile options + { kUnknown, 0, "", "", + kBuildTypeAll, kArgCheckPolicyUnknown, + "\n====== BC Bytecode Compile Options ======", "hir2mpl", {} }, + { kRC, 0, "", "rc", + kBuildTypeAll, kArgCheckPolicyNone, + " -rc : enable rc", "hir2mpl", {} }, + { kNoBarrier, 0, "", "nobarrier", + kBuildTypeAll, kArgCheckPolicyNone, + " -nobarrier : no barrier", "hir2mpl", {} }, + + // ast compiler options + { kUnknown, 0, "", "", + kBuildTypeAll, kArgCheckPolicyUnknown, + "\n====== ast Compile Options ======", "hir2mpl", {} }, + { kUseSignedChar, 0, "", "usesignedchar", + kBuildTypeAll, kArgCheckPolicyNone, + " -usesignedchar : use signed char", "hir2mpl", {} }, + { kFEBigEndian, 0, "", "be", + kBuildTypeAll, kArgCheckPolicyNone, + " -be : enable big endian", "hir2mpl", {} }, + { kO2, 0, "O2", "", + kBuildTypeAll, kArgCheckPolicyNone, + " -O2 : enable hir2mpl O2 optimize", "hir2mpl", {} }, + { kSimplifyShortCircuit, 0, "", "simplify-short-circuit", + kBuildTypeAll, kArgCheckPolicyNone, + " -simplify-short-circuit\n" \ + " : enable simplify short circuit", "hir2mpl", {} }, + { kEnableVariableArray, 0, "", "enable-variable-array", + kBuildTypeAll, kArgCheckPolicyNone, + " -enable-variable-array\n" \ + " : enable variable array", "hir2mpl", {} }, + { kFuncInlineSize, 0, "", "func-inline-size", + kBuildTypeAll, kArgCheckPolicyRequired, + " -func-inline-size : set func inline size", "hir2mpl", {} }, + { kWPAA, 0, "", "wpaa", + kBuildTypeAll, kArgCheckPolicyNone, + " -wpaa : enable whole program ailas analysis", "hir2mpl", {} }, + + // multi-thread control + { kUnknown, 0, "", "", + kBuildTypeAll, kArgCheckPolicyUnknown, + "\n====== Multi-Thread Control Options ======", "hir2mpl", {} }, + { kNThreads, 0, "", "np", + kBuildTypeAll, kArgCheckPolicyRequired, + " -np num : number of threads", "hir2mpl", {} }, + { kDumpThreadTime, 0, "", "dump-thread-time", + kBuildTypeAll, kArgCheckPolicyNone, + " -dump-thread-time : dump thread time in mpl schedular", "hir2mpl", {} }, + + // On Demand Type Creation + { kUnknown, 0, "", "", + kBuildTypeAll, kArgCheckPolicyUnknown, + "\n====== On Demand Type Creation ======", "hir2mpl", {} }, + { kXBootClassPath, 0, "", "Xbootclasspath", + kBuildTypeAll, kArgCheckPolicyRequired, + " -Xbootclasspath=bootclasspath\n"\ + " : boot class path list", "hir2mpl", {} }, + { kClassLoaderContext, 0, "", "classloadercontext", + kBuildTypeAll, kArgCheckPolicyRequired, + " -classloadercontext=pcl\n"\ + " : class loader context \n"\ + " : path class loader", "hir2mpl", {} }, + { kCollectDepTypes, 0, "", "dep", + kBuildTypeAll, kArgCheckPolicyRequired, + " -dep=all or func\n"\ + " : [all] collect all dependent types\n"\ + " : [func] collect dependent types in function", "hir2mpl", {} }, + { kDepSameNamePolicy, 0, "", "depsamename", + kBuildTypeAll, kArgCheckPolicyRequired, + " -DepSameNamePolicy=sys or src\n"\ + " : [sys] load type from sys when on-demand load same name type\n"\ + " : [src] load type from src when on-demand load same name type", "hir2mpl", {} }, + + // security check + { kUnknown, 0, "", "", + kBuildTypeAll, kArgCheckPolicyUnknown, + "\n====== Security Check ======", "hir2mpl", {} }, + { kNpeCheckDynamic, 0, "", "npe-check-dynamic", + kBuildTypeAll, kArgCheckPolicyNone, + " -npe-check-dynamic : Nonnull pointr dynamic checking", "hir2mpl", {} }, + { kBoundaryCheckDynamic, 0, "", "boundary-check-dynamic", + kBuildTypeAll, kArgCheckPolicyNone, + " -boundary-check-dynamic\n" \ + " : Boundary dynamic checking", "hir2mpl", {} }, + { kSafeRegion, 0, "", "safe-region", + kBuildTypeAll, kArgCheckPolicyNone, + " -safe-region : Enable safe region", "hir2mpl", {} }, + { kUnknown, 0, "", "", + kBuildTypeAll, kArgCheckPolicyNone, + "\n", "hir2mpl", {} } +}; + +HIR2MPLOptions::HIR2MPLOptions() { + CreateUsages(kUsage); + Init(); +} + +void HIR2MPLOptions::Init() { + FEOptions::GetInstance().Init(); + bool success = InitFactory(); + CHECK_FATAL(success, "InitFactory failed. Exit."); +} + +bool HIR2MPLOptions::InitFactory() { + RegisterFactoryFunction(kHir2mplHelp, + &HIR2MPLOptions::ProcessHelp); + RegisterFactoryFunction(kVersion, + &HIR2MPLOptions::ProcessVersion); + + // input control options + RegisterFactoryFunction(kMpltSys, + &HIR2MPLOptions::ProcessInputMpltFromSys); + RegisterFactoryFunction(kMpltApk, + &HIR2MPLOptions::ProcessInputMpltFromApk); + RegisterFactoryFunction(kInMplt, + &HIR2MPLOptions::ProcessInputMplt); + RegisterFactoryFunction(kInClass, + &HIR2MPLOptions::ProcessInClass); + RegisterFactoryFunction(kInJar, + &HIR2MPLOptions::ProcessInJar); + RegisterFactoryFunction(kInDex, + &HIR2MPLOptions::ProcessInDex); + RegisterFactoryFunction(kInAST, + &HIR2MPLOptions::ProcessInAST); + RegisterFactoryFunction(kInMAST, + &HIR2MPLOptions::ProcessInMAST); + + // output control options + RegisterFactoryFunction(kOutputPath, + &HIR2MPLOptions::ProcessOutputPath); + RegisterFactoryFunction(kOutputName, + &HIR2MPLOptions::ProcessOutputName); + RegisterFactoryFunction(kGenMpltOnly, + &HIR2MPLOptions::ProcessGenMpltOnly); + RegisterFactoryFunction(kGenAsciiMplt, + &HIR2MPLOptions::ProcessGenAsciiMplt); + RegisterFactoryFunction(kDumpInstComment, + &HIR2MPLOptions::ProcessDumpInstComment); + RegisterFactoryFunction(kNoMplFile, + &HIR2MPLOptions::ProcessNoMplFile); + + // debug info control options + RegisterFactoryFunction(kDumpLevel, + &HIR2MPLOptions::ProcessDumpLevel); + RegisterFactoryFunction(kDumpTime, + &HIR2MPLOptions::ProcessDumpTime); + RegisterFactoryFunction(kDumpComment, + &HIR2MPLOptions::ProcessDumpComment); + RegisterFactoryFunction(kDumpLOC, + &HIR2MPLOptions::ProcessDumpLOC); + RegisterFactoryFunction(kDumpPhaseTime, + &HIR2MPLOptions::ProcessDumpPhaseTime); + RegisterFactoryFunction(kDumpPhaseTimeDetail, + &HIR2MPLOptions::ProcessDumpPhaseTimeDetail); + + // java bytecode compile options + RegisterFactoryFunction(kJavaStaticFieldName, + &HIR2MPLOptions::ProcessModeForJavaStaticFieldName); + RegisterFactoryFunction(kJBCInfoUsePathName, + &HIR2MPLOptions::ProcessJBCInfoUsePathName); + RegisterFactoryFunction(kDumpJBCStmt, + &HIR2MPLOptions::ProcessDumpJBCStmt); + RegisterFactoryFunction(kDumpJBCErrorOnly, + &HIR2MPLOptions::ProcessDumpJBCErrorOnly); + RegisterFactoryFunction(kDumpJBCFuncName, + &HIR2MPLOptions::ProcessDumpJBCFuncName); + RegisterFactoryFunction(kEmitJBCLocalVarInfo, + &HIR2MPLOptions::ProcessEmitJBCLocalVarInfo); + + // general stmt/bb/cfg debug options + RegisterFactoryFunction(kDumpFEIRBB, + &HIR2MPLOptions::ProcessDumpFEIRBB); + RegisterFactoryFunction(kDumpFEIRCFGGraph, + &HIR2MPLOptions::ProcessDumpFEIRCFGGraph); + + // multi-thread control options + RegisterFactoryFunction(kNThreads, + &HIR2MPLOptions::ProcessNThreads); + RegisterFactoryFunction(kDumpThreadTime, + &HIR2MPLOptions::ProcessDumpThreadTime); + + RegisterFactoryFunction(kRC, + &HIR2MPLOptions::ProcessRC); + RegisterFactoryFunction(kNoBarrier, + &HIR2MPLOptions::ProcessNoBarrier); + + // ast compiler options + RegisterFactoryFunction(kUseSignedChar, + &HIR2MPLOptions::ProcessUseSignedChar); + RegisterFactoryFunction(kFEBigEndian, + &HIR2MPLOptions::ProcessBigEndian); + // On Demand Type Creation + RegisterFactoryFunction(kXBootClassPath, + &HIR2MPLOptions::ProcessXbootclasspath); + RegisterFactoryFunction(kClassLoaderContext, + &HIR2MPLOptions::ProcessClassLoaderContext); + RegisterFactoryFunction(kInputFile, + &HIR2MPLOptions::ProcessCompilefile); + RegisterFactoryFunction(kCollectDepTypes, + &HIR2MPLOptions::ProcessCollectDepTypes); + RegisterFactoryFunction(kDepSameNamePolicy, + &HIR2MPLOptions::ProcessDepSameNamePolicy); + // EnhanceC + RegisterFactoryFunction(kNpeCheckDynamic, + &HIR2MPLOptions::ProcessNpeCheckDynamic); + RegisterFactoryFunction(kBoundaryCheckDynamic, + &HIR2MPLOptions::ProcessBoundaryCheckDynamic); + RegisterFactoryFunction(kSafeRegion, + &HIR2MPLOptions::ProcessSafeRegion); + + RegisterFactoryFunction(kO2, + &HIR2MPLOptions::ProcessO2); + RegisterFactoryFunction(kSimplifyShortCircuit, + &HIR2MPLOptions::ProcessSimplifyShortCircuit); + RegisterFactoryFunction(kEnableVariableArray, + &HIR2MPLOptions::ProcessEnableVariableArray); + RegisterFactoryFunction(kFuncInlineSize, + &HIR2MPLOptions::ProcessFuncInlineSize); + RegisterFactoryFunction(kWPAA, + &HIR2MPLOptions::ProcessWPAA); + return true; +} + +bool HIR2MPLOptions::SolveOptions(const std::deque