<commit_before>// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "include/dart_api.h"

#include "vm/unit_test.h"

// Custom Isolate Test.
//
// This mid-size test uses the Dart Embedding Api to create a custom
// isolate abstraction.  Instead of having a dedicated thread for each
// isolate, as is the case normally, this implementation shares a
// single thread among the isolates using an event queue.

namespace dart {

#if defined(TARGET_ARCH_IA32)  // only ia32 can run execution tests.

static void native_echo(Dart_NativeArguments args);
static void CustomIsolateImpl_start(Dart_NativeArguments args);
static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc);

static const char* kCustomIsolateScriptChars =
    "class GlobalsHack {\n"
    "  static ReceivePort _receivePort;\n"
    "}\n"
    "\n"
    "ReceivePort get receivePort() {\n"
    "  return GlobalsHack._receivePort;\n"
    "}\n"
    "\n"
    "echo(arg) native \"native_echo\";\n"
    "\n"
    "class CustomIsolateImpl implements CustomIsolate {\n"
    "  CustomIsolateImpl(String entry) : _entry = entry{\n"
    "    echo('Constructing isolate');\n"
    "  }\n"
    "\n"
    "  Future<SendPort> spawn() {\n"
    "    Completer<SendPort> completer = new Completer<SendPort>();\n"
    "    SendPort port = _start(_entry);\n"
    "    completer.complete(port);\n"
    "    return completer.future;\n"
    "  }\n"
    "\n"
    "  static SendPort _start(entry)\n"
    "      native \"CustomIsolateImpl_start\";\n"
    "\n"
    "  String _entry;\n"
    "}\n"
    "\n"
    "interface CustomIsolate factory CustomIsolateImpl {\n"
    "  CustomIsolate(String entry);\n"
    "\n"
    "  Future<SendPort> spawn();\n"
    "}\n"
    "\n"
    "isolateMain() {\n"
    "   echo('Running isolateMain');\n"
    "   receivePort.receive((message, SendPort replyTo) {\n"
    "     echo('Received: ' + message);\n"
    "     replyTo.send((message + 1), null);\n"
    "   });\n"
    "}\n"
    "\n"
    "main() {\n"
    "  Isolate isolate = new CustomIsolate(\"isolateMain\");\n"
    "  isolate.spawn().then((SendPort port) {\n"
    "    port.call(42).receive((message, replyTo) {\n"
    "      echo('Received: ' + message);\n"
    "    });\n"
    "  });\n"
    "  return 'success';\n"
    "}\n";

// An entry in our event queue.
class Event {
 protected:
  Event() : next_(NULL) {}

 public:
  virtual ~Event() {}
  virtual void Process() = 0;

  virtual bool IsShutdownEvent(Dart_Isolate isolate) {
    return false;
  }
  virtual bool IsMessageEvent(Dart_Isolate isolate, Dart_Port port) {
    return false;
  }

 private:
  friend class EventQueue;
  Event* next_;
};

// Start an isolate.
class StartEvent : public Event {
 public:
  StartEvent(Dart_Isolate isolate, const char* main)
      : isolate_(isolate), main_(main) {}

  virtual void Process();
 private:
  Dart_Isolate isolate_;
  const char* main_;
};

void StartEvent::Process() {
  OS::Print(">> StartEvent with isolate(%p)--\n", isolate_);
  Dart_EnterIsolate(isolate_);
  Dart_EnterScope();
  Dart_Handle result;

  // Reload all the test classes here.
  //
  // TODO(turnidge): Use the create isolate callback instead?
  Dart_Handle lib = TestCase::LoadTestScript(kCustomIsolateScriptChars,
                                             NativeLookup);
  EXPECT_VALID(lib);
  EXPECT_VALID(Dart_CompileAll());

  Dart_Handle recv_port = Dart_GetReceivePort(Dart_GetMainPortId());
  EXPECT_VALID(recv_port);

  // TODO(turnidge): Provide a way to set a top-level variable from
  // the dart embedding api.
  Dart_Handle hidden = Dart_GetClass(lib, Dart_NewString("GlobalsHack"));
  EXPECT_VALID(hidden);
  result = Dart_SetStaticField(hidden, Dart_NewString("_receivePort"),
                               recv_port);
  EXPECT_VALID(result);

  result = Dart_InvokeStatic(lib,
                             Dart_NewString(""),
                             Dart_NewString(main_),
                             0,
                             NULL);
  EXPECT_VALID(result);
  free(const_cast<char*>(main_));
  main_ = NULL;

  Dart_ExitScope();
  Dart_ExitIsolate();
}

// Shutdown an isolate.
class ShutdownEvent : public Event {
 public:
  explicit ShutdownEvent(Dart_Isolate isolate) : isolate_(isolate) {}

  virtual bool IsShutdownEvent(Dart_Isolate isolate) {
    return isolate == isolate_;
  }

  virtual void Process();
 private:
  Dart_Isolate isolate_;
};

void ShutdownEvent::Process() {
  OS::Print("<< ShutdownEvent with isolate(%p)--\n", isolate_);
  Dart_EnterIsolate(isolate_);
  Dart_ShutdownIsolate();
}

// Deliver a message to an isolate.
class MessageEvent : public Event {
 public:
  MessageEvent(Dart_Isolate isolate, Dart_Port dest, Dart_Port reply,
               Dart_Message msg)
      : isolate_(isolate), dest_(dest), reply_(reply), msg_(msg) {}

  ~MessageEvent() {
    free(msg_);
    msg_ = NULL;
  }

  virtual bool IsMessageEvent(Dart_Isolate isolate, Dart_Port port) {
    return isolate == isolate_ && (port == kCloseAllPorts || port == dest_);
  }

  virtual void Process();
 private:
  Dart_Isolate isolate_;
  Dart_Port dest_;
  Dart_Port reply_;
  Dart_Message msg_;
};

void MessageEvent::Process() {
  OS::Print("$$ MessageEvent with dest port %lld--\n", dest_);
  Dart_EnterIsolate(isolate_);
  Dart_EnterScope();

  Dart_Handle result = Dart_HandleMessage(dest_, reply_, msg_);
  EXPECT_VALID(result);

  Dart_ExitScope();
  Dart_ExitIsolate();
}

// A simple event queue for our test.
class EventQueue {
 public:
  EventQueue() {
    head_ = NULL;
  }

  void Add(Event* event) {
    if (head_ == NULL) {
      head_ = event;
      tail_ = event;
    } else {
      tail_->next_ = event;
      tail_ = event;
    }
  }

  Event* Get() {
    if (head_ == NULL) {
      return NULL;
    }
    Event* tmp = head_;
    head_ = head_->next_;
    if (head_ == NULL) {
      tail_ = NULL;
    }

    return tmp;
  }

  void ClosePort(Dart_Isolate isolate, Dart_Port port) {
    Event* cur = head_;
    Event* prev = NULL;
    while (cur != NULL) {
      Event* next = cur->next_;
      if (cur->IsMessageEvent(isolate, port)) {
        // Remove matching event.
        if (prev != NULL) {
          prev->next_ = next;
        } else {
          head_ = next;
        }
        delete cur;
      } else {
        // Advance.
        prev = cur;
      }
      cur = next;
    }
    tail_ = prev;
  }

 private:
  Event* head_;
  Event* tail_;
};
EventQueue* event_queue;
Event* current_event;

static bool PostMessage(Dart_Isolate dest_isolate,
                        Dart_Port dest_port,
                        Dart_Port reply_port,
                        Dart_Message message) {
  OS::Print("-- Posting message dest(%d) reply(%d) --\n",
            dest_port, reply_port);
  OS::Print("-- Adding MessageEvent to queue --\n");
  event_queue->Add(
      new MessageEvent(dest_isolate, dest_port, reply_port, message));
  return true;
}

static void ClosePort(Dart_Isolate isolate,
                      Dart_Port port) {
  OS::Print("-- Closing port (%lld) for isolate(%p) --\n",
            port, isolate);

  // Remove any pending events for the isolate/port.
  event_queue->ClosePort(isolate, port);

  Dart_Isolate current = Dart_CurrentIsolate();
  if (current) {
    Dart_ExitIsolate();
  }
  Dart_EnterIsolate(isolate);
  if (!Dart_HasLivePorts() &&
      (current_event == NULL || !current_event->IsShutdownEvent(isolate))) {
    OS::Print("-- Adding ShutdownEvent to queue --\n");
    event_queue->Add(new ShutdownEvent(isolate));
  }
  Dart_ExitIsolate();
  if (current) {
    Dart_EnterIsolate(current);
  }
}

static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc) {
  const char* name_str = NULL;
  EXPECT(Dart_IsString(name));
  EXPECT_VALID(Dart_StringToCString(name, &name_str));
  if (strcmp(name_str, "native_echo") == 0) {
    return &native_echo;
  } else if (strcmp(name_str, "CustomIsolateImpl_start") == 0) {
    return &CustomIsolateImpl_start;
  }
  return NULL;
}

const char* saved_echo = NULL;
static void native_echo(Dart_NativeArguments args) {
  Dart_EnterScope();
  Dart_Handle arg = Dart_GetNativeArgument(args, 0);
  Dart_Handle toString = Dart_ToString(arg);
  EXPECT_VALID(toString);
  const char* c_str = NULL;
  EXPECT_VALID(Dart_StringToCString(toString, &c_str));
  if (saved_echo) {
    free(const_cast<char*>(saved_echo));
  }
  saved_echo = strdup(c_str);
  OS::Print("-- (isolate=%p) %s\n", Dart_CurrentIsolate(), c_str);
  Dart_ExitScope();
}

