/*
 * Copyright (C) 2016 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.
 */

#include "escape.h"

#include "nodes.h"

namespace art {

void CalculateEscape(HInstruction* reference,
                     bool (*no_escape)(HInstruction*, HInstruction*),
                     /*out*/ bool* is_singleton,
                     /*out*/ bool* is_singleton_and_not_returned,
                     /*out*/ bool* is_singleton_and_not_deopt_visible) {
  // For references not allocated in the method, don't assume anything.
  if (!reference->IsNewInstance() && !reference->IsNewArray()) {
    *is_singleton = false;
    *is_singleton_and_not_returned = false;
    *is_singleton_and_not_deopt_visible = false;
    return;
  }
  // Assume the best until proven otherwise.
  *is_singleton = true;
  *is_singleton_and_not_returned = true;
  *is_singleton_and_not_deopt_visible = true;
  // Visit all uses to determine if this reference can escape into the heap,
  // a method call, an alias, etc.
  for (const HUseListNode<HInstruction*>& use : reference->GetUses()) {
    HInstruction* user = use.GetUser();
    if (no_escape != nullptr && (*no_escape)(reference, user)) {
      // Client supplied analysis says there is no escape.
      continue;
    } else if (user->IsBoundType() || user->IsNullCheck()) {
      // BoundType shouldn't normally be necessary for an allocation. Just be conservative
      // for the uncommon cases. Similarly, null checks are eventually eliminated for explicit
      // allocations, but if we see one before it is simplified, assume an alias.
      *is_singleton = false;
      *is_singleton_and_not_returned = false;
      *is_singleton_and_not_deopt_visible = false;
      return;
    } else if (user->IsPhi() || user->IsSelect() || user->IsInvoke() ||
               (user->IsInstanceFieldSet() && (reference == user->InputAt(1))) ||
               (user->IsUnresolvedInstanceFieldSet() && (reference == user->InputAt(1))) ||
               (user->IsStaticFieldSet() && (reference == user->InputAt(1))) ||
               (user->IsUnresolvedStaticFieldSet() && (reference == user->InputAt(0))) ||
               (user->IsArraySet() && (reference == user->InputAt(2)))) {
      // The reference is merged to HPhi/HSelect, passed to a callee, or stored to heap.
      // Hence, the reference is no longer the only name that can refer to its value.
      *is_singleton = false;
      *is_singleton_and_not_returned = false;
      *is_singleton_and_not_deopt_visible = false;
      return;
    } else if ((user->IsUnresolvedInstanceFieldGet() && (reference == user->InputAt(0))) ||
               (user->IsUnresolvedInstanceFieldSet() && (reference == user->InputAt(0)))) {
      // The field is accessed in an unresolved way. We mark the object as a non-singleton.
      // Note that we could optimize this case and still perform some optimizations until
      // we hit the unresolved access, but the conservative assumption is the simplest.
      *is_singleton = false;
      *is_singleton_and_not_returned = false;
      *is_singleton_and_not_deopt_visible = false;
      return;
    } else if (user->IsReturn()) {
      *is_singleton_and_not_returned = false;
    }
  }

  // Look at the environment uses if it's for HDeoptimize. Other environment uses are fine,
  // as long as client optimizations that rely on this information are disabled for debuggable.
  for (const HUseListNode<HEnvironment*>& use : reference->GetEnvUses()) {
    HEnvironment* user = use.GetUser();
    if (user->GetHolder()->IsDeoptimize()) {
      *is_singleton_and_not_deopt_visible = false;
      break;
    }
  }
}

bool DoesNotEscape(HInstruction* reference, bool (*no_escape)(HInstruction*, HInstruction*)) {
  bool is_singleton = false;
  bool is_singleton_and_not_returned = false;
  bool is_singleton_and_not_deopt_visible = false;  // not relevant for escape
  CalculateEscape(reference,
                  no_escape,
                  &is_singleton,
                  &is_singleton_and_not_returned,
                  &is_singleton_and_not_deopt_visible);
  return is_singleton_and_not_returned;
}

}  // namespace art
