<commit_before>/*
 * Copyright (C) 2014 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 "quick_exception_handler.h"

#include "arch/context.h"
#include "dex_instruction.h"
#include "entrypoints/entrypoint_utils.h"
#include "handle_scope-inl.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/throwable.h"
#include "verifier/method_verifier.h"

namespace art {

static constexpr bool kDebugExceptionDelivery = false;
static constexpr size_t kInvalidFrameDepth = 0xffffffff;

QuickExceptionHandler::QuickExceptionHandler(Thread* self, bool is_deoptimization)
  : self_(self), context_(self->GetLongJumpContext()), is_deoptimization_(is_deoptimization),
    method_tracing_active_(is_deoptimization ||
                           Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()),
    handler_quick_frame_(nullptr), handler_quick_frame_pc_(0), handler_method_(nullptr),
    handler_dex_pc_(0), clear_exception_(false), handler_frame_depth_(kInvalidFrameDepth) {
}

// Finds catch handler or prepares for deoptimization.
class CatchBlockStackVisitor FINAL : public StackVisitor {
 public:
  CatchBlockStackVisitor(Thread* self, Context* context, Handle<mirror::Throwable>* exception,
                         QuickExceptionHandler* exception_handler)
      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
      : StackVisitor(self, context), self_(self), exception_(exception),
        exception_handler_(exception_handler) {
  }

  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    mirror::ArtMethod* method = GetMethod();
    exception_handler_->SetHandlerFrameDepth(GetFrameDepth());
    if (method == nullptr) {
      // This is the upcall, we remember the frame and last pc so that we may long jump to them.
      exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
      exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
      uint32_t next_dex_pc;
      mirror::ArtMethod* next_art_method;
      bool has_next = GetNextMethodAndDexPc(&next_art_method, &next_dex_pc);
      // Report the method that did the down call as the handler.
      exception_handler_->SetHandlerDexPc(next_dex_pc);
      exception_handler_->SetHandlerMethod(next_art_method);
      if (!has_next) {
        // No next method? Check exception handler is set up for the unhandled exception handler
        // case.
        DCHECK_EQ(0U, exception_handler_->GetHandlerDexPc());
        DCHECK(nullptr == exception_handler_->GetHandlerMethod());
      }
      return false;  // End stack walk.
    }
    if (method->IsRuntimeMethod()) {
      // Ignore callee save method.
      DCHECK(method->IsCalleeSaveMethod());
      return true;
    }
    StackHandleScope<1> hs(self_);
    return HandleTryItems(hs.NewHandle(method));
  }

 private:
  bool HandleTryItems(Handle<mirror::ArtMethod> method)
      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    uint32_t dex_pc = DexFile::kDexNoIndex;
    if (!method->IsNative()) {
      dex_pc = GetDexPc();
    }
    if (dex_pc != DexFile::kDexNoIndex) {
      bool clear_exception = false;
      StackHandleScope<1> hs(Thread::Current());
      Handle<mirror::Class> to_find(hs.NewHandle((*exception_)->GetClass()));
      uint32_t found_dex_pc = mirror::ArtMethod::FindCatchBlock(method, to_find, dex_pc,
                                                                &clear_exception);
      exception_handler_->SetClearException(clear_exception);
      if (found_dex_pc != DexFile::kDexNoIndex) {
        exception_handler_->SetHandlerMethod(method.Get());
        exception_handler_->SetHandlerDexPc(found_dex_pc);
        exception_handler_->SetHandlerQuickFramePc(method->ToNativePc(found_dex_pc));
        exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
        return false;  // End stack walk.
      }
    }
    return true;  // Continue stack walk.
  }

  Thread* const self_;
  // The exception we're looking for the catch block of.
  Handle<mirror::Throwable>* exception_;
  // The quick exception handler we're visiting for.
  QuickExceptionHandler* const exception_handler_;

  DISALLOW_COPY_AND_ASSIGN(CatchBlockStackVisitor);
};

void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location,
                                      mirror::Throwable* exception,
                                      bool is_exception_reported) {
  DCHECK(!is_deoptimization_);
  if (kDebugExceptionDelivery) {
    mirror::String* msg = exception->GetDetailMessage();
    std::string str_msg(msg != nullptr ? msg->ToModifiedUtf8() : "");
    self_->DumpStack(LOG(INFO) << "Delivering exception: " << PrettyTypeOf(exception)
                     << ": " << str_msg << "\n");
  }
  StackHandleScope<1> hs(self_);
  Handle<mirror::Throwable> exception_ref(hs.NewHandle(exception));

  // Walk the stack to find catch handler or prepare for deoptimization.
  CatchBlockStackVisitor visitor(self_, context_, &exception_ref, this);
  visitor.WalkStack(true);

  if (kDebugExceptionDelivery) {
    if (handler_quick_frame_->AsMirrorPtr() == nullptr) {
      LOG(INFO) << "Handler is upcall";
    }
    if (handler_method_ != nullptr) {
      const DexFile& dex_file = *handler_method_->GetDeclaringClass()->GetDexCache()->GetDexFile();
      int line_number = dex_file.GetLineNumFromPC(handler_method_, handler_dex_pc_);
      LOG(INFO) << "Handler: " << PrettyMethod(handler_method_) << " (line: " << line_number << ")";
    }
  }
  if (clear_exception_) {
    // Exception was cleared as part of delivery.
    DCHECK(!self_->IsExceptionPending());
  } else {
    // Put exception back in root set with clear throw location.
    self_->SetException(ThrowLocation(), exception_ref.Get());
    self_->SetExceptionReportedToInstrumentation(is_exception_reported);
  }
  // The debugger may suspend this thread and walk its stack. Let's do this before popping
  // instrumentation frames.
  if (!is_exception_reported) {
    instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
    instrumentation->ExceptionCaughtEvent(self_, throw_location, handler_method_, handler_dex_pc_,
                                          exception_ref.Get());
      // We're not catching this exception but let's remind we already reported the exception above
      // to avoid reporting it twice.
      self_->SetExceptionReportedToInstrumentation(true);
  }
  bool caught_exception = (handler_method_ != nullptr && handler_dex_pc_ != DexFile::kDexNoIndex);
  if (caught_exception) {
    // We're catching this exception so we finish reporting it. We do it here to avoid doing it
    // in the compiled code.
    self_->SetExceptionReportedToInstrumentation(false);
  }
}

// Prepares deoptimization.
class DeoptimizeStackVisitor FINAL : public StackVisitor {
 public:
  DeoptimizeStackVisitor(Thread* self, Context* context, QuickExceptionHandler* exception_handler)
      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
      : StackVisitor(self, context), self_(self), exception_handler_(exception_handler),
        prev_shadow_frame_(nullptr) {
    CHECK(!self_->HasDeoptimizationShadowFrame());
  }

  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    exception_handler_->SetHandlerFrameDepth(GetFrameDepth());
    mirror::ArtMethod* method = GetMethod();
    if (method == nullptr) {
      // This is the upcall, we remember the frame and last pc so that we may long jump to them.
      exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
      exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
      return false;  // End stack walk.
    } else if (method->IsRuntimeMethod()) {
      // Ignore callee save method.
      DCHECK(method->IsCalleeSaveMethod());
      return true;
    } else {
      return HandleDeoptimization(method);
    }
  }

 private:
  static VRegKind GetVRegKind(uint16_t reg, const std::vector<int32_t>& kinds) {
    return static_cast<VRegKind>(kinds.at(reg * 2));
  }

  bool HandleDeoptimization(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    const DexFile::CodeItem* code_item = m->GetCodeItem();
    CHECK(code_item != nullptr);
    uint16_t num_regs = code_item->registers_size_;
    uint32_t dex_pc = GetDexPc();
    const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc);
    uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits();
    ShadowFrame* new_frame = ShadowFrame::Create(num_regs, nullptr, m, new_dex_pc);
    StackHandleScope<2> hs(self_);
    mirror::Class* declaring_class = m->GetDeclaringClass();
    Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
    Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
    verifier::MethodVerifier verifier(h_dex_cache->GetDexFile(), &h_dex_cache, &h_class_loader,
                                      &m->GetClassDef(), code_item, m->GetDexMethodIndex(), m,
                                      m->GetAccessFlags(), false, true, true);
    verifier.Verify();
    const std::vector<int32_t> kinds(verifier.DescribeVRegs(dex_pc));
    for (uint16_t reg = 0; reg < num_regs; ++reg) {
      VRegKind kind = GetVRegKind(reg, kinds);
      switch (kind) {
        case kUndefined:
          new_frame->SetVReg(reg, 0xEBADDE09);
          break;
        case kConstant:
          new_frame->SetVReg(reg, kinds.at((reg * 2) + 1));
          break;
        case kReferenceVReg:
          new_frame->SetVRegReference(reg,
                                      reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kind)));
          break;
        case kLongLoVReg:
          if (GetVRegKind(reg + 1, kinds), kLongHiVReg) {
            // Treat it as a "long" register pair.
            new_frame->SetVRegLong(reg, GetVRegPair(m, reg, kLongLoVReg, kLongHiVReg));
          } else {
            new_frame->SetVReg(reg, GetVReg(m, reg, kind));
          }
          break;
        case kLongHiVReg:
          if (GetVRegKind(reg - 1, kinds), kLongLoVReg) {
            // Nothing to do: we treated it as a "long" register pair.
          } else {
            new_frame->SetVReg(reg, GetVReg(m, reg, kind));
          }
          break;
        case kDoubleLoVReg:
          if (GetVRegKind(reg + 1, kinds), kDoubleHiVReg) {
            // Treat it as a "double" register pair.
            new_frame->SetVRegLong(reg, GetVRegPair(m, reg, kDoubleLoVReg, kDoubleHiVReg));
          } else {
            new_frame->SetVReg(reg, GetVReg(m, reg, kind));
          }
          break;
        case kDoubleHiVReg:
          if (GetVRegKind(reg - 1, kinds), kDoubleLoVReg) {
            // Nothing to do: we treated it as a "double" register pair.
          } else {
            new_frame->SetVReg(reg, GetVReg(m, reg, kind));
          }
          break;
        default:
          new_frame->SetVReg(reg, GetVReg(m, reg, kind));
          break;
      }
    }
    if (prev_shadow_frame_ != nullptr) {
      prev_shadow_frame_->SetLink(new_frame);
    } else {
      self_->SetDeoptimizationShadowFrame(new_frame);
    }
    prev_shadow_frame_ = new_frame;
    return true;
  }

  Thread* const self_;
  QuickExceptionHandler* const exception_handler_;
  ShadowFrame* prev_shadow_frame_;

  DISALLOW_COPY_AND_ASSIGN(DeoptimizeStackVisitor);
};

void QuickExceptionHandler::DeoptimizeStack() {
  DCHECK(is_deoptimization_);
  if (kDebugExceptionDelivery) {
    self_->DumpStack(LOG(INFO) << "Deoptimizing: ");
  }

  DeoptimizeStackVisitor visitor(self_, context_, this);
  visitor.WalkStack(true);

  // Restore deoptimization exception
  self_->SetException(ThrowLocation(), Thread::GetDeoptimizationException());
}

// Unwinds all instrumentation stack frame prior to catch handler or upcall.
class InstrumentationStackVisitor : public StackVisitor {
 public:
  InstrumentationStackVisitor(Thread* self, bool is_deoptimization, size_t frame_depth)
      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
      : StackVisitor(self, nullptr),
        self_(self), frame_depth_(frame_depth),
        instrumentation_frames_to_pop_(0) {
    CHECK_NE(frame_depth_, kInvalidFrameDepth);
  }

  bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    size_t current_frame_depth = GetFrameDepth();
    if (current_frame_depth < frame_depth_) {
      CHECK(GetMethod() != nullptr);
      if (UNLIKELY(GetQuickInstrumentationExitPc() == GetReturnPc())) {
        ++instrumentation_frames_to_pop_;
      }
      return true;
    } else {
      // We reached the frame of the catch handler or the upcall.
      return false;
    }
  }

  size_t GetInstrumentationFramesToPop() const {
    return instrumentation_frames_to_pop_;
  }

 private:
  Thread* const self_;
  const size_t frame_depth_;
  size_t instrumentation_frames_to_pop_;

  DISALLOW_COPY_AND_ASSIGN(InstrumentationStackVisitor);
};

void QuickExceptionHandler::UpdateInstrumentationStack() {
  if (method_tracing_active_) {
    InstrumentationStackVisitor visitor(self_, is_deoptimization_, handler_frame_depth_);
    visitor.WalkStack(true);

    size_t instrumentation_frames_to_pop = visitor.GetInstrumentationFramesToPop();
    instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
    for (size_t i = 0; i < instrumentation_frames_to_pop; ++i) {
      instrumentation->PopMethodForUnwind(self_, is_deoptimization_);
    }
  }
}

void QuickExceptionHandler::DoLongJump() {
  // Place context back on thread so it will be available when we continue.
  self_->ReleaseLongJumpContext(context_);
  context_->SetSP(reinterpret_cast<uintptr_t>(handler_quick_frame_));
  CHECK_NE(handler_quick_frame_pc_, 0u);
  context_->SetPC(handler_quick_frame_pc_);
  context_->SmashCallerSaves();
  context_->DoLongJump();
}

}  // namespace art
<commit_msg>Fix deoptimization bugs<commit_after>/*
 * Copyright (C) 2014 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 "quick_exception_handler.h"

#include "arch/context.h"
#include "dex_instruction.h"
#include "entrypoints/entrypoint_utils.h"
#include "handle_scope-inl.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/throwable.h"
#include "verifier/method_verifier.h"

namespace art {

static constexpr bool kDebugExceptionDelivery = false;
static constexpr size_t kInvalidFrameDepth = 0xffffffff;

QuickExceptionHandler::QuickExceptionHandler(Thread* self, bool is_deoptimization)
  : self_(self), context_(self->GetLongJumpContext()), is_deoptimization_(is_deoptimization),
    method_tracing_active_(is_deoptimization ||
                           Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()),
    handler_quick_frame_(nullptr), handler_quick_frame_pc_(0), handler_method_(nullptr),
    handler_dex_pc_(0), clear_exception_(false), handler_frame_depth_(kInvalidFrameDepth) {
}

// Finds catch handler or prepares for deoptimization.
class CatchBlockStackVisitor FINAL : public StackVisitor {
 public:
  CatchBlockStackVisitor(Thread* self, Context* context, Handle<mirror::Throwable>* exception,
                         QuickExceptionHandler* exception_handler)
      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
      : StackVisitor(self, context), self_(self), exception_(exception),
        exception_handler_(exception_handler) {
  }

  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    mirror::ArtMethod* method = GetMethod();
    exception_handler_->SetHandlerFrameDepth(GetFrameDepth());
    if (method == nullptr) {
      // This is the upcall, we remember the frame and last pc so that we may long jump to them.
      exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
      exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
      uint32_t next_dex_pc;
      mirror::ArtMethod* next_art_method;
      bool has_next = GetNextMethodAndDexPc(&next_art_method, &next_dex_pc);
      // Report the method that did the down call as the handler.
      exception_handler_->SetHandlerDexPc(next_dex_pc);
      exception_handler_->SetHandlerMethod(next_art_method);
      if (!has_next) {
        // No next method? Check exception handler is set up for the unhandled exception handler
        // case.
        DCHECK_EQ(0U, exception_handler_->GetHandlerDexPc());
        DCHECK(nullptr == exception_handler_->GetHandlerMethod());
      }
      return false;  // End stack walk.
    }
    if (method->IsRuntimeMethod()) {
      // Ignore callee save method.
      DCHECK(method->IsCalleeSaveMethod());
      return true;
    }
    StackHandleScope<1> hs(self_);
    return HandleTryItems(hs.NewHandle(method));
  }

 private:
  bool HandleTryItems(Handle<mirror::ArtMethod> method)
      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    uint32_t dex_pc = DexFile::kDexNoIndex;
    if (!method->IsNative()) {
      dex_pc = GetDexPc();
    }
    if (dex_pc != DexFile::kDexNoIndex) {
      bool clear_exception = false;
      StackHandleScope<1> hs(Thread::Current());
      Handle<mirror::Class> to_find(hs.NewHandle((*exception_)->GetClass()));
      uint32_t found_dex_pc = mirror::ArtMethod::FindCatchBlock(method, to_find, dex_pc,
                                                                &clear_exception);
      exception_handler_->SetClearException(clear_exception);
      if (found_dex_pc != DexFile::kDexNoIndex) {
        exception_handler_->SetHandlerMethod(method.Get());
        exception_handler_->SetHandlerDexPc(found_dex_pc);
        exception_handler_->SetHandlerQuickFramePc(method->ToNativePc(found_dex_pc));
        exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
        return false;  // End stack walk.
      }
    }
    return true;  // Continue stack walk.
  }

  Thread* const self_;
  // The exception we're looking for the catch block of.
  Handle<mirror::Throwable>* exception_;
  // The quick exception handler we're visiting for.
  QuickExceptionHandler* const exception_handler_;

  DISALLOW_COPY_AND_ASSIGN(CatchBlockStackVisitor);
};

void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location,
                                      mirror::Throwable* exception,
                                      bool is_exception_reported) {
  DCHECK(!is_deoptimization_);
  if (kDebugExceptionDelivery) {
    mirror::String* msg = exception->GetDetailMessage();
    std::string str_msg(msg != nullptr ? msg->ToModifiedUtf8() : "");
    self_->DumpStack(LOG(INFO) << "Delivering exception: " << PrettyTypeOf(exception)
                     << ": " << str_msg << "\n");
  }
  StackHandleScope<1> hs(self_);
  Handle<mirror::Throwable> exception_ref(hs.NewHandle(exception));

  // Walk the stack to find catch handler or prepare for deoptimization.
  CatchBlockStackVisitor visitor(self_, context_, &exception_ref, this);
  visitor.WalkStack(true);

  if (kDebugExceptionDelivery) {
    if (handler_quick_frame_->AsMirrorPtr() == nullptr) {
      LOG(INFO) << "Handler is upcall";
    }
    if (handler_method_ != nullptr) {
      const DexFile& dex_file = *handler_method_->GetDeclaringClass()->GetDexCache()->GetDexFile();
      int line_number = dex_file.GetLineNumFromPC(handler_method_, handler_dex_pc_);
      LOG(INFO) << "Handler: " << PrettyMethod(handler_method_) << " (line: " << line_number << ")";
    }
  }
  if (clear_exception_) {
    // Exception was cleared as part of delivery.
    DCHECK(!self_->IsExceptionPending());
  } else {
    // Put exception back in root set with clear throw location.
    self_->SetException(ThrowLocation(), exception_ref.Get());
    self_->SetExceptionReportedToInstrumentation(is_exception_reported);
  }
  // The debugger may suspend this thread and walk its stack. Let's do this before popping
  // instrumentation frames.
  if (!is_exception_reported) {
    instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
    instrumentation->ExceptionCaughtEvent(self_, throw_location, handler_method_, handler_dex_pc_,
                                          exception_ref.Get());
      // We're not catching this exception but let's remind we already reported the exception above
      // to avoid reporting it twice.
      self_->SetExceptionReportedToInstrumentation(true);
  }
  bool caught_exception = (handler_method_ != nullptr && handler_dex_pc_ != DexFile::kDexNoIndex);
  if (caught_exception) {
    // We're catching this exception so we finish reporting it. We do it here to avoid doing it
    // in the compiled code.
    self_->SetExceptionReportedToInstrumentation(false);
  }
}

// Prepares deoptimization.
class DeoptimizeStackVisitor FINAL : public StackVisitor {
 public:
  DeoptimizeStackVisitor(Thread* self, Context* context, QuickExceptionHandler* exception_handler)
      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
      : StackVisitor(self, context), self_(self), exception_handler_(exception_handler),
        prev_shadow_frame_(nullptr) {
    CHECK(!self_->HasDeoptimizationShadowFrame());
  }

  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    exception_handler_->SetHandlerFrameDepth(GetFrameDepth());
    mirror::ArtMethod* method = GetMethod();
    if (method == nullptr) {
      // This is the upcall, we remember the frame and last pc so that we may long jump to them.
      exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
      exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
      return false;  // End stack walk.
    } else if (method->IsRuntimeMethod()) {
      // Ignore callee save method.
      DCHECK(method->IsCalleeSaveMethod());
      return true;
    } else {
      return HandleDeoptimization(method);
    }
  }

 private:
  static VRegKind GetVRegKind(uint16_t reg, const std::vector<int32_t>& kinds) {
    return static_cast<VRegKind>(kinds.at(reg * 2));
  }

  bool HandleDeoptimization(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    const DexFile::CodeItem* code_item = m->GetCodeItem();
    CHECK(code_item != nullptr);
    uint16_t num_regs = code_item->registers_size_;
    uint32_t dex_pc = GetDexPc();
    const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc);
    uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits();
    ShadowFrame* new_frame = ShadowFrame::Create(num_regs, nullptr, m, new_dex_pc);
    StackHandleScope<2> hs(self_);
    mirror::Class* declaring_class = m->GetDeclaringClass();
    Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
    Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
    verifier::MethodVerifier verifier(h_dex_cache->GetDexFile(), &h_dex_cache, &h_class_loader,
                                      &m->GetClassDef(), code_item, m->GetDexMethodIndex(), m,
                                      m->GetAccessFlags(), false, true, true);
    verifier.Verify();
    const std::vector<int32_t> kinds(verifier.DescribeVRegs(dex_pc));
    for (uint16_t reg = 0; reg < num_regs; ++reg) {
      VRegKind kind = GetVRegKind(reg, kinds);
      switch (kind) {
        case kUndefined:
          new_frame->SetVReg(reg, 0xEBADDE09);
          break;
        case kConstant:
          new_frame->SetVReg(reg, kinds.at((reg * 2) + 1));
          break;
        case kReferenceVReg:
          new_frame->SetVRegReference(reg,
                                      reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kind)));
          break;
        case kLongLoVReg:
          if (GetVRegKind(reg + 1, kinds) == kLongHiVReg) {
            // Treat it as a "long" register pair.
            new_frame->SetVRegLong(reg, GetVRegPair(m, reg, kLongLoVReg, kLongHiVReg));
          } else {
            new_frame->SetVReg(reg, GetVReg(m, reg, kind));
          }
          break;
        case kLongHiVReg:
          if (GetVRegKind(reg - 1, kinds) == kLongLoVReg) {
            // Nothing to do: we treated it as a "long" register pair.
          } else {
            new_frame->SetVReg(reg, GetVReg(m, reg, kind));
          }
          break;
        case kDoubleLoVReg:
          if (GetVRegKind(reg + 1, kinds) == kDoubleHiVReg) {
            // Treat it as a "double" register pair.
            new_frame->SetVRegLong(reg, GetVRegPair(m, reg, kDoubleLoVReg, kDoubleHiVReg));
          } else {
            new_frame->SetVReg(reg, GetVReg(m, reg, kind));
          }
          break;
        case kDoubleHiVReg:
          if (GetVRegKind(reg - 1, kinds) == kDoubleLoVReg) {
            // Nothing to do: we treated it as a "double" register pair.
          } else {
            new_frame->SetVReg(reg, GetVReg(m, reg, kind));
          }
          break;
        default:
          new_frame->SetVReg(reg, GetVReg(m, reg, kind));
          break;
      }
    }
    if (prev_shadow_frame_ != nullptr) {
      prev_shadow_frame_->SetLink(new_frame);
    } else {
      self_->SetDeoptimizationShadowFrame(new_frame);
    }
    prev_shadow_frame_ = new_frame;
    return true;
  }

  Thread* const self_;
  QuickExceptionHandler* const exception_handler_;
  ShadowFrame* prev_shadow_frame_;

  DISALLOW_COPY_AND_ASSIGN(DeoptimizeStackVisitor);
};

void QuickExceptionHandler::DeoptimizeStack() {
  DCHECK(is_deoptimization_);
  if (kDebugExceptionDelivery) {
    self_->DumpStack(LOG(INFO) << "Deoptimizing: ");
  }

  DeoptimizeStackVisitor visitor(self_, context_, this);
  visitor.WalkStack(true);

  // Restore deoptimization exception
  self_->SetException(ThrowLocation(), Thread::GetDeoptimizationException());
}

// Unwinds all instrumentation stack frame prior to catch handler or upcall.
class InstrumentationStackVisitor : public StackVisitor {
 public:
  InstrumentationStackVisitor(Thread* self, bool is_deoptimization, size_t frame_depth)
      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
      : StackVisitor(self, nullptr),
        self_(self), frame_depth_(frame_depth),
        instrumentation_frames_to_pop_(0) {
    CHECK_NE(frame_depth_, kInvalidFrameDepth);
  }

  bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    size_t current_frame_depth = GetFrameDepth();
    if (current_frame_depth < frame_depth_) {
      CHECK(GetMethod() != nullptr);
      if (UNLIKELY(GetQuickInstrumentationExitPc() == GetReturnPc())) {
        ++instrumentation_frames_to_pop_;
      }
      return true;
    } else {
      // We reached the frame of the catch handler or the upcall.
      return false;
    }
  }

  size_t GetInstrumentationFramesToPop() const {
    return instrumentation_frames_to_pop_;
  }

 private:
  Thread* const self_;
  const size_t frame_depth_;
  size_t instrumentation_frames_to_pop_;

  DISALLOW_COPY_AND_ASSIGN(InstrumentationStackVisitor);
};

void QuickExceptionHandler::UpdateInstrumentationStack() {
  if (method_tracing_active_) {
    InstrumentationStackVisitor visitor(self_, is_deoptimization_, handler_frame_depth_);
    visitor.WalkStack(true);

    size_t instrumentation_frames_to_pop = visitor.GetInstrumentationFramesToPop();
    instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
    for (size_t i = 0; i < instrumentation_frames_to_pop; ++i) {
      instrumentation->PopMethodForUnwind(self_, is_deoptimization_);
    }
  }
}

void QuickExceptionHandler::DoLongJump() {
  // Place context back on thread so it will be available when we continue.
  self_->ReleaseLongJumpContext(context_);
  context_->SetSP(reinterpret_cast<uintptr_t>(handler_quick_frame_));
  CHECK_NE(handler_quick_frame_pc_, 0u);
  context_->SetPC(handler_quick_frame_pc_);
  context_->SmashCallerSaves();
  context_->DoLongJump();
}

}  // namespace art
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: operators_new_delete.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: kz $ $Date: 2006-02-28 10:33:55 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifdef WNT /* avoid 'std::bad_alloc' unresolved externals */
#define _CRTIMP
#define _NTSDK
#endif /* WNT */