static void CustomIsolateImpl_start(Dart_NativeArguments args) {
  OS::Print("-- Enter: CustomIsolateImpl_start --\n");

  // We would probably want to pass in the this pointer too, so we
  // could associate the CustomIsolateImpl instance with the
  // Dart_Isolate by storing it in a native field.
  EXPECT_EQ(1, Dart_GetNativeArgumentCount(args));
  Dart_Handle param = Dart_GetNativeArgument(args, 0);
  EXPECT_VALID(param);
  EXPECT(Dart_IsString(param));
  const char* isolate_main = NULL;
  EXPECT_VALID(Dart_StringToCString(param, &isolate_main));
  isolate_main = strdup(isolate_main);

  // Save current isolate.
  Dart_Isolate saved_isolate = Dart_CurrentIsolate();
  Dart_ExitIsolate();

  // Create a new Dart_Isolate.
  Dart_Isolate new_isolate = Dart_CreateIsolate(NULL, NULL);
  Dart_SetMessageCallbacks(&PostMessage, &ClosePort);
  Dart_Port new_port = Dart_GetMainPortId();

  OS::Print("-- Adding StartEvent to queue --\n");
  event_queue->Add(new StartEvent(new_isolate, isolate_main));

  // Restore the original isolate.
  Dart_ExitIsolate();
  Dart_EnterIsolate(saved_isolate);
  Dart_EnterScope();

  Dart_Handle send_port = Dart_NewSendPort(new_port);
  EXPECT_VALID(send_port);
  Dart_SetReturnValue(args, send_port);

  OS::Print("-- Exit: CustomIsolateImpl_start --\n");
  Dart_ExitScope();
}

UNIT_TEST_CASE(CustomIsolates) {
  event_queue = new EventQueue();
  current_event = NULL;

  Dart_CreateIsolate(NULL, NULL);
  Dart_SetMessageCallbacks(&PostMessage, &ClosePort);
  Dart_EnterScope();
  Dart_Handle result;

  // Create a test library.
  Dart_Handle lib = TestCase::LoadTestScript(kCustomIsolateScriptChars,
                                             NativeLookup);
  EXPECT_VALID(lib);

  // Run main.
  result = Dart_InvokeStatic(lib,
                             Dart_NewString(""),
                             Dart_NewString("main"),
                             0,
                             NULL);
  EXPECT_VALID(result);
  EXPECT(Dart_IsString(result));
  const char* result_str = NULL;
  EXPECT_VALID(Dart_StringToCString(result, &result_str));
  EXPECT_STREQ("success", result_str);

  Dart_ExitScope();
  Dart_ExitIsolate();

  OS::Print("-- Starting event loop --\n");
  Event* event = event_queue->Get();
  while (event) {
    current_event = event;
    event->Process();
    current_event = NULL;
    delete event;
    event = event_queue->Get();
  }
  OS::Print("-- Finished event loop --\n");
  EXPECT_STREQ("Received: 43", saved_echo);
  free(const_cast<char*>(saved_echo));

  delete event_queue;
}

#endif  // TARGET_ARCH_IA32.

}  // namespace dart
<commit_msg>Fix checked mode test. Review URL: http://codereview.chromium.org//8735006<commit_after>// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "include/dart_api.h"

#include "vm/unit_test.h"

// Custom Isolate Test.
//
// This mid-size test uses the Dart Embedding Api to create a custom
// isolate abstraction.  Instead of having a dedicated thread for each
// isolate, as is the case normally, this implementation shares a
// single thread among the isolates using an event queue.

namespace dart {

#if defined(TARGET_ARCH_IA32)  // only ia32 can run execution tests.

static void native_echo(Dart_NativeArguments args);
static void CustomIsolateImpl_start(Dart_NativeArguments args);
static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc);

static const char* kCustomIsolateScriptChars =
    "class GlobalsHack {\n"
    "  static ReceivePort _receivePort;\n"
    "}\n"
    "\n"
    "ReceivePort get receivePort() {\n"
    "  return GlobalsHack._receivePort;\n"
    "}\n"
    "\n"
    "echo(arg) native \"native_echo\";\n"
    "\n"
    "class CustomIsolateImpl implements CustomIsolate {\n"
    "  CustomIsolateImpl(String entry) : _entry = entry{\n"
    "    echo('Constructing isolate');\n"
    "  }\n"
    "\n"
    "  Future<SendPort> spawn() {\n"
    "    Completer<SendPort> completer = new Completer<SendPort>();\n"
    "    SendPort port = _start(_entry);\n"
    "    completer.complete(port);\n"
    "    return completer.future;\n"
    "  }\n"
    "\n"
    "  static SendPort _start(entry)\n"
    "      native \"CustomIsolateImpl_start\";\n"
    "\n"
    "  String _entry;\n"
    "}\n"
    "\n"
    "interface CustomIsolate factory CustomIsolateImpl {\n"
    "  CustomIsolate(String entry);\n"
    "\n"
    "  Future<SendPort> spawn();\n"
    "}\n"
    "\n"
    "isolateMain() {\n"
    "   echo('Running isolateMain');\n"
    "   receivePort.receive((message, SendPort replyTo) {\n"
    "     echo('Received: ' + message);\n"
    "     replyTo.send((message + 1), null);\n"
    "   });\n"
    "}\n"
    "\n"
    "main() {\n"
    "  var isolate = new CustomIsolate(\"isolateMain\");\n"
    "  isolate.spawn().then((SendPort port) {\n"
    "    port.call(42).receive((message, replyTo) {\n"
    "      echo('Received: ' + message);\n"
    "    });\n"
    "  });\n"
    "  return 'success';\n"
    "}\n";

// An entry in our event queue.
class Event {
 protected:
  Event() : next_(NULL) {}

 public:
  virtual ~Event() {}
  virtual void Process() = 0;

  virtual bool IsShutdownEvent(Dart_Isolate isolate) {
    return false;
  }
  virtual bool IsMessageEvent(Dart_Isolate isolate, Dart_Port port) {
    return false;
  }

 private:
  friend class EventQueue;
  Event* next_;
};

// Start an isolate.
class StartEvent : public Event {
 public:
  StartEvent(Dart_Isolate isolate, const char* main)
      : isolate_(isolate), main_(main) {}

  virtual void Process();
 private:
  Dart_Isolate isolate_;
  const char* main_;
};

void StartEvent::Process() {
  OS::Print(">> StartEvent with isolate(%p)--\n", isolate_);
  Dart_EnterIsolate(isolate_);
  Dart_EnterScope();
  Dart_Handle result;

  // Reload all the test classes here.
  //
  // TODO(turnidge): Use the create isolate callback instead?
  Dart_Handle lib = TestCase::LoadTestScript(kCustomIsolateScriptChars,
                                             NativeLookup);
  EXPECT_VALID(lib);
  EXPECT_VALID(Dart_CompileAll());

  Dart_Handle recv_port = Dart_GetReceivePort(Dart_GetMainPortId());
  EXPECT_VALID(recv_port);

  // TODO(turnidge): Provide a way to set a top-level variable from
  // the dart embedding api.
  Dart_Handle hidden = Dart_GetClass(lib, Dart_NewString("GlobalsHack"));
  EXPECT_VALID(hidden);
  result = Dart_SetStaticField(hidden, Dart_NewString("_receivePort"),
                               recv_port);
  EXPECT_VALID(result);

  result = Dart_InvokeStatic(lib,
                             Dart_NewString(""),
                             Dart_NewString(main_),
                             0,
                             NULL);
  EXPECT_VALID(result);
  free(const_cast<char*>(main_));
  main_ = NULL;

  Dart_ExitScope();
  Dart_ExitIsolate();
}

// Shutdown an isolate.
class ShutdownEvent : public Event {
 public:
  explicit ShutdownEvent(Dart_Isolate isolate) : isolate_(isolate) {}

  virtual bool IsShutdownEvent(Dart_Isolate isolate) {
    return isolate == isolate_;
  }

  virtual void Process();
 private:
  Dart_Isolate isolate_;
};

void ShutdownEvent::Process() {
  OS::Print("<< ShutdownEvent with isolate(%p)--\n", isolate_);
  Dart_EnterIsolate(isolate_);
  Dart_ShutdownIsolate();
}

// Deliver a message to an isolate.
class MessageEvent : public Event {
 public:
  MessageEvent(Dart_Isolate isolate, Dart_Port dest, Dart_Port reply,
               Dart_Message msg)
      : isolate_(isolate), dest_(dest), reply_(reply), msg_(msg) {}

  ~MessageEvent() {
    free(msg_);
    msg_ = NULL;
  }

  virtual bool IsMessageEvent(Dart_Isolate isolate, Dart_Port port) {
    return isolate == isolate_ && (port == kCloseAllPorts || port == dest_);
  }

  virtual void Process();
 private:
  Dart_Isolate isolate_;
  Dart_Port dest_;
  Dart_Port reply_;
  Dart_Message msg_;
};

void MessageEvent::Process() {
  OS::Print("$$ MessageEvent with dest port %lld--\n", dest_);
  Dart_EnterIsolate(isolate_);
  Dart_EnterScope();

  Dart_Handle result = Dart_HandleMessage(dest_, reply_, msg_);
  EXPECT_VALID(result);

  Dart_ExitScope();
  Dart_ExitIsolate();
}

// A simple event queue for our test.
class EventQueue {
 public:
  EventQueue() {
    head_ = NULL;
  }

  void Add(Event* event) {
    if (head_ == NULL) {
      head_ = event;
      tail_ = event;
    } else {
      tail_->next_ = event;
      tail_ = event;
    }
  }

  Event* Get() {
    if (head_ == NULL) {
      return NULL;
    }
    Event* tmp = head_;
    head_ = head_->next_;
    if (head_ == NULL) {
      tail_ = NULL;
    }

    return tmp;
  }

