/*
 * Copyright (C) 2018-2020 Western Digital Corporation or its affiliates
 * Copyright (C) 2017-2018 Wearable, Inc.
 * Copyright (C) 2000-2012 leJOS Contributors
 * Copyright (C) 2000 Jose H. Solorzano and TinyVM Contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 * 
 * This Source Code Form is “Incompatible With Secondary Licenses”,
 * as defined by the Mozilla Public License, v. 2.0.
 */

/**
 * This is included inside a switch statement.
 */

OPCODE(OP_ANEWARRAY)
  // Stack size: unchanged
  // Arguments: 1
  {
    nvm_array_size_t index = (pc[0] << 8) | pc[1];
    SAVE_REGS(pState);
    REFERENCE tempStackWord = obj2ref(new_single_array (pState, index, (JINT)get_top_word(), false));
    LOAD_REGS(pState);
    // Do not modify the stack if an exception has been thrown
    if (!ref_null_p(tempStackWord)) {
      pc += 2;
      set_top_ref(tempStackWord);
    }
  }
  // Exceptions are taken care of
  DISPATCH_CHECKED;

OPCODE(OP_NEWARRAY)
  // Stack size: unchanged
  // Arguments: 1
  {
    SAVE_REGS(pState);
    REFERENCE tempStackWord = obj2ref(new_single_array(pState, ALJAVA_LANG_OBJECT + *pc, (JINT)get_top_word(), false));
    LOAD_REGS(pState);
    // Do not modify the stack if an exception has been thrown
    if (!ref_null_p(tempStackWord)) {
      pc++;
      set_top_ref(tempStackWord);
    }
  }
  // Exceptions are taken care of
  DISPATCH_CHECKED;

OPCODE(OP_MULTIANEWARRAY)
  // Stack size: -N + 1
  // Arguments: 3
  {
    int tempInt = pc[2] - 1;
    nvm_array_size_t index = (pc[0] << 8) | pc[1];
    SAVE_REGS(pState);
    REFERENCE tempStackWord = obj2ref(new_multi_array (pState, index, pc[2], get_stack_ptr() - tempInt));
    LOAD_REGS(pState);
    // Must not modify either the stack or the pc if an exception has been thrown
    if (!ref_null_p(tempStackWord)) {
      pop_words (tempInt);
      pc += 3;
      set_top_ref (tempStackWord);
    }
  }
  DISPATCH_CHECKED;

OPCODE(OP_AALOAD)
  // Stack size: -2 + 1
  // Arguments: 0
  {
    REFERENCE* tempWordPtr = array_helper(pState, get_top_word(), ref2obj(get_ref_at(1)), sizeof(REFERENCE));
    just_pop_word();
    if(tempWordPtr == NULL) {
      goto LABEL_THROW_EXCEPTION;
    }
    set_top_ref(*tempWordPtr);
  }
  DISPATCH;

OPCODE(OP_IALOAD)
OPCODE(OP_FALOAD)
  // Stack size: -2 + 1
  // Arguments: 0
  {
    STACKWORD* tempWordPtr = array_helper(pState, get_top_word(), ref2obj(get_ref_at(1)), sizeof(STACKWORD));
    just_pop_word();
    if(tempWordPtr == NULL) {
      goto LABEL_THROW_EXCEPTION;
    }
    set_top_word (*tempWordPtr);
  }
  DISPATCH;

OPCODE(OP_CALOAD)
  {
    JCHAR* tempWordPtr = array_helper(pState, get_top_word(), ref2obj(get_ref_at(1)), sizeof(JCHAR));
    just_pop_word();
    if(tempWordPtr == NULL) {
      goto LABEL_THROW_EXCEPTION;
    }
    set_top_word (*tempWordPtr);
  }
  DISPATCH;

OPCODE(OP_SALOAD)
  {
    JSHORT* tempWordPtr = array_helper(pState, get_top_word(), ref2obj(get_ref_at(1)), sizeof(JSHORT));
    just_pop_word();
    if(tempWordPtr == NULL) {
      goto LABEL_THROW_EXCEPTION;
    }
    set_top_word (*tempWordPtr);
  }
  DISPATCH;

OPCODE(OP_BALOAD)
  {
    JBYTE* tempWordPtr = array_helper(pState, get_top_word(), ref2obj(get_ref_at(1)), sizeof(JBYTE));
    just_pop_word();
    if(tempWordPtr == NULL) {
      goto LABEL_THROW_EXCEPTION;
    }
    set_top_word (*tempWordPtr);
  }
  DISPATCH;