#ifndef INCLUDED_ALGORITHM
#include <algorithm>
#define INCLUDED_ALGORITHM
#endif

#ifndef INCLUDED_NEW
#include <new>
#define INCLUDED_NEW
#endif

#ifndef INCLUDED_STRING_H
#include <string.h>
#define INCLUDED_STRING_H
#endif

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#ifndef _RTL_ALLOC_H_
#include <rtl/alloc.h>
#endif

using std::nothrow_t;

// =======================================================================
// AllocatorTraits
// =======================================================================

namespace
{

struct AllocatorTraits
{
    typedef char const signature_type[8];
    const signature_type & m_signature;

    explicit AllocatorTraits (signature_type const & s) SAL_THROW(())
        : m_signature (s)
    {}

    std::size_t size (std::size_t n) const SAL_THROW(())
    {
        n = std::max(n, std::size_t(1));
#if OSL_DEBUG_LEVEL > 0
        n += sizeof(signature_type);
#endif  /* OSL_DEBUG_LEVEL  */
        return n;
    }

    void* init (void * p) const SAL_THROW(())
    {
#if OSL_DEBUG_LEVEL > 0
        memcpy (p, m_signature, sizeof(signature_type));
        p = static_cast<char*>(p) + sizeof(signature_type);
#endif  /* OSL_DEBUG_LEVEL */
        return p;
    }

