blob: f9dca110c377e846c48da15e3295dced77770ff3 [file] [log] [blame]
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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
lrn@chromium.org1c092762011-05-09 09:42:16 +000031#include "allocation.h"
32
kasperl@chromium.org71affb52009-05-26 05:44:31 +000033namespace v8 {
34namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035
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
48class Arguments BASE_EMBEDDED {
49 public:
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000050 Arguments(int length, Object** arguments)
51 : length_(length), arguments_(arguments) { }
52
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053 Object*& operator[] (int index) {
mads.s.ager31e71382008-08-13 09:32:07 +000054 ASSERT(0 <= index && index < length_);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +000055 return *(reinterpret_cast<Object**>(reinterpret_cast<intptr_t>(arguments_) -
56 index * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057 }
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
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000067 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000075 // Get the total number of arguments including the receiver.
mads.s.ager31e71382008-08-13 09:32:07 +000076 int length() const { return length_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000078 Object** arguments() { return arguments_; }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000079
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000080 private:
81 int length_;
82 Object** arguments_;
83};
84
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000085
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000086// mappings from old property callbacks to new ones
87// F(old name, new name, return value, parameters...)
88//
89// These aren't included in the list as they have duplicate signatures
90// F(NamedPropertyEnumerator, NamedPropertyEnumeratorCallback, ...)
91// F(NamedPropertyGetter, NamedPropertyGetterCallback, ...)
92
93#define FOR_EACH_CALLBACK_TABLE_MAPPING_0(F) \
94 F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback, v8::Array) \
95
96#define FOR_EACH_CALLBACK_TABLE_MAPPING_1(F) \
97 F(AccessorGetter, AccessorGetterCallback, v8::Value, v8::Local<v8::String>) \
98 F(NamedPropertyQuery, \
99 NamedPropertyQueryCallback, \
100 v8::Integer, \
101 v8::Local<v8::String>) \
102 F(NamedPropertyDeleter, \
103 NamedPropertyDeleterCallback, \
104 v8::Boolean, \
105 v8::Local<v8::String>) \
106 F(IndexedPropertyGetter, \
107 IndexedPropertyGetterCallback, \
108 v8::Value, \
109 uint32_t) \
110 F(IndexedPropertyQuery, \
111 IndexedPropertyQueryCallback, \
112 v8::Integer, \
113 uint32_t) \
114 F(IndexedPropertyDeleter, \
115 IndexedPropertyDeleterCallback, \
116 v8::Boolean, \
117 uint32_t) \
118
119#define FOR_EACH_CALLBACK_TABLE_MAPPING_2(F) \
120 F(NamedPropertySetter, \
121 NamedPropertySetterCallback, \
122 v8::Value, \
123 v8::Local<v8::String>, \
124 v8::Local<v8::Value>) \
125 F(IndexedPropertySetter, \
126 IndexedPropertySetterCallback, \
127 v8::Value, \
128 uint32_t, \
129 v8::Local<v8::Value>) \
130
131#define FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(F) \
132 F(AccessorSetter, \
133 AccessorSetterCallback, \
134 void, \
135 v8::Local<v8::String>, \
136 v8::Local<v8::Value>) \
137
138// All property callbacks as well as invocation callbacks
139#define FOR_EACH_CALLBACK_TABLE_MAPPING(F) \
140 F(InvocationCallback, FunctionCallback) \
141 F(AccessorGetter, AccessorGetterCallback) \
142 F(AccessorSetter, AccessorSetterCallback) \
143 F(NamedPropertySetter, NamedPropertySetterCallback) \
144 F(NamedPropertyQuery, NamedPropertyQueryCallback) \
145 F(NamedPropertyDeleter, NamedPropertyDeleterCallback) \
146 F(IndexedPropertyGetter, IndexedPropertyGetterCallback) \
147 F(IndexedPropertySetter, IndexedPropertySetterCallback) \
148 F(IndexedPropertyQuery, IndexedPropertyQueryCallback) \
149 F(IndexedPropertyDeleter, IndexedPropertyDeleterCallback) \
150 F(IndexedPropertyEnumerator, IndexedPropertyEnumeratorCallback) \
151
152
153// TODO(dcarney): Remove this class when old callbacks are gone.
154class CallbackTable {
155 public:
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000156 static const bool kStoreVoidFunctions = false;
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000157 static inline bool ReturnsVoid(Isolate* isolate, void* function) {
158 CallbackTable* table = isolate->callback_table();
159 bool contains =
160 table != NULL &&
161 table->map_.occupancy() != 0 &&
162 table->Contains(function);
163 return contains == kStoreVoidFunctions;
164 }
165
166 STATIC_ASSERT(sizeof(intptr_t) == sizeof(AccessorGetterCallback));
167
168 template<typename F>
169 static inline void* FunctionToVoidPtr(F function) {
170 return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(function));
171 }
172
173#define WRITE_REGISTER(OldFunction, NewFunction) \
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000174 static NewFunction Register(Isolate* isolate, OldFunction f) { \
175 InsertCallback(isolate, FunctionToVoidPtr(f), false); \
176 return reinterpret_cast<NewFunction>(f); \
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000177 } \
178 \
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000179 static NewFunction Register(Isolate* isolate, NewFunction f) { \
180 InsertCallback(isolate, FunctionToVoidPtr(f), true); \
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000181 return f; \
182 }
183 FOR_EACH_CALLBACK_TABLE_MAPPING(WRITE_REGISTER)
184#undef WRITE_REGISTER
185
186 private:
187 CallbackTable();
188 bool Contains(void* function);
189 static void InsertCallback(Isolate* isolate,
190 void* function,
191 bool returns_void);
192 HashMap map_;
193 DISALLOW_COPY_AND_ASSIGN(CallbackTable);
194};
195
196
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000197// Custom arguments replicate a small segment of stack that can be
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000198// accessed through an Arguments object the same way the actual stack
199// can.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000200template<int kArrayLength>
201class CustomArgumentsBase : public Relocatable {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000202 public:
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000203 virtual inline void IterateInstance(ObjectVisitor* v) {
204 v->VisitPointers(values_, values_ + kArrayLength);
205 }
206 protected:
207 inline Object** end() { return values_ + kArrayLength - 1; }
208 explicit inline CustomArgumentsBase(Isolate* isolate)
209 : Relocatable(isolate) {}
210 Object* values_[kArrayLength];
211};
212
213
214template<typename T>
215class CustomArguments : public CustomArgumentsBase<T::kArgsLength> {
216 public:
217 static const int kReturnValueOffset = T::kReturnValueIndex;
218
219 typedef CustomArgumentsBase<T::kArgsLength> Super;
220 ~CustomArguments() {
221 // TODO(dcarney): create a new zap value for this.
222 this->end()[kReturnValueOffset] =
223 reinterpret_cast<Object*>(kHandleZapValue);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000224 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000225
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000226 protected:
227 explicit inline CustomArguments(Isolate* isolate) : Super(isolate) {}
228
229 template<typename V>
230 v8::Handle<V> GetReturnValue(Isolate* isolate);
231
232 inline Isolate* isolate() {
233 return reinterpret_cast<Isolate*>(this->end()[T::kIsolateIndex]);
234 }
235};
236
237
238class PropertyCallbackArguments
239 : public CustomArguments<PropertyCallbackInfo<Value> > {
240 public:
241 typedef PropertyCallbackInfo<Value> T;
242 typedef CustomArguments<T> Super;
243 static const int kArgsLength = T::kArgsLength;
244 static const int kThisIndex = T::kThisIndex;
245 static const int kHolderIndex = T::kHolderIndex;
246
247 PropertyCallbackArguments(Isolate* isolate,
248 Object* data,
249 Object* self,
250 JSObject* holder)
251 : Super(isolate) {
252 Object** values = this->end();
253 values[T::kThisIndex] = self;
254 values[T::kHolderIndex] = holder;
255 values[T::kDataIndex] = data;
256 values[T::kIsolateIndex] = reinterpret_cast<Object*>(isolate);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000257 // Here the hole is set as default value.
258 // It cannot escape into js as it's remove in Call below.
259 values[T::kReturnValueDefaultValueIndex] =
260 isolate->heap()->the_hole_value();
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000261 values[T::kReturnValueIndex] = isolate->heap()->the_hole_value();
262 ASSERT(values[T::kHolderIndex]->IsHeapObject());
263 ASSERT(values[T::kIsolateIndex]->IsSmi());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000264 }
265
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000266 /*
267 * The following Call functions wrap the calling of all callbacks to handle
268 * calling either the old or the new style callbacks depending on which one
269 * has been registered.
270 * For old callbacks which return an empty handle, the ReturnValue is checked
271 * and used if it's been set to anything inside the callback.
272 * New style callbacks always use the return value.
273 */
274#define WRITE_CALL_0(OldFunction, NewFunction, ReturnValue) \
275 v8::Handle<ReturnValue> Call(OldFunction f); \
276
277#define WRITE_CALL_1(OldFunction, NewFunction, ReturnValue, Arg1) \
278 v8::Handle<ReturnValue> Call(OldFunction f, Arg1 arg1); \
279
280#define WRITE_CALL_2(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \
281 v8::Handle<ReturnValue> Call(OldFunction f, Arg1 arg1, Arg2 arg2); \
282
283#define WRITE_CALL_2_VOID(OldFunction, NewFunction, ReturnValue, Arg1, Arg2) \
284 void Call(OldFunction f, Arg1 arg1, Arg2 arg2); \
285
286FOR_EACH_CALLBACK_TABLE_MAPPING_0(WRITE_CALL_0)
287FOR_EACH_CALLBACK_TABLE_MAPPING_1(WRITE_CALL_1)
288FOR_EACH_CALLBACK_TABLE_MAPPING_2(WRITE_CALL_2)
289FOR_EACH_CALLBACK_TABLE_MAPPING_2_VOID_RETURN(WRITE_CALL_2_VOID)
290
291#undef WRITE_CALL_0
292#undef WRITE_CALL_1
293#undef WRITE_CALL_2
294#undef WRITE_CALL_2_VOID
295};
296
297
298class FunctionCallbackArguments
299 : public CustomArguments<FunctionCallbackInfo<Value> > {
300 public:
301 typedef FunctionCallbackInfo<Value> T;
302 typedef CustomArguments<T> Super;
303 static const int kArgsLength = T::kArgsLength;
304
305 FunctionCallbackArguments(internal::Isolate* isolate,
306 internal::Object* data,
307 internal::JSFunction* callee,
308 internal::Object* holder,
309 internal::Object** argv,
310 int argc,
311 bool is_construct_call)
312 : Super(isolate),
313 argv_(argv),
314 argc_(argc),
315 is_construct_call_(is_construct_call) {
316 Object** values = end();
317 values[T::kDataIndex] = data;
318 values[T::kCalleeIndex] = callee;
319 values[T::kHolderIndex] = holder;
320 values[T::kIsolateIndex] = reinterpret_cast<internal::Object*>(isolate);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000321 // Here the hole is set as default value.
322 // It cannot escape into js as it's remove in Call below.
323 values[T::kReturnValueDefaultValueIndex] =
324 isolate->heap()->the_hole_value();
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000325 values[T::kReturnValueIndex] = isolate->heap()->the_hole_value();
326 ASSERT(values[T::kCalleeIndex]->IsJSFunction());
327 ASSERT(values[T::kHolderIndex]->IsHeapObject());
328 ASSERT(values[T::kIsolateIndex]->IsSmi());
329 }
330
331 /*
332 * The following Call function wraps the calling of all callbacks to handle
333 * calling either the old or the new style callbacks depending on which one
334 * has been registered.
335 * For old callbacks which return an empty handle, the ReturnValue is checked
336 * and used if it's been set to anything inside the callback.
337 * New style callbacks always use the return value.
338 */
339 v8::Handle<v8::Value> Call(InvocationCallback f);
jkummerow@chromium.org3ee08a62012-04-13 13:01:33 +0000340
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000341 private:
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000342 internal::Object** argv_;
343 int argc_;
344 bool is_construct_call_;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000345};
346
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000347
348#define DECLARE_RUNTIME_FUNCTION(Type, Name) \
danno@chromium.orgf005df62013-04-30 16:36:45 +0000349Type Name(int args_length, Object** args_object, Isolate* isolate)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000350
danno@chromium.orgf005df62013-04-30 16:36:45 +0000351#define RUNTIME_FUNCTION(Type, Name) \
352static Type __RT_impl_##Name(Arguments args, Isolate* isolate); \
353Type Name(int args_length, Object** args_object, Isolate* isolate) { \
354 Arguments args(args_length, args_object); \
355 return __RT_impl_##Name(args, isolate); \
356} \
357static Type __RT_impl_##Name(Arguments args, Isolate* isolate)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000358
danno@chromium.orgf005df62013-04-30 16:36:45 +0000359#define RUNTIME_ARGUMENTS(isolate, args) \
360 args.length(), args.arguments(), isolate
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000361
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362} } // namespace v8::internal
363
364#endif // V8_ARGUMENTS_H_