1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_ARGUMENTS_H_
6#define V8_ARGUMENTS_H_
7
8#include "src/allocation.h"
9#include "src/isolate.h"
10
11namespace v8 {
12namespace internal {
13
14// Arguments provides access to runtime call parameters.
15//
16// It uses the fact that the instance fields of Arguments
17// (length_, arguments_) are "overlayed" with the parameters
18// (no. of parameters, and the parameter pointer) passed so
19// that inside the C++ function, the parameters passed can
20// be accessed conveniently:
21//
22//   Object* Runtime_function(Arguments args) {
23//     ... use args[i] here ...
24//   }
25//
26// Note that length_ (whose value is in the integer range) is defined
27// as intptr_t to provide endian-neutrality on 64-bit archs.
28
29class Arguments BASE_EMBEDDED {
30 public:
31  Arguments(int length, Object** arguments)
32      : length_(length), arguments_(arguments) { }
33
34  Object*& operator[] (int index) {
35    DCHECK(0 <= index && index < length_);
36    return *(reinterpret_cast<Object**>(reinterpret_cast<intptr_t>(arguments_) -
37                                        index * kPointerSize));
38  }
39
40  template <class S> Handle<S> at(int index) {
41    Object** value = &((*this)[index]);
42    // This cast checks that the object we're accessing does indeed have the
43    // expected type.
44    S::cast(*value);
45    return Handle<S>(reinterpret_cast<S**>(value));
46  }
47
48  int smi_at(int index) {
49    return Smi::cast((*this)[index])->value();
50  }
51
52  double number_at(int index) {
53    return (*this)[index]->Number();
54  }
55
56  // Get the total number of arguments including the receiver.
57  int length() const { return static_cast<int>(length_); }
58
59  Object** arguments() { return arguments_; }
60
61 private:
62  intptr_t length_;
63  Object** arguments_;
64};
65
66
67// For each type of callback, we have a list of arguments
68// They are used to generate the Call() functions below
69// These aren't included in the list as they have duplicate signatures
70// F(NamedPropertyEnumeratorCallback, ...)
71
72#define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \
73  F(IndexedPropertyEnumeratorCallback, v8::Array) \
74
75#define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \
76  F(NamedPropertyGetterCallback, v8::Value, v8::Local<v8::String>) \
77  F(AccessorNameGetterCallback, v8::Value, v8::Local<v8::Name>) \
78  F(NamedPropertyQueryCallback, \
79    v8::Integer, \
80    v8::Local<v8::String>) \
81  F(NamedPropertyDeleterCallback, \
82    v8::Boolean, \
83    v8::Local<v8::String>) \
84  F(IndexedPropertyGetterCallback, \
85    v8::Value, \
86    uint32_t) \
87  F(IndexedPropertyQueryCallback, \
88    v8::Integer, \
89    uint32_t) \
90  F(IndexedPropertyDeleterCallback, \
91    v8::Boolean, \
92    uint32_t) \
93
94#define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F) \
95  F(NamedPropertySetterCallback, \
96    v8::Value, \
97    v8::Local<v8::String>, \
98    v8::Local<v8::Value>) \
99  F(IndexedPropertySetterCallback, \
100    v8::Value, \
101    uint32_t, \
102    v8::Local<v8::Value>) \
103
104#define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \
105  F(AccessorNameSetterCallback, \
106    void, \
107    v8::Local<v8::Name>, \
108    v8::Local<v8::Value>) \
109
110
111// Custom arguments replicate a small segment of stack that can be
112// accessed through an Arguments object the same way the actual stack
113// can.
114template<int kArrayLength>
115class CustomArgumentsBase : public Relocatable {
116 public:
117  virtual inline void IterateInstance(ObjectVisitor* v) {
118    v->VisitPointers(values_, values_ + kArrayLength);
119  }
120 protected:
121  inline Object** begin() { return values_; }
122  explicit inline CustomArgumentsBase(Isolate* isolate)
123      : Relocatable(isolate) {}
124  Object* values_[kArrayLength];
125};
126
127
128template<typename T>
129class CustomArguments : public CustomArgumentsBase<T::kArgsLength> {
130 public:
131  static const int kReturnValueOffset = T::kReturnValueIndex;
132
133  typedef CustomArgumentsBase<T::kArgsLength> Super;
134  ~CustomArguments() {
135    this->begin()[kReturnValueOffset] =
136        reinterpret_cast<Object*>(kHandleZapValue);
137  }
138
139 protected:
140  explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {}
141
142  template<typename V>
143  v8::Handle<V> GetReturnValue(Isolate* isolate);
144
145  inline Isolate* isolate() {
146    return reinterpret_cast<Isolate*>(this->begin()[T::kIsolateIndex]);
147  }
148};
149
150
151class PropertyCallbackArguments
152    : public CustomArguments<PropertyCallbackInfo<Value> > {
153 public:
154  typedef PropertyCallbackInfo<Value> T;
155  typedef CustomArguments<T> Super;
156  static const int kArgsLength = T::kArgsLength;
157  static const int kThisIndex = T::kThisIndex;
158  static const int kHolderIndex = T::kHolderIndex;
159  static const int kDataIndex = T::kDataIndex;
160  static const int kReturnValueDefaultValueIndex =
161      T::kReturnValueDefaultValueIndex;
162  static const int kIsolateIndex = T::kIsolateIndex;
163
164  PropertyCallbackArguments(Isolate* isolate,
165                            Object* data,
166                            Object* self,
167                            JSObject* holder)
168      : Super(isolate) {
169    Object** values = this->begin();
170    values[T::kThisIndex] = self;
171    values[T::kHolderIndex] = holder;
172    values[T::kDataIndex] = data;
173    values[T::kIsolateIndex] = reinterpret_cast<Object*>(isolate);
174    // Here the hole is set as default value.
175    // It cannot escape into js as it's remove in Call below.
176    values[T::kReturnValueDefaultValueIndex] =
177        isolate->heap()->the_hole_value();
178    values[T::kReturnValueIndex] = isolate->heap()->the_hole_value();
179    DCHECK(values[T::kHolderIndex]->IsHeapObject());
180    DCHECK(values[T::kIsolateIndex]->IsSmi());
181  }
182
183  /*
184   * The following Call functions wrap the calling of all callbacks to handle
185   * calling either the old or the new style callbacks depending on which one
186   * has been registered.
187   * For old callbacks which return an empty handle, the ReturnValue is checked
188   * and used if it's been set to anything inside the callback.
189   * New style callbacks always use the return value.
190   */
191#define WRITE_CALL_0(Function, ReturnValue)                                  \
192  v8::Handle<ReturnValue> Call(Function f);                                  \
193
194#define WRITE_CALL_1(Function, ReturnValue, Arg1)                            \
195  v8::Handle<ReturnValue> Call(Function f, Arg1 arg1);                       \
196
197#define WRITE_CALL_2(Function, ReturnValue, Arg1, Arg2)                      \
198  v8::Handle<ReturnValue> Call(Function f, Arg1 arg1, Arg2 arg2);            \
199
200#define WRITE_CALL_2_VOID(Function, ReturnValue, Arg1, Arg2)                 \
201  void Call(Function f, Arg1 arg1, Arg2 arg2);                               \
202
203FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0)
204FOR_EACH_CALLBACK_TABLE_MAPPING_1(WRITE_CALL_1)
205FOR_EACH_CALLBACK_TABLE_MAPPING_2(WRITE_CALL_2)
206FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(WRITE_CALL_2_VOID)
207
208#undef WRITE_CALL_0
209#undef WRITE_CALL_1
210#undef WRITE_CALL_2
211#undef WRITE_CALL_2_VOID
212};
213
214
215class FunctionCallbackArguments
216    : public CustomArguments<FunctionCallbackInfo<Value> > {
217 public:
218  typedef FunctionCallbackInfo<Value> T;
219  typedef CustomArguments<T> Super;
220  static const int kArgsLength = T::kArgsLength;
221  static const int kHolderIndex = T::kHolderIndex;
222  static const int kDataIndex = T::kDataIndex;
223  static const int kReturnValueDefaultValueIndex =
224      T::kReturnValueDefaultValueIndex;
225  static const int kIsolateIndex = T::kIsolateIndex;
226  static const int kCalleeIndex = T::kCalleeIndex;
227  static const int kContextSaveIndex = T::kContextSaveIndex;
228
229  FunctionCallbackArguments(internal::Isolate* isolate,
230      internal::Object* data,
231      internal::JSFunction* callee,
232      internal::Object* holder,
233      internal::Object** argv,
234      int argc,
235      bool is_construct_call)
236        : Super(isolate),
237          argv_(argv),
238          argc_(argc),
239          is_construct_call_(is_construct_call) {
240    Object** values = begin();
241    values[T::kDataIndex] = data;
242    values[T::kCalleeIndex] = callee;
243    values[T::kHolderIndex] = holder;
244    values[T::kContextSaveIndex] = isolate->heap()->the_hole_value();
245    values[T::kIsolateIndex] = reinterpret_cast<internal::Object*>(isolate);
246    // Here the hole is set as default value.
247    // It cannot escape into js as it's remove in Call below.
248    values[T::kReturnValueDefaultValueIndex] =
249        isolate->heap()->the_hole_value();
250    values[T::kReturnValueIndex] = isolate->heap()->the_hole_value();
251    DCHECK(values[T::kCalleeIndex]->IsJSFunction());
252    DCHECK(values[T::kHolderIndex]->IsHeapObject());
253    DCHECK(values[T::kIsolateIndex]->IsSmi());
254  }
255
256  /*
257   * The following Call function wraps the calling of all callbacks to handle
258   * calling either the old or the new style callbacks depending on which one
259   * has been registered.
260   * For old callbacks which return an empty handle, the ReturnValue is checked
261   * and used if it's been set to anything inside the callback.
262   * New style callbacks always use the return value.
263   */
264  v8::Handle<v8::Value> Call(FunctionCallback f);
265
266 private:
267  internal::Object** argv_;
268  int argc_;
269  bool is_construct_call_;
270};
271
272
273double ClobberDoubleRegisters(double x1, double x2, double x3, double x4);
274
275
276#ifdef DEBUG
277#define CLOBBER_DOUBLE_REGISTERS() ClobberDoubleRegisters(1, 2, 3, 4);
278#else
279#define CLOBBER_DOUBLE_REGISTERS()
280#endif
281
282
283#define DECLARE_RUNTIME_FUNCTION(Name)    \
284Object* Name(int args_length, Object** args_object, Isolate* isolate)
285
286#define RUNTIME_FUNCTION_RETURNS_TYPE(Type, Name)                        \
287static INLINE(Type __RT_impl_##Name(Arguments args, Isolate* isolate));  \
288Type Name(int args_length, Object** args_object, Isolate* isolate) {     \
289  CLOBBER_DOUBLE_REGISTERS();                                            \
290  Arguments args(args_length, args_object);                              \
291  return __RT_impl_##Name(args, isolate);                                \
292}                                                                        \
293static Type __RT_impl_##Name(Arguments args, Isolate* isolate)
294
295
296#define RUNTIME_FUNCTION(Name) RUNTIME_FUNCTION_RETURNS_TYPE(Object*, Name)
297#define RUNTIME_FUNCTION_RETURN_PAIR(Name) \
298    RUNTIME_FUNCTION_RETURNS_TYPE(ObjectPair, Name)
299
300#define RUNTIME_ARGUMENTS(isolate, args) \
301  args.length(), args.arguments(), isolate
302
303} }  // namespace v8::internal
304
305#endif  // V8_ARGUMENTS_H_
306