    void* fini (void * p) const SAL_THROW(())
    {
#if OSL_DEBUG_LEVEL > 0
        p = static_cast<char*>(p) - sizeof(signature_type);
        if (memcmp (p, m_signature, sizeof(signature_type)) != 0)
        {
            OSL_ENSURE(0, "operator delete mismatch");
        }
#endif  /* OSL_DEBUG_LEVEL */
        return p;
    }
};

// =======================================================================

struct VectorTraits : public AllocatorTraits
{
    static const signature_type g_signature;

    VectorTraits() SAL_THROW(())
        : AllocatorTraits (g_signature)
    {}
};

struct ScalarTraits : public AllocatorTraits
{
    static const signature_type g_signature;

    ScalarTraits() SAL_THROW(())
        : AllocatorTraits (g_signature)
    {}
};

const AllocatorTraits::signature_type VectorTraits::g_signature = "new[]()";
const AllocatorTraits::signature_type ScalarTraits::g_signature = "new()  ";

} // anonymous namespace

// =======================================================================
// Allocator
// =======================================================================

static void default_handler (void)
{
    // Multithreading race in 'std::set_new_handler()' call sequence below.
    throw std::bad_alloc();
}

// =======================================================================

static void* allocate (
    std::size_t n, AllocatorTraits const & rTraits)
    SAL_THROW((std::bad_alloc))
{
    n = rTraits.size (n);
    for (;;)
    {
        void * p = rtl_allocateMemory (sal_Size(n));
        if (p != 0)
            return rTraits.init (p);

        std::new_handler d = default_handler, f = std::set_new_handler (d);
        if (f != d)
            std::set_new_handler (f);

        if (f == 0)
            throw std::bad_alloc();
        (*f)();
    }
}

