include/keima.h
author David Anderson <dvander@alliedmods.net>
Sat Dec 22 19:48:43 2012 -0800 (2012-12-22)
changeset 232 2b8512340180
parent 195 c1ba166f3fc4
child 251 ca99a81745fe
permissions -rw-r--r--
Re-introduce definite return analysis.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2004-2012 David Anderson
     4  *
     5  * This file is part of SourcePawn.
     6  *
     7  * SourcePawn is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * SourcePawn. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #ifndef _include_sourcepawn2_api_h_
    20 #define _include_sourcepawn2_api_h_
    21 
    22 #include <assert.h>
    23 #include <stddef.h>
    24 #include "../include/keima_util.h"
    25 
    26 namespace ke {
    27 
    28 class Zone;
    29 class Object;
    30 class HandleScope;
    31 class HeapRoot;
    32 
    33 }
    34 
    35 namespace Ke {
    36 
    37 class Function;
    38 
    39 /*
    40  * A Handle is a safe pointer that holds an object reference, such that it
    41  * can be scanned and potentially moved by the garbage collector.
    42  */
    43 template <typename T>
    44 class Handle
    45 {
    46     template <typename S> friend class Root;
    47   protected:
    48     template <typename S> void typeCheck() {
    49         while (false) {
    50             T *v1 = NULL;
    51             S *v2 = NULL;
    52             v1 = v2;
    53             (void)v1;
    54         }
    55     }
    56 
    57   public:
    58     Handle()
    59       : obj_(NULL)
    60     {
    61     }
    62 
    63     template <typename S> Handle(Handle<S> other)
    64       : obj_(reinterpret_cast<S *>(*other))
    65     {
    66         typeCheck<S>();
    67     }
    68  
    69     explicit Handle(T *obj)
    70       : obj_(obj)
    71     {
    72     }
    73 
    74     T *operator ->() const {
    75         return obj_;
    76     }
    77     T *operator *() const {
    78         return obj_;
    79     }
    80     operator bool () const {
    81         return !!obj_;
    82     }
    83 
    84   protected:
    85     T *obj_;
    86 };
    87 
    88 /*
    89  * A local variable that roots an object. Locals are owned by the nearest
    90  * HandleScope, and as soon as that HandleScope dies, all its Locals are
    91  * no longer available.
    92  */
    93 template <typename T>
    94 class Local : public Handle<T>
    95 {
    96   public:
    97     Local()
    98       : Handle<T>()
    99     {
   100     }
   101 
   102     template <typename S> Local(Local<S> other)
   103       : Handle<T>(reinterpret_cast<T *>(*other))
   104     {
   105         this->template typeCheck<S>();
   106     }
   107 
   108     template <typename S> Local(S *other)
   109       : Handle<T>(other)
   110     {
   111     }
   112 };
   113 
   114 /*
   115  * A non-local variable that outlives HandleScopes. Unlike Local, a Root
   116  * actually represents a rooted location. Roots must be allocated and
   117  * disposed, and assignment to a root changes its contained object, not
   118  * the location of the object.
   119  */
   120 template <typename T>
   121 class Root
   122 {
   123   public:
   124     Root()
   125       : root_(NULL)
   126     {
   127     }
   128 
   129     Root(Handle<T> other)
   130       : root_(NULL)
   131     {
   132         set(other);
   133     }
   134 
   135     inline ~Root();
   136 
   137     operator const Handle<T>() const {
   138         return obj_;
   139     }
   140 
   141     bool operator ==(Handle<T> other) {
   142         return Handle<T>(*this) == other;
   143     }
   144     Root<T> &operator =(Handle<T> other) {
   145         set(other);
   146         return *this;
   147     }
   148 
   149   private:
   150     void set(Handle<T> other);
   151 
   152     ke::HeapRoot *root_;
   153     Handle<T> obj_;
   154 };
   155 
   156 /*
   157  * A HandleScope is where Local roots are allcoated. When the HandleScope
   158  * is destroyed, all Handles created under it are also destroyed. HandleScopes
   159  * may only be allocated on the stack, in LIFO order.
   160  */
   161 class HandleScope
   162 {
   163   protected:
   164     ke::Zone *zone_;
   165     ke::Object **position_;
   166     HandleScope *prev_;
   167 
   168     HandleScope(ke::Zone *zone, ke::Object **position, HandleScope *prev)
   169       : zone_(zone),
   170         position_(position),
   171         prev_(prev)
   172     {
   173     }
   174 
   175   public:
   176     HandleScope();
   177     ~HandleScope();
   178 
   179     static ke::Object **CreateHandle(ke::Object *obj);
   180 
   181   private:
   182     // Disallow silly stuff.
   183     HandleScope(const HandleScope &);
   184     void operator =(const HandleScope &);
   185     void *operator new (size_t size);
   186     void operator delete(void *, size_t);
   187 };
   188 
   189 class Parameter;
   190 
   191 // Error messages are pumped through this interface.
   192 class IMessageReporter
   193 {
   194   public:
   195     virtual void onOutOfMemory() {
   196     }
   197     virtual void onUncaughtException(const char *message) {
   198     }
   199     virtual void beginCompilationErrors(const char *file) {
   200     }
   201     virtual void reportCompilationError(const char *message, unsigned line, unsigned col) {
   202     }
   203     virtual void endCompilationErrors() {
   204     }
   205 };
   206 
   207 // For the purposes of error reporting, very basic information can be queried
   208 // about the stack frame. This structure may be used to retrieve such
   209 // information. During iteration, it is illegal to re-enter any scripted code
   210 // or call any Keima functions that may cause garbage collection.
   211 class IStackFrameIterator
   212 {
   213   public:
   214     virtual ~IStackFrameIterator() {
   215     }
   216 
   217     // Returns true if there are more frames, false otherwise.
   218     virtual bool done() = 0;
   219 
   220     // Returns the name of the current function. This may be NULL if the
   221     // function is anonymous.
   222     virtual const char *function() = 0;
   223 
   224     // Returns the file of the current function. This will return an invalid
   225     // path for C++ functions (for example, "<native>").
   226     virtual const char *source() = 0;
   227 
   228     // Returns the line number currently executing on this frame. For C++
   229     // functions, this is always 0.
   230     virtual unsigned lineNumber() = 0;
   231 
   232     // Advance to the previous frame in the call stack.
   233     virtual void prev() = 0;
   234 };
   235 
   236 // Listener interface for when public functions are registered or unregisted.
   237 class IPublicFunctionListener
   238 {
   239   public:
   240     virtual ~IPublicFunctionListener() {
   241     }
   242 
   243     // Called when a public function becomes available to the runtime.
   244     virtual void registerPublic(Handle<Function> fun) = 0;
   245 
   246     // Called when a public is no longer available to the runtime.
   247     virtual void unregisterPublic(Handle<Function> fun) = 0;
   248 };
   249 
   250 // A string is an immutable UTF8 buffer.
   251 class KE_EXPORT String
   252 {
   253   public:
   254     // Returns the length of the string, in bytes.
   255     unsigned length();
   256 
   257     // Returns the character buffer of the string, or NULL on failure. If the
   258     // string is interned, chars() is guaranteed to succeed.
   259     const char *chars();
   260 };
   261 
   262 // A function is an executable unit of code.
   263 class KE_EXPORT Function
   264 {
   265   public:
   266     // Returns the name of a function, which may be NULL. If not NULL, the
   267     // string is guaranteed to be interned.
   268     Local<String> name();
   269 };
   270 
   271 // A pubvar is an ISourcePawnEngine-compatible structure that holds information
   272 // about public variables.
   273 class KE_EXPORT Pubvar
   274 {
   275   public:
   276     // Returns the name of a pubvar, which is never NULL. The string is
   277     // guaranteed to be interned.
   278     Local<String> name();
   279 };
   280 
   281 // A module represents a single compiled file, and contains functions and
   282 // global variables for that file (as well as exported types).
   283 class KE_EXPORT Module
   284 {
   285   public:
   286     // Sets the native identity pointer, which is passed as the first argument
   287     // to natives.
   288     void setNativeIdentity(void *ptr);
   289 };
   290 
   291 class Keima
   292 {
   293   public:
   294     /*
   295      * Initializes the Keima engine. This must be called exactly once before any
   296      * other Keima functions are called. After this, it is safe to use Keima
   297      * on the calling thread.
   298      */
   299     static bool Initialize();
   300 
   301     /*
   302      * Shuts down the Keima engine and frees data structures on all threads.
   303      */
   304     static void Shutdown();
   305 
   306     /*
   307      * Searches the call stack and returns true if the given module has any
   308      * active code running. This is an O(n) algorithm.
   309      */
   310     static bool IsInCallStack(Handle<Module> module);
   311 
   312     /*
   313      * Reclaim as much memory as possible. This pauses the calling thread
   314      * until garbage collection completes.
   315      */
   316     static void CollectGarbage();
   317 
   318     /*
   319      * Clear any pending exception.
   320      */
   321     static void ClearPendingException();
   322 
   323     /*
   324      * Executes a function with the given parameters. This interface is
   325      * intended for compatibility with SourceMod's ISourcePawnEngine2 and
   326      * should not be used otherwise, since it is intended to support only
   327      * a small subset of the core language.
   328      */
   329     static bool Invoke(Handle<Function> fun, const Parameter *params, unsigned nparams,
   330                        bool checkTypes, int *result);
   331 
   332     /*
   333      * Sets the global message handler through which errors will be reported
   334      */
   335     static void InstallMessageReporter(IMessageReporter *reporter);
   336 
   337     /* Returns a new stack frame iterator object. */
   338     static IStackFrameIterator *NewStackFrameIterator();
   339 
   340     /*
   341      * Binds a native, by name, to an address. Natives are an ISPE1 concept
   342      * (originally from Pawn/Small's AMX API). In SourceMod 1, natives were
   343      * registered globally, but bound to plugins individually. We roughly
   344      * preserve that functionality here, by allowing host applications to
   345      * give us the name -> address mappings.
   346      *
   347      * Natives can be rebound or unbound any number of times. This function
   348      * fails if there is not enough memory.
   349      */
   350     static bool BindNative(const char *name, void *address);
   351 
   352     /* Sets the object that will listen for public functions. */
   353     static void SetPublicFunctionListener(IPublicFunctionListener *listener);
   354 };
   355 
   356 /*
   357  * Suppresses exceptions. This is useful for calling API functions. When this
   358  * in scope, errors will be reported, but the exception will be cleared after.
   359  */
   360 class AutoClearExceptions
   361 {
   362   public:
   363     ~AutoClearExceptions()
   364     {
   365         Keima::ClearPendingException();
   366     }
   367 };
   368 
   369 // Argument-passing interface for Invoke().
   370 class Parameter
   371 {
   372   public:
   373     enum Type {
   374         Int,
   375         Float,
   376         IntRef,
   377         FloatRef,
   378         Array,
   379         CharArray
   380     };
   381 
   382     Parameter()
   383     {
   384     }
   385 
   386     Parameter(int i)
   387       : type_(Int)
   388     {
   389         u.i = i;
   390     }
   391 
   392     Parameter(int *i, bool writeback)
   393       : type_(IntRef),
   394         writeback_(writeback)
   395     {
   396         u.ip = i;
   397     }
   398 
   399     Parameter(float f)
   400       : type_(Float)
   401     {
   402         u.f = f;
   403     }
   404 
   405     Parameter(float *f, bool writeback)
   406       : type_(FloatRef),
   407         writeback_(writeback)
   408     {
   409         u.fp = f;
   410     }
   411 
   412     Parameter(Type type, void *buffer, size_t length, bool writeback)
   413       : type_(type),
   414         writeback_(writeback),
   415         length_(length)
   416     {
   417         assert(type == Array || type == CharArray);
   418         u.buffer = buffer;
   419     }
   420 
   421     Type type() const {
   422         return type_;
   423     }
   424 
   425     int i32() const {
   426         assert(type() == Int);
   427         return u.i;
   428     }
   429     float f() const {
   430         assert(type() == Float);
   431         return u.f;
   432     }
   433     int *i32p() const {
   434         assert(type() == IntRef);
   435         return u.ip;
   436     }
   437     float *fp() const {
   438         assert(type() == FloatRef);
   439         return u.fp;
   440     }
   441     bool writeback() const {
   442         assert(type() >= IntRef && type() <= CharArray);
   443         return writeback_;
   444     }
   445     size_t length() const {
   446         return length_;
   447     }
   448     void *buffer() const {
   449         assert(type() == Array || type() == CharArray);
   450         return u.buffer;
   451     }
   452 
   453   private:
   454     Type type_;
   455     bool writeback_;
   456     size_t length_;
   457 
   458     union {
   459         int i;
   460         float f;
   461         int *ip;
   462         float *fp;
   463         void *buffer;
   464     } u;
   465 };
   466 
   467 /*
   468  * Compiles a file and returns a Module.
   469  */
   470 extern bool Compile(const char *path);
   471 
   472 class Internals
   473 {
   474     template <typename T> friend class Root;
   475 
   476   private:
   477     static ke::HeapRoot *NewHeapRoot();
   478     static void Destroy(ke::HeapRoot *root);
   479 };
   480 
   481 template <typename T> void
   482 Root<T>::set(Handle<T> other)
   483 {
   484     if (!other) {
   485         obj_ = other;
   486         return;
   487     }
   488 
   489     ke::Object **ptr = reinterpret_cast<ke::Object **>(*other);
   490     if (!root_) {
   491         root_ = Internals::NewHeapRoot();
   492         if (!root_)
   493             return;
   494     }
   495 
   496     *reinterpret_cast<ke::Object **>(root_) = *ptr;
   497     obj_.obj_ = reinterpret_cast<T *>(root_);
   498 }
   499 
   500 template <typename T>
   501 Root<T>::~Root()
   502 {
   503     if (!root_)
   504         return;
   505     Internals::Destroy(root_);
   506 }
   507 
   508 
   509 }
   510 
   511 #endif // _include_sourcepawn2_api_h_