blob: 64ec3d9fcc485f9d8fe9c7856072c4f5c4cea84b [file] [log] [blame]
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000031#include "arguments.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "bootstrapper.h"
33#include "builtins.h"
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000034#include "gdb-jit.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "ic-inl.h"
ulan@chromium.org6ff65142012-03-21 09:52:17 +000036#include "heap-profiler.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000037#include "mark-compact.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000038#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
kasperl@chromium.org71affb52009-05-26 05:44:31 +000040namespace v8 {
41namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112// ----------------------------------------------------------------------------
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000113// Support macro for defining builtins in C++.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000114// ----------------------------------------------------------------------------
115//
116// A builtin function is defined by writing:
117//
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000118// BUILTIN(name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000119// ...
120// }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121//
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000122// In the body of the builtin function the arguments can be accessed
123// through the BuiltinArguments object args.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125#ifdef DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000127#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)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000138
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000139#else // For release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000141#define BUILTIN(name) \
142 static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000143
144#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000145
146
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000147static inline bool CalledAsConstructor(Isolate* isolate) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +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.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000152 StackFrameIterator it;
153 ASSERT(it.frame()->is_exit());
154 it.Advance();
155 StackFrame* frame = it.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000156 bool reference_result = frame->is_construct();
157#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +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;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000173}
174
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000175// ----------------------------------------------------------------------------
176
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000177BUILTIN(Illegal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000178 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000179 return isolate->heap()->undefined_value(); // Make compiler happy.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000180}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181
182
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000183BUILTIN(EmptyFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000184 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000186
187
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000188static MaybeObject* ArrayCodeGenericCommon(Arguments* args,
189 Isolate* isolate,
190 JSFunction* constructor) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000191 Heap* heap = isolate->heap();
192 isolate->counters()->array_function_runtime()->Increment();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000193
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000194 JSArray* array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000195 if (CalledAsConstructor(isolate)) {
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000196 array = JSArray::cast((*args)[0]);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000197 // 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();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000203 if (array->GetElementsKind() == GetInitialFastElementsKind() &&
204 !global_context->js_array_maps()->IsUndefined()) {
205 FixedArray* map_array =
206 FixedArray::cast(global_context->js_array_maps());
207 array->set_map(Map::cast(map_array->
208 get(TERMINAL_FAST_ELEMENTS_KIND)));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000209 }
210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000211 } else {
212 // Allocate the JS Array
yangguo@chromium.org56454712012-02-16 15:33:53 +0000213 MaybeObject* maybe_obj = heap->AllocateJSObject(constructor);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000214 if (!maybe_obj->To(&array)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000215 }
216
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000217 // Optimize the case where there is one argument and the argument is a
218 // small smi.
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000219 if (args->length() == 2) {
220 Object* obj = (*args)[1];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000221 if (obj->IsSmi()) {
222 int len = Smi::cast(obj)->value();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000223 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
yangguo@chromium.org56454712012-02-16 15:33:53 +0000224 Object* fixed_array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000225 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
yangguo@chromium.org56454712012-02-16 15:33:53 +0000226 if (!maybe_obj->ToObject(&fixed_array)) return maybe_obj;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000227 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000228 ElementsKind elements_kind = array->GetElementsKind();
229 if (!IsFastHoleyElementsKind(elements_kind)) {
230 elements_kind = GetHoleyElementsKind(elements_kind);
231 MaybeObject* maybe_array =
232 array->TransitionElementsKind(elements_kind);
233 if (maybe_array->IsFailure()) return maybe_array;
234 }
yangguo@chromium.org56454712012-02-16 15:33:53 +0000235 // We do not use SetContent to skip the unnecessary elements type check.
236 array->set_elements(FixedArray::cast(fixed_array));
237 array->set_length(Smi::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000238 return array;
239 }
240 }
241 // Take the argument as the length.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000242 { MaybeObject* maybe_obj = array->Initialize(0);
243 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
244 }
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000245 return array->SetElementsLength((*args)[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000246 }
247
v8.team.kasperl727e9952008-09-02 14:56:44 +0000248 // Optimize the case where there are no parameters passed.
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000249 if (args->length() == 1) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000250 return array->Initialize(JSArray::kPreallocatedArrayElements);
251 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000253 // Set length and elements on the array.
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000254 int number_of_elements = args->length() - 1;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000255 MaybeObject* maybe_object =
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000256 array->EnsureCanContainElements(args, 1, number_of_elements,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000257 ALLOW_CONVERTED_DOUBLE_ELEMENTS);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000258 if (maybe_object->IsFailure()) return maybe_object;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000259
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000260 // Allocate an appropriately typed elements array.
261 MaybeObject* maybe_elms;
262 ElementsKind elements_kind = array->GetElementsKind();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000263 if (IsFastDoubleElementsKind(elements_kind)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000264 maybe_elms = heap->AllocateUninitializedFixedDoubleArray(
265 number_of_elements);
266 } else {
267 maybe_elms = heap->AllocateFixedArrayWithHoles(number_of_elements);
268 }
269 FixedArrayBase* elms;
270 if (!maybe_elms->To<FixedArrayBase>(&elms)) return maybe_elms;
271
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000272 // Fill in the content
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000273 switch (array->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000274 case FAST_HOLEY_SMI_ELEMENTS:
275 case FAST_SMI_ELEMENTS: {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000276 FixedArray* smi_elms = FixedArray::cast(elms);
277 for (int index = 0; index < number_of_elements; index++) {
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000278 smi_elms->set(index, (*args)[index+1], SKIP_WRITE_BARRIER);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000279 }
280 break;
281 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000282 case FAST_HOLEY_ELEMENTS:
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000283 case FAST_ELEMENTS: {
284 AssertNoAllocation no_gc;
285 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
286 FixedArray* object_elms = FixedArray::cast(elms);
287 for (int index = 0; index < number_of_elements; index++) {
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000288 object_elms->set(index, (*args)[index+1], mode);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000289 }
290 break;
291 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000292 case FAST_HOLEY_DOUBLE_ELEMENTS:
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000293 case FAST_DOUBLE_ELEMENTS: {
294 FixedDoubleArray* double_elms = FixedDoubleArray::cast(elms);
295 for (int index = 0; index < number_of_elements; index++) {
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000296 double_elms->set(index, (*args)[index+1]->Number());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000297 }
298 break;
299 }
300 default:
301 UNREACHABLE();
302 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000303 }
304
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000305 array->set_elements(elms);
306 array->set_length(Smi::FromInt(number_of_elements));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000307 return array;
308}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309
310
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +0000311BUILTIN(InternalArrayCodeGeneric) {
312 return ArrayCodeGenericCommon(
313 &args,
314 isolate,
315 isolate->context()->global_context()->internal_array_function());
316}
317
318
319BUILTIN(ArrayCodeGeneric) {
320 return ArrayCodeGenericCommon(
321 &args,
322 isolate,
323 isolate->context()->global_context()->array_function());
324}
325
326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000327static void MoveElements(Heap* heap,
328 AssertNoAllocation* no_gc,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000329 FixedArray* dst,
330 int dst_index,
331 FixedArray* src,
332 int src_index,
333 int len) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000334 if (len == 0) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000335 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000336 memmove(dst->data_start() + dst_index,
337 src->data_start() + src_index,
338 len * kPointerSize);
339 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
340 if (mode == UPDATE_WRITE_BARRIER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000341 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000342 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000343 heap->incremental_marking()->RecordWrites(dst);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000344}
345
346
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000347static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) {
348 ASSERT(dst->map() != heap->fixed_cow_array_map());
349 MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000350}
351
352
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000353static FixedArray* LeftTrimFixedArray(Heap* heap,
354 FixedArray* elms,
355 int to_trim) {
356 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000357 // For now this trick is only applied to fixed arrays in new and paged space.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000358 // In large object space the object's start must coincide with chunk
359 // and thus the trick is just not applicable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 ASSERT(!HEAP->lo_space()->Contains(elms));
lrn@chromium.org25156de2010-04-06 13:10:27 +0000361
362 STATIC_ASSERT(FixedArray::kMapOffset == 0);
363 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
364 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
365
366 Object** former_start = HeapObject::RawField(elms, 0);
367
368 const int len = elms->length();
369
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000370 if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000371 !heap->new_space()->Contains(elms)) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000372 // If we are doing a big trim in old space then we zap the space that was
373 // formerly part of the array so that the GC (aided by the card-based
374 // remembered set) won't find pointers to new-space there.
375 Object** zap = reinterpret_cast<Object**>(elms->address());
376 zap++; // Header of filler must be at least one word so skip that.
377 for (int i = 1; i < to_trim; i++) {
378 *zap++ = Smi::FromInt(0);
379 }
380 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000381 // Technically in new space this write might be omitted (except for
382 // debug mode which iterates through the heap), but to play safer
383 // we still do it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000384 heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000385
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000386 former_start[to_trim] = heap->fixed_array_map();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000387 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000388
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000389 // Maintain marking consistency for HeapObjectIterator and
390 // IncrementalMarking.
391 int size_delta = to_trim * kPointerSize;
392 if (heap->marking()->TransferMark(elms->address(),
393 elms->address() + size_delta)) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000394 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000395 }
396
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000397 HEAP_PROFILE(heap, ObjectMoveEvent(elms->address(),
398 elms->address() + size_delta));
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000399 return FixedArray::cast(HeapObject::FromAddress(
400 elms->address() + to_trim * kPointerSize));
lrn@chromium.org25156de2010-04-06 13:10:27 +0000401}
402
403
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000404static bool ArrayPrototypeHasNoElements(Heap* heap,
405 Context* global_context,
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000406 JSObject* array_proto) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000407 // This method depends on non writability of Object and Array prototype
408 // fields.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000409 if (array_proto->elements() != heap->empty_fixed_array()) return false;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000410 // Object.prototype
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000411 Object* proto = array_proto->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000412 if (proto == heap->null_value()) return false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000413 array_proto = JSObject::cast(proto);
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000414 if (array_proto != global_context->initial_object_prototype()) return false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 if (array_proto->elements() != heap->empty_fixed_array()) return false;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000416 return array_proto->GetPrototype()->IsNull();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000417}
418
419
lrn@chromium.org303ada72010-10-27 09:33:13 +0000420MUST_USE_RESULT
421static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000422 Heap* heap, Object* receiver, Arguments* args, int first_added_arg) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000423 if (!receiver->IsJSArray()) return NULL;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000424 JSArray* array = JSArray::cast(receiver);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000425 HeapObject* elms = array->elements();
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000426 Map* map = elms->map();
427 if (map == heap->fixed_array_map()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000428 if (args == NULL || array->HasFastObjectElements()) return elms;
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +0000429 if (array->HasFastDoubleElements()) {
430 ASSERT(elms == heap->empty_fixed_array());
431 MaybeObject* maybe_transition =
432 array->TransitionElementsKind(FAST_ELEMENTS);
433 if (maybe_transition->IsFailure()) return maybe_transition;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000434 return elms;
435 }
436 } else if (map == heap->fixed_cow_array_map()) {
437 MaybeObject* maybe_writable_result = array->EnsureWritableFastElements();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000438 if (args == NULL || array->HasFastObjectElements() ||
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000439 maybe_writable_result->IsFailure()) {
440 return maybe_writable_result;
441 }
442 } else {
443 return NULL;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000444 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000445
446 // Need to ensure that the arguments passed in args can be contained in
447 // the array.
448 int args_length = args->length();
449 if (first_added_arg >= args_length) return array->elements();
450
451 MaybeObject* maybe_array = array->EnsureCanContainElements(
452 args,
453 first_added_arg,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000454 args_length - first_added_arg,
455 DONT_ALLOW_DOUBLE_ELEMENTS);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000456 if (maybe_array->IsFailure()) return maybe_array;
457 return array->elements();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000458}
459
460
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000461static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
462 JSArray* receiver) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000463 if (!FLAG_clever_optimizations) return false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000464 Context* global_context = heap->isolate()->context()->global_context();
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000465 JSObject* array_proto =
466 JSObject::cast(global_context->array_function()->prototype());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000467 return receiver->GetPrototype() == array_proto &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468 ArrayPrototypeHasNoElements(heap, global_context, array_proto);
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000469}
470
471
lrn@chromium.org303ada72010-10-27 09:33:13 +0000472MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000473 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000474 const char* name,
475 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000476 HandleScope handleScope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000477
478 Handle<Object> js_builtin =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000479 GetProperty(Handle<JSObject>(isolate->global_context()->builtins()),
480 name);
481 Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin);
482 int argc = args.length() - 1;
483 ScopedVector<Handle<Object> > argv(argc);
484 for (int i = 0; i < argc; ++i) {
485 argv[i] = args.at<Object>(i + 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000486 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000487 bool pending_exception;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000488 Handle<Object> result = Execution::Call(function,
489 args.receiver(),
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000490 argc,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000491 argv.start(),
492 &pending_exception);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000493 if (pending_exception) return Failure::Exception();
494 return *result;
495}
496
497
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000498BUILTIN(ArrayPush) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000499 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000500 Object* receiver = *args.receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000501 Object* elms_obj;
502 { MaybeObject* maybe_elms_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000503 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000504 if (maybe_elms_obj == NULL) {
505 return CallJsBuiltin(isolate, "ArrayPush", args);
506 }
lrn@chromium.org303ada72010-10-27 09:33:13 +0000507 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
508 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000509 FixedArray* elms = FixedArray::cast(elms_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000510 JSArray* array = JSArray::cast(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512 int len = Smi::cast(array->length())->value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000513 int to_add = args.length() - 1;
514 if (to_add == 0) {
515 return Smi::FromInt(len);
516 }
517 // Currently fixed arrays cannot grow too big, so
518 // we should never hit this case.
519 ASSERT(to_add <= (Smi::kMaxValue - len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000520
ager@chromium.org5c838252010-02-19 08:53:10 +0000521 int new_length = len + to_add;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522
ager@chromium.org5c838252010-02-19 08:53:10 +0000523 if (new_length > elms->length()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000524 // New backing storage is needed.
525 int capacity = new_length + (new_length >> 1) + 16;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000526 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000527 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000528 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
529 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000530 FixedArray* new_elms = FixedArray::cast(obj);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000531
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000532 ElementsKind kind = array->GetElementsKind();
533 CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, 0, len);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 FillWithHoles(heap, new_elms, new_length, capacity);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000535
ager@chromium.org5c838252010-02-19 08:53:10 +0000536 elms = new_elms;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000538
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000539 // Add the provided values.
ager@chromium.org5c838252010-02-19 08:53:10 +0000540 AssertNoAllocation no_gc;
541 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
ager@chromium.org5c838252010-02-19 08:53:10 +0000542 for (int index = 0; index < to_add; index++) {
543 elms->set(index + len, args[index + 1], mode);
544 }
545
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000546 if (elms != array->elements()) {
547 array->set_elements(elms);
548 }
549
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550 // Set the length.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000551 array->set_length(Smi::FromInt(new_length));
ager@chromium.org5c838252010-02-19 08:53:10 +0000552 return Smi::FromInt(new_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000554
555
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000556BUILTIN(ArrayPop) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000557 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000558 Object* receiver = *args.receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000559 Object* elms_obj;
560 { MaybeObject* maybe_elms_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000561 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000562 if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000563 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
564 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000565 FixedArray* elms = FixedArray::cast(elms_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000566 JSArray* array = JSArray::cast(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000567
568 int len = Smi::cast(array->length())->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 if (len == 0) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570
571 // Get top element
lrn@chromium.org303ada72010-10-27 09:33:13 +0000572 MaybeObject* top = elms->get(len - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573
574 // Set the length.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000575 array->set_length(Smi::FromInt(len - 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000576
577 if (!top->IsTheHole()) {
578 // Delete the top element.
579 elms->set_the_hole(len - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580 return top;
581 }
582
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000583 top = array->GetPrototype()->GetElement(len - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000584
585 return top;
586}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000587
588
ager@chromium.org5c838252010-02-19 08:53:10 +0000589BUILTIN(ArrayShift) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000590 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000591 Object* receiver = *args.receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000592 Object* elms_obj;
593 { MaybeObject* maybe_elms_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000594 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000595 if (maybe_elms_obj == NULL)
596 return CallJsBuiltin(isolate, "ArrayShift", args);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000597 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
598 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
600 return CallJsBuiltin(isolate, "ArrayShift", args);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000601 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000602 FixedArray* elms = FixedArray::cast(elms_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000603 JSArray* array = JSArray::cast(receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000604 ASSERT(array->HasFastSmiOrObjectElements());
ager@chromium.org5c838252010-02-19 08:53:10 +0000605
606 int len = Smi::cast(array->length())->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000607 if (len == 0) return heap->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000608
ager@chromium.org5c838252010-02-19 08:53:10 +0000609 // Get first element
610 Object* first = elms->get(0);
611 if (first->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000612 first = heap->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000613 }
614
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 if (!heap->lo_space()->Contains(elms)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000616 array->set_elements(LeftTrimFixedArray(heap, elms, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000617 } else {
618 // Shift the elements.
619 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
621 elms->set(len - 1, heap->the_hole_value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000622 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000623
624 // Set the length.
625 array->set_length(Smi::FromInt(len - 1));
626
627 return first;
628}
629
630
631BUILTIN(ArrayUnshift) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000633 Object* receiver = *args.receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000634 Object* elms_obj;
635 { MaybeObject* maybe_elms_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000636 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000637 if (maybe_elms_obj == NULL)
638 return CallJsBuiltin(isolate, "ArrayUnshift", args);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000639 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
640 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000641 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
642 return CallJsBuiltin(isolate, "ArrayUnshift", args);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000643 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000644 FixedArray* elms = FixedArray::cast(elms_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000645 JSArray* array = JSArray::cast(receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000646 ASSERT(array->HasFastSmiOrObjectElements());
ager@chromium.org5c838252010-02-19 08:53:10 +0000647
648 int len = Smi::cast(array->length())->value();
649 int to_add = args.length() - 1;
ager@chromium.org5c838252010-02-19 08:53:10 +0000650 int new_length = len + to_add;
651 // Currently fixed arrays cannot grow too big, so
652 // we should never hit this case.
653 ASSERT(to_add <= (Smi::kMaxValue - len));
654
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000655 MaybeObject* maybe_object =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000656 array->EnsureCanContainElements(&args, 1, to_add,
657 DONT_ALLOW_DOUBLE_ELEMENTS);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000658 if (maybe_object->IsFailure()) return maybe_object;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000659
ager@chromium.org5c838252010-02-19 08:53:10 +0000660 if (new_length > elms->length()) {
661 // New backing storage is needed.
662 int capacity = new_length + (new_length >> 1) + 16;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000663 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000664 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000665 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
666 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000667 FixedArray* new_elms = FixedArray::cast(obj);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000668 ElementsKind kind = array->GetElementsKind();
669 CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, to_add, len);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000670 FillWithHoles(heap, new_elms, new_length, capacity);
ager@chromium.org5c838252010-02-19 08:53:10 +0000671 elms = new_elms;
672 array->set_elements(elms);
673 } else {
674 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000675 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000676 }
677
678 // Add the provided values.
679 AssertNoAllocation no_gc;
680 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
681 for (int i = 0; i < to_add; i++) {
682 elms->set(i, args[i + 1], mode);
683 }
684
685 // Set the length.
686 array->set_length(Smi::FromInt(new_length));
687 return Smi::FromInt(new_length);
688}
689
690
ager@chromium.org5c838252010-02-19 08:53:10 +0000691BUILTIN(ArraySlice) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000692 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000693 Object* receiver = *args.receiver();
whesse@chromium.org023421e2010-12-21 12:19:12 +0000694 FixedArray* elms;
695 int len = -1;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000696 if (receiver->IsJSArray()) {
697 JSArray* array = JSArray::cast(receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000698 if (!array->HasFastSmiOrObjectElements() ||
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000699 !IsJSArrayFastElementMovingAllowed(heap, array)) {
700 return CallJsBuiltin(isolate, "ArraySlice", args);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000701 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000702
703 elms = FixedArray::cast(array->elements());
704 len = Smi::cast(array->length())->value();
705 } else {
706 // Array.slice(arguments, ...) is quite a common idiom (notably more
707 // than 50% of invocations in Web apps). Treat it in C++ as well.
708 Map* arguments_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000709 isolate->context()->global_context()->arguments_boilerplate()->map();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000710
711 bool is_arguments_object_with_fast_elements =
712 receiver->IsJSObject()
713 && JSObject::cast(receiver)->map() == arguments_map
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000714 && JSObject::cast(receiver)->HasFastSmiOrObjectElements();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000715 if (!is_arguments_object_with_fast_elements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000716 return CallJsBuiltin(isolate, "ArraySlice", args);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000717 }
718 elms = FixedArray::cast(JSObject::cast(receiver)->elements());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000719 Object* len_obj = JSObject::cast(receiver)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000720 ->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000721 if (!len_obj->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000722 return CallJsBuiltin(isolate, "ArraySlice", args);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000723 }
724 len = Smi::cast(len_obj)->value();
725 if (len > elms->length()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000726 return CallJsBuiltin(isolate, "ArraySlice", args);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000727 }
728 for (int i = 0; i < len; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000729 if (elms->get(i) == heap->the_hole_value()) {
730 return CallJsBuiltin(isolate, "ArraySlice", args);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000731 }
732 }
whesse@chromium.org023421e2010-12-21 12:19:12 +0000733 }
734 ASSERT(len >= 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000735 int n_arguments = args.length() - 1;
736
737 // Note carefully choosen defaults---if argument is missing,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000738 // it's undefined which gets converted to 0 for relative_start
739 // and to len for relative_end.
740 int relative_start = 0;
741 int relative_end = len;
ager@chromium.org5c838252010-02-19 08:53:10 +0000742 if (n_arguments > 0) {
743 Object* arg1 = args[1];
744 if (arg1->IsSmi()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000745 relative_start = Smi::cast(arg1)->value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000746 } else if (!arg1->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000747 return CallJsBuiltin(isolate, "ArraySlice", args);
ager@chromium.org5c838252010-02-19 08:53:10 +0000748 }
749 if (n_arguments > 1) {
750 Object* arg2 = args[2];
751 if (arg2->IsSmi()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000752 relative_end = Smi::cast(arg2)->value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000753 } else if (!arg2->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000754 return CallJsBuiltin(isolate, "ArraySlice", args);
ager@chromium.org5c838252010-02-19 08:53:10 +0000755 }
756 }
757 }
758
759 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000760 int k = (relative_start < 0) ? Max(len + relative_start, 0)
761 : Min(relative_start, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000762
763 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000764 int final = (relative_end < 0) ? Max(len + relative_end, 0)
765 : Min(relative_end, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000766
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000767 ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind();
768
ager@chromium.org5c838252010-02-19 08:53:10 +0000769 // Calculate the length of result array.
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000770 int result_len = Max(final - k, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000771
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000772 MaybeObject* maybe_array =
773 heap->AllocateJSArrayAndStorage(elements_kind,
774 result_len,
775 result_len);
776 JSArray* result_array;
777 if (!maybe_array->To(&result_array)) return maybe_array;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000778
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000779 CopyObjectToObjectElements(elms, elements_kind, k,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000780 FixedArray::cast(result_array->elements()),
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000781 elements_kind, 0, result_len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000782
ager@chromium.org5c838252010-02-19 08:53:10 +0000783 return result_array;
784}
785
786
787BUILTIN(ArraySplice) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000788 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000789 Object* receiver = *args.receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000790 Object* elms_obj;
791 { MaybeObject* maybe_elms_obj =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000792 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000793 if (maybe_elms_obj == NULL)
794 return CallJsBuiltin(isolate, "ArraySplice", args);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000795 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
796 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000797 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
798 return CallJsBuiltin(isolate, "ArraySplice", args);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000799 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000800 FixedArray* elms = FixedArray::cast(elms_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000801 JSArray* array = JSArray::cast(receiver);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000802 ASSERT(array->HasFastSmiOrObjectElements());
ager@chromium.org5c838252010-02-19 08:53:10 +0000803
804 int len = Smi::cast(array->length())->value();
805
806 int n_arguments = args.length() - 1;
807
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000808 int relative_start = 0;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000809 if (n_arguments > 0) {
810 Object* arg1 = args[1];
811 if (arg1->IsSmi()) {
812 relative_start = Smi::cast(arg1)->value();
813 } else if (!arg1->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000814 return CallJsBuiltin(isolate, "ArraySplice", args);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000815 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000816 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000817 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
818 : Min(relative_start, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000819
820 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000821 // given as a request to delete all the elements from the start.
822 // And it differs from the case of undefined delete count.
ager@chromium.org5c838252010-02-19 08:53:10 +0000823 // This does not follow ECMA-262, but we do the same for
824 // compatibility.
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000825 int actual_delete_count;
826 if (n_arguments == 1) {
827 ASSERT(len - actual_start >= 0);
828 actual_delete_count = len - actual_start;
829 } else {
830 int value = 0; // ToInteger(undefined) == 0
831 if (n_arguments > 1) {
832 Object* arg2 = args[2];
833 if (arg2->IsSmi()) {
834 value = Smi::cast(arg2)->value();
835 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000836 return CallJsBuiltin(isolate, "ArraySplice", args);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000837 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000838 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000839 actual_delete_count = Min(Max(value, 0), len - actual_start);
ager@chromium.org5c838252010-02-19 08:53:10 +0000840 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000841
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000842 JSArray* result_array = NULL;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000843 ElementsKind elements_kind =
844 JSObject::cast(receiver)->GetElementsKind();
845 MaybeObject* maybe_array =
846 heap->AllocateJSArrayAndStorage(elements_kind,
847 actual_delete_count,
848 actual_delete_count);
849 if (!maybe_array->To(&result_array)) return maybe_array;
ager@chromium.org5c838252010-02-19 08:53:10 +0000850
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000851 {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000852 // Fill newly created array.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000853 CopyObjectToObjectElements(elms, elements_kind, actual_start,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000854 FixedArray::cast(result_array->elements()),
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000855 elements_kind, 0, actual_delete_count);
ager@chromium.org5c838252010-02-19 08:53:10 +0000856 }
857
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000858 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000859 int new_length = len - actual_delete_count + item_count;
ager@chromium.org5c838252010-02-19 08:53:10 +0000860
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000861 bool elms_changed = false;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000862 if (item_count < actual_delete_count) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000863 // Shrink the array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000864 const bool trim_array = !heap->lo_space()->Contains(elms) &&
lrn@chromium.org25156de2010-04-06 13:10:27 +0000865 ((actual_start + item_count) <
866 (len - actual_delete_count - actual_start));
867 if (trim_array) {
868 const int delta = actual_delete_count - item_count;
869
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000870 {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000871 AssertNoAllocation no_gc;
872 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000873 }
874
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000875 elms = LeftTrimFixedArray(heap, elms, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000876
877 elms_changed = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000878 } else {
879 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000880 MoveElements(heap, &no_gc,
lrn@chromium.org25156de2010-04-06 13:10:27 +0000881 elms, actual_start + item_count,
882 elms, actual_start + actual_delete_count,
883 (len - actual_delete_count - actual_start));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000884 FillWithHoles(heap, elms, new_length, len);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000885 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000886 } else if (item_count > actual_delete_count) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000887 // Currently fixed arrays cannot grow too big, so
888 // we should never hit this case.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000889 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
ager@chromium.org5c838252010-02-19 08:53:10 +0000890
891 // Check if array need to grow.
892 if (new_length > elms->length()) {
893 // New backing storage is needed.
894 int capacity = new_length + (new_length >> 1) + 16;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000895 Object* obj;
896 { MaybeObject* maybe_obj =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000897 heap->AllocateUninitializedFixedArray(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000898 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
899 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000900 FixedArray* new_elms = FixedArray::cast(obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000901
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000902 {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000903 // Copy the part before actual_start as is.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000904 ElementsKind kind = array->GetElementsKind();
905 CopyObjectToObjectElements(elms, kind, 0,
906 new_elms, kind, 0, actual_start);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000907 const int to_copy = len - actual_delete_count - actual_start;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000908 CopyObjectToObjectElements(elms, kind,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000909 actual_start + actual_delete_count,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000910 new_elms, kind,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +0000911 actual_start + item_count, to_copy);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000912 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000913
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000914 FillWithHoles(heap, new_elms, new_length, capacity);
ager@chromium.org5c838252010-02-19 08:53:10 +0000915
ager@chromium.org5c838252010-02-19 08:53:10 +0000916 elms = new_elms;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000917 elms_changed = true;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000918 } else {
919 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 MoveElements(heap, &no_gc,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000921 elms, actual_start + item_count,
922 elms, actual_start + actual_delete_count,
923 (len - actual_delete_count - actual_start));
ager@chromium.org5c838252010-02-19 08:53:10 +0000924 }
925 }
926
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000927 AssertNoAllocation no_gc;
928 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
929 for (int k = actual_start; k < actual_start + item_count; k++) {
930 elms->set(k, args[3 + k - actual_start], mode);
ager@chromium.org5c838252010-02-19 08:53:10 +0000931 }
932
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000933 if (elms_changed) {
934 array->set_elements(elms);
935 }
936
ager@chromium.org5c838252010-02-19 08:53:10 +0000937 // Set the length.
938 array->set_length(Smi::FromInt(new_length));
939
940 return result_array;
941}
942
943
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000944BUILTIN(ArrayConcat) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000945 Heap* heap = isolate->heap();
946 Context* global_context = isolate->context()->global_context();
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000947 JSObject* array_proto =
948 JSObject::cast(global_context->array_function()->prototype());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000949 if (!ArrayPrototypeHasNoElements(heap, global_context, array_proto)) {
950 return CallJsBuiltin(isolate, "ArrayConcat", args);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000951 }
952
953 // Iterate through all the arguments performing checks
954 // and calculating total length.
955 int n_arguments = args.length();
956 int result_len = 0;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000957 ElementsKind elements_kind = GetInitialFastElementsKind();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000958 for (int i = 0; i < n_arguments; i++) {
959 Object* arg = args[i];
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000960 if (!arg->IsJSArray() ||
961 !JSArray::cast(arg)->HasFastSmiOrObjectElements() ||
962 JSArray::cast(arg)->GetPrototype() != array_proto) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000963 return CallJsBuiltin(isolate, "ArrayConcat", args);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000964 }
965
966 int len = Smi::cast(JSArray::cast(arg)->length())->value();
967
968 // We shouldn't overflow when adding another len.
969 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
970 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
971 USE(kHalfOfMaxInt);
972 result_len += len;
973 ASSERT(result_len >= 0);
974
975 if (result_len > FixedArray::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 return CallJsBuiltin(isolate, "ArrayConcat", args);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000977 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000978
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000979 if (!JSArray::cast(arg)->HasFastSmiElements()) {
980 if (IsFastSmiElementsKind(elements_kind)) {
981 if (IsFastHoleyElementsKind(elements_kind)) {
982 elements_kind = FAST_HOLEY_ELEMENTS;
983 } else {
984 elements_kind = FAST_ELEMENTS;
985 }
986 }
987 }
988
989 if (JSArray::cast(arg)->HasFastHoleyElements()) {
990 elements_kind = GetHoleyElementsKind(elements_kind);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000991 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000992 }
993
994 // Allocate result.
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000995 JSArray* result_array;
996 MaybeObject* maybe_array =
997 heap->AllocateJSArrayAndStorage(elements_kind,
998 result_len,
999 result_len);
1000 if (!maybe_array->To(&result_array)) return maybe_array;
1001 if (result_len == 0) return result_array;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001002
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001003 // Copy data.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001004 int start_pos = 0;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001005 FixedArray* result_elms(FixedArray::cast(result_array->elements()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001006 for (int i = 0; i < n_arguments; i++) {
1007 JSArray* array = JSArray::cast(args[i]);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001008 int len = Smi::cast(array->length())->value();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001009 FixedArray* elms = FixedArray::cast(array->elements());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001010 CopyObjectToObjectElements(elms, elements_kind, 0,
1011 result_elms, elements_kind,
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001012 start_pos, len);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001013 start_pos += len;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001014 }
1015 ASSERT(start_pos == result_len);
1016
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001017 return result_array;
1018}
1019
1020
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021// -----------------------------------------------------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001022// Strict mode poison pills
1023
1024
danno@chromium.org40cb8782011-05-25 07:58:50 +00001025BUILTIN(StrictModePoisonPill) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001026 HandleScope scope;
1027 return isolate->Throw(*isolate->factory()->NewTypeError(
danno@chromium.org40cb8782011-05-25 07:58:50 +00001028 "strict_poison_pill", HandleVector<Object>(NULL, 0)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001029}
1030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001031// -----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001032//
1033
1034
1035// Returns the holder JSObject if the function can legally be called
1036// with this receiver. Returns Heap::null_value() if the call is
1037// illegal. Any arguments that don't fit the expected type is
1038// overwritten with undefined. Arguments that do fit the expected
1039// type is overwritten with the object in the prototype chain that
1040// actually has that type.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001041static inline Object* TypeCheck(Heap* heap,
1042 int argc,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043 Object** argv,
1044 FunctionTemplateInfo* info) {
1045 Object* recv = argv[0];
lrn@chromium.org1c092762011-05-09 09:42:16 +00001046 // API calls are only supported with JSObject receivers.
1047 if (!recv->IsJSObject()) return heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048 Object* sig_obj = info->signature();
1049 if (sig_obj->IsUndefined()) return recv;
1050 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
1051 // If necessary, check the receiver
1052 Object* recv_type = sig->receiver();
1053
1054 Object* holder = recv;
1055 if (!recv_type->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001056 for (; holder != heap->null_value(); holder = holder->GetPrototype()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
1058 break;
1059 }
1060 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 if (holder == heap->null_value()) return holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062 }
1063 Object* args_obj = sig->args();
1064 // If there is no argument signature we're done
1065 if (args_obj->IsUndefined()) return holder;
1066 FixedArray* args = FixedArray::cast(args_obj);
1067 int length = args->length();
mads.s.ager31e71382008-08-13 09:32:07 +00001068 if (argc <= length) length = argc - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069 for (int i = 0; i < length; i++) {
1070 Object* argtype = args->get(i);
1071 if (argtype->IsUndefined()) continue;
1072 Object** arg = &argv[-1 - i];
1073 Object* current = *arg;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074 for (; current != heap->null_value(); current = current->GetPrototype()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
1076 *arg = current;
1077 break;
1078 }
1079 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001080 if (current == heap->null_value()) *arg = heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081 }
1082 return holder;
1083}
1084
1085
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001086template <bool is_construct>
lrn@chromium.org303ada72010-10-27 09:33:13 +00001087MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001088 BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
1089 ASSERT(is_construct == CalledAsConstructor(isolate));
1090 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001092 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001093 Handle<JSFunction> function = args.called_function();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001094 ASSERT(function->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001095
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001096 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001097 if (is_construct) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 Handle<FunctionTemplateInfo> desc(fun_data, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099 bool pending_exception = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001100 isolate->factory()->ConfigureInstance(
1101 desc, Handle<JSObject>::cast(args.receiver()), &pending_exception);
1102 ASSERT(isolate->has_pending_exception() == pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103 if (pending_exception) return Failure::Exception();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001104 fun_data = *desc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105 }
1106
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001107 Object* raw_holder = TypeCheck(heap, args.length(), &args[0], fun_data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001108
1109 if (raw_holder->IsNull()) {
1110 // This function cannot be called with the given receiver. Abort!
1111 Handle<Object> obj =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001112 isolate->factory()->NewTypeError(
1113 "illegal_invocation", HandleVector(&function, 1));
1114 return isolate->Throw(*obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001115 }
1116
1117 Object* raw_call_data = fun_data->call_code();
1118 if (!raw_call_data->IsUndefined()) {
1119 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1120 Object* callback_obj = call_data->callback();
1121 v8::InvocationCallback callback =
1122 v8::ToCData<v8::InvocationCallback>(callback_obj);
1123 Object* data_obj = call_data->data();
1124 Object* result;
1125
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001126 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001127 ASSERT(raw_holder->IsJSObject());
1128
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001129 CustomArguments custom(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001130 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001131 isolate, data_obj, *function, raw_holder);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001132
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001133 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001134 custom.end(),
1135 &args[0] - 1,
1136 args.length() - 1,
1137 is_construct);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138
1139 v8::Handle<v8::Value> value;
1140 {
1141 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001142 VMState state(isolate, EXTERNAL);
1143 ExternalCallbackScope call_scope(isolate,
1144 v8::ToCData<Address>(callback_obj));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001145 value = callback(new_args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146 }
1147 if (value.IsEmpty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 result = heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149 } else {
1150 result = *reinterpret_cast<Object**>(*value);
1151 }
1152
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001153 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001154 if (!is_construct || result->IsJSObject()) return result;
1155 }
1156
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001157 return *args.receiver();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001158}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001159
1160
1161BUILTIN(HandleApiCall) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001162 return HandleApiCallHelper<false>(args, isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001163}
1164
1165
1166BUILTIN(HandleApiCallConstruct) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001167 return HandleApiCallHelper<true>(args, isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001168}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169
1170
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001171// Helper function to handle calls to non-function objects created through the
1172// API. The object can be called as either a constructor (using new) or just as
1173// a function (without new).
lrn@chromium.org303ada72010-10-27 09:33:13 +00001174MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001175 Isolate* isolate,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001176 bool is_construct_call,
1177 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001178 // Non-functions are never called as constructors. Even if this is an object
1179 // called as a constructor the delegate call is not a construct call.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001180 ASSERT(!CalledAsConstructor(isolate));
1181 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001183 Handle<Object> receiver = args.receiver();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001184
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185 // Get the object called.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001186 JSObject* obj = JSObject::cast(*receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001187
1188 // Get the invocation callback from the function descriptor that was
1189 // used to create the called object.
1190 ASSERT(obj->map()->has_instance_call_handler());
1191 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001192 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 Object* handler =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001194 constructor->shared()->get_api_func_data()->instance_call_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195 ASSERT(!handler->IsUndefined());
1196 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1197 Object* callback_obj = call_data->callback();
1198 v8::InvocationCallback callback =
1199 v8::ToCData<v8::InvocationCallback>(callback_obj);
1200
1201 // Get the data for the call and perform the callback.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202 Object* result;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001203 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001204 HandleScope scope(isolate);
1205 LOG(isolate, ApiObjectAccess("call non-function", obj));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001207 CustomArguments custom(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001208 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00001209 isolate, call_data->data(), constructor, obj);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001210 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001211 custom.end(),
1212 &args[0] - 1,
1213 args.length() - 1,
1214 is_construct_call);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 v8::Handle<v8::Value> value;
1216 {
1217 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001218 VMState state(isolate, EXTERNAL);
1219 ExternalCallbackScope call_scope(isolate,
1220 v8::ToCData<Address>(callback_obj));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001221 value = callback(new_args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 }
1223 if (value.IsEmpty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001224 result = heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001225 } else {
1226 result = *reinterpret_cast<Object**>(*value);
1227 }
1228 }
1229 // Check for exceptions and return result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001230 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001231 return result;
1232}
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001233
1234
1235// Handle calls to non-function objects created through the API. This delegate
1236// function is used when the call is a normal function call.
1237BUILTIN(HandleApiCallAsFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001238 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001239}
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001240
1241
1242// Handle calls to non-function objects created through the API. This delegate
1243// function is used when the call is a construct call.
1244BUILTIN(HandleApiCallAsConstructor) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001245 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001246}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247
1248
1249static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1250 LoadIC::GenerateArrayLength(masm);
1251}
1252
1253
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001254static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001255 LoadIC::GenerateStringLength(masm, false);
1256}
1257
1258
1259static void Generate_LoadIC_StringWrapperLength(MacroAssembler* masm) {
1260 LoadIC::GenerateStringLength(masm, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261}
1262
1263
1264static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1265 LoadIC::GenerateFunctionPrototype(masm);
1266}
1267
1268
1269static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1270 LoadIC::GenerateInitialize(masm);
1271}
1272
1273
1274static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1275 LoadIC::GeneratePreMonomorphic(masm);
1276}
1277
1278
1279static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1280 LoadIC::GenerateMiss(masm);
1281}
1282
1283
1284static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1285 LoadIC::GenerateMegamorphic(masm);
1286}
1287
1288
1289static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1290 LoadIC::GenerateNormal(masm);
1291}
1292
1293
1294static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1295 KeyedLoadIC::GenerateInitialize(masm);
1296}
1297
1298
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001299static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
1300 KeyedLoadIC::GenerateRuntimeGetProperty(masm);
1301}
1302
1303
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001305 KeyedLoadIC::GenerateMiss(masm, false);
1306}
1307
1308
1309static void Generate_KeyedLoadIC_MissForceGeneric(MacroAssembler* masm) {
1310 KeyedLoadIC::GenerateMiss(masm, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311}
1312
1313
1314static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1315 KeyedLoadIC::GenerateGeneric(masm);
1316}
1317
1318
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001319static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1320 KeyedLoadIC::GenerateString(masm);
1321}
1322
1323
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1325 KeyedLoadIC::GeneratePreMonomorphic(masm);
1326}
1327
ager@chromium.org5c838252010-02-19 08:53:10 +00001328static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1329 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1330}
1331
whesse@chromium.org7b260152011-06-20 15:33:18 +00001332static void Generate_KeyedLoadIC_NonStrictArguments(MacroAssembler* masm) {
1333 KeyedLoadIC::GenerateNonStrictArguments(masm);
1334}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335
1336static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1337 StoreIC::GenerateInitialize(masm);
1338}
1339
1340
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001341static void Generate_StoreIC_Initialize_Strict(MacroAssembler* masm) {
1342 StoreIC::GenerateInitialize(masm);
1343}
1344
1345
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1347 StoreIC::GenerateMiss(masm);
1348}
1349
1350
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001351static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1352 StoreIC::GenerateNormal(masm);
1353}
1354
1355
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001356static void Generate_StoreIC_Normal_Strict(MacroAssembler* masm) {
1357 StoreIC::GenerateNormal(masm);
1358}
1359
1360
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001362 StoreIC::GenerateMegamorphic(masm, kNonStrictMode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001363}
1364
1365
1366static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001367 StoreIC::GenerateMegamorphic(masm, kStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368}
1369
1370
ager@chromium.org5c838252010-02-19 08:53:10 +00001371static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1372 StoreIC::GenerateArrayLength(masm);
1373}
1374
1375
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001376static void Generate_StoreIC_ArrayLength_Strict(MacroAssembler* masm) {
1377 StoreIC::GenerateArrayLength(masm);
1378}
1379
1380
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001381static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001382 StoreIC::GenerateGlobalProxy(masm, kNonStrictMode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001383}
1384
1385
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001386static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001387 StoreIC::GenerateGlobalProxy(masm, kStrictMode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001388}
1389
1390
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001392 KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode);
1393}
1394
1395
1396static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) {
1397 KeyedStoreIC::GenerateGeneric(masm, kStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398}
1399
1400
1401static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001402 KeyedStoreIC::GenerateMiss(masm, false);
1403}
1404
1405
1406static void Generate_KeyedStoreIC_MissForceGeneric(MacroAssembler* masm) {
1407 KeyedStoreIC::GenerateMiss(masm, true);
1408}
1409
1410
1411static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
1412 KeyedStoreIC::GenerateSlow(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413}
1414
1415
1416static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1417 KeyedStoreIC::GenerateInitialize(masm);
1418}
1419
1420
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001421static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
1422 KeyedStoreIC::GenerateInitialize(masm);
1423}
1424
whesse@chromium.org7b260152011-06-20 15:33:18 +00001425static void Generate_KeyedStoreIC_NonStrictArguments(MacroAssembler* masm) {
1426 KeyedStoreIC::GenerateNonStrictArguments(masm);
1427}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001428
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001429static void Generate_TransitionElementsSmiToDouble(MacroAssembler* masm) {
1430 KeyedStoreIC::GenerateTransitionElementsSmiToDouble(masm);
1431}
1432
1433static void Generate_TransitionElementsDoubleToObject(MacroAssembler* masm) {
1434 KeyedStoreIC::GenerateTransitionElementsDoubleToObject(masm);
1435}
1436
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001437#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org8bb60582008-12-11 12:02:20 +00001438static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1439 Debug::GenerateLoadICDebugBreak(masm);
1440}
1441
1442
1443static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1444 Debug::GenerateStoreICDebugBreak(masm);
1445}
1446
1447
1448static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1449 Debug::GenerateKeyedLoadICDebugBreak(masm);
1450}
1451
1452
1453static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1454 Debug::GenerateKeyedStoreICDebugBreak(masm);
1455}
1456
1457
ager@chromium.org8bb60582008-12-11 12:02:20 +00001458static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1459 Debug::GenerateReturnDebugBreak(masm);
1460}
1461
1462
danno@chromium.orgc612e022011-11-10 11:38:15 +00001463static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) {
1464 Debug::GenerateCallFunctionStubDebugBreak(masm);
ager@chromium.org8bb60582008-12-11 12:02:20 +00001465}
ager@chromium.org357bf652010-04-12 11:30:10 +00001466
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001467
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001468static void Generate_CallFunctionStub_Recording_DebugBreak(
1469 MacroAssembler* masm) {
1470 Debug::GenerateCallFunctionStubRecordDebugBreak(masm);
1471}
1472
1473
1474static void Generate_CallConstructStub_DebugBreak(MacroAssembler* masm) {
1475 Debug::GenerateCallConstructStubDebugBreak(masm);
1476}
1477
1478
1479static void Generate_CallConstructStub_Recording_DebugBreak(
1480 MacroAssembler* masm) {
1481 Debug::GenerateCallConstructStubRecordDebugBreak(masm);
1482}
1483
1484
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001485static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1486 Debug::GenerateSlotDebugBreak(masm);
1487}
1488
1489
ager@chromium.org357bf652010-04-12 11:30:10 +00001490static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1491 Debug::GeneratePlainReturnLiveEdit(masm);
1492}
1493
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001494
ager@chromium.org357bf652010-04-12 11:30:10 +00001495static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1496 Debug::GenerateFrameDropperLiveEdit(masm);
1497}
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001498#endif
ager@chromium.org8bb60582008-12-11 12:02:20 +00001499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001500
1501Builtins::Builtins() : initialized_(false) {
1502 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
1503 memset(names_, 0, sizeof(names_[0]) * builtin_count);
1504}
1505
1506
1507Builtins::~Builtins() {
1508}
1509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001511#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001512Address const Builtins::c_functions_[cfunction_count] = {
1513 BUILTIN_LIST_C(DEF_ENUM_C)
1514};
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515#undef DEF_ENUM_C
1516
1517#define DEF_JS_NAME(name, ignore) #name,
1518#define DEF_JS_ARGC(ignore, argc) argc,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001519const char* const Builtins::javascript_names_[id_count] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001520 BUILTINS_LIST_JS(DEF_JS_NAME)
1521};
1522
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001523int const Builtins::javascript_argc_[id_count] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 BUILTINS_LIST_JS(DEF_JS_ARGC)
1525};
1526#undef DEF_JS_NAME
1527#undef DEF_JS_ARGC
1528
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001529struct BuiltinDesc {
1530 byte* generator;
1531 byte* c_code;
1532 const char* s_name; // name is only used for generating log information.
1533 int name;
1534 Code::Flags flags;
1535 BuiltinExtraArguments extra_args;
1536};
1537
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001538#define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} }
1539
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001540class BuiltinFunctionTable {
1541 public:
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001542 BuiltinDesc* functions() {
1543 CallOnce(&once_, &Builtins::InitBuiltinFunctionTable);
1544 return functions_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001545 }
1546
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001547 OnceType once_;
1548 BuiltinDesc functions_[Builtins::builtin_count + 1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001549
1550 friend class Builtins;
1551};
1552
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001553static BuiltinFunctionTable builtin_function_table =
1554 BUILTIN_FUNCTION_TABLE_INIT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001555
1556// Define array of pointers to generators and C builtin functions.
1557// We do this in a sort of roundabout way so that we can do the initialization
1558// within the lexical scope of Builtins:: and within a context where
1559// Code::Flags names a non-abstract type.
1560void Builtins::InitBuiltinFunctionTable() {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001561 BuiltinDesc* functions = builtin_function_table.functions_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001562 functions[builtin_count].generator = NULL;
1563 functions[builtin_count].c_code = NULL;
1564 functions[builtin_count].s_name = NULL;
1565 functions[builtin_count].name = builtin_count;
1566 functions[builtin_count].flags = static_cast<Code::Flags>(0);
1567 functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
1568
1569#define DEF_FUNCTION_PTR_C(aname, aextra_args) \
1570 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
1571 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
1572 functions->s_name = #aname; \
1573 functions->name = c_##aname; \
1574 functions->flags = Code::ComputeFlags(Code::BUILTIN); \
1575 functions->extra_args = aextra_args; \
1576 ++functions;
1577
1578#define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
1579 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1580 functions->c_code = NULL; \
1581 functions->s_name = #aname; \
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001582 functions->name = k##aname; \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001583 functions->flags = Code::ComputeFlags(Code::kind, \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001584 state, \
1585 extra); \
1586 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1587 ++functions;
1588
1589 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1590 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1591 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1592
1593#undef DEF_FUNCTION_PTR_C
1594#undef DEF_FUNCTION_PTR_A
1595}
1596
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001597void Builtins::SetUp(bool create_heap_objects) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001598 ASSERT(!initialized_);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001599 Isolate* isolate = Isolate::Current();
1600 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601
1602 // Create a scope for the handles in the builtins.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001603 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001605 const BuiltinDesc* functions = builtin_function_table.functions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606
1607 // For now we generate builtin adaptor code into a stack-allocated
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001608 // buffer, before copying it into individual code objects. Be careful
1609 // with alignment, some platforms don't like unaligned code.
1610 union { int force_alignment; byte buffer[4*KB]; } u;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611
1612 // Traverse the list of builtins and generate an adaptor in a
1613 // separate code object for each one.
1614 for (int i = 0; i < builtin_count; i++) {
1615 if (create_heap_objects) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001616 MacroAssembler masm(isolate, u.buffer, sizeof u.buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 // Generate the code/adaptor.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001618 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1620 // We pass all arguments to the generator, but it may not use all of
1621 // them. This works because the first arguments are on top of the
1622 // stack.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001623 ASSERT(!masm.has_frame());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001624 g(&masm, functions[i].name, functions[i].extra_args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625 // Move the code into the object heap.
1626 CodeDesc desc;
1627 masm.GetCode(&desc);
1628 Code::Flags flags = functions[i].flags;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001629 Object* code = NULL;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001630 {
1631 // During startup it's OK to always allocate and defer GC to later.
1632 // This simplifies things because we don't need to retry.
1633 AlwaysAllocateScope __scope__;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001634 { MaybeObject* maybe_code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001635 heap->CreateCode(desc, flags, masm.CodeObject());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001636 if (!maybe_code->ToObject(&code)) {
1637 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1638 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001639 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001641 // Log the event and add the code to the builtins array.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001642 PROFILE(isolate,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001643 CodeCreateEvent(Logger::BUILTIN_TAG,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001644 Code::cast(code),
1645 functions[i].s_name));
1646 GDBJIT(AddCode(GDBJITInterface::BUILTIN,
1647 functions[i].s_name,
1648 Code::cast(code)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649 builtins_[i] = code;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001650#ifdef ENABLE_DISASSEMBLER
mads.s.ager31e71382008-08-13 09:32:07 +00001651 if (FLAG_print_builtin_code) {
1652 PrintF("Builtin: %s\n", functions[i].s_name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001653 Code::cast(code)->Disassemble(functions[i].s_name);
mads.s.ager31e71382008-08-13 09:32:07 +00001654 PrintF("\n");
1655 }
1656#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001657 } else {
1658 // Deserializing. The values will be filled in during IterateBuiltins.
1659 builtins_[i] = NULL;
1660 }
1661 names_[i] = functions[i].s_name;
1662 }
1663
1664 // Mark as initialized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001665 initialized_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001666}
1667
1668
1669void Builtins::TearDown() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001670 initialized_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001671}
1672
1673
1674void Builtins::IterateBuiltins(ObjectVisitor* v) {
1675 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1676}
1677
1678
1679const char* Builtins::Lookup(byte* pc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001680 // may be called during initialization (disassembler!)
1681 if (initialized_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 for (int i = 0; i < builtin_count; i++) {
1683 Code* entry = Code::cast(builtins_[i]);
1684 if (entry->contains(pc)) {
1685 return names_[i];
1686 }
1687 }
1688 }
1689 return NULL;
1690}
1691
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001692
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001693#define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
1694Handle<Code> Builtins::name() { \
1695 Code** code_address = \
1696 reinterpret_cast<Code**>(builtin_address(k##name)); \
1697 return Handle<Code>(code_address); \
1698}
1699#define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
1700Handle<Code> Builtins::name() { \
1701 Code** code_address = \
1702 reinterpret_cast<Code**>(builtin_address(k##name)); \
1703 return Handle<Code>(code_address); \
1704}
1705BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1706BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1707BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1708#undef DEFINE_BUILTIN_ACCESSOR_C
1709#undef DEFINE_BUILTIN_ACCESSOR_A
1710
1711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001712} } // namespace v8::internal