blob: 21381f15d5cb578e49c2594d4cfec3749e366471 [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"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036
37namespace v8 {
38namespace internal {
39
Leon Clarkee46be812010-01-19 14:06:41 +000040namespace {
41
42// Arguments object passed to C++ builtins.
43template <BuiltinExtraArguments extra_args>
44class BuiltinArguments : public Arguments {
45 public:
46 BuiltinArguments(int length, Object** arguments)
47 : Arguments(length, arguments) { }
48
49 Object*& operator[] (int index) {
50 ASSERT(index < length());
51 return Arguments::operator[](index);
52 }
53
54 template <class S> Handle<S> at(int index) {
55 ASSERT(index < length());
56 return Arguments::at<S>(index);
57 }
58
59 Handle<Object> receiver() {
60 return Arguments::at<Object>(0);
61 }
62
63 Handle<JSFunction> called_function() {
64 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
65 return Arguments::at<JSFunction>(Arguments::length() - 1);
66 }
67
68 // Gets the total number of arguments including the receiver (but
69 // excluding extra arguments).
70 int length() const {
71 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
72 return Arguments::length();
73 }
74
75#ifdef DEBUG
76 void Verify() {
77 // Check we have at least the receiver.
78 ASSERT(Arguments::length() >= 1);
79 }
80#endif
81};
82
83
84// Specialize BuiltinArguments for the called function extra argument.
85
86template <>
87int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
88 return Arguments::length() - 1;
89}
90
91#ifdef DEBUG
92template <>
93void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
94 // Check we have at least the receiver and the called function.
95 ASSERT(Arguments::length() >= 2);
96 // Make sure cast to JSFunction succeeds.
97 called_function();
98}
99#endif
100
101
102#define DEF_ARG_TYPE(name, spec) \
103 typedef BuiltinArguments<spec> name##ArgumentsType;
104BUILTIN_LIST_C(DEF_ARG_TYPE)
105#undef DEF_ARG_TYPE
106
107} // namespace
108
109
Steve Blocka7e24c12009-10-30 11:49:00 +0000110// ----------------------------------------------------------------------------
Leon Clarkee46be812010-01-19 14:06:41 +0000111// Support macro for defining builtins in C++.
Steve Blocka7e24c12009-10-30 11:49:00 +0000112// ----------------------------------------------------------------------------
113//
114// A builtin function is defined by writing:
115//
116// BUILTIN(name) {
117// ...
118// }
Steve Blocka7e24c12009-10-30 11:49:00 +0000119//
Leon Clarkee46be812010-01-19 14:06:41 +0000120// In the body of the builtin function the arguments can be accessed
121// through the BuiltinArguments object args.
Steve Blocka7e24c12009-10-30 11:49:00 +0000122
Leon Clarkee46be812010-01-19 14:06:41 +0000123#ifdef DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +0000124
John Reck59135872010-11-02 12:39:01 -0700125#define BUILTIN(name) \
126 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
127 name##ArgumentsType args); \
128 MUST_USE_RESULT static MaybeObject* Builtin_##name( \
129 name##ArgumentsType args) { \
130 args.Verify(); \
131 return Builtin_Impl_##name(args); \
132 } \
133 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
134 name##ArgumentsType args)
Steve Blocka7e24c12009-10-30 11:49:00 +0000135
Leon Clarkee46be812010-01-19 14:06:41 +0000136#else // For release mode.
Steve Blocka7e24c12009-10-30 11:49:00 +0000137
John Reck59135872010-11-02 12:39:01 -0700138#define BUILTIN(name) \
139 static MaybeObject* Builtin_##name(name##ArgumentsType args)
Leon Clarkee46be812010-01-19 14:06:41 +0000140
141#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000142
143
144static inline bool CalledAsConstructor() {
145#ifdef DEBUG
146 // Calculate the result using a full stack frame iterator and check
147 // that the state of the stack is as we assume it to be in the
148 // code below.
149 StackFrameIterator it;
150 ASSERT(it.frame()->is_exit());
151 it.Advance();
152 StackFrame* frame = it.frame();
153 bool reference_result = frame->is_construct();
154#endif
155 Address fp = Top::c_entry_fp(Top::GetCurrentThread());
156 // Because we know fp points to an exit frame we can use the relevant
157 // part of ExitFrame::ComputeCallerState directly.
158 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
159 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
160 // This inlines the part of StackFrame::ComputeType that grabs the
161 // type of the current frame. Note that StackFrame::ComputeType
162 // has been specialized for each architecture so if any one of them
163 // changes this code has to be changed as well.
164 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
165 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
166 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
167 bool result = (marker == kConstructMarker);
168 ASSERT_EQ(result, reference_result);
169 return result;
170}
171
172// ----------------------------------------------------------------------------
173
174
Steve Blocka7e24c12009-10-30 11:49:00 +0000175BUILTIN(Illegal) {
176 UNREACHABLE();
Leon Clarkee46be812010-01-19 14:06:41 +0000177 return Heap::undefined_value(); // Make compiler happy.
Steve Blocka7e24c12009-10-30 11:49:00 +0000178}
Steve Blocka7e24c12009-10-30 11:49:00 +0000179
180
181BUILTIN(EmptyFunction) {
Leon Clarkee46be812010-01-19 14:06:41 +0000182 return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000183}
Steve Blocka7e24c12009-10-30 11:49:00 +0000184
185
186BUILTIN(ArrayCodeGeneric) {
187 Counters::array_function_runtime.Increment();
188
189 JSArray* array;
190 if (CalledAsConstructor()) {
Leon Clarkee46be812010-01-19 14:06:41 +0000191 array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000192 } else {
193 // Allocate the JS Array
194 JSFunction* constructor =
195 Top::context()->global_context()->array_function();
John Reck59135872010-11-02 12:39:01 -0700196 Object* obj;
197 { MaybeObject* maybe_obj = Heap::AllocateJSObject(constructor);
198 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
199 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000200 array = JSArray::cast(obj);
201 }
202
203 // 'array' now contains the JSArray we should initialize.
Steve Block8defd9f2010-07-08 12:39:36 +0100204 ASSERT(array->HasFastElements());
Steve Blocka7e24c12009-10-30 11:49:00 +0000205
206 // Optimize the case where there is one argument and the argument is a
207 // small smi.
208 if (args.length() == 2) {
209 Object* obj = args[1];
210 if (obj->IsSmi()) {
211 int len = Smi::cast(obj)->value();
212 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
John Reck59135872010-11-02 12:39:01 -0700213 Object* obj;
214 { MaybeObject* maybe_obj = Heap::AllocateFixedArrayWithHoles(len);
215 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
216 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000217 array->SetContent(FixedArray::cast(obj));
218 return array;
219 }
220 }
221 // Take the argument as the length.
John Reck59135872010-11-02 12:39:01 -0700222 { MaybeObject* maybe_obj = array->Initialize(0);
223 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
224 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000225 return array->SetElementsLength(args[1]);
226 }
227
228 // Optimize the case where there are no parameters passed.
229 if (args.length() == 1) {
230 return array->Initialize(JSArray::kPreallocatedArrayElements);
231 }
232
233 // Take the arguments as elements.
234 int number_of_elements = args.length() - 1;
235 Smi* len = Smi::FromInt(number_of_elements);
John Reck59135872010-11-02 12:39:01 -0700236 Object* obj;
237 { MaybeObject* maybe_obj = Heap::AllocateFixedArrayWithHoles(len->value());
238 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
239 }
Leon Clarke4515c472010-02-03 11:58:03 +0000240
241 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000242 FixedArray* elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000243 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000244 // Fill in the content
245 for (int index = 0; index < number_of_elements; index++) {
246 elms->set(index, args[index+1], mode);
247 }
248
249 // Set length and elements on the array.
250 array->set_elements(FixedArray::cast(obj));
Leon Clarke4515c472010-02-03 11:58:03 +0000251 array->set_length(len);
Steve Blocka7e24c12009-10-30 11:49:00 +0000252
253 return array;
254}
Steve Blocka7e24c12009-10-30 11:49:00 +0000255
256
John Reck59135872010-11-02 12:39:01 -0700257MUST_USE_RESULT static MaybeObject* AllocateJSArray() {
Steve Block6ded16b2010-05-10 14:33:55 +0100258 JSFunction* array_function =
259 Top::context()->global_context()->array_function();
John Reck59135872010-11-02 12:39:01 -0700260 Object* result;
261 { MaybeObject* maybe_result = Heap::AllocateJSObject(array_function);
262 if (!maybe_result->ToObject(&result)) return maybe_result;
263 }
Steve Block6ded16b2010-05-10 14:33:55 +0100264 return result;
265}
266
267
John Reck59135872010-11-02 12:39:01 -0700268MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray() {
269 Object* result;
270 { MaybeObject* maybe_result = AllocateJSArray();
271 if (!maybe_result->ToObject(&result)) return maybe_result;
272 }
Steve Block6ded16b2010-05-10 14:33:55 +0100273 JSArray* result_array = JSArray::cast(result);
274 result_array->set_length(Smi::FromInt(0));
275 result_array->set_elements(Heap::empty_fixed_array());
276 return result_array;
277}
278
279
280static void CopyElements(AssertNoAllocation* no_gc,
281 FixedArray* dst,
282 int dst_index,
283 FixedArray* src,
284 int src_index,
285 int len) {
286 ASSERT(dst != src); // Use MoveElements instead.
Iain Merrick75681382010-08-19 15:07:18 +0100287 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100288 ASSERT(len > 0);
289 CopyWords(dst->data_start() + dst_index,
290 src->data_start() + src_index,
291 len);
292 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
293 if (mode == UPDATE_WRITE_BARRIER) {
294 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
295 }
296}
297
298
299static void MoveElements(AssertNoAllocation* no_gc,
300 FixedArray* dst,
301 int dst_index,
302 FixedArray* src,
303 int src_index,
304 int len) {
Iain Merrick75681382010-08-19 15:07:18 +0100305 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100306 memmove(dst->data_start() + dst_index,
307 src->data_start() + src_index,
308 len * kPointerSize);
309 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
310 if (mode == UPDATE_WRITE_BARRIER) {
311 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
312 }
313}
314
315
316static void FillWithHoles(FixedArray* dst, int from, int to) {
Iain Merrick75681382010-08-19 15:07:18 +0100317 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100318 MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from);
319}
320
321
322static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
Iain Merrick75681382010-08-19 15:07:18 +0100323 ASSERT(elms->map() != Heap::fixed_cow_array_map());
Steve Block791712a2010-08-27 10:21:07 +0100324 // For now this trick is only applied to fixed arrays in new and paged space.
Steve Block6ded16b2010-05-10 14:33:55 +0100325 // In large object space the object's start must coincide with chunk
326 // and thus the trick is just not applicable.
Steve Block791712a2010-08-27 10:21:07 +0100327 ASSERT(!Heap::lo_space()->Contains(elms));
Steve Block6ded16b2010-05-10 14:33:55 +0100328
329 STATIC_ASSERT(FixedArray::kMapOffset == 0);
330 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
331 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
332
333 Object** former_start = HeapObject::RawField(elms, 0);
334
335 const int len = elms->length();
336
Steve Block791712a2010-08-27 10:21:07 +0100337 if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
338 !Heap::new_space()->Contains(elms)) {
339 // If we are doing a big trim in old space then we zap the space that was
340 // formerly part of the array so that the GC (aided by the card-based
341 // remembered set) won't find pointers to new-space there.
342 Object** zap = reinterpret_cast<Object**>(elms->address());
343 zap++; // Header of filler must be at least one word so skip that.
344 for (int i = 1; i < to_trim; i++) {
345 *zap++ = Smi::FromInt(0);
346 }
347 }
Steve Block6ded16b2010-05-10 14:33:55 +0100348 // Technically in new space this write might be omitted (except for
349 // debug mode which iterates through the heap), but to play safer
350 // we still do it.
351 Heap::CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
352
353 former_start[to_trim] = Heap::fixed_array_map();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100354 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
Steve Block6ded16b2010-05-10 14:33:55 +0100355
Steve Block791712a2010-08-27 10:21:07 +0100356 return FixedArray::cast(HeapObject::FromAddress(
357 elms->address() + to_trim * kPointerSize));
Steve Block6ded16b2010-05-10 14:33:55 +0100358}
359
360
Kristian Monsen25f61362010-05-21 11:50:48 +0100361static bool ArrayPrototypeHasNoElements(Context* global_context,
362 JSObject* array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100363 // This method depends on non writability of Object and Array prototype
364 // fields.
Kristian Monsen25f61362010-05-21 11:50:48 +0100365 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
Steve Block6ded16b2010-05-10 14:33:55 +0100366 // Hidden prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100367 array_proto = JSObject::cast(array_proto->GetPrototype());
368 ASSERT(array_proto->elements() == Heap::empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +0100369 // Object.prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100370 array_proto = JSObject::cast(array_proto->GetPrototype());
371 if (array_proto != global_context->initial_object_prototype()) return false;
372 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
373 ASSERT(array_proto->GetPrototype()->IsNull());
Steve Block6ded16b2010-05-10 14:33:55 +0100374 return true;
375}
376
377
John Reck59135872010-11-02 12:39:01 -0700378MUST_USE_RESULT
379static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
380 Object* receiver) {
Iain Merrick75681382010-08-19 15:07:18 +0100381 if (!receiver->IsJSArray()) return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100382 JSArray* array = JSArray::cast(receiver);
Steve Block6ded16b2010-05-10 14:33:55 +0100383 HeapObject* elms = HeapObject::cast(array->elements());
Iain Merrick75681382010-08-19 15:07:18 +0100384 if (elms->map() == Heap::fixed_array_map()) return elms;
385 if (elms->map() == Heap::fixed_cow_array_map()) {
386 return array->EnsureWritableFastElements();
Steve Block6ded16b2010-05-10 14:33:55 +0100387 }
Iain Merrick75681382010-08-19 15:07:18 +0100388 return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100389}
390
391
Iain Merrick75681382010-08-19 15:07:18 +0100392static inline bool IsJSArrayFastElementMovingAllowed(JSArray* receiver) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100393 Context* global_context = Top::context()->global_context();
394 JSObject* array_proto =
395 JSObject::cast(global_context->array_function()->prototype());
Iain Merrick75681382010-08-19 15:07:18 +0100396 return receiver->GetPrototype() == array_proto &&
397 ArrayPrototypeHasNoElements(global_context, array_proto);
Kristian Monsen25f61362010-05-21 11:50:48 +0100398}
399
400
John Reck59135872010-11-02 12:39:01 -0700401MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
402 const char* name,
403 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Block6ded16b2010-05-10 14:33:55 +0100404 HandleScope handleScope;
405
406 Handle<Object> js_builtin =
407 GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
408 name);
409 ASSERT(js_builtin->IsJSFunction());
410 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
Kristian Monsen25f61362010-05-21 11:50:48 +0100411 ScopedVector<Object**> argv(args.length() - 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100412 int n_args = args.length() - 1;
413 for (int i = 0; i < n_args; i++) {
414 argv[i] = args.at<Object>(i + 1).location();
415 }
416 bool pending_exception = false;
417 Handle<Object> result = Execution::Call(function,
418 args.receiver(),
419 n_args,
420 argv.start(),
421 &pending_exception);
Steve Block6ded16b2010-05-10 14:33:55 +0100422 if (pending_exception) return Failure::Exception();
423 return *result;
424}
425
426
Steve Blocka7e24c12009-10-30 11:49:00 +0000427BUILTIN(ArrayPush) {
Steve Block6ded16b2010-05-10 14:33:55 +0100428 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700429 Object* elms_obj;
430 { MaybeObject* maybe_elms_obj =
431 EnsureJSArrayWithWritableFastElements(receiver);
432 if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayPush", args);
433 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
434 }
Iain Merrick75681382010-08-19 15:07:18 +0100435 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100436 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000437
Steve Blocka7e24c12009-10-30 11:49:00 +0000438 int len = Smi::cast(array->length())->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000439 int to_add = args.length() - 1;
440 if (to_add == 0) {
441 return Smi::FromInt(len);
442 }
443 // Currently fixed arrays cannot grow too big, so
444 // we should never hit this case.
445 ASSERT(to_add <= (Smi::kMaxValue - len));
Steve Blocka7e24c12009-10-30 11:49:00 +0000446
Andrei Popescu402d9372010-02-26 13:31:12 +0000447 int new_length = len + to_add;
Steve Blocka7e24c12009-10-30 11:49:00 +0000448
Andrei Popescu402d9372010-02-26 13:31:12 +0000449 if (new_length > elms->length()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000450 // New backing storage is needed.
451 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700452 Object* obj;
453 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(capacity);
454 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
455 }
Steve Block6ded16b2010-05-10 14:33:55 +0100456 FixedArray* new_elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000457
458 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100459 if (len > 0) {
460 CopyElements(&no_gc, new_elms, 0, elms, 0, len);
461 }
462 FillWithHoles(new_elms, new_length, capacity);
463
Andrei Popescu402d9372010-02-26 13:31:12 +0000464 elms = new_elms;
465 array->set_elements(elms);
Steve Blocka7e24c12009-10-30 11:49:00 +0000466 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000467
Steve Block6ded16b2010-05-10 14:33:55 +0100468 // Add the provided values.
Andrei Popescu402d9372010-02-26 13:31:12 +0000469 AssertNoAllocation no_gc;
470 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Andrei Popescu402d9372010-02-26 13:31:12 +0000471 for (int index = 0; index < to_add; index++) {
472 elms->set(index + len, args[index + 1], mode);
473 }
474
Steve Blocka7e24c12009-10-30 11:49:00 +0000475 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000476 array->set_length(Smi::FromInt(new_length));
Andrei Popescu402d9372010-02-26 13:31:12 +0000477 return Smi::FromInt(new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000478}
Steve Blocka7e24c12009-10-30 11:49:00 +0000479
480
481BUILTIN(ArrayPop) {
Steve Block6ded16b2010-05-10 14:33:55 +0100482 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700483 Object* elms_obj;
484 { MaybeObject* maybe_elms_obj =
485 EnsureJSArrayWithWritableFastElements(receiver);
486 if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayPop", args);
487 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
488 }
Iain Merrick75681382010-08-19 15:07:18 +0100489 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100490 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000491
492 int len = Smi::cast(array->length())->value();
Steve Block6ded16b2010-05-10 14:33:55 +0100493 if (len == 0) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000494
495 // Get top element
John Reck59135872010-11-02 12:39:01 -0700496 MaybeObject* top = elms->get(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000497
498 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000499 array->set_length(Smi::FromInt(len - 1));
Steve Blocka7e24c12009-10-30 11:49:00 +0000500
501 if (!top->IsTheHole()) {
502 // Delete the top element.
503 elms->set_the_hole(len - 1);
504 return top;
505 }
506
Kristian Monsen25f61362010-05-21 11:50:48 +0100507 top = array->GetPrototype()->GetElement(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000508
509 return top;
510}
Steve Blocka7e24c12009-10-30 11:49:00 +0000511
512
Andrei Popescu402d9372010-02-26 13:31:12 +0000513BUILTIN(ArrayShift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100514 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700515 Object* elms_obj;
516 { MaybeObject* maybe_elms_obj =
517 EnsureJSArrayWithWritableFastElements(receiver);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100518 if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayShift", args);
John Reck59135872010-11-02 12:39:01 -0700519 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
520 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100521 if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100522 return CallJsBuiltin("ArrayShift", args);
523 }
Iain Merrick75681382010-08-19 15:07:18 +0100524 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100525 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000526 ASSERT(array->HasFastElements());
527
528 int len = Smi::cast(array->length())->value();
529 if (len == 0) return Heap::undefined_value();
530
Andrei Popescu402d9372010-02-26 13:31:12 +0000531 // Get first element
532 Object* first = elms->get(0);
533 if (first->IsTheHole()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100534 first = Heap::undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000535 }
536
Steve Block791712a2010-08-27 10:21:07 +0100537 if (!Heap::lo_space()->Contains(elms)) {
538 // As elms still in the same space they used to be,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100539 // there is no need to update region dirty mark.
Steve Block6ded16b2010-05-10 14:33:55 +0100540 array->set_elements(LeftTrimFixedArray(elms, 1), SKIP_WRITE_BARRIER);
541 } else {
542 // Shift the elements.
543 AssertNoAllocation no_gc;
544 MoveElements(&no_gc, elms, 0, elms, 1, len - 1);
545 elms->set(len - 1, Heap::the_hole_value());
Andrei Popescu402d9372010-02-26 13:31:12 +0000546 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000547
548 // Set the length.
549 array->set_length(Smi::FromInt(len - 1));
550
551 return first;
552}
553
554
555BUILTIN(ArrayUnshift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100556 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700557 Object* elms_obj;
558 { MaybeObject* maybe_elms_obj =
559 EnsureJSArrayWithWritableFastElements(receiver);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100560 if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayUnshift", args);
John Reck59135872010-11-02 12:39:01 -0700561 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
562 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100563 if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100564 return CallJsBuiltin("ArrayUnshift", args);
565 }
Iain Merrick75681382010-08-19 15:07:18 +0100566 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100567 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000568 ASSERT(array->HasFastElements());
569
570 int len = Smi::cast(array->length())->value();
571 int to_add = args.length() - 1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000572 int new_length = len + to_add;
573 // Currently fixed arrays cannot grow too big, so
574 // we should never hit this case.
575 ASSERT(to_add <= (Smi::kMaxValue - len));
576
Andrei Popescu402d9372010-02-26 13:31:12 +0000577 if (new_length > elms->length()) {
578 // New backing storage is needed.
579 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700580 Object* obj;
581 { MaybeObject* maybe_obj = Heap::AllocateUninitializedFixedArray(capacity);
582 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
583 }
Steve Block6ded16b2010-05-10 14:33:55 +0100584 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000585
586 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100587 if (len > 0) {
588 CopyElements(&no_gc, new_elms, to_add, elms, 0, len);
589 }
590 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000591
592 elms = new_elms;
593 array->set_elements(elms);
594 } else {
595 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100596 MoveElements(&no_gc, elms, to_add, elms, 0, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000597 }
598
599 // Add the provided values.
600 AssertNoAllocation no_gc;
601 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
602 for (int i = 0; i < to_add; i++) {
603 elms->set(i, args[i + 1], mode);
604 }
605
606 // Set the length.
607 array->set_length(Smi::FromInt(new_length));
608 return Smi::FromInt(new_length);
609}
610
611
Andrei Popescu402d9372010-02-26 13:31:12 +0000612BUILTIN(ArraySlice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100613 Object* receiver = *args.receiver();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100614 FixedArray* elms;
615 int len = -1;
John Reck59135872010-11-02 12:39:01 -0700616 { MaybeObject* maybe_elms_obj =
617 EnsureJSArrayWithWritableFastElements(receiver);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100618 Object* elms_obj;
619 if (maybe_elms_obj != NULL && maybe_elms_obj->ToObject(&elms_obj)) {
620 if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
621 return CallJsBuiltin("ArraySlice", args);
622 }
623 elms = FixedArray::cast(elms_obj);
624 JSArray* array = JSArray::cast(receiver);
625 ASSERT(array->HasFastElements());
Andrei Popescu402d9372010-02-26 13:31:12 +0000626
Ben Murdochb0fe1622011-05-05 13:52:32 +0100627 len = Smi::cast(array->length())->value();
628 } else {
629 // Array.slice(arguments, ...) is quite a common idiom (notably more
630 // than 50% of invocations in Web apps). Treat it in C++ as well.
631 Map* arguments_map =
632 Top::context()->global_context()->arguments_boilerplate()->map();
Andrei Popescu402d9372010-02-26 13:31:12 +0000633
Ben Murdochb0fe1622011-05-05 13:52:32 +0100634 bool is_arguments_object_with_fast_elements =
635 receiver->IsJSObject()
636 && JSObject::cast(receiver)->map() == arguments_map
637 && JSObject::cast(receiver)->HasFastElements();
638 if (!is_arguments_object_with_fast_elements) {
639 return CallJsBuiltin("ArraySlice", args);
640 }
641 elms = FixedArray::cast(JSObject::cast(receiver)->elements());
642 len = elms->length();
643#ifdef DEBUG
644 // Arguments object by construction should have no holes, check it.
645 if (FLAG_enable_slow_asserts) {
646 for (int i = 0; i < len; i++) {
647 ASSERT(elms->get(i) != Heap::the_hole_value());
648 }
649 }
650#endif
651 }
652 }
653 ASSERT(len >= 0);
Andrei Popescu402d9372010-02-26 13:31:12 +0000654 int n_arguments = args.length() - 1;
655
656 // Note carefully choosen defaults---if argument is missing,
Steve Block6ded16b2010-05-10 14:33:55 +0100657 // it's undefined which gets converted to 0 for relative_start
658 // and to len for relative_end.
659 int relative_start = 0;
660 int relative_end = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000661 if (n_arguments > 0) {
662 Object* arg1 = args[1];
663 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100664 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000665 } else if (!arg1->IsUndefined()) {
666 return CallJsBuiltin("ArraySlice", args);
667 }
668 if (n_arguments > 1) {
669 Object* arg2 = args[2];
670 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100671 relative_end = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000672 } else if (!arg2->IsUndefined()) {
673 return CallJsBuiltin("ArraySlice", args);
674 }
675 }
676 }
677
678 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
Steve Block6ded16b2010-05-10 14:33:55 +0100679 int k = (relative_start < 0) ? Max(len + relative_start, 0)
680 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000681
682 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
Steve Block6ded16b2010-05-10 14:33:55 +0100683 int final = (relative_end < 0) ? Max(len + relative_end, 0)
684 : Min(relative_end, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000685
686 // Calculate the length of result array.
687 int result_len = final - k;
Steve Block6ded16b2010-05-10 14:33:55 +0100688 if (result_len <= 0) {
689 return AllocateEmptyJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000690 }
691
John Reck59135872010-11-02 12:39:01 -0700692 Object* result;
693 { MaybeObject* maybe_result = AllocateJSArray();
694 if (!maybe_result->ToObject(&result)) return maybe_result;
695 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000696 JSArray* result_array = JSArray::cast(result);
697
John Reck59135872010-11-02 12:39:01 -0700698 { MaybeObject* maybe_result =
699 Heap::AllocateUninitializedFixedArray(result_len);
700 if (!maybe_result->ToObject(&result)) return maybe_result;
701 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000702 FixedArray* result_elms = FixedArray::cast(result);
703
Andrei Popescu402d9372010-02-26 13:31:12 +0000704 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100705 CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000706
707 // Set elements.
708 result_array->set_elements(result_elms);
709
710 // Set the length.
711 result_array->set_length(Smi::FromInt(result_len));
712 return result_array;
713}
714
715
716BUILTIN(ArraySplice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100717 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700718 Object* elms_obj;
719 { MaybeObject* maybe_elms_obj =
720 EnsureJSArrayWithWritableFastElements(receiver);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100721 if (maybe_elms_obj == NULL) return CallJsBuiltin("ArraySplice", args);
John Reck59135872010-11-02 12:39:01 -0700722 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
723 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100724 if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100725 return CallJsBuiltin("ArraySplice", args);
726 }
Iain Merrick75681382010-08-19 15:07:18 +0100727 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100728 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000729 ASSERT(array->HasFastElements());
730
731 int len = Smi::cast(array->length())->value();
732
733 int n_arguments = args.length() - 1;
734
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100735 // Return empty array when no arguments are supplied.
Andrei Popescu402d9372010-02-26 13:31:12 +0000736 if (n_arguments == 0) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100737 return AllocateEmptyJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000738 }
739
Steve Block6ded16b2010-05-10 14:33:55 +0100740 int relative_start = 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000741 Object* arg1 = args[1];
742 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100743 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000744 } else if (!arg1->IsUndefined()) {
745 return CallJsBuiltin("ArraySplice", args);
746 }
Steve Block6ded16b2010-05-10 14:33:55 +0100747 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
748 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000749
750 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
751 // given differently from when an undefined delete count is given.
752 // This does not follow ECMA-262, but we do the same for
753 // compatibility.
Steve Block6ded16b2010-05-10 14:33:55 +0100754 int delete_count = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000755 if (n_arguments > 1) {
756 Object* arg2 = args[2];
757 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100758 delete_count = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000759 } else {
760 return CallJsBuiltin("ArraySplice", args);
761 }
762 }
Steve Block6ded16b2010-05-10 14:33:55 +0100763 int actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000764
Steve Block6ded16b2010-05-10 14:33:55 +0100765 JSArray* result_array = NULL;
766 if (actual_delete_count == 0) {
John Reck59135872010-11-02 12:39:01 -0700767 Object* result;
768 { MaybeObject* maybe_result = AllocateEmptyJSArray();
769 if (!maybe_result->ToObject(&result)) return maybe_result;
770 }
Steve Block6ded16b2010-05-10 14:33:55 +0100771 result_array = JSArray::cast(result);
772 } else {
773 // Allocate result array.
John Reck59135872010-11-02 12:39:01 -0700774 Object* result;
775 { MaybeObject* maybe_result = AllocateJSArray();
776 if (!maybe_result->ToObject(&result)) return maybe_result;
777 }
Steve Block6ded16b2010-05-10 14:33:55 +0100778 result_array = JSArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000779
John Reck59135872010-11-02 12:39:01 -0700780 { MaybeObject* maybe_result =
781 Heap::AllocateUninitializedFixedArray(actual_delete_count);
782 if (!maybe_result->ToObject(&result)) return maybe_result;
783 }
Steve Block6ded16b2010-05-10 14:33:55 +0100784 FixedArray* result_elms = FixedArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000785
Steve Block6ded16b2010-05-10 14:33:55 +0100786 AssertNoAllocation no_gc;
787 // Fill newly created array.
788 CopyElements(&no_gc,
789 result_elms, 0,
790 elms, actual_start,
791 actual_delete_count);
Andrei Popescu402d9372010-02-26 13:31:12 +0000792
Steve Block6ded16b2010-05-10 14:33:55 +0100793 // Set elements.
794 result_array->set_elements(result_elms);
Andrei Popescu402d9372010-02-26 13:31:12 +0000795
Steve Block6ded16b2010-05-10 14:33:55 +0100796 // Set the length.
797 result_array->set_length(Smi::FromInt(actual_delete_count));
Andrei Popescu402d9372010-02-26 13:31:12 +0000798 }
799
Steve Block6ded16b2010-05-10 14:33:55 +0100800 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000801
Steve Block6ded16b2010-05-10 14:33:55 +0100802 int new_length = len - actual_delete_count + item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000803
Steve Block6ded16b2010-05-10 14:33:55 +0100804 if (item_count < actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000805 // Shrink the array.
Steve Block791712a2010-08-27 10:21:07 +0100806 const bool trim_array = !Heap::lo_space()->Contains(elms) &&
Steve Block6ded16b2010-05-10 14:33:55 +0100807 ((actual_start + item_count) <
808 (len - actual_delete_count - actual_start));
809 if (trim_array) {
810 const int delta = actual_delete_count - item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000811
Steve Block6ded16b2010-05-10 14:33:55 +0100812 if (actual_start > 0) {
813 Object** start = elms->data_start();
814 memmove(start + delta, start, actual_start * kPointerSize);
815 }
816
817 elms = LeftTrimFixedArray(elms, delta);
818 array->set_elements(elms, SKIP_WRITE_BARRIER);
819 } else {
820 AssertNoAllocation no_gc;
821 MoveElements(&no_gc,
822 elms, actual_start + item_count,
823 elms, actual_start + actual_delete_count,
824 (len - actual_delete_count - actual_start));
825 FillWithHoles(elms, new_length, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000826 }
Steve Block6ded16b2010-05-10 14:33:55 +0100827 } else if (item_count > actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000828 // Currently fixed arrays cannot grow too big, so
829 // we should never hit this case.
Steve Block6ded16b2010-05-10 14:33:55 +0100830 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
Andrei Popescu402d9372010-02-26 13:31:12 +0000831
832 // Check if array need to grow.
833 if (new_length > elms->length()) {
834 // New backing storage is needed.
835 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700836 Object* obj;
837 { MaybeObject* maybe_obj =
838 Heap::AllocateUninitializedFixedArray(capacity);
839 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
840 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000841 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000842
Steve Block6ded16b2010-05-10 14:33:55 +0100843 AssertNoAllocation no_gc;
844 // Copy the part before actual_start as is.
845 if (actual_start > 0) {
846 CopyElements(&no_gc, new_elms, 0, elms, 0, actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000847 }
Steve Block6ded16b2010-05-10 14:33:55 +0100848 const int to_copy = len - actual_delete_count - actual_start;
849 if (to_copy > 0) {
850 CopyElements(&no_gc,
851 new_elms, actual_start + item_count,
852 elms, actual_start + actual_delete_count,
853 to_copy);
854 }
855 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000856
Andrei Popescu402d9372010-02-26 13:31:12 +0000857 elms = new_elms;
858 array->set_elements(elms);
Steve Block6ded16b2010-05-10 14:33:55 +0100859 } else {
860 AssertNoAllocation no_gc;
861 MoveElements(&no_gc,
862 elms, actual_start + item_count,
863 elms, actual_start + actual_delete_count,
864 (len - actual_delete_count - actual_start));
Andrei Popescu402d9372010-02-26 13:31:12 +0000865 }
866 }
867
Steve Block6ded16b2010-05-10 14:33:55 +0100868 AssertNoAllocation no_gc;
869 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
870 for (int k = actual_start; k < actual_start + item_count; k++) {
871 elms->set(k, args[3 + k - actual_start], mode);
Andrei Popescu402d9372010-02-26 13:31:12 +0000872 }
873
874 // Set the length.
875 array->set_length(Smi::FromInt(new_length));
876
877 return result_array;
878}
879
880
Steve Block6ded16b2010-05-10 14:33:55 +0100881BUILTIN(ArrayConcat) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100882 Context* global_context = Top::context()->global_context();
883 JSObject* array_proto =
884 JSObject::cast(global_context->array_function()->prototype());
885 if (!ArrayPrototypeHasNoElements(global_context, array_proto)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100886 return CallJsBuiltin("ArrayConcat", args);
887 }
888
889 // Iterate through all the arguments performing checks
890 // and calculating total length.
891 int n_arguments = args.length();
892 int result_len = 0;
893 for (int i = 0; i < n_arguments; i++) {
894 Object* arg = args[i];
Kristian Monsen25f61362010-05-21 11:50:48 +0100895 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
896 || JSArray::cast(arg)->GetPrototype() != array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100897 return CallJsBuiltin("ArrayConcat", args);
898 }
899
900 int len = Smi::cast(JSArray::cast(arg)->length())->value();
901
902 // We shouldn't overflow when adding another len.
903 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
904 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
905 USE(kHalfOfMaxInt);
906 result_len += len;
907 ASSERT(result_len >= 0);
908
909 if (result_len > FixedArray::kMaxLength) {
910 return CallJsBuiltin("ArrayConcat", args);
911 }
912 }
913
914 if (result_len == 0) {
915 return AllocateEmptyJSArray();
916 }
917
918 // Allocate result.
John Reck59135872010-11-02 12:39:01 -0700919 Object* result;
920 { MaybeObject* maybe_result = AllocateJSArray();
921 if (!maybe_result->ToObject(&result)) return maybe_result;
922 }
Steve Block6ded16b2010-05-10 14:33:55 +0100923 JSArray* result_array = JSArray::cast(result);
924
John Reck59135872010-11-02 12:39:01 -0700925 { MaybeObject* maybe_result =
926 Heap::AllocateUninitializedFixedArray(result_len);
927 if (!maybe_result->ToObject(&result)) return maybe_result;
928 }
Steve Block6ded16b2010-05-10 14:33:55 +0100929 FixedArray* result_elms = FixedArray::cast(result);
930
931 // Copy data.
932 AssertNoAllocation no_gc;
933 int start_pos = 0;
934 for (int i = 0; i < n_arguments; i++) {
935 JSArray* array = JSArray::cast(args[i]);
936 int len = Smi::cast(array->length())->value();
937 if (len > 0) {
938 FixedArray* elms = FixedArray::cast(array->elements());
939 CopyElements(&no_gc, result_elms, start_pos, elms, 0, len);
940 start_pos += len;
941 }
942 }
943 ASSERT(start_pos == result_len);
944
945 // Set the length and elements.
946 result_array->set_length(Smi::FromInt(result_len));
947 result_array->set_elements(result_elms);
948
949 return result_array;
950}
951
952
Steve Blocka7e24c12009-10-30 11:49:00 +0000953// -----------------------------------------------------------------------------
954//
955
956
957// Returns the holder JSObject if the function can legally be called
958// with this receiver. Returns Heap::null_value() if the call is
959// illegal. Any arguments that don't fit the expected type is
960// overwritten with undefined. Arguments that do fit the expected
961// type is overwritten with the object in the prototype chain that
962// actually has that type.
963static inline Object* TypeCheck(int argc,
964 Object** argv,
965 FunctionTemplateInfo* info) {
966 Object* recv = argv[0];
967 Object* sig_obj = info->signature();
968 if (sig_obj->IsUndefined()) return recv;
969 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
970 // If necessary, check the receiver
971 Object* recv_type = sig->receiver();
972
973 Object* holder = recv;
974 if (!recv_type->IsUndefined()) {
975 for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
976 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
977 break;
978 }
979 }
980 if (holder == Heap::null_value()) return holder;
981 }
982 Object* args_obj = sig->args();
983 // If there is no argument signature we're done
984 if (args_obj->IsUndefined()) return holder;
985 FixedArray* args = FixedArray::cast(args_obj);
986 int length = args->length();
987 if (argc <= length) length = argc - 1;
988 for (int i = 0; i < length; i++) {
989 Object* argtype = args->get(i);
990 if (argtype->IsUndefined()) continue;
991 Object** arg = &argv[-1 - i];
992 Object* current = *arg;
993 for (; current != Heap::null_value(); current = current->GetPrototype()) {
994 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
995 *arg = current;
996 break;
997 }
998 }
999 if (current == Heap::null_value()) *arg = Heap::undefined_value();
1000 }
1001 return holder;
1002}
1003
1004
Leon Clarkee46be812010-01-19 14:06:41 +00001005template <bool is_construct>
John Reck59135872010-11-02 12:39:01 -07001006MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
Leon Clarkee46be812010-01-19 14:06:41 +00001007 BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
1008 ASSERT(is_construct == CalledAsConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +00001009
Leon Clarkee46be812010-01-19 14:06:41 +00001010 HandleScope scope;
1011 Handle<JSFunction> function = args.called_function();
Steve Block6ded16b2010-05-10 14:33:55 +01001012 ASSERT(function->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001013
Steve Block6ded16b2010-05-10 14:33:55 +01001014 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
Steve Blocka7e24c12009-10-30 11:49:00 +00001015 if (is_construct) {
Steve Block6ded16b2010-05-10 14:33:55 +01001016 Handle<FunctionTemplateInfo> desc(fun_data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001017 bool pending_exception = false;
Leon Clarkee46be812010-01-19 14:06:41 +00001018 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
Steve Blocka7e24c12009-10-30 11:49:00 +00001019 &pending_exception);
1020 ASSERT(Top::has_pending_exception() == pending_exception);
1021 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +01001022 fun_data = *desc;
Steve Blocka7e24c12009-10-30 11:49:00 +00001023 }
1024
Steve Blocka7e24c12009-10-30 11:49:00 +00001025 Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
1026
1027 if (raw_holder->IsNull()) {
1028 // This function cannot be called with the given receiver. Abort!
1029 Handle<Object> obj =
1030 Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
1031 return Top::Throw(*obj);
1032 }
1033
1034 Object* raw_call_data = fun_data->call_code();
1035 if (!raw_call_data->IsUndefined()) {
1036 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1037 Object* callback_obj = call_data->callback();
1038 v8::InvocationCallback callback =
1039 v8::ToCData<v8::InvocationCallback>(callback_obj);
1040 Object* data_obj = call_data->data();
1041 Object* result;
1042
Leon Clarkee46be812010-01-19 14:06:41 +00001043 LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001044 ASSERT(raw_holder->IsJSObject());
1045
1046 CustomArguments custom;
1047 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1048 data_obj, *function, raw_holder);
1049
Steve Blocka7e24c12009-10-30 11:49:00 +00001050 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001051 custom.end(),
1052 &args[0] - 1,
1053 args.length() - 1,
1054 is_construct);
Steve Blocka7e24c12009-10-30 11:49:00 +00001055
1056 v8::Handle<v8::Value> value;
1057 {
1058 // Leaving JavaScript.
1059 VMState state(EXTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001060 ExternalCallbackScope call_scope(v8::ToCData<Address>(callback_obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00001061 value = callback(new_args);
1062 }
1063 if (value.IsEmpty()) {
1064 result = Heap::undefined_value();
1065 } else {
1066 result = *reinterpret_cast<Object**>(*value);
1067 }
1068
1069 RETURN_IF_SCHEDULED_EXCEPTION();
1070 if (!is_construct || result->IsJSObject()) return result;
1071 }
1072
Leon Clarkee46be812010-01-19 14:06:41 +00001073 return *args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +00001074}
Leon Clarkee46be812010-01-19 14:06:41 +00001075
1076
1077BUILTIN(HandleApiCall) {
1078 return HandleApiCallHelper<false>(args);
1079}
1080
1081
1082BUILTIN(HandleApiCallConstruct) {
1083 return HandleApiCallHelper<true>(args);
1084}
Steve Blocka7e24c12009-10-30 11:49:00 +00001085
1086
Andrei Popescu402d9372010-02-26 13:31:12 +00001087#ifdef DEBUG
1088
1089static void VerifyTypeCheck(Handle<JSObject> object,
1090 Handle<JSFunction> function) {
Steve Block6ded16b2010-05-10 14:33:55 +01001091 ASSERT(function->shared()->IsApiFunction());
1092 FunctionTemplateInfo* info = function->shared()->get_api_func_data();
Andrei Popescu402d9372010-02-26 13:31:12 +00001093 if (info->signature()->IsUndefined()) return;
1094 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1095 Object* receiver_type = signature->receiver();
1096 if (receiver_type->IsUndefined()) return;
1097 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
1098 ASSERT(object->IsInstanceOf(type));
1099}
1100
1101#endif
1102
1103
1104BUILTIN(FastHandleApiCall) {
1105 ASSERT(!CalledAsConstructor());
1106 const bool is_construct = false;
1107
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001108 // We expect four more arguments: callback, function, call data, and holder.
Andrei Popescu402d9372010-02-26 13:31:12 +00001109 const int args_length = args.length() - 4;
1110 ASSERT(args_length >= 0);
1111
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001112 Object* callback_obj = args[args_length];
Andrei Popescu402d9372010-02-26 13:31:12 +00001113
1114 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001115 &args[args_length + 1],
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001116 &args[0] - 1,
1117 args_length - 1,
1118 is_construct);
Andrei Popescu402d9372010-02-26 13:31:12 +00001119
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001120#ifdef DEBUG
1121 VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()),
1122 Utils::OpenHandle(*new_args.Callee()));
1123#endif
Andrei Popescu402d9372010-02-26 13:31:12 +00001124 HandleScope scope;
1125 Object* result;
1126 v8::Handle<v8::Value> value;
1127 {
1128 // Leaving JavaScript.
1129 VMState state(EXTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001130 ExternalCallbackScope call_scope(v8::ToCData<Address>(callback_obj));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001131 v8::InvocationCallback callback =
1132 v8::ToCData<v8::InvocationCallback>(callback_obj);
1133
Andrei Popescu402d9372010-02-26 13:31:12 +00001134 value = callback(new_args);
1135 }
1136 if (value.IsEmpty()) {
1137 result = Heap::undefined_value();
1138 } else {
1139 result = *reinterpret_cast<Object**>(*value);
1140 }
1141
1142 RETURN_IF_SCHEDULED_EXCEPTION();
1143 return result;
1144}
1145
1146
Steve Blocka7e24c12009-10-30 11:49:00 +00001147// Helper function to handle calls to non-function objects created through the
1148// API. The object can be called as either a constructor (using new) or just as
1149// a function (without new).
John Reck59135872010-11-02 12:39:01 -07001150MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
Leon Clarkee46be812010-01-19 14:06:41 +00001151 bool is_construct_call,
1152 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001153 // Non-functions are never called as constructors. Even if this is an object
1154 // called as a constructor the delegate call is not a construct call.
1155 ASSERT(!CalledAsConstructor());
1156
1157 Handle<Object> receiver = args.at<Object>(0);
1158
1159 // Get the object called.
Leon Clarkee46be812010-01-19 14:06:41 +00001160 JSObject* obj = JSObject::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +00001161
1162 // Get the invocation callback from the function descriptor that was
1163 // used to create the called object.
1164 ASSERT(obj->map()->has_instance_call_handler());
1165 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01001166 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001167 Object* handler =
Steve Block6ded16b2010-05-10 14:33:55 +01001168 constructor->shared()->get_api_func_data()->instance_call_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00001169 ASSERT(!handler->IsUndefined());
1170 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1171 Object* callback_obj = call_data->callback();
1172 v8::InvocationCallback callback =
1173 v8::ToCData<v8::InvocationCallback>(callback_obj);
1174
1175 // Get the data for the call and perform the callback.
Steve Blocka7e24c12009-10-30 11:49:00 +00001176 Object* result;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001177 {
1178 HandleScope scope;
1179
1180 LOG(ApiObjectAccess("call non-function", obj));
1181
1182 CustomArguments custom;
1183 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1184 call_data->data(), constructor, obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00001185 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001186 custom.end(),
1187 &args[0] - 1,
1188 args.length() - 1,
1189 is_construct_call);
Steve Blocka7e24c12009-10-30 11:49:00 +00001190 v8::Handle<v8::Value> value;
1191 {
1192 // Leaving JavaScript.
1193 VMState state(EXTERNAL);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001194 ExternalCallbackScope call_scope(v8::ToCData<Address>(callback_obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00001195 value = callback(new_args);
1196 }
1197 if (value.IsEmpty()) {
1198 result = Heap::undefined_value();
1199 } else {
1200 result = *reinterpret_cast<Object**>(*value);
1201 }
1202 }
1203 // Check for exceptions and return result.
1204 RETURN_IF_SCHEDULED_EXCEPTION();
1205 return result;
1206}
1207
1208
1209// Handle calls to non-function objects created through the API. This delegate
1210// function is used when the call is a normal function call.
1211BUILTIN(HandleApiCallAsFunction) {
1212 return HandleApiCallAsFunctionOrConstructor(false, args);
1213}
Steve Blocka7e24c12009-10-30 11:49:00 +00001214
1215
1216// Handle calls to non-function objects created through the API. This delegate
1217// function is used when the call is a construct call.
1218BUILTIN(HandleApiCallAsConstructor) {
1219 return HandleApiCallAsFunctionOrConstructor(true, args);
1220}
Steve Blocka7e24c12009-10-30 11:49:00 +00001221
1222
1223static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1224 LoadIC::GenerateArrayLength(masm);
1225}
1226
1227
1228static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
1229 LoadIC::GenerateStringLength(masm);
1230}
1231
1232
1233static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1234 LoadIC::GenerateFunctionPrototype(masm);
1235}
1236
1237
1238static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1239 LoadIC::GenerateInitialize(masm);
1240}
1241
1242
1243static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1244 LoadIC::GeneratePreMonomorphic(masm);
1245}
1246
1247
1248static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1249 LoadIC::GenerateMiss(masm);
1250}
1251
1252
1253static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1254 LoadIC::GenerateMegamorphic(masm);
1255}
1256
1257
1258static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1259 LoadIC::GenerateNormal(masm);
1260}
1261
1262
1263static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1264 KeyedLoadIC::GenerateInitialize(masm);
1265}
1266
1267
1268static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1269 KeyedLoadIC::GenerateMiss(masm);
1270}
1271
1272
1273static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1274 KeyedLoadIC::GenerateGeneric(masm);
1275}
1276
1277
Leon Clarkee46be812010-01-19 14:06:41 +00001278static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1279 KeyedLoadIC::GenerateString(masm);
1280}
1281
1282
Steve Block3ce2e202009-11-05 08:53:23 +00001283static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
1284 KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
1285}
1286
1287
1288static void Generate_KeyedLoadIC_ExternalUnsignedByteArray(
1289 MacroAssembler* masm) {
1290 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1291}
1292
1293
1294static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) {
1295 KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray);
1296}
1297
1298
1299static void Generate_KeyedLoadIC_ExternalUnsignedShortArray(
1300 MacroAssembler* masm) {
1301 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1302}
1303
1304
1305static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) {
1306 KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray);
1307}
1308
1309
1310static void Generate_KeyedLoadIC_ExternalUnsignedIntArray(
1311 MacroAssembler* masm) {
1312 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1313}
1314
1315
1316static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) {
1317 KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray);
1318}
1319
1320
Steve Blocka7e24c12009-10-30 11:49:00 +00001321static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1322 KeyedLoadIC::GeneratePreMonomorphic(masm);
1323}
1324
Andrei Popescu402d9372010-02-26 13:31:12 +00001325static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1326 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1327}
1328
Steve Blocka7e24c12009-10-30 11:49:00 +00001329
1330static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1331 StoreIC::GenerateInitialize(masm);
1332}
1333
1334
1335static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1336 StoreIC::GenerateMiss(masm);
1337}
1338
1339
Steve Block8defd9f2010-07-08 12:39:36 +01001340static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1341 StoreIC::GenerateNormal(masm);
1342}
1343
1344
Steve Blocka7e24c12009-10-30 11:49:00 +00001345static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
1346 StoreIC::GenerateMegamorphic(masm);
1347}
1348
1349
Steve Block6ded16b2010-05-10 14:33:55 +01001350static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1351 StoreIC::GenerateArrayLength(masm);
1352}
1353
1354
Ben Murdochb0fe1622011-05-05 13:52:32 +01001355static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
1356 StoreIC::GenerateGlobalProxy(masm);
1357}
1358
1359
Steve Blocka7e24c12009-10-30 11:49:00 +00001360static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
1361 KeyedStoreIC::GenerateGeneric(masm);
1362}
1363
1364
Steve Block3ce2e202009-11-05 08:53:23 +00001365static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) {
1366 KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray);
1367}
1368
1369
1370static void Generate_KeyedStoreIC_ExternalUnsignedByteArray(
1371 MacroAssembler* masm) {
1372 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1373}
1374
1375
1376static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) {
1377 KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray);
1378}
1379
1380
1381static void Generate_KeyedStoreIC_ExternalUnsignedShortArray(
1382 MacroAssembler* masm) {
1383 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1384}
1385
1386
1387static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) {
1388 KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray);
1389}
1390
1391
1392static void Generate_KeyedStoreIC_ExternalUnsignedIntArray(
1393 MacroAssembler* masm) {
1394 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1395}
1396
1397
1398static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) {
1399 KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray);
1400}
1401
1402
Steve Blocka7e24c12009-10-30 11:49:00 +00001403static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1404 KeyedStoreIC::GenerateMiss(masm);
1405}
1406
1407
1408static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1409 KeyedStoreIC::GenerateInitialize(masm);
1410}
1411
1412
1413#ifdef ENABLE_DEBUGGER_SUPPORT
1414static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1415 Debug::GenerateLoadICDebugBreak(masm);
1416}
1417
1418
1419static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1420 Debug::GenerateStoreICDebugBreak(masm);
1421}
1422
1423
1424static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1425 Debug::GenerateKeyedLoadICDebugBreak(masm);
1426}
1427
1428
1429static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1430 Debug::GenerateKeyedStoreICDebugBreak(masm);
1431}
1432
1433
1434static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1435 Debug::GenerateConstructCallDebugBreak(masm);
1436}
1437
1438
1439static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1440 Debug::GenerateReturnDebugBreak(masm);
1441}
1442
1443
1444static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
1445 Debug::GenerateStubNoRegistersDebugBreak(masm);
1446}
Steve Block6ded16b2010-05-10 14:33:55 +01001447
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001448
1449static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1450 Debug::GenerateSlotDebugBreak(masm);
1451}
1452
1453
Steve Block6ded16b2010-05-10 14:33:55 +01001454static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1455 Debug::GeneratePlainReturnLiveEdit(masm);
1456}
1457
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001458
Steve Block6ded16b2010-05-10 14:33:55 +01001459static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1460 Debug::GenerateFrameDropperLiveEdit(masm);
1461}
Steve Blocka7e24c12009-10-30 11:49:00 +00001462#endif
1463
1464Object* Builtins::builtins_[builtin_count] = { NULL, };
1465const char* Builtins::names_[builtin_count] = { NULL, };
1466
Leon Clarkee46be812010-01-19 14:06:41 +00001467#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Steve Blocka7e24c12009-10-30 11:49:00 +00001468 Address Builtins::c_functions_[cfunction_count] = {
1469 BUILTIN_LIST_C(DEF_ENUM_C)
1470 };
1471#undef DEF_ENUM_C
1472
1473#define DEF_JS_NAME(name, ignore) #name,
1474#define DEF_JS_ARGC(ignore, argc) argc,
1475const char* Builtins::javascript_names_[id_count] = {
1476 BUILTINS_LIST_JS(DEF_JS_NAME)
1477};
1478
1479int Builtins::javascript_argc_[id_count] = {
1480 BUILTINS_LIST_JS(DEF_JS_ARGC)
1481};
1482#undef DEF_JS_NAME
1483#undef DEF_JS_ARGC
1484
1485static bool is_initialized = false;
1486void Builtins::Setup(bool create_heap_objects) {
1487 ASSERT(!is_initialized);
1488
1489 // Create a scope for the handles in the builtins.
1490 HandleScope scope;
1491
1492 struct BuiltinDesc {
1493 byte* generator;
1494 byte* c_code;
1495 const char* s_name; // name is only used for generating log information.
1496 int name;
1497 Code::Flags flags;
Leon Clarkee46be812010-01-19 14:06:41 +00001498 BuiltinExtraArguments extra_args;
Steve Blocka7e24c12009-10-30 11:49:00 +00001499 };
1500
Leon Clarkee46be812010-01-19 14:06:41 +00001501#define DEF_FUNCTION_PTR_C(name, extra_args) \
1502 { FUNCTION_ADDR(Generate_Adaptor), \
1503 FUNCTION_ADDR(Builtin_##name), \
1504 #name, \
1505 c_##name, \
1506 Code::ComputeFlags(Code::BUILTIN), \
1507 extra_args \
Steve Blocka7e24c12009-10-30 11:49:00 +00001508 },
1509
1510#define DEF_FUNCTION_PTR_A(name, kind, state) \
1511 { FUNCTION_ADDR(Generate_##name), \
1512 NULL, \
1513 #name, \
1514 name, \
Leon Clarkee46be812010-01-19 14:06:41 +00001515 Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
1516 NO_EXTRA_ARGUMENTS \
Steve Blocka7e24c12009-10-30 11:49:00 +00001517 },
1518
1519 // Define array of pointers to generators and C builtin functions.
1520 static BuiltinDesc functions[] = {
1521 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1522 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1523 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1524 // Terminator:
Leon Clarkee46be812010-01-19 14:06:41 +00001525 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
1526 NO_EXTRA_ARGUMENTS }
Steve Blocka7e24c12009-10-30 11:49:00 +00001527 };
1528
1529#undef DEF_FUNCTION_PTR_C
1530#undef DEF_FUNCTION_PTR_A
1531
1532 // For now we generate builtin adaptor code into a stack-allocated
1533 // buffer, before copying it into individual code objects.
1534 byte buffer[4*KB];
1535
1536 // Traverse the list of builtins and generate an adaptor in a
1537 // separate code object for each one.
1538 for (int i = 0; i < builtin_count; i++) {
1539 if (create_heap_objects) {
1540 MacroAssembler masm(buffer, sizeof buffer);
1541 // Generate the code/adaptor.
Leon Clarkee46be812010-01-19 14:06:41 +00001542 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001543 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1544 // We pass all arguments to the generator, but it may not use all of
1545 // them. This works because the first arguments are on top of the
1546 // stack.
Leon Clarkee46be812010-01-19 14:06:41 +00001547 g(&masm, functions[i].name, functions[i].extra_args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001548 // Move the code into the object heap.
1549 CodeDesc desc;
1550 masm.GetCode(&desc);
1551 Code::Flags flags = functions[i].flags;
John Reck59135872010-11-02 12:39:01 -07001552 Object* code = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001553 {
1554 // During startup it's OK to always allocate and defer GC to later.
1555 // This simplifies things because we don't need to retry.
1556 AlwaysAllocateScope __scope__;
John Reck59135872010-11-02 12:39:01 -07001557 { MaybeObject* maybe_code =
1558 Heap::CreateCode(desc, flags, masm.CodeObject());
1559 if (!maybe_code->ToObject(&code)) {
1560 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1561 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001562 }
1563 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001564 // Log the event and add the code to the builtins array.
Steve Block6ded16b2010-05-10 14:33:55 +01001565 PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
1566 Code::cast(code), functions[i].s_name));
Steve Blocka7e24c12009-10-30 11:49:00 +00001567 builtins_[i] = code;
1568#ifdef ENABLE_DISASSEMBLER
1569 if (FLAG_print_builtin_code) {
1570 PrintF("Builtin: %s\n", functions[i].s_name);
1571 Code::cast(code)->Disassemble(functions[i].s_name);
1572 PrintF("\n");
1573 }
1574#endif
1575 } else {
1576 // Deserializing. The values will be filled in during IterateBuiltins.
1577 builtins_[i] = NULL;
1578 }
1579 names_[i] = functions[i].s_name;
1580 }
1581
1582 // Mark as initialized.
1583 is_initialized = true;
1584}
1585
1586
1587void Builtins::TearDown() {
1588 is_initialized = false;
1589}
1590
1591
1592void Builtins::IterateBuiltins(ObjectVisitor* v) {
1593 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1594}
1595
1596
1597const char* Builtins::Lookup(byte* pc) {
1598 if (is_initialized) { // may be called during initialization (disassembler!)
1599 for (int i = 0; i < builtin_count; i++) {
1600 Code* entry = Code::cast(builtins_[i]);
1601 if (entry->contains(pc)) {
1602 return names_[i];
1603 }
1604 }
1605 }
1606 return NULL;
1607}
1608
Ben Murdochb0fe1622011-05-05 13:52:32 +01001609
Steve Blocka7e24c12009-10-30 11:49:00 +00001610} } // namespace v8::internal