  void ClosePort(Dart_Isolate isolate, Dart_Port port) {
    Event* cur = head_;
    Event* prev = NULL;
    while (cur != NULL) {
      Event* next = cur->next_;
      if (cur->IsMessageEvent(isolate, port)) {
        // Remove matching event.
        if (prev != NULL) {
          prev->next_ = next;
        } else {
          head_ = next;
        }
        delete cur;
      } else {
        // Advance.
        prev = cur;
      }
      cur = next;
    }
    tail_ = prev;
  }

 private:
  Event* head_;
  Event* tail_;
};
EventQueue* event_queue;
Event* current_event;

static bool PostMessage(Dart_Isolate dest_isolate,
                        Dart_Port dest_port,
                        Dart_Port reply_port,
                        Dart_Message message) {
  OS::Print("-- Posting message dest(%d) reply(%d) --\n",
            dest_port, reply_port);
  OS::Print("-- Adding MessageEvent to queue --\n");
  event_queue->Add(
      new MessageEvent(dest_isolate, dest_port, reply_port, message));
  return true;
}

static void ClosePort(Dart_Isolate isolate,
                      Dart_Port port) {
  OS::Print("-- Closing port (%lld) for isolate(%p) --\n",
            port, isolate);

  // Remove any pending events for the isolate/port.
  event_queue->ClosePort(isolate, port);

  Dart_Isolate current = Dart_CurrentIsolate();
  if (current) {
    Dart_ExitIsolate();
  }
  Dart_EnterIsolate(isolate);
  if (!Dart_HasLivePorts() &&
      (current_event == NULL || !current_event->IsShutdownEvent(isolate))) {
    OS::Print("-- Adding ShutdownEvent to queue --\n");
    event_queue->Add(new ShutdownEvent(isolate));
  }
  Dart_ExitIsolate();
  if (current) {
    Dart_EnterIsolate(current);
  }
}

static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc) {
  const char* name_str = NULL;
  EXPECT(Dart_IsString(name));
  EXPECT_VALID(Dart_StringToCString(name, &name_str));
  if (strcmp(name_str, "native_echo") == 0) {
    return &native_echo;
  } else if (strcmp(name_str, "CustomIsolateImpl_start") == 0) {
    return &CustomIsolateImpl_start;
  }
  return NULL;
}

const char* saved_echo = NULL;
static void native_echo(Dart_NativeArguments args) {
  Dart_EnterScope();
  Dart_Handle arg = Dart_GetNativeArgument(args, 0);
  Dart_Handle toString = Dart_ToString(arg);
  EXPECT_VALID(toString);
  const char* c_str = NULL;
  EXPECT_VALID(Dart_StringToCString(toString, &c_str));
  if (saved_echo) {
    free(const_cast<char*>(saved_echo));
  }
  saved_echo = strdup(c_str);
  OS::Print("-- (isolate=%p) %s\n", Dart_CurrentIsolate(), c_str);
  Dart_ExitScope();
}

static void CustomIsolateImpl_start(Dart_NativeArguments args) {
  OS::Print("-- Enter: CustomIsolateImpl_start --\n");

  // We would probably want to pass in the this pointer too, so we
  // could associate the CustomIsolateImpl instance with the
  // Dart_Isolate by storing it in a native field.
  EXPECT_EQ(1, Dart_GetNativeArgumentCount(args));
  Dart_Handle param = Dart_GetNativeArgument(args, 0);
  EXPECT_VALID(param);
  EXPECT(Dart_IsString(param));
  const char* isolate_main = NULL;
  EXPECT_VALID(Dart_StringToCString(param, &isolate_main));
  isolate_main = strdup(isolate_main);

  // Save current isolate.
  Dart_Isolate saved_isolate = Dart_CurrentIsolate();
  Dart_ExitIsolate();

  // Create a new Dart_Isolate.
  Dart_Isolate new_isolate = Dart_CreateIsolate(NULL, NULL);
  Dart_SetMessageCallbacks(&PostMessage, &ClosePort);
  Dart_Port new_port = Dart_GetMainPortId();

  OS::Print("-- Adding StartEvent to queue --\n");
  event_queue->Add(new StartEvent(new_isolate, isolate_main));

  // Restore the original isolate.
  Dart_ExitIsolate();
  Dart_EnterIsolate(saved_isolate);
  Dart_EnterScope();

  Dart_Handle send_port = Dart_NewSendPort(new_port);
  EXPECT_VALID(send_port);
  Dart_SetReturnValue(args, send_port);

  OS::Print("-- Exit: CustomIsolateImpl_start --\n");
  Dart_ExitScope();
}

UNIT_TEST_CASE(CustomIsolates) {
  event_queue = new EventQueue();
  current_event = NULL;

  Dart_CreateIsolate(NULL, NULL);
  Dart_SetMessageCallbacks(&PostMessage, &ClosePort);
  Dart_EnterScope();
  Dart_Handle result;

  // Create a test library.
  Dart_Handle lib = TestCase::LoadTestScript(kCustomIsolateScriptChars,
                                             NativeLookup);
  EXPECT_VALID(lib);

  // Run main.
  result = Dart_InvokeStatic(lib,
                             Dart_NewString(""),
                             Dart_NewString("main"),
                             0,
                             NULL);
  EXPECT_VALID(result);
  EXPECT(Dart_IsString(result));
  const char* result_str = NULL;
  EXPECT_VALID(Dart_StringToCString(result, &result_str));
  EXPECT_STREQ("success", result_str);

  Dart_ExitScope();
  Dart_ExitIsolate();

  OS::Print("-- Starting event loop --\n");
  Event* event = event_queue->Get();
  while (event) {
    current_event = event;
    event->Process();
    current_event = NULL;
    delete event;
    event = event_queue->Get();
  }
  OS::Print("-- Finished event loop --\n");
  EXPECT_STREQ("Received: 43", saved_echo);
  free(const_cast<char*>(saved_echo));

  delete event_queue;
}

#endif  // TARGET_ARCH_IA32.

}  // namespace dart
<|endoftext|>


<commit_before>/*
Copyright (c) 2012 Carsten Burstedde, Donna Calhoun
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.

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 HOLDER 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.
*/

#include "bowl_user.h"
#include <fclaw2d_forestclaw.h>
#include <fclaw2d_clawpatch.h>
#include <fc2d_geoclaw.h>

static fclaw2d_vtable_t vt;
static fc2d_geoclaw_vtable_t geoclaw;

void bowl_link_solvers(fclaw2d_domain_t *domain)
{
    fclaw2d_init_vtable(&vt);

#if 0
    vt.problem_setup            = &fc2d_geoclaw_setprob;
    vt.patch_setup              = &bowl_patch_setup;
    vt.patch_initialize         = &bowl_patch_initialize;
    vt.patch_physical_bc        = &bowl_patch_physical_bc;
    vt.patch_single_step_update = &fc2d_geoclaw_update;  /* Includes b4step2 and src2 */

    vt.regrid_tag4refinement     = &bowl_patch_tag4refinement;
    vt.fort_tag4refinement      = &TAG4REFINEMENT;

    vt.regrid_tag4coarsening     = &bowl_patch_tag4coarsening;
    vt.fort_tag4coarsening      = &TAG4COARSENING;

    vt.write_header             = &fclaw2d_output_header_ascii;
    vt.fort_write_header        = &FCLAW2D_FORT_WRITE_HEADER;

    vt.patch_write_file         = &fclaw2d_output_patch_ascii;
    vt.fort_write_file          = &FCLAW2D_FORT_WRITE_FILE;
#endif

    fclaw2d_set_vtable(domain,&vt);

#if 0
    /* Needed for the geoclaw package */
    geoclaw.qinit = &QINIT;
    geoclaw.bc2 = &BC2;
    geoclaw.setaux = &SETAUX;
    geoclaw.setprob = &SETPROB;
    geoclaw.b4step2 = &B4STEP2;
    geoclaw.rpn2 = &RPN2;
    geoclaw.rpt2 = &RPT2;
#endif

    fc2d_geoclaw_set_vtable(&geoclaw);

}

void bowl_patch_setup(fclaw2d_domain_t *domain,
                          fclaw2d_patch_t *this_patch,
                          int this_block_idx,
                          int this_patch_idx)
{
    /* Dummy setup - use multiple libraries */
    fc2d_geoclaw_setaux(domain,this_patch,this_block_idx,this_patch_idx);
}

void bowl_patch_initialize(fclaw2d_domain_t *domain,
                            fclaw2d_patch_t *this_patch,
                            int this_block_idx,
                            int this_patch_idx)
{
    /* This is an example of how to call the initialization routines explicitly
       This routine can be replaced by setting the appropriate fclaw2d_vtable_t,
       entry above, or by calling fclaw2d_geoclaw_qinit(...) from here. */

    int mx,my,mbc,meqn, maux;
    double xlower,ylower,dx,dy;
    double *q, *aux;

    vt = fclaw2d_get_vtable(domain);

    fclaw2d_clawpatch_grid_data(domain,this_patch,&mx,&my,&mbc,
                                &xlower,&ylower,&dx,&dy);

    fclaw2d_clawpatch_soln_data(domain,this_patch,&q,&meqn);
    fc2d_geoclaw_aux_data(domain,this_patch,&aux,&maux);

    /* Call to used defined, classic Clawpack (ver. 4.6)  'qinit' routine.
       Header is in the Clawpack package
    */
#if 0
    QINIT(&meqn,&mbc,&mx,&my,&xlower,&ylower,&dx,&dy,q,&maux,aux);
#endif
}