OPCODE(OP_LALOAD)
OPCODE(OP_DALOAD)
  {
    // Stack size: -2 + 2
    // Arguments: 0
    STACKWORD* tempWordPtr = array_helper(pState, get_top_word(), ref2obj(get_ref_at(1)), sizeof(JLONG));
    just_pop_word();
    if(tempWordPtr == NULL) {
      goto LABEL_THROW_EXCEPTION;
    }
    set_top_word (*tempWordPtr++);
    push_word (*tempWordPtr);
  }
  DISPATCH;

OPCODE(OP_AASTORE)
  // Stack size: -3
  {
    REFERENCE tempStackWord = pop_ref();
    STACKWORD* tempWordPtr = (STACKWORD *) ref2ptr(get_ref_at(1));
    if (type_checks_enabled(pState) && !ref_null_p(tempStackWord) && tempWordPtr != NULL && !is_assignable(pState, nvm_object_class_index(ref2obj(tempStackWord)), get_element_class(get_class_record(pState, nvm_object_class_index((Object *)tempWordPtr))))) {
      pState->thrown_exception = JAVA_LANG_ARRAYSTOREEXCEPTION;
      goto LABEL_THROW_EXCEPTION;
    }
    if(!tempWordPtr) {
        pState->thrown_exception = JAVA_LANG_ARRAYSTOREEXCEPTION;
        goto LABEL_THROW_EXCEPTION;
    }
    update_array(pState, (Object *) tempWordPtr);
    tempWordPtr = array_helper(pState, get_top_word(), (Object *)tempWordPtr, sizeof(REFERENCE));
    if(tempWordPtr == NULL) {
      goto LABEL_THROW_EXCEPTION;
    }
    *tempWordPtr = ref2stackword(tempStackWord);
    pop_words(2);
  }
  DISPATCH;

OPCODE(OP_IASTORE)
OPCODE(OP_FASTORE)
  // Stack size: -3
  {
    STACKWORD tempStackWord = pop_word();
    STACKWORD* tempWordPtr = array_helper(pState, get_top_word(), ref2obj(get_ref_at(1)), sizeof(STACKWORD));
    if(tempWordPtr == NULL) {
      goto LABEL_THROW_EXCEPTION;
    }
    *tempWordPtr = tempStackWord;
    pop_words(2);
  }
  DISPATCH;

OPCODE(OP_CASTORE)
OPCODE(OP_SASTORE)
  // Stack size: -3
  {
    STACKWORD tempStackWord = pop_word();
    STACKWORD* tempWordPtr = array_helper(pState, get_top_word(), ref2obj(get_ref_at(1)), sizeof(JCHAR));
    if(tempWordPtr == NULL) {
      goto LABEL_THROW_EXCEPTION;
    }
    *(JSHORT *)tempWordPtr = tempStackWord;
    pop_words(2);
  }
  DISPATCH;

OPCODE(OP_BASTORE)
  // Stack size: -3
  {
    STACKWORD tempStackWord = pop_word();
    STACKWORD* tempWordPtr = array_helper(pState, get_top_word(), ref2obj(get_ref_at(1)), sizeof(JBYTE));
    if(tempWordPtr == NULL) {
      goto LABEL_THROW_EXCEPTION;
    }
    *(JBYTE *)tempWordPtr = tempStackWord;
    pop_words(2);
  }
  DISPATCH;

OPCODE(OP_DASTORE)
OPCODE(OP_LASTORE)
  // Stack size: -4
  {
    STACKWORD tempStackWord2 = pop_word();
    STACKWORD tempStackWord = pop_word();
    STACKWORD* tempWordPtr = array_helper(pState, get_top_word(), ref2obj(get_ref_at(1)), sizeof(JLONG));
    if(tempWordPtr == NULL) {
      goto LABEL_THROW_EXCEPTION;
    }
    *tempWordPtr++ = tempStackWord;
    *tempWordPtr = tempStackWord2;
    pop_words(2);
  }
  DISPATCH;

OPCODE(OP_ARRAYLENGTH)
  // Stack size: -1 + 1
  // Arguments: 0
  {
    REFERENCE tempRef;

    tempRef = get_top_ref();
    
    if (ref_null_p(tempRef)) {
      goto LABEL_THROW_NULLPTR_EXCEPTION;
    }
    set_top_word (nvm_array_size(ref2obj(tempRef)));
  }
  DISPATCH;

/*end*/