// =======================================================================

static void* allocate (
    std::size_t n, AllocatorTraits const & rTraits, std::nothrow_t const &)
    SAL_THROW(())
{
    try
    {
        return allocate (n, rTraits);
    }
    catch (std::bad_alloc const &)
    {
        return (0);
    }
}

// =======================================================================

static void deallocate (void * p, AllocatorTraits const & rTraits)
    SAL_THROW(())
{
    if (p)
    {
        rtl_freeMemory (rTraits.fini(p));
    }
}

// =======================================================================
// T * p = new T; delete p;
// =======================================================================

void* SAL_CALL operator new (std::size_t n) throw (std::bad_alloc)
{
    return allocate (n, ScalarTraits());
}

// =======================================================================

void SAL_CALL operator delete (void * p) throw ()
{
    deallocate (p, ScalarTraits());
}

// =======================================================================
// T * p = new(nothrow) T; delete(nothrow) p;
// =======================================================================

void* SAL_CALL operator new (std::size_t n, std::nothrow_t const &) throw ()
{
    return allocate (n, ScalarTraits(), nothrow_t());
}

// =======================================================================

void SAL_CALL operator delete (void * p, std::nothrow_t const &) throw ()
{
    deallocate (p, ScalarTraits());
}

// =======================================================================
// T * p = new T[n]; delete[] p;
// =======================================================================

void* SAL_CALL operator new[] (std::size_t n) throw (std::bad_alloc)
{
    return allocate (n, VectorTraits());
}

// =======================================================================

void SAL_CALL operator delete[] (void * p) throw ()
{
    deallocate (p, VectorTraits());
}

// =======================================================================
// T * p = new(nothrow) T[n]; delete(nothrow)[] p;
// =======================================================================

void* SAL_CALL operator new[] (std::size_t n, std::nothrow_t const &) throw ()
{
    return allocate (n, VectorTraits(), nothrow_t());
}

// =======================================================================

void SAL_CALL operator delete[] (void * p, std::nothrow_t const &) throw ()
{
    deallocate (p, VectorTraits());
}

// =======================================================================
<commit_msg>INTEGRATION: CWS pchfix02 (1.5.76); FILE MERGED 2006/09/01 17:33:58 kaib 1.5.76.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: operators_new_delete.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 08:44:21 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sal.hxx"

#ifdef WNT /* avoid 'std::bad_alloc' unresolved externals */
#define _CRTIMP
#define _NTSDK
#endif /* WNT */

#ifndef INCLUDED_ALGORITHM
#include <algorithm>
#define INCLUDED_ALGORITHM
#endif

#ifndef INCLUDED_NEW
#include <new>
#define INCLUDED_NEW
#endif

#ifndef INCLUDED_STRING_H
#include <string.h>
#define INCLUDED_STRING_H
#endif

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#ifndef _RTL_ALLOC_H_
#include <rtl/alloc.h>
#endif

using std::nothrow_t;

// =======================================================================
// AllocatorTraits
// =======================================================================

namespace
{

struct AllocatorTraits
{
    typedef char const signature_type[8];
    const signature_type & m_signature;

    explicit AllocatorTraits (signature_type const & s) SAL_THROW(())
        : m_signature (s)
    {}

    std::size_t size (std::size_t n) const SAL_THROW(())
    {
        n = std::max(n, std::size_t(1));
#if OSL_DEBUG_LEVEL > 0
        n += sizeof(signature_type);
#endif  /* OSL_DEBUG_LEVEL  */
        return n;
    }

    void* init (void * p) const SAL_THROW(())
    {
#if OSL_DEBUG_LEVEL > 0
        memcpy (p, m_signature, sizeof(signature_type));
        p = static_cast<char*>(p) + sizeof(signature_type);
#endif  /* OSL_DEBUG_LEVEL */
        return p;
    }

    void* fini (void * p) const SAL_THROW(())
    {
#if OSL_DEBUG_LEVEL > 0
        p = static_cast<char*>(p) - sizeof(signature_type);
        if (memcmp (p, m_signature, sizeof(signature_type)) != 0)
        {
            OSL_ENSURE(0, "operator delete mismatch");
        }
#endif  /* OSL_DEBUG_LEVEL */
        return p;
    }
};

// =======================================================================

struct VectorTraits : public AllocatorTraits
{
    static const signature_type g_signature;

    VectorTraits() SAL_THROW(())
        : AllocatorTraits (g_signature)
    {}
};

struct ScalarTraits : public AllocatorTraits
{
    static const signature_type g_signature;

    ScalarTraits() SAL_THROW(())
        : AllocatorTraits (g_signature)
    {}
};

const AllocatorTraits::signature_type VectorTraits::g_signature = "new[]()";
const AllocatorTraits::signature_type ScalarTraits::g_signature = "new()  ";

} // anonymous namespace

// =======================================================================
// Allocator
// =======================================================================

static void default_handler (void)
{
    // Multithreading race in 'std::set_new_handler()' call sequence below.
    throw std::bad_alloc();
}

// =======================================================================

static void* allocate (
    std::size_t n, AllocatorTraits const & rTraits)
    SAL_THROW((std::bad_alloc))
{
    n = rTraits.size (n);
    for (;;)
    {
        void * p = rtl_allocateMemory (sal_Size(n));
        if (p != 0)
            return rTraits.init (p);

        std::new_handler d = default_handler, f = std::set_new_handler (d);
        if (f != d)
            std::set_new_handler (f);

        if (f == 0)
            throw std::bad_alloc();
        (*f)();
    }
}

// =======================================================================

static void* allocate (
    std::size_t n, AllocatorTraits const & rTraits, std::nothrow_t const &)
    SAL_THROW(())
{
    try
    {
        return allocate (n, rTraits);
    }
    catch (std::bad_alloc const &)
    {
        return (0);
    }
}

// =======================================================================

static void deallocate (void * p, AllocatorTraits const & rTraits)
    SAL_THROW(())
{
    if (p)
    {
        rtl_freeMemory (rTraits.fini(p));
    }
}

// =======================================================================
// T * p = new T; delete p;
// =======================================================================

void* SAL_CALL operator new (std::size_t n) throw (std::bad_alloc)
{
    return allocate (n, ScalarTraits());
}

// =======================================================================

void SAL_CALL operator delete (void * p) throw ()
{
    deallocate (p, ScalarTraits());
}

// =======================================================================
// T * p = new(nothrow) T; delete(nothrow) p;
// =======================================================================

void* SAL_CALL operator new (std::size_t n, std::nothrow_t const &) throw ()
{
    return allocate (n, ScalarTraits(), nothrow_t());
}

// =======================================================================

void SAL_CALL operator delete (void * p, std::nothrow_t const &) throw ()
{
    deallocate (p, ScalarTraits());
}

// =======================================================================
// T * p = new T[n]; delete[] p;
// =======================================================================

void* SAL_CALL operator new[] (std::size_t n) throw (std::bad_alloc)
{
    return allocate (n, VectorTraits());
}

// =======================================================================

void SAL_CALL operator delete[] (void * p) throw ()
{
    deallocate (p, VectorTraits());
}

// =======================================================================
// T * p = new(nothrow) T[n]; delete(nothrow)[] p;
// =======================================================================

void* SAL_CALL operator new[] (std::size_t n, std::nothrow_t const &) throw ()
{
    return allocate (n, VectorTraits(), nothrow_t());
}

// =======================================================================

void SAL_CALL operator delete[] (void * p, std::nothrow_t const &) throw ()
{
    deallocate (p, VectorTraits());
}

// =======================================================================
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_X86_FAULTS_HH__
#define __ARCH_X86_FAULTS_HH__

#include "base/misc.hh"
#include "sim/faults.hh"

namespace X86ISA
{
    // Base class for all x86 "faults" where faults is in the m5 sense
    class X86FaultBase : public FaultBase
    {
      protected:
        const char * faultName;
        const char * mnem;
        uint64_t errorCode;

        X86FaultBase(const char * _faultName, const char * _mnem,
                uint64_t _errorCode = 0) :
            faultName(_faultName), mnem(_mnem), errorCode(_errorCode)
        {
        }

        const char * name() const
        {
            return faultName;
        }

        virtual bool isBenign()
        {
            return true;
        }

        virtual const char * mnemonic() const
        {
            return mnem;
        }
    };

    // Base class for x86 faults which behave as if the underlying instruction
    // didn't happen.
    class X86Fault : public X86FaultBase
    {
      protected:
        X86Fault(const char * name, const char * mnem,
                uint64_t _errorCode = 0) :
            X86FaultBase(name, mnem, _errorCode)
        {}
    };

    // Base class for x86 traps which behave as if the underlying instruction
    // completed.
    class X86Trap : public X86FaultBase
    {
      protected:
        X86Trap(const char * name, const char * mnem,
                uint64_t _errorCode = 0) :
            X86FaultBase(name, mnem, _errorCode)
        {}

#if FULL_SYSTEM
        void invoke(ThreadContext * tc);
#endif
    };