void bowl_patch_physical_bc(fclaw2d_domain *domain,
                             fclaw2d_patch_t *this_patch,
                             int this_block_idx,
                             int this_patch_idx,
                             double t,
                             double dt,
                             fclaw_bool intersects_bc[],
                             fclaw_bool time_interp)
{
    /* This calls bc2 in bowl/user_4.6;  that file isn't changed but
       is included to show that both the local version of bc2.f and the
       geoclaw library code can be included */
    fc2d_geoclaw_bc2(domain,this_patch,this_block_idx,this_patch_idx,
                     t,dt,intersects_bc,time_interp);
}

int bowl_patch_tag4refinement(fclaw2d_domain_t *domain,
                               fclaw2d_patch_t *this_patch,
                               int blockno, int this_patch_idx,
                               int initflag)
{
    fclaw2d_vtable_t vt;
    int mx,my,mbc,meqn;
    double xlower,ylower,dx,dy;
    double *q;
    int tag_patch;
    const amr_options_t *amropt;
    double rt;

    amropt = get_domain_parms(domain);
    rt = amropt->refine_threshold;

    vt = fclaw2d_get_vtable(domain);

    fclaw2d_clawpatch_grid_data(domain,this_patch,&mx,&my,&mbc,
                                &xlower,&ylower,&dx,&dy);

    fclaw2d_clawpatch_soln_data(domain,this_patch,&q,&meqn);

    tag_patch = 0;
    vt.fort_tag4refinement(&mx,&my,&mbc,&meqn,&xlower,&ylower,
                           &dx,&dy,&blockno, q,&rt,&initflag,
                           &tag_patch);
    return tag_patch;
}

int bowl_patch_tag4coarsening(fclaw2d_domain_t *domain,
                               fclaw2d_patch_t *fine_patches,
                               int blockno, int patchno)

{
    fclaw2d_vtable_t vt;

    int mx,my,mbc,meqn;
    double xlower,ylower,dx,dy;
    double *q[4];
    int tag_patch,igrid;
    double coarsen_threshold;
    fclaw2d_patch_t *patch0;

    patch0 = &fine_patches[0];

    const amr_options_t *amropt;
    amropt = get_domain_parms(domain);

    coarsen_threshold = amropt->coarsen_threshold;

    vt = fclaw2d_get_vtable(domain);

    fclaw2d_clawpatch_grid_data(domain,patch0,&mx,&my,&mbc,
                                &xlower,&ylower,&dx,&dy);

    for (igrid = 0; igrid < 4; igrid++)
    {
        fclaw2d_clawpatch_soln_data(domain,&fine_patches[igrid],&q[igrid],&meqn);
    }
    tag_patch = 0;
    vt.fort_tag4coarsening(&mx,&my,&mbc,&meqn,&xlower,&ylower,&dx,&dy,
                           &blockno, q[0],q[1],q[2],q[3],
                           &coarsen_threshold, &tag_patch);
    return tag_patch;

}
<commit_msg>(geoclaw/bowl) Call user setprob routine<commit_after>/*
Copyright (c) 2012 Carsten Burstedde, Donna Calhoun
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.

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 HOLDER 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.
*/

#include "bowl_user.h"
#include <fclaw2d_forestclaw.h>
#include <fclaw2d_clawpatch.h>
#include <fc2d_geoclaw.h>

static fclaw2d_vtable_t vt;
static fc2d_geoclaw_vtable_t geoclaw;

void bowl_link_solvers(fclaw2d_domain_t *domain)
{
    fclaw2d_init_vtable(&vt);

    vt.problem_setup            = &fc2d_geoclaw_setprob;

#if 0
    vt.patch_setup              = &bowl_patch_setup;
    vt.patch_initialize         = &bowl_patch_initialize;
    vt.patch_physical_bc        = &bowl_patch_physical_bc;
    vt.patch_single_step_update = &fc2d_geoclaw_update;  /* Includes b4step2 and src2 */

    vt.regrid_tag4refinement     = &bowl_patch_tag4refinement;
    vt.fort_tag4refinement      = &TAG4REFINEMENT;

    vt.regrid_tag4coarsening     = &bowl_patch_tag4coarsening;
    vt.fort_tag4coarsening      = &TAG4COARSENING;

    vt.write_header             = &fclaw2d_output_header_ascii;
    vt.fort_write_header        = &FCLAW2D_FORT_WRITE_HEADER;

    vt.patch_write_file         = &fclaw2d_output_patch_ascii;
    vt.fort_write_file          = &FCLAW2D_FORT_WRITE_FILE;
#endif

    fclaw2d_set_vtable(domain,&vt);

#if 0
    /* Needed for the geoclaw package */
    geoclaw.qinit = &QINIT;
    geoclaw.bc2 = &BC2;
    geoclaw.setaux = &SETAUX;
    geoclaw.setprob = &SETPROB;
    geoclaw.b4step2 = &B4STEP2;
    geoclaw.rpn2 = &RPN2;
    geoclaw.rpt2 = &RPT2;
#endif

    fc2d_geoclaw_set_vtable(&geoclaw);

}

void bowl_patch_setup(fclaw2d_domain_t *domain,
                          fclaw2d_patch_t *this_patch,
                          int this_block_idx,
                          int this_patch_idx)
{
    /* Dummy setup - use multiple libraries */
    fc2d_geoclaw_setaux(domain,this_patch,this_block_idx,this_patch_idx);
}

void bowl_patch_initialize(fclaw2d_domain_t *domain,
                            fclaw2d_patch_t *this_patch,
                            int this_block_idx,
                            int this_patch_idx)
{
    /* This is an example of how to call the initialization routines explicitly
       This routine can be replaced by setting the appropriate fclaw2d_vtable_t,
       entry above, or by calling fclaw2d_geoclaw_qinit(...) from here. */

    int mx,my,mbc,meqn, maux;
    double xlower,ylower,dx,dy;
    double *q, *aux;

    vt = fclaw2d_get_vtable(domain);

    fclaw2d_clawpatch_grid_data(domain,this_patch,&mx,&my,&mbc,
                                &xlower,&ylower,&dx,&dy);

    fclaw2d_clawpatch_soln_data(domain,this_patch,&q,&meqn);
    fc2d_geoclaw_aux_data(domain,this_patch,&aux,&maux);

    /* Call to used defined, classic Clawpack (ver. 4.6)  'qinit' routine.
       Header is in the Clawpack package
    */
#if 0
    QINIT(&meqn,&mbc,&mx,&my,&xlower,&ylower,&dx,&dy,q,&maux,aux);
#endif
}

void bowl_patch_physical_bc(fclaw2d_domain *domain,
                             fclaw2d_patch_t *this_patch,
                             int this_block_idx,
                             int this_patch_idx,
                             double t,
                             double dt,
                             fclaw_bool intersects_bc[],
                             fclaw_bool time_interp)
{
    /* This calls bc2 in bowl/user_4.6;  that file isn't changed but
       is included to show that both the local version of bc2.f and the
       geoclaw library code can be included */
    fc2d_geoclaw_bc2(domain,this_patch,this_block_idx,this_patch_idx,
                     t,dt,intersects_bc,time_interp);
}

int bowl_patch_tag4refinement(fclaw2d_domain_t *domain,
                               fclaw2d_patch_t *this_patch,
                               int blockno, int this_patch_idx,
                               int initflag)
{
    fclaw2d_vtable_t vt;
    int mx,my,mbc,meqn;
    double xlower,ylower,dx,dy;
    double *q;
    int tag_patch;
    const amr_options_t *amropt;
    double rt;

    amropt = get_domain_parms(domain);
    rt = amropt->refine_threshold;

    vt = fclaw2d_get_vtable(domain);

    fclaw2d_clawpatch_grid_data(domain,this_patch,&mx,&my,&mbc,
                                &xlower,&ylower,&dx,&dy);

    fclaw2d_clawpatch_soln_data(domain,this_patch,&q,&meqn);

    tag_patch = 0;
    vt.fort_tag4refinement(&mx,&my,&mbc,&meqn,&xlower,&ylower,
                           &dx,&dy,&blockno, q,&rt,&initflag,
                           &tag_patch);
    return tag_patch;
}

int bowl_patch_tag4coarsening(fclaw2d_domain_t *domain,
                               fclaw2d_patch_t *fine_patches,
                               int blockno, int patchno)

{
    fclaw2d_vtable_t vt;

    int mx,my,mbc,meqn;
    double xlower,ylower,dx,dy;
    double *q[4];
    int tag_patch,igrid;
    double coarsen_threshold;
    fclaw2d_patch_t *patch0;

    patch0 = &fine_patches[0];

    const amr_options_t *amropt;
    amropt = get_domain_parms(domain);

    coarsen_threshold = amropt->coarsen_threshold;

    vt = fclaw2d_get_vtable(domain);

    fclaw2d_clawpatch_grid_data(domain,patch0,&mx,&my,&mbc,
                                &xlower,&ylower,&dx,&dy);

    for (igrid = 0; igrid < 4; igrid++)
    {
        fclaw2d_clawpatch_soln_data(domain,&fine_patches[igrid],&q[igrid],&meqn);
    }
    tag_patch = 0;
    vt.fort_tag4coarsening(&mx,&my,&mbc,&meqn,&xlower,&ylower,&dx,&dy,
                           &blockno, q[0],q[1],q[2],q[3],
                           &coarsen_threshold, &tag_patch);
    return tag_patch;

}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Manasij Mukherjee  <manasij7479@gmail.com>
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Path.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/AST.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/AutoloadCallback.h"
#include "cling/Interpreter/Transaction.h"

using namespace clang;

namespace cling {

