blob: b4f4a0611afb82a44dda19353333573e94993a18 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2008 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#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
33#include "builtins.h"
34#include "ic-inl.h"
35
36namespace v8 {
37namespace internal {
38
Leon Clarkee46be812010-01-19 14:06:41 +000039namespace {
40
41// Arguments object passed to C++ builtins.
42template <BuiltinExtraArguments extra_args>
43class BuiltinArguments : public Arguments {
44 public:
45 BuiltinArguments(int length, Object** arguments)
46 : Arguments(length, arguments) { }
47
48 Object*& operator[] (int index) {
49 ASSERT(index < length());
50 return Arguments::operator[](index);
51 }
52
53 template <class S> Handle<S> at(int index) {
54 ASSERT(index < length());
55 return Arguments::at<S>(index);
56 }
57
58 Handle<Object> receiver() {
59 return Arguments::at<Object>(0);
60 }
61
62 Handle<JSFunction> called_function() {
63 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
64 return Arguments::at<JSFunction>(Arguments::length() - 1);
65 }
66
67 // Gets the total number of arguments including the receiver (but
68 // excluding extra arguments).
69 int length() const {
70 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
71 return Arguments::length();
72 }
73
74#ifdef DEBUG
75 void Verify() {
76 // Check we have at least the receiver.
77 ASSERT(Arguments::length() >= 1);
78 }
79#endif
80};
81
82
83// Specialize BuiltinArguments for the called function extra argument.
84
85template <>
86int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
87 return Arguments::length() - 1;
88}
89
90#ifdef DEBUG
91template <>
92void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
93 // Check we have at least the receiver and the called function.
94 ASSERT(Arguments::length() >= 2);
95 // Make sure cast to JSFunction succeeds.
96 called_function();
97}
98#endif
99
100
101#define DEF_ARG_TYPE(name, spec) \
102 typedef BuiltinArguments<spec> name##ArgumentsType;
103BUILTIN_LIST_C(DEF_ARG_TYPE)
104#undef DEF_ARG_TYPE
105
106} // namespace
107
108
Steve Blocka7e24c12009-10-30 11:49:00 +0000109// ----------------------------------------------------------------------------
Leon Clarkee46be812010-01-19 14:06:41 +0000110// Support macro for defining builtins in C++.
Steve Blocka7e24c12009-10-30 11:49:00 +0000111// ----------------------------------------------------------------------------
112//
113// A builtin function is defined by writing:
114//
115// BUILTIN(name) {
116// ...
117// }
Steve Blocka7e24c12009-10-30 11:49:00 +0000118//
Leon Clarkee46be812010-01-19 14:06:41 +0000119// In the body of the builtin function the arguments can be accessed
120// through the BuiltinArguments object args.
Steve Blocka7e24c12009-10-30 11:49:00 +0000121
Leon Clarkee46be812010-01-19 14:06:41 +0000122#ifdef DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +0000123
Leon Clarkee46be812010-01-19 14:06:41 +0000124#define BUILTIN(name) \
125 static Object* Builtin_Impl_##name(name##ArgumentsType args); \
126 static Object* Builtin_##name(name##ArgumentsType args) { \
127 args.Verify(); \
128 return Builtin_Impl_##name(args); \
129 } \
130 static Object* Builtin_Impl_##name(name##ArgumentsType args)
Steve Blocka7e24c12009-10-30 11:49:00 +0000131
Leon Clarkee46be812010-01-19 14:06:41 +0000132#else // For release mode.
Steve Blocka7e24c12009-10-30 11:49:00 +0000133
Leon Clarkee46be812010-01-19 14:06:41 +0000134#define BUILTIN(name) \
135 static Object* Builtin_##name(name##ArgumentsType args)
136
137#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000138
139
140static inline bool CalledAsConstructor() {
141#ifdef DEBUG
142 // Calculate the result using a full stack frame iterator and check
143 // that the state of the stack is as we assume it to be in the
144 // code below.
145 StackFrameIterator it;
146 ASSERT(it.frame()->is_exit());
147 it.Advance();
148 StackFrame* frame = it.frame();
149 bool reference_result = frame->is_construct();
150#endif
151 Address fp = Top::c_entry_fp(Top::GetCurrentThread());
152 // Because we know fp points to an exit frame we can use the relevant
153 // part of ExitFrame::ComputeCallerState directly.
154 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
155 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
156 // This inlines the part of StackFrame::ComputeType that grabs the
157 // type of the current frame. Note that StackFrame::ComputeType
158 // has been specialized for each architecture so if any one of them
159 // changes this code has to be changed as well.
160 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
161 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
162 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
163 bool result = (marker == kConstructMarker);
164 ASSERT_EQ(result, reference_result);
165 return result;
166}
167
168// ----------------------------------------------------------------------------
169
170
Steve Blocka7e24c12009-10-30 11:49:00 +0000171BUILTIN(Illegal) {
172 UNREACHABLE();
Leon Clarkee46be812010-01-19 14:06:41 +0000173 return Heap::undefined_value(); // Make compiler happy.
Steve Blocka7e24c12009-10-30 11:49:00 +0000174}
Steve Blocka7e24c12009-10-30 11:49:00 +0000175
176
177BUILTIN(EmptyFunction) {
Leon Clarkee46be812010-01-19 14:06:41 +0000178 return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000179}
Steve Blocka7e24c12009-10-30 11:49:00 +0000180
181
182BUILTIN(ArrayCodeGeneric) {
183 Counters::array_function_runtime.Increment();
184
185 JSArray* array;
186 if (CalledAsConstructor()) {
Leon Clarkee46be812010-01-19 14:06:41 +0000187 array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000188 } else {
189 // Allocate the JS Array
190 JSFunction* constructor =
191 Top::context()->global_context()->array_function();
192 Object* obj = Heap::AllocateJSObject(constructor);
193 if (obj->IsFailure()) return obj;
194 array = JSArray::cast(obj);
195 }
196
197 // 'array' now contains the JSArray we should initialize.
Steve Block8defd9f2010-07-08 12:39:36 +0100198 ASSERT(array->HasFastElements());
Steve Blocka7e24c12009-10-30 11:49:00 +0000199
200 // Optimize the case where there is one argument and the argument is a
201 // small smi.
202 if (args.length() == 2) {
203 Object* obj = args[1];
204 if (obj->IsSmi()) {
205 int len = Smi::cast(obj)->value();
206 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
207 Object* obj = Heap::AllocateFixedArrayWithHoles(len);
208 if (obj->IsFailure()) return obj;
209 array->SetContent(FixedArray::cast(obj));
210 return array;
211 }
212 }
213 // Take the argument as the length.
214 obj = array->Initialize(0);
215 if (obj->IsFailure()) return obj;
216 return array->SetElementsLength(args[1]);
217 }
218
219 // Optimize the case where there are no parameters passed.
220 if (args.length() == 1) {
221 return array->Initialize(JSArray::kPreallocatedArrayElements);
222 }
223
224 // Take the arguments as elements.
225 int number_of_elements = args.length() - 1;
226 Smi* len = Smi::FromInt(number_of_elements);
227 Object* obj = Heap::AllocateFixedArrayWithHoles(len->value());
228 if (obj->IsFailure()) return obj;
Leon Clarke4515c472010-02-03 11:58:03 +0000229
230 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000231 FixedArray* elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000232 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 // Fill in the content
234 for (int index = 0; index < number_of_elements; index++) {
235 elms->set(index, args[index+1], mode);
236 }
237
238 // Set length and elements on the array.
239 array->set_elements(FixedArray::cast(obj));
Leon Clarke4515c472010-02-03 11:58:03 +0000240 array->set_length(len);
Steve Blocka7e24c12009-10-30 11:49:00 +0000241
242 return array;
243}
Steve Blocka7e24c12009-10-30 11:49:00 +0000244
245
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100246MUST_USE_RESULT static Object* AllocateJSArray() {
Steve Block6ded16b2010-05-10 14:33:55 +0100247 JSFunction* array_function =
248 Top::context()->global_context()->array_function();
249 Object* result = Heap::AllocateJSObject(array_function);
250 if (result->IsFailure()) return result;
251 return result;
252}
253
254
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100255MUST_USE_RESULT static Object* AllocateEmptyJSArray() {
Steve Block6ded16b2010-05-10 14:33:55 +0100256 Object* result = AllocateJSArray();
257 if (result->IsFailure()) return result;
258 JSArray* result_array = JSArray::cast(result);
259 result_array->set_length(Smi::FromInt(0));
260 result_array->set_elements(Heap::empty_fixed_array());
261 return result_array;
262}
263
264
265static void CopyElements(AssertNoAllocation* no_gc,
266 FixedArray* dst,
267 int dst_index,
268 FixedArray* src,
269 int src_index,
270 int len) {
271 ASSERT(dst != src); // Use MoveElements instead.
Iain Merrick75681382010-08-19 15:07:18 +0100272 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100273 ASSERT(len > 0);
274 CopyWords(dst->data_start() + dst_index,
275 src->data_start() + src_index,
276 len);
277 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
278 if (mode == UPDATE_WRITE_BARRIER) {
279 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
280 }
281}
282
283
284static void MoveElements(AssertNoAllocation* no_gc,
285 FixedArray* dst,
286 int dst_index,
287 FixedArray* src,
288 int src_index,
289 int len) {
Iain Merrick75681382010-08-19 15:07:18 +0100290 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100291 memmove(dst->data_start() + dst_index,
292 src->data_start() + src_index,
293 len * kPointerSize);
294 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
295 if (mode == UPDATE_WRITE_BARRIER) {
296 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
297 }
298}
299
300
301static void FillWithHoles(FixedArray* dst, int from, int to) {
Iain Merrick75681382010-08-19 15:07:18 +0100302 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100303 MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from);
304}
305
306
307static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
Iain Merrick75681382010-08-19 15:07:18 +0100308 ASSERT(elms->map() != Heap::fixed_cow_array_map());
Steve Block791712a2010-08-27 10:21:07 +0100309 // For now this trick is only applied to fixed arrays in new and paged space.
Steve Block6ded16b2010-05-10 14:33:55 +0100310 // In large object space the object's start must coincide with chunk
311 // and thus the trick is just not applicable.
Steve Block791712a2010-08-27 10:21:07 +0100312 ASSERT(!Heap::lo_space()->Contains(elms));
Steve Block6ded16b2010-05-10 14:33:55 +0100313
314 STATIC_ASSERT(FixedArray::kMapOffset == 0);
315 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
316 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
317
318 Object** former_start = HeapObject::RawField(elms, 0);
319
320 const int len = elms->length();
321
Steve Block791712a2010-08-27 10:21:07 +0100322 if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
323 !Heap::new_space()->Contains(elms)) {
324 // If we are doing a big trim in old space then we zap the space that was
325 // formerly part of the array so that the GC (aided by the card-based
326 // remembered set) won't find pointers to new-space there.
327 Object** zap = reinterpret_cast<Object**>(elms->address());
328 zap++; // Header of filler must be at least one word so skip that.
329 for (int i = 1; i < to_trim; i++) {
330 *zap++ = Smi::FromInt(0);
331 }
332 }
Steve Block6ded16b2010-05-10 14:33:55 +0100333 // Technically in new space this write might be omitted (except for
334 // debug mode which iterates through the heap), but to play safer
335 // we still do it.
336 Heap::CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
337
338 former_start[to_trim] = Heap::fixed_array_map();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100339 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
Steve Block6ded16b2010-05-10 14:33:55 +0100340
Steve Block791712a2010-08-27 10:21:07 +0100341 return FixedArray::cast(HeapObject::FromAddress(
342 elms->address() + to_trim * kPointerSize));
Steve Block6ded16b2010-05-10 14:33:55 +0100343}
344
345
Kristian Monsen25f61362010-05-21 11:50:48 +0100346static bool ArrayPrototypeHasNoElements(Context* global_context,
347 JSObject* array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100348 // This method depends on non writability of Object and Array prototype
349 // fields.
Kristian Monsen25f61362010-05-21 11:50:48 +0100350 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
Steve Block6ded16b2010-05-10 14:33:55 +0100351 // Hidden prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100352 array_proto = JSObject::cast(array_proto->GetPrototype());
353 ASSERT(array_proto->elements() == Heap::empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +0100354 // Object.prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100355 array_proto = JSObject::cast(array_proto->GetPrototype());
356 if (array_proto != global_context->initial_object_prototype()) return false;
357 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
358 ASSERT(array_proto->GetPrototype()->IsNull());
Steve Block6ded16b2010-05-10 14:33:55 +0100359 return true;
360}
361
362
Iain Merrick75681382010-08-19 15:07:18 +0100363static inline Object* EnsureJSArrayWithWritableFastElements(Object* receiver) {
364 if (!receiver->IsJSArray()) return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100365 JSArray* array = JSArray::cast(receiver);
Steve Block6ded16b2010-05-10 14:33:55 +0100366 HeapObject* elms = HeapObject::cast(array->elements());
Iain Merrick75681382010-08-19 15:07:18 +0100367 if (elms->map() == Heap::fixed_array_map()) return elms;
368 if (elms->map() == Heap::fixed_cow_array_map()) {
369 return array->EnsureWritableFastElements();
Steve Block6ded16b2010-05-10 14:33:55 +0100370 }
Iain Merrick75681382010-08-19 15:07:18 +0100371 return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100372}
373
374
Iain Merrick75681382010-08-19 15:07:18 +0100375static inline bool IsJSArrayFastElementMovingAllowed(JSArray* receiver) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100376 Context* global_context = Top::context()->global_context();
377 JSObject* array_proto =
378 JSObject::cast(global_context->array_function()->prototype());
Iain Merrick75681382010-08-19 15:07:18 +0100379 return receiver->GetPrototype() == array_proto &&
380 ArrayPrototypeHasNoElements(global_context, array_proto);
Kristian Monsen25f61362010-05-21 11:50:48 +0100381}
382
383
Steve Block6ded16b2010-05-10 14:33:55 +0100384static Object* CallJsBuiltin(const char* name,
385 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
386 HandleScope handleScope;
387
388 Handle<Object> js_builtin =
389 GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
390 name);
391 ASSERT(js_builtin->IsJSFunction());
392 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
Kristian Monsen25f61362010-05-21 11:50:48 +0100393 ScopedVector<Object**> argv(args.length() - 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100394 int n_args = args.length() - 1;
395 for (int i = 0; i < n_args; i++) {
396 argv[i] = args.at<Object>(i + 1).location();
397 }
398 bool pending_exception = false;
399 Handle<Object> result = Execution::Call(function,
400 args.receiver(),
401 n_args,
402 argv.start(),
403 &pending_exception);
Steve Block6ded16b2010-05-10 14:33:55 +0100404 if (pending_exception) return Failure::Exception();
405 return *result;
406}
407
408
Steve Blocka7e24c12009-10-30 11:49:00 +0000409BUILTIN(ArrayPush) {
Steve Block6ded16b2010-05-10 14:33:55 +0100410 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100411 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
412 if (elms_obj == NULL) return CallJsBuiltin("ArrayPush", args);
413 if (elms_obj->IsFailure()) return elms_obj;
414 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100415 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000416
Steve Blocka7e24c12009-10-30 11:49:00 +0000417 int len = Smi::cast(array->length())->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000418 int to_add = args.length() - 1;
419 if (to_add == 0) {
420 return Smi::FromInt(len);
421 }
422 // Currently fixed arrays cannot grow too big, so
423 // we should never hit this case.
424 ASSERT(to_add <= (Smi::kMaxValue - len));
Steve Blocka7e24c12009-10-30 11:49:00 +0000425
Andrei Popescu402d9372010-02-26 13:31:12 +0000426 int new_length = len + to_add;
Steve Blocka7e24c12009-10-30 11:49:00 +0000427
Andrei Popescu402d9372010-02-26 13:31:12 +0000428 if (new_length > elms->length()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000429 // New backing storage is needed.
430 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100431 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +0000432 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +0100433 FixedArray* new_elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000434
435 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100436 if (len > 0) {
437 CopyElements(&no_gc, new_elms, 0, elms, 0, len);
438 }
439 FillWithHoles(new_elms, new_length, capacity);
440
Andrei Popescu402d9372010-02-26 13:31:12 +0000441 elms = new_elms;
442 array->set_elements(elms);
Steve Blocka7e24c12009-10-30 11:49:00 +0000443 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000444
Steve Block6ded16b2010-05-10 14:33:55 +0100445 // Add the provided values.
Andrei Popescu402d9372010-02-26 13:31:12 +0000446 AssertNoAllocation no_gc;
447 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Andrei Popescu402d9372010-02-26 13:31:12 +0000448 for (int index = 0; index < to_add; index++) {
449 elms->set(index + len, args[index + 1], mode);
450 }
451
Steve Blocka7e24c12009-10-30 11:49:00 +0000452 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000453 array->set_length(Smi::FromInt(new_length));
Andrei Popescu402d9372010-02-26 13:31:12 +0000454 return Smi::FromInt(new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000455}
Steve Blocka7e24c12009-10-30 11:49:00 +0000456
457
458BUILTIN(ArrayPop) {
Steve Block6ded16b2010-05-10 14:33:55 +0100459 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100460 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
461 if (elms_obj == NULL) return CallJsBuiltin("ArrayPop", args);
462 if (elms_obj->IsFailure()) return elms_obj;
463 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100464 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000465
466 int len = Smi::cast(array->length())->value();
Steve Block6ded16b2010-05-10 14:33:55 +0100467 if (len == 0) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000468
469 // Get top element
Steve Blocka7e24c12009-10-30 11:49:00 +0000470 Object* top = elms->get(len - 1);
471
472 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000473 array->set_length(Smi::FromInt(len - 1));
Steve Blocka7e24c12009-10-30 11:49:00 +0000474
475 if (!top->IsTheHole()) {
476 // Delete the top element.
477 elms->set_the_hole(len - 1);
478 return top;
479 }
480
Kristian Monsen25f61362010-05-21 11:50:48 +0100481 top = array->GetPrototype()->GetElement(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000482
483 return top;
484}
Steve Blocka7e24c12009-10-30 11:49:00 +0000485
486
Andrei Popescu402d9372010-02-26 13:31:12 +0000487BUILTIN(ArrayShift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100488 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100489 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
490 if (elms_obj->IsFailure()) return elms_obj;
491 if (elms_obj == NULL ||
492 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100493 return CallJsBuiltin("ArrayShift", args);
494 }
Iain Merrick75681382010-08-19 15:07:18 +0100495 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100496 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000497 ASSERT(array->HasFastElements());
498
499 int len = Smi::cast(array->length())->value();
500 if (len == 0) return Heap::undefined_value();
501
Andrei Popescu402d9372010-02-26 13:31:12 +0000502 // Get first element
503 Object* first = elms->get(0);
504 if (first->IsTheHole()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100505 first = Heap::undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000506 }
507
Steve Block791712a2010-08-27 10:21:07 +0100508 if (!Heap::lo_space()->Contains(elms)) {
509 // As elms still in the same space they used to be,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100510 // there is no need to update region dirty mark.
Steve Block6ded16b2010-05-10 14:33:55 +0100511 array->set_elements(LeftTrimFixedArray(elms, 1), SKIP_WRITE_BARRIER);
512 } else {
513 // Shift the elements.
514 AssertNoAllocation no_gc;
515 MoveElements(&no_gc, elms, 0, elms, 1, len - 1);
516 elms->set(len - 1, Heap::the_hole_value());
Andrei Popescu402d9372010-02-26 13:31:12 +0000517 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000518
519 // Set the length.
520 array->set_length(Smi::FromInt(len - 1));
521
522 return first;
523}
524
525
526BUILTIN(ArrayUnshift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100527 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100528 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
529 if (elms_obj->IsFailure()) return elms_obj;
530 if (elms_obj == NULL ||
531 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100532 return CallJsBuiltin("ArrayUnshift", args);
533 }
Iain Merrick75681382010-08-19 15:07:18 +0100534 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100535 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000536 ASSERT(array->HasFastElements());
537
538 int len = Smi::cast(array->length())->value();
539 int to_add = args.length() - 1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000540 int new_length = len + to_add;
541 // Currently fixed arrays cannot grow too big, so
542 // we should never hit this case.
543 ASSERT(to_add <= (Smi::kMaxValue - len));
544
Andrei Popescu402d9372010-02-26 13:31:12 +0000545 if (new_length > elms->length()) {
546 // New backing storage is needed.
547 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100548 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000549 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +0100550 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000551
552 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100553 if (len > 0) {
554 CopyElements(&no_gc, new_elms, to_add, elms, 0, len);
555 }
556 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000557
558 elms = new_elms;
559 array->set_elements(elms);
560 } else {
561 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100562 MoveElements(&no_gc, elms, to_add, elms, 0, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000563 }
564
565 // Add the provided values.
566 AssertNoAllocation no_gc;
567 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
568 for (int i = 0; i < to_add; i++) {
569 elms->set(i, args[i + 1], mode);
570 }
571
572 // Set the length.
573 array->set_length(Smi::FromInt(new_length));
574 return Smi::FromInt(new_length);
575}
576
577
Andrei Popescu402d9372010-02-26 13:31:12 +0000578BUILTIN(ArraySlice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100579 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100580 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
581 if (elms_obj->IsFailure()) return elms_obj;
582 if (elms_obj == NULL ||
583 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100584 return CallJsBuiltin("ArraySlice", args);
585 }
Iain Merrick75681382010-08-19 15:07:18 +0100586 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100587 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000588 ASSERT(array->HasFastElements());
589
590 int len = Smi::cast(array->length())->value();
591
592 int n_arguments = args.length() - 1;
593
594 // Note carefully choosen defaults---if argument is missing,
Steve Block6ded16b2010-05-10 14:33:55 +0100595 // it's undefined which gets converted to 0 for relative_start
596 // and to len for relative_end.
597 int relative_start = 0;
598 int relative_end = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000599 if (n_arguments > 0) {
600 Object* arg1 = args[1];
601 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100602 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000603 } else if (!arg1->IsUndefined()) {
604 return CallJsBuiltin("ArraySlice", args);
605 }
606 if (n_arguments > 1) {
607 Object* arg2 = args[2];
608 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100609 relative_end = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000610 } else if (!arg2->IsUndefined()) {
611 return CallJsBuiltin("ArraySlice", args);
612 }
613 }
614 }
615
616 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
Steve Block6ded16b2010-05-10 14:33:55 +0100617 int k = (relative_start < 0) ? Max(len + relative_start, 0)
618 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000619
620 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
Steve Block6ded16b2010-05-10 14:33:55 +0100621 int final = (relative_end < 0) ? Max(len + relative_end, 0)
622 : Min(relative_end, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000623
624 // Calculate the length of result array.
625 int result_len = final - k;
Steve Block6ded16b2010-05-10 14:33:55 +0100626 if (result_len <= 0) {
627 return AllocateEmptyJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000628 }
629
Steve Block6ded16b2010-05-10 14:33:55 +0100630 Object* result = AllocateJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000631 if (result->IsFailure()) return result;
632 JSArray* result_array = JSArray::cast(result);
633
Steve Block6ded16b2010-05-10 14:33:55 +0100634 result = Heap::AllocateUninitializedFixedArray(result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000635 if (result->IsFailure()) return result;
636 FixedArray* result_elms = FixedArray::cast(result);
637
Andrei Popescu402d9372010-02-26 13:31:12 +0000638 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100639 CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000640
641 // Set elements.
642 result_array->set_elements(result_elms);
643
644 // Set the length.
645 result_array->set_length(Smi::FromInt(result_len));
646 return result_array;
647}
648
649
650BUILTIN(ArraySplice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100651 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100652 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
653 if (elms_obj->IsFailure()) return elms_obj;
654 if (elms_obj == NULL ||
655 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100656 return CallJsBuiltin("ArraySplice", args);
657 }
Iain Merrick75681382010-08-19 15:07:18 +0100658 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100659 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000660 ASSERT(array->HasFastElements());
661
662 int len = Smi::cast(array->length())->value();
663
664 int n_arguments = args.length() - 1;
665
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100666 // Return empty array when no arguments are supplied.
Andrei Popescu402d9372010-02-26 13:31:12 +0000667 if (n_arguments == 0) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100668 return AllocateEmptyJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000669 }
670
Steve Block6ded16b2010-05-10 14:33:55 +0100671 int relative_start = 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000672 Object* arg1 = args[1];
673 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100674 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000675 } else if (!arg1->IsUndefined()) {
676 return CallJsBuiltin("ArraySplice", args);
677 }
Steve Block6ded16b2010-05-10 14:33:55 +0100678 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
679 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000680
681 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
682 // given differently from when an undefined delete count is given.
683 // This does not follow ECMA-262, but we do the same for
684 // compatibility.
Steve Block6ded16b2010-05-10 14:33:55 +0100685 int delete_count = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000686 if (n_arguments > 1) {
687 Object* arg2 = args[2];
688 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100689 delete_count = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000690 } else {
691 return CallJsBuiltin("ArraySplice", args);
692 }
693 }
Steve Block6ded16b2010-05-10 14:33:55 +0100694 int actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000695
Steve Block6ded16b2010-05-10 14:33:55 +0100696 JSArray* result_array = NULL;
697 if (actual_delete_count == 0) {
698 Object* result = AllocateEmptyJSArray();
699 if (result->IsFailure()) return result;
700 result_array = JSArray::cast(result);
701 } else {
702 // Allocate result array.
703 Object* result = AllocateJSArray();
704 if (result->IsFailure()) return result;
705 result_array = JSArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000706
Steve Block6ded16b2010-05-10 14:33:55 +0100707 result = Heap::AllocateUninitializedFixedArray(actual_delete_count);
708 if (result->IsFailure()) return result;
709 FixedArray* result_elms = FixedArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000710
Steve Block6ded16b2010-05-10 14:33:55 +0100711 AssertNoAllocation no_gc;
712 // Fill newly created array.
713 CopyElements(&no_gc,
714 result_elms, 0,
715 elms, actual_start,
716 actual_delete_count);
Andrei Popescu402d9372010-02-26 13:31:12 +0000717
Steve Block6ded16b2010-05-10 14:33:55 +0100718 // Set elements.
719 result_array->set_elements(result_elms);
Andrei Popescu402d9372010-02-26 13:31:12 +0000720
Steve Block6ded16b2010-05-10 14:33:55 +0100721 // Set the length.
722 result_array->set_length(Smi::FromInt(actual_delete_count));
Andrei Popescu402d9372010-02-26 13:31:12 +0000723 }
724
Steve Block6ded16b2010-05-10 14:33:55 +0100725 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000726
Steve Block6ded16b2010-05-10 14:33:55 +0100727 int new_length = len - actual_delete_count + item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000728
Steve Block6ded16b2010-05-10 14:33:55 +0100729 if (item_count < actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000730 // Shrink the array.
Steve Block791712a2010-08-27 10:21:07 +0100731 const bool trim_array = !Heap::lo_space()->Contains(elms) &&
Steve Block6ded16b2010-05-10 14:33:55 +0100732 ((actual_start + item_count) <
733 (len - actual_delete_count - actual_start));
734 if (trim_array) {
735 const int delta = actual_delete_count - item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000736
Steve Block6ded16b2010-05-10 14:33:55 +0100737 if (actual_start > 0) {
738 Object** start = elms->data_start();
739 memmove(start + delta, start, actual_start * kPointerSize);
740 }
741
742 elms = LeftTrimFixedArray(elms, delta);
743 array->set_elements(elms, SKIP_WRITE_BARRIER);
744 } else {
745 AssertNoAllocation no_gc;
746 MoveElements(&no_gc,
747 elms, actual_start + item_count,
748 elms, actual_start + actual_delete_count,
749 (len - actual_delete_count - actual_start));
750 FillWithHoles(elms, new_length, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000751 }
Steve Block6ded16b2010-05-10 14:33:55 +0100752 } else if (item_count > actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000753 // Currently fixed arrays cannot grow too big, so
754 // we should never hit this case.
Steve Block6ded16b2010-05-10 14:33:55 +0100755 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
Andrei Popescu402d9372010-02-26 13:31:12 +0000756
757 // Check if array need to grow.
758 if (new_length > elms->length()) {
759 // New backing storage is needed.
760 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100761 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000762 if (obj->IsFailure()) return obj;
Andrei Popescu402d9372010-02-26 13:31:12 +0000763 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000764
Steve Block6ded16b2010-05-10 14:33:55 +0100765 AssertNoAllocation no_gc;
766 // Copy the part before actual_start as is.
767 if (actual_start > 0) {
768 CopyElements(&no_gc, new_elms, 0, elms, 0, actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000769 }
Steve Block6ded16b2010-05-10 14:33:55 +0100770 const int to_copy = len - actual_delete_count - actual_start;
771 if (to_copy > 0) {
772 CopyElements(&no_gc,
773 new_elms, actual_start + item_count,
774 elms, actual_start + actual_delete_count,
775 to_copy);
776 }
777 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000778
Andrei Popescu402d9372010-02-26 13:31:12 +0000779 elms = new_elms;
780 array->set_elements(elms);
Steve Block6ded16b2010-05-10 14:33:55 +0100781 } else {
782 AssertNoAllocation no_gc;
783 MoveElements(&no_gc,
784 elms, actual_start + item_count,
785 elms, actual_start + actual_delete_count,
786 (len - actual_delete_count - actual_start));
Andrei Popescu402d9372010-02-26 13:31:12 +0000787 }
788 }
789
Steve Block6ded16b2010-05-10 14:33:55 +0100790 AssertNoAllocation no_gc;
791 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
792 for (int k = actual_start; k < actual_start + item_count; k++) {
793 elms->set(k, args[3 + k - actual_start], mode);
Andrei Popescu402d9372010-02-26 13:31:12 +0000794 }
795
796 // Set the length.
797 array->set_length(Smi::FromInt(new_length));
798
799 return result_array;
800}
801
802
Steve Block6ded16b2010-05-10 14:33:55 +0100803BUILTIN(ArrayConcat) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100804 Context* global_context = Top::context()->global_context();
805 JSObject* array_proto =
806 JSObject::cast(global_context->array_function()->prototype());
807 if (!ArrayPrototypeHasNoElements(global_context, array_proto)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100808 return CallJsBuiltin("ArrayConcat", args);
809 }
810
811 // Iterate through all the arguments performing checks
812 // and calculating total length.
813 int n_arguments = args.length();
814 int result_len = 0;
815 for (int i = 0; i < n_arguments; i++) {
816 Object* arg = args[i];
Kristian Monsen25f61362010-05-21 11:50:48 +0100817 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
818 || JSArray::cast(arg)->GetPrototype() != array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100819 return CallJsBuiltin("ArrayConcat", args);
820 }
821
822 int len = Smi::cast(JSArray::cast(arg)->length())->value();
823
824 // We shouldn't overflow when adding another len.
825 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
826 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
827 USE(kHalfOfMaxInt);
828 result_len += len;
829 ASSERT(result_len >= 0);
830
831 if (result_len > FixedArray::kMaxLength) {
832 return CallJsBuiltin("ArrayConcat", args);
833 }
834 }
835
836 if (result_len == 0) {
837 return AllocateEmptyJSArray();
838 }
839
840 // Allocate result.
841 Object* result = AllocateJSArray();
842 if (result->IsFailure()) return result;
843 JSArray* result_array = JSArray::cast(result);
844
845 result = Heap::AllocateUninitializedFixedArray(result_len);
846 if (result->IsFailure()) return result;
847 FixedArray* result_elms = FixedArray::cast(result);
848
849 // Copy data.
850 AssertNoAllocation no_gc;
851 int start_pos = 0;
852 for (int i = 0; i < n_arguments; i++) {
853 JSArray* array = JSArray::cast(args[i]);
854 int len = Smi::cast(array->length())->value();
855 if (len > 0) {
856 FixedArray* elms = FixedArray::cast(array->elements());
857 CopyElements(&no_gc, result_elms, start_pos, elms, 0, len);
858 start_pos += len;
859 }
860 }
861 ASSERT(start_pos == result_len);
862
863 // Set the length and elements.
864 result_array->set_length(Smi::FromInt(result_len));
865 result_array->set_elements(result_elms);
866
867 return result_array;
868}
869
870
Steve Blocka7e24c12009-10-30 11:49:00 +0000871// -----------------------------------------------------------------------------
872//
873
874
875// Returns the holder JSObject if the function can legally be called
876// with this receiver. Returns Heap::null_value() if the call is
877// illegal. Any arguments that don't fit the expected type is
878// overwritten with undefined. Arguments that do fit the expected
879// type is overwritten with the object in the prototype chain that
880// actually has that type.
881static inline Object* TypeCheck(int argc,
882 Object** argv,
883 FunctionTemplateInfo* info) {
884 Object* recv = argv[0];
885 Object* sig_obj = info->signature();
886 if (sig_obj->IsUndefined()) return recv;
887 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
888 // If necessary, check the receiver
889 Object* recv_type = sig->receiver();
890
891 Object* holder = recv;
892 if (!recv_type->IsUndefined()) {
893 for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
894 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
895 break;
896 }
897 }
898 if (holder == Heap::null_value()) return holder;
899 }
900 Object* args_obj = sig->args();
901 // If there is no argument signature we're done
902 if (args_obj->IsUndefined()) return holder;
903 FixedArray* args = FixedArray::cast(args_obj);
904 int length = args->length();
905 if (argc <= length) length = argc - 1;
906 for (int i = 0; i < length; i++) {
907 Object* argtype = args->get(i);
908 if (argtype->IsUndefined()) continue;
909 Object** arg = &argv[-1 - i];
910 Object* current = *arg;
911 for (; current != Heap::null_value(); current = current->GetPrototype()) {
912 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
913 *arg = current;
914 break;
915 }
916 }
917 if (current == Heap::null_value()) *arg = Heap::undefined_value();
918 }
919 return holder;
920}
921
922
Leon Clarkee46be812010-01-19 14:06:41 +0000923template <bool is_construct>
924static Object* HandleApiCallHelper(
925 BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
926 ASSERT(is_construct == CalledAsConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +0000927
Leon Clarkee46be812010-01-19 14:06:41 +0000928 HandleScope scope;
929 Handle<JSFunction> function = args.called_function();
Steve Block6ded16b2010-05-10 14:33:55 +0100930 ASSERT(function->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +0000931
Steve Block6ded16b2010-05-10 14:33:55 +0100932 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
Steve Blocka7e24c12009-10-30 11:49:00 +0000933 if (is_construct) {
Steve Block6ded16b2010-05-10 14:33:55 +0100934 Handle<FunctionTemplateInfo> desc(fun_data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000935 bool pending_exception = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000936 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000937 &pending_exception);
938 ASSERT(Top::has_pending_exception() == pending_exception);
939 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +0100940 fun_data = *desc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000941 }
942
Steve Blocka7e24c12009-10-30 11:49:00 +0000943 Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
944
945 if (raw_holder->IsNull()) {
946 // This function cannot be called with the given receiver. Abort!
947 Handle<Object> obj =
948 Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
949 return Top::Throw(*obj);
950 }
951
952 Object* raw_call_data = fun_data->call_code();
953 if (!raw_call_data->IsUndefined()) {
954 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
955 Object* callback_obj = call_data->callback();
956 v8::InvocationCallback callback =
957 v8::ToCData<v8::InvocationCallback>(callback_obj);
958 Object* data_obj = call_data->data();
959 Object* result;
960
Steve Blocka7e24c12009-10-30 11:49:00 +0000961 Handle<Object> data_handle(data_obj);
962 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
963 ASSERT(raw_holder->IsJSObject());
964 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
965 Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
966 v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
Leon Clarkee46be812010-01-19 14:06:41 +0000967 LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +0000968 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
969 data,
970 holder,
971 callee,
972 is_construct,
973 reinterpret_cast<void**>(&args[0] - 1),
974 args.length() - 1);
975
976 v8::Handle<v8::Value> value;
977 {
978 // Leaving JavaScript.
979 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000980#ifdef ENABLE_LOGGING_AND_PROFILING
981 state.set_external_callback(v8::ToCData<Address>(callback_obj));
982#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000983 value = callback(new_args);
984 }
985 if (value.IsEmpty()) {
986 result = Heap::undefined_value();
987 } else {
988 result = *reinterpret_cast<Object**>(*value);
989 }
990
991 RETURN_IF_SCHEDULED_EXCEPTION();
992 if (!is_construct || result->IsJSObject()) return result;
993 }
994
Leon Clarkee46be812010-01-19 14:06:41 +0000995 return *args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +0000996}
Leon Clarkee46be812010-01-19 14:06:41 +0000997
998
999BUILTIN(HandleApiCall) {
1000 return HandleApiCallHelper<false>(args);
1001}
1002
1003
1004BUILTIN(HandleApiCallConstruct) {
1005 return HandleApiCallHelper<true>(args);
1006}
Steve Blocka7e24c12009-10-30 11:49:00 +00001007
1008
Andrei Popescu402d9372010-02-26 13:31:12 +00001009#ifdef DEBUG
1010
1011static void VerifyTypeCheck(Handle<JSObject> object,
1012 Handle<JSFunction> function) {
Steve Block6ded16b2010-05-10 14:33:55 +01001013 ASSERT(function->shared()->IsApiFunction());
1014 FunctionTemplateInfo* info = function->shared()->get_api_func_data();
Andrei Popescu402d9372010-02-26 13:31:12 +00001015 if (info->signature()->IsUndefined()) return;
1016 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1017 Object* receiver_type = signature->receiver();
1018 if (receiver_type->IsUndefined()) return;
1019 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
1020 ASSERT(object->IsInstanceOf(type));
1021}
1022
1023#endif
1024
1025
1026BUILTIN(FastHandleApiCall) {
1027 ASSERT(!CalledAsConstructor());
1028 const bool is_construct = false;
1029
1030 // We expect four more arguments: function, callback, call data, and holder.
1031 const int args_length = args.length() - 4;
1032 ASSERT(args_length >= 0);
1033
1034 Handle<JSFunction> function = args.at<JSFunction>(args_length);
1035 Object* callback_obj = args[args_length + 1];
1036 Handle<Object> data_handle = args.at<Object>(args_length + 2);
1037 Handle<JSObject> checked_holder = args.at<JSObject>(args_length + 3);
1038
1039#ifdef DEBUG
1040 VerifyTypeCheck(checked_holder, function);
1041#endif
1042
1043 v8::Local<v8::Object> holder = v8::Utils::ToLocal(checked_holder);
1044 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
1045 v8::InvocationCallback callback =
1046 v8::ToCData<v8::InvocationCallback>(callback_obj);
1047 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
1048
1049 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1050 data,
1051 holder,
1052 callee,
1053 is_construct,
1054 reinterpret_cast<void**>(&args[0] - 1),
1055 args_length - 1);
1056
1057 HandleScope scope;
1058 Object* result;
1059 v8::Handle<v8::Value> value;
1060 {
1061 // Leaving JavaScript.
1062 VMState state(EXTERNAL);
1063#ifdef ENABLE_LOGGING_AND_PROFILING
1064 state.set_external_callback(v8::ToCData<Address>(callback_obj));
1065#endif
1066 value = callback(new_args);
1067 }
1068 if (value.IsEmpty()) {
1069 result = Heap::undefined_value();
1070 } else {
1071 result = *reinterpret_cast<Object**>(*value);
1072 }
1073
1074 RETURN_IF_SCHEDULED_EXCEPTION();
1075 return result;
1076}
1077
1078
Steve Blocka7e24c12009-10-30 11:49:00 +00001079// Helper function to handle calls to non-function objects created through the
1080// API. The object can be called as either a constructor (using new) or just as
1081// a function (without new).
Leon Clarkee46be812010-01-19 14:06:41 +00001082static Object* HandleApiCallAsFunctionOrConstructor(
1083 bool is_construct_call,
1084 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001085 // Non-functions are never called as constructors. Even if this is an object
1086 // called as a constructor the delegate call is not a construct call.
1087 ASSERT(!CalledAsConstructor());
1088
1089 Handle<Object> receiver = args.at<Object>(0);
1090
1091 // Get the object called.
Leon Clarkee46be812010-01-19 14:06:41 +00001092 JSObject* obj = JSObject::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +00001093
1094 // Get the invocation callback from the function descriptor that was
1095 // used to create the called object.
1096 ASSERT(obj->map()->has_instance_call_handler());
1097 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01001098 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001099 Object* handler =
Steve Block6ded16b2010-05-10 14:33:55 +01001100 constructor->shared()->get_api_func_data()->instance_call_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00001101 ASSERT(!handler->IsUndefined());
1102 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1103 Object* callback_obj = call_data->callback();
1104 v8::InvocationCallback callback =
1105 v8::ToCData<v8::InvocationCallback>(callback_obj);
1106
1107 // Get the data for the call and perform the callback.
1108 Object* data_obj = call_data->data();
1109 Object* result;
1110 { HandleScope scope;
1111 v8::Local<v8::Object> self =
Leon Clarkee46be812010-01-19 14:06:41 +00001112 v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001113 Handle<Object> data_handle(data_obj);
1114 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
1115 Handle<JSFunction> callee_handle(constructor);
1116 v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
Leon Clarkee46be812010-01-19 14:06:41 +00001117 LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001118 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1119 data,
1120 self,
1121 callee,
1122 is_construct_call,
1123 reinterpret_cast<void**>(&args[0] - 1),
1124 args.length() - 1);
1125 v8::Handle<v8::Value> value;
1126 {
1127 // Leaving JavaScript.
1128 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +00001129#ifdef ENABLE_LOGGING_AND_PROFILING
1130 state.set_external_callback(v8::ToCData<Address>(callback_obj));
1131#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001132 value = callback(new_args);
1133 }
1134 if (value.IsEmpty()) {
1135 result = Heap::undefined_value();
1136 } else {
1137 result = *reinterpret_cast<Object**>(*value);
1138 }
1139 }
1140 // Check for exceptions and return result.
1141 RETURN_IF_SCHEDULED_EXCEPTION();
1142 return result;
1143}
1144
1145
1146// Handle calls to non-function objects created through the API. This delegate
1147// function is used when the call is a normal function call.
1148BUILTIN(HandleApiCallAsFunction) {
1149 return HandleApiCallAsFunctionOrConstructor(false, args);
1150}
Steve Blocka7e24c12009-10-30 11:49:00 +00001151
1152
1153// Handle calls to non-function objects created through the API. This delegate
1154// function is used when the call is a construct call.
1155BUILTIN(HandleApiCallAsConstructor) {
1156 return HandleApiCallAsFunctionOrConstructor(true, args);
1157}
Steve Blocka7e24c12009-10-30 11:49:00 +00001158
1159
1160static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1161 LoadIC::GenerateArrayLength(masm);
1162}
1163
1164
1165static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
1166 LoadIC::GenerateStringLength(masm);
1167}
1168
1169
1170static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1171 LoadIC::GenerateFunctionPrototype(masm);
1172}
1173
1174
1175static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1176 LoadIC::GenerateInitialize(masm);
1177}
1178
1179
1180static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1181 LoadIC::GeneratePreMonomorphic(masm);
1182}
1183
1184
1185static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1186 LoadIC::GenerateMiss(masm);
1187}
1188
1189
1190static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1191 LoadIC::GenerateMegamorphic(masm);
1192}
1193
1194
1195static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1196 LoadIC::GenerateNormal(masm);
1197}
1198
1199
1200static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1201 KeyedLoadIC::GenerateInitialize(masm);
1202}
1203
1204
1205static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1206 KeyedLoadIC::GenerateMiss(masm);
1207}
1208
1209
1210static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1211 KeyedLoadIC::GenerateGeneric(masm);
1212}
1213
1214
Leon Clarkee46be812010-01-19 14:06:41 +00001215static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1216 KeyedLoadIC::GenerateString(masm);
1217}
1218
1219
Steve Block3ce2e202009-11-05 08:53:23 +00001220static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
1221 KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
1222}
1223
1224
1225static void Generate_KeyedLoadIC_ExternalUnsignedByteArray(
1226 MacroAssembler* masm) {
1227 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1228}
1229
1230
1231static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) {
1232 KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray);
1233}
1234
1235
1236static void Generate_KeyedLoadIC_ExternalUnsignedShortArray(
1237 MacroAssembler* masm) {
1238 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1239}
1240
1241
1242static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) {
1243 KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray);
1244}
1245
1246
1247static void Generate_KeyedLoadIC_ExternalUnsignedIntArray(
1248 MacroAssembler* masm) {
1249 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1250}
1251
1252
1253static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) {
1254 KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray);
1255}
1256
1257
Steve Blocka7e24c12009-10-30 11:49:00 +00001258static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1259 KeyedLoadIC::GeneratePreMonomorphic(masm);
1260}
1261
Andrei Popescu402d9372010-02-26 13:31:12 +00001262static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1263 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1264}
1265
Steve Blocka7e24c12009-10-30 11:49:00 +00001266
1267static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1268 StoreIC::GenerateInitialize(masm);
1269}
1270
1271
1272static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1273 StoreIC::GenerateMiss(masm);
1274}
1275
1276
Steve Block8defd9f2010-07-08 12:39:36 +01001277static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1278 StoreIC::GenerateNormal(masm);
1279}
1280
1281
Steve Blocka7e24c12009-10-30 11:49:00 +00001282static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
1283 StoreIC::GenerateMegamorphic(masm);
1284}
1285
1286
Steve Block6ded16b2010-05-10 14:33:55 +01001287static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1288 StoreIC::GenerateArrayLength(masm);
1289}
1290
1291
Steve Blocka7e24c12009-10-30 11:49:00 +00001292static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
1293 KeyedStoreIC::GenerateGeneric(masm);
1294}
1295
1296
Steve Block3ce2e202009-11-05 08:53:23 +00001297static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) {
1298 KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray);
1299}
1300
1301
1302static void Generate_KeyedStoreIC_ExternalUnsignedByteArray(
1303 MacroAssembler* masm) {
1304 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1305}
1306
1307
1308static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) {
1309 KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray);
1310}
1311
1312
1313static void Generate_KeyedStoreIC_ExternalUnsignedShortArray(
1314 MacroAssembler* masm) {
1315 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1316}
1317
1318
1319static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) {
1320 KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray);
1321}
1322
1323
1324static void Generate_KeyedStoreIC_ExternalUnsignedIntArray(
1325 MacroAssembler* masm) {
1326 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1327}
1328
1329
1330static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) {
1331 KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray);
1332}
1333
1334
Steve Blocka7e24c12009-10-30 11:49:00 +00001335static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1336 KeyedStoreIC::GenerateMiss(masm);
1337}
1338
1339
1340static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1341 KeyedStoreIC::GenerateInitialize(masm);
1342}
1343
1344
1345#ifdef ENABLE_DEBUGGER_SUPPORT
1346static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1347 Debug::GenerateLoadICDebugBreak(masm);
1348}
1349
1350
1351static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1352 Debug::GenerateStoreICDebugBreak(masm);
1353}
1354
1355
1356static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1357 Debug::GenerateKeyedLoadICDebugBreak(masm);
1358}
1359
1360
1361static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1362 Debug::GenerateKeyedStoreICDebugBreak(masm);
1363}
1364
1365
1366static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1367 Debug::GenerateConstructCallDebugBreak(masm);
1368}
1369
1370
1371static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1372 Debug::GenerateReturnDebugBreak(masm);
1373}
1374
1375
1376static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
1377 Debug::GenerateStubNoRegistersDebugBreak(masm);
1378}
Steve Block6ded16b2010-05-10 14:33:55 +01001379
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001380
1381static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1382 Debug::GenerateSlotDebugBreak(masm);
1383}
1384
1385
Steve Block6ded16b2010-05-10 14:33:55 +01001386static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1387 Debug::GeneratePlainReturnLiveEdit(masm);
1388}
1389
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001390
Steve Block6ded16b2010-05-10 14:33:55 +01001391static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1392 Debug::GenerateFrameDropperLiveEdit(masm);
1393}
Steve Blocka7e24c12009-10-30 11:49:00 +00001394#endif
1395
1396Object* Builtins::builtins_[builtin_count] = { NULL, };
1397const char* Builtins::names_[builtin_count] = { NULL, };
1398
Leon Clarkee46be812010-01-19 14:06:41 +00001399#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Steve Blocka7e24c12009-10-30 11:49:00 +00001400 Address Builtins::c_functions_[cfunction_count] = {
1401 BUILTIN_LIST_C(DEF_ENUM_C)
1402 };
1403#undef DEF_ENUM_C
1404
1405#define DEF_JS_NAME(name, ignore) #name,
1406#define DEF_JS_ARGC(ignore, argc) argc,
1407const char* Builtins::javascript_names_[id_count] = {
1408 BUILTINS_LIST_JS(DEF_JS_NAME)
1409};
1410
1411int Builtins::javascript_argc_[id_count] = {
1412 BUILTINS_LIST_JS(DEF_JS_ARGC)
1413};
1414#undef DEF_JS_NAME
1415#undef DEF_JS_ARGC
1416
1417static bool is_initialized = false;
1418void Builtins::Setup(bool create_heap_objects) {
1419 ASSERT(!is_initialized);
1420
1421 // Create a scope for the handles in the builtins.
1422 HandleScope scope;
1423
1424 struct BuiltinDesc {
1425 byte* generator;
1426 byte* c_code;
1427 const char* s_name; // name is only used for generating log information.
1428 int name;
1429 Code::Flags flags;
Leon Clarkee46be812010-01-19 14:06:41 +00001430 BuiltinExtraArguments extra_args;
Steve Blocka7e24c12009-10-30 11:49:00 +00001431 };
1432
Leon Clarkee46be812010-01-19 14:06:41 +00001433#define DEF_FUNCTION_PTR_C(name, extra_args) \
1434 { FUNCTION_ADDR(Generate_Adaptor), \
1435 FUNCTION_ADDR(Builtin_##name), \
1436 #name, \
1437 c_##name, \
1438 Code::ComputeFlags(Code::BUILTIN), \
1439 extra_args \
Steve Blocka7e24c12009-10-30 11:49:00 +00001440 },
1441
1442#define DEF_FUNCTION_PTR_A(name, kind, state) \
1443 { FUNCTION_ADDR(Generate_##name), \
1444 NULL, \
1445 #name, \
1446 name, \
Leon Clarkee46be812010-01-19 14:06:41 +00001447 Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
1448 NO_EXTRA_ARGUMENTS \
Steve Blocka7e24c12009-10-30 11:49:00 +00001449 },
1450
1451 // Define array of pointers to generators and C builtin functions.
1452 static BuiltinDesc functions[] = {
1453 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1454 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1455 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1456 // Terminator:
Leon Clarkee46be812010-01-19 14:06:41 +00001457 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
1458 NO_EXTRA_ARGUMENTS }
Steve Blocka7e24c12009-10-30 11:49:00 +00001459 };
1460
1461#undef DEF_FUNCTION_PTR_C
1462#undef DEF_FUNCTION_PTR_A
1463
1464 // For now we generate builtin adaptor code into a stack-allocated
1465 // buffer, before copying it into individual code objects.
1466 byte buffer[4*KB];
1467
1468 // Traverse the list of builtins and generate an adaptor in a
1469 // separate code object for each one.
1470 for (int i = 0; i < builtin_count; i++) {
1471 if (create_heap_objects) {
1472 MacroAssembler masm(buffer, sizeof buffer);
1473 // Generate the code/adaptor.
Leon Clarkee46be812010-01-19 14:06:41 +00001474 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001475 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1476 // We pass all arguments to the generator, but it may not use all of
1477 // them. This works because the first arguments are on top of the
1478 // stack.
Leon Clarkee46be812010-01-19 14:06:41 +00001479 g(&masm, functions[i].name, functions[i].extra_args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001480 // Move the code into the object heap.
1481 CodeDesc desc;
1482 masm.GetCode(&desc);
1483 Code::Flags flags = functions[i].flags;
1484 Object* code;
1485 {
1486 // During startup it's OK to always allocate and defer GC to later.
1487 // This simplifies things because we don't need to retry.
1488 AlwaysAllocateScope __scope__;
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001489 code = Heap::CreateCode(desc, flags, masm.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00001490 if (code->IsFailure()) {
1491 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1492 }
1493 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001494 // Log the event and add the code to the builtins array.
Steve Block6ded16b2010-05-10 14:33:55 +01001495 PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
1496 Code::cast(code), functions[i].s_name));
Steve Blocka7e24c12009-10-30 11:49:00 +00001497 builtins_[i] = code;
1498#ifdef ENABLE_DISASSEMBLER
1499 if (FLAG_print_builtin_code) {
1500 PrintF("Builtin: %s\n", functions[i].s_name);
1501 Code::cast(code)->Disassemble(functions[i].s_name);
1502 PrintF("\n");
1503 }
1504#endif
1505 } else {
1506 // Deserializing. The values will be filled in during IterateBuiltins.
1507 builtins_[i] = NULL;
1508 }
1509 names_[i] = functions[i].s_name;
1510 }
1511
1512 // Mark as initialized.
1513 is_initialized = true;
1514}
1515
1516
1517void Builtins::TearDown() {
1518 is_initialized = false;
1519}
1520
1521
1522void Builtins::IterateBuiltins(ObjectVisitor* v) {
1523 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1524}
1525
1526
1527const char* Builtins::Lookup(byte* pc) {
1528 if (is_initialized) { // may be called during initialization (disassembler!)
1529 for (int i = 0; i < builtin_count; i++) {
1530 Code* entry = Code::cast(builtins_[i]);
1531 if (entry->contains(pc)) {
1532 return names_[i];
1533 }
1534 }
1535 }
1536 return NULL;
1537}
1538
1539
1540} } // namespace v8::internal