• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
Arguments(int length,Object ** arguments)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 
at(int index)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 
smi_at(int index)67   int smi_at(int index) {
68     return Smi::cast((*this)[index])->value();
69   }
70 
number_at(int index)71   double number_at(int index) {
72     return (*this)[index]->Number();
73   }
74 
75   // Get the total number of arguments including the receiver.
length()76   int length() const { return length_; }
77 
arguments()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:
IterateInstance(ObjectVisitor * v)136   virtual inline void IterateInstance(ObjectVisitor* v) {
137     v->VisitPointers(values_, values_ + kArrayLength);
138   }
139  protected:
begin()140   inline Object** begin() { return values_; }
CustomArgumentsBase(Isolate * isolate)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;
~CustomArguments()153   ~CustomArguments() {
154     this->begin()[kReturnValueOffset] =
155         reinterpret_cast<Object*>(kHandleZapValue);
156   }
157 
158  protected:
CustomArguments(Isolate * isolate)159   explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {}
160 
161   template<typename V>
162   v8::Handle<V> GetReturnValue(Isolate* isolate);
163 
isolate()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 
PropertyCallbackArguments(Isolate * isolate,Object * data,Object * self,JSObject * holder)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 
FunctionCallbackArguments(internal::Isolate * isolate,internal::Object * data,internal::JSFunction * callee,internal::Object * holder,internal::Object ** argv,int argc,bool is_construct_call)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