  void AutoloadCallback::report(clang::SourceLocation l,std::string name,std::string header) {
    Sema& sema= m_Interpreter->getSema();

    unsigned id
      = sema.getDiagnostics().getCustomDiagID (DiagnosticsEngine::Level::Warning,
                                                 "Note: '%0' can be found in %1");
/*    unsigned idn //TODO: To be enabled after we have a way to get the full path
      = sema.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Level::Note,
                                                "Type : %0 , Full Path: %1")*/;

    sema.Diags.Report(l, id) << name << header;

  }

  bool AutoloadCallback::LookupObject (TagDecl *t) {
    if (t->hasAttr<AnnotateAttr>())
      report(t->getLocation(),t->getNameAsString(),t->getAttr<AnnotateAttr>()->getAnnotation());
    return false;
  }
  class DeclFixer : public DeclVisitor<DeclFixer> {
  public:
    void VisitDecl(Decl* D) {
      if (DeclContext* DC = dyn_cast<DeclContext>(D))
        for (auto Child : DC->decls())
          Visit(Child);
    }

    void VisitEnumDecl(EnumDecl* ED) {
      if (ED->isFixed()) {
        StringRef str = ED->getAttr<AnnotateAttr>()->getAnnotation();
        char ch = str.back();
        str.drop_back(2);
        ED->getAttr<AnnotateAttr>()->setAnnotation(ED->getASTContext(), str);
        struct EnumDeclDerived: public EnumDecl {
          static void setFixed(EnumDecl* ED, bool value = true) {
            ((EnumDeclDerived*)ED)->IsFixed = value;
          }
        };

        if (ch != '1')
          EnumDeclDerived::setFixed(ED, false);
      }
    }
  };

  class DefaultArgVisitor: public RecursiveASTVisitor<DefaultArgVisitor> {
  private:
    bool m_IsStoringState;
    AutoloadCallback::FwdDeclsMap* m_Map;
    clang::Preprocessor* m_PP;
  private:
    void InsertIntoAutoloadingState (Decl* decl, std::string annotation) {

      assert(annotation != "" && "Empty annotation!");
      assert(m_PP);

      const FileEntry* FE = 0;
      SourceLocation fileNameLoc;
      bool isAngled = false;
      const DirectoryLookup* LookupFrom = 0;
      const DirectoryLookup* CurDir = 0;

      FE = m_PP->LookupFile(fileNameLoc, annotation, isAngled, LookupFrom,
                            CurDir, /*SearchPath*/0, /*RelativePath*/ 0,
                            /*suggestedModule*/0, /*SkipCache*/false,
                            /*OpenFile*/ false, /*CacheFail*/ false);

      assert(FE && "Must have a valid FileEntry");

      if (m_Map->find(FE) == m_Map->end())
        (*m_Map)[FE] = std::vector<Decl*>();

      (*m_Map)[FE].push_back(decl);
    }

  public:
    DefaultArgVisitor() : m_IsStoringState(false), m_Map(0) {}
    void RemoveDefaultArgsOf(Decl* D) {
      //D = D->getMostRecentDecl();
      TraverseDecl(D);
      //while ((D = D->getPreviousDecl()))
      //  TraverseDecl(D);
    }

    void TrackDefaultArgStateOf(Decl* D, AutoloadCallback::FwdDeclsMap& map,
                                Preprocessor& PP) {
      m_IsStoringState = true;
      m_Map = ↦
      m_PP = &PP;
      TraverseDecl(D);
      m_PP = 0;
      m_Map = 0;
      m_IsStoringState = false;
    }

    bool shouldVisitTemplateInstantiations() { return true; }

    bool VisitDecl(Decl* D) {
      if (!m_IsStoringState)
        return true;

      if (!D->hasAttr<AnnotateAttr>())
        return true;

      AnnotateAttr* attr = D->getAttr<AnnotateAttr>();
      if (!attr)
        return true;

      switch (D->getKind()) {
      default:
        InsertIntoAutoloadingState(D, attr->getAnnotation());
        break;
      case Decl::Enum:
        // EnumDecls have extra information 2 chars after the filename used
        // for extra fixups.
        InsertIntoAutoloadingState(D, attr->getAnnotation().drop_back(2));
        break;
      }

      return true;
    }

    bool VisitCXXRecordDecl(CXXRecordDecl* D) {
      if (!D->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      if (ClassTemplateDecl* TmplD = D->getDescribedClassTemplate())
        return VisitTemplateDecl(TmplD);
      return true;
    }

    bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitTemplateDecl(TemplateDecl* D) {
      if (D->getTemplatedDecl() &&
          !D->getTemplatedDecl()->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      for(auto P: D->getTemplateParameters()->asArray())
        TraverseDecl(P);
      return true;
    }

    bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitParmVarDecl(ParmVarDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArg())
        D->setDefaultArg(nullptr);
      return true;
    }
  };

  void AutoloadCallback::InclusionDirective(clang::SourceLocation HashLoc,
                          const clang::Token &IncludeTok,
                          llvm::StringRef FileName,
                          bool IsAngled,
                          clang::CharSourceRange FilenameRange,
                          const clang::FileEntry *File,
                          llvm::StringRef SearchPath,
                          llvm::StringRef RelativePath,
                          const clang::Module *Imported) {
    assert(File && "Must have a valid File");

    auto found = m_Map.find(File);
    if (found == m_Map.end())
     return; // nothing to do, file not referred in any annotation

    DefaultArgVisitor defaultArgsCleaner;
    for (auto D : found->second) {
      defaultArgsCleaner.RemoveDefaultArgsOf(D);
    }
    // Don't need to keep track of cleaned up decls from file.
    m_Map.erase(found);
  }

  AutoloadCallback::AutoloadCallback(Interpreter* interp) :
    InterpreterCallbacks(interp,true,false,true), m_Interpreter(interp){
//#ifdef _POSIX_C_SOURCE
//      //Workaround for differnt expansion of macros to typedefs
//      m_Interpreter->parse("#include <sys/types.h>");
//#endif
  }

  AutoloadCallback::~AutoloadCallback() {
  }

  void AutoloadCallback::TransactionCommitted(const Transaction &T) {
    if (T.decls_begin() == T.decls_end())
      return;
    if (T.decls_begin()->m_DGR.isNull())
      return;

    if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
      if (ND->getIdentifier() && ND->getName().equals("__Cling_Autoloading_Map")) {
        DefaultArgVisitor defaultArgsStateCollector;
        Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
        for (Transaction::const_iterator I = T.decls_begin(), E = T.decls_end();
             I != E; ++I) {
          Transaction::DelayCallInfo DCI = *I;

          // if (DCI.m_Call != Transaction::kCCIHandleTopLevelDecl)
          //   continue;
          if (DCI.m_DGR.isNull())
            continue;

          if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
            if (ND->getIdentifier()
                && ND->getName().equals("__Cling_Autoloading_Map")) {

              DeclFixer visitor;
              for (Transaction::const_iterator I = T.decls_begin(),
                     E = T.decls_end(); I != E; ++I) {
                Transaction::DelayCallInfo DCI = *I;
                for (DeclGroupRef::iterator J = DCI.m_DGR.begin(),
                       JE = DCI.m_DGR.end(); J != JE; ++J) {
                  visitor.Visit(*J);
                }
              }
            }

          for (DeclGroupRef::iterator J = DCI.m_DGR.begin(),
                 JE = DCI.m_DGR.end(); J != JE; ++J) {
            defaultArgsStateCollector.TrackDefaultArgStateOf(*J, m_Map, PP);
          }
        }
      }
  }

} //end namespace cling
<commit_msg>Put DeclFixer logic in AutoloadingVisitor<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Manasij Mukherjee  <manasij7479@gmail.com>
// author:  Vassil Vassilev <vvasilev@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Path.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/AST.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/CompilerInstance.h"

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/AutoloadCallback.h"
#include "cling/Interpreter/Transaction.h"

using namespace clang;

namespace cling {

  void AutoloadCallback::report(clang::SourceLocation l,std::string name,std::string header) {
    Sema& sema= m_Interpreter->getSema();

    unsigned id
      = sema.getDiagnostics().getCustomDiagID (DiagnosticsEngine::Level::Warning,
                                                 "Note: '%0' can be found in %1");
/*    unsigned idn //TODO: To be enabled after we have a way to get the full path
      = sema.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Level::Note,
                                                "Type : %0 , Full Path: %1")*/;

    sema.Diags.Report(l, id) << name << header;

  }

  bool AutoloadCallback::LookupObject (TagDecl *t) {
    if (t->hasAttr<AnnotateAttr>())
      report(t->getLocation(),t->getNameAsString(),t->getAttr<AnnotateAttr>()->getAnnotation());
    return false;
  }

  class AutoloadingVisitor: public RecursiveASTVisitor<AutoloadingVisitor> {
  private:
    bool m_IsStoringState;
    AutoloadCallback::FwdDeclsMap* m_Map;
    clang::Preprocessor* m_PP;
  private:
    void InsertIntoAutoloadingState (Decl* decl, std::string annotation) {

      assert(annotation != "" && "Empty annotation!");
      assert(m_PP);

      const FileEntry* FE = 0;
      SourceLocation fileNameLoc;
      bool isAngled = false;
      const DirectoryLookup* LookupFrom = 0;
      const DirectoryLookup* CurDir = 0;

      FE = m_PP->LookupFile(fileNameLoc, annotation, isAngled, LookupFrom,
                            CurDir, /*SearchPath*/0, /*RelativePath*/ 0,
                            /*suggestedModule*/0, /*SkipCache*/false,
                            /*OpenFile*/ false, /*CacheFail*/ false);

      assert(FE && "Must have a valid FileEntry");

      if (m_Map->find(FE) == m_Map->end())
        (*m_Map)[FE] = std::vector<Decl*>();

      (*m_Map)[FE].push_back(decl);
    }