    // Base class for x86 aborts which seem to be catastrophic failures.
    class X86Abort : public X86FaultBase
    {
      protected:
        X86Abort(const char * name, const char * mnem,
                uint64_t _errorCode = 0) :
            X86FaultBase(name, mnem, _errorCode)
        {}

#if FULL_SYSTEM
        void invoke(ThreadContext * tc);
#endif
    };

    // Base class for x86 interrupts.
    class X86Interrupt : public X86FaultBase
    {
      protected:
        uint8_t vector;
        X86Interrupt(const char * name, const char * mnem, uint8_t _vector,
                uint64_t _errorCode = 0) :
            X86FaultBase(name, mnem, _errorCode), vector(_vector)
        {}

#if FULL_SYSTEM
        void invoke(ThreadContext * tc);
#endif
    };

    class UnimpInstFault : public FaultBase
    {
      public:
        const char * name() const
        {
            return "unimplemented_micro";
        }

        void invoke(ThreadContext * tc)
        {
            panic("Unimplemented instruction!");
        }
    };

    static inline Fault genMachineCheckFault()
    {
        panic("Machine check fault not implemented in x86!\n");
    }

    // Below is a summary of the interrupt/exception information in the
    // architecture manuals.

    // Class  |  Type    | vector |               Cause                 | mnem
    //------------------------------------------------------------------------
    //Contrib   Fault     0         Divide-by-Zero-Error                  #DE
    //Benign    Either    1         Debug                                 #DB
    //Benign    Interrupt 2         Non-Maskable-Interrupt                #NMI
    //Benign    Trap      3         Breakpoint                            #BP
    //Benign    Trap      4         Overflow                              #OF
    //Benign    Fault     5         Bound-Range                           #BR
    //Benign    Fault     6         Invalid-Opcode                        #UD
    //Benign    Fault     7         Device-Not-Available                  #NM
    //Benign    Abort     8         Double-Fault                          #DF
    //                    9         Coprocessor-Segment-Overrun
    //Contrib   Fault     10        Invalid-TSS                           #TS
    //Contrib   Fault     11        Segment-Not-Present                   #NP
    //Contrib   Fault     12        Stack                                 #SS
    //Contrib   Fault     13        General-Protection                    #GP
    //Either    Fault     14        Page-Fault                            #PF
    //                    15        Reserved
    //Benign    Fault     16        x87 Floating-Point Exception Pending  #MF
    //Benign    Fault     17        Alignment-Check                       #AC
    //Benign    Abort     18        Machine-Check                         #MC
    //Benign    Fault     19        SIMD Floating-Point                   #XF
    //                    20-29     Reserved
    //Contrib   ?         30        Security Exception                    #SX
    //                    31        Reserved
    //Benign    Interrupt 0-255     External Interrupts                   #INTR
    //Benign    Interrupt 0-255     Software Interrupts                   INTn

    class DivideByZero : public X86Fault
    {
      public:
        DivideByZero() :
            X86Fault("Divide-by-Zero-Error", "#DE")
        {}
    };

    class DebugException : public X86FaultBase
    {
      public:
        DebugException() :
            X86FaultBase("Debug", "#DB")
        {}
    };

    class NonMaskableInterrupt : public X86Interrupt
    {
      public:
        NonMaskableInterrupt(uint8_t _vector) :
            X86Interrupt("Non Maskable Interrupt", "#NMI", _vector)
        {}
    };

    class Breakpoint : public X86Trap
    {
      public:
        Breakpoint() :
            X86Trap("Breakpoint", "#BP")
        {}
    };

    class OverflowTrap : public X86Trap
    {
      public:
        OverflowTrap() :
            X86Trap("Overflow", "#OF")
        {}
    };

    class BoundRange : public X86Fault
    {
      public:
        BoundRange() :
            X86Fault("Bound-Range", "#BR")
        {}
    };

    class InvalidOpcode : public X86Fault
    {
      public:
        InvalidOpcode() :
            X86Fault("Invalid-Opcode", "#UD")
        {}
    };

    class DeviceNotAvailable : public X86Fault
    {
      public:
        DeviceNotAvailable() :
            X86Fault("Device-Not-Available", "#NM")
        {}
    };

    class DoubleFault : public X86Abort
    {
      public:
        DoubleFault() :
            X86Abort("Double-Fault", "#DF")
        {}
    };

    class InvalidTSS : public X86Fault
    {
      public:
        InvalidTSS() :
            X86Fault("Invalid-TSS", "#TS")
        {}
    };

    class SegmentNotPresent : public X86Fault
    {
      public:
        SegmentNotPresent() :
            X86Fault("Segment-Not-Present", "#NP")
        {}
    };

    class StackFault : public X86Fault
    {
      public:
        StackFault() :
            X86Fault("Stack", "#SS")
        {}
    };

    class GeneralProtection : public X86Fault
    {
      public:
        GeneralProtection(uint64_t _errorCode) :
            X86Fault("General-Protection", "#GP", _errorCode)
        {}
    };

    class PageFault : public X86Fault
    {
      public:
        PageFault() :
            X86Fault("Page-Fault", "#PF")
        {}
    };

    class X87FpExceptionPending : public X86Fault
    {
      public:
        X87FpExceptionPending() :
            X86Fault("x87 Floating-Point Exception Pending", "#MF")
        {}
    };

    class AlignmentCheck : public X86Fault
    {
      public:
        AlignmentCheck() :
            X86Fault("Alignment-Check", "#AC")
        {}
    };

    class MachineCheck : public X86Abort
    {
      public:
        MachineCheck() :
            X86Abort("Machine-Check", "#MC")
        {}
    };

    class SIMDFloatingPointFault : public X86Fault
    {
      public:
        SIMDFloatingPointFault() :
            X86Fault("SIMD Floating-Point", "#XF")
        {}
    };

    class SecurityException : public X86FaultBase
    {
      public:
        SecurityException() :
            X86FaultBase("Security Exception", "#SX")
        {}
    };

    class ExternalInterrupt : public X86Interrupt
    {
      public:
        ExternalInterrupt(uint8_t _vector) :
            X86Interrupt("External Interrupt", "#INTR", _vector)
        {}
    };

    class SystemManagementInterrupt : public X86Interrupt
    {
      public:
        SystemManagementInterrupt() :
            X86Interrupt("System Management Interrupt", "#SMI", 0)
        {}
    };

    class InitInterrupt : public X86Interrupt
    {
        uint8_t vector;
      public:
        InitInterrupt(uint8_t _vector) :
            X86Interrupt("INIT Interrupt", "#INIT", _vector)
        {}
    };

    class SoftwareInterrupt : public X86Interrupt
    {
      public:
        SoftwareInterrupt(uint8_t _vector) :
            X86Interrupt("Software Interrupt", "INTn", _vector)
        {}
    };

    // These faults aren't part of the ISA definition. They trigger filling
    // the tlb on a miss and are to take the place of a hardware table walker.
    class FakeITLBFault : public X86Fault
    {
      protected:
        Addr vaddr;
      public:
        FakeITLBFault(Addr _vaddr) :
            X86Fault("fake instruction tlb fault", "itlb"),
            vaddr(_vaddr)
        {}

        void invoke(ThreadContext * tc);
    };

    class FakeDTLBFault : public X86Fault
    {
      protected:
        Addr vaddr;
      public:
        FakeDTLBFault(Addr _vaddr) :
            X86Fault("fake data tlb fault", "dtlb"),
            vaddr(_vaddr)
        {}

        void invoke(ThreadContext * tc);
    };
};

#endif // __ARCH_X86_FAULTS_HH__
<commit_msg>X86: Panic when an unimplemented fault is invoked, rather than spinning forever<commit_after>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_X86_FAULTS_HH__
#define __ARCH_X86_FAULTS_HH__

#include "base/misc.hh"
#include "sim/faults.hh"

namespace X86ISA
{
    // Base class for all x86 "faults" where faults is in the m5 sense
    class X86FaultBase : public FaultBase
    {
      protected:
        const char * faultName;
        const char * mnem;
        uint64_t errorCode;

        X86FaultBase(const char * _faultName, const char * _mnem,
                uint64_t _errorCode = 0) :
            faultName(_faultName), mnem(_mnem), errorCode(_errorCode)
        {
        }

        const char * name() const
        {
            return faultName;
        }

        virtual bool isBenign()
        {
            return true;
        }

        virtual const char * mnemonic() const
        {
            return mnem;
        }

        void
        invoke(ThreadContext * tc)
        {
            panic("Unimplemented fault %s.\n", name());
        }
    };

    // Base class for x86 faults which behave as if the underlying instruction
    // didn't happen.
    class X86Fault : public X86FaultBase
    {
      protected:
        X86Fault(const char * name, const char * mnem,
                uint64_t _errorCode = 0) :
            X86FaultBase(name, mnem, _errorCode)
        {}
    };

    // Base class for x86 traps which behave as if the underlying instruction
    // completed.
    class X86Trap : public X86FaultBase
    {
      protected:
        X86Trap(const char * name, const char * mnem,
                uint64_t _errorCode = 0) :
            X86FaultBase(name, mnem, _errorCode)
        {}

#if FULL_SYSTEM
        void invoke(ThreadContext * tc);
#endif
    };

    // Base class for x86 aborts which seem to be catastrophic failures.
    class X86Abort : public X86FaultBase
    {
      protected:
        X86Abort(const char * name, const char * mnem,
                uint64_t _errorCode = 0) :
            X86FaultBase(name, mnem, _errorCode)
        {}

#if FULL_SYSTEM
        void invoke(ThreadContext * tc);
#endif
    };

    // Base class for x86 interrupts.
    class X86Interrupt : public X86FaultBase
    {
      protected:
        uint8_t vector;
        X86Interrupt(const char * name, const char * mnem, uint8_t _vector,
                uint64_t _errorCode = 0) :
            X86FaultBase(name, mnem, _errorCode), vector(_vector)
        {}

#if FULL_SYSTEM
        void invoke(ThreadContext * tc);
#endif
    };

