blob: 0f493e6e5712558237a4b3dbdd4edb541b54b7f1 [file] [log] [blame]
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
33#include "builtins.h"
Ben Murdochb8e0da22011-05-16 14:20:40 +010034#include "gdb-jit.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035#include "ic-inl.h"
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010036#include "heap-profiler.h"
Ben Murdoch592a9fc2012-03-05 11:04:45 +000037#include "mark-compact.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010038#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039
40namespace v8 {
41namespace internal {
42
Leon Clarkee46be812010-01-19 14:06:41 +000043namespace {
44
45// Arguments object passed to C++ builtins.
46template <BuiltinExtraArguments extra_args>
47class BuiltinArguments : public Arguments {
48 public:
49 BuiltinArguments(int length, Object** arguments)
50 : Arguments(length, arguments) { }
51
52 Object*& operator[] (int index) {
53 ASSERT(index < length());
54 return Arguments::operator[](index);
55 }
56
57 template <class S> Handle<S> at(int index) {
58 ASSERT(index < length());
59 return Arguments::at<S>(index);
60 }
61
62 Handle<Object> receiver() {
63 return Arguments::at<Object>(0);
64 }
65
66 Handle<JSFunction> called_function() {
67 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
68 return Arguments::at<JSFunction>(Arguments::length() - 1);
69 }
70
71 // Gets the total number of arguments including the receiver (but
72 // excluding extra arguments).
73 int length() const {
74 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
75 return Arguments::length();
76 }
77
78#ifdef DEBUG
79 void Verify() {
80 // Check we have at least the receiver.
81 ASSERT(Arguments::length() >= 1);
82 }
83#endif
84};
85
86
87// Specialize BuiltinArguments for the called function extra argument.
88
89template <>
90int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
91 return Arguments::length() - 1;
92}
93
94#ifdef DEBUG
95template <>
96void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
97 // Check we have at least the receiver and the called function.
98 ASSERT(Arguments::length() >= 2);
99 // Make sure cast to JSFunction succeeds.
100 called_function();
101}
102#endif
103
104
105#define DEF_ARG_TYPE(name, spec) \
106 typedef BuiltinArguments<spec> name##ArgumentsType;
107BUILTIN_LIST_C(DEF_ARG_TYPE)
108#undef DEF_ARG_TYPE
109
110} // namespace
111
Steve Blocka7e24c12009-10-30 11:49:00 +0000112// ----------------------------------------------------------------------------
Leon Clarkee46be812010-01-19 14:06:41 +0000113// Support macro for defining builtins in C++.
Steve Blocka7e24c12009-10-30 11:49:00 +0000114// ----------------------------------------------------------------------------
115//
116// A builtin function is defined by writing:
117//
118// BUILTIN(name) {
119// ...
120// }
Steve Blocka7e24c12009-10-30 11:49:00 +0000121//
Leon Clarkee46be812010-01-19 14:06:41 +0000122// In the body of the builtin function the arguments can be accessed
123// through the BuiltinArguments object args.
Steve Blocka7e24c12009-10-30 11:49:00 +0000124
Leon Clarkee46be812010-01-19 14:06:41 +0000125#ifdef DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +0000126
Steve Block44f0eee2011-05-26 01:26:41 +0100127#define BUILTIN(name) \
128 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
129 name##ArgumentsType args, Isolate* isolate); \
130 MUST_USE_RESULT static MaybeObject* Builtin_##name( \
131 name##ArgumentsType args, Isolate* isolate) { \
132 ASSERT(isolate == Isolate::Current()); \
133 args.Verify(); \
134 return Builtin_Impl_##name(args, isolate); \
135 } \
136 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
137 name##ArgumentsType args, Isolate* isolate)
Steve Blocka7e24c12009-10-30 11:49:00 +0000138
Leon Clarkee46be812010-01-19 14:06:41 +0000139#else // For release mode.
Steve Blocka7e24c12009-10-30 11:49:00 +0000140
Steve Block44f0eee2011-05-26 01:26:41 +0100141#define BUILTIN(name) \
142 static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate)
Leon Clarkee46be812010-01-19 14:06:41 +0000143
144#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000145
146
Steve Block44f0eee2011-05-26 01:26:41 +0100147static inline bool CalledAsConstructor(Isolate* isolate) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000148#ifdef DEBUG
149 // Calculate the result using a full stack frame iterator and check
150 // that the state of the stack is as we assume it to be in the
151 // code below.
152 StackFrameIterator it;
153 ASSERT(it.frame()->is_exit());
154 it.Advance();
155 StackFrame* frame = it.frame();
156 bool reference_result = frame->is_construct();
157#endif
Steve Block44f0eee2011-05-26 01:26:41 +0100158 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
Steve Blocka7e24c12009-10-30 11:49:00 +0000159 // Because we know fp points to an exit frame we can use the relevant
160 // part of ExitFrame::ComputeCallerState directly.
161 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
162 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
163 // This inlines the part of StackFrame::ComputeType that grabs the
164 // type of the current frame. Note that StackFrame::ComputeType
165 // has been specialized for each architecture so if any one of them
166 // changes this code has to be changed as well.
167 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
168 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
169 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
170 bool result = (marker == kConstructMarker);
171 ASSERT_EQ(result, reference_result);
172 return result;
173}
174
175// ----------------------------------------------------------------------------
176
Steve Blocka7e24c12009-10-30 11:49:00 +0000177BUILTIN(Illegal) {
178 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100179 return isolate->heap()->undefined_value(); // Make compiler happy.
Steve Blocka7e24c12009-10-30 11:49:00 +0000180}
Steve Blocka7e24c12009-10-30 11:49:00 +0000181
182
183BUILTIN(EmptyFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +0100184 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000185}
Steve Blocka7e24c12009-10-30 11:49:00 +0000186
187
Ben Murdochc7cc0282012-03-05 14:35:55 +0000188static MaybeObject* ArrayCodeGenericCommon(Arguments* args,
189 Isolate* isolate,
190 JSFunction* constructor) {
Steve Block44f0eee2011-05-26 01:26:41 +0100191 Heap* heap = isolate->heap();
192 isolate->counters()->array_function_runtime()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +0000193
194 JSArray* array;
Steve Block44f0eee2011-05-26 01:26:41 +0100195 if (CalledAsConstructor(isolate)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000196 array = JSArray::cast((*args)[0]);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100197 // Initialize elements and length in case later allocations fail so that the
198 // array object is initialized in a valid state.
199 array->set_length(Smi::FromInt(0));
200 array->set_elements(heap->empty_fixed_array());
201 if (!FLAG_smi_only_arrays) {
202 Context* global_context = isolate->context()->global_context();
203 if (array->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS &&
204 !global_context->object_js_array_map()->IsUndefined()) {
205 array->set_map(Map::cast(global_context->object_js_array_map()));
206 }
207 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000208 } else {
209 // Allocate the JS Array
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100210 MaybeObject* maybe_obj = heap->AllocateJSObject(constructor);
211 if (!maybe_obj->To(&array)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +0000212 }
213
Steve Blocka7e24c12009-10-30 11:49:00 +0000214 // Optimize the case where there is one argument and the argument is a
215 // small smi.
Ben Murdochc7cc0282012-03-05 14:35:55 +0000216 if (args->length() == 2) {
217 Object* obj = (*args)[1];
Steve Blocka7e24c12009-10-30 11:49:00 +0000218 if (obj->IsSmi()) {
219 int len = Smi::cast(obj)->value();
220 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100221 Object* fixed_array;
Steve Block44f0eee2011-05-26 01:26:41 +0100222 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100223 if (!maybe_obj->ToObject(&fixed_array)) return maybe_obj;
John Reck59135872010-11-02 12:39:01 -0700224 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100225 // We do not use SetContent to skip the unnecessary elements type check.
226 array->set_elements(FixedArray::cast(fixed_array));
227 array->set_length(Smi::cast(obj));
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 return array;
229 }
230 }
231 // Take the argument as the length.
John Reck59135872010-11-02 12:39:01 -0700232 { MaybeObject* maybe_obj = array->Initialize(0);
233 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
234 }
Ben Murdochc7cc0282012-03-05 14:35:55 +0000235 return array->SetElementsLength((*args)[1]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000236 }
237
238 // Optimize the case where there are no parameters passed.
Ben Murdochc7cc0282012-03-05 14:35:55 +0000239 if (args->length() == 1) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000240 return array->Initialize(JSArray::kPreallocatedArrayElements);
241 }
242
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000243 // Set length and elements on the array.
Ben Murdochc7cc0282012-03-05 14:35:55 +0000244 int number_of_elements = args->length() - 1;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000245 MaybeObject* maybe_object =
Ben Murdochc7cc0282012-03-05 14:35:55 +0000246 array->EnsureCanContainElements(args, 1, number_of_elements,
247 ALLOW_CONVERTED_DOUBLE_ELEMENTS);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000248 if (maybe_object->IsFailure()) return maybe_object;
249
Ben Murdochc7cc0282012-03-05 14:35:55 +0000250 // Allocate an appropriately typed elements array.
251 MaybeObject* maybe_elms;
252 ElementsKind elements_kind = array->GetElementsKind();
253 if (elements_kind == FAST_DOUBLE_ELEMENTS) {
254 maybe_elms = heap->AllocateUninitializedFixedDoubleArray(
255 number_of_elements);
256 } else {
257 maybe_elms = heap->AllocateFixedArrayWithHoles(number_of_elements);
258 }
259 FixedArrayBase* elms;
260 if (!maybe_elms->To<FixedArrayBase>(&elms)) return maybe_elms;
261
Steve Blocka7e24c12009-10-30 11:49:00 +0000262 // Fill in the content
Ben Murdochc7cc0282012-03-05 14:35:55 +0000263 switch (array->GetElementsKind()) {
264 case FAST_SMI_ONLY_ELEMENTS: {
265 FixedArray* smi_elms = FixedArray::cast(elms);
266 for (int index = 0; index < number_of_elements; index++) {
267 smi_elms->set(index, (*args)[index+1], SKIP_WRITE_BARRIER);
268 }
269 break;
270 }
271 case FAST_ELEMENTS: {
272 AssertNoAllocation no_gc;
273 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
274 FixedArray* object_elms = FixedArray::cast(elms);
275 for (int index = 0; index < number_of_elements; index++) {
276 object_elms->set(index, (*args)[index+1], mode);
277 }
278 break;
279 }
280 case FAST_DOUBLE_ELEMENTS: {
281 FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms);
282 for (int index = 0; index < number_of_elements; index++) {
283 double_elms->set(index, (*args)[index+1]->Number());
284 }
285 break;
286 }
287 default:
288 UNREACHABLE();
289 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000290 }
291
Ben Murdochc7cc0282012-03-05 14:35:55 +0000292 array->set_elements(elms);
293 array->set_length(Smi::FromInt(number_of_elements));
Steve Blocka7e24c12009-10-30 11:49:00 +0000294 return array;
295}
Steve Blocka7e24c12009-10-30 11:49:00 +0000296
297
Ben Murdochc7cc0282012-03-05 14:35:55 +0000298BUILTIN(InternalArrayCodeGeneric) {
299 return ArrayCodeGenericCommon(
300 &args,
301 isolate,
302 isolate->context()->global_context()->internal_array_function());
303}
304
305
306BUILTIN(ArrayCodeGeneric) {
307 return ArrayCodeGenericCommon(
308 &args,
309 isolate,
310 isolate->context()->global_context()->array_function());
311}
312
313
Steve Block44f0eee2011-05-26 01:26:41 +0100314static void MoveElements(Heap* heap,
315 AssertNoAllocation* no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100316 FixedArray* dst,
317 int dst_index,
318 FixedArray* src,
319 int src_index,
320 int len) {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100321 if (len == 0) return;
Steve Block44f0eee2011-05-26 01:26:41 +0100322 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100323 memmove(dst->data_start() + dst_index,
324 src->data_start() + src_index,
325 len * kPointerSize);
326 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
327 if (mode == UPDATE_WRITE_BARRIER) {
Steve Block44f0eee2011-05-26 01:26:41 +0100328 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
Steve Block6ded16b2010-05-10 14:33:55 +0100329 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000330 heap->incremental_marking()->RecordWrites(dst);
Steve Block6ded16b2010-05-10 14:33:55 +0100331}
332
333
Steve Block44f0eee2011-05-26 01:26:41 +0100334static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) {
335 ASSERT(dst->map() != heap->fixed_cow_array_map());
336 MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from);
Steve Block6ded16b2010-05-10 14:33:55 +0100337}
338
339
Steve Block44f0eee2011-05-26 01:26:41 +0100340static FixedArray* LeftTrimFixedArray(Heap* heap,
341 FixedArray* elms,
342 int to_trim) {
343 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
Steve Block791712a2010-08-27 10:21:07 +0100344 // For now this trick is only applied to fixed arrays in new and paged space.
Steve Block6ded16b2010-05-10 14:33:55 +0100345 // In large object space the object's start must coincide with chunk
346 // and thus the trick is just not applicable.
Steve Block44f0eee2011-05-26 01:26:41 +0100347 ASSERT(!HEAP->lo_space()->Contains(elms));
Steve Block6ded16b2010-05-10 14:33:55 +0100348
349 STATIC_ASSERT(FixedArray::kMapOffset == 0);
350 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
351 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
352
353 Object** former_start = HeapObject::RawField(elms, 0);
354
355 const int len = elms->length();
356
Steve Block791712a2010-08-27 10:21:07 +0100357 if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
Steve Block44f0eee2011-05-26 01:26:41 +0100358 !heap->new_space()->Contains(elms)) {
Steve Block791712a2010-08-27 10:21:07 +0100359 // If we are doing a big trim in old space then we zap the space that was
360 // formerly part of the array so that the GC (aided by the card-based
361 // remembered set) won't find pointers to new-space there.
362 Object** zap = reinterpret_cast<Object**>(elms->address());
363 zap++; // Header of filler must be at least one word so skip that.
364 for (int i = 1; i < to_trim; i++) {
365 *zap++ = Smi::FromInt(0);
366 }
367 }
Steve Block6ded16b2010-05-10 14:33:55 +0100368 // Technically in new space this write might be omitted (except for
369 // debug mode which iterates through the heap), but to play safer
370 // we still do it.
Steve Block44f0eee2011-05-26 01:26:41 +0100371 heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
Steve Block6ded16b2010-05-10 14:33:55 +0100372
Steve Block44f0eee2011-05-26 01:26:41 +0100373 former_start[to_trim] = heap->fixed_array_map();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100374 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
Steve Block6ded16b2010-05-10 14:33:55 +0100375
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000376 // Maintain marking consistency for HeapObjectIterator and
377 // IncrementalMarking.
378 int size_delta = to_trim * kPointerSize;
379 if (heap->marking()->TransferMark(elms->address(),
380 elms->address() + size_delta)) {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000381 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000382 }
383
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100384 HEAP_PROFILE(heap, ObjectMoveEvent(elms->address(),
385 elms->address() + size_delta));
Steve Block791712a2010-08-27 10:21:07 +0100386 return FixedArray::cast(HeapObject::FromAddress(
387 elms->address() + to_trim * kPointerSize));
Steve Block6ded16b2010-05-10 14:33:55 +0100388}
389
390
Steve Block44f0eee2011-05-26 01:26:41 +0100391static bool ArrayPrototypeHasNoElements(Heap* heap,
392 Context* global_context,
Kristian Monsen25f61362010-05-21 11:50:48 +0100393 JSObject* array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100394 // This method depends on non writability of Object and Array prototype
395 // fields.
Steve Block44f0eee2011-05-26 01:26:41 +0100396 if (array_proto->elements() != heap->empty_fixed_array()) return false;
Steve Block6ded16b2010-05-10 14:33:55 +0100397 // Object.prototype
Steve Block1e0659c2011-05-24 12:43:12 +0100398 Object* proto = array_proto->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +0100399 if (proto == heap->null_value()) return false;
Steve Block1e0659c2011-05-24 12:43:12 +0100400 array_proto = JSObject::cast(proto);
Kristian Monsen25f61362010-05-21 11:50:48 +0100401 if (array_proto != global_context->initial_object_prototype()) return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100402 if (array_proto->elements() != heap->empty_fixed_array()) return false;
Steve Block053d10c2011-06-13 19:13:29 +0100403 return array_proto->GetPrototype()->IsNull();
Steve Block6ded16b2010-05-10 14:33:55 +0100404}
405
406
John Reck59135872010-11-02 12:39:01 -0700407MUST_USE_RESULT
408static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000409 Heap* heap, Object* receiver, Arguments* args, int first_added_arg) {
Iain Merrick75681382010-08-19 15:07:18 +0100410 if (!receiver->IsJSArray()) return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100411 JSArray* array = JSArray::cast(receiver);
Steve Block9fac8402011-05-12 15:51:54 +0100412 HeapObject* elms = array->elements();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000413 Map* map = elms->map();
414 if (map == heap->fixed_array_map()) {
415 if (args == NULL || !array->HasFastSmiOnlyElements()) {
416 return elms;
417 }
418 } else if (map == heap->fixed_cow_array_map()) {
419 MaybeObject* maybe_writable_result = array->EnsureWritableFastElements();
420 if (args == NULL || !array->HasFastSmiOnlyElements() ||
421 maybe_writable_result->IsFailure()) {
422 return maybe_writable_result;
423 }
424 } else {
425 return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100426 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000427
428 // Need to ensure that the arguments passed in args can be contained in
429 // the array.
430 int args_length = args->length();
431 if (first_added_arg >= args_length) return array->elements();
432
433 MaybeObject* maybe_array = array->EnsureCanContainElements(
434 args,
435 first_added_arg,
Ben Murdochc7cc0282012-03-05 14:35:55 +0000436 args_length - first_added_arg,
437 DONT_ALLOW_DOUBLE_ELEMENTS);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000438 if (maybe_array->IsFailure()) return maybe_array;
439 return array->elements();
Steve Block6ded16b2010-05-10 14:33:55 +0100440}
441
442
Steve Block44f0eee2011-05-26 01:26:41 +0100443static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
444 JSArray* receiver) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000445 if (!FLAG_clever_optimizations) return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100446 Context* global_context = heap->isolate()->context()->global_context();
Kristian Monsen25f61362010-05-21 11:50:48 +0100447 JSObject* array_proto =
448 JSObject::cast(global_context->array_function()->prototype());
Iain Merrick75681382010-08-19 15:07:18 +0100449 return receiver->GetPrototype() == array_proto &&
Steve Block44f0eee2011-05-26 01:26:41 +0100450 ArrayPrototypeHasNoElements(heap, global_context, array_proto);
Kristian Monsen25f61362010-05-21 11:50:48 +0100451}
452
453
John Reck59135872010-11-02 12:39:01 -0700454MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
Steve Block44f0eee2011-05-26 01:26:41 +0100455 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -0700456 const char* name,
457 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Block44f0eee2011-05-26 01:26:41 +0100458 HandleScope handleScope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100459
460 Handle<Object> js_builtin =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000461 GetProperty(Handle<JSObject>(isolate->global_context()->builtins()),
462 name);
463 Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin);
464 int argc = args.length() - 1;
465 ScopedVector<Handle<Object> > argv(argc);
466 for (int i = 0; i < argc; ++i) {
467 argv[i] = args.at<Object>(i + 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100468 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000469 bool pending_exception;
Steve Block6ded16b2010-05-10 14:33:55 +0100470 Handle<Object> result = Execution::Call(function,
471 args.receiver(),
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000472 argc,
Steve Block6ded16b2010-05-10 14:33:55 +0100473 argv.start(),
474 &pending_exception);
Steve Block6ded16b2010-05-10 14:33:55 +0100475 if (pending_exception) return Failure::Exception();
476 return *result;
477}
478
479
Steve Blocka7e24c12009-10-30 11:49:00 +0000480BUILTIN(ArrayPush) {
Steve Block44f0eee2011-05-26 01:26:41 +0100481 Heap* heap = isolate->heap();
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 =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000485 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1);
Steve Block44f0eee2011-05-26 01:26:41 +0100486 if (maybe_elms_obj == NULL) {
487 return CallJsBuiltin(isolate, "ArrayPush", args);
488 }
John Reck59135872010-11-02 12:39:01 -0700489 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
490 }
Iain Merrick75681382010-08-19 15:07:18 +0100491 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100492 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000493
Steve Blocka7e24c12009-10-30 11:49:00 +0000494 int len = Smi::cast(array->length())->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000495 int to_add = args.length() - 1;
496 if (to_add == 0) {
497 return Smi::FromInt(len);
498 }
499 // Currently fixed arrays cannot grow too big, so
500 // we should never hit this case.
501 ASSERT(to_add <= (Smi::kMaxValue - len));
Steve Blocka7e24c12009-10-30 11:49:00 +0000502
Andrei Popescu402d9372010-02-26 13:31:12 +0000503 int new_length = len + to_add;
Steve Blocka7e24c12009-10-30 11:49:00 +0000504
Andrei Popescu402d9372010-02-26 13:31:12 +0000505 if (new_length > elms->length()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000506 // New backing storage is needed.
507 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700508 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100509 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
John Reck59135872010-11-02 12:39:01 -0700510 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
511 }
Steve Block6ded16b2010-05-10 14:33:55 +0100512 FixedArray* new_elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000513
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100514 CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
515 new_elms, FAST_ELEMENTS, 0, len);
Steve Block44f0eee2011-05-26 01:26:41 +0100516 FillWithHoles(heap, new_elms, new_length, capacity);
Steve Block6ded16b2010-05-10 14:33:55 +0100517
Andrei Popescu402d9372010-02-26 13:31:12 +0000518 elms = new_elms;
Steve Blocka7e24c12009-10-30 11:49:00 +0000519 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000520
Steve Block6ded16b2010-05-10 14:33:55 +0100521 // Add the provided values.
Andrei Popescu402d9372010-02-26 13:31:12 +0000522 AssertNoAllocation no_gc;
523 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Andrei Popescu402d9372010-02-26 13:31:12 +0000524 for (int index = 0; index < to_add; index++) {
525 elms->set(index + len, args[index + 1], mode);
526 }
527
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000528 if (elms != array->elements()) {
529 array->set_elements(elms);
530 }
531
Steve Blocka7e24c12009-10-30 11:49:00 +0000532 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000533 array->set_length(Smi::FromInt(new_length));
Andrei Popescu402d9372010-02-26 13:31:12 +0000534 return Smi::FromInt(new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000535}
Steve Blocka7e24c12009-10-30 11:49:00 +0000536
537
538BUILTIN(ArrayPop) {
Steve Block44f0eee2011-05-26 01:26:41 +0100539 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100540 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700541 Object* elms_obj;
542 { MaybeObject* maybe_elms_obj =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000543 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100544 if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
John Reck59135872010-11-02 12:39:01 -0700545 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
546 }
Iain Merrick75681382010-08-19 15:07:18 +0100547 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100548 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000549
550 int len = Smi::cast(array->length())->value();
Steve Block44f0eee2011-05-26 01:26:41 +0100551 if (len == 0) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000552
553 // Get top element
John Reck59135872010-11-02 12:39:01 -0700554 MaybeObject* top = elms->get(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000555
556 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000557 array->set_length(Smi::FromInt(len - 1));
Steve Blocka7e24c12009-10-30 11:49:00 +0000558
559 if (!top->IsTheHole()) {
560 // Delete the top element.
561 elms->set_the_hole(len - 1);
562 return top;
563 }
564
Kristian Monsen25f61362010-05-21 11:50:48 +0100565 top = array->GetPrototype()->GetElement(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000566
567 return top;
568}
Steve Blocka7e24c12009-10-30 11:49:00 +0000569
570
Andrei Popescu402d9372010-02-26 13:31:12 +0000571BUILTIN(ArrayShift) {
Steve Block44f0eee2011-05-26 01:26:41 +0100572 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100573 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700574 Object* elms_obj;
575 { MaybeObject* maybe_elms_obj =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000576 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100577 if (maybe_elms_obj == NULL)
578 return CallJsBuiltin(isolate, "ArrayShift", args);
John Reck59135872010-11-02 12:39:01 -0700579 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
580 }
Steve Block44f0eee2011-05-26 01:26:41 +0100581 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
582 return CallJsBuiltin(isolate, "ArrayShift", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100583 }
Iain Merrick75681382010-08-19 15:07:18 +0100584 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100585 JSArray* array = JSArray::cast(receiver);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000586 ASSERT(array->HasFastTypeElements());
Andrei Popescu402d9372010-02-26 13:31:12 +0000587
588 int len = Smi::cast(array->length())->value();
Steve Block44f0eee2011-05-26 01:26:41 +0100589 if (len == 0) return heap->undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000590
Andrei Popescu402d9372010-02-26 13:31:12 +0000591 // Get first element
592 Object* first = elms->get(0);
593 if (first->IsTheHole()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100594 first = heap->undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000595 }
596
Steve Block44f0eee2011-05-26 01:26:41 +0100597 if (!heap->lo_space()->Contains(elms)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000598 array->set_elements(LeftTrimFixedArray(heap, elms, 1));
Steve Block6ded16b2010-05-10 14:33:55 +0100599 } else {
600 // Shift the elements.
601 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100602 MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
603 elms->set(len - 1, heap->the_hole_value());
Andrei Popescu402d9372010-02-26 13:31:12 +0000604 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000605
606 // Set the length.
607 array->set_length(Smi::FromInt(len - 1));
608
609 return first;
610}
611
612
613BUILTIN(ArrayUnshift) {
Steve Block44f0eee2011-05-26 01:26:41 +0100614 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100615 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700616 Object* elms_obj;
617 { MaybeObject* maybe_elms_obj =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000618 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100619 if (maybe_elms_obj == NULL)
620 return CallJsBuiltin(isolate, "ArrayUnshift", args);
John Reck59135872010-11-02 12:39:01 -0700621 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
622 }
Steve Block44f0eee2011-05-26 01:26:41 +0100623 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
624 return CallJsBuiltin(isolate, "ArrayUnshift", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100625 }
Iain Merrick75681382010-08-19 15:07:18 +0100626 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100627 JSArray* array = JSArray::cast(receiver);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000628 ASSERT(array->HasFastTypeElements());
Andrei Popescu402d9372010-02-26 13:31:12 +0000629
630 int len = Smi::cast(array->length())->value();
631 int to_add = args.length() - 1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000632 int new_length = len + to_add;
633 // Currently fixed arrays cannot grow too big, so
634 // we should never hit this case.
635 ASSERT(to_add <= (Smi::kMaxValue - len));
636
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000637 MaybeObject* maybe_object =
Ben Murdochc7cc0282012-03-05 14:35:55 +0000638 array->EnsureCanContainElements(&args, 1, to_add,
639 DONT_ALLOW_DOUBLE_ELEMENTS);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000640 if (maybe_object->IsFailure()) return maybe_object;
641
Andrei Popescu402d9372010-02-26 13:31:12 +0000642 if (new_length > elms->length()) {
643 // New backing storage is needed.
644 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700645 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100646 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
John Reck59135872010-11-02 12:39:01 -0700647 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
648 }
Steve Block6ded16b2010-05-10 14:33:55 +0100649 FixedArray* new_elms = FixedArray::cast(obj);
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100650 CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
651 new_elms, FAST_ELEMENTS, to_add, len);
Steve Block44f0eee2011-05-26 01:26:41 +0100652 FillWithHoles(heap, new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000653 elms = new_elms;
654 array->set_elements(elms);
655 } else {
656 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100657 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000658 }
659
660 // Add the provided values.
661 AssertNoAllocation no_gc;
662 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
663 for (int i = 0; i < to_add; i++) {
664 elms->set(i, args[i + 1], mode);
665 }
666
667 // Set the length.
668 array->set_length(Smi::FromInt(new_length));
669 return Smi::FromInt(new_length);
670}
671
672
Andrei Popescu402d9372010-02-26 13:31:12 +0000673BUILTIN(ArraySlice) {
Steve Block44f0eee2011-05-26 01:26:41 +0100674 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100675 Object* receiver = *args.receiver();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100676 FixedArray* elms;
677 int len = -1;
Steve Block9fac8402011-05-12 15:51:54 +0100678 if (receiver->IsJSArray()) {
679 JSArray* array = JSArray::cast(receiver);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000680 if (!array->HasFastTypeElements() ||
Steve Block44f0eee2011-05-26 01:26:41 +0100681 !IsJSArrayFastElementMovingAllowed(heap, array)) {
682 return CallJsBuiltin(isolate, "ArraySlice", args);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100683 }
Steve Block9fac8402011-05-12 15:51:54 +0100684
685 elms = FixedArray::cast(array->elements());
686 len = Smi::cast(array->length())->value();
687 } else {
688 // Array.slice(arguments, ...) is quite a common idiom (notably more
689 // than 50% of invocations in Web apps). Treat it in C++ as well.
690 Map* arguments_map =
Steve Block44f0eee2011-05-26 01:26:41 +0100691 isolate->context()->global_context()->arguments_boilerplate()->map();
Steve Block9fac8402011-05-12 15:51:54 +0100692
693 bool is_arguments_object_with_fast_elements =
694 receiver->IsJSObject()
695 && JSObject::cast(receiver)->map() == arguments_map
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000696 && JSObject::cast(receiver)->HasFastTypeElements();
Steve Block9fac8402011-05-12 15:51:54 +0100697 if (!is_arguments_object_with_fast_elements) {
Steve Block44f0eee2011-05-26 01:26:41 +0100698 return CallJsBuiltin(isolate, "ArraySlice", args);
Steve Block9fac8402011-05-12 15:51:54 +0100699 }
700 elms = FixedArray::cast(JSObject::cast(receiver)->elements());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100701 Object* len_obj = JSObject::cast(receiver)
Steve Block44f0eee2011-05-26 01:26:41 +0100702 ->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100703 if (!len_obj->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100704 return CallJsBuiltin(isolate, "ArraySlice", args);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100705 }
706 len = Smi::cast(len_obj)->value();
707 if (len > elms->length()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100708 return CallJsBuiltin(isolate, "ArraySlice", args);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100709 }
710 for (int i = 0; i < len; i++) {
Steve Block44f0eee2011-05-26 01:26:41 +0100711 if (elms->get(i) == heap->the_hole_value()) {
712 return CallJsBuiltin(isolate, "ArraySlice", args);
Steve Block9fac8402011-05-12 15:51:54 +0100713 }
714 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100715 }
716 ASSERT(len >= 0);
Andrei Popescu402d9372010-02-26 13:31:12 +0000717 int n_arguments = args.length() - 1;
718
719 // Note carefully choosen defaults---if argument is missing,
Steve Block6ded16b2010-05-10 14:33:55 +0100720 // it's undefined which gets converted to 0 for relative_start
721 // and to len for relative_end.
722 int relative_start = 0;
723 int relative_end = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000724 if (n_arguments > 0) {
725 Object* arg1 = args[1];
726 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100727 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000728 } else if (!arg1->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100729 return CallJsBuiltin(isolate, "ArraySlice", args);
Andrei Popescu402d9372010-02-26 13:31:12 +0000730 }
731 if (n_arguments > 1) {
732 Object* arg2 = args[2];
733 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100734 relative_end = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000735 } else if (!arg2->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100736 return CallJsBuiltin(isolate, "ArraySlice", args);
Andrei Popescu402d9372010-02-26 13:31:12 +0000737 }
738 }
739 }
740
741 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
Steve Block6ded16b2010-05-10 14:33:55 +0100742 int k = (relative_start < 0) ? Max(len + relative_start, 0)
743 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000744
745 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
Steve Block6ded16b2010-05-10 14:33:55 +0100746 int final = (relative_end < 0) ? Max(len + relative_end, 0)
747 : Min(relative_end, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000748
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000749 ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100750
751 // Calculate the length of result array.
752 int result_len = Max(final - k, 0);
753
754 MaybeObject* maybe_array =
755 heap->AllocateJSArrayAndStorage(elements_kind,
756 result_len,
757 result_len);
758 JSArray* result_array;
759 if (!maybe_array->To(&result_array)) return maybe_array;
760
761 CopyObjectToObjectElements(elms, FAST_ELEMENTS, k,
762 FixedArray::cast(result_array->elements()),
763 FAST_ELEMENTS, 0, result_len);
764
Andrei Popescu402d9372010-02-26 13:31:12 +0000765 return result_array;
766}
767
768
769BUILTIN(ArraySplice) {
Steve Block44f0eee2011-05-26 01:26:41 +0100770 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100771 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700772 Object* elms_obj;
773 { MaybeObject* maybe_elms_obj =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000774 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
Steve Block44f0eee2011-05-26 01:26:41 +0100775 if (maybe_elms_obj == NULL)
776 return CallJsBuiltin(isolate, "ArraySplice", args);
John Reck59135872010-11-02 12:39:01 -0700777 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
778 }
Steve Block44f0eee2011-05-26 01:26:41 +0100779 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
780 return CallJsBuiltin(isolate, "ArraySplice", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100781 }
Iain Merrick75681382010-08-19 15:07:18 +0100782 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100783 JSArray* array = JSArray::cast(receiver);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000784 ASSERT(array->HasFastTypeElements());
Andrei Popescu402d9372010-02-26 13:31:12 +0000785
786 int len = Smi::cast(array->length())->value();
787
788 int n_arguments = args.length() - 1;
789
Steve Block6ded16b2010-05-10 14:33:55 +0100790 int relative_start = 0;
Steve Block1e0659c2011-05-24 12:43:12 +0100791 if (n_arguments > 0) {
792 Object* arg1 = args[1];
793 if (arg1->IsSmi()) {
794 relative_start = Smi::cast(arg1)->value();
795 } else if (!arg1->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100796 return CallJsBuiltin(isolate, "ArraySplice", args);
Steve Block1e0659c2011-05-24 12:43:12 +0100797 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000798 }
Steve Block6ded16b2010-05-10 14:33:55 +0100799 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
800 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000801
802 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
Steve Block1e0659c2011-05-24 12:43:12 +0100803 // given as a request to delete all the elements from the start.
804 // And it differs from the case of undefined delete count.
Andrei Popescu402d9372010-02-26 13:31:12 +0000805 // This does not follow ECMA-262, but we do the same for
806 // compatibility.
Steve Block1e0659c2011-05-24 12:43:12 +0100807 int actual_delete_count;
808 if (n_arguments == 1) {
809 ASSERT(len - actual_start >= 0);
810 actual_delete_count = len - actual_start;
811 } else {
812 int value = 0; // ToInteger(undefined) == 0
813 if (n_arguments > 1) {
814 Object* arg2 = args[2];
815 if (arg2->IsSmi()) {
816 value = Smi::cast(arg2)->value();
817 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100818 return CallJsBuiltin(isolate, "ArraySplice", args);
Steve Block1e0659c2011-05-24 12:43:12 +0100819 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000820 }
Steve Block1e0659c2011-05-24 12:43:12 +0100821 actual_delete_count = Min(Max(value, 0), len - actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000822 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000823
Steve Block6ded16b2010-05-10 14:33:55 +0100824 JSArray* result_array = NULL;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100825 ElementsKind elements_kind =
826 JSObject::cast(receiver)->GetElementsKind();
827 MaybeObject* maybe_array =
828 heap->AllocateJSArrayAndStorage(elements_kind,
829 actual_delete_count,
830 actual_delete_count);
831 if (!maybe_array->To(&result_array)) return maybe_array;
Andrei Popescu402d9372010-02-26 13:31:12 +0000832
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100833 {
Steve Block6ded16b2010-05-10 14:33:55 +0100834 // Fill newly created array.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100835 CopyObjectToObjectElements(elms, FAST_ELEMENTS, actual_start,
836 FixedArray::cast(result_array->elements()),
837 FAST_ELEMENTS, 0, actual_delete_count);
Andrei Popescu402d9372010-02-26 13:31:12 +0000838 }
839
Steve Block6ded16b2010-05-10 14:33:55 +0100840 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100841 int new_length = len - actual_delete_count + item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000842
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000843 bool elms_changed = false;
Steve Block6ded16b2010-05-10 14:33:55 +0100844 if (item_count < actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000845 // Shrink the array.
Steve Block44f0eee2011-05-26 01:26:41 +0100846 const bool trim_array = !heap->lo_space()->Contains(elms) &&
Steve Block6ded16b2010-05-10 14:33:55 +0100847 ((actual_start + item_count) <
848 (len - actual_delete_count - actual_start));
849 if (trim_array) {
850 const int delta = actual_delete_count - item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000851
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100852 {
Steve Block053d10c2011-06-13 19:13:29 +0100853 AssertNoAllocation no_gc;
854 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
Steve Block6ded16b2010-05-10 14:33:55 +0100855 }
856
Steve Block44f0eee2011-05-26 01:26:41 +0100857 elms = LeftTrimFixedArray(heap, elms, delta);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000858
859 elms_changed = true;
Steve Block6ded16b2010-05-10 14:33:55 +0100860 } else {
861 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100862 MoveElements(heap, &no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100863 elms, actual_start + item_count,
864 elms, actual_start + actual_delete_count,
865 (len - actual_delete_count - actual_start));
Steve Block44f0eee2011-05-26 01:26:41 +0100866 FillWithHoles(heap, elms, new_length, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000867 }
Steve Block6ded16b2010-05-10 14:33:55 +0100868 } else if (item_count > actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000869 // Currently fixed arrays cannot grow too big, so
870 // we should never hit this case.
Steve Block6ded16b2010-05-10 14:33:55 +0100871 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
Andrei Popescu402d9372010-02-26 13:31:12 +0000872
873 // Check if array need to grow.
874 if (new_length > elms->length()) {
875 // New backing storage is needed.
876 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700877 Object* obj;
878 { MaybeObject* maybe_obj =
Steve Block44f0eee2011-05-26 01:26:41 +0100879 heap->AllocateUninitializedFixedArray(capacity);
John Reck59135872010-11-02 12:39:01 -0700880 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
881 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000882 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000883
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100884 {
885 // Copy the part before actual_start as is.
886 CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
887 new_elms, FAST_ELEMENTS, 0, actual_start);
888 const int to_copy = len - actual_delete_count - actual_start;
889 CopyObjectToObjectElements(elms, FAST_ELEMENTS,
890 actual_start + actual_delete_count,
891 new_elms, FAST_ELEMENTS,
892 actual_start + item_count, to_copy);
Andrei Popescu402d9372010-02-26 13:31:12 +0000893 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100894
Steve Block44f0eee2011-05-26 01:26:41 +0100895 FillWithHoles(heap, new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000896
Andrei Popescu402d9372010-02-26 13:31:12 +0000897 elms = new_elms;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000898 elms_changed = true;
Steve Block6ded16b2010-05-10 14:33:55 +0100899 } else {
900 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100901 MoveElements(heap, &no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100902 elms, actual_start + item_count,
903 elms, actual_start + actual_delete_count,
904 (len - actual_delete_count - actual_start));
Andrei Popescu402d9372010-02-26 13:31:12 +0000905 }
906 }
907
Steve Block6ded16b2010-05-10 14:33:55 +0100908 AssertNoAllocation no_gc;
909 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
910 for (int k = actual_start; k < actual_start + item_count; k++) {
911 elms->set(k, args[3 + k - actual_start], mode);
Andrei Popescu402d9372010-02-26 13:31:12 +0000912 }
913
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000914 if (elms_changed) {
915 array->set_elements(elms);
916 }
917
Andrei Popescu402d9372010-02-26 13:31:12 +0000918 // Set the length.
919 array->set_length(Smi::FromInt(new_length));
920
921 return result_array;
922}
923
924
Steve Block6ded16b2010-05-10 14:33:55 +0100925BUILTIN(ArrayConcat) {
Steve Block44f0eee2011-05-26 01:26:41 +0100926 Heap* heap = isolate->heap();
927 Context* global_context = isolate->context()->global_context();
Kristian Monsen25f61362010-05-21 11:50:48 +0100928 JSObject* array_proto =
929 JSObject::cast(global_context->array_function()->prototype());
Steve Block44f0eee2011-05-26 01:26:41 +0100930 if (!ArrayPrototypeHasNoElements(heap, global_context, array_proto)) {
931 return CallJsBuiltin(isolate, "ArrayConcat", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100932 }
933
934 // Iterate through all the arguments performing checks
935 // and calculating total length.
936 int n_arguments = args.length();
937 int result_len = 0;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100938 ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS;
Steve Block6ded16b2010-05-10 14:33:55 +0100939 for (int i = 0; i < n_arguments; i++) {
940 Object* arg = args[i];
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000941 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastTypeElements()
Kristian Monsen25f61362010-05-21 11:50:48 +0100942 || JSArray::cast(arg)->GetPrototype() != array_proto) {
Steve Block44f0eee2011-05-26 01:26:41 +0100943 return CallJsBuiltin(isolate, "ArrayConcat", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100944 }
945
946 int len = Smi::cast(JSArray::cast(arg)->length())->value();
947
948 // We shouldn't overflow when adding another len.
949 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
950 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
951 USE(kHalfOfMaxInt);
952 result_len += len;
953 ASSERT(result_len >= 0);
954
955 if (result_len > FixedArray::kMaxLength) {
Steve Block44f0eee2011-05-26 01:26:41 +0100956 return CallJsBuiltin(isolate, "ArrayConcat", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100957 }
Steve Block6ded16b2010-05-10 14:33:55 +0100958
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100959 if (!JSArray::cast(arg)->HasFastSmiOnlyElements()) {
960 elements_kind = FAST_ELEMENTS;
961 }
Steve Block6ded16b2010-05-10 14:33:55 +0100962 }
963
964 // Allocate result.
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100965 JSArray* result_array;
966 MaybeObject* maybe_array =
967 heap->AllocateJSArrayAndStorage(elements_kind,
968 result_len,
969 result_len);
970 if (!maybe_array->To(&result_array)) return maybe_array;
971 if (result_len == 0) return result_array;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000972
Steve Block6ded16b2010-05-10 14:33:55 +0100973 // Copy data.
Steve Block6ded16b2010-05-10 14:33:55 +0100974 int start_pos = 0;
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100975 FixedArray* result_elms(FixedArray::cast(result_array->elements()));
Steve Block6ded16b2010-05-10 14:33:55 +0100976 for (int i = 0; i < n_arguments; i++) {
977 JSArray* array = JSArray::cast(args[i]);
978 int len = Smi::cast(array->length())->value();
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +0100979 FixedArray* elms = FixedArray::cast(array->elements());
980 CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
981 result_elms, FAST_ELEMENTS,
982 start_pos, len);
983 start_pos += len;
Steve Block6ded16b2010-05-10 14:33:55 +0100984 }
985 ASSERT(start_pos == result_len);
986
Steve Block6ded16b2010-05-10 14:33:55 +0100987 return result_array;
988}
989
990
Steve Blocka7e24c12009-10-30 11:49:00 +0000991// -----------------------------------------------------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100992// Strict mode poison pills
993
994
Ben Murdoch257744e2011-11-30 15:57:28 +0000995BUILTIN(StrictModePoisonPill) {
Steve Block44f0eee2011-05-26 01:26:41 +0100996 HandleScope scope;
997 return isolate->Throw(*isolate->factory()->NewTypeError(
Ben Murdoch257744e2011-11-30 15:57:28 +0000998 "strict_poison_pill", HandleVector<Object>(NULL, 0)));
Steve Block44f0eee2011-05-26 01:26:41 +0100999}
1000
Steve Block44f0eee2011-05-26 01:26:41 +01001001// -----------------------------------------------------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001002//
1003
1004
1005// Returns the holder JSObject if the function can legally be called
1006// with this receiver. Returns Heap::null_value() if the call is
1007// illegal. Any arguments that don't fit the expected type is
1008// overwritten with undefined. Arguments that do fit the expected
1009// type is overwritten with the object in the prototype chain that
1010// actually has that type.
Steve Block44f0eee2011-05-26 01:26:41 +01001011static inline Object* TypeCheck(Heap* heap,
1012 int argc,
Steve Blocka7e24c12009-10-30 11:49:00 +00001013 Object** argv,
1014 FunctionTemplateInfo* info) {
1015 Object* recv = argv[0];
Ben Murdoch257744e2011-11-30 15:57:28 +00001016 // API calls are only supported with JSObject receivers.
1017 if (!recv->IsJSObject()) return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001018 Object* sig_obj = info->signature();
1019 if (sig_obj->IsUndefined()) return recv;
1020 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
1021 // If necessary, check the receiver
1022 Object* recv_type = sig->receiver();
1023
1024 Object* holder = recv;
1025 if (!recv_type->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001026 for (; holder != heap->null_value(); holder = holder->GetPrototype()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001027 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
1028 break;
1029 }
1030 }
Steve Block44f0eee2011-05-26 01:26:41 +01001031 if (holder == heap->null_value()) return holder;
Steve Blocka7e24c12009-10-30 11:49:00 +00001032 }
1033 Object* args_obj = sig->args();
1034 // If there is no argument signature we're done
1035 if (args_obj->IsUndefined()) return holder;
1036 FixedArray* args = FixedArray::cast(args_obj);
1037 int length = args->length();
1038 if (argc <= length) length = argc - 1;
1039 for (int i = 0; i < length; i++) {
1040 Object* argtype = args->get(i);
1041 if (argtype->IsUndefined()) continue;
1042 Object** arg = &argv[-1 - i];
1043 Object* current = *arg;
Steve Block44f0eee2011-05-26 01:26:41 +01001044 for (; current != heap->null_value(); current = current->GetPrototype()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001045 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
1046 *arg = current;
1047 break;
1048 }
1049 }
Steve Block44f0eee2011-05-26 01:26:41 +01001050 if (current == heap->null_value()) *arg = heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001051 }
1052 return holder;
1053}
1054
1055
Leon Clarkee46be812010-01-19 14:06:41 +00001056template <bool is_construct>
John Reck59135872010-11-02 12:39:01 -07001057MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
Steve Block44f0eee2011-05-26 01:26:41 +01001058 BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
1059 ASSERT(is_construct == CalledAsConstructor(isolate));
1060 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001061
Steve Block44f0eee2011-05-26 01:26:41 +01001062 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00001063 Handle<JSFunction> function = args.called_function();
Steve Block6ded16b2010-05-10 14:33:55 +01001064 ASSERT(function->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001065
Steve Block6ded16b2010-05-10 14:33:55 +01001066 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
Steve Blocka7e24c12009-10-30 11:49:00 +00001067 if (is_construct) {
Steve Block44f0eee2011-05-26 01:26:41 +01001068 Handle<FunctionTemplateInfo> desc(fun_data, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001069 bool pending_exception = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001070 isolate->factory()->ConfigureInstance(
1071 desc, Handle<JSObject>::cast(args.receiver()), &pending_exception);
1072 ASSERT(isolate->has_pending_exception() == pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +00001073 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +01001074 fun_data = *desc;
Steve Blocka7e24c12009-10-30 11:49:00 +00001075 }
1076
Steve Block44f0eee2011-05-26 01:26:41 +01001077 Object* raw_holder = TypeCheck(heap, args.length(), &args[0], fun_data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001078
1079 if (raw_holder->IsNull()) {
1080 // This function cannot be called with the given receiver. Abort!
1081 Handle<Object> obj =
Steve Block44f0eee2011-05-26 01:26:41 +01001082 isolate->factory()->NewTypeError(
1083 "illegal_invocation", HandleVector(&function, 1));
1084 return isolate->Throw(*obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00001085 }
1086
1087 Object* raw_call_data = fun_data->call_code();
1088 if (!raw_call_data->IsUndefined()) {
1089 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1090 Object* callback_obj = call_data->callback();
1091 v8::InvocationCallback callback =
1092 v8::ToCData<v8::InvocationCallback>(callback_obj);
1093 Object* data_obj = call_data->data();
1094 Object* result;
1095
Steve Block44f0eee2011-05-26 01:26:41 +01001096 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001097 ASSERT(raw_holder->IsJSObject());
1098
Steve Block44f0eee2011-05-26 01:26:41 +01001099 CustomArguments custom(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001100 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1101 data_obj, *function, raw_holder);
1102
Steve Blocka7e24c12009-10-30 11:49:00 +00001103 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001104 custom.end(),
1105 &args[0] - 1,
1106 args.length() - 1,
1107 is_construct);
Steve Blocka7e24c12009-10-30 11:49:00 +00001108
1109 v8::Handle<v8::Value> value;
1110 {
1111 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001112 VMState state(isolate, EXTERNAL);
1113 ExternalCallbackScope call_scope(isolate,
1114 v8::ToCData<Address>(callback_obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00001115 value = callback(new_args);
1116 }
1117 if (value.IsEmpty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001118 result = heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001119 } else {
1120 result = *reinterpret_cast<Object**>(*value);
1121 }
1122
Steve Block44f0eee2011-05-26 01:26:41 +01001123 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001124 if (!is_construct || result->IsJSObject()) return result;
1125 }
1126
Leon Clarkee46be812010-01-19 14:06:41 +00001127 return *args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +00001128}
Leon Clarkee46be812010-01-19 14:06:41 +00001129
1130
1131BUILTIN(HandleApiCall) {
Steve Block44f0eee2011-05-26 01:26:41 +01001132 return HandleApiCallHelper<false>(args, isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00001133}
1134
1135
1136BUILTIN(HandleApiCallConstruct) {
Steve Block44f0eee2011-05-26 01:26:41 +01001137 return HandleApiCallHelper<true>(args, isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00001138}
Steve Blocka7e24c12009-10-30 11:49:00 +00001139
1140
Andrei Popescu402d9372010-02-26 13:31:12 +00001141#ifdef DEBUG
1142
1143static void VerifyTypeCheck(Handle<JSObject> object,
1144 Handle<JSFunction> function) {
Steve Block6ded16b2010-05-10 14:33:55 +01001145 ASSERT(function->shared()->IsApiFunction());
1146 FunctionTemplateInfo* info = function->shared()->get_api_func_data();
Andrei Popescu402d9372010-02-26 13:31:12 +00001147 if (info->signature()->IsUndefined()) return;
1148 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1149 Object* receiver_type = signature->receiver();
1150 if (receiver_type->IsUndefined()) return;
1151 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
1152 ASSERT(object->IsInstanceOf(type));
1153}
1154
1155#endif
1156
1157
1158BUILTIN(FastHandleApiCall) {
Steve Block44f0eee2011-05-26 01:26:41 +01001159 ASSERT(!CalledAsConstructor(isolate));
1160 Heap* heap = isolate->heap();
Andrei Popescu402d9372010-02-26 13:31:12 +00001161 const bool is_construct = false;
1162
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001163 // We expect four more arguments: callback, function, call data, and holder.
Andrei Popescu402d9372010-02-26 13:31:12 +00001164 const int args_length = args.length() - 4;
1165 ASSERT(args_length >= 0);
1166
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001167 Object* callback_obj = args[args_length];
Andrei Popescu402d9372010-02-26 13:31:12 +00001168
1169 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001170 &args[args_length + 1],
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001171 &args[0] - 1,
1172 args_length - 1,
1173 is_construct);
Andrei Popescu402d9372010-02-26 13:31:12 +00001174
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001175#ifdef DEBUG
1176 VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()),
1177 Utils::OpenHandle(*new_args.Callee()));
1178#endif
Steve Block44f0eee2011-05-26 01:26:41 +01001179 HandleScope scope(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00001180 Object* result;
1181 v8::Handle<v8::Value> value;
1182 {
1183 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001184 VMState state(isolate, EXTERNAL);
1185 ExternalCallbackScope call_scope(isolate,
1186 v8::ToCData<Address>(callback_obj));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001187 v8::InvocationCallback callback =
1188 v8::ToCData<v8::InvocationCallback>(callback_obj);
1189
Andrei Popescu402d9372010-02-26 13:31:12 +00001190 value = callback(new_args);
1191 }
1192 if (value.IsEmpty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001193 result = heap->undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00001194 } else {
1195 result = *reinterpret_cast<Object**>(*value);
1196 }
1197
Steve Block44f0eee2011-05-26 01:26:41 +01001198 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00001199 return result;
1200}
1201
1202
Steve Blocka7e24c12009-10-30 11:49:00 +00001203// Helper function to handle calls to non-function objects created through the
1204// API. The object can be called as either a constructor (using new) or just as
1205// a function (without new).
John Reck59135872010-11-02 12:39:01 -07001206MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
Steve Block44f0eee2011-05-26 01:26:41 +01001207 Isolate* isolate,
Leon Clarkee46be812010-01-19 14:06:41 +00001208 bool is_construct_call,
1209 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001210 // Non-functions are never called as constructors. Even if this is an object
1211 // called as a constructor the delegate call is not a construct call.
Steve Block44f0eee2011-05-26 01:26:41 +01001212 ASSERT(!CalledAsConstructor(isolate));
1213 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001214
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001215 Handle<Object> receiver = args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +00001216
1217 // Get the object called.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001218 JSObject* obj = JSObject::cast(*receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00001219
1220 // Get the invocation callback from the function descriptor that was
1221 // used to create the called object.
1222 ASSERT(obj->map()->has_instance_call_handler());
1223 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01001224 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001225 Object* handler =
Steve Block6ded16b2010-05-10 14:33:55 +01001226 constructor->shared()->get_api_func_data()->instance_call_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00001227 ASSERT(!handler->IsUndefined());
1228 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1229 Object* callback_obj = call_data->callback();
1230 v8::InvocationCallback callback =
1231 v8::ToCData<v8::InvocationCallback>(callback_obj);
1232
1233 // Get the data for the call and perform the callback.
Steve Blocka7e24c12009-10-30 11:49:00 +00001234 Object* result;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001235 {
Steve Block44f0eee2011-05-26 01:26:41 +01001236 HandleScope scope(isolate);
1237 LOG(isolate, ApiObjectAccess("call non-function", obj));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001238
Steve Block44f0eee2011-05-26 01:26:41 +01001239 CustomArguments custom(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001240 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1241 call_data->data(), constructor, obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00001242 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001243 custom.end(),
1244 &args[0] - 1,
1245 args.length() - 1,
1246 is_construct_call);
Steve Blocka7e24c12009-10-30 11:49:00 +00001247 v8::Handle<v8::Value> value;
1248 {
1249 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001250 VMState state(isolate, EXTERNAL);
1251 ExternalCallbackScope call_scope(isolate,
1252 v8::ToCData<Address>(callback_obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00001253 value = callback(new_args);
1254 }
1255 if (value.IsEmpty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001256 result = heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001257 } else {
1258 result = *reinterpret_cast<Object**>(*value);
1259 }
1260 }
1261 // Check for exceptions and return result.
Steve Block44f0eee2011-05-26 01:26:41 +01001262 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001263 return result;
1264}
1265
1266
1267// Handle calls to non-function objects created through the API. This delegate
1268// function is used when the call is a normal function call.
1269BUILTIN(HandleApiCallAsFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +01001270 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001271}
Steve Blocka7e24c12009-10-30 11:49:00 +00001272
1273
1274// Handle calls to non-function objects created through the API. This delegate
1275// function is used when the call is a construct call.
1276BUILTIN(HandleApiCallAsConstructor) {
Steve Block44f0eee2011-05-26 01:26:41 +01001277 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001278}
Steve Blocka7e24c12009-10-30 11:49:00 +00001279
1280
1281static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1282 LoadIC::GenerateArrayLength(masm);
1283}
1284
1285
1286static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
Steve Block1e0659c2011-05-24 12:43:12 +01001287 LoadIC::GenerateStringLength(masm, false);
1288}
1289
1290
1291static void Generate_LoadIC_StringWrapperLength(MacroAssembler* masm) {
1292 LoadIC::GenerateStringLength(masm, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001293}
1294
1295
1296static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1297 LoadIC::GenerateFunctionPrototype(masm);
1298}
1299
1300
1301static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1302 LoadIC::GenerateInitialize(masm);
1303}
1304
1305
1306static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1307 LoadIC::GeneratePreMonomorphic(masm);
1308}
1309
1310
1311static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1312 LoadIC::GenerateMiss(masm);
1313}
1314
1315
1316static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1317 LoadIC::GenerateMegamorphic(masm);
1318}
1319
1320
1321static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1322 LoadIC::GenerateNormal(masm);
1323}
1324
1325
1326static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1327 KeyedLoadIC::GenerateInitialize(masm);
1328}
1329
1330
Ben Murdoch257744e2011-11-30 15:57:28 +00001331static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
1332 KeyedLoadIC::GenerateRuntimeGetProperty(masm);
1333}
1334
1335
Steve Blocka7e24c12009-10-30 11:49:00 +00001336static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001337 KeyedLoadIC::GenerateMiss(masm, false);
1338}
1339
1340
1341static void Generate_KeyedLoadIC_MissForceGeneric(MacroAssembler* masm) {
1342 KeyedLoadIC::GenerateMiss(masm, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001343}
1344
1345
1346static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1347 KeyedLoadIC::GenerateGeneric(masm);
1348}
1349
1350
Leon Clarkee46be812010-01-19 14:06:41 +00001351static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1352 KeyedLoadIC::GenerateString(masm);
1353}
1354
1355
Steve Blocka7e24c12009-10-30 11:49:00 +00001356static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1357 KeyedLoadIC::GeneratePreMonomorphic(masm);
1358}
1359
Andrei Popescu402d9372010-02-26 13:31:12 +00001360static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1361 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1362}
1363
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001364static void Generate_KeyedLoadIC_NonStrictArguments(MacroAssembler* masm) {
1365 KeyedLoadIC::GenerateNonStrictArguments(masm);
1366}
Steve Blocka7e24c12009-10-30 11:49:00 +00001367
1368static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1369 StoreIC::GenerateInitialize(masm);
1370}
1371
1372
Steve Block1e0659c2011-05-24 12:43:12 +01001373static void Generate_StoreIC_Initialize_Strict(MacroAssembler* masm) {
1374 StoreIC::GenerateInitialize(masm);
1375}
1376
1377
Steve Blocka7e24c12009-10-30 11:49:00 +00001378static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1379 StoreIC::GenerateMiss(masm);
1380}
1381
1382
Steve Block8defd9f2010-07-08 12:39:36 +01001383static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1384 StoreIC::GenerateNormal(masm);
1385}
1386
1387
Steve Block1e0659c2011-05-24 12:43:12 +01001388static void Generate_StoreIC_Normal_Strict(MacroAssembler* masm) {
1389 StoreIC::GenerateNormal(masm);
1390}
1391
1392
Steve Blocka7e24c12009-10-30 11:49:00 +00001393static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001394 StoreIC::GenerateMegamorphic(masm, kNonStrictMode);
Steve Block1e0659c2011-05-24 12:43:12 +01001395}
1396
1397
1398static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001399 StoreIC::GenerateMegamorphic(masm, kStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001400}
1401
1402
Steve Block6ded16b2010-05-10 14:33:55 +01001403static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1404 StoreIC::GenerateArrayLength(masm);
1405}
1406
1407
Steve Block1e0659c2011-05-24 12:43:12 +01001408static void Generate_StoreIC_ArrayLength_Strict(MacroAssembler* masm) {
1409 StoreIC::GenerateArrayLength(masm);
1410}
1411
1412
Ben Murdochb0fe1622011-05-05 13:52:32 +01001413static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001414 StoreIC::GenerateGlobalProxy(masm, kNonStrictMode);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001415}
1416
1417
Steve Block1e0659c2011-05-24 12:43:12 +01001418static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001419 StoreIC::GenerateGlobalProxy(masm, kStrictMode);
Steve Block1e0659c2011-05-24 12:43:12 +01001420}
1421
1422
Steve Blocka7e24c12009-10-30 11:49:00 +00001423static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001424 KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode);
1425}
1426
1427
1428static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) {
1429 KeyedStoreIC::GenerateGeneric(masm, kStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001430}
1431
1432
Steve Blocka7e24c12009-10-30 11:49:00 +00001433static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001434 KeyedStoreIC::GenerateMiss(masm, false);
1435}
1436
1437
1438static void Generate_KeyedStoreIC_MissForceGeneric(MacroAssembler* masm) {
1439 KeyedStoreIC::GenerateMiss(masm, true);
1440}
1441
1442
1443static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
1444 KeyedStoreIC::GenerateSlow(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001445}
1446
1447
1448static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1449 KeyedStoreIC::GenerateInitialize(masm);
1450}
1451
1452
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001453static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
1454 KeyedStoreIC::GenerateInitialize(masm);
1455}
1456
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001457static void Generate_KeyedStoreIC_NonStrictArguments(MacroAssembler* masm) {
1458 KeyedStoreIC::GenerateNonStrictArguments(masm);
1459}
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001460
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001461static void Generate_TransitionElementsSmiToDouble(MacroAssembler* masm) {
1462 KeyedStoreIC::GenerateTransitionElementsSmiToDouble(masm);
1463}
1464
1465static void Generate_TransitionElementsDoubleToObject(MacroAssembler* masm) {
1466 KeyedStoreIC::GenerateTransitionElementsDoubleToObject(masm);
1467}
1468
Steve Blocka7e24c12009-10-30 11:49:00 +00001469#ifdef ENABLE_DEBUGGER_SUPPORT
1470static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1471 Debug::GenerateLoadICDebugBreak(masm);
1472}
1473
1474
1475static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1476 Debug::GenerateStoreICDebugBreak(masm);
1477}
1478
1479
1480static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1481 Debug::GenerateKeyedLoadICDebugBreak(masm);
1482}
1483
1484
1485static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1486 Debug::GenerateKeyedStoreICDebugBreak(masm);
1487}
1488
1489
Steve Blocka7e24c12009-10-30 11:49:00 +00001490static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1491 Debug::GenerateReturnDebugBreak(masm);
1492}
1493
1494
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001495static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) {
1496 Debug::GenerateCallFunctionStubDebugBreak(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001497}
Steve Block6ded16b2010-05-10 14:33:55 +01001498
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001499
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001500static void Generate_CallFunctionStub_Recording_DebugBreak(
1501 MacroAssembler* masm) {
1502 Debug::GenerateCallFunctionStubRecordDebugBreak(masm);
1503}
1504
1505
1506static void Generate_CallConstructStub_DebugBreak(MacroAssembler* masm) {
1507 Debug::GenerateCallConstructStubDebugBreak(masm);
1508}
1509
1510
1511static void Generate_CallConstructStub_Recording_DebugBreak(
1512 MacroAssembler* masm) {
1513 Debug::GenerateCallConstructStubRecordDebugBreak(masm);
1514}
1515
1516
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001517static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1518 Debug::GenerateSlotDebugBreak(masm);
1519}
1520
1521
Steve Block6ded16b2010-05-10 14:33:55 +01001522static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1523 Debug::GeneratePlainReturnLiveEdit(masm);
1524}
1525
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001526
Steve Block6ded16b2010-05-10 14:33:55 +01001527static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1528 Debug::GenerateFrameDropperLiveEdit(masm);
1529}
Steve Blocka7e24c12009-10-30 11:49:00 +00001530#endif
1531
Steve Block44f0eee2011-05-26 01:26:41 +01001532
1533Builtins::Builtins() : initialized_(false) {
1534 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
1535 memset(names_, 0, sizeof(names_[0]) * builtin_count);
1536}
1537
1538
1539Builtins::~Builtins() {
1540}
1541
Steve Blocka7e24c12009-10-30 11:49:00 +00001542
Leon Clarkee46be812010-01-19 14:06:41 +00001543#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Steve Block44f0eee2011-05-26 01:26:41 +01001544Address const Builtins::c_functions_[cfunction_count] = {
1545 BUILTIN_LIST_C(DEF_ENUM_C)
1546};
Steve Blocka7e24c12009-10-30 11:49:00 +00001547#undef DEF_ENUM_C
1548
1549#define DEF_JS_NAME(name, ignore) #name,
1550#define DEF_JS_ARGC(ignore, argc) argc,
Steve Block44f0eee2011-05-26 01:26:41 +01001551const char* const Builtins::javascript_names_[id_count] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00001552 BUILTINS_LIST_JS(DEF_JS_NAME)
1553};
1554
Steve Block44f0eee2011-05-26 01:26:41 +01001555int const Builtins::javascript_argc_[id_count] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00001556 BUILTINS_LIST_JS(DEF_JS_ARGC)
1557};
1558#undef DEF_JS_NAME
1559#undef DEF_JS_ARGC
1560
Steve Block44f0eee2011-05-26 01:26:41 +01001561struct BuiltinDesc {
1562 byte* generator;
1563 byte* c_code;
1564 const char* s_name; // name is only used for generating log information.
1565 int name;
1566 Code::Flags flags;
1567 BuiltinExtraArguments extra_args;
1568};
1569
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001570#define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} }
1571
Steve Block44f0eee2011-05-26 01:26:41 +01001572class BuiltinFunctionTable {
1573 public:
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001574 BuiltinDesc* functions() {
1575 CallOnce(&once_, &Builtins::InitBuiltinFunctionTable);
1576 return functions_;
Steve Block44f0eee2011-05-26 01:26:41 +01001577 }
1578
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001579 OnceType once_;
1580 BuiltinDesc functions_[Builtins::builtin_count + 1];
Steve Block44f0eee2011-05-26 01:26:41 +01001581
1582 friend class Builtins;
1583};
1584
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001585static BuiltinFunctionTable builtin_function_table =
1586 BUILTIN_FUNCTION_TABLE_INIT;
Steve Block44f0eee2011-05-26 01:26:41 +01001587
1588// Define array of pointers to generators and C builtin functions.
1589// We do this in a sort of roundabout way so that we can do the initialization
1590// within the lexical scope of Builtins:: and within a context where
1591// Code::Flags names a non-abstract type.
1592void Builtins::InitBuiltinFunctionTable() {
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001593 BuiltinDesc* functions = builtin_function_table.functions_;
Steve Block44f0eee2011-05-26 01:26:41 +01001594 functions[builtin_count].generator = NULL;
1595 functions[builtin_count].c_code = NULL;
1596 functions[builtin_count].s_name = NULL;
1597 functions[builtin_count].name = builtin_count;
1598 functions[builtin_count].flags = static_cast<Code::Flags>(0);
1599 functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
1600
1601#define DEF_FUNCTION_PTR_C(aname, aextra_args) \
1602 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
1603 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
1604 functions->s_name = #aname; \
1605 functions->name = c_##aname; \
1606 functions->flags = Code::ComputeFlags(Code::BUILTIN); \
1607 functions->extra_args = aextra_args; \
1608 ++functions;
1609
1610#define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
1611 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1612 functions->c_code = NULL; \
1613 functions->s_name = #aname; \
1614 functions->name = k##aname; \
1615 functions->flags = Code::ComputeFlags(Code::kind, \
Steve Block44f0eee2011-05-26 01:26:41 +01001616 state, \
1617 extra); \
1618 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1619 ++functions;
1620
1621 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1622 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1623 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1624
1625#undef DEF_FUNCTION_PTR_C
1626#undef DEF_FUNCTION_PTR_A
1627}
1628
Ben Murdochc7cc0282012-03-05 14:35:55 +00001629void Builtins::SetUp(bool create_heap_objects) {
Steve Block44f0eee2011-05-26 01:26:41 +01001630 ASSERT(!initialized_);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001631 Isolate* isolate = Isolate::Current();
1632 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001633
1634 // Create a scope for the handles in the builtins.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001635 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001636
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +01001637 const BuiltinDesc* functions = builtin_function_table.functions();
Steve Blocka7e24c12009-10-30 11:49:00 +00001638
1639 // For now we generate builtin adaptor code into a stack-allocated
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001640 // buffer, before copying it into individual code objects. Be careful
1641 // with alignment, some platforms don't like unaligned code.
1642 union { int force_alignment; byte buffer[4*KB]; } u;
Steve Blocka7e24c12009-10-30 11:49:00 +00001643
1644 // Traverse the list of builtins and generate an adaptor in a
1645 // separate code object for each one.
1646 for (int i = 0; i < builtin_count; i++) {
1647 if (create_heap_objects) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001648 MacroAssembler masm(isolate, u.buffer, sizeof u.buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00001649 // Generate the code/adaptor.
Leon Clarkee46be812010-01-19 14:06:41 +00001650 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001651 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1652 // We pass all arguments to the generator, but it may not use all of
1653 // them. This works because the first arguments are on top of the
1654 // stack.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001655 ASSERT(!masm.has_frame());
Leon Clarkee46be812010-01-19 14:06:41 +00001656 g(&masm, functions[i].name, functions[i].extra_args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001657 // Move the code into the object heap.
1658 CodeDesc desc;
1659 masm.GetCode(&desc);
1660 Code::Flags flags = functions[i].flags;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001661 Object* code = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00001662 {
1663 // During startup it's OK to always allocate and defer GC to later.
1664 // This simplifies things because we don't need to retry.
1665 AlwaysAllocateScope __scope__;
John Reck59135872010-11-02 12:39:01 -07001666 { MaybeObject* maybe_code =
Steve Block44f0eee2011-05-26 01:26:41 +01001667 heap->CreateCode(desc, flags, masm.CodeObject());
John Reck59135872010-11-02 12:39:01 -07001668 if (!maybe_code->ToObject(&code)) {
1669 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1670 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001671 }
1672 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001673 // Log the event and add the code to the builtins array.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001674 PROFILE(isolate,
Steve Block44f0eee2011-05-26 01:26:41 +01001675 CodeCreateEvent(Logger::BUILTIN_TAG,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001676 Code::cast(code),
1677 functions[i].s_name));
1678 GDBJIT(AddCode(GDBJITInterface::BUILTIN,
1679 functions[i].s_name,
1680 Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001681 builtins_[i] = code;
1682#ifdef ENABLE_DISASSEMBLER
1683 if (FLAG_print_builtin_code) {
1684 PrintF("Builtin: %s\n", functions[i].s_name);
1685 Code::cast(code)->Disassemble(functions[i].s_name);
1686 PrintF("\n");
1687 }
1688#endif
1689 } else {
1690 // Deserializing. The values will be filled in during IterateBuiltins.
1691 builtins_[i] = NULL;
1692 }
1693 names_[i] = functions[i].s_name;
1694 }
1695
1696 // Mark as initialized.
Steve Block44f0eee2011-05-26 01:26:41 +01001697 initialized_ = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001698}
1699
1700
1701void Builtins::TearDown() {
Steve Block44f0eee2011-05-26 01:26:41 +01001702 initialized_ = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001703}
1704
1705
1706void Builtins::IterateBuiltins(ObjectVisitor* v) {
1707 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1708}
1709
1710
1711const char* Builtins::Lookup(byte* pc) {
Steve Block44f0eee2011-05-26 01:26:41 +01001712 // may be called during initialization (disassembler!)
1713 if (initialized_) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001714 for (int i = 0; i < builtin_count; i++) {
1715 Code* entry = Code::cast(builtins_[i]);
1716 if (entry->contains(pc)) {
1717 return names_[i];
1718 }
1719 }
1720 }
1721 return NULL;
1722}
1723
Ben Murdochb0fe1622011-05-05 13:52:32 +01001724
Steve Block44f0eee2011-05-26 01:26:41 +01001725#define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
1726Handle<Code> Builtins::name() { \
1727 Code** code_address = \
1728 reinterpret_cast<Code**>(builtin_address(k##name)); \
1729 return Handle<Code>(code_address); \
1730}
1731#define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
1732Handle<Code> Builtins::name() { \
1733 Code** code_address = \
1734 reinterpret_cast<Code**>(builtin_address(k##name)); \
1735 return Handle<Code>(code_address); \
1736}
1737BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1738BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1739BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1740#undef DEFINE_BUILTIN_ACCESSOR_C
1741#undef DEFINE_BUILTIN_ACCESSOR_A
1742
1743
Steve Blocka7e24c12009-10-30 11:49:00 +00001744} } // namespace v8::internal