  public:
    AutoloadingVisitor() : m_IsStoringState(false), m_Map(0) {}
    void RemoveDefaultArgsOf(Decl* D) {
      //D = D->getMostRecentDecl();
      TraverseDecl(D);
      //while ((D = D->getPreviousDecl()))
      //  TraverseDecl(D);
    }

    void TrackDefaultArgStateOf(Decl* D, AutoloadCallback::FwdDeclsMap& map,
                                Preprocessor& PP) {
      m_IsStoringState = true;
      m_Map = ↦
      m_PP = &PP;
      TraverseDecl(D);
      m_PP = 0;
      m_Map = 0;
      m_IsStoringState = false;
    }

    bool shouldVisitTemplateInstantiations() { return true; }

    bool VisitDecl(Decl* D) {
      if (!m_IsStoringState)
        return true;

      if (!D->hasAttr<AnnotateAttr>())
        return true;

      AnnotateAttr* attr = D->getAttr<AnnotateAttr>();
      if (!attr)
        return true;

      switch (D->getKind()) {
      default:
        InsertIntoAutoloadingState(D, attr->getAnnotation());
        break;
      case Decl::Enum:
        // EnumDecls have extra information 2 chars after the filename used
        // for extra fixups.
          EnumDecl* ED = cast<EnumDecl>(D);
          if (ED->isFixed()) {
            StringRef str = ED->getAttr<AnnotateAttr>()->getAnnotation();
            char ch = str.back();
//            str.drop_back(2);
            ED->getAttr<AnnotateAttr>()->setAnnotation(ED->getASTContext(), str);
            struct EnumDeclDerived: public EnumDecl {
              static void setFixed(EnumDecl* ED, bool value = true) {
                ((EnumDeclDerived*)ED)->IsFixed = value;
              }
            };

            if (ch != '1')
              EnumDeclDerived::setFixed(ED, false);
          }
        InsertIntoAutoloadingState(D, attr->getAnnotation().drop_back(2));
        break;
      }

      return true;
    }

    bool VisitCXXRecordDecl(CXXRecordDecl* D) {
      if (!D->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      if (ClassTemplateDecl* TmplD = D->getDescribedClassTemplate())
        return VisitTemplateDecl(TmplD);
      return true;
    }

    bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitTemplateDecl(TemplateDecl* D) {
      if (D->getTemplatedDecl() &&
          !D->getTemplatedDecl()->hasAttr<AnnotateAttr>())
        return true;

      VisitDecl(D);

      for(auto P: D->getTemplateParameters()->asArray())
        TraverseDecl(P);
      return true;
    }

    bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArgument())
        D->removeDefaultArgument();
      return true;
    }

    bool VisitParmVarDecl(ParmVarDecl* D) {
      VisitDecl(D);

      if (m_IsStoringState)
        return true;

      if (D->hasDefaultArg())
        D->setDefaultArg(nullptr);
      return true;
    }
  };

  void AutoloadCallback::InclusionDirective(clang::SourceLocation HashLoc,
                          const clang::Token &IncludeTok,
                          llvm::StringRef FileName,
                          bool IsAngled,
                          clang::CharSourceRange FilenameRange,
                          const clang::FileEntry *File,
                          llvm::StringRef SearchPath,
                          llvm::StringRef RelativePath,
                          const clang::Module *Imported) {
    assert(File && "Must have a valid File");

    auto found = m_Map.find(File);
    if (found == m_Map.end())
     return; // nothing to do, file not referred in any annotation

    AutoloadingVisitor defaultArgsCleaner;
    for (auto D : found->second) {
      defaultArgsCleaner.RemoveDefaultArgsOf(D);
    }
    // Don't need to keep track of cleaned up decls from file.
    m_Map.erase(found);
  }

  AutoloadCallback::AutoloadCallback(Interpreter* interp) :
    InterpreterCallbacks(interp,true,false,true), m_Interpreter(interp){
//#ifdef _POSIX_C_SOURCE
//      //Workaround for differnt expansion of macros to typedefs
//      m_Interpreter->parse("#include <sys/types.h>");
//#endif
  }

  AutoloadCallback::~AutoloadCallback() {
  }

  void AutoloadCallback::TransactionCommitted(const Transaction &T) {
    if (T.decls_begin() == T.decls_end())
      return;
    if (T.decls_begin()->m_DGR.isNull())
      return;

    if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
      if (ND->getIdentifier() && ND->getName().equals("__Cling_Autoloading_Map")) {
        AutoloadingVisitor defaultArgsStateCollector;
        Preprocessor& PP = m_Interpreter->getCI()->getPreprocessor();
        for (Transaction::const_iterator I = T.decls_begin(), E = T.decls_end();
             I != E; ++I) {
          Transaction::DelayCallInfo DCI = *I;

          // if (DCI.m_Call != Transaction::kCCIHandleTopLevelDecl)
          //   continue;
          if (DCI.m_DGR.isNull())
            continue;

          if (const NamedDecl* ND = dyn_cast<NamedDecl>(*T.decls_begin()->m_DGR.begin()))
            if (ND->getIdentifier()
                && ND->getName().equals("__Cling_Autoloading_Map")) {

              for (Transaction::const_iterator I = T.decls_begin(),
                     E = T.decls_end(); I != E; ++I) {
                Transaction::DelayCallInfo DCI = *I;
                for (DeclGroupRef::iterator J = DCI.m_DGR.begin(),
                       JE = DCI.m_DGR.end(); J != JE; ++J) {
                    defaultArgsStateCollector.TrackDefaultArgStateOf(*J, m_Map, PP);
                }
              }
            }

        }
      }
  }

} //end namespace cling
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  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

#include "bochs.h"
#include <assert.h>
#include "state_file.h"

static char *divider = "========================================================================";

// Just for the iofunctions

#define LOG_THIS this->log->

int Allocio=0;

void
iofunctions::flush(void) {
	if(logfd && magic == MAGIC_LOGNUM) {
		fflush(logfd);
	}
}

void
iofunctions::init(void) {
	// iofunctions methods must not be called before this magic
	// number is set.
	magic=MAGIC_LOGNUM;
	showtick = 1;
	n_logfn = 0;
	init_log(stderr);
	log = new logfunc_t(this);
	LOG_THIS put("IO");
	LOG_THIS settype(IOLOG);
	BX_DEBUG(("Init(log file: '%s').",logfn));
}

void
iofunctions::add_logfn (logfunc_t *fn)
{
  assert (n_logfn < MAX_LOGFNS);
  logfn_list[n_logfn++] = fn;
}

void
iofunctions::set_log_action (int loglevel, int action)
{
  for (int i=0; i<n_logfn; i++)
    logfn_list[i]->setonoff(loglevel, action);
}

void
iofunctions::init_log(const char *fn)
{
	assert (magic==MAGIC_LOGNUM);
	// use newfd/newfn so that we can log the message to the OLD log
	// file descriptor.
	FILE *newfd = stderr;
	char *newfn = "/dev/stderr";
	if( strcmp( fn, "-" ) != 0 ) {
		newfd = fopen(fn, "w");
		if(newfd != NULL) {
			newfn = strdup(fn);
			BX_DEBUG(("Opened log file '%s'.", fn ));
		} else {
		  	BX_PANIC(("Couldn't open log file: %s", fn));
		}
	}
	logfd = newfd;
	logfn = newfn;
}

void
iofunctions::init_log(FILE *fs)
{
	assert (magic==MAGIC_LOGNUM);
	logfd = fs;

	if(fs == stderr) {
		logfn = "/dev/stderr";
	} else if(fs == stdout) {
		logfn = "/dev/stdout";
	} else {
		logfn = "(unknown)";
	}
}

void
iofunctions::init_log(int fd)
{
	assert (magic==MAGIC_LOGNUM);
	FILE *tmpfd;
	if( (tmpfd = fdopen(fd,"w")) == NULL ) {
	  BX_PANIC(("Couldn't open fd %d as a stream for writing", fd));
	  return;
	}

	init_log(tmpfd);
	return;
};

//  iofunctions::out( class, level, prefix, fmt, ap)
//  DO NOT nest out() from ::info() and the like.
//    fmt and ap retained for direct printinf from iofunctions only!

void
iofunctions::out(int f, int l, const char *prefix, const char *fmt, va_list ap)
{
	char c=' ';
	assert (magic==MAGIC_LOGNUM);
	assert (this != NULL);
	assert (logfd != NULL);

	if( showtick )
		fprintf(logfd, "%011lld", bx_pc_system.time_ticks());

	switch(l) {
		case LOGLEV_INFO: c='i'; break;
		case LOGLEV_PANIC: c='p'; break;
		case LOGLEV_ERROR: c='e'; break;
		case LOGLEV_DEBUG: c='d'; break;
		default: break;
	}
	fprintf(logfd, "%c",c);

	if(prefix != NULL)
		fprintf(logfd, "%s ", prefix);

	if(l==LOGLEV_PANIC)
		fprintf(logfd, ">>PANIC<< ");

	vfprintf(logfd, fmt, ap);
	fprintf(logfd, "\n");
	fflush(logfd);

	return;
}

iofunctions::iofunctions(FILE *fs)
{
	init();
	init_log(fs);
}

iofunctions::iofunctions(const char *fn)
{
	init();
	init_log(fn);
}

iofunctions::iofunctions(int fd)
{
	init();
	init_log(fd);
}

iofunctions::iofunctions(void)
{
	this->init();
}

iofunctions::~iofunctions(void)
{
	// flush before erasing magic number, or flush does nothing.
	this->flush();
	this->magic=0;
}

#undef LOG_THIS
#define LOG_THIS genlog->