    class UnimpInstFault : public FaultBase
    {
      public:
        const char * name() const
        {
            return "unimplemented_micro";
        }

        void invoke(ThreadContext * tc)
        {
            panic("Unimplemented instruction!");
        }
    };

    static inline Fault genMachineCheckFault()
    {
        panic("Machine check fault not implemented in x86!\n");
    }

    // Below is a summary of the interrupt/exception information in the
    // architecture manuals.

    // Class  |  Type    | vector |               Cause                 | mnem
    //------------------------------------------------------------------------
    //Contrib   Fault     0         Divide-by-Zero-Error                  #DE
    //Benign    Either    1         Debug                                 #DB
    //Benign    Interrupt 2         Non-Maskable-Interrupt                #NMI
    //Benign    Trap      3         Breakpoint                            #BP
    //Benign    Trap      4         Overflow                              #OF
    //Benign    Fault     5         Bound-Range                           #BR
    //Benign    Fault     6         Invalid-Opcode                        #UD
    //Benign    Fault     7         Device-Not-Available                  #NM
    //Benign    Abort     8         Double-Fault                          #DF
    //                    9         Coprocessor-Segment-Overrun
    //Contrib   Fault     10        Invalid-TSS                           #TS
    //Contrib   Fault     11        Segment-Not-Present                   #NP
    //Contrib   Fault     12        Stack                                 #SS
    //Contrib   Fault     13        General-Protection                    #GP
    //Either    Fault     14        Page-Fault                            #PF
    //                    15        Reserved
    //Benign    Fault     16        x87 Floating-Point Exception Pending  #MF
    //Benign    Fault     17        Alignment-Check                       #AC
    //Benign    Abort     18        Machine-Check                         #MC
    //Benign    Fault     19        SIMD Floating-Point                   #XF
    //                    20-29     Reserved
    //Contrib   ?         30        Security Exception                    #SX
    //                    31        Reserved
    //Benign    Interrupt 0-255     External Interrupts                   #INTR
    //Benign    Interrupt 0-255     Software Interrupts                   INTn

    class DivideByZero : public X86Fault
    {
      public:
        DivideByZero() :
            X86Fault("Divide-by-Zero-Error", "#DE")
        {}
    };

    class DebugException : public X86FaultBase
    {
      public:
        DebugException() :
            X86FaultBase("Debug", "#DB")
        {}
    };

    class NonMaskableInterrupt : public X86Interrupt
    {
      public:
        NonMaskableInterrupt(uint8_t _vector) :
            X86Interrupt("Non Maskable Interrupt", "#NMI", _vector)
        {}
    };

    class Breakpoint : public X86Trap
    {
      public:
        Breakpoint() :
            X86Trap("Breakpoint", "#BP")
        {}
    };

    class OverflowTrap : public X86Trap
    {
      public:
        OverflowTrap() :
            X86Trap("Overflow", "#OF")
        {}
    };

    class BoundRange : public X86Fault
    {
      public:
        BoundRange() :
            X86Fault("Bound-Range", "#BR")
        {}
    };

    class InvalidOpcode : public X86Fault
    {
      public:
        InvalidOpcode() :
            X86Fault("Invalid-Opcode", "#UD")
        {}
    };

    class DeviceNotAvailable : public X86Fault
    {
      public:
        DeviceNotAvailable() :
            X86Fault("Device-Not-Available", "#NM")
        {}
    };

    class DoubleFault : public X86Abort
    {
      public:
        DoubleFault() :
            X86Abort("Double-Fault", "#DF")
        {}
    };

    class InvalidTSS : public X86Fault
    {
      public:
        InvalidTSS() :
            X86Fault("Invalid-TSS", "#TS")
        {}
    };

    class SegmentNotPresent : public X86Fault
    {
      public:
        SegmentNotPresent() :
            X86Fault("Segment-Not-Present", "#NP")
        {}
    };

    class StackFault : public X86Fault
    {
      public:
        StackFault() :
            X86Fault("Stack", "#SS")
        {}
    };

    class GeneralProtection : public X86Fault
    {
      public:
        GeneralProtection(uint64_t _errorCode) :
            X86Fault("General-Protection", "#GP", _errorCode)
        {}
    };

    class PageFault : public X86Fault
    {
      public:
        PageFault() :
            X86Fault("Page-Fault", "#PF")
        {}
    };

    class X87FpExceptionPending : public X86Fault
    {
      public:
        X87FpExceptionPending() :
            X86Fault("x87 Floating-Point Exception Pending", "#MF")
        {}
    };

    class AlignmentCheck : public X86Fault
    {
      public:
        AlignmentCheck() :
            X86Fault("Alignment-Check", "#AC")
        {}
    };

    class MachineCheck : public X86Abort
    {
      public:
        MachineCheck() :
            X86Abort("Machine-Check", "#MC")
        {}
    };

    class SIMDFloatingPointFault : public X86Fault
    {
      public:
        SIMDFloatingPointFault() :
            X86Fault("SIMD Floating-Point", "#XF")
        {}
    };

    class SecurityException : public X86FaultBase
    {
      public:
        SecurityException() :
            X86FaultBase("Security Exception", "#SX")
        {}
    };

    class ExternalInterrupt : public X86Interrupt
    {
      public:
        ExternalInterrupt(uint8_t _vector) :
            X86Interrupt("External Interrupt", "#INTR", _vector)
        {}
    };

    class SystemManagementInterrupt : public X86Interrupt
    {
      public:
        SystemManagementInterrupt() :
            X86Interrupt("System Management Interrupt", "#SMI", 0)
        {}
    };

    class InitInterrupt : public X86Interrupt
    {
        uint8_t vector;
      public:
        InitInterrupt(uint8_t _vector) :
            X86Interrupt("INIT Interrupt", "#INIT", _vector)
        {}
    };

    class SoftwareInterrupt : public X86Interrupt
    {
      public:
        SoftwareInterrupt(uint8_t _vector) :
            X86Interrupt("Software Interrupt", "INTn", _vector)
        {}
    };

    // These faults aren't part of the ISA definition. They trigger filling
    // the tlb on a miss and are to take the place of a hardware table walker.
    class FakeITLBFault : public X86Fault
    {
      protected:
        Addr vaddr;
      public:
        FakeITLBFault(Addr _vaddr) :
            X86Fault("fake instruction tlb fault", "itlb"),
            vaddr(_vaddr)
        {}

        void invoke(ThreadContext * tc);
    };

    class FakeDTLBFault : public X86Fault
    {
      protected:
        Addr vaddr;
      public:
        FakeDTLBFault(Addr _vaddr) :
            X86Fault("fake data tlb fault", "dtlb"),
            vaddr(_vaddr)
        {}

        void invoke(ThreadContext * tc);
    };
};

#endif // __ARCH_X86_FAULTS_HH__
<|endoftext|>


<commit_before>#include "Globals.h"
#include "Application.h"
#include "ModuleSceneIntro.h"
#include "Primitive.h"
#include "PhysBody3D.h"
#include "imgui.h"
#include "glut\glut.h"

#include <stdlib.h>
#include <time.h>

#define RADIUS 44

ModuleSceneIntro::ModuleSceneIntro(Application* app, bool start_enabled) : Module(app, start_enabled)
{
}

ModuleSceneIntro::~ModuleSceneIntro()
{}

// Load assets
bool ModuleSceneIntro::Start()
{
	LOG("Loading Intro assets");
	bool ret = true;

	srand(time(NULL));

	//App->audio->PlayMusic("F-Zero_-_Mute_City.ogg");

	App->camera->Move(vec3(1.0f, 1.0f, 0.0f));
	App->camera->LookAt(vec3(0, 0, 0));

	ImGuiIO& io = ImGui::GetIO();
	io.DisplaySize.x = 1920.0f;
	io.DisplaySize.y = 1280.0f;
	io.RenderDrawListsFn = nullptr;

	unsigned char* pixels;
	int width, height;
	io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
	SDL_Surface* font = SDL_CreateRGBSurfaceFrom(pixels, width, height, 32, (4 * width), 0, 0, 0, 0);

	io.Fonts->TexID = (void*)SDL_CreateTextureFromSurface(SDL_GetRenderer(App->window->window), font);

	return ret;
}

// Load assets
bool ModuleSceneIntro::CleanUp()
{
	LOG("Unloading Intro scene");

	return true;
}

// Update
update_status ModuleSceneIntro::Update(float dt)
{
	/*Plane p(0, 1, 0, 0);
	p.axis = true;
	p.Render();*/

	ImGui::NewFrame();

	if (App->input->GetKey(SDL_SCANCODE_R) == KEY_DOWN) ImGui::ShowTestWindow();

	return UPDATE_CONTINUE;
}
<commit_msg>Small changes<commit_after>#include "Globals.h"
#include "Application.h"
#include "ModuleSceneIntro.h"
#include "Primitive.h"
#include "PhysBody3D.h"
#include "imgui.h"
#include "glut\glut.h"

#include <stdlib.h>
#include <time.h>

#define RADIUS 44

ModuleSceneIntro::ModuleSceneIntro(Application* app, bool start_enabled) : Module(app, start_enabled)
{
}

ModuleSceneIntro::~ModuleSceneIntro()
{}

