# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

definitions:
  - name: pandasm_header
    template: |
      .language PandaAssembly

      .record panda.Object <external>

      .record Q {}
      .function void Q.ctor(Q a0) <ctor> {
        return.void
      }

      .record R {
        u1             fu1
        u8             fu8
        i8             fi8
        u16            fu16
        i16            fi16
        u32            fu32
        i32            fi32
        u64            fu64
        i64            fi64
        f32            ff32
        f64            ff64
        # objects
        i32[]          fi32Array
        Q              fQ
        Q[]            fQArray
        R              fR
        R[]            fRArray
        panda.Object   fObj
        panda.Object[] fObjArray
      }
      .function void R.ctor(R a0) <ctor> {
        return.void
      }

  - name: PandaAssembly_header
    template: |
      .language PandaAssembly

      .record panda.Object <external>
      .function void panda.Object.ctor(panda.Object a0) <external, ctor>

      .record I <panda.interface> {}

      .record Q <panda.implements=I> {}
      .function void Q.ctor(Q a0) <ctor> {
        return.void
      }

      .record R <panda.extends=Q> {
        u1                 fu1
        i8                 fi8
        u16                fu16
        i16                fi16
        i32                fi32
        i64                fi64
        f32                ff32
        f64                ff64
        # objects
        i32[]              fi32Array
        Q                  fQ
        Q[]                fQArray
        R                  fR
        R[]                fRArray
        I                  fI
        I[]                fIArray
        panda.Object   fObj
        panda.Object[] fObjArray
      }
      .function void R.ctor(R a0) <ctor> {
        return.void
      }