logfunctions::logfunctions(void)
{
	put(" ");
	settype(GENLOG);
	if(io == NULL && Allocio == 0) {
		Allocio = 1;
		io = new iofunc_t(stderr);
	}
	setio(io);
	// BUG: unfortunately this can be called before the bochsrc is read,
	// which means that the bochsrc has no effect on the actions.
	for (int i=0; i<N_LOGLEV; i++)
	  onoff[i] = bx_options.log.actions[i];
}

logfunctions::logfunctions(iofunc_t *iofunc)
{
	put(" ");
	settype(GENLOG);
	setio(iofunc);
	// BUG: unfortunately this can be called before the bochsrc is read,
	// which means that the bochsrc has no effect on the actions.
	for (int i=0; i<N_LOGLEV; i++)
	  onoff[i] = bx_options.log.actions[i];
}

logfunctions::~logfunctions(void)
{
}

void
logfunctions::setio(iofunc_t *i)
{
  	// add pointer to iofunction object to use
	this->logio = i;
	// give iofunction a pointer to me
	i->add_logfn (this);
}

void
logfunctions::put(char *p)
{
	char *tmpbuf;
	tmpbuf=strdup("[     ]");// if we ever have more than 32 chars,
						   //  we need to rethink this
	int len=strlen(p);
	for(int i=1;i<len+1;i++) {
		tmpbuf[i]=p[i-1];
	}

	switch(len) {
	case  1: tmpbuf[2]=' ';
	case  2: tmpbuf[3]=' ';
	case  3: tmpbuf[4]=' ';
	case  4: tmpbuf[5]=' ';
	default: tmpbuf[6]=']'; tmpbuf[7]='\0'; break;
	}

	this->prefix=tmpbuf;
}

void
logfunctions::settype(int t)
{
	type=t;
}

void
logfunctions::info(const char *fmt, ...)
{
	va_list ap;

	assert (this != NULL);
	assert (this->logio != NULL);

	if(!onoff[LOGLEV_INFO]) return;

	va_start(ap, fmt);
	this->logio->out(this->type,LOGLEV_INFO,this->prefix, fmt, ap);
	if (onoff[LOGLEV_INFO] == ACT_ASK)
	  ask (LOGLEV_INFO, this->prefix, fmt, ap);
	if (onoff[LOGLEV_INFO] == ACT_FATAL)
	  fatal (this->prefix, fmt, ap);
	va_end(ap);

}

void
logfunctions::error(const char *fmt, ...)
{
	va_list ap;

	assert (this != NULL);
	assert (this->logio != NULL);

	if(!onoff[LOGLEV_ERROR]) return;

	va_start(ap, fmt);
	this->logio->out(this->type,LOGLEV_ERROR,this->prefix, fmt, ap);
	if (onoff[LOGLEV_ERROR] == ACT_ASK)
	  ask (LOGLEV_ERROR, this->prefix, fmt, ap);
	if (onoff[LOGLEV_ERROR] == ACT_FATAL)
	  fatal (this->prefix, fmt, ap);
	va_end(ap);
}

void
logfunctions::panic(const char *fmt, ...)
{
	va_list ap;

	assert (this != NULL);
	assert (this->logio != NULL);

	// Special case for panics since they are so important.  Always print
	// the panic to the log, no matter what the log action says.
	//if(!onoff[LOGLEV_PANIC]) return;

	va_start(ap, fmt);
	this->logio->out(this->type,LOGLEV_PANIC,this->prefix, fmt, ap);
	if (onoff[LOGLEV_PANIC] == ACT_ASK)
	  ask (LOGLEV_PANIC, this->prefix, fmt, ap);
	if (onoff[LOGLEV_PANIC] == ACT_FATAL)
	  fatal (this->prefix, fmt, ap);
	va_end(ap);
}

void
logfunctions::ldebug(const char *fmt, ...)
{
	va_list ap;

	assert (this != NULL);
	assert (this->logio != NULL);

	if(!onoff[LOGLEV_DEBUG]) return;

	va_start(ap, fmt);
	this->logio->out(this->type,LOGLEV_DEBUG,this->prefix, fmt, ap);
	if (onoff[LOGLEV_DEBUG] == ACT_ASK)
	  ask (LOGLEV_DEBUG, this->prefix, fmt, ap);
	if (onoff[LOGLEV_DEBUG] == ACT_FATAL)
	  fatal (this->prefix, fmt, ap);
	va_end(ap);
}

void
logfunctions::ask (int level, const char *prefix, const char *fmt, va_list ap)
{
  char buf1[1024], buf2[1024];
  vsprintf (buf1, fmt, ap);
  sprintf (buf2, "%s %s", prefix, buf1);
  // FIXME: facility set to 0 because it's unknown.
  int val = SIM->LOCAL_log_msg (prefix, level, buf2);
  switch (val)
  {
    case 0:   // user chose continue
      break;
    case 1:   // user said continue, and don't ask for this facility again.
      setonoff (level, ACT_REPORT);
      break;
    case 2:   // user chose die
      fatal (prefix, fmt, ap);
    case 3: // user chose abort
      fprintf (stderr, "User chose to dump core...\n");
#if BX_HAVE_ABORT
      abort ();
#else
      // do something highly illegal that should kill the process.
      // Hey, this is fun!
      {
      char *crashptr = (char *)0; char c = *crashptr;
      }
      fprintf (stderr, "Sorry, I couldn't find your abort() function.  Exiting.");
      exit (0);
#endif
#if BX_DEBUGGER
    case 4:
      // user chose debugger.  To "drop into the debugger" we just set the
      // interrupt_requested bit and continue execution.  Before the next
      // instruction, it should notice the user interrupt and return to
      // the debugger.
      bx_guard.interrupt_requested = 1;
      break;
#endif
    default:
      // this happens if panics happen before the callback is initialized
      // in gui/control.cc.
      fprintf (stderr, "WARNING: LOCAL_log_msg returned unexpected value %d\n", val);
  }
}

void
logfunctions::fatal (const char *prefix, const char *fmt, va_list ap)
{
  static int fatal_reentry = 0;
  if (fatal_reentry) return;
  fatal_reentry++;
  bx_atexit();
  fprintf (stderr, "%s\n", divider);
  fprintf (stderr, "Bochs is exiting with the following message:\n");
  fprintf (stderr, "%s ", prefix);
  vfprintf (stderr, fmt, ap);
  fprintf (stderr, "\n%s\n", divider);
#if 0 && defined(WIN32)
#error disabled because it  is not working yet!
  // wait for a keypress before quitting.  Depending on how bochs is
  // installed, the console window can disappear before the user has
  // a chance to read the final message.
  fprintf (stderr, "\n\nPress Enter to exit...\n");
  char buf[8];
  fgets (buf, 8, stdin);
#endif
#if !BX_DEBUGGER
  exit(1);
#else
  static Boolean dbg_exit_called = 0;
  if (dbg_exit_called == 0) {
    dbg_exit_called = 1;
    bx_dbg_exit(1);
    }
#endif
  fatal_reentry--;
}

iofunc_t *io = NULL;
logfunc_t *genlog = NULL;

void bx_center_print (FILE *file, char *line, int maxwidth)
{
  int imax;
  imax = (maxwidth - strlen(line)) >> 1;
  for (int i=0; i<imax; i++) fputc (' ', file);
  fputs (line, file);
}

<commit_msg>- update vga screen when you enter the logfunctions::ask() function.  This is   useful because sometimes useful messages are printed on the screen just   before a panic.  It's also potentially dangerous if the vga update function   calls ask() again...so I added a re-entry check.<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  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

#include "bochs.h"
#include <assert.h>
#include "state_file.h"

static char *divider = "========================================================================";

// Just for the iofunctions

#define LOG_THIS this->log->

int Allocio=0;

void
iofunctions::flush(void) {
	if(logfd && magic == MAGIC_LOGNUM) {
		fflush(logfd);
	}
}

void
iofunctions::init(void) {
	// iofunctions methods must not be called before this magic
	// number is set.
	magic=MAGIC_LOGNUM;
	showtick = 1;
	n_logfn = 0;
	init_log(stderr);
	log = new logfunc_t(this);
	LOG_THIS put("IO");
	LOG_THIS settype(IOLOG);
	BX_DEBUG(("Init(log file: '%s').",logfn));
}

void
iofunctions::add_logfn (logfunc_t *fn)
{
  assert (n_logfn < MAX_LOGFNS);
  logfn_list[n_logfn++] = fn;
}

void
iofunctions::set_log_action (int loglevel, int action)
{
  for (int i=0; i<n_logfn; i++)
    logfn_list[i]->setonoff(loglevel, action);
}

void
iofunctions::init_log(const char *fn)
{
	assert (magic==MAGIC_LOGNUM);
	// use newfd/newfn so that we can log the message to the OLD log
	// file descriptor.
	FILE *newfd = stderr;
	char *newfn = "/dev/stderr";
	if( strcmp( fn, "-" ) != 0 ) {
		newfd = fopen(fn, "w");
		if(newfd != NULL) {
			newfn = strdup(fn);
			BX_DEBUG(("Opened log file '%s'.", fn ));
		} else {
		  	BX_PANIC(("Couldn't open log file: %s", fn));
		}
	}
	logfd = newfd;
	logfn = newfn;
}

void
iofunctions::init_log(FILE *fs)
{
	assert (magic==MAGIC_LOGNUM);
	logfd = fs;

	if(fs == stderr) {
		logfn = "/dev/stderr";
	} else if(fs == stdout) {
		logfn = "/dev/stdout";
	} else {
		logfn = "(unknown)";
	}
}