// Load assets
bool ModuleSceneIntro::Start()
{
	LOG("Loading Intro assets");
	bool ret = true;

	srand(time(NULL));

	//App->audio->PlayMusic("F-Zero_-_Mute_City.ogg");

	App->camera->Move(vec3(1.0f, 1.0f, 0.0f));
	App->camera->LookAt(vec3(0, 0, 0));

	ImGuiIO& io = ImGui::GetIO();
	io.DisplaySize.x = 1920.0f;
	io.DisplaySize.y = 1280.0f;
	io.RenderDrawListsFn = nullptr;

	unsigned char* pixels;
	int width, height;
	io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
	SDL_Surface* font = SDL_CreateRGBSurfaceFrom(pixels, width, height, 32, (4 * width), 0, 0, 0, 0);

	io.Fonts->TexID = (void*)SDL_CreateTextureFromSurface(SDL_GetRenderer(App->window->window), font);

	return ret;
}

// Load assets
bool ModuleSceneIntro::CleanUp()
{
	LOG("Unloading Intro scene");

	return true;
}

// Update
update_status ModuleSceneIntro::Update(float dt)
{
	Plane p(0, 1, 0, 0);
	p.axis = true;
	p.Render();

	ImGui::NewFrame();

	if (App->input->GetKey(SDL_SCANCODE_R) == KEY_DOWN) {
		ImVec2 aux(0, 0);
		ImGui::SetNextWindowPos(aux);
		ImGui::ShowTestWindow();
	}

	return UPDATE_CONTINUE;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 */

#include "base/flags.hh"
#include "base/stats/types.hh"

namespace Stats {

typedef uint16_t FlagsType;
typedef ::Flags<FlagsType> Flags;

/** Nothing extra to print. */
const FlagsType none =          0x0000;
/** This Stat is Initialized */
const FlagsType init =          0x0001;
/** Print this stat. */
const FlagsType print =         0x0002;
/** Print the total. */
const FlagsType total =         0x0010;
/** Print the percent of the total that this entry represents. */
const FlagsType pdf =           0x0020;
/** Print the cumulative percentage of total upto this entry. */
const FlagsType cdf =           0x0040;
/** Print the distribution. */
const FlagsType dist =          0x0080;
/** Don't print if this is zero. */
const FlagsType nozero =        0x0100;
/** Don't print if this is NAN */
const FlagsType nonan =         0x0200;
/** Used for SS compatability. */
const FlagsType __substat =     0x8000;

/** Mask of flags that can't be set directly */
const FlagsType __reserved =    init | print | __substat;

struct StorageParams
{
    virtual ~StorageParams();
};

struct Visit;

class Info
{
  public:
    /** The name of the stat. */
    std::string name;
    /** The description of the stat. */
    std::string desc;
    /** The formatting flags. */
    Flags flags;
    /** The display precision. */
    int precision;
    /** A pointer to a prerequisite Stat. */
    const Info *prereq;
    /**
     * A unique stat ID for each stat in the simulator.
     * Can be used externally for lookups as well as for debugging.
     */
    static int id_count;
    int id;

  public:
    const StorageParams *storageParams;

  public:
    Info();
    virtual ~Info();

    /** Set the name of this statistic */
    void setName(const std::string &name);

    /**
     * Check that this stat has been set up properly and is ready for
     * use
     * @return true for success
     */
    virtual bool check() const = 0;
    bool baseCheck() const;

    /**
     * Enable the stat for use
     */
    virtual void enable();

    /**
     * Prepare the stat for dumping.
     */
    virtual void prepare() = 0;

    /**
     * Reset the stat to the default state.
     */
    virtual void reset() = 0;

    /**
     * @return true if this stat has a value and satisfies its
     * requirement as a prereq
     */
    virtual bool zero() const = 0;

    /**
     * Visitor entry for outputing statistics data
     */
    virtual void visit(Visit &visitor) = 0;

    /**
     * Checks if the first stat's name is alphabetically less than the second.
     * This function breaks names up at periods and considers each subname
     * separately.
     * @param stat1 The first stat.
     * @param stat2 The second stat.
     * @return stat1's name is alphabetically before stat2's
     */
    static bool less(Info *stat1, Info *stat2);
};

class ScalarInfo : public Info
{
  public:
    virtual Counter value() const = 0;
    virtual Result result() const = 0;
    virtual Result total() const = 0;
};

class VectorInfo : public Info
{
  public:
    /** Names and descriptions of subfields. */
    std::vector<std::string> subnames;
    std::vector<std::string> subdescs;

  public:
    void enable();

  public:
    virtual size_type size() const = 0;
    virtual const VCounter &value() const = 0;
    virtual const VResult &result() const = 0;
    virtual Result total() const = 0;
};

struct DistData
{
    Counter min_val;
    Counter max_val;
    Counter underflow;
    Counter overflow;
    VCounter cvec;
    Counter sum;
    Counter squares;
    Counter samples;
};

struct DistParams : public StorageParams
{
    const bool fancy;

    /** The minimum value to track. */
    Counter min;
    /** The maximum value to track. */
    Counter max;
    /** The number of entries in each bucket. */
    Counter bucket_size;
    /** The number of buckets. Equal to (max-min)/bucket_size. */
    size_type buckets;

    explicit DistParams(bool f) : fancy(f) {}
};

class DistInfo : public Info
{
  public:
    /** Local storage for the entry values, used for printing. */
    DistData data;
};

class VectorDistInfo : public Info
{
  public:
    std::vector<DistData> data;

    /** Names and descriptions of subfields. */
    std::vector<std::string> subnames;
    std::vector<std::string> subdescs;
    void enable();

  protected:
    /** Local storage for the entry values, used for printing. */
    mutable VResult rvec;

  public:
    virtual size_type size() const = 0;
};

class Vector2dInfo : public Info
{
  public:
    /** Names and descriptions of subfields. */
    std::vector<std::string> subnames;
    std::vector<std::string> subdescs;
    std::vector<std::string> y_subnames;

    size_type x;
    size_type y;

    /** Local storage for the entry values, used for printing. */
    mutable VCounter cvec;

    void enable();
};

class FormulaInfo : public VectorInfo
{
  public:
    virtual std::string str() const = 0;
};

/* namespace Stats */ }
<commit_msg>scons: add include guards to info.hh<commit_after>/*
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 */

#ifndef __BASE_STATS_INFO_HH__
#define __BASE_STATS_INFO_HH__

#include "base/flags.hh"
#include "base/stats/types.hh"

namespace Stats {

typedef uint16_t FlagsType;
typedef ::Flags<FlagsType> Flags;

/** Nothing extra to print. */
const FlagsType none =          0x0000;
/** This Stat is Initialized */
const FlagsType init =          0x0001;
/** Print this stat. */
const FlagsType print =         0x0002;
/** Print the total. */
const FlagsType total =         0x0010;
/** Print the percent of the total that this entry represents. */
const FlagsType pdf =           0x0020;
/** Print the cumulative percentage of total upto this entry. */
const FlagsType cdf =           0x0040;
/** Print the distribution. */
const FlagsType dist =          0x0080;
/** Don't print if this is zero. */
const FlagsType nozero =        0x0100;
/** Don't print if this is NAN */
const FlagsType nonan =         0x0200;
/** Used for SS compatability. */
const FlagsType __substat =     0x8000;

/** Mask of flags that can't be set directly */
const FlagsType __reserved =    init | print | __substat;

struct StorageParams
{
    virtual ~StorageParams();
};

struct Visit;

class Info
{
  public:
    /** The name of the stat. */
    std::string name;
    /** The description of the stat. */
    std::string desc;
    /** The formatting flags. */
    Flags flags;
    /** The display precision. */
    int precision;
    /** A pointer to a prerequisite Stat. */
    const Info *prereq;
    /**
     * A unique stat ID for each stat in the simulator.
     * Can be used externally for lookups as well as for debugging.
     */
    static int id_count;
    int id;

  public:
    const StorageParams *storageParams;

  public:
    Info();
    virtual ~Info();

    /** Set the name of this statistic */
    void setName(const std::string &name);

    /**
     * Check that this stat has been set up properly and is ready for
     * use
     * @return true for success
     */
    virtual bool check() const = 0;
    bool baseCheck() const;

    /**
     * Enable the stat for use
     */
    virtual void enable();

    /**
     * Prepare the stat for dumping.
     */
    virtual void prepare() = 0;

    /**
     * Reset the stat to the default state.
     */
    virtual void reset() = 0;

    /**
     * @return true if this stat has a value and satisfies its
     * requirement as a prereq
     */
    virtual bool zero() const = 0;

    /**
     * Visitor entry for outputing statistics data
     */
    virtual void visit(Visit &visitor) = 0;

    /**
     * Checks if the first stat's name is alphabetically less than the second.
     * This function breaks names up at periods and considers each subname
     * separately.
     * @param stat1 The first stat.
     * @param stat2 The second stat.
     * @return stat1's name is alphabetically before stat2's
     */
    static bool less(Info *stat1, Info *stat2);
};

class ScalarInfo : public Info
{
  public:
    virtual Counter value() const = 0;
    virtual Result result() const = 0;
    virtual Result total() const = 0;
};

class VectorInfo : public Info
{
  public:
    /** Names and descriptions of subfields. */
    std::vector<std::string> subnames;
    std::vector<std::string> subdescs;

  public:
    void enable();

  public:
    virtual size_type size() const = 0;
    virtual const VCounter &value() const = 0;
    virtual const VResult &result() const = 0;
    virtual Result total() const = 0;
};

struct DistData
{
    Counter min_val;
    Counter max_val;
    Counter underflow;
    Counter overflow;
    VCounter cvec;
    Counter sum;
    Counter squares;
    Counter samples;
};

struct DistParams : public StorageParams
{
    const bool fancy;

    /** The minimum value to track. */
    Counter min;
    /** The maximum value to track. */
    Counter max;
    /** The number of entries in each bucket. */
    Counter bucket_size;
    /** The number of buckets. Equal to (max-min)/bucket_size. */
    size_type buckets;

    explicit DistParams(bool f) : fancy(f) {}
};

class DistInfo : public Info
{
  public:
    /** Local storage for the entry values, used for printing. */
    DistData data;
};

class VectorDistInfo : public Info
{
  public:
    std::vector<DistData> data;

    /** Names and descriptions of subfields. */
    std::vector<std::string> subnames;
    std::vector<std::string> subdescs;
    void enable();

  protected:
    /** Local storage for the entry values, used for printing. */
    mutable VResult rvec;

  public:
    virtual size_type size() const = 0;
};

class Vector2dInfo : public Info
{
  public:
    /** Names and descriptions of subfields. */
    std::vector<std::string> subnames;
    std::vector<std::string> subdescs;
    std::vector<std::string> y_subnames;

    size_type x;
    size_type y;

    /** Local storage for the entry values, used for printing. */
    mutable VCounter cvec;

    void enable();
};

class FormulaInfo : public VectorInfo
{
  public:
    virtual std::string str() const = 0;
};

/* namespace Stats */ }

#endif // __BASE_STATS_INFO_HH__
<|endoftext|>


<commit_before>#include "imagelist.h"
using namespace AhoViewer::Booru;

#include "image.h"
#include "imagefetcher.h"
#include "page.h"
#include "site.h"
#include "tempdir.h"

ImageList::ImageList(Widget *w)
  : AhoViewer::ImageList(w)
{

}

ImageList::~ImageList()
{
    // Explicitly clear all signal handlers since we are destroying everything
    m_SignalCleared.clear();
    clear();
}

// This is also used when reusing the same page with a new query
void ImageList::clear()
{
    cancel_thumbnail_thread();

    // This prepares the imagefetcher for a clean death
    if (m_ImageFetcher)
        m_ImageFetcher->shutdown();

    // Clears the image vector and widget (Booru::Page)
    AhoViewer::ImageList::clear();

    if (!m_Path.empty())
    {
        TempDir::get_instance().remove_dir(m_Path);
        m_Path.clear();
    }

    m_Size = 0;
    m_ImageFetcher = nullptr;
}

std::string ImageList::get_path()
{
    if (m_Path.empty())
    {
        m_Path = TempDir::get_instance().make_dir();
        g_mkdir_with_parents(Glib::build_filename(m_Path, "thumbnails").c_str(), 0755);
    }

    return m_Path;
}

void ImageList::load(const xml::Document &posts, const Page &page)
{
    m_Site = page.get_site();

    if (!m_ImageFetcher)
        m_ImageFetcher = std::make_unique<ImageFetcher>(m_Site->get_max_connections());

    std::string c = posts.get_attribute("count");
    if (!c.empty())
       m_Size = std::stoul(c);

    for (const xml::Node &post : posts.get_children())
    {
        std::string thumbUrl  = post.get_attribute("preview_url"),
                    thumbPath = Glib::build_filename(get_path(), "thumbnails",
                                                   Glib::uri_unescape_string(Glib::path_get_basename(thumbUrl))),
                    imageUrl  = post.get_attribute(m_Site->use_samples() ? "sample_url" : "file_url"),
                    imagePath = Glib::build_filename(get_path(),
                                                   Glib::uri_unescape_string(Glib::path_get_basename(imageUrl)));

        std::istringstream ss(post.get_attribute("tags"));
        std::set<std::string> tags { std::istream_iterator<std::string>(ss),
                                     std::istream_iterator<std::string>() };
        m_Site->add_tags(tags);

        if (thumbUrl[0] == '/')
        {
            if (thumbUrl[1] == '/')
                thumbUrl = "https:" + thumbUrl;
            else
                thumbUrl = m_Site->get_url() + thumbUrl;
        }

        if (imageUrl[0] == '/')
        {
            if (imageUrl[1] == '/')
                imageUrl = "https:" + imageUrl;
            else
                imageUrl = m_Site->get_url() + imageUrl;
        }

        std::string postUrl = m_Site->get_post_url(post.get_attribute("id"));

        if (Image::is_valid_extension(imageUrl))
            m_Images.emplace_back(std::make_shared<Image>(imagePath, imageUrl,
                                                          thumbPath, thumbUrl,
                                                          postUrl, tags,
                                                          m_Site, *m_ImageFetcher));
        else
            --m_Size;
    }

    if (m_Images.empty())
        return;

    if (m_ThumbnailThread.joinable())
        m_ThumbnailThread.join();

    m_ThumbnailThread = std::thread(sigc::mem_fun(*this, &ImageList::load_thumbnails));

    // only call set_current if this is the first page
    if (page.get_page_num() == 1)
        set_current(m_Index, false, true);
    else
        m_SignalChanged(m_Images[m_Index]);
}

// Override this so we dont cancel and restart the thumbnail thread
void ImageList::set_current(const size_t index, const bool fromWidget, const bool force)
{
    if (index == m_Index && !force)
        return;

    m_Index = index;
    m_SignalChanged(m_Images[m_Index]);
    update_cache();

    if (!fromWidget)
        m_Widget->set_selected(m_Index);
}

// Cancel all image thumbnail curlers.
void ImageList::cancel_thumbnail_thread()
{
    m_ThumbnailCancel->cancel();

    for (auto img : *this)
    {
        auto bimage = std::static_pointer_cast<Image>(img);
        bimage->cancel_thumbnail_download();
    }
}
<commit_msg>booru/imagelist: Fix safebooru.org thumbnail urls<commit_after>#include "imagelist.h"
using namespace AhoViewer::Booru;

#include "image.h"
#include "imagefetcher.h"
#include "page.h"
#include "site.h"
#include "tempdir.h"

ImageList::ImageList(Widget *w)
  : AhoViewer::ImageList(w)
{

}

ImageList::~ImageList()
{
    // Explicitly clear all signal handlers since we are destroying everything
    m_SignalCleared.clear();
    clear();
}

// This is also used when reusing the same page with a new query
void ImageList::clear()
{
    cancel_thumbnail_thread();

    // This prepares the imagefetcher for a clean death
    if (m_ImageFetcher)
        m_ImageFetcher->shutdown();

    // Clears the image vector and widget (Booru::Page)
    AhoViewer::ImageList::clear();

    if (!m_Path.empty())
    {
        TempDir::get_instance().remove_dir(m_Path);
        m_Path.clear();
    }

    m_Size = 0;
    m_ImageFetcher = nullptr;
}

std::string ImageList::get_path()
{
    if (m_Path.empty())
    {
        m_Path = TempDir::get_instance().make_dir();
        g_mkdir_with_parents(Glib::build_filename(m_Path, "thumbnails").c_str(), 0755);
    }

    return m_Path;
}

void ImageList::load(const xml::Document &posts, const Page &page)
{
    m_Site = page.get_site();

    if (!m_ImageFetcher)
        m_ImageFetcher = std::make_unique<ImageFetcher>(m_Site->get_max_connections());

    std::string c = posts.get_attribute("count");
    if (!c.empty())
       m_Size = std::stoul(c);

    for (const xml::Node &post : posts.get_children())
    {
        std::string thumbUrl  = post.get_attribute("preview_url"),
                    thumbPath = Glib::build_filename(get_path(), "thumbnails",
                                                   Glib::uri_unescape_string(Glib::path_get_basename(thumbUrl))),
                    imageUrl  = post.get_attribute(m_Site->use_samples() ? "sample_url" : "file_url"),
                    imagePath = Glib::build_filename(get_path(),
                                                   Glib::uri_unescape_string(Glib::path_get_basename(imageUrl)));

        std::istringstream ss(post.get_attribute("tags"));
        std::set<std::string> tags { std::istream_iterator<std::string>(ss),
                                     std::istream_iterator<std::string>() };
        m_Site->add_tags(tags);

        if (thumbUrl[0] == '/')
        {
            if (thumbUrl[1] == '/')
                thumbUrl = "https:" + thumbUrl;
            else
                thumbUrl = m_Site->get_url() + thumbUrl;
        }

        if (imageUrl[0] == '/')
        {
            if (imageUrl[1] == '/')
                imageUrl = "https:" + imageUrl;
            else
                imageUrl = m_Site->get_url() + imageUrl;
        }

        // safebooru.org provides the wrong file extension for thumbnails
        // All their thumbnails are .jpg, but their api gives links to with the
        // same exntension as the original images exnteion
        if (thumbUrl.find("safebooru.org") != std::string::npos)
            thumbUrl = thumbUrl.substr(0, thumbUrl.find_last_of('.')) + ".jpg";

        std::string postUrl = m_Site->get_post_url(post.get_attribute("id"));

        if (Image::is_valid_extension(imageUrl))
            m_Images.emplace_back(std::make_shared<Image>(imagePath, imageUrl,
                                                          thumbPath, thumbUrl,
                                                          postUrl, tags,
                                                          m_Site, *m_ImageFetcher));
        else
            --m_Size;
    }

    if (m_Images.empty())
        return;

    if (m_ThumbnailThread.joinable())
        m_ThumbnailThread.join();

    m_ThumbnailThread = std::thread(sigc::mem_fun(*this, &ImageList::load_thumbnails));

    // only call set_current if this is the first page
    if (page.get_page_num() == 1)
        set_current(m_Index, false, true);
    else
        m_SignalChanged(m_Images[m_Index]);
}

// Override this so we dont cancel and restart the thumbnail thread
void ImageList::set_current(const size_t index, const bool fromWidget, const bool force)
{
    if (index == m_Index && !force)
        return;

    m_Index = index;
    m_SignalChanged(m_Images[m_Index]);
    update_cache();

    if (!fromWidget)
        m_Widget->set_selected(m_Index);
}

// Cancel all image thumbnail curlers.
void ImageList::cancel_thumbnail_thread()
{
    m_ThumbnailCancel->cancel();

    for (auto img : *this)
    {
        auto bimage = std::static_pointer_cast<Image>(img);
        bimage->cancel_thumbnail_download();
    }
}
<|endoftext|>