Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_ARGUMENTS_H_
     29 #define V8_ARGUMENTS_H_
     30 
     31 #include "allocation.h"
     32 
     33 namespace v8 {
     34 namespace internal {
     35 
     36 // Arguments provides access to runtime call parameters.
     37 //
     38 // It uses the fact that the instance fields of Arguments
     39 // (length_, arguments_) are "overlayed" with the parameters
     40 // (no. of parameters, and the parameter pointer) passed so
     41 // that inside the C++ function, the parameters passed can
     42 // be accessed conveniently:
     43 //
     44 //   Object* Runtime_function(Arguments args) {
     45 //     ... use args[i] here ...
     46 //   }
     47 
     48 class Arguments BASE_EMBEDDED {
     49  public:
     50   Arguments(int length, Object** arguments)
     51       : length_(length), arguments_(arguments) { }
     52 
     53   Object*& operator[] (int index) {
     54     ASSERT(0 <= index && index < length_);
     55     return *(reinterpret_cast<Object**>(reinterpret_cast<intptr_t>(arguments_) -
     56                                         index * kPointerSize));
     57   }
     58 
     59   template <class S> Handle<S> at(int index) {
     60     Object** value = &((*this)[index]);
     61     // This cast checks that the object we're accessing does indeed have the
     62     // expected type.
     63     S::cast(*value);
     64     return Handle<S>(reinterpret_cast<S**>(value));
     65   }
     66 
     67   int smi_at(int index) {
     68     return Smi::cast((*this)[index])->value();
     69   }
     70 
     71   double number_at(int index) {
     72     return (*this)[index]->Number();
     73   }
     74 
     75   // Get the total number of arguments including the receiver.
     76   int length() const { return length_; }
     77 
     78   Object** arguments() { return arguments_; }
     79 
     80  private:
     81   int length_;
     82   Object** arguments_;
     83 };
     84 
     85 
     86 // For each type of callback, we have a list of arguments
     87 // They are used to generate the Call() functions below
     88 // These aren't included in the list as they have duplicate signatures
     89 // F(NamedPropertyEnumeratorCallback, ...)
     90 // F(NamedPropertyGetterCallback, ...)
     91 
     92 #define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \
     93   F(IndexedPropertyEnumeratorCallback, v8::Array) \
     94 
     95 #define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \
     96   F(AccessorGetterCallback, v8::Value, v8::Local<v8::String>) \
     97   F(NamedPropertyQueryCallback, \
     98     v8::Integer, \
     99     v8::Local<v8::String>) \
    100   F(NamedPropertyDeleterCallback, \
    101     v8::Boolean, \
    102     v8::Local<v8::String>) \
    103   F(IndexedPropertyGetterCallback, \
    104     v8::Value, \
    105     uint32_t) \
    106   F(IndexedPropertyQueryCallback, \
    107     v8::Integer, \
    108     uint32_t) \
    109   F(IndexedPropertyDeleterCallback, \
    110     v8::Boolean, \
    111     uint32_t) \
    112 
    113 #define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F) \
    114   F(NamedPropertySetterCallback, \
    115     v8::Value, \
    116     v8::Local<v8::String>, \
    117     v8::Local<v8::Value>) \
    118   F(IndexedPropertySetterCallback, \
    119     v8::Value, \
    120     uint32_t, \
    121     v8::Local<v8::Value>) \
    122 
    123 #define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \
    124   F(AccessorSetterCallback, \
    125     void, \
    126     v8::Local<v8::String>, \
    127     v8::Local<v8::Value>) \
    128 
    129 
    130 // Custom arguments replicate a small segment of stack that can be
    131 // accessed through an Arguments object the same way the actual stack
    132 // can.
    133 template<int kArrayLength>
    134 class CustomArgumentsBase : public Relocatable {
    135  public:
    136   virtual inline void IterateInstance(ObjectVisitor* v) {
    137     v->VisitPointers(values_, values_ + kArrayLength);
    138   }
    139  protected:
    140   inline Object** begin() { return values_; }
    141   explicit inline CustomArgumentsBase(Isolate* isolate)
    142       : Relocatable(isolate) {}
    143   Object* values_[kArrayLength];
    144 };
    145 
    146 
    147 template<typename T>
    148 class CustomArguments : public CustomArgumentsBase<T::kArgsLength> {
    149  public:
    150   static const int kReturnValueOffset = T::kReturnValueIndex;
    151 
    152   typedef CustomArgumentsBase<T::kArgsLength> Super;
    153   ~CustomArguments() {
    154     this->begin()[kReturnValueOffset] =
    155         reinterpret_cast<Object*>(kHandleZapValue);
    156   }
    157 
    158  protected:
    159   explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {}
    160 
    161   template<typename V>
    162   v8::Handle<V> GetReturnValue(Isolate* isolate);
    163 
    164   inline Isolate* isolate() {
    165     return reinterpret_cast<Isolate*>(this->begin()[T::kIsolateIndex]);
    166   }
    167 };
    168 
    169 
    170 class PropertyCallbackArguments
    171     : public CustomArguments<PropertyCallbackInfo<Value> > {
    172  public:
    173   typedef PropertyCallbackInfo<Value> T;
    174   typedef CustomArguments<T> Super;
    175   static const int kArgsLength = T::kArgsLength;
    176   static const int kThisIndex = T::kThisIndex;
    177   static const int kHolderIndex = T::kHolderIndex;
    178   static const int kDataIndex = T::kDataIndex;
    179   static const int kReturnValueDefaultValueIndex =
    180       T::kReturnValueDefaultValueIndex;
    181   static const int kIsolateIndex = T::kIsolateIndex;
    182 
    183   PropertyCallbackArguments(Isolate* isolate,
    184                             Object* data,
    185                             Object* self,
    186                             JSObject* holder)
    187       : Super(isolate) {
    188     Object** values = this->begin();
    189     values[T::kThisIndex] = self;
    190     values[T::kHolderIndex] = holder;
    191     values[T::kDataIndex] = data;
    192     values[T::kIsolateIndex] = reinterpret_cast<Object*>(isolate);
    193     // Here the hole is set as default value.
    194     // It cannot escape into js as it's remove in Call below.
    195     values[T::kReturnValueDefaultValueIndex] =
    196         isolate->heap()->the_hole_value();
    197     values[T::kReturnValueIndex] = isolate->heap()->the_hole_value();
    198     ASSERT(values[T::kHolderIndex]->IsHeapObject());
    199     ASSERT(values[T::kIsolateIndex]->IsSmi());
    200   }
    201 
    202   /*
    203    * The following Call functions wrap the calling of all callbacks to handle
    204    * calling either the old or the new style callbacks depending on which one
    205    * has been registered.
    206    * For old callbacks which return an empty handle, the ReturnValue is checked
    207    * and used if it's been set to anything inside the callback.
    208    * New style callbacks always use the return value.
    209    */
    210 #define WRITE_CALL_0(Function, ReturnValue)                                  \
    211   v8::Handle<ReturnValue> Call(Function f);                                  \
    212 
    213 #define WRITE_CALL_1(Function, ReturnValue, Arg1)                            \
    214   v8::Handle<ReturnValue> Call(Function f, Arg1 arg1);                       \
    215 
    216 #define WRITE_CALL_2(Function, ReturnValue, Arg1, Arg2)                      \
    217   v8::Handle<ReturnValue> Call(Function f, Arg1 arg1, Arg2 arg2);            \
    218 
    219 #define WRITE_CALL_2_VOID(Function, ReturnValue, Arg1, Arg2)                 \
    220   void Call(Function f, Arg1 arg1, Arg2 arg2);                               \
    221 
    222 FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0)
    223 FOR_EACH_CALLBACK_TABLE_MAPPING_1(WRITE_CALL_1)
    224 FOR_EACH_CALLBACK_TABLE_MAPPING_2(WRITE_CALL_2)
    225 FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(WRITE_CALL_2_VOID)
    226 
    227 #undef WRITE_CALL_0
    228 #undef WRITE_CALL_1
    229 #undef WRITE_CALL_2
    230 #undef WRITE_CALL_2_VOID
    231 };
    232 
    233 
    234 class FunctionCallbackArguments
    235     : public CustomArguments<FunctionCallbackInfo<Value> > {
    236  public:
    237   typedef FunctionCallbackInfo<Value> T;
    238   typedef CustomArguments<T> Super;
    239   static const int kArgsLength = T::kArgsLength;
    240   static const int kHolderIndex = T::kHolderIndex;
    241   static const int kDataIndex = T::kDataIndex;
    242   static const int kReturnValueDefaultValueIndex =
    243       T::kReturnValueDefaultValueIndex;
    244   static const int kIsolateIndex = T::kIsolateIndex;
    245   static const int kCalleeIndex = T::kCalleeIndex;
    246   static const int kContextSaveIndex = T::kContextSaveIndex;
    247 
    248   FunctionCallbackArguments(internal::Isolate* isolate,
    249       internal::Object* data,
    250       internal::JSFunction* callee,
    251       internal::Object* holder,
    252       internal::Object** argv,
    253       int argc,
    254       bool is_construct_call)
    255         : Super(isolate),
    256           argv_(argv),
    257           argc_(argc),
    258           is_construct_call_(is_construct_call) {
    259     Object** values = begin();
    260     values[T::kDataIndex] = data;
    261     values[T::kCalleeIndex] = callee;
    262     values[T::kHolderIndex] = holder;
    263     values[T::kContextSaveIndex] = isolate->heap()->the_hole_value();
    264     values[T::kIsolateIndex] = reinterpret_cast<internal::Object*>(isolate);
    265     // Here the hole is set as default value.
    266     // It cannot escape into js as it's remove in Call below.
    267     values[T::kReturnValueDefaultValueIndex] =
    268         isolate->heap()->the_hole_value();
    269     values[T::kReturnValueIndex] = isolate->heap()->the_hole_value();
    270     ASSERT(values[T::kCalleeIndex]->IsJSFunction());
    271     ASSERT(values[T::kHolderIndex]->IsHeapObject());
    272     ASSERT(values[T::kIsolateIndex]->IsSmi());
    273   }
    274 
    275   /*
    276    * The following Call function wraps the calling of all callbacks to handle
    277    * calling either the old or the new style callbacks depending on which one
    278    * has been registered.
    279    * For old callbacks which return an empty handle, the ReturnValue is checked
    280    * and used if it's been set to anything inside the callback.
    281    * New style callbacks always use the return value.
    282    */
    283   v8::Handle<v8::Value> Call(FunctionCallback f);
    284 
    285  private:
    286   internal::Object** argv_;
    287   int argc_;
    288   bool is_construct_call_;
    289 };
    290 
    291 
    292 double ClobberDoubleRegisters(double x1, double x2, double x3, double x4);
    293 
    294 
    295 #ifdef DEBUG
    296 #define CLOBBER_DOUBLE_REGISTERS() ClobberDoubleRegisters(1, 2, 3, 4);
    297 #else
    298 #define CLOBBER_DOUBLE_REGISTERS()
    299 #endif
    300 
    301 
    302 #define DECLARE_RUNTIME_FUNCTION(Type, Name)    \
    303 Type Name(int args_length, Object** args_object, Isolate* isolate)
    304 
    305 #define RUNTIME_FUNCTION(Type, Name)                                  \
    306 static Type __RT_impl_##Name(Arguments args, Isolate* isolate);       \
    307 Type Name(int args_length, Object** args_object, Isolate* isolate) {  \
    308   CLOBBER_DOUBLE_REGISTERS();                                         \
    309   Arguments args(args_length, args_object);                           \
    310   return __RT_impl_##Name(args, isolate);                             \
    311 }                                                                     \
    312 static Type __RT_impl_##Name(Arguments args, Isolate* isolate)
    313 
    314 #define RUNTIME_ARGUMENTS(isolate, args) \
    315   args.length(), args.arguments(), isolate
    316 
    317 } }  // namespace v8::internal
    318 
    319 #endif  // V8_ARGUMENTS_H_
    320