blob: 43cf358d4fdeb195699866bef5503d39d8c9191c [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 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 Murdoch592a9fc2012-03-05 11:04:45 +000036#include "mark-compact.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010037#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000038
39namespace v8 {
40namespace internal {
41
Leon Clarkee46be812010-01-19 14:06:41 +000042namespace {
43
44// Arguments object passed to C++ builtins.
45template <BuiltinExtraArguments extra_args>
46class BuiltinArguments : public Arguments {
47 public:
48 BuiltinArguments(int length, Object** arguments)
49 : Arguments(length, arguments) { }
50
51 Object*& operator[] (int index) {
52 ASSERT(index < length());
53 return Arguments::operator[](index);
54 }
55
56 template <class S> Handle<S> at(int index) {
57 ASSERT(index < length());
58 return Arguments::at<S>(index);
59 }
60
61 Handle<Object> receiver() {
62 return Arguments::at<Object>(0);
63 }
64
65 Handle<JSFunction> called_function() {
66 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
67 return Arguments::at<JSFunction>(Arguments::length() - 1);
68 }
69
70 // Gets the total number of arguments including the receiver (but
71 // excluding extra arguments).
72 int length() const {
73 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
74 return Arguments::length();
75 }
76
77#ifdef DEBUG
78 void Verify() {
79 // Check we have at least the receiver.
80 ASSERT(Arguments::length() >= 1);
81 }
82#endif
83};
84
85
86// Specialize BuiltinArguments for the called function extra argument.
87
88template <>
89int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
90 return Arguments::length() - 1;
91}
92
93#ifdef DEBUG
94template <>
95void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
96 // Check we have at least the receiver and the called function.
97 ASSERT(Arguments::length() >= 2);
98 // Make sure cast to JSFunction succeeds.
99 called_function();
100}
101#endif
102
103
104#define DEF_ARG_TYPE(name, spec) \
105 typedef BuiltinArguments<spec> name##ArgumentsType;
106BUILTIN_LIST_C(DEF_ARG_TYPE)
107#undef DEF_ARG_TYPE
108
109} // namespace
110
Steve Blocka7e24c12009-10-30 11:49:00 +0000111// ----------------------------------------------------------------------------
Leon Clarkee46be812010-01-19 14:06:41 +0000112// Support macro for defining builtins in C++.
Steve Blocka7e24c12009-10-30 11:49:00 +0000113// ----------------------------------------------------------------------------
114//
115// A builtin function is defined by writing:
116//
117// BUILTIN(name) {
118// ...
119// }
Steve Blocka7e24c12009-10-30 11:49:00 +0000120//
Leon Clarkee46be812010-01-19 14:06:41 +0000121// In the body of the builtin function the arguments can be accessed
122// through the BuiltinArguments object args.
Steve Blocka7e24c12009-10-30 11:49:00 +0000123
Leon Clarkee46be812010-01-19 14:06:41 +0000124#ifdef DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +0000125
Steve Block44f0eee2011-05-26 01:26:41 +0100126#define BUILTIN(name) \
127 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
128 name##ArgumentsType args, Isolate* isolate); \
129 MUST_USE_RESULT static MaybeObject* Builtin_##name( \
130 name##ArgumentsType args, Isolate* isolate) { \
131 ASSERT(isolate == Isolate::Current()); \
132 args.Verify(); \
133 return Builtin_Impl_##name(args, isolate); \
134 } \
135 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
136 name##ArgumentsType args, Isolate* isolate)
Steve Blocka7e24c12009-10-30 11:49:00 +0000137
Leon Clarkee46be812010-01-19 14:06:41 +0000138#else // For release mode.
Steve Blocka7e24c12009-10-30 11:49:00 +0000139
Steve Block44f0eee2011-05-26 01:26:41 +0100140#define BUILTIN(name) \
141 static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate)
Leon Clarkee46be812010-01-19 14:06:41 +0000142
143#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000144
145
Steve Block44f0eee2011-05-26 01:26:41 +0100146static inline bool CalledAsConstructor(Isolate* isolate) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000147#ifdef DEBUG
148 // Calculate the result using a full stack frame iterator and check
149 // that the state of the stack is as we assume it to be in the
150 // code below.
151 StackFrameIterator it;
152 ASSERT(it.frame()->is_exit());
153 it.Advance();
154 StackFrame* frame = it.frame();
155 bool reference_result = frame->is_construct();
156#endif
Steve Block44f0eee2011-05-26 01:26:41 +0100157 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
Steve Blocka7e24c12009-10-30 11:49:00 +0000158 // Because we know fp points to an exit frame we can use the relevant
159 // part of ExitFrame::ComputeCallerState directly.
160 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
161 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
162 // This inlines the part of StackFrame::ComputeType that grabs the
163 // type of the current frame. Note that StackFrame::ComputeType
164 // has been specialized for each architecture so if any one of them
165 // changes this code has to be changed as well.
166 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
167 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
168 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
169 bool result = (marker == kConstructMarker);
170 ASSERT_EQ(result, reference_result);
171 return result;
172}
173
174// ----------------------------------------------------------------------------
175
Steve Blocka7e24c12009-10-30 11:49:00 +0000176BUILTIN(Illegal) {
177 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100178 return isolate->heap()->undefined_value(); // Make compiler happy.
Steve Blocka7e24c12009-10-30 11:49:00 +0000179}
Steve Blocka7e24c12009-10-30 11:49:00 +0000180
181
182BUILTIN(EmptyFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +0100183 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000184}
Steve Blocka7e24c12009-10-30 11:49:00 +0000185
186
187BUILTIN(ArrayCodeGeneric) {
Steve Block44f0eee2011-05-26 01:26:41 +0100188 Heap* heap = isolate->heap();
189 isolate->counters()->array_function_runtime()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +0000190
191 JSArray* array;
Steve Block44f0eee2011-05-26 01:26:41 +0100192 if (CalledAsConstructor(isolate)) {
Leon Clarkee46be812010-01-19 14:06:41 +0000193 array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000194 } else {
195 // Allocate the JS Array
196 JSFunction* constructor =
Steve Block44f0eee2011-05-26 01:26:41 +0100197 isolate->context()->global_context()->array_function();
John Reck59135872010-11-02 12:39:01 -0700198 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100199 { MaybeObject* maybe_obj = heap->AllocateJSObject(constructor);
John Reck59135872010-11-02 12:39:01 -0700200 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
201 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000202 array = JSArray::cast(obj);
203 }
204
205 // 'array' now contains the JSArray we should initialize.
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000206 ASSERT(array->HasFastTypeElements());
Steve Blocka7e24c12009-10-30 11:49:00 +0000207
208 // Optimize the case where there is one argument and the argument is a
209 // small smi.
210 if (args.length() == 2) {
211 Object* obj = args[1];
212 if (obj->IsSmi()) {
213 int len = Smi::cast(obj)->value();
214 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
John Reck59135872010-11-02 12:39:01 -0700215 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100216 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
John Reck59135872010-11-02 12:39:01 -0700217 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
218 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000219 MaybeObject* maybe_obj = array->SetContent(FixedArray::cast(obj));
220 if (maybe_obj->IsFailure()) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +0000221 return array;
222 }
223 }
224 // Take the argument as the length.
John Reck59135872010-11-02 12:39:01 -0700225 { MaybeObject* maybe_obj = array->Initialize(0);
226 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
227 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 return array->SetElementsLength(args[1]);
229 }
230
231 // Optimize the case where there are no parameters passed.
232 if (args.length() == 1) {
233 return array->Initialize(JSArray::kPreallocatedArrayElements);
234 }
235
236 // Take the arguments as elements.
237 int number_of_elements = args.length() - 1;
238 Smi* len = Smi::FromInt(number_of_elements);
John Reck59135872010-11-02 12:39:01 -0700239 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100240 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len->value());
John Reck59135872010-11-02 12:39:01 -0700241 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
242 }
Leon Clarke4515c472010-02-03 11:58:03 +0000243
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000244 // Set length and elements on the array.
245 MaybeObject* maybe_object =
246 array->EnsureCanContainElements(FixedArray::cast(obj));
247 if (maybe_object->IsFailure()) return maybe_object;
248
Leon Clarke4515c472010-02-03 11:58:03 +0000249 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000250 FixedArray* elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000251 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000252 // Fill in the content
253 for (int index = 0; index < number_of_elements; index++) {
254 elms->set(index, args[index+1], mode);
255 }
256
Steve Blocka7e24c12009-10-30 11:49:00 +0000257 array->set_elements(FixedArray::cast(obj));
Leon Clarke4515c472010-02-03 11:58:03 +0000258 array->set_length(len);
Steve Blocka7e24c12009-10-30 11:49:00 +0000259
260 return array;
261}
Steve Blocka7e24c12009-10-30 11:49:00 +0000262
263
Steve Block44f0eee2011-05-26 01:26:41 +0100264MUST_USE_RESULT static MaybeObject* AllocateJSArray(Heap* heap) {
Steve Block6ded16b2010-05-10 14:33:55 +0100265 JSFunction* array_function =
Steve Block44f0eee2011-05-26 01:26:41 +0100266 heap->isolate()->context()->global_context()->array_function();
John Reck59135872010-11-02 12:39:01 -0700267 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100268 { MaybeObject* maybe_result = heap->AllocateJSObject(array_function);
John Reck59135872010-11-02 12:39:01 -0700269 if (!maybe_result->ToObject(&result)) return maybe_result;
270 }
Steve Block6ded16b2010-05-10 14:33:55 +0100271 return result;
272}
273
274
Steve Block44f0eee2011-05-26 01:26:41 +0100275MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray(Heap* heap) {
John Reck59135872010-11-02 12:39:01 -0700276 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100277 { MaybeObject* maybe_result = AllocateJSArray(heap);
John Reck59135872010-11-02 12:39:01 -0700278 if (!maybe_result->ToObject(&result)) return maybe_result;
279 }
Steve Block6ded16b2010-05-10 14:33:55 +0100280 JSArray* result_array = JSArray::cast(result);
281 result_array->set_length(Smi::FromInt(0));
Steve Block44f0eee2011-05-26 01:26:41 +0100282 result_array->set_elements(heap->empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +0100283 return result_array;
284}
285
286
Steve Block44f0eee2011-05-26 01:26:41 +0100287static void CopyElements(Heap* heap,
288 AssertNoAllocation* no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100289 FixedArray* dst,
290 int dst_index,
291 FixedArray* src,
292 int src_index,
293 int len) {
294 ASSERT(dst != src); // Use MoveElements instead.
Steve Block44f0eee2011-05-26 01:26:41 +0100295 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100296 ASSERT(len > 0);
297 CopyWords(dst->data_start() + dst_index,
298 src->data_start() + src_index,
299 len);
300 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
301 if (mode == UPDATE_WRITE_BARRIER) {
Steve Block44f0eee2011-05-26 01:26:41 +0100302 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
Steve Block6ded16b2010-05-10 14:33:55 +0100303 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000304 heap->incremental_marking()->RecordWrites(dst);
Steve Block6ded16b2010-05-10 14:33:55 +0100305}
306
307
Steve Block44f0eee2011-05-26 01:26:41 +0100308static void MoveElements(Heap* heap,
309 AssertNoAllocation* no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100310 FixedArray* dst,
311 int dst_index,
312 FixedArray* src,
313 int src_index,
314 int len) {
Steve Block44f0eee2011-05-26 01:26:41 +0100315 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100316 memmove(dst->data_start() + dst_index,
317 src->data_start() + src_index,
318 len * kPointerSize);
319 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
320 if (mode == UPDATE_WRITE_BARRIER) {
Steve Block44f0eee2011-05-26 01:26:41 +0100321 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
Steve Block6ded16b2010-05-10 14:33:55 +0100322 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000323 heap->incremental_marking()->RecordWrites(dst);
Steve Block6ded16b2010-05-10 14:33:55 +0100324}
325
326
Steve Block44f0eee2011-05-26 01:26:41 +0100327static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) {
328 ASSERT(dst->map() != heap->fixed_cow_array_map());
329 MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from);
Steve Block6ded16b2010-05-10 14:33:55 +0100330}
331
332
Steve Block44f0eee2011-05-26 01:26:41 +0100333static FixedArray* LeftTrimFixedArray(Heap* heap,
334 FixedArray* elms,
335 int to_trim) {
336 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
Steve Block791712a2010-08-27 10:21:07 +0100337 // For now this trick is only applied to fixed arrays in new and paged space.
Steve Block6ded16b2010-05-10 14:33:55 +0100338 // In large object space the object's start must coincide with chunk
339 // and thus the trick is just not applicable.
Steve Block44f0eee2011-05-26 01:26:41 +0100340 ASSERT(!HEAP->lo_space()->Contains(elms));
Steve Block6ded16b2010-05-10 14:33:55 +0100341
342 STATIC_ASSERT(FixedArray::kMapOffset == 0);
343 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
344 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
345
346 Object** former_start = HeapObject::RawField(elms, 0);
347
348 const int len = elms->length();
349
Steve Block791712a2010-08-27 10:21:07 +0100350 if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
Steve Block44f0eee2011-05-26 01:26:41 +0100351 !heap->new_space()->Contains(elms)) {
Steve Block791712a2010-08-27 10:21:07 +0100352 // If we are doing a big trim in old space then we zap the space that was
353 // formerly part of the array so that the GC (aided by the card-based
354 // remembered set) won't find pointers to new-space there.
355 Object** zap = reinterpret_cast<Object**>(elms->address());
356 zap++; // Header of filler must be at least one word so skip that.
357 for (int i = 1; i < to_trim; i++) {
358 *zap++ = Smi::FromInt(0);
359 }
360 }
Steve Block6ded16b2010-05-10 14:33:55 +0100361 // Technically in new space this write might be omitted (except for
362 // debug mode which iterates through the heap), but to play safer
363 // we still do it.
Steve Block44f0eee2011-05-26 01:26:41 +0100364 heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
Steve Block6ded16b2010-05-10 14:33:55 +0100365
Steve Block44f0eee2011-05-26 01:26:41 +0100366 former_start[to_trim] = heap->fixed_array_map();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100367 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
Steve Block6ded16b2010-05-10 14:33:55 +0100368
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000369 // Maintain marking consistency for HeapObjectIterator and
370 // IncrementalMarking.
371 int size_delta = to_trim * kPointerSize;
372 if (heap->marking()->TransferMark(elms->address(),
373 elms->address() + size_delta)) {
374 MemoryChunk::IncrementLiveBytes(elms->address(), -size_delta);
375 }
376
Steve Block791712a2010-08-27 10:21:07 +0100377 return FixedArray::cast(HeapObject::FromAddress(
378 elms->address() + to_trim * kPointerSize));
Steve Block6ded16b2010-05-10 14:33:55 +0100379}
380
381
Steve Block44f0eee2011-05-26 01:26:41 +0100382static bool ArrayPrototypeHasNoElements(Heap* heap,
383 Context* global_context,
Kristian Monsen25f61362010-05-21 11:50:48 +0100384 JSObject* array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100385 // This method depends on non writability of Object and Array prototype
386 // fields.
Steve Block44f0eee2011-05-26 01:26:41 +0100387 if (array_proto->elements() != heap->empty_fixed_array()) return false;
Steve Block6ded16b2010-05-10 14:33:55 +0100388 // Object.prototype
Steve Block1e0659c2011-05-24 12:43:12 +0100389 Object* proto = array_proto->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +0100390 if (proto == heap->null_value()) return false;
Steve Block1e0659c2011-05-24 12:43:12 +0100391 array_proto = JSObject::cast(proto);
Kristian Monsen25f61362010-05-21 11:50:48 +0100392 if (array_proto != global_context->initial_object_prototype()) return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100393 if (array_proto->elements() != heap->empty_fixed_array()) return false;
Steve Block053d10c2011-06-13 19:13:29 +0100394 return array_proto->GetPrototype()->IsNull();
Steve Block6ded16b2010-05-10 14:33:55 +0100395}
396
397
John Reck59135872010-11-02 12:39:01 -0700398MUST_USE_RESULT
399static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000400 Heap* heap, Object* receiver, Arguments* args, int first_added_arg) {
Iain Merrick75681382010-08-19 15:07:18 +0100401 if (!receiver->IsJSArray()) return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100402 JSArray* array = JSArray::cast(receiver);
Steve Block9fac8402011-05-12 15:51:54 +0100403 HeapObject* elms = array->elements();
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000404 Map* map = elms->map();
405 if (map == heap->fixed_array_map()) {
406 if (args == NULL || !array->HasFastSmiOnlyElements()) {
407 return elms;
408 }
409 } else if (map == heap->fixed_cow_array_map()) {
410 MaybeObject* maybe_writable_result = array->EnsureWritableFastElements();
411 if (args == NULL || !array->HasFastSmiOnlyElements() ||
412 maybe_writable_result->IsFailure()) {
413 return maybe_writable_result;
414 }
415 } else {
416 return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100417 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000418
419 // Need to ensure that the arguments passed in args can be contained in
420 // the array.
421 int args_length = args->length();
422 if (first_added_arg >= args_length) return array->elements();
423
424 MaybeObject* maybe_array = array->EnsureCanContainElements(
425 args,
426 first_added_arg,
427 args_length - first_added_arg);
428 if (maybe_array->IsFailure()) return maybe_array;
429 return array->elements();
Steve Block6ded16b2010-05-10 14:33:55 +0100430}
431
432
Steve Block44f0eee2011-05-26 01:26:41 +0100433static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
434 JSArray* receiver) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000435 if (!FLAG_clever_optimizations) return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100436 Context* global_context = heap->isolate()->context()->global_context();
Kristian Monsen25f61362010-05-21 11:50:48 +0100437 JSObject* array_proto =
438 JSObject::cast(global_context->array_function()->prototype());
Iain Merrick75681382010-08-19 15:07:18 +0100439 return receiver->GetPrototype() == array_proto &&
Steve Block44f0eee2011-05-26 01:26:41 +0100440 ArrayPrototypeHasNoElements(heap, global_context, array_proto);
Kristian Monsen25f61362010-05-21 11:50:48 +0100441}
442
443
John Reck59135872010-11-02 12:39:01 -0700444MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
Steve Block44f0eee2011-05-26 01:26:41 +0100445 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -0700446 const char* name,
447 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Block44f0eee2011-05-26 01:26:41 +0100448 HandleScope handleScope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100449
450 Handle<Object> js_builtin =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000451 GetProperty(Handle<JSObject>(isolate->global_context()->builtins()),
452 name);
453 Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin);
454 int argc = args.length() - 1;
455 ScopedVector<Handle<Object> > argv(argc);
456 for (int i = 0; i < argc; ++i) {
457 argv[i] = args.at<Object>(i + 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100458 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000459 bool pending_exception;
Steve Block6ded16b2010-05-10 14:33:55 +0100460 Handle<Object> result = Execution::Call(function,
461 args.receiver(),
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000462 argc,
Steve Block6ded16b2010-05-10 14:33:55 +0100463 argv.start(),
464 &pending_exception);
Steve Block6ded16b2010-05-10 14:33:55 +0100465 if (pending_exception) return Failure::Exception();
466 return *result;
467}
468
469
Steve Blocka7e24c12009-10-30 11:49:00 +0000470BUILTIN(ArrayPush) {
Steve Block44f0eee2011-05-26 01:26:41 +0100471 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100472 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700473 Object* elms_obj;
474 { MaybeObject* maybe_elms_obj =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000475 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1);
Steve Block44f0eee2011-05-26 01:26:41 +0100476 if (maybe_elms_obj == NULL) {
477 return CallJsBuiltin(isolate, "ArrayPush", args);
478 }
John Reck59135872010-11-02 12:39:01 -0700479 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
480 }
Iain Merrick75681382010-08-19 15:07:18 +0100481 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100482 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000483
Steve Blocka7e24c12009-10-30 11:49:00 +0000484 int len = Smi::cast(array->length())->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000485 int to_add = args.length() - 1;
486 if (to_add == 0) {
487 return Smi::FromInt(len);
488 }
489 // Currently fixed arrays cannot grow too big, so
490 // we should never hit this case.
491 ASSERT(to_add <= (Smi::kMaxValue - len));
Steve Blocka7e24c12009-10-30 11:49:00 +0000492
Andrei Popescu402d9372010-02-26 13:31:12 +0000493 int new_length = len + to_add;
Steve Blocka7e24c12009-10-30 11:49:00 +0000494
Andrei Popescu402d9372010-02-26 13:31:12 +0000495 if (new_length > elms->length()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000496 // New backing storage is needed.
497 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700498 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100499 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
John Reck59135872010-11-02 12:39:01 -0700500 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
501 }
Steve Block6ded16b2010-05-10 14:33:55 +0100502 FixedArray* new_elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000503
504 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100505 if (len > 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100506 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, len);
Steve Block6ded16b2010-05-10 14:33:55 +0100507 }
Steve Block44f0eee2011-05-26 01:26:41 +0100508 FillWithHoles(heap, new_elms, new_length, capacity);
Steve Block6ded16b2010-05-10 14:33:55 +0100509
Andrei Popescu402d9372010-02-26 13:31:12 +0000510 elms = new_elms;
Steve Blocka7e24c12009-10-30 11:49:00 +0000511 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000512
Steve Block6ded16b2010-05-10 14:33:55 +0100513 // Add the provided values.
Andrei Popescu402d9372010-02-26 13:31:12 +0000514 AssertNoAllocation no_gc;
515 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Andrei Popescu402d9372010-02-26 13:31:12 +0000516 for (int index = 0; index < to_add; index++) {
517 elms->set(index + len, args[index + 1], mode);
518 }
519
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000520 if (elms != array->elements()) {
521 array->set_elements(elms);
522 }
523
Steve Blocka7e24c12009-10-30 11:49:00 +0000524 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000525 array->set_length(Smi::FromInt(new_length));
Andrei Popescu402d9372010-02-26 13:31:12 +0000526 return Smi::FromInt(new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000527}
Steve Blocka7e24c12009-10-30 11:49:00 +0000528
529
530BUILTIN(ArrayPop) {
Steve Block44f0eee2011-05-26 01:26:41 +0100531 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100532 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700533 Object* elms_obj;
534 { MaybeObject* maybe_elms_obj =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000535 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100536 if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
John Reck59135872010-11-02 12:39:01 -0700537 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
538 }
Iain Merrick75681382010-08-19 15:07:18 +0100539 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100540 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000541
542 int len = Smi::cast(array->length())->value();
Steve Block44f0eee2011-05-26 01:26:41 +0100543 if (len == 0) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000544
545 // Get top element
John Reck59135872010-11-02 12:39:01 -0700546 MaybeObject* top = elms->get(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000547
548 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000549 array->set_length(Smi::FromInt(len - 1));
Steve Blocka7e24c12009-10-30 11:49:00 +0000550
551 if (!top->IsTheHole()) {
552 // Delete the top element.
553 elms->set_the_hole(len - 1);
554 return top;
555 }
556
Kristian Monsen25f61362010-05-21 11:50:48 +0100557 top = array->GetPrototype()->GetElement(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000558
559 return top;
560}
Steve Blocka7e24c12009-10-30 11:49:00 +0000561
562
Andrei Popescu402d9372010-02-26 13:31:12 +0000563BUILTIN(ArrayShift) {
Steve Block44f0eee2011-05-26 01:26:41 +0100564 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100565 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700566 Object* elms_obj;
567 { MaybeObject* maybe_elms_obj =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000568 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100569 if (maybe_elms_obj == NULL)
570 return CallJsBuiltin(isolate, "ArrayShift", args);
John Reck59135872010-11-02 12:39:01 -0700571 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
572 }
Steve Block44f0eee2011-05-26 01:26:41 +0100573 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
574 return CallJsBuiltin(isolate, "ArrayShift", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100575 }
Iain Merrick75681382010-08-19 15:07:18 +0100576 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100577 JSArray* array = JSArray::cast(receiver);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000578 ASSERT(array->HasFastTypeElements());
Andrei Popescu402d9372010-02-26 13:31:12 +0000579
580 int len = Smi::cast(array->length())->value();
Steve Block44f0eee2011-05-26 01:26:41 +0100581 if (len == 0) return heap->undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000582
Andrei Popescu402d9372010-02-26 13:31:12 +0000583 // Get first element
584 Object* first = elms->get(0);
585 if (first->IsTheHole()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100586 first = heap->undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000587 }
588
Steve Block44f0eee2011-05-26 01:26:41 +0100589 if (!heap->lo_space()->Contains(elms)) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000590 array->set_elements(LeftTrimFixedArray(heap, elms, 1));
Steve Block6ded16b2010-05-10 14:33:55 +0100591 } else {
592 // Shift the elements.
593 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100594 MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
595 elms->set(len - 1, heap->the_hole_value());
Andrei Popescu402d9372010-02-26 13:31:12 +0000596 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000597
598 // Set the length.
599 array->set_length(Smi::FromInt(len - 1));
600
601 return first;
602}
603
604
605BUILTIN(ArrayUnshift) {
Steve Block44f0eee2011-05-26 01:26:41 +0100606 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100607 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700608 Object* elms_obj;
609 { MaybeObject* maybe_elms_obj =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000610 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
Steve Block44f0eee2011-05-26 01:26:41 +0100611 if (maybe_elms_obj == NULL)
612 return CallJsBuiltin(isolate, "ArrayUnshift", args);
John Reck59135872010-11-02 12:39:01 -0700613 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
614 }
Steve Block44f0eee2011-05-26 01:26:41 +0100615 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
616 return CallJsBuiltin(isolate, "ArrayUnshift", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100617 }
Iain Merrick75681382010-08-19 15:07:18 +0100618 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100619 JSArray* array = JSArray::cast(receiver);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000620 ASSERT(array->HasFastTypeElements());
Andrei Popescu402d9372010-02-26 13:31:12 +0000621
622 int len = Smi::cast(array->length())->value();
623 int to_add = args.length() - 1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000624 int new_length = len + to_add;
625 // Currently fixed arrays cannot grow too big, so
626 // we should never hit this case.
627 ASSERT(to_add <= (Smi::kMaxValue - len));
628
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000629 MaybeObject* maybe_object =
630 array->EnsureCanContainElements(&args, 1, to_add);
631 if (maybe_object->IsFailure()) return maybe_object;
632
Andrei Popescu402d9372010-02-26 13:31:12 +0000633 if (new_length > elms->length()) {
634 // New backing storage is needed.
635 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700636 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100637 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
John Reck59135872010-11-02 12:39:01 -0700638 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
639 }
Steve Block6ded16b2010-05-10 14:33:55 +0100640 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000641 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100642 if (len > 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100643 CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len);
Steve Block6ded16b2010-05-10 14:33:55 +0100644 }
Steve Block44f0eee2011-05-26 01:26:41 +0100645 FillWithHoles(heap, new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000646 elms = new_elms;
647 array->set_elements(elms);
648 } else {
649 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100650 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000651 }
652
653 // Add the provided values.
654 AssertNoAllocation no_gc;
655 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
656 for (int i = 0; i < to_add; i++) {
657 elms->set(i, args[i + 1], mode);
658 }
659
660 // Set the length.
661 array->set_length(Smi::FromInt(new_length));
662 return Smi::FromInt(new_length);
663}
664
665
Andrei Popescu402d9372010-02-26 13:31:12 +0000666BUILTIN(ArraySlice) {
Steve Block44f0eee2011-05-26 01:26:41 +0100667 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100668 Object* receiver = *args.receiver();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100669 FixedArray* elms;
670 int len = -1;
Steve Block9fac8402011-05-12 15:51:54 +0100671 if (receiver->IsJSArray()) {
672 JSArray* array = JSArray::cast(receiver);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000673 if (!array->HasFastTypeElements() ||
Steve Block44f0eee2011-05-26 01:26:41 +0100674 !IsJSArrayFastElementMovingAllowed(heap, array)) {
675 return CallJsBuiltin(isolate, "ArraySlice", args);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100676 }
Steve Block9fac8402011-05-12 15:51:54 +0100677
678 elms = FixedArray::cast(array->elements());
679 len = Smi::cast(array->length())->value();
680 } else {
681 // Array.slice(arguments, ...) is quite a common idiom (notably more
682 // than 50% of invocations in Web apps). Treat it in C++ as well.
683 Map* arguments_map =
Steve Block44f0eee2011-05-26 01:26:41 +0100684 isolate->context()->global_context()->arguments_boilerplate()->map();
Steve Block9fac8402011-05-12 15:51:54 +0100685
686 bool is_arguments_object_with_fast_elements =
687 receiver->IsJSObject()
688 && JSObject::cast(receiver)->map() == arguments_map
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000689 && JSObject::cast(receiver)->HasFastTypeElements();
Steve Block9fac8402011-05-12 15:51:54 +0100690 if (!is_arguments_object_with_fast_elements) {
Steve Block44f0eee2011-05-26 01:26:41 +0100691 return CallJsBuiltin(isolate, "ArraySlice", args);
Steve Block9fac8402011-05-12 15:51:54 +0100692 }
693 elms = FixedArray::cast(JSObject::cast(receiver)->elements());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100694 Object* len_obj = JSObject::cast(receiver)
Steve Block44f0eee2011-05-26 01:26:41 +0100695 ->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100696 if (!len_obj->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100697 return CallJsBuiltin(isolate, "ArraySlice", args);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100698 }
699 len = Smi::cast(len_obj)->value();
700 if (len > elms->length()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100701 return CallJsBuiltin(isolate, "ArraySlice", args);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100702 }
703 for (int i = 0; i < len; i++) {
Steve Block44f0eee2011-05-26 01:26:41 +0100704 if (elms->get(i) == heap->the_hole_value()) {
705 return CallJsBuiltin(isolate, "ArraySlice", args);
Steve Block9fac8402011-05-12 15:51:54 +0100706 }
707 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100708 }
709 ASSERT(len >= 0);
Andrei Popescu402d9372010-02-26 13:31:12 +0000710 int n_arguments = args.length() - 1;
711
712 // Note carefully choosen defaults---if argument is missing,
Steve Block6ded16b2010-05-10 14:33:55 +0100713 // it's undefined which gets converted to 0 for relative_start
714 // and to len for relative_end.
715 int relative_start = 0;
716 int relative_end = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000717 if (n_arguments > 0) {
718 Object* arg1 = args[1];
719 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100720 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000721 } else if (!arg1->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100722 return CallJsBuiltin(isolate, "ArraySlice", args);
Andrei Popescu402d9372010-02-26 13:31:12 +0000723 }
724 if (n_arguments > 1) {
725 Object* arg2 = args[2];
726 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100727 relative_end = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000728 } else if (!arg2->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100729 return CallJsBuiltin(isolate, "ArraySlice", args);
Andrei Popescu402d9372010-02-26 13:31:12 +0000730 }
731 }
732 }
733
734 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
Steve Block6ded16b2010-05-10 14:33:55 +0100735 int k = (relative_start < 0) ? Max(len + relative_start, 0)
736 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000737
738 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
Steve Block6ded16b2010-05-10 14:33:55 +0100739 int final = (relative_end < 0) ? Max(len + relative_end, 0)
740 : Min(relative_end, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000741
742 // Calculate the length of result array.
743 int result_len = final - k;
Steve Block6ded16b2010-05-10 14:33:55 +0100744 if (result_len <= 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100745 return AllocateEmptyJSArray(heap);
Andrei Popescu402d9372010-02-26 13:31:12 +0000746 }
747
John Reck59135872010-11-02 12:39:01 -0700748 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100749 { MaybeObject* maybe_result = AllocateJSArray(heap);
John Reck59135872010-11-02 12:39:01 -0700750 if (!maybe_result->ToObject(&result)) return maybe_result;
751 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000752 JSArray* result_array = JSArray::cast(result);
753
John Reck59135872010-11-02 12:39:01 -0700754 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +0100755 heap->AllocateUninitializedFixedArray(result_len);
John Reck59135872010-11-02 12:39:01 -0700756 if (!maybe_result->ToObject(&result)) return maybe_result;
757 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000758 FixedArray* result_elms = FixedArray::cast(result);
759
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000760 MaybeObject* maybe_object =
761 result_array->EnsureCanContainElements(result_elms);
762 if (maybe_object->IsFailure()) return maybe_object;
763
Andrei Popescu402d9372010-02-26 13:31:12 +0000764 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100765 CopyElements(heap, &no_gc, result_elms, 0, elms, k, result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000766
767 // Set elements.
768 result_array->set_elements(result_elms);
769
770 // Set the length.
771 result_array->set_length(Smi::FromInt(result_len));
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000772
773 // Set the ElementsKind.
774 ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind();
775 if (IsMoreGeneralElementsKindTransition(result_array->GetElementsKind(),
776 elements_kind)) {
777 MaybeObject* maybe = result_array->TransitionElementsKind(elements_kind);
778 if (maybe->IsFailure()) return maybe;
779 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000780 return result_array;
781}
782
783
784BUILTIN(ArraySplice) {
Steve Block44f0eee2011-05-26 01:26:41 +0100785 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100786 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700787 Object* elms_obj;
788 { MaybeObject* maybe_elms_obj =
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000789 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
Steve Block44f0eee2011-05-26 01:26:41 +0100790 if (maybe_elms_obj == NULL)
791 return CallJsBuiltin(isolate, "ArraySplice", args);
John Reck59135872010-11-02 12:39:01 -0700792 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
793 }
Steve Block44f0eee2011-05-26 01:26:41 +0100794 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
795 return CallJsBuiltin(isolate, "ArraySplice", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100796 }
Iain Merrick75681382010-08-19 15:07:18 +0100797 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100798 JSArray* array = JSArray::cast(receiver);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000799 ASSERT(array->HasFastTypeElements());
Andrei Popescu402d9372010-02-26 13:31:12 +0000800
801 int len = Smi::cast(array->length())->value();
802
803 int n_arguments = args.length() - 1;
804
Steve Block6ded16b2010-05-10 14:33:55 +0100805 int relative_start = 0;
Steve Block1e0659c2011-05-24 12:43:12 +0100806 if (n_arguments > 0) {
807 Object* arg1 = args[1];
808 if (arg1->IsSmi()) {
809 relative_start = Smi::cast(arg1)->value();
810 } else if (!arg1->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100811 return CallJsBuiltin(isolate, "ArraySplice", args);
Steve Block1e0659c2011-05-24 12:43:12 +0100812 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000813 }
Steve Block6ded16b2010-05-10 14:33:55 +0100814 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
815 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000816
817 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
Steve Block1e0659c2011-05-24 12:43:12 +0100818 // given as a request to delete all the elements from the start.
819 // And it differs from the case of undefined delete count.
Andrei Popescu402d9372010-02-26 13:31:12 +0000820 // This does not follow ECMA-262, but we do the same for
821 // compatibility.
Steve Block1e0659c2011-05-24 12:43:12 +0100822 int actual_delete_count;
823 if (n_arguments == 1) {
824 ASSERT(len - actual_start >= 0);
825 actual_delete_count = len - actual_start;
826 } else {
827 int value = 0; // ToInteger(undefined) == 0
828 if (n_arguments > 1) {
829 Object* arg2 = args[2];
830 if (arg2->IsSmi()) {
831 value = Smi::cast(arg2)->value();
832 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100833 return CallJsBuiltin(isolate, "ArraySplice", args);
Steve Block1e0659c2011-05-24 12:43:12 +0100834 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000835 }
Steve Block1e0659c2011-05-24 12:43:12 +0100836 actual_delete_count = Min(Max(value, 0), len - actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000837 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000838
Steve Block6ded16b2010-05-10 14:33:55 +0100839 JSArray* result_array = NULL;
840 if (actual_delete_count == 0) {
John Reck59135872010-11-02 12:39:01 -0700841 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100842 { MaybeObject* maybe_result = AllocateEmptyJSArray(heap);
John Reck59135872010-11-02 12:39:01 -0700843 if (!maybe_result->ToObject(&result)) return maybe_result;
844 }
Steve Block6ded16b2010-05-10 14:33:55 +0100845 result_array = JSArray::cast(result);
846 } else {
847 // Allocate result array.
John Reck59135872010-11-02 12:39:01 -0700848 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100849 { MaybeObject* maybe_result = AllocateJSArray(heap);
John Reck59135872010-11-02 12:39:01 -0700850 if (!maybe_result->ToObject(&result)) return maybe_result;
851 }
Steve Block6ded16b2010-05-10 14:33:55 +0100852 result_array = JSArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000853
John Reck59135872010-11-02 12:39:01 -0700854 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +0100855 heap->AllocateUninitializedFixedArray(actual_delete_count);
John Reck59135872010-11-02 12:39:01 -0700856 if (!maybe_result->ToObject(&result)) return maybe_result;
857 }
Steve Block6ded16b2010-05-10 14:33:55 +0100858 FixedArray* result_elms = FixedArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000859
Steve Block6ded16b2010-05-10 14:33:55 +0100860 AssertNoAllocation no_gc;
861 // Fill newly created array.
Steve Block44f0eee2011-05-26 01:26:41 +0100862 CopyElements(heap,
863 &no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100864 result_elms, 0,
865 elms, actual_start,
866 actual_delete_count);
Andrei Popescu402d9372010-02-26 13:31:12 +0000867
Steve Block6ded16b2010-05-10 14:33:55 +0100868 // Set elements.
869 result_array->set_elements(result_elms);
Andrei Popescu402d9372010-02-26 13:31:12 +0000870
Steve Block6ded16b2010-05-10 14:33:55 +0100871 // Set the length.
872 result_array->set_length(Smi::FromInt(actual_delete_count));
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000873
874 // Set the ElementsKind.
875 ElementsKind elements_kind = array->GetElementsKind();
876 if (IsMoreGeneralElementsKindTransition(result_array->GetElementsKind(),
877 elements_kind)) {
878 MaybeObject* maybe = result_array->TransitionElementsKind(elements_kind);
879 if (maybe->IsFailure()) return maybe;
880 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000881 }
882
Steve Block6ded16b2010-05-10 14:33:55 +0100883 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
Steve Block6ded16b2010-05-10 14:33:55 +0100884 int new_length = len - actual_delete_count + item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000885
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000886 bool elms_changed = false;
Steve Block6ded16b2010-05-10 14:33:55 +0100887 if (item_count < actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000888 // Shrink the array.
Steve Block44f0eee2011-05-26 01:26:41 +0100889 const bool trim_array = !heap->lo_space()->Contains(elms) &&
Steve Block6ded16b2010-05-10 14:33:55 +0100890 ((actual_start + item_count) <
891 (len - actual_delete_count - actual_start));
892 if (trim_array) {
893 const int delta = actual_delete_count - item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000894
Steve Block6ded16b2010-05-10 14:33:55 +0100895 if (actual_start > 0) {
Steve Block053d10c2011-06-13 19:13:29 +0100896 AssertNoAllocation no_gc;
897 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
Steve Block6ded16b2010-05-10 14:33:55 +0100898 }
899
Steve Block44f0eee2011-05-26 01:26:41 +0100900 elms = LeftTrimFixedArray(heap, elms, delta);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000901
902 elms_changed = true;
Steve Block6ded16b2010-05-10 14:33:55 +0100903 } else {
904 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100905 MoveElements(heap, &no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100906 elms, actual_start + item_count,
907 elms, actual_start + actual_delete_count,
908 (len - actual_delete_count - actual_start));
Steve Block44f0eee2011-05-26 01:26:41 +0100909 FillWithHoles(heap, elms, new_length, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000910 }
Steve Block6ded16b2010-05-10 14:33:55 +0100911 } else if (item_count > actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000912 // Currently fixed arrays cannot grow too big, so
913 // we should never hit this case.
Steve Block6ded16b2010-05-10 14:33:55 +0100914 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
Andrei Popescu402d9372010-02-26 13:31:12 +0000915
916 // Check if array need to grow.
917 if (new_length > elms->length()) {
918 // New backing storage is needed.
919 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700920 Object* obj;
921 { MaybeObject* maybe_obj =
Steve Block44f0eee2011-05-26 01:26:41 +0100922 heap->AllocateUninitializedFixedArray(capacity);
John Reck59135872010-11-02 12:39:01 -0700923 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
924 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000925 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000926
Steve Block6ded16b2010-05-10 14:33:55 +0100927 AssertNoAllocation no_gc;
928 // Copy the part before actual_start as is.
929 if (actual_start > 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100930 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000931 }
Steve Block6ded16b2010-05-10 14:33:55 +0100932 const int to_copy = len - actual_delete_count - actual_start;
933 if (to_copy > 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100934 CopyElements(heap, &no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100935 new_elms, actual_start + item_count,
936 elms, actual_start + actual_delete_count,
937 to_copy);
938 }
Steve Block44f0eee2011-05-26 01:26:41 +0100939 FillWithHoles(heap, new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000940
Andrei Popescu402d9372010-02-26 13:31:12 +0000941 elms = new_elms;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000942 elms_changed = true;
Steve Block6ded16b2010-05-10 14:33:55 +0100943 } else {
944 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100945 MoveElements(heap, &no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100946 elms, actual_start + item_count,
947 elms, actual_start + actual_delete_count,
948 (len - actual_delete_count - actual_start));
Andrei Popescu402d9372010-02-26 13:31:12 +0000949 }
950 }
951
Steve Block6ded16b2010-05-10 14:33:55 +0100952 AssertNoAllocation no_gc;
953 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
954 for (int k = actual_start; k < actual_start + item_count; k++) {
955 elms->set(k, args[3 + k - actual_start], mode);
Andrei Popescu402d9372010-02-26 13:31:12 +0000956 }
957
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000958 if (elms_changed) {
959 array->set_elements(elms);
960 }
961
Andrei Popescu402d9372010-02-26 13:31:12 +0000962 // Set the length.
963 array->set_length(Smi::FromInt(new_length));
964
965 return result_array;
966}
967
968
Steve Block6ded16b2010-05-10 14:33:55 +0100969BUILTIN(ArrayConcat) {
Steve Block44f0eee2011-05-26 01:26:41 +0100970 Heap* heap = isolate->heap();
971 Context* global_context = isolate->context()->global_context();
Kristian Monsen25f61362010-05-21 11:50:48 +0100972 JSObject* array_proto =
973 JSObject::cast(global_context->array_function()->prototype());
Steve Block44f0eee2011-05-26 01:26:41 +0100974 if (!ArrayPrototypeHasNoElements(heap, global_context, array_proto)) {
975 return CallJsBuiltin(isolate, "ArrayConcat", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100976 }
977
978 // Iterate through all the arguments performing checks
979 // and calculating total length.
980 int n_arguments = args.length();
981 int result_len = 0;
982 for (int i = 0; i < n_arguments; i++) {
983 Object* arg = args[i];
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000984 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastTypeElements()
Kristian Monsen25f61362010-05-21 11:50:48 +0100985 || JSArray::cast(arg)->GetPrototype() != array_proto) {
Steve Block44f0eee2011-05-26 01:26:41 +0100986 return CallJsBuiltin(isolate, "ArrayConcat", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100987 }
988
989 int len = Smi::cast(JSArray::cast(arg)->length())->value();
990
991 // We shouldn't overflow when adding another len.
992 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
993 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
994 USE(kHalfOfMaxInt);
995 result_len += len;
996 ASSERT(result_len >= 0);
997
998 if (result_len > FixedArray::kMaxLength) {
Steve Block44f0eee2011-05-26 01:26:41 +0100999 return CallJsBuiltin(isolate, "ArrayConcat", args);
Steve Block6ded16b2010-05-10 14:33:55 +01001000 }
1001 }
1002
1003 if (result_len == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01001004 return AllocateEmptyJSArray(heap);
Steve Block6ded16b2010-05-10 14:33:55 +01001005 }
1006
1007 // Allocate result.
John Reck59135872010-11-02 12:39:01 -07001008 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +01001009 { MaybeObject* maybe_result = AllocateJSArray(heap);
John Reck59135872010-11-02 12:39:01 -07001010 if (!maybe_result->ToObject(&result)) return maybe_result;
1011 }
Steve Block6ded16b2010-05-10 14:33:55 +01001012 JSArray* result_array = JSArray::cast(result);
1013
John Reck59135872010-11-02 12:39:01 -07001014 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01001015 heap->AllocateUninitializedFixedArray(result_len);
John Reck59135872010-11-02 12:39:01 -07001016 if (!maybe_result->ToObject(&result)) return maybe_result;
1017 }
Steve Block6ded16b2010-05-10 14:33:55 +01001018 FixedArray* result_elms = FixedArray::cast(result);
1019
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001020 // Ensure element type transitions happen before copying elements in.
1021 if (result_array->HasFastSmiOnlyElements()) {
1022 for (int i = 0; i < n_arguments; i++) {
1023 JSArray* array = JSArray::cast(args[i]);
1024 if (!array->HasFastSmiOnlyElements()) {
1025 result_array->EnsureCanContainNonSmiElements();
1026 break;
1027 }
1028 }
1029 }
1030
Steve Block6ded16b2010-05-10 14:33:55 +01001031 // Copy data.
1032 AssertNoAllocation no_gc;
1033 int start_pos = 0;
1034 for (int i = 0; i < n_arguments; i++) {
1035 JSArray* array = JSArray::cast(args[i]);
1036 int len = Smi::cast(array->length())->value();
1037 if (len > 0) {
1038 FixedArray* elms = FixedArray::cast(array->elements());
Steve Block44f0eee2011-05-26 01:26:41 +01001039 CopyElements(heap, &no_gc, result_elms, start_pos, elms, 0, len);
Steve Block6ded16b2010-05-10 14:33:55 +01001040 start_pos += len;
1041 }
1042 }
1043 ASSERT(start_pos == result_len);
1044
1045 // Set the length and elements.
1046 result_array->set_length(Smi::FromInt(result_len));
1047 result_array->set_elements(result_elms);
1048
1049 return result_array;
1050}
1051
1052
Steve Blocka7e24c12009-10-30 11:49:00 +00001053// -----------------------------------------------------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +01001054// Strict mode poison pills
1055
1056
Ben Murdoch257744e2011-11-30 15:57:28 +00001057BUILTIN(StrictModePoisonPill) {
Steve Block44f0eee2011-05-26 01:26:41 +01001058 HandleScope scope;
1059 return isolate->Throw(*isolate->factory()->NewTypeError(
Ben Murdoch257744e2011-11-30 15:57:28 +00001060 "strict_poison_pill", HandleVector<Object>(NULL, 0)));
Steve Block44f0eee2011-05-26 01:26:41 +01001061}
1062
Steve Block44f0eee2011-05-26 01:26:41 +01001063// -----------------------------------------------------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001064//
1065
1066
1067// Returns the holder JSObject if the function can legally be called
1068// with this receiver. Returns Heap::null_value() if the call is
1069// illegal. Any arguments that don't fit the expected type is
1070// overwritten with undefined. Arguments that do fit the expected
1071// type is overwritten with the object in the prototype chain that
1072// actually has that type.
Steve Block44f0eee2011-05-26 01:26:41 +01001073static inline Object* TypeCheck(Heap* heap,
1074 int argc,
Steve Blocka7e24c12009-10-30 11:49:00 +00001075 Object** argv,
1076 FunctionTemplateInfo* info) {
1077 Object* recv = argv[0];
Ben Murdoch257744e2011-11-30 15:57:28 +00001078 // API calls are only supported with JSObject receivers.
1079 if (!recv->IsJSObject()) return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 Object* sig_obj = info->signature();
1081 if (sig_obj->IsUndefined()) return recv;
1082 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
1083 // If necessary, check the receiver
1084 Object* recv_type = sig->receiver();
1085
1086 Object* holder = recv;
1087 if (!recv_type->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001088 for (; holder != heap->null_value(); holder = holder->GetPrototype()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001089 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
1090 break;
1091 }
1092 }
Steve Block44f0eee2011-05-26 01:26:41 +01001093 if (holder == heap->null_value()) return holder;
Steve Blocka7e24c12009-10-30 11:49:00 +00001094 }
1095 Object* args_obj = sig->args();
1096 // If there is no argument signature we're done
1097 if (args_obj->IsUndefined()) return holder;
1098 FixedArray* args = FixedArray::cast(args_obj);
1099 int length = args->length();
1100 if (argc <= length) length = argc - 1;
1101 for (int i = 0; i < length; i++) {
1102 Object* argtype = args->get(i);
1103 if (argtype->IsUndefined()) continue;
1104 Object** arg = &argv[-1 - i];
1105 Object* current = *arg;
Steve Block44f0eee2011-05-26 01:26:41 +01001106 for (; current != heap->null_value(); current = current->GetPrototype()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001107 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
1108 *arg = current;
1109 break;
1110 }
1111 }
Steve Block44f0eee2011-05-26 01:26:41 +01001112 if (current == heap->null_value()) *arg = heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001113 }
1114 return holder;
1115}
1116
1117
Leon Clarkee46be812010-01-19 14:06:41 +00001118template <bool is_construct>
John Reck59135872010-11-02 12:39:01 -07001119MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
Steve Block44f0eee2011-05-26 01:26:41 +01001120 BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
1121 ASSERT(is_construct == CalledAsConstructor(isolate));
1122 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001123
Steve Block44f0eee2011-05-26 01:26:41 +01001124 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00001125 Handle<JSFunction> function = args.called_function();
Steve Block6ded16b2010-05-10 14:33:55 +01001126 ASSERT(function->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001127
Steve Block6ded16b2010-05-10 14:33:55 +01001128 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
Steve Blocka7e24c12009-10-30 11:49:00 +00001129 if (is_construct) {
Steve Block44f0eee2011-05-26 01:26:41 +01001130 Handle<FunctionTemplateInfo> desc(fun_data, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001131 bool pending_exception = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001132 isolate->factory()->ConfigureInstance(
1133 desc, Handle<JSObject>::cast(args.receiver()), &pending_exception);
1134 ASSERT(isolate->has_pending_exception() == pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +00001135 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +01001136 fun_data = *desc;
Steve Blocka7e24c12009-10-30 11:49:00 +00001137 }
1138
Steve Block44f0eee2011-05-26 01:26:41 +01001139 Object* raw_holder = TypeCheck(heap, args.length(), &args[0], fun_data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001140
1141 if (raw_holder->IsNull()) {
1142 // This function cannot be called with the given receiver. Abort!
1143 Handle<Object> obj =
Steve Block44f0eee2011-05-26 01:26:41 +01001144 isolate->factory()->NewTypeError(
1145 "illegal_invocation", HandleVector(&function, 1));
1146 return isolate->Throw(*obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00001147 }
1148
1149 Object* raw_call_data = fun_data->call_code();
1150 if (!raw_call_data->IsUndefined()) {
1151 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1152 Object* callback_obj = call_data->callback();
1153 v8::InvocationCallback callback =
1154 v8::ToCData<v8::InvocationCallback>(callback_obj);
1155 Object* data_obj = call_data->data();
1156 Object* result;
1157
Steve Block44f0eee2011-05-26 01:26:41 +01001158 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001159 ASSERT(raw_holder->IsJSObject());
1160
Steve Block44f0eee2011-05-26 01:26:41 +01001161 CustomArguments custom(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001162 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1163 data_obj, *function, raw_holder);
1164
Steve Blocka7e24c12009-10-30 11:49:00 +00001165 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001166 custom.end(),
1167 &args[0] - 1,
1168 args.length() - 1,
1169 is_construct);
Steve Blocka7e24c12009-10-30 11:49:00 +00001170
1171 v8::Handle<v8::Value> value;
1172 {
1173 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001174 VMState state(isolate, EXTERNAL);
1175 ExternalCallbackScope call_scope(isolate,
1176 v8::ToCData<Address>(callback_obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00001177 value = callback(new_args);
1178 }
1179 if (value.IsEmpty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001180 result = heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001181 } else {
1182 result = *reinterpret_cast<Object**>(*value);
1183 }
1184
Steve Block44f0eee2011-05-26 01:26:41 +01001185 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001186 if (!is_construct || result->IsJSObject()) return result;
1187 }
1188
Leon Clarkee46be812010-01-19 14:06:41 +00001189 return *args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +00001190}
Leon Clarkee46be812010-01-19 14:06:41 +00001191
1192
1193BUILTIN(HandleApiCall) {
Steve Block44f0eee2011-05-26 01:26:41 +01001194 return HandleApiCallHelper<false>(args, isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00001195}
1196
1197
1198BUILTIN(HandleApiCallConstruct) {
Steve Block44f0eee2011-05-26 01:26:41 +01001199 return HandleApiCallHelper<true>(args, isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00001200}
Steve Blocka7e24c12009-10-30 11:49:00 +00001201
1202
Andrei Popescu402d9372010-02-26 13:31:12 +00001203#ifdef DEBUG
1204
1205static void VerifyTypeCheck(Handle<JSObject> object,
1206 Handle<JSFunction> function) {
Steve Block6ded16b2010-05-10 14:33:55 +01001207 ASSERT(function->shared()->IsApiFunction());
1208 FunctionTemplateInfo* info = function->shared()->get_api_func_data();
Andrei Popescu402d9372010-02-26 13:31:12 +00001209 if (info->signature()->IsUndefined()) return;
1210 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1211 Object* receiver_type = signature->receiver();
1212 if (receiver_type->IsUndefined()) return;
1213 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
1214 ASSERT(object->IsInstanceOf(type));
1215}
1216
1217#endif
1218
1219
1220BUILTIN(FastHandleApiCall) {
Steve Block44f0eee2011-05-26 01:26:41 +01001221 ASSERT(!CalledAsConstructor(isolate));
1222 Heap* heap = isolate->heap();
Andrei Popescu402d9372010-02-26 13:31:12 +00001223 const bool is_construct = false;
1224
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001225 // We expect four more arguments: callback, function, call data, and holder.
Andrei Popescu402d9372010-02-26 13:31:12 +00001226 const int args_length = args.length() - 4;
1227 ASSERT(args_length >= 0);
1228
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001229 Object* callback_obj = args[args_length];
Andrei Popescu402d9372010-02-26 13:31:12 +00001230
1231 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001232 &args[args_length + 1],
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001233 &args[0] - 1,
1234 args_length - 1,
1235 is_construct);
Andrei Popescu402d9372010-02-26 13:31:12 +00001236
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001237#ifdef DEBUG
1238 VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()),
1239 Utils::OpenHandle(*new_args.Callee()));
1240#endif
Steve Block44f0eee2011-05-26 01:26:41 +01001241 HandleScope scope(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00001242 Object* result;
1243 v8::Handle<v8::Value> value;
1244 {
1245 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001246 VMState state(isolate, EXTERNAL);
1247 ExternalCallbackScope call_scope(isolate,
1248 v8::ToCData<Address>(callback_obj));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001249 v8::InvocationCallback callback =
1250 v8::ToCData<v8::InvocationCallback>(callback_obj);
1251
Andrei Popescu402d9372010-02-26 13:31:12 +00001252 value = callback(new_args);
1253 }
1254 if (value.IsEmpty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001255 result = heap->undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00001256 } else {
1257 result = *reinterpret_cast<Object**>(*value);
1258 }
1259
Steve Block44f0eee2011-05-26 01:26:41 +01001260 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00001261 return result;
1262}
1263
1264
Steve Blocka7e24c12009-10-30 11:49:00 +00001265// Helper function to handle calls to non-function objects created through the
1266// API. The object can be called as either a constructor (using new) or just as
1267// a function (without new).
John Reck59135872010-11-02 12:39:01 -07001268MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
Steve Block44f0eee2011-05-26 01:26:41 +01001269 Isolate* isolate,
Leon Clarkee46be812010-01-19 14:06:41 +00001270 bool is_construct_call,
1271 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001272 // Non-functions are never called as constructors. Even if this is an object
1273 // called as a constructor the delegate call is not a construct call.
Steve Block44f0eee2011-05-26 01:26:41 +01001274 ASSERT(!CalledAsConstructor(isolate));
1275 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001276
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001277 Handle<Object> receiver = args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +00001278
1279 // Get the object called.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001280 JSObject* obj = JSObject::cast(*receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00001281
1282 // Get the invocation callback from the function descriptor that was
1283 // used to create the called object.
1284 ASSERT(obj->map()->has_instance_call_handler());
1285 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01001286 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001287 Object* handler =
Steve Block6ded16b2010-05-10 14:33:55 +01001288 constructor->shared()->get_api_func_data()->instance_call_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00001289 ASSERT(!handler->IsUndefined());
1290 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1291 Object* callback_obj = call_data->callback();
1292 v8::InvocationCallback callback =
1293 v8::ToCData<v8::InvocationCallback>(callback_obj);
1294
1295 // Get the data for the call and perform the callback.
Steve Blocka7e24c12009-10-30 11:49:00 +00001296 Object* result;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001297 {
Steve Block44f0eee2011-05-26 01:26:41 +01001298 HandleScope scope(isolate);
1299 LOG(isolate, ApiObjectAccess("call non-function", obj));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001300
Steve Block44f0eee2011-05-26 01:26:41 +01001301 CustomArguments custom(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001302 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1303 call_data->data(), constructor, obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001305 custom.end(),
1306 &args[0] - 1,
1307 args.length() - 1,
1308 is_construct_call);
Steve Blocka7e24c12009-10-30 11:49:00 +00001309 v8::Handle<v8::Value> value;
1310 {
1311 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001312 VMState state(isolate, EXTERNAL);
1313 ExternalCallbackScope call_scope(isolate,
1314 v8::ToCData<Address>(callback_obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00001315 value = callback(new_args);
1316 }
1317 if (value.IsEmpty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001318 result = heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001319 } else {
1320 result = *reinterpret_cast<Object**>(*value);
1321 }
1322 }
1323 // Check for exceptions and return result.
Steve Block44f0eee2011-05-26 01:26:41 +01001324 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001325 return result;
1326}
1327
1328
1329// Handle calls to non-function objects created through the API. This delegate
1330// function is used when the call is a normal function call.
1331BUILTIN(HandleApiCallAsFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +01001332 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001333}
Steve Blocka7e24c12009-10-30 11:49:00 +00001334
1335
1336// Handle calls to non-function objects created through the API. This delegate
1337// function is used when the call is a construct call.
1338BUILTIN(HandleApiCallAsConstructor) {
Steve Block44f0eee2011-05-26 01:26:41 +01001339 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001340}
Steve Blocka7e24c12009-10-30 11:49:00 +00001341
1342
1343static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1344 LoadIC::GenerateArrayLength(masm);
1345}
1346
1347
1348static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
Steve Block1e0659c2011-05-24 12:43:12 +01001349 LoadIC::GenerateStringLength(masm, false);
1350}
1351
1352
1353static void Generate_LoadIC_StringWrapperLength(MacroAssembler* masm) {
1354 LoadIC::GenerateStringLength(masm, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001355}
1356
1357
1358static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1359 LoadIC::GenerateFunctionPrototype(masm);
1360}
1361
1362
1363static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1364 LoadIC::GenerateInitialize(masm);
1365}
1366
1367
1368static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1369 LoadIC::GeneratePreMonomorphic(masm);
1370}
1371
1372
1373static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1374 LoadIC::GenerateMiss(masm);
1375}
1376
1377
1378static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1379 LoadIC::GenerateMegamorphic(masm);
1380}
1381
1382
1383static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1384 LoadIC::GenerateNormal(masm);
1385}
1386
1387
1388static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1389 KeyedLoadIC::GenerateInitialize(masm);
1390}
1391
1392
Ben Murdoch257744e2011-11-30 15:57:28 +00001393static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
1394 KeyedLoadIC::GenerateRuntimeGetProperty(masm);
1395}
1396
1397
Steve Blocka7e24c12009-10-30 11:49:00 +00001398static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001399 KeyedLoadIC::GenerateMiss(masm, false);
1400}
1401
1402
1403static void Generate_KeyedLoadIC_MissForceGeneric(MacroAssembler* masm) {
1404 KeyedLoadIC::GenerateMiss(masm, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001405}
1406
1407
1408static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1409 KeyedLoadIC::GenerateGeneric(masm);
1410}
1411
1412
Leon Clarkee46be812010-01-19 14:06:41 +00001413static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1414 KeyedLoadIC::GenerateString(masm);
1415}
1416
1417
Steve Blocka7e24c12009-10-30 11:49:00 +00001418static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1419 KeyedLoadIC::GeneratePreMonomorphic(masm);
1420}
1421
Andrei Popescu402d9372010-02-26 13:31:12 +00001422static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1423 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1424}
1425
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001426static void Generate_KeyedLoadIC_NonStrictArguments(MacroAssembler* masm) {
1427 KeyedLoadIC::GenerateNonStrictArguments(masm);
1428}
Steve Blocka7e24c12009-10-30 11:49:00 +00001429
1430static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1431 StoreIC::GenerateInitialize(masm);
1432}
1433
1434
Steve Block1e0659c2011-05-24 12:43:12 +01001435static void Generate_StoreIC_Initialize_Strict(MacroAssembler* masm) {
1436 StoreIC::GenerateInitialize(masm);
1437}
1438
1439
Steve Blocka7e24c12009-10-30 11:49:00 +00001440static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1441 StoreIC::GenerateMiss(masm);
1442}
1443
1444
Steve Block8defd9f2010-07-08 12:39:36 +01001445static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1446 StoreIC::GenerateNormal(masm);
1447}
1448
1449
Steve Block1e0659c2011-05-24 12:43:12 +01001450static void Generate_StoreIC_Normal_Strict(MacroAssembler* masm) {
1451 StoreIC::GenerateNormal(masm);
1452}
1453
1454
Steve Blocka7e24c12009-10-30 11:49:00 +00001455static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001456 StoreIC::GenerateMegamorphic(masm, kNonStrictMode);
Steve Block1e0659c2011-05-24 12:43:12 +01001457}
1458
1459
1460static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001461 StoreIC::GenerateMegamorphic(masm, kStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001462}
1463
1464
Steve Block6ded16b2010-05-10 14:33:55 +01001465static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1466 StoreIC::GenerateArrayLength(masm);
1467}
1468
1469
Steve Block1e0659c2011-05-24 12:43:12 +01001470static void Generate_StoreIC_ArrayLength_Strict(MacroAssembler* masm) {
1471 StoreIC::GenerateArrayLength(masm);
1472}
1473
1474
Ben Murdochb0fe1622011-05-05 13:52:32 +01001475static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001476 StoreIC::GenerateGlobalProxy(masm, kNonStrictMode);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001477}
1478
1479
Steve Block1e0659c2011-05-24 12:43:12 +01001480static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001481 StoreIC::GenerateGlobalProxy(masm, kStrictMode);
Steve Block1e0659c2011-05-24 12:43:12 +01001482}
1483
1484
Steve Blocka7e24c12009-10-30 11:49:00 +00001485static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001486 KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode);
1487}
1488
1489
1490static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) {
1491 KeyedStoreIC::GenerateGeneric(masm, kStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001492}
1493
1494
Steve Blocka7e24c12009-10-30 11:49:00 +00001495static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
Ben Murdoch257744e2011-11-30 15:57:28 +00001496 KeyedStoreIC::GenerateMiss(masm, false);
1497}
1498
1499
1500static void Generate_KeyedStoreIC_MissForceGeneric(MacroAssembler* masm) {
1501 KeyedStoreIC::GenerateMiss(masm, true);
1502}
1503
1504
1505static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
1506 KeyedStoreIC::GenerateSlow(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001507}
1508
1509
1510static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1511 KeyedStoreIC::GenerateInitialize(masm);
1512}
1513
1514
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001515static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
1516 KeyedStoreIC::GenerateInitialize(masm);
1517}
1518
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001519static void Generate_KeyedStoreIC_NonStrictArguments(MacroAssembler* masm) {
1520 KeyedStoreIC::GenerateNonStrictArguments(masm);
1521}
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001522
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001523static void Generate_TransitionElementsSmiToDouble(MacroAssembler* masm) {
1524 KeyedStoreIC::GenerateTransitionElementsSmiToDouble(masm);
1525}
1526
1527static void Generate_TransitionElementsDoubleToObject(MacroAssembler* masm) {
1528 KeyedStoreIC::GenerateTransitionElementsDoubleToObject(masm);
1529}
1530
Steve Blocka7e24c12009-10-30 11:49:00 +00001531#ifdef ENABLE_DEBUGGER_SUPPORT
1532static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1533 Debug::GenerateLoadICDebugBreak(masm);
1534}
1535
1536
1537static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1538 Debug::GenerateStoreICDebugBreak(masm);
1539}
1540
1541
1542static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1543 Debug::GenerateKeyedLoadICDebugBreak(masm);
1544}
1545
1546
1547static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1548 Debug::GenerateKeyedStoreICDebugBreak(masm);
1549}
1550
1551
1552static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1553 Debug::GenerateConstructCallDebugBreak(masm);
1554}
1555
1556
1557static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1558 Debug::GenerateReturnDebugBreak(masm);
1559}
1560
1561
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001562static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) {
1563 Debug::GenerateCallFunctionStubDebugBreak(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001564}
Steve Block6ded16b2010-05-10 14:33:55 +01001565
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001566
1567static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1568 Debug::GenerateSlotDebugBreak(masm);
1569}
1570
1571
Steve Block6ded16b2010-05-10 14:33:55 +01001572static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1573 Debug::GeneratePlainReturnLiveEdit(masm);
1574}
1575
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001576
Steve Block6ded16b2010-05-10 14:33:55 +01001577static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1578 Debug::GenerateFrameDropperLiveEdit(masm);
1579}
Steve Blocka7e24c12009-10-30 11:49:00 +00001580#endif
1581
Steve Block44f0eee2011-05-26 01:26:41 +01001582
1583Builtins::Builtins() : initialized_(false) {
1584 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
1585 memset(names_, 0, sizeof(names_[0]) * builtin_count);
1586}
1587
1588
1589Builtins::~Builtins() {
1590}
1591
Steve Blocka7e24c12009-10-30 11:49:00 +00001592
Leon Clarkee46be812010-01-19 14:06:41 +00001593#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Steve Block44f0eee2011-05-26 01:26:41 +01001594Address const Builtins::c_functions_[cfunction_count] = {
1595 BUILTIN_LIST_C(DEF_ENUM_C)
1596};
Steve Blocka7e24c12009-10-30 11:49:00 +00001597#undef DEF_ENUM_C
1598
1599#define DEF_JS_NAME(name, ignore) #name,
1600#define DEF_JS_ARGC(ignore, argc) argc,
Steve Block44f0eee2011-05-26 01:26:41 +01001601const char* const Builtins::javascript_names_[id_count] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00001602 BUILTINS_LIST_JS(DEF_JS_NAME)
1603};
1604
Steve Block44f0eee2011-05-26 01:26:41 +01001605int const Builtins::javascript_argc_[id_count] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00001606 BUILTINS_LIST_JS(DEF_JS_ARGC)
1607};
1608#undef DEF_JS_NAME
1609#undef DEF_JS_ARGC
1610
Steve Block44f0eee2011-05-26 01:26:41 +01001611struct BuiltinDesc {
1612 byte* generator;
1613 byte* c_code;
1614 const char* s_name; // name is only used for generating log information.
1615 int name;
1616 Code::Flags flags;
1617 BuiltinExtraArguments extra_args;
1618};
1619
1620class BuiltinFunctionTable {
1621 public:
1622 BuiltinFunctionTable() {
1623 Builtins::InitBuiltinFunctionTable();
1624 }
1625
1626 static const BuiltinDesc* functions() { return functions_; }
1627
1628 private:
1629 static BuiltinDesc functions_[Builtins::builtin_count + 1];
1630
1631 friend class Builtins;
1632};
1633
1634BuiltinDesc BuiltinFunctionTable::functions_[Builtins::builtin_count + 1];
1635
1636static const BuiltinFunctionTable builtin_function_table_init;
1637
1638// Define array of pointers to generators and C builtin functions.
1639// We do this in a sort of roundabout way so that we can do the initialization
1640// within the lexical scope of Builtins:: and within a context where
1641// Code::Flags names a non-abstract type.
1642void Builtins::InitBuiltinFunctionTable() {
1643 BuiltinDesc* functions = BuiltinFunctionTable::functions_;
1644 functions[builtin_count].generator = NULL;
1645 functions[builtin_count].c_code = NULL;
1646 functions[builtin_count].s_name = NULL;
1647 functions[builtin_count].name = builtin_count;
1648 functions[builtin_count].flags = static_cast<Code::Flags>(0);
1649 functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
1650
1651#define DEF_FUNCTION_PTR_C(aname, aextra_args) \
1652 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
1653 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
1654 functions->s_name = #aname; \
1655 functions->name = c_##aname; \
1656 functions->flags = Code::ComputeFlags(Code::BUILTIN); \
1657 functions->extra_args = aextra_args; \
1658 ++functions;
1659
1660#define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
1661 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1662 functions->c_code = NULL; \
1663 functions->s_name = #aname; \
1664 functions->name = k##aname; \
1665 functions->flags = Code::ComputeFlags(Code::kind, \
Steve Block44f0eee2011-05-26 01:26:41 +01001666 state, \
1667 extra); \
1668 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1669 ++functions;
1670
1671 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1672 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1673 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1674
1675#undef DEF_FUNCTION_PTR_C
1676#undef DEF_FUNCTION_PTR_A
1677}
1678
Steve Blocka7e24c12009-10-30 11:49:00 +00001679void Builtins::Setup(bool create_heap_objects) {
Steve Block44f0eee2011-05-26 01:26:41 +01001680 ASSERT(!initialized_);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001681 Isolate* isolate = Isolate::Current();
1682 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001683
1684 // Create a scope for the handles in the builtins.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001685 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001686
Steve Block44f0eee2011-05-26 01:26:41 +01001687 const BuiltinDesc* functions = BuiltinFunctionTable::functions();
Steve Blocka7e24c12009-10-30 11:49:00 +00001688
1689 // For now we generate builtin adaptor code into a stack-allocated
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001690 // buffer, before copying it into individual code objects. Be careful
1691 // with alignment, some platforms don't like unaligned code.
1692 union { int force_alignment; byte buffer[4*KB]; } u;
Steve Blocka7e24c12009-10-30 11:49:00 +00001693
1694 // Traverse the list of builtins and generate an adaptor in a
1695 // separate code object for each one.
1696 for (int i = 0; i < builtin_count; i++) {
1697 if (create_heap_objects) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001698 MacroAssembler masm(isolate, u.buffer, sizeof u.buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00001699 // Generate the code/adaptor.
Leon Clarkee46be812010-01-19 14:06:41 +00001700 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001701 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1702 // We pass all arguments to the generator, but it may not use all of
1703 // them. This works because the first arguments are on top of the
1704 // stack.
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001705 ASSERT(!masm.has_frame());
Leon Clarkee46be812010-01-19 14:06:41 +00001706 g(&masm, functions[i].name, functions[i].extra_args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001707 // Move the code into the object heap.
1708 CodeDesc desc;
1709 masm.GetCode(&desc);
1710 Code::Flags flags = functions[i].flags;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001711 Object* code = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00001712 {
1713 // During startup it's OK to always allocate and defer GC to later.
1714 // This simplifies things because we don't need to retry.
1715 AlwaysAllocateScope __scope__;
John Reck59135872010-11-02 12:39:01 -07001716 { MaybeObject* maybe_code =
Steve Block44f0eee2011-05-26 01:26:41 +01001717 heap->CreateCode(desc, flags, masm.CodeObject());
John Reck59135872010-11-02 12:39:01 -07001718 if (!maybe_code->ToObject(&code)) {
1719 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1720 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001721 }
1722 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001723 // Log the event and add the code to the builtins array.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001724 PROFILE(isolate,
Steve Block44f0eee2011-05-26 01:26:41 +01001725 CodeCreateEvent(Logger::BUILTIN_TAG,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001726 Code::cast(code),
1727 functions[i].s_name));
1728 GDBJIT(AddCode(GDBJITInterface::BUILTIN,
1729 functions[i].s_name,
1730 Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001731 builtins_[i] = code;
1732#ifdef ENABLE_DISASSEMBLER
1733 if (FLAG_print_builtin_code) {
1734 PrintF("Builtin: %s\n", functions[i].s_name);
1735 Code::cast(code)->Disassemble(functions[i].s_name);
1736 PrintF("\n");
1737 }
1738#endif
1739 } else {
1740 // Deserializing. The values will be filled in during IterateBuiltins.
1741 builtins_[i] = NULL;
1742 }
1743 names_[i] = functions[i].s_name;
1744 }
1745
1746 // Mark as initialized.
Steve Block44f0eee2011-05-26 01:26:41 +01001747 initialized_ = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001748}
1749
1750
1751void Builtins::TearDown() {
Steve Block44f0eee2011-05-26 01:26:41 +01001752 initialized_ = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001753}
1754
1755
1756void Builtins::IterateBuiltins(ObjectVisitor* v) {
1757 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1758}
1759
1760
1761const char* Builtins::Lookup(byte* pc) {
Steve Block44f0eee2011-05-26 01:26:41 +01001762 // may be called during initialization (disassembler!)
1763 if (initialized_) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001764 for (int i = 0; i < builtin_count; i++) {
1765 Code* entry = Code::cast(builtins_[i]);
1766 if (entry->contains(pc)) {
1767 return names_[i];
1768 }
1769 }
1770 }
1771 return NULL;
1772}
1773
Ben Murdochb0fe1622011-05-05 13:52:32 +01001774
Steve Block44f0eee2011-05-26 01:26:41 +01001775#define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
1776Handle<Code> Builtins::name() { \
1777 Code** code_address = \
1778 reinterpret_cast<Code**>(builtin_address(k##name)); \
1779 return Handle<Code>(code_address); \
1780}
1781#define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
1782Handle<Code> Builtins::name() { \
1783 Code** code_address = \
1784 reinterpret_cast<Code**>(builtin_address(k##name)); \
1785 return Handle<Code>(code_address); \
1786}
1787BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1788BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1789BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1790#undef DEFINE_BUILTIN_ACCESSOR_C
1791#undef DEFINE_BUILTIN_ACCESSOR_A
1792
1793
Steve Blocka7e24c12009-10-30 11:49:00 +00001794} } // namespace v8::internal