tests:
  - file-name: "stobj.obj"
    isa:
      title: Store accumulator content into object field
      description: >
        Store accumulator content into object field by field_id.
      instructions:
        - sig: stobj.obj v:in:ref, field_id
          acc: in:ref
          format: [op_v_8_id_16]
    commands:

      - file-name: "check_if_regs_initialized"
        description: Check that verifier reports error if source registers are not initialized
        isa:
          description: Store accumulator content into object field by field_id.
        header-template: ['pandasm_header']
        check-type: exit-positive
        tags: ['verifier']
        bugid: ['1324']
        runner-options: ['verifier-failure', 'verifier-config']
        code-template: |

          %s

          .function i32 main() {
            initobj R.ctor
            sta.obj v0
            call.short check, v0
        cases:
          - values:
            - |
              # acc (value) not initialized in the frame
              .function void check(R a0) {
                stobj.obj a0, R.fR
                return.void
              }
          - values:
            - |
              # v0 (object) not initialized in the frame
              .function void check(R a0) {
                lda.obj a0
                stobj.obj v0, R.fR
                return.void
              }
            bugid: ['1324']


      - file-name: "with_null_ref_p"
        description: Check that NullPointerException is thrown if source ref is null
        isa:
          exceptions:
            - x_null
        header-template: ['pandasm_header']
        check-type: empty
        tags: ['irtoc_ignore']
        bugid: ['3047']
        code-template: |
          .record panda.NullPointerException <external>

          .function R get_null() {
            lda.null
            return.obj
          }

          .function i32 main() {
            call.short get_null
            sta.obj v0
            %s
          try_begin:
            stobj.obj v0, %s
            ldai 1
            return
          try_end:
            ldai 0
            return
          .catch panda.NullPointerException, try_begin, try_end, try_end
          }
        cases:
          - values:
            - lda.null
            - R.fR
          - values:
            - initobj Q.ctor
            - R.fQ
          - values:
            - |
              movi v1, 10
                newarr v1, v1, i32[]
                lda.obj v1
            - R.fi32Array


      - file-name: "with_null_ref_j"
        description: Check that NullPointerException is thrown if source ref is null
        isa:
          exceptions:
            - x_null
        header-template: ['PandaAssembly_header']
        runner-options: ['use-pa']
        bugid: ['3047']
        tags: ['irtoc_ignore']
        check-type: empty
        code-template: |
          .record panda.NullPointerException <external>

          .function R get_null() {
            lda.null
            return.obj
          }

          .function i32 main() {
            call.short get_null
            sta.obj v0
            %s
          try_begin:
            stobj.obj v0, %s
            ldai 1
            return
          try_end:
            ldai 0
            return
          .catch panda.NullPointerException, try_begin, try_end, try_end
          }
        cases:
          - values:
            - lda.null
            - R.fObj
          - values:
            - initobj Q.ctor
            - R.fQ
          - values:
            - |
              movi v1, 10
                newarr v1, v1, panda.Object[]
                lda.obj v1
            - R.fObjArray


      - file-name: "with_non_object_ref_p"
        description: Check that verifier reports error when the 1st operand is not a ref to an object (other than array)
        isa:
          verification:
            - v1_object
        header-template: ['pandasm_header']
        check-type: empty
        tags: ['verifier']
        bugid: ['1324', '1826', '1827']
        runner-options: ['verifier-failure', 'verifier-config']
        code-template: |

          .function i32 main() {
            %s
            initobj Q.ctor
          try_begin:
            stobj.obj v0, R.fQ
          try_end:
            ldai 0
            return
          .catchall try_begin, try_end, try_end
          }
        cases:
          - values:
            - movi v0, 0

          - values:
            - movi v0, 1
          - values:
            - movi.64 v0, 0x00
          - values:
            - movi.64 v0, 0xCAFECAFECAFECAFE
          - values:
            - fmovi.64 v0, 0.0
          - values:
            - fmovi.64 v0, 6.62607015
          - values:
            - |
                movi v1, 10
                  newarr v0, v1, R[]


      - file-name: "with_static_field_id_p"
        description: Check that verifier reports error when the field doesn't resolve to a non-static object field
        isa:
          verification:
            - field_id_non_static
        header-template: []
        check-type: exit-positive
        bugid: ['1324', '1828', '1833']
        tags: ['verifier']
        runner-options: ['verifier-failure', 'verifier-config']
        code-template: |
          .record W {
            W   static_field  <static>
            W[] static_array  <static>
          }
          .function void W.ctor(W a0) <ctor> {
            return.void
          }
          .function void W.foo(W a0) {
            return.void
          }

          .record random_record_name {
            W random_field_name
          }

          .function void random_function_name() {
            return.void
          }

          .function i32 main() {
            initobj W.ctor
            sta.obj v0
            lda.null
            stobj.obj v0, %s
        cases:
          # resolves to a static object field
          - values:
            - W.static_field
          # resolves to a static object array
          - values:
            - W.static_array
          # resolves to a non-existing object field
          - values:
            - W.field_not_exists
            runner-options: ['compile-failure']
          # resolves to object's constructor
          - values:
            - W.ctor
            runner-options: ['compile-failure']
          # resolves to objects's method
          - values:
            - W.foo
            runner-options: ['compile-failure']
          # resolves to some other object
          - values:
            - random_record_name
            runner-options: ['compile-failure']
          # resolves to some static function
          - values:
            - random_function_name
            runner-options: ['compile-failure']
          # resolves to a field name in a wrong object
          - values:
            - random_record_name.random_field_name
            bugid: ['3536']
          # cannot resolve, because it's a i32 number
          - values:
            - 0
            runner-options: ['compile-failure']
          # cannot resolve, because it's a f64 number
          - values:
            - -1.1
            runner-options: ['compile-failure']
          # cannot resolve, because it's a "null" string
          - values:
            - "null"
            runner-options: ['compile-failure']


      - file-name: "with_wrong_acc_type_p"
        description: Check that verifier reports error when the accumulator contains a value of type not corresponding to the bytecode
        isa:
          verification:
            - acc_type
        header-template: ['pandasm_header']
        check-type: exit-positive
        tags: ['verifier']
        runner-options: ['verifier-failure', 'verifier-config']
        code-template: |

          .function i32 main() {
            initobj R.ctor
            sta.obj v0
            %s
            stobj.obj v0, %s
        cases:
          # store into object field
          - values:
            - ldai 0
            - R.fQ
            bugid: ['1324', '1834']
          - values:
            - ldai.64 1
            - R.fQ
            bugid: ['1324', '1834']
          - values:
            - fldai.64 0x7FFFFFFFFFFFFFFF
            - R.fQ
            bugid: ['1324', '1834']
          - values:
            - lda.type R
            - R.fQ
            bugid: ['1834']
          - values:
            - |
              #
                newobj v1, panda.Object
                lda.obj v1
            - R.fQ
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, Q[]
                lda.obj v1
            - R.fQ
            bugid: ['1834']
          # store into object array field
          - values:
            - ldai 0
            - R.fQArray
            bugid: ['1324', '1834']
          - values:
            - ldai.64 1
            - R.fQArray
            bugid: ['1324', '1834']
          - values:
            - fldai.64 0x7FFFFFFFFFFFFFFF
            - R.fQArray
            bugid: ['1324', '1834']
          - values:
            - initobj Q.ctor
            - R.fQArray
            bugid: ['1834']
          - values:
            - |
              #
                newobj v1, panda.Object
                lda.obj v1
            - R.fQArray
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, R[]
                lda.obj v1
            - R.fQArray
            bugid: ['1834']
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, panda.Object[]
                lda.obj v1
            - R.fQArray
          # store into i32[] array field
          - values:
            - ldai 0
            - R.fi32Array
            bugid: ['1324', '1834']
          - values:
            - ldai.64 1
            - R.fi32Array
            bugid: ['1324', '1834']
          - values:
            - fldai.64 0x7FFFFFFFFFFFFFFF
            - R.fi32Array
            bugid: ['1324', '1834']
          - values:
            - lda.type R
            - R.fi32Array
            bugid: ['1834']
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, Q[]
                lda.obj v1
            - R.fi32Array
            bugid: ['1834']
          # store into panda.Object field
          - values:
            - ldai 0
            - R.fObj
          - values:
            - ldai.64 1
            - R.fObj
          - values:
            - fldai.64 0x7FFFFFFFFFFFFFFF
            - R.fObj
          - values:
            - |
              #
                newobj v1, panda.Object
                lda.obj v1
            - R.fObj
            runner-options: ['verifier-only', 'verifier-config']
          - values:
            - lda.type R
            - R.fObj
            runner-options: ['verifier-only', 'verifier-config']
            bugid: ['3594']
            ignore: true
          - values:
            - lda.str ""
            - R.fObj
            runner-options: ['verifier-only', 'verifier-config']
          - values:
            - lda.null
            - R.fObj
            runner-options: ['verifier-only', 'verifier-config']
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, Q[]
                lda.obj v1
            - R.fObj
            runner-options: ['verifier-only', 'verifier-config']
          # store into panda.Object[] field
          - values:
            - ldai 0
            - R.fObjArray
          - values:
            - ldai.64 1
            - R.fObjArray
          - values:
            - fldai.64 0x7FFFFFFFFFFFFFFF
            - R.fObjArray
          - values:
            - |
              #
                newobj v1, panda.Object
                lda.obj v1
            - R.fObjArray
          - values:
            - lda.type R
            - R.fObjArray
          - values:
            - lda.str ""
            - R.fObjArray
          - values:
            - lda.null
            - R.fObjArray
            runner-options: ['verifier-only', 'verifier-config']
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, Q[]
                lda.obj v1
            - R.fObjArray
            runner-options: ['verifier-only', 'verifier-config']
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, panda.Object[]
                lda.obj v1
            - R.fObjArray
            runner-options: ['verifier-only', 'verifier-config']


      - file-name: "with_wrong_acc_type_j"
        description: Check that verifier reports error when the accumulator contains a value of type not corresponding to the bytecode
        isa:
          verification:
            - acc_type
        header-template: ['PandaAssembly_header']
        check-type: exit-positive
        tags: [verifier, pa-verifier]
        bugid: ['3293']
        runner-options: ['verifier-failure', 'verifier-config', 'use-pa']
        code-template: |

          .function i32 main() {
            initobj R.ctor
            sta.obj v0
            %s
            stobj.obj v0, %s
        cases:
          # store into object field
          - values:
            - ldai 0
            - R.fObj
            bugid: ['1324', '1834']
          - values:
            - ldai.64 1
            - R.fObj
            bugid: ['1324', '1834']
          - values:
            - fldai.64 0x7FFFFFFFFFFFFFFF
            - R.fObj
            bugid: ['1324', '1834']
          - values:
            - lda.type R # wrong type
            - R.fQ
            bugid: ['2256']
          - values:
            - lda.str "abc"  # wrong interface
            - R.fI
            bugid: ['1834']
          - values:
            - initobj Q.ctor  # supertype
            - R.fR
            bugid: ['1834']
          - values:
            - initobj panda.Object.ctor # supertype
            - R.fQ
            bugid: ['1834']
          - values:
            - |
                movi v1, 10
                  newarr v1, v1, R[]
                  lda.obj v1
            - R.fR
            bugid: ['1834']
          # store into object array field
          - values:
            - ldai 0
            - R.fObjArray
            bugid: ['1324', '1834']
          - values:
            - ldai.64 1
            - R.fObjArray
            bugid: ['1324', '1834']
          - values:
            - fldai.64 0x7FFFFFFFFFFFFFFF
            - R.fObjArray
            bugid: ['1324', '1834']
          - values:
            - initobj R.ctor
            - R.fRArray
            bugid: ['1834']
          - values:
            - lda.type R
            - R.fObjArray
            bugid: ['1834']
          - values:
            - | # array of supertypes
                movi v1, 10
                  newarr v1, v1, Q[]
                  lda.obj v1
            - R.fRArray
            bugid: ['1834']
          # store into panda.Object field
          - values:
            - ldai 0
            - R.fObj
          - values:
            - ldai.64 1
            - R.fObj
          - values:
            - fldai.64 0x7FFFFFFFFFFFFFFF
            - R.fObj
          - values:
            - lda.type R
            - R.fObj
            runner-options: ['verifier-only', 'verifier-config', 'use-pa']
            bugid: ['3594']
            ignore: true
          - values:
            - lda.str ""
            - R.fObj
            runner-options: ['verifier-only', 'verifier-config', 'use-pa']
          - values:
            - lda.null
            - R.fObj
            runner-options: ['verifier-only', 'verifier-config', 'use-pa']
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, Q[]
                lda.obj v1
            - R.fObj
            runner-options: ['verifier-only', 'verifier-config', 'use-pa']
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, panda.Object[]
                lda.obj v1
            - R.fObj
            runner-options: ['verifier-only', 'verifier-config', 'use-pa']
          # store into panda.Object[] field
          - values:
            - ldai 0
            - R.fObjArray
          - values:
            - ldai.64 1
            - R.fObjArray
          - values:
            - fldai.64 0x7FFFFFFFFFFFFFFF
            - R.fObjArray
          - values:
            - lda.type R
            - R.fObjArray
          - values:
            - lda.str ""
            - R.fObjArray
          - values:
            - lda.null
            - R.fObjArray
            runner-options: ['verifier-only', 'verifier-config', 'use-pa']
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, Q[]
                lda.obj v1
            - R.fObjArray
            runner-options: ['verifier-only', 'verifier-config', 'use-pa']
          - values:
            - |
              #
                movi v1, 10
                newarr v1, v1, panda.Object[]
                lda.obj v1
            - R.fObjArray
            runner-options: ['verifier-only', 'verifier-config', 'use-pa']


      - file-name: "op_v_8_id_16"
        description: Check that compiler reports error when the register number is out of 8 bit size
        isa:
          instructions:
            - sig: stobj.obj v:in:ref, field_id
              acc: in:ref
              format: [op_v_8_id_16]
        header-template: ['pandasm_header']
        check-type: exit-positive
        code-template: |

          .function i32 main() {
            stobj.obj %s, R.fQ
        cases:
          - values: ['v255']
            runner-options: ['compile-only']
          - values: ['v256']
            runner-options: ['compile-failure']
          - values: ['v65535']
            runner-options: ['compile-failure']


      - file-name: "into_all_field_types_p"
        description: Check that accumulator value is stored in field
        isa:
          description: Store accumulator content into object field by field_id.
        header-template: ['pandasm_header']
        check-type: exit-positive
        tags: ['tsan', 'irtoc_ignore']
        code-template: |

          .function i32 main() {
            initobj R.ctor
            sta.obj v0
            %s
            sta.obj v7
            stobj.obj v0, R.%s
            lda.null
            ldobj.obj v0, R.%s
            jeq.obj v7, success
            ldai 1
            return
          success:
        cases:
          - values:
            - |
                # store null into Q type field
                  lda.null
            - fQ
            - fQ
          - values:
            - |
                # store null into Q[] type field
                  lda.null
            - fQArray
            - fQArray
          - values:
            - |
                # store Q into Q type field
                  initobj Q.ctor
            - fQ
            - fQ
          - values:
            - |
                # store Q[] into Q[] type field
                  movi v1, 10
                  newarr v1, v1, Q[]
                  lda.obj v1
            - fQArray
            - fQArray
          - values:
            - |
                # store Q into panda.Object type field
                  initobj Q.ctor
            - fObj
            - fObj
          - values:
            - |
                # store Q[] into panda.Object type field
                  movi v1, 10
                  newarr v1, v1, Q[]
                  lda.obj v1
            - fObj
            - fObj
          - values:
            - |
                # store Q[] into panda.Object[] type field
                  movi v1, 10
                  newarr v1, v1, Q[]
                  lda.obj v1
            - fObjArray
            - fObjArray


      - file-name: "into_all_field_types_j"
        description: Check that accumulator value is stored in field
        isa:
          description: Store accumulator content into object field by field_id.
        header-template: ['PandaAssembly_header']
        runner-options: ['use-pa']
        check-type: exit-positive
        tags: ['irtoc_ignore']
        code-template: |

          .function i32 main() {
            initobj R.ctor
            sta.obj v0
            %s
            sta.obj v7
            stobj.obj v0, R.%s
            lda.null
            ldobj.obj v0, R.%s
            jeq.obj v7, success
            ldai 1
            return
          success:
        cases:
          - values:
            - |
                # store subsclass R into Q type field
                  initobj R.ctor
            - fQ
            - fQ
          - values:
            - |
                # store subsclass R into interface type field
                  initobj R.ctor
            - fI
            - fI
          - values:
            - |
                # store subsclass R into base type field
                  initobj R.ctor
            - fObj
            - fObj
          - values:
            - |
                # store subclass R[] into Q[] type field
                  movi v1, 10
                  newarr v1, v1, R[]
                  lda.obj v1
            - fQArray
            - fQArray
          - values:
            - |
                # store subclass R[] into interface [] type field
                  movi v1, 10
                  newarr v1, v1, R[]
                  lda.obj v1
            - fIArray
            - fIArray
          - values:
            - |
                # store subclass R[] into base type [] field
                  movi v1, 10
                  newarr v1, v1, R[]
                  lda.obj v1
            - fObjArray
            - fObjArray
          - values:
            - |
                # store subclass R[] into base type field
                  movi v1, 10
                  newarr v1, v1, R[]
                  lda.obj v1
            - fObj
            - fObj