void
iofunctions::init_log(int fd)
{
	assert (magic==MAGIC_LOGNUM);
	FILE *tmpfd;
	if( (tmpfd = fdopen(fd,"w")) == NULL ) {
	  BX_PANIC(("Couldn't open fd %d as a stream for writing", fd));
	  return;
	}

	init_log(tmpfd);
	return;
};

//  iofunctions::out( class, level, prefix, fmt, ap)
//  DO NOT nest out() from ::info() and the like.
//    fmt and ap retained for direct printinf from iofunctions only!

void
iofunctions::out(int f, int l, const char *prefix, const char *fmt, va_list ap)
{
	char c=' ';
	assert (magic==MAGIC_LOGNUM);
	assert (this != NULL);
	assert (logfd != NULL);

	if( showtick )
		fprintf(logfd, "%011lld", bx_pc_system.time_ticks());

	switch(l) {
		case LOGLEV_INFO: c='i'; break;
		case LOGLEV_PANIC: c='p'; break;
		case LOGLEV_ERROR: c='e'; break;
		case LOGLEV_DEBUG: c='d'; break;
		default: break;
	}
	fprintf(logfd, "%c",c);

	if(prefix != NULL)
		fprintf(logfd, "%s ", prefix);

	if(l==LOGLEV_PANIC)
		fprintf(logfd, ">>PANIC<< ");

	vfprintf(logfd, fmt, ap);
	fprintf(logfd, "\n");
	fflush(logfd);

	return;
}

iofunctions::iofunctions(FILE *fs)
{
	init();
	init_log(fs);
}

iofunctions::iofunctions(const char *fn)
{
	init();
	init_log(fn);
}

iofunctions::iofunctions(int fd)
{
	init();
	init_log(fd);
}

iofunctions::iofunctions(void)
{
	this->init();
}

iofunctions::~iofunctions(void)
{
	// flush before erasing magic number, or flush does nothing.
	this->flush();
	this->magic=0;
}

#undef LOG_THIS
#define LOG_THIS genlog->

logfunctions::logfunctions(void)
{
	put(" ");
	settype(GENLOG);
	if(io == NULL && Allocio == 0) {
		Allocio = 1;
		io = new iofunc_t(stderr);
	}
	setio(io);
	// BUG: unfortunately this can be called before the bochsrc is read,
	// which means that the bochsrc has no effect on the actions.
	for (int i=0; i<N_LOGLEV; i++)
	  onoff[i] = bx_options.log.actions[i];
}

logfunctions::logfunctions(iofunc_t *iofunc)
{
	put(" ");
	settype(GENLOG);
	setio(iofunc);
	// BUG: unfortunately this can be called before the bochsrc is read,
	// which means that the bochsrc has no effect on the actions.
	for (int i=0; i<N_LOGLEV; i++)
	  onoff[i] = bx_options.log.actions[i];
}

logfunctions::~logfunctions(void)
{
}

void
logfunctions::setio(iofunc_t *i)
{
  	// add pointer to iofunction object to use
	this->logio = i;
	// give iofunction a pointer to me
	i->add_logfn (this);
}

void
logfunctions::put(char *p)
{
	char *tmpbuf;
	tmpbuf=strdup("[     ]");// if we ever have more than 32 chars,
						   //  we need to rethink this
	int len=strlen(p);
	for(int i=1;i<len+1;i++) {
		tmpbuf[i]=p[i-1];
	}

	switch(len) {
	case  1: tmpbuf[2]=' ';
	case  2: tmpbuf[3]=' ';
	case  3: tmpbuf[4]=' ';
	case  4: tmpbuf[5]=' ';
	default: tmpbuf[6]=']'; tmpbuf[7]='\0'; break;
	}

	this->prefix=tmpbuf;
}

void
logfunctions::settype(int t)
{
	type=t;
}

void
logfunctions::info(const char *fmt, ...)
{
	va_list ap;

	assert (this != NULL);
	assert (this->logio != NULL);

	if(!onoff[LOGLEV_INFO]) return;

	va_start(ap, fmt);
	this->logio->out(this->type,LOGLEV_INFO,this->prefix, fmt, ap);
	if (onoff[LOGLEV_INFO] == ACT_ASK)
	  ask (LOGLEV_INFO, this->prefix, fmt, ap);
	if (onoff[LOGLEV_INFO] == ACT_FATAL)
	  fatal (this->prefix, fmt, ap);
	va_end(ap);

}

void
logfunctions::error(const char *fmt, ...)
{
	va_list ap;

	assert (this != NULL);
	assert (this->logio != NULL);

	if(!onoff[LOGLEV_ERROR]) return;

	va_start(ap, fmt);
	this->logio->out(this->type,LOGLEV_ERROR,this->prefix, fmt, ap);
	if (onoff[LOGLEV_ERROR] == ACT_ASK)
	  ask (LOGLEV_ERROR, this->prefix, fmt, ap);
	if (onoff[LOGLEV_ERROR] == ACT_FATAL)
	  fatal (this->prefix, fmt, ap);
	va_end(ap);
}

void
logfunctions::panic(const char *fmt, ...)
{
	va_list ap;

	assert (this != NULL);
	assert (this->logio != NULL);

	// Special case for panics since they are so important.  Always print
	// the panic to the log, no matter what the log action says.
	//if(!onoff[LOGLEV_PANIC]) return;

	va_start(ap, fmt);
	this->logio->out(this->type,LOGLEV_PANIC,this->prefix, fmt, ap);
	if (onoff[LOGLEV_PANIC] == ACT_ASK)
	  ask (LOGLEV_PANIC, this->prefix, fmt, ap);
	if (onoff[LOGLEV_PANIC] == ACT_FATAL)
	  fatal (this->prefix, fmt, ap);
	va_end(ap);
}

void
logfunctions::ldebug(const char *fmt, ...)
{
	va_list ap;

	assert (this != NULL);
	assert (this->logio != NULL);

	if(!onoff[LOGLEV_DEBUG]) return;

	va_start(ap, fmt);
	this->logio->out(this->type,LOGLEV_DEBUG,this->prefix, fmt, ap);
	if (onoff[LOGLEV_DEBUG] == ACT_ASK)
	  ask (LOGLEV_DEBUG, this->prefix, fmt, ap);
	if (onoff[LOGLEV_DEBUG] == ACT_FATAL)
	  fatal (this->prefix, fmt, ap);
	va_end(ap);
}

void
logfunctions::ask (int level, const char *prefix, const char *fmt, va_list ap)
{
  static char in_ask_already = 0;
  char buf1[1024], buf2[1024];
  if (in_ask_already) {
    fprintf (stderr, "logfunctions::ask() should not reenter!!\n");
    return;
  }
  in_ask_already = 1;
  vsprintf (buf1, fmt, ap);
  sprintf (buf2, "%s %s", prefix, buf1);
  // FIXME: facility set to 0 because it's unknown.

  // update vga screen.  This is useful because sometimes useful messages
  // are printed on the screen just before a panic.  It's also potentially
  // dangerous if this function calls ask again...  That's why I added
  // the reentry check above.
  bx_vga.timer_handler(&bx_vga);

  int val = SIM->LOCAL_log_msg (prefix, level, buf2);
  switch (val)
  {
    case 0:   // user chose continue
      break;
    case 1:   // user said continue, and don't ask for this facility again.
      setonoff (level, ACT_REPORT);
      break;
    case 2:   // user chose die
      fatal (prefix, fmt, ap);
    case 3: // user chose abort
      fprintf (stderr, "User chose to dump core...\n");
#if BX_HAVE_ABORT
      abort ();
#else
      // do something highly illegal that should kill the process.
      // Hey, this is fun!
      {
      char *crashptr = (char *)0; char c = *crashptr;
      }
      fprintf (stderr, "Sorry, I couldn't find your abort() function.  Exiting.");
      exit (0);
#endif
#if BX_DEBUGGER
    case 4:
      // user chose debugger.  To "drop into the debugger" we just set the
      // interrupt_requested bit and continue execution.  Before the next
      // instruction, it should notice the user interrupt and return to
      // the debugger.
      bx_guard.interrupt_requested = 1;
      break;
#endif
    default:
      // this happens if panics happen before the callback is initialized
      // in gui/control.cc.
      fprintf (stderr, "WARNING: LOCAL_log_msg returned unexpected value %d\n", val);
  }
  in_ask_already = 0;
}

void
logfunctions::fatal (const char *prefix, const char *fmt, va_list ap)
{
  static int fatal_reentry = 0;
  if (fatal_reentry) return;
  fatal_reentry++;
  bx_atexit();
  fprintf (stderr, "%s\n", divider);
  fprintf (stderr, "Bochs is exiting with the following message:\n");
  fprintf (stderr, "%s ", prefix);
  vfprintf (stderr, fmt, ap);
  fprintf (stderr, "\n%s\n", divider);
#if 0 && defined(WIN32)
#error disabled because it  is not working yet!
  // wait for a keypress before quitting.  Depending on how bochs is
  // installed, the console window can disappear before the user has
  // a chance to read the final message.
  fprintf (stderr, "\n\nPress Enter to exit...\n");
  char buf[8];
  fgets (buf, 8, stdin);
#endif
#if !BX_DEBUGGER
  exit(1);
#else
  static Boolean dbg_exit_called = 0;
  if (dbg_exit_called == 0) {
    dbg_exit_called = 1;
    bx_dbg_exit(1);
    }
#endif
  fatal_reentry--;
}

iofunc_t *io = NULL;
logfunc_t *genlog = NULL;

void bx_center_print (FILE *file, char *line, int maxwidth)
{
  int imax;
  imax = (maxwidth - strlen(line)) >> 1;
  for (int i=0; i<imax; i++) fputc (' ', file);
  fputs (line, file);
}

<|endoftext|>