blob: aede3020358dcf2d5306a486b485ea200abbdb91 [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
John Reck59135872010-11-02 12:39:01 -0700124#define BUILTIN(name) \
125 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
126 name##ArgumentsType args); \
127 MUST_USE_RESULT static MaybeObject* Builtin_##name( \
128 name##ArgumentsType args) { \
129 args.Verify(); \
130 return Builtin_Impl_##name(args); \
131 } \
132 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
133 name##ArgumentsType args)
Steve Blocka7e24c12009-10-30 11:49:00 +0000134
Leon Clarkee46be812010-01-19 14:06:41 +0000135#else // For release mode.
Steve Blocka7e24c12009-10-30 11:49:00 +0000136
John Reck59135872010-11-02 12:39:01 -0700137#define BUILTIN(name) \
138 static MaybeObject* Builtin_##name(name##ArgumentsType args)
Leon Clarkee46be812010-01-19 14:06:41 +0000139
140#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000141
142
143static inline bool CalledAsConstructor() {
144#ifdef DEBUG
145 // Calculate the result using a full stack frame iterator and check
146 // that the state of the stack is as we assume it to be in the
147 // code below.
148 StackFrameIterator it;
149 ASSERT(it.frame()->is_exit());
150 it.Advance();
151 StackFrame* frame = it.frame();
152 bool reference_result = frame->is_construct();
153#endif
154 Address fp = Top::c_entry_fp(Top::GetCurrentThread());
155 // Because we know fp points to an exit frame we can use the relevant
156 // part of ExitFrame::ComputeCallerState directly.
157 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
158 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
159 // This inlines the part of StackFrame::ComputeType that grabs the
160 // type of the current frame. Note that StackFrame::ComputeType
161 // has been specialized for each architecture so if any one of them
162 // changes this code has to be changed as well.
163 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
164 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
165 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
166 bool result = (marker == kConstructMarker);
167 ASSERT_EQ(result, reference_result);
168 return result;
169}
170
171// ----------------------------------------------------------------------------
172
173
Steve Blocka7e24c12009-10-30 11:49:00 +0000174BUILTIN(Illegal) {
175 UNREACHABLE();
Leon Clarkee46be812010-01-19 14:06:41 +0000176 return Heap::undefined_value(); // Make compiler happy.
Steve Blocka7e24c12009-10-30 11:49:00 +0000177}
Steve Blocka7e24c12009-10-30 11:49:00 +0000178
179
180BUILTIN(EmptyFunction) {
Leon Clarkee46be812010-01-19 14:06:41 +0000181 return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000182}
Steve Blocka7e24c12009-10-30 11:49:00 +0000183
184
185BUILTIN(ArrayCodeGeneric) {
186 Counters::array_function_runtime.Increment();
187
188 JSArray* array;
189 if (CalledAsConstructor()) {
Leon Clarkee46be812010-01-19 14:06:41 +0000190 array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000191 } else {
192 // Allocate the JS Array
193 JSFunction* constructor =
194 Top::context()->global_context()->array_function();
John Reck59135872010-11-02 12:39:01 -0700195 Object* obj;
196 { MaybeObject* maybe_obj = Heap::AllocateJSObject(constructor);
197 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
198 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000199 array = JSArray::cast(obj);
200 }
201
202 // 'array' now contains the JSArray we should initialize.
Steve Block8defd9f2010-07-08 12:39:36 +0100203 ASSERT(array->HasFastElements());
Steve Blocka7e24c12009-10-30 11:49:00 +0000204
205 // Optimize the case where there is one argument and the argument is a
206 // small smi.
207 if (args.length() == 2) {
208 Object* obj = args[1];
209 if (obj->IsSmi()) {
210 int len = Smi::cast(obj)->value();
211 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
John Reck59135872010-11-02 12:39:01 -0700212 Object* obj;
213 { MaybeObject* maybe_obj = Heap::AllocateFixedArrayWithHoles(len);
214 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
215 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000216 array->SetContent(FixedArray::cast(obj));
217 return array;
218 }
219 }
220 // Take the argument as the length.
John Reck59135872010-11-02 12:39:01 -0700221 { MaybeObject* maybe_obj = array->Initialize(0);
222 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
223 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 return array->SetElementsLength(args[1]);
225 }
226
227 // Optimize the case where there are no parameters passed.
228 if (args.length() == 1) {
229 return array->Initialize(JSArray::kPreallocatedArrayElements);
230 }
231
232 // Take the arguments as elements.
233 int number_of_elements = args.length() - 1;
234 Smi* len = Smi::FromInt(number_of_elements);
John Reck59135872010-11-02 12:39:01 -0700235 Object* obj;
236 { MaybeObject* maybe_obj = Heap::AllocateFixedArrayWithHoles(len->value());
237 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
238 }
Leon Clarke4515c472010-02-03 11:58:03 +0000239
240 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000241 FixedArray* elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000242 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000243 // Fill in the content
244 for (int index = 0; index < number_of_elements; index++) {
245 elms->set(index, args[index+1], mode);
246 }
247
248 // Set length and elements on the array.
249 array->set_elements(FixedArray::cast(obj));
Leon Clarke4515c472010-02-03 11:58:03 +0000250 array->set_length(len);
Steve Blocka7e24c12009-10-30 11:49:00 +0000251
252 return array;
253}
Steve Blocka7e24c12009-10-30 11:49:00 +0000254
255
John Reck59135872010-11-02 12:39:01 -0700256MUST_USE_RESULT static MaybeObject* AllocateJSArray() {
Steve Block6ded16b2010-05-10 14:33:55 +0100257 JSFunction* array_function =
258 Top::context()->global_context()->array_function();
John Reck59135872010-11-02 12:39:01 -0700259 Object* result;
260 { MaybeObject* maybe_result = Heap::AllocateJSObject(array_function);
261 if (!maybe_result->ToObject(&result)) return maybe_result;
262 }
Steve Block6ded16b2010-05-10 14:33:55 +0100263 return result;
264}
265
266
John Reck59135872010-11-02 12:39:01 -0700267MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray() {
268 Object* result;
269 { MaybeObject* maybe_result = AllocateJSArray();
270 if (!maybe_result->ToObject(&result)) return maybe_result;
271 }
Steve Block6ded16b2010-05-10 14:33:55 +0100272 JSArray* result_array = JSArray::cast(result);
273 result_array->set_length(Smi::FromInt(0));
274 result_array->set_elements(Heap::empty_fixed_array());
275 return result_array;
276}
277
278
279static void CopyElements(AssertNoAllocation* no_gc,
280 FixedArray* dst,
281 int dst_index,
282 FixedArray* src,
283 int src_index,
284 int len) {
285 ASSERT(dst != src); // Use MoveElements instead.
Iain Merrick75681382010-08-19 15:07:18 +0100286 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100287 ASSERT(len > 0);
288 CopyWords(dst->data_start() + dst_index,
289 src->data_start() + src_index,
290 len);
291 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
292 if (mode == UPDATE_WRITE_BARRIER) {
293 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
294 }
295}
296
297
298static void MoveElements(AssertNoAllocation* no_gc,
299 FixedArray* dst,
300 int dst_index,
301 FixedArray* src,
302 int src_index,
303 int len) {
Iain Merrick75681382010-08-19 15:07:18 +0100304 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100305 memmove(dst->data_start() + dst_index,
306 src->data_start() + src_index,
307 len * kPointerSize);
308 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
309 if (mode == UPDATE_WRITE_BARRIER) {
310 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
311 }
312}
313
314
315static void FillWithHoles(FixedArray* dst, int from, int to) {
Iain Merrick75681382010-08-19 15:07:18 +0100316 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100317 MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from);
318}
319
320
321static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
Iain Merrick75681382010-08-19 15:07:18 +0100322 ASSERT(elms->map() != Heap::fixed_cow_array_map());
Steve Block791712a2010-08-27 10:21:07 +0100323 // For now this trick is only applied to fixed arrays in new and paged space.
Steve Block6ded16b2010-05-10 14:33:55 +0100324 // In large object space the object's start must coincide with chunk
325 // and thus the trick is just not applicable.
Steve Block791712a2010-08-27 10:21:07 +0100326 ASSERT(!Heap::lo_space()->Contains(elms));
Steve Block6ded16b2010-05-10 14:33:55 +0100327
328 STATIC_ASSERT(FixedArray::kMapOffset == 0);
329 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
330 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
331
332 Object** former_start = HeapObject::RawField(elms, 0);
333
334 const int len = elms->length();
335
Steve Block791712a2010-08-27 10:21:07 +0100336 if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
337 !Heap::new_space()->Contains(elms)) {
338 // If we are doing a big trim in old space then we zap the space that was
339 // formerly part of the array so that the GC (aided by the card-based
340 // remembered set) won't find pointers to new-space there.
341 Object** zap = reinterpret_cast<Object**>(elms->address());
342 zap++; // Header of filler must be at least one word so skip that.
343 for (int i = 1; i < to_trim; i++) {
344 *zap++ = Smi::FromInt(0);
345 }
346 }
Steve Block6ded16b2010-05-10 14:33:55 +0100347 // Technically in new space this write might be omitted (except for
348 // debug mode which iterates through the heap), but to play safer
349 // we still do it.
350 Heap::CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
351
352 former_start[to_trim] = Heap::fixed_array_map();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100353 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
Steve Block6ded16b2010-05-10 14:33:55 +0100354
Steve Block791712a2010-08-27 10:21:07 +0100355 return FixedArray::cast(HeapObject::FromAddress(
356 elms->address() + to_trim * kPointerSize));
Steve Block6ded16b2010-05-10 14:33:55 +0100357}
358
359
Kristian Monsen25f61362010-05-21 11:50:48 +0100360static bool ArrayPrototypeHasNoElements(Context* global_context,
361 JSObject* array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100362 // This method depends on non writability of Object and Array prototype
363 // fields.
Kristian Monsen25f61362010-05-21 11:50:48 +0100364 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
Steve Block6ded16b2010-05-10 14:33:55 +0100365 // Hidden prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100366 array_proto = JSObject::cast(array_proto->GetPrototype());
367 ASSERT(array_proto->elements() == Heap::empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +0100368 // Object.prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100369 array_proto = JSObject::cast(array_proto->GetPrototype());
370 if (array_proto != global_context->initial_object_prototype()) return false;
371 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
372 ASSERT(array_proto->GetPrototype()->IsNull());
Steve Block6ded16b2010-05-10 14:33:55 +0100373 return true;
374}
375
376
John Reck59135872010-11-02 12:39:01 -0700377MUST_USE_RESULT
378static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
379 Object* receiver) {
Iain Merrick75681382010-08-19 15:07:18 +0100380 if (!receiver->IsJSArray()) return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100381 JSArray* array = JSArray::cast(receiver);
Steve Block6ded16b2010-05-10 14:33:55 +0100382 HeapObject* elms = HeapObject::cast(array->elements());
Iain Merrick75681382010-08-19 15:07:18 +0100383 if (elms->map() == Heap::fixed_array_map()) return elms;
384 if (elms->map() == Heap::fixed_cow_array_map()) {
385 return array->EnsureWritableFastElements();
Steve Block6ded16b2010-05-10 14:33:55 +0100386 }
Iain Merrick75681382010-08-19 15:07:18 +0100387 return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100388}
389
390
Iain Merrick75681382010-08-19 15:07:18 +0100391static inline bool IsJSArrayFastElementMovingAllowed(JSArray* receiver) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100392 Context* global_context = Top::context()->global_context();
393 JSObject* array_proto =
394 JSObject::cast(global_context->array_function()->prototype());
Iain Merrick75681382010-08-19 15:07:18 +0100395 return receiver->GetPrototype() == array_proto &&
396 ArrayPrototypeHasNoElements(global_context, array_proto);
Kristian Monsen25f61362010-05-21 11:50:48 +0100397}
398
399
John Reck59135872010-11-02 12:39:01 -0700400MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
401 const char* name,
402 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Block6ded16b2010-05-10 14:33:55 +0100403 HandleScope handleScope;
404
405 Handle<Object> js_builtin =
406 GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
407 name);
408 ASSERT(js_builtin->IsJSFunction());
409 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
Kristian Monsen25f61362010-05-21 11:50:48 +0100410 ScopedVector<Object**> argv(args.length() - 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100411 int n_args = args.length() - 1;
412 for (int i = 0; i < n_args; i++) {
413 argv[i] = args.at<Object>(i + 1).location();
414 }
415 bool pending_exception = false;
416 Handle<Object> result = Execution::Call(function,
417 args.receiver(),
418 n_args,
419 argv.start(),
420 &pending_exception);
Steve Block6ded16b2010-05-10 14:33:55 +0100421 if (pending_exception) return Failure::Exception();
422 return *result;
423}
424
425
Steve Blocka7e24c12009-10-30 11:49:00 +0000426BUILTIN(ArrayPush) {
Steve Block6ded16b2010-05-10 14:33:55 +0100427 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700428 Object* elms_obj;
429 { MaybeObject* maybe_elms_obj =
430 EnsureJSArrayWithWritableFastElements(receiver);
431 if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayPush", args);
432 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
433 }
Iain Merrick75681382010-08-19 15:07:18 +0100434 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100435 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000436
Steve Blocka7e24c12009-10-30 11:49:00 +0000437 int len = Smi::cast(array->length())->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000438 int to_add = args.length() - 1;
439 if (to_add == 0) {
440 return Smi::FromInt(len);
441 }
442 // Currently fixed arrays cannot grow too big, so
443 // we should never hit this case.
444 ASSERT(to_add <= (Smi::kMaxValue - len));
Steve Blocka7e24c12009-10-30 11:49:00 +0000445
Andrei Popescu402d9372010-02-26 13:31:12 +0000446 int new_length = len + to_add;
Steve Blocka7e24c12009-10-30 11:49:00 +0000447
Andrei Popescu402d9372010-02-26 13:31:12 +0000448 if (new_length > elms->length()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000449 // New backing storage is needed.
450 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700451 Object* obj;
452 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(capacity);
453 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
454 }
Steve Block6ded16b2010-05-10 14:33:55 +0100455 FixedArray* new_elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000456
457 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100458 if (len > 0) {
459 CopyElements(&no_gc, new_elms, 0, elms, 0, len);
460 }
461 FillWithHoles(new_elms, new_length, capacity);
462
Andrei Popescu402d9372010-02-26 13:31:12 +0000463 elms = new_elms;
464 array->set_elements(elms);
Steve Blocka7e24c12009-10-30 11:49:00 +0000465 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000466
Steve Block6ded16b2010-05-10 14:33:55 +0100467 // Add the provided values.
Andrei Popescu402d9372010-02-26 13:31:12 +0000468 AssertNoAllocation no_gc;
469 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Andrei Popescu402d9372010-02-26 13:31:12 +0000470 for (int index = 0; index < to_add; index++) {
471 elms->set(index + len, args[index + 1], mode);
472 }
473
Steve Blocka7e24c12009-10-30 11:49:00 +0000474 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000475 array->set_length(Smi::FromInt(new_length));
Andrei Popescu402d9372010-02-26 13:31:12 +0000476 return Smi::FromInt(new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000477}
Steve Blocka7e24c12009-10-30 11:49:00 +0000478
479
480BUILTIN(ArrayPop) {
Steve Block6ded16b2010-05-10 14:33:55 +0100481 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700482 Object* elms_obj;
483 { MaybeObject* maybe_elms_obj =
484 EnsureJSArrayWithWritableFastElements(receiver);
485 if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayPop", args);
486 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
487 }
Iain Merrick75681382010-08-19 15:07:18 +0100488 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100489 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000490
491 int len = Smi::cast(array->length())->value();
Steve Block6ded16b2010-05-10 14:33:55 +0100492 if (len == 0) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000493
494 // Get top element
John Reck59135872010-11-02 12:39:01 -0700495 MaybeObject* top = elms->get(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000496
497 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000498 array->set_length(Smi::FromInt(len - 1));
Steve Blocka7e24c12009-10-30 11:49:00 +0000499
500 if (!top->IsTheHole()) {
501 // Delete the top element.
502 elms->set_the_hole(len - 1);
503 return top;
504 }
505
Kristian Monsen25f61362010-05-21 11:50:48 +0100506 top = array->GetPrototype()->GetElement(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000507
508 return top;
509}
Steve Blocka7e24c12009-10-30 11:49:00 +0000510
511
Andrei Popescu402d9372010-02-26 13:31:12 +0000512BUILTIN(ArrayShift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100513 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700514 Object* elms_obj;
515 { MaybeObject* maybe_elms_obj =
516 EnsureJSArrayWithWritableFastElements(receiver);
517 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
518 }
Iain Merrick75681382010-08-19 15:07:18 +0100519 if (elms_obj == NULL ||
520 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100521 return CallJsBuiltin("ArrayShift", args);
522 }
Iain Merrick75681382010-08-19 15:07:18 +0100523 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100524 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000525 ASSERT(array->HasFastElements());
526
527 int len = Smi::cast(array->length())->value();
528 if (len == 0) return Heap::undefined_value();
529
Andrei Popescu402d9372010-02-26 13:31:12 +0000530 // Get first element
531 Object* first = elms->get(0);
532 if (first->IsTheHole()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100533 first = Heap::undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000534 }
535
Steve Block791712a2010-08-27 10:21:07 +0100536 if (!Heap::lo_space()->Contains(elms)) {
537 // As elms still in the same space they used to be,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100538 // there is no need to update region dirty mark.
Steve Block6ded16b2010-05-10 14:33:55 +0100539 array->set_elements(LeftTrimFixedArray(elms, 1), SKIP_WRITE_BARRIER);
540 } else {
541 // Shift the elements.
542 AssertNoAllocation no_gc;
543 MoveElements(&no_gc, elms, 0, elms, 1, len - 1);
544 elms->set(len - 1, Heap::the_hole_value());
Andrei Popescu402d9372010-02-26 13:31:12 +0000545 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000546
547 // Set the length.
548 array->set_length(Smi::FromInt(len - 1));
549
550 return first;
551}
552
553
554BUILTIN(ArrayUnshift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100555 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700556 Object* elms_obj;
557 { MaybeObject* maybe_elms_obj =
558 EnsureJSArrayWithWritableFastElements(receiver);
559 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
560 }
Iain Merrick75681382010-08-19 15:07:18 +0100561 if (elms_obj == NULL ||
562 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100563 return CallJsBuiltin("ArrayUnshift", args);
564 }
Iain Merrick75681382010-08-19 15:07:18 +0100565 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100566 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000567 ASSERT(array->HasFastElements());
568
569 int len = Smi::cast(array->length())->value();
570 int to_add = args.length() - 1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000571 int new_length = len + to_add;
572 // Currently fixed arrays cannot grow too big, so
573 // we should never hit this case.
574 ASSERT(to_add <= (Smi::kMaxValue - len));
575
Andrei Popescu402d9372010-02-26 13:31:12 +0000576 if (new_length > elms->length()) {
577 // New backing storage is needed.
578 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700579 Object* obj;
580 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(capacity);
581 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
582 }
Steve Block6ded16b2010-05-10 14:33:55 +0100583 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000584
585 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100586 if (len > 0) {
587 CopyElements(&no_gc, new_elms, to_add, elms, 0, len);
588 }
589 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000590
591 elms = new_elms;
592 array->set_elements(elms);
593 } else {
594 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100595 MoveElements(&no_gc, elms, to_add, elms, 0, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000596 }
597
598 // Add the provided values.
599 AssertNoAllocation no_gc;
600 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
601 for (int i = 0; i < to_add; i++) {
602 elms->set(i, args[i + 1], mode);
603 }
604
605 // Set the length.
606 array->set_length(Smi::FromInt(new_length));
607 return Smi::FromInt(new_length);
608}
609
610
Andrei Popescu402d9372010-02-26 13:31:12 +0000611BUILTIN(ArraySlice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100612 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700613 Object* elms_obj;
614 { MaybeObject* maybe_elms_obj =
615 EnsureJSArrayWithWritableFastElements(receiver);
616 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
617 }
Iain Merrick75681382010-08-19 15:07:18 +0100618 if (elms_obj == NULL ||
619 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100620 return CallJsBuiltin("ArraySlice", args);
621 }
Iain Merrick75681382010-08-19 15:07:18 +0100622 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100623 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000624 ASSERT(array->HasFastElements());
625
626 int len = Smi::cast(array->length())->value();
627
628 int n_arguments = args.length() - 1;
629
630 // Note carefully choosen defaults---if argument is missing,
Steve Block6ded16b2010-05-10 14:33:55 +0100631 // it's undefined which gets converted to 0 for relative_start
632 // and to len for relative_end.
633 int relative_start = 0;
634 int relative_end = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000635 if (n_arguments > 0) {
636 Object* arg1 = args[1];
637 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100638 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000639 } else if (!arg1->IsUndefined()) {
640 return CallJsBuiltin("ArraySlice", args);
641 }
642 if (n_arguments > 1) {
643 Object* arg2 = args[2];
644 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100645 relative_end = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000646 } else if (!arg2->IsUndefined()) {
647 return CallJsBuiltin("ArraySlice", args);
648 }
649 }
650 }
651
652 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
Steve Block6ded16b2010-05-10 14:33:55 +0100653 int k = (relative_start < 0) ? Max(len + relative_start, 0)
654 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000655
656 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
Steve Block6ded16b2010-05-10 14:33:55 +0100657 int final = (relative_end < 0) ? Max(len + relative_end, 0)
658 : Min(relative_end, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000659
660 // Calculate the length of result array.
661 int result_len = final - k;
Steve Block6ded16b2010-05-10 14:33:55 +0100662 if (result_len <= 0) {
663 return AllocateEmptyJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000664 }
665
John Reck59135872010-11-02 12:39:01 -0700666 Object* result;
667 { MaybeObject* maybe_result = AllocateJSArray();
668 if (!maybe_result->ToObject(&result)) return maybe_result;
669 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000670 JSArray* result_array = JSArray::cast(result);
671
John Reck59135872010-11-02 12:39:01 -0700672 { MaybeObject* maybe_result =
673 Heap::AllocateUninitializedFixedArray(result_len);
674 if (!maybe_result->ToObject(&result)) return maybe_result;
675 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000676 FixedArray* result_elms = FixedArray::cast(result);
677
Andrei Popescu402d9372010-02-26 13:31:12 +0000678 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100679 CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000680
681 // Set elements.
682 result_array->set_elements(result_elms);
683
684 // Set the length.
685 result_array->set_length(Smi::FromInt(result_len));
686 return result_array;
687}
688
689
690BUILTIN(ArraySplice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100691 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700692 Object* elms_obj;
693 { MaybeObject* maybe_elms_obj =
694 EnsureJSArrayWithWritableFastElements(receiver);
695 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
696 }
Iain Merrick75681382010-08-19 15:07:18 +0100697 if (elms_obj == NULL ||
698 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100699 return CallJsBuiltin("ArraySplice", args);
700 }
Iain Merrick75681382010-08-19 15:07:18 +0100701 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100702 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000703 ASSERT(array->HasFastElements());
704
705 int len = Smi::cast(array->length())->value();
706
707 int n_arguments = args.length() - 1;
708
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100709 // Return empty array when no arguments are supplied.
Andrei Popescu402d9372010-02-26 13:31:12 +0000710 if (n_arguments == 0) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100711 return AllocateEmptyJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000712 }
713
Steve Block6ded16b2010-05-10 14:33:55 +0100714 int relative_start = 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000715 Object* arg1 = args[1];
716 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100717 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000718 } else if (!arg1->IsUndefined()) {
719 return CallJsBuiltin("ArraySplice", args);
720 }
Steve Block6ded16b2010-05-10 14:33:55 +0100721 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
722 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000723
724 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
725 // given differently from when an undefined delete count is given.
726 // This does not follow ECMA-262, but we do the same for
727 // compatibility.
Steve Block6ded16b2010-05-10 14:33:55 +0100728 int delete_count = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000729 if (n_arguments > 1) {
730 Object* arg2 = args[2];
731 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100732 delete_count = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000733 } else {
734 return CallJsBuiltin("ArraySplice", args);
735 }
736 }
Steve Block6ded16b2010-05-10 14:33:55 +0100737 int actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000738
Steve Block6ded16b2010-05-10 14:33:55 +0100739 JSArray* result_array = NULL;
740 if (actual_delete_count == 0) {
John Reck59135872010-11-02 12:39:01 -0700741 Object* result;
742 { MaybeObject* maybe_result = AllocateEmptyJSArray();
743 if (!maybe_result->ToObject(&result)) return maybe_result;
744 }
Steve Block6ded16b2010-05-10 14:33:55 +0100745 result_array = JSArray::cast(result);
746 } else {
747 // Allocate result array.
John Reck59135872010-11-02 12:39:01 -0700748 Object* result;
749 { MaybeObject* maybe_result = AllocateJSArray();
750 if (!maybe_result->ToObject(&result)) return maybe_result;
751 }
Steve Block6ded16b2010-05-10 14:33:55 +0100752 result_array = JSArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000753
John Reck59135872010-11-02 12:39:01 -0700754 { MaybeObject* maybe_result =
755 Heap::AllocateUninitializedFixedArray(actual_delete_count);
756 if (!maybe_result->ToObject(&result)) return maybe_result;
757 }
Steve Block6ded16b2010-05-10 14:33:55 +0100758 FixedArray* result_elms = FixedArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000759
Steve Block6ded16b2010-05-10 14:33:55 +0100760 AssertNoAllocation no_gc;
761 // Fill newly created array.
762 CopyElements(&no_gc,
763 result_elms, 0,
764 elms, actual_start,
765 actual_delete_count);
Andrei Popescu402d9372010-02-26 13:31:12 +0000766
Steve Block6ded16b2010-05-10 14:33:55 +0100767 // Set elements.
768 result_array->set_elements(result_elms);
Andrei Popescu402d9372010-02-26 13:31:12 +0000769
Steve Block6ded16b2010-05-10 14:33:55 +0100770 // Set the length.
771 result_array->set_length(Smi::FromInt(actual_delete_count));
Andrei Popescu402d9372010-02-26 13:31:12 +0000772 }
773
Steve Block6ded16b2010-05-10 14:33:55 +0100774 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000775
Steve Block6ded16b2010-05-10 14:33:55 +0100776 int new_length = len - actual_delete_count + item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000777
Steve Block6ded16b2010-05-10 14:33:55 +0100778 if (item_count < actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000779 // Shrink the array.
Steve Block791712a2010-08-27 10:21:07 +0100780 const bool trim_array = !Heap::lo_space()->Contains(elms) &&
Steve Block6ded16b2010-05-10 14:33:55 +0100781 ((actual_start + item_count) <
782 (len - actual_delete_count - actual_start));
783 if (trim_array) {
784 const int delta = actual_delete_count - item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000785
Steve Block6ded16b2010-05-10 14:33:55 +0100786 if (actual_start > 0) {
787 Object** start = elms->data_start();
788 memmove(start + delta, start, actual_start * kPointerSize);
789 }
790
791 elms = LeftTrimFixedArray(elms, delta);
792 array->set_elements(elms, SKIP_WRITE_BARRIER);
793 } else {
794 AssertNoAllocation no_gc;
795 MoveElements(&no_gc,
796 elms, actual_start + item_count,
797 elms, actual_start + actual_delete_count,
798 (len - actual_delete_count - actual_start));
799 FillWithHoles(elms, new_length, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000800 }
Steve Block6ded16b2010-05-10 14:33:55 +0100801 } else if (item_count > actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000802 // Currently fixed arrays cannot grow too big, so
803 // we should never hit this case.
Steve Block6ded16b2010-05-10 14:33:55 +0100804 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
Andrei Popescu402d9372010-02-26 13:31:12 +0000805
806 // Check if array need to grow.
807 if (new_length > elms->length()) {
808 // New backing storage is needed.
809 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700810 Object* obj;
811 { MaybeObject* maybe_obj =
812 Heap::AllocateUninitializedFixedArray(capacity);
813 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
814 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000815 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000816
Steve Block6ded16b2010-05-10 14:33:55 +0100817 AssertNoAllocation no_gc;
818 // Copy the part before actual_start as is.
819 if (actual_start > 0) {
820 CopyElements(&no_gc, new_elms, 0, elms, 0, actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000821 }
Steve Block6ded16b2010-05-10 14:33:55 +0100822 const int to_copy = len - actual_delete_count - actual_start;
823 if (to_copy > 0) {
824 CopyElements(&no_gc,
825 new_elms, actual_start + item_count,
826 elms, actual_start + actual_delete_count,
827 to_copy);
828 }
829 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000830
Andrei Popescu402d9372010-02-26 13:31:12 +0000831 elms = new_elms;
832 array->set_elements(elms);
Steve Block6ded16b2010-05-10 14:33:55 +0100833 } else {
834 AssertNoAllocation no_gc;
835 MoveElements(&no_gc,
836 elms, actual_start + item_count,
837 elms, actual_start + actual_delete_count,
838 (len - actual_delete_count - actual_start));
Andrei Popescu402d9372010-02-26 13:31:12 +0000839 }
840 }
841
Steve Block6ded16b2010-05-10 14:33:55 +0100842 AssertNoAllocation no_gc;
843 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
844 for (int k = actual_start; k < actual_start + item_count; k++) {
845 elms->set(k, args[3 + k - actual_start], mode);
Andrei Popescu402d9372010-02-26 13:31:12 +0000846 }
847
848 // Set the length.
849 array->set_length(Smi::FromInt(new_length));
850
851 return result_array;
852}
853
854
Steve Block6ded16b2010-05-10 14:33:55 +0100855BUILTIN(ArrayConcat) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100856 Context* global_context = Top::context()->global_context();
857 JSObject* array_proto =
858 JSObject::cast(global_context->array_function()->prototype());
859 if (!ArrayPrototypeHasNoElements(global_context, array_proto)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100860 return CallJsBuiltin("ArrayConcat", args);
861 }
862
863 // Iterate through all the arguments performing checks
864 // and calculating total length.
865 int n_arguments = args.length();
866 int result_len = 0;
867 for (int i = 0; i < n_arguments; i++) {
868 Object* arg = args[i];
Kristian Monsen25f61362010-05-21 11:50:48 +0100869 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
870 || JSArray::cast(arg)->GetPrototype() != array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100871 return CallJsBuiltin("ArrayConcat", args);
872 }
873
874 int len = Smi::cast(JSArray::cast(arg)->length())->value();
875
876 // We shouldn't overflow when adding another len.
877 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
878 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
879 USE(kHalfOfMaxInt);
880 result_len += len;
881 ASSERT(result_len >= 0);
882
883 if (result_len > FixedArray::kMaxLength) {
884 return CallJsBuiltin("ArrayConcat", args);
885 }
886 }
887
888 if (result_len == 0) {
889 return AllocateEmptyJSArray();
890 }
891
892 // Allocate result.
John Reck59135872010-11-02 12:39:01 -0700893 Object* result;
894 { MaybeObject* maybe_result = AllocateJSArray();
895 if (!maybe_result->ToObject(&result)) return maybe_result;
896 }
Steve Block6ded16b2010-05-10 14:33:55 +0100897 JSArray* result_array = JSArray::cast(result);
898
John Reck59135872010-11-02 12:39:01 -0700899 { MaybeObject* maybe_result =
900 Heap::AllocateUninitializedFixedArray(result_len);
901 if (!maybe_result->ToObject(&result)) return maybe_result;
902 }
Steve Block6ded16b2010-05-10 14:33:55 +0100903 FixedArray* result_elms = FixedArray::cast(result);
904
905 // Copy data.
906 AssertNoAllocation no_gc;
907 int start_pos = 0;
908 for (int i = 0; i < n_arguments; i++) {
909 JSArray* array = JSArray::cast(args[i]);
910 int len = Smi::cast(array->length())->value();
911 if (len > 0) {
912 FixedArray* elms = FixedArray::cast(array->elements());
913 CopyElements(&no_gc, result_elms, start_pos, elms, 0, len);
914 start_pos += len;
915 }
916 }
917 ASSERT(start_pos == result_len);
918
919 // Set the length and elements.
920 result_array->set_length(Smi::FromInt(result_len));
921 result_array->set_elements(result_elms);
922
923 return result_array;
924}
925
926
Steve Blocka7e24c12009-10-30 11:49:00 +0000927// -----------------------------------------------------------------------------
928//
929
930
931// Returns the holder JSObject if the function can legally be called
932// with this receiver. Returns Heap::null_value() if the call is
933// illegal. Any arguments that don't fit the expected type is
934// overwritten with undefined. Arguments that do fit the expected
935// type is overwritten with the object in the prototype chain that
936// actually has that type.
937static inline Object* TypeCheck(int argc,
938 Object** argv,
939 FunctionTemplateInfo* info) {
940 Object* recv = argv[0];
941 Object* sig_obj = info->signature();
942 if (sig_obj->IsUndefined()) return recv;
943 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
944 // If necessary, check the receiver
945 Object* recv_type = sig->receiver();
946
947 Object* holder = recv;
948 if (!recv_type->IsUndefined()) {
949 for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
950 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
951 break;
952 }
953 }
954 if (holder == Heap::null_value()) return holder;
955 }
956 Object* args_obj = sig->args();
957 // If there is no argument signature we're done
958 if (args_obj->IsUndefined()) return holder;
959 FixedArray* args = FixedArray::cast(args_obj);
960 int length = args->length();
961 if (argc <= length) length = argc - 1;
962 for (int i = 0; i < length; i++) {
963 Object* argtype = args->get(i);
964 if (argtype->IsUndefined()) continue;
965 Object** arg = &argv[-1 - i];
966 Object* current = *arg;
967 for (; current != Heap::null_value(); current = current->GetPrototype()) {
968 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
969 *arg = current;
970 break;
971 }
972 }
973 if (current == Heap::null_value()) *arg = Heap::undefined_value();
974 }
975 return holder;
976}
977
978
Leon Clarkee46be812010-01-19 14:06:41 +0000979template <bool is_construct>
John Reck59135872010-11-02 12:39:01 -0700980MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
Leon Clarkee46be812010-01-19 14:06:41 +0000981 BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
982 ASSERT(is_construct == CalledAsConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +0000983
Leon Clarkee46be812010-01-19 14:06:41 +0000984 HandleScope scope;
985 Handle<JSFunction> function = args.called_function();
Steve Block6ded16b2010-05-10 14:33:55 +0100986 ASSERT(function->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +0000987
Steve Block6ded16b2010-05-10 14:33:55 +0100988 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
Steve Blocka7e24c12009-10-30 11:49:00 +0000989 if (is_construct) {
Steve Block6ded16b2010-05-10 14:33:55 +0100990 Handle<FunctionTemplateInfo> desc(fun_data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000991 bool pending_exception = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000992 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000993 &pending_exception);
994 ASSERT(Top::has_pending_exception() == pending_exception);
995 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +0100996 fun_data = *desc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000997 }
998
Steve Blocka7e24c12009-10-30 11:49:00 +0000999 Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
1000
1001 if (raw_holder->IsNull()) {
1002 // This function cannot be called with the given receiver. Abort!
1003 Handle<Object> obj =
1004 Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
1005 return Top::Throw(*obj);
1006 }
1007
1008 Object* raw_call_data = fun_data->call_code();
1009 if (!raw_call_data->IsUndefined()) {
1010 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1011 Object* callback_obj = call_data->callback();
1012 v8::InvocationCallback callback =
1013 v8::ToCData<v8::InvocationCallback>(callback_obj);
1014 Object* data_obj = call_data->data();
1015 Object* result;
1016
Leon Clarkee46be812010-01-19 14:06:41 +00001017 LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001018 ASSERT(raw_holder->IsJSObject());
1019
1020 CustomArguments custom;
1021 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1022 data_obj, *function, raw_holder);
1023
Steve Blocka7e24c12009-10-30 11:49:00 +00001024 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001025 custom.end(),
1026 &args[0] - 1,
1027 args.length() - 1,
1028 is_construct);
Steve Blocka7e24c12009-10-30 11:49:00 +00001029
1030 v8::Handle<v8::Value> value;
1031 {
1032 // Leaving JavaScript.
1033 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +00001034#ifdef ENABLE_LOGGING_AND_PROFILING
1035 state.set_external_callback(v8::ToCData<Address>(callback_obj));
1036#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001037 value = callback(new_args);
1038 }
1039 if (value.IsEmpty()) {
1040 result = Heap::undefined_value();
1041 } else {
1042 result = *reinterpret_cast<Object**>(*value);
1043 }
1044
1045 RETURN_IF_SCHEDULED_EXCEPTION();
1046 if (!is_construct || result->IsJSObject()) return result;
1047 }
1048
Leon Clarkee46be812010-01-19 14:06:41 +00001049 return *args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +00001050}
Leon Clarkee46be812010-01-19 14:06:41 +00001051
1052
1053BUILTIN(HandleApiCall) {
1054 return HandleApiCallHelper<false>(args);
1055}
1056
1057
1058BUILTIN(HandleApiCallConstruct) {
1059 return HandleApiCallHelper<true>(args);
1060}
Steve Blocka7e24c12009-10-30 11:49:00 +00001061
1062
Andrei Popescu402d9372010-02-26 13:31:12 +00001063#ifdef DEBUG
1064
1065static void VerifyTypeCheck(Handle<JSObject> object,
1066 Handle<JSFunction> function) {
Steve Block6ded16b2010-05-10 14:33:55 +01001067 ASSERT(function->shared()->IsApiFunction());
1068 FunctionTemplateInfo* info = function->shared()->get_api_func_data();
Andrei Popescu402d9372010-02-26 13:31:12 +00001069 if (info->signature()->IsUndefined()) return;
1070 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1071 Object* receiver_type = signature->receiver();
1072 if (receiver_type->IsUndefined()) return;
1073 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
1074 ASSERT(object->IsInstanceOf(type));
1075}
1076
1077#endif
1078
1079
1080BUILTIN(FastHandleApiCall) {
1081 ASSERT(!CalledAsConstructor());
1082 const bool is_construct = false;
1083
1084 // We expect four more arguments: function, callback, call data, and holder.
1085 const int args_length = args.length() - 4;
1086 ASSERT(args_length >= 0);
1087
1088 Handle<JSFunction> function = args.at<JSFunction>(args_length);
1089 Object* callback_obj = args[args_length + 1];
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001090 Handle<Object> data = args.at<Object>(args_length + 2);
Andrei Popescu402d9372010-02-26 13:31:12 +00001091 Handle<JSObject> checked_holder = args.at<JSObject>(args_length + 3);
1092
1093#ifdef DEBUG
1094 VerifyTypeCheck(checked_holder, function);
1095#endif
1096
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001097 CustomArguments custom;
1098 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1099 *data, *function, *checked_holder);
Andrei Popescu402d9372010-02-26 13:31:12 +00001100
1101 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001102 custom.end(),
1103 &args[0] - 1,
1104 args_length - 1,
1105 is_construct);
Andrei Popescu402d9372010-02-26 13:31:12 +00001106
1107 HandleScope scope;
1108 Object* result;
1109 v8::Handle<v8::Value> value;
1110 {
1111 // Leaving JavaScript.
1112 VMState state(EXTERNAL);
1113#ifdef ENABLE_LOGGING_AND_PROFILING
1114 state.set_external_callback(v8::ToCData<Address>(callback_obj));
1115#endif
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001116 v8::InvocationCallback callback =
1117 v8::ToCData<v8::InvocationCallback>(callback_obj);
1118
Andrei Popescu402d9372010-02-26 13:31:12 +00001119 value = callback(new_args);
1120 }
1121 if (value.IsEmpty()) {
1122 result = Heap::undefined_value();
1123 } else {
1124 result = *reinterpret_cast<Object**>(*value);
1125 }
1126
1127 RETURN_IF_SCHEDULED_EXCEPTION();
1128 return result;
1129}
1130
1131
Steve Blocka7e24c12009-10-30 11:49:00 +00001132// Helper function to handle calls to non-function objects created through the
1133// API. The object can be called as either a constructor (using new) or just as
1134// a function (without new).
John Reck59135872010-11-02 12:39:01 -07001135MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
Leon Clarkee46be812010-01-19 14:06:41 +00001136 bool is_construct_call,
1137 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001138 // Non-functions are never called as constructors. Even if this is an object
1139 // called as a constructor the delegate call is not a construct call.
1140 ASSERT(!CalledAsConstructor());
1141
1142 Handle<Object> receiver = args.at<Object>(0);
1143
1144 // Get the object called.
Leon Clarkee46be812010-01-19 14:06:41 +00001145 JSObject* obj = JSObject::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +00001146
1147 // Get the invocation callback from the function descriptor that was
1148 // used to create the called object.
1149 ASSERT(obj->map()->has_instance_call_handler());
1150 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01001151 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001152 Object* handler =
Steve Block6ded16b2010-05-10 14:33:55 +01001153 constructor->shared()->get_api_func_data()->instance_call_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00001154 ASSERT(!handler->IsUndefined());
1155 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1156 Object* callback_obj = call_data->callback();
1157 v8::InvocationCallback callback =
1158 v8::ToCData<v8::InvocationCallback>(callback_obj);
1159
1160 // Get the data for the call and perform the callback.
Steve Blocka7e24c12009-10-30 11:49:00 +00001161 Object* result;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001162 {
1163 HandleScope scope;
1164
1165 LOG(ApiObjectAccess("call non-function", obj));
1166
1167 CustomArguments custom;
1168 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1169 call_data->data(), constructor, obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00001170 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001171 custom.end(),
1172 &args[0] - 1,
1173 args.length() - 1,
1174 is_construct_call);
Steve Blocka7e24c12009-10-30 11:49:00 +00001175 v8::Handle<v8::Value> value;
1176 {
1177 // Leaving JavaScript.
1178 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +00001179#ifdef ENABLE_LOGGING_AND_PROFILING
1180 state.set_external_callback(v8::ToCData<Address>(callback_obj));
1181#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001182 value = callback(new_args);
1183 }
1184 if (value.IsEmpty()) {
1185 result = Heap::undefined_value();
1186 } else {
1187 result = *reinterpret_cast<Object**>(*value);
1188 }
1189 }
1190 // Check for exceptions and return result.
1191 RETURN_IF_SCHEDULED_EXCEPTION();
1192 return result;
1193}
1194
1195
1196// Handle calls to non-function objects created through the API. This delegate
1197// function is used when the call is a normal function call.
1198BUILTIN(HandleApiCallAsFunction) {
1199 return HandleApiCallAsFunctionOrConstructor(false, args);
1200}
Steve Blocka7e24c12009-10-30 11:49:00 +00001201
1202
1203// Handle calls to non-function objects created through the API. This delegate
1204// function is used when the call is a construct call.
1205BUILTIN(HandleApiCallAsConstructor) {
1206 return HandleApiCallAsFunctionOrConstructor(true, args);
1207}
Steve Blocka7e24c12009-10-30 11:49:00 +00001208
1209
1210static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1211 LoadIC::GenerateArrayLength(masm);
1212}
1213
1214
1215static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
1216 LoadIC::GenerateStringLength(masm);
1217}
1218
1219
1220static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1221 LoadIC::GenerateFunctionPrototype(masm);
1222}
1223
1224
1225static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1226 LoadIC::GenerateInitialize(masm);
1227}
1228
1229
1230static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1231 LoadIC::GeneratePreMonomorphic(masm);
1232}
1233
1234
1235static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1236 LoadIC::GenerateMiss(masm);
1237}
1238
1239
1240static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1241 LoadIC::GenerateMegamorphic(masm);
1242}
1243
1244
1245static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1246 LoadIC::GenerateNormal(masm);
1247}
1248
1249
1250static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1251 KeyedLoadIC::GenerateInitialize(masm);
1252}
1253
1254
1255static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1256 KeyedLoadIC::GenerateMiss(masm);
1257}
1258
1259
1260static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1261 KeyedLoadIC::GenerateGeneric(masm);
1262}
1263
1264
Leon Clarkee46be812010-01-19 14:06:41 +00001265static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1266 KeyedLoadIC::GenerateString(masm);
1267}
1268
1269
Steve Block3ce2e202009-11-05 08:53:23 +00001270static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
1271 KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
1272}
1273
1274
1275static void Generate_KeyedLoadIC_ExternalUnsignedByteArray(
1276 MacroAssembler* masm) {
1277 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1278}
1279
1280
1281static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) {
1282 KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray);
1283}
1284
1285
1286static void Generate_KeyedLoadIC_ExternalUnsignedShortArray(
1287 MacroAssembler* masm) {
1288 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1289}
1290
1291
1292static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) {
1293 KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray);
1294}
1295
1296
1297static void Generate_KeyedLoadIC_ExternalUnsignedIntArray(
1298 MacroAssembler* masm) {
1299 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1300}
1301
1302
1303static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) {
1304 KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray);
1305}
1306
1307
Steve Blocka7e24c12009-10-30 11:49:00 +00001308static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1309 KeyedLoadIC::GeneratePreMonomorphic(masm);
1310}
1311
Andrei Popescu402d9372010-02-26 13:31:12 +00001312static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1313 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1314}
1315
Steve Blocka7e24c12009-10-30 11:49:00 +00001316
1317static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1318 StoreIC::GenerateInitialize(masm);
1319}
1320
1321
1322static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1323 StoreIC::GenerateMiss(masm);
1324}
1325
1326
Steve Block8defd9f2010-07-08 12:39:36 +01001327static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1328 StoreIC::GenerateNormal(masm);
1329}
1330
1331
Steve Blocka7e24c12009-10-30 11:49:00 +00001332static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
1333 StoreIC::GenerateMegamorphic(masm);
1334}
1335
1336
Steve Block6ded16b2010-05-10 14:33:55 +01001337static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1338 StoreIC::GenerateArrayLength(masm);
1339}
1340
1341
Steve Blocka7e24c12009-10-30 11:49:00 +00001342static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
1343 KeyedStoreIC::GenerateGeneric(masm);
1344}
1345
1346
Steve Block3ce2e202009-11-05 08:53:23 +00001347static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) {
1348 KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray);
1349}
1350
1351
1352static void Generate_KeyedStoreIC_ExternalUnsignedByteArray(
1353 MacroAssembler* masm) {
1354 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1355}
1356
1357
1358static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) {
1359 KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray);
1360}
1361
1362
1363static void Generate_KeyedStoreIC_ExternalUnsignedShortArray(
1364 MacroAssembler* masm) {
1365 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1366}
1367
1368
1369static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) {
1370 KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray);
1371}
1372
1373
1374static void Generate_KeyedStoreIC_ExternalUnsignedIntArray(
1375 MacroAssembler* masm) {
1376 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1377}
1378
1379
1380static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) {
1381 KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray);
1382}
1383
1384
Steve Blocka7e24c12009-10-30 11:49:00 +00001385static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1386 KeyedStoreIC::GenerateMiss(masm);
1387}
1388
1389
1390static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1391 KeyedStoreIC::GenerateInitialize(masm);
1392}
1393
1394
1395#ifdef ENABLE_DEBUGGER_SUPPORT
1396static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1397 Debug::GenerateLoadICDebugBreak(masm);
1398}
1399
1400
1401static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1402 Debug::GenerateStoreICDebugBreak(masm);
1403}
1404
1405
1406static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1407 Debug::GenerateKeyedLoadICDebugBreak(masm);
1408}
1409
1410
1411static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1412 Debug::GenerateKeyedStoreICDebugBreak(masm);
1413}
1414
1415
1416static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1417 Debug::GenerateConstructCallDebugBreak(masm);
1418}
1419
1420
1421static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1422 Debug::GenerateReturnDebugBreak(masm);
1423}
1424
1425
1426static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
1427 Debug::GenerateStubNoRegistersDebugBreak(masm);
1428}
Steve Block6ded16b2010-05-10 14:33:55 +01001429
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001430
1431static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1432 Debug::GenerateSlotDebugBreak(masm);
1433}
1434
1435
Steve Block6ded16b2010-05-10 14:33:55 +01001436static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1437 Debug::GeneratePlainReturnLiveEdit(masm);
1438}
1439
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001440
Steve Block6ded16b2010-05-10 14:33:55 +01001441static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1442 Debug::GenerateFrameDropperLiveEdit(masm);
1443}
Steve Blocka7e24c12009-10-30 11:49:00 +00001444#endif
1445
1446Object* Builtins::builtins_[builtin_count] = { NULL, };
1447const char* Builtins::names_[builtin_count] = { NULL, };
1448
Leon Clarkee46be812010-01-19 14:06:41 +00001449#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Steve Blocka7e24c12009-10-30 11:49:00 +00001450 Address Builtins::c_functions_[cfunction_count] = {
1451 BUILTIN_LIST_C(DEF_ENUM_C)
1452 };
1453#undef DEF_ENUM_C
1454
1455#define DEF_JS_NAME(name, ignore) #name,
1456#define DEF_JS_ARGC(ignore, argc) argc,
1457const char* Builtins::javascript_names_[id_count] = {
1458 BUILTINS_LIST_JS(DEF_JS_NAME)
1459};
1460
1461int Builtins::javascript_argc_[id_count] = {
1462 BUILTINS_LIST_JS(DEF_JS_ARGC)
1463};
1464#undef DEF_JS_NAME
1465#undef DEF_JS_ARGC
1466
1467static bool is_initialized = false;
1468void Builtins::Setup(bool create_heap_objects) {
1469 ASSERT(!is_initialized);
1470
1471 // Create a scope for the handles in the builtins.
1472 HandleScope scope;
1473
1474 struct BuiltinDesc {
1475 byte* generator;
1476 byte* c_code;
1477 const char* s_name; // name is only used for generating log information.
1478 int name;
1479 Code::Flags flags;
Leon Clarkee46be812010-01-19 14:06:41 +00001480 BuiltinExtraArguments extra_args;
Steve Blocka7e24c12009-10-30 11:49:00 +00001481 };
1482
Leon Clarkee46be812010-01-19 14:06:41 +00001483#define DEF_FUNCTION_PTR_C(name, extra_args) \
1484 { FUNCTION_ADDR(Generate_Adaptor), \
1485 FUNCTION_ADDR(Builtin_##name), \
1486 #name, \
1487 c_##name, \
1488 Code::ComputeFlags(Code::BUILTIN), \
1489 extra_args \
Steve Blocka7e24c12009-10-30 11:49:00 +00001490 },
1491
1492#define DEF_FUNCTION_PTR_A(name, kind, state) \
1493 { FUNCTION_ADDR(Generate_##name), \
1494 NULL, \
1495 #name, \
1496 name, \
Leon Clarkee46be812010-01-19 14:06:41 +00001497 Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
1498 NO_EXTRA_ARGUMENTS \
Steve Blocka7e24c12009-10-30 11:49:00 +00001499 },
1500
1501 // Define array of pointers to generators and C builtin functions.
1502 static BuiltinDesc functions[] = {
1503 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1504 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1505 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1506 // Terminator:
Leon Clarkee46be812010-01-19 14:06:41 +00001507 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
1508 NO_EXTRA_ARGUMENTS }
Steve Blocka7e24c12009-10-30 11:49:00 +00001509 };
1510
1511#undef DEF_FUNCTION_PTR_C
1512#undef DEF_FUNCTION_PTR_A
1513
1514 // For now we generate builtin adaptor code into a stack-allocated
1515 // buffer, before copying it into individual code objects.
1516 byte buffer[4*KB];
1517
1518 // Traverse the list of builtins and generate an adaptor in a
1519 // separate code object for each one.
1520 for (int i = 0; i < builtin_count; i++) {
1521 if (create_heap_objects) {
1522 MacroAssembler masm(buffer, sizeof buffer);
1523 // Generate the code/adaptor.
Leon Clarkee46be812010-01-19 14:06:41 +00001524 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001525 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1526 // We pass all arguments to the generator, but it may not use all of
1527 // them. This works because the first arguments are on top of the
1528 // stack.
Leon Clarkee46be812010-01-19 14:06:41 +00001529 g(&masm, functions[i].name, functions[i].extra_args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001530 // Move the code into the object heap.
1531 CodeDesc desc;
1532 masm.GetCode(&desc);
1533 Code::Flags flags = functions[i].flags;
John Reck59135872010-11-02 12:39:01 -07001534 Object* code = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001535 {
1536 // During startup it's OK to always allocate and defer GC to later.
1537 // This simplifies things because we don't need to retry.
1538 AlwaysAllocateScope __scope__;
John Reck59135872010-11-02 12:39:01 -07001539 { MaybeObject* maybe_code =
1540 Heap::CreateCode(desc, flags, masm.CodeObject());
1541 if (!maybe_code->ToObject(&code)) {
1542 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1543 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001544 }
1545 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001546 // Log the event and add the code to the builtins array.
Steve Block6ded16b2010-05-10 14:33:55 +01001547 PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
1548 Code::cast(code), functions[i].s_name));
Steve Blocka7e24c12009-10-30 11:49:00 +00001549 builtins_[i] = code;
1550#ifdef ENABLE_DISASSEMBLER
1551 if (FLAG_print_builtin_code) {
1552 PrintF("Builtin: %s\n", functions[i].s_name);
1553 Code::cast(code)->Disassemble(functions[i].s_name);
1554 PrintF("\n");
1555 }
1556#endif
1557 } else {
1558 // Deserializing. The values will be filled in during IterateBuiltins.
1559 builtins_[i] = NULL;
1560 }
1561 names_[i] = functions[i].s_name;
1562 }
1563
1564 // Mark as initialized.
1565 is_initialized = true;
1566}
1567
1568
1569void Builtins::TearDown() {
1570 is_initialized = false;
1571}
1572
1573
1574void Builtins::IterateBuiltins(ObjectVisitor* v) {
1575 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1576}
1577
1578
1579const char* Builtins::Lookup(byte* pc) {
1580 if (is_initialized) { // may be called during initialization (disassembler!)
1581 for (int i = 0; i < builtin_count; i++) {
1582 Code* entry = Code::cast(builtins_[i]);
1583 if (entry->contains(pc)) {
1584 return names_[i];
1585 }
1586 }
1587 }
1588 return NULL;
1589}
1590
Steve Blocka7e24c12009-10-30 11:49:00 +00001591} } // namespace v8::internal