blob: 655b808f1be51910bf1e482c5d1cc17ffcc935b6 [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"
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000034#include "cpu-profiler.h"
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000035#include "gdb-jit.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "ic-inl.h"
ulan@chromium.org6ff65142012-03-21 09:52:17 +000037#include "heap-profiler.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000038#include "mark-compact.h"
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000039#include "stub-cache.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000040#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041
kasperl@chromium.org71affb52009-05-26 05:44:31 +000042namespace v8 {
43namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000045namespace {
46
47// Arguments object passed to C++ builtins.
48template <BuiltinExtraArguments extra_args>
49class BuiltinArguments : public Arguments {
50 public:
51 BuiltinArguments(int length, Object** arguments)
52 : Arguments(length, arguments) { }
53
54 Object*& operator[] (int index) {
55 ASSERT(index < length());
56 return Arguments::operator[](index);
57 }
58
59 template <class S> Handle<S> at(int index) {
60 ASSERT(index < length());
61 return Arguments::at<S>(index);
62 }
63
64 Handle<Object> receiver() {
65 return Arguments::at<Object>(0);
66 }
67
68 Handle<JSFunction> called_function() {
69 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
70 return Arguments::at<JSFunction>(Arguments::length() - 1);
71 }
72
73 // Gets the total number of arguments including the receiver (but
74 // excluding extra arguments).
75 int length() const {
76 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
77 return Arguments::length();
78 }
79
80#ifdef DEBUG
81 void Verify() {
82 // Check we have at least the receiver.
83 ASSERT(Arguments::length() >= 1);
84 }
85#endif
86};
87
88
89// Specialize BuiltinArguments for the called function extra argument.
90
91template <>
92int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
93 return Arguments::length() - 1;
94}
95
96#ifdef DEBUG
97template <>
98void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
99 // Check we have at least the receiver and the called function.
100 ASSERT(Arguments::length() >= 2);
101 // Make sure cast to JSFunction succeeds.
102 called_function();
103}
104#endif
105
106
107#define DEF_ARG_TYPE(name, spec) \
108 typedef BuiltinArguments<spec> name##ArgumentsType;
109BUILTIN_LIST_C(DEF_ARG_TYPE)
110#undef DEF_ARG_TYPE
111
112} // namespace
113
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000114// ----------------------------------------------------------------------------
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000115// Support macro for defining builtins in C++.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000116// ----------------------------------------------------------------------------
117//
118// A builtin function is defined by writing:
119//
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000120// BUILTIN(name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121// ...
122// }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123//
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000124// In the body of the builtin function the arguments can be accessed
125// through the BuiltinArguments object args.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127#ifdef DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000128
danno@chromium.orgf005df62013-04-30 16:36:45 +0000129#define BUILTIN(name) \
130 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
131 name##ArgumentsType args, Isolate* isolate); \
132 MUST_USE_RESULT static MaybeObject* Builtin_##name( \
133 int args_length, Object** args_object, Isolate* isolate) { \
134 name##ArgumentsType args(args_length, args_object); \
danno@chromium.orgf005df62013-04-30 16:36:45 +0000135 args.Verify(); \
136 return Builtin_Impl_##name(args, isolate); \
137 } \
138 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139 name##ArgumentsType args, Isolate* isolate)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000140
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141#else // For release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142
danno@chromium.orgf005df62013-04-30 16:36:45 +0000143#define BUILTIN(name) \
144 static MaybeObject* Builtin_impl##name( \
145 name##ArgumentsType args, Isolate* isolate); \
146 static MaybeObject* Builtin_##name( \
147 int args_length, Object** args_object, Isolate* isolate) { \
148 name##ArgumentsType args(args_length, args_object); \
149 return Builtin_impl##name(args, isolate); \
150 } \
151 static MaybeObject* Builtin_impl##name( \
152 name##ArgumentsType args, Isolate* isolate)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000154
155
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000156static inline bool CalledAsConstructor(Isolate* isolate) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000157#ifdef DEBUG
158 // Calculate the result using a full stack frame iterator and check
159 // that the state of the stack is as we assume it to be in the
160 // code below.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000161 StackFrameIterator it(isolate);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000162 ASSERT(it.frame()->is_exit());
163 it.Advance();
164 StackFrame* frame = it.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000165 bool reference_result = frame->is_construct();
166#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000167 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000168 // Because we know fp points to an exit frame we can use the relevant
169 // part of ExitFrame::ComputeCallerState directly.
170 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
171 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
172 // This inlines the part of StackFrame::ComputeType that grabs the
173 // type of the current frame. Note that StackFrame::ComputeType
174 // has been specialized for each architecture so if any one of them
175 // changes this code has to be changed as well.
176 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
177 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
178 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
179 bool result = (marker == kConstructMarker);
180 ASSERT_EQ(result, reference_result);
181 return result;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000182}
183
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +0000184
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185// ----------------------------------------------------------------------------
186
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000187BUILTIN(Illegal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000188 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000189 return isolate->heap()->undefined_value(); // Make compiler happy.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000190}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000191
192
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000193BUILTIN(EmptyFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000195}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000196
197
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000198static void MoveDoubleElements(FixedDoubleArray* dst,
199 int dst_index,
200 FixedDoubleArray* src,
201 int src_index,
202 int len) {
203 if (len == 0) return;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000204 OS::MemMove(dst->data_start() + dst_index,
205 src->data_start() + src_index,
206 len * kDoubleSize);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000207}
208
209
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000210static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) {
211 ASSERT(dst->map() != heap->fixed_cow_array_map());
212 MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000213}
214
215
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000216static void FillWithHoles(FixedDoubleArray* dst, int from, int to) {
217 for (int i = from; i < to; i++) {
218 dst->set_the_hole(i);
219 }
220}
221
222
223static FixedArrayBase* LeftTrimFixedArray(Heap* heap,
224 FixedArrayBase* elms,
225 int to_trim) {
226 Map* map = elms->map();
227 int entry_size;
228 if (elms->IsFixedArray()) {
229 entry_size = kPointerSize;
230 } else {
231 entry_size = kDoubleSize;
232 }
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000233 ASSERT(elms->map() != heap->fixed_cow_array_map());
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000234 // For now this trick is only applied to fixed arrays in new and paged space.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000235 // In large object space the object's start must coincide with chunk
236 // and thus the trick is just not applicable.
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +0000237 ASSERT(!heap->lo_space()->Contains(elms));
lrn@chromium.org25156de2010-04-06 13:10:27 +0000238
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000239 STATIC_ASSERT(FixedArrayBase::kMapOffset == 0);
240 STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize);
241 STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000242
243 Object** former_start = HeapObject::RawField(elms, 0);
244
245 const int len = elms->length();
246
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000247 if (to_trim * entry_size > FixedArrayBase::kHeaderSize &&
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000248 elms->IsFixedArray() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000249 !heap->new_space()->Contains(elms)) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000250 // If we are doing a big trim in old space then we zap the space that was
251 // formerly part of the array so that the GC (aided by the card-based
252 // remembered set) won't find pointers to new-space there.
253 Object** zap = reinterpret_cast<Object**>(elms->address());
254 zap++; // Header of filler must be at least one word so skip that.
255 for (int i = 1; i < to_trim; i++) {
256 *zap++ = Smi::FromInt(0);
257 }
258 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000259 // Technically in new space this write might be omitted (except for
260 // debug mode which iterates through the heap), but to play safer
261 // we still do it.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000262 heap->CreateFillerObjectAt(elms->address(), to_trim * entry_size);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000263
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000264 int new_start_index = to_trim * (entry_size / kPointerSize);
265 former_start[new_start_index] = map;
266 former_start[new_start_index + 1] = Smi::FromInt(len - to_trim);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000267
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000268 // Maintain marking consistency for HeapObjectIterator and
269 // IncrementalMarking.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000270 int size_delta = to_trim * entry_size;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000271 if (heap->marking()->TransferMark(elms->address(),
272 elms->address() + size_delta)) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000273 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000274 }
275
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000276 FixedArrayBase* new_elms = FixedArrayBase::cast(HeapObject::FromAddress(
277 elms->address() + size_delta));
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000278 HeapProfiler* profiler = heap->isolate()->heap_profiler();
279 if (profiler->is_profiling()) {
280 profiler->ObjectMoveEvent(elms->address(),
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000281 new_elms->address(),
282 new_elms->Size());
283 if (profiler->is_tracking_allocations()) {
284 // Report filler object as a new allocation.
285 // Otherwise it will become an untracked object.
286 profiler->NewObjectEvent(elms->address(), elms->Size());
287 }
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000288 }
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +0000289 return new_elms;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000290}
291
292
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000293static bool ArrayPrototypeHasNoElements(Heap* heap,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000294 Context* native_context,
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000295 JSObject* array_proto) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000296 // This method depends on non writability of Object and Array prototype
297 // fields.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000298 if (array_proto->elements() != heap->empty_fixed_array()) return false;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000299 // Object.prototype
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000300 Object* proto = array_proto->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 if (proto == heap->null_value()) return false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000302 array_proto = JSObject::cast(proto);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000303 if (array_proto != native_context->initial_object_prototype()) return false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 if (array_proto->elements() != heap->empty_fixed_array()) return false;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000305 return array_proto->GetPrototype()->IsNull();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000306}
307
308
lrn@chromium.org303ada72010-10-27 09:33:13 +0000309MUST_USE_RESULT
310static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000311 Heap* heap, Object* receiver, Arguments* args, int first_added_arg) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000312 if (!receiver->IsJSArray()) return NULL;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000313 JSArray* array = JSArray::cast(receiver);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000314 if (array->map()->is_observed()) return NULL;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000315 HeapObject* elms = array->elements();
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000316 Map* map = elms->map();
317 if (map == heap->fixed_array_map()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000318 if (args == NULL || array->HasFastObjectElements()) return elms;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000319 } else if (map == heap->fixed_cow_array_map()) {
320 MaybeObject* maybe_writable_result = array->EnsureWritableFastElements();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000321 if (args == NULL || array->HasFastObjectElements() ||
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000322 !maybe_writable_result->To(&elms)) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000323 return maybe_writable_result;
324 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000325 } else if (map == heap->fixed_double_array_map()) {
326 if (args == NULL) return elms;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000327 } else {
328 return NULL;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000329 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000330
331 // Need to ensure that the arguments passed in args can be contained in
332 // the array.
333 int args_length = args->length();
334 if (first_added_arg >= args_length) return array->elements();
335
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000336 ElementsKind origin_kind = array->map()->elements_kind();
337 ASSERT(!IsFastObjectElementsKind(origin_kind));
338 ElementsKind target_kind = origin_kind;
339 int arg_count = args->length() - first_added_arg;
340 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1);
341 for (int i = 0; i < arg_count; i++) {
342 Object* arg = arguments[i];
343 if (arg->IsHeapObject()) {
344 if (arg->IsHeapNumber()) {
345 target_kind = FAST_DOUBLE_ELEMENTS;
346 } else {
347 target_kind = FAST_ELEMENTS;
348 break;
349 }
350 }
351 }
352 if (target_kind != origin_kind) {
353 MaybeObject* maybe_failure = array->TransitionElementsKind(target_kind);
354 if (maybe_failure->IsFailure()) return maybe_failure;
355 return array->elements();
356 }
357 return elms;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000358}
359
360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
362 JSArray* receiver) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000363 if (!FLAG_clever_optimizations) return false;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000364 Context* native_context = heap->isolate()->context()->native_context();
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000365 JSObject* array_proto =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000366 JSObject::cast(native_context->array_function()->prototype());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000367 return receiver->GetPrototype() == array_proto &&
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000368 ArrayPrototypeHasNoElements(heap, native_context, array_proto);
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000369}
370
371
lrn@chromium.org303ada72010-10-27 09:33:13 +0000372MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000373 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000374 const char* name,
375 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 HandleScope handleScope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000377
378 Handle<Object> js_builtin =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000379 GetProperty(Handle<JSObject>(isolate->native_context()->builtins()),
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000380 name);
381 Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin);
382 int argc = args.length() - 1;
383 ScopedVector<Handle<Object> > argv(argc);
384 for (int i = 0; i < argc; ++i) {
385 argv[i] = args.at<Object>(i + 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000386 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000387 bool pending_exception;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +0000388 Handle<Object> result = Execution::Call(isolate,
389 function,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000390 args.receiver(),
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000391 argc,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000392 argv.start(),
393 &pending_exception);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000394 if (pending_exception) return Failure::Exception();
395 return *result;
396}
397
398
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000399BUILTIN(ArrayPush) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000400 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000401 Object* receiver = *args.receiver();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000402 FixedArrayBase* elms_obj;
403 MaybeObject* maybe_elms_obj =
404 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1);
405 if (maybe_elms_obj == NULL) {
406 return CallJsBuiltin(isolate, "ArrayPush", args);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000407 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000408 if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000410 JSArray* array = JSArray::cast(receiver);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000411 ASSERT(!array->map()->is_observed());
412
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000413 ElementsKind kind = array->GetElementsKind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000415 if (IsFastSmiOrObjectElementsKind(kind)) {
416 FixedArray* elms = FixedArray::cast(elms_obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000418 int len = Smi::cast(array->length())->value();
419 int to_add = args.length() - 1;
420 if (to_add == 0) {
421 return Smi::FromInt(len);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000422 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000423 // Currently fixed arrays cannot grow too big, so
424 // we should never hit this case.
425 ASSERT(to_add <= (Smi::kMaxValue - len));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000426
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000427 int new_length = len + to_add;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000428
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000429 if (new_length > elms->length()) {
430 // New backing storage is needed.
431 int capacity = new_length + (new_length >> 1) + 16;
432 FixedArray* new_elms;
433 MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
434 if (!maybe_obj->To(&new_elms)) return maybe_obj;
435
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000436 ElementsAccessor* accessor = array->GetElementsAccessor();
437 MaybeObject* maybe_failure = accessor->CopyElements(
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000438 NULL, 0, kind, new_elms, 0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000439 ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj);
440 ASSERT(!maybe_failure->IsFailure());
441 USE(maybe_failure);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000442
443 elms = new_elms;
444 }
445
446 // Add the provided values.
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000447 DisallowHeapAllocation no_gc;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000448 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
449 for (int index = 0; index < to_add; index++) {
450 elms->set(index + len, args[index + 1], mode);
451 }
452
453 if (elms != array->elements()) {
454 array->set_elements(elms);
455 }
456
457 // Set the length.
458 array->set_length(Smi::FromInt(new_length));
459 return Smi::FromInt(new_length);
460 } else {
461 int len = Smi::cast(array->length())->value();
462 int elms_len = elms_obj->length();
463
464 int to_add = args.length() - 1;
465 if (to_add == 0) {
466 return Smi::FromInt(len);
467 }
468 // Currently fixed arrays cannot grow too big, so
469 // we should never hit this case.
470 ASSERT(to_add <= (Smi::kMaxValue - len));
471
472 int new_length = len + to_add;
473
474 FixedDoubleArray* new_elms;
475
476 if (new_length > elms_len) {
477 // New backing storage is needed.
478 int capacity = new_length + (new_length >> 1) + 16;
479 MaybeObject* maybe_obj =
480 heap->AllocateUninitializedFixedDoubleArray(capacity);
481 if (!maybe_obj->To(&new_elms)) return maybe_obj;
482
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000483 ElementsAccessor* accessor = array->GetElementsAccessor();
484 MaybeObject* maybe_failure = accessor->CopyElements(
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000485 NULL, 0, kind, new_elms, 0,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000486 ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj);
487 ASSERT(!maybe_failure->IsFailure());
488 USE(maybe_failure);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000489 } else {
490 // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the
491 // empty_fixed_array.
492 new_elms = FixedDoubleArray::cast(elms_obj);
493 }
494
495 // Add the provided values.
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000496 DisallowHeapAllocation no_gc;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000497 int index;
498 for (index = 0; index < to_add; index++) {
499 Object* arg = args[index + 1];
500 new_elms->set(index + len, arg->Number());
501 }
502
503 if (new_elms != array->elements()) {
504 array->set_elements(new_elms);
505 }
506
507 // Set the length.
508 array->set_length(Smi::FromInt(new_length));
509 return Smi::FromInt(new_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000510 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000511}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512
513
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000514BUILTIN(ArrayPop) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000515 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000516 Object* receiver = *args.receiver();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000517 FixedArrayBase* elms_obj;
518 MaybeObject* maybe_elms =
519 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
520 if (maybe_elms == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
521 if (!maybe_elms->To(&elms_obj)) return maybe_elms;
522
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000523 JSArray* array = JSArray::cast(receiver);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000524 ASSERT(!array->map()->is_observed());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000525
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526 int len = Smi::cast(array->length())->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000527 if (len == 0) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000528
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000529 ElementsAccessor* accessor = array->GetElementsAccessor();
530 int new_length = len - 1;
531 MaybeObject* maybe_result;
532 if (accessor->HasElement(array, array, new_length, elms_obj)) {
533 maybe_result = accessor->Get(array, array, new_length, elms_obj);
534 } else {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000535 maybe_result = array->GetPrototype()->GetElement(isolate, len - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000537 if (maybe_result->IsFailure()) return maybe_result;
538 MaybeObject* maybe_failure =
539 accessor->SetLength(array, Smi::FromInt(new_length));
540 if (maybe_failure->IsFailure()) return maybe_failure;
541 return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000543
544
ager@chromium.org5c838252010-02-19 08:53:10 +0000545BUILTIN(ArrayShift) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000547 Object* receiver = *args.receiver();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000548 FixedArrayBase* elms_obj;
549 MaybeObject* maybe_elms_obj =
550 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
551 if (maybe_elms_obj == NULL)
552 return CallJsBuiltin(isolate, "ArrayShift", args);
553 if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
554
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000555 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
556 return CallJsBuiltin(isolate, "ArrayShift", args);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000557 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000558 JSArray* array = JSArray::cast(receiver);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000559 ASSERT(!array->map()->is_observed());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000560
ager@chromium.org5c838252010-02-19 08:53:10 +0000561 int len = Smi::cast(array->length())->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000562 if (len == 0) return heap->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000563
ager@chromium.org5c838252010-02-19 08:53:10 +0000564 // Get first element
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000565 ElementsAccessor* accessor = array->GetElementsAccessor();
566 Object* first;
567 MaybeObject* maybe_first = accessor->Get(receiver, array, 0, elms_obj);
568 if (!maybe_first->To(&first)) return maybe_first;
ager@chromium.org5c838252010-02-19 08:53:10 +0000569 if (first->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 first = heap->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000571 }
572
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000573 if (!heap->lo_space()->Contains(elms_obj)) {
574 array->set_elements(LeftTrimFixedArray(heap, elms_obj, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000575 } else {
576 // Shift the elements.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000577 if (elms_obj->IsFixedArray()) {
578 FixedArray* elms = FixedArray::cast(elms_obj);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000579 DisallowHeapAllocation no_gc;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000580 heap->MoveElements(elms, 0, 1, len - 1);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000581 elms->set(len - 1, heap->the_hole_value());
582 } else {
583 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
584 MoveDoubleElements(elms, 0, elms, 1, len - 1);
585 elms->set_the_hole(len - 1);
586 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000587 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000588
589 // Set the length.
590 array->set_length(Smi::FromInt(len - 1));
591
592 return first;
593}
594
595
596BUILTIN(ArrayUnshift) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000598 Object* receiver = *args.receiver();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000599 FixedArrayBase* elms_obj;
600 MaybeObject* maybe_elms_obj =
601 EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
602 if (maybe_elms_obj == NULL)
603 return CallJsBuiltin(isolate, "ArrayUnshift", args);
604 if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
605
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000606 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
607 return CallJsBuiltin(isolate, "ArrayUnshift", args);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000608 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000609 JSArray* array = JSArray::cast(receiver);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000610 ASSERT(!array->map()->is_observed());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000611 if (!array->HasFastSmiOrObjectElements()) {
612 return CallJsBuiltin(isolate, "ArrayUnshift", args);
613 }
614 FixedArray* elms = FixedArray::cast(elms_obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000615
616 int len = Smi::cast(array->length())->value();
617 int to_add = args.length() - 1;
ager@chromium.org5c838252010-02-19 08:53:10 +0000618 int new_length = len + to_add;
619 // Currently fixed arrays cannot grow too big, so
620 // we should never hit this case.
621 ASSERT(to_add <= (Smi::kMaxValue - len));
622
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000623 MaybeObject* maybe_object =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000624 array->EnsureCanContainElements(&args, 1, to_add,
625 DONT_ALLOW_DOUBLE_ELEMENTS);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000626 if (maybe_object->IsFailure()) return maybe_object;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000627
ager@chromium.org5c838252010-02-19 08:53:10 +0000628 if (new_length > elms->length()) {
629 // New backing storage is needed.
630 int capacity = new_length + (new_length >> 1) + 16;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000631 FixedArray* new_elms;
632 MaybeObject* maybe_elms = heap->AllocateUninitializedFixedArray(capacity);
633 if (!maybe_elms->To(&new_elms)) return maybe_elms;
634
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000635 ElementsKind kind = array->GetElementsKind();
636 ElementsAccessor* accessor = array->GetElementsAccessor();
637 MaybeObject* maybe_failure = accessor->CopyElements(
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000638 NULL, 0, kind, new_elms, to_add,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000639 ElementsAccessor::kCopyToEndAndInitializeToHole, elms);
640 ASSERT(!maybe_failure->IsFailure());
641 USE(maybe_failure);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000642
ager@chromium.org5c838252010-02-19 08:53:10 +0000643 elms = new_elms;
644 array->set_elements(elms);
645 } else {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000646 DisallowHeapAllocation no_gc;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000647 heap->MoveElements(elms, to_add, 0, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000648 }
649
650 // Add the provided values.
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000651 DisallowHeapAllocation no_gc;
ager@chromium.org5c838252010-02-19 08:53:10 +0000652 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
653 for (int i = 0; i < to_add; i++) {
654 elms->set(i, args[i + 1], mode);
655 }
656
657 // Set the length.
658 array->set_length(Smi::FromInt(new_length));
659 return Smi::FromInt(new_length);
660}
661
662
ager@chromium.org5c838252010-02-19 08:53:10 +0000663BUILTIN(ArraySlice) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000664 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000665 Object* receiver = *args.receiver();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000666 FixedArrayBase* elms;
whesse@chromium.org023421e2010-12-21 12:19:12 +0000667 int len = -1;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000668 if (receiver->IsJSArray()) {
669 JSArray* array = JSArray::cast(receiver);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000670 if (!IsJSArrayFastElementMovingAllowed(heap, array)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000671 return CallJsBuiltin(isolate, "ArraySlice", args);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000672 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000673
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000674 if (array->HasFastElements()) {
675 elms = array->elements();
676 } else {
677 return CallJsBuiltin(isolate, "ArraySlice", args);
678 }
679
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000680 len = Smi::cast(array->length())->value();
681 } else {
682 // Array.slice(arguments, ...) is quite a common idiom (notably more
683 // than 50% of invocations in Web apps). Treat it in C++ as well.
684 Map* arguments_map =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000685 isolate->context()->native_context()->arguments_boilerplate()->map();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000686
687 bool is_arguments_object_with_fast_elements =
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000688 receiver->IsJSObject() &&
689 JSObject::cast(receiver)->map() == arguments_map;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000690 if (!is_arguments_object_with_fast_elements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000691 return CallJsBuiltin(isolate, "ArraySlice", args);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000692 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000693 JSObject* object = JSObject::cast(receiver);
694
695 if (object->HasFastElements()) {
696 elms = object->elements();
697 } else {
698 return CallJsBuiltin(isolate, "ArraySlice", args);
699 }
700 Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000701 if (!len_obj->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000702 return CallJsBuiltin(isolate, "ArraySlice", args);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000703 }
704 len = Smi::cast(len_obj)->value();
705 if (len > elms->length()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000706 return CallJsBuiltin(isolate, "ArraySlice", args);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000707 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000708 }
709
710 JSObject* object = JSObject::cast(receiver);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000711
whesse@chromium.org023421e2010-12-21 12:19:12 +0000712 ASSERT(len >= 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000713 int n_arguments = args.length() - 1;
714
715 // Note carefully choosen defaults---if argument is missing,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000716 // it's undefined which gets converted to 0 for relative_start
717 // and to len for relative_end.
718 int relative_start = 0;
719 int relative_end = len;
ager@chromium.org5c838252010-02-19 08:53:10 +0000720 if (n_arguments > 0) {
721 Object* arg1 = args[1];
722 if (arg1->IsSmi()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000723 relative_start = Smi::cast(arg1)->value();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000724 } else if (arg1->IsHeapNumber()) {
725 double start = HeapNumber::cast(arg1)->value();
726 if (start < kMinInt || start > kMaxInt) {
727 return CallJsBuiltin(isolate, "ArraySlice", args);
728 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000729 relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
ager@chromium.org5c838252010-02-19 08:53:10 +0000730 } else if (!arg1->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000731 return CallJsBuiltin(isolate, "ArraySlice", args);
ager@chromium.org5c838252010-02-19 08:53:10 +0000732 }
733 if (n_arguments > 1) {
734 Object* arg2 = args[2];
735 if (arg2->IsSmi()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000736 relative_end = Smi::cast(arg2)->value();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000737 } else if (arg2->IsHeapNumber()) {
738 double end = HeapNumber::cast(arg2)->value();
739 if (end < kMinInt || end > kMaxInt) {
740 return CallJsBuiltin(isolate, "ArraySlice", args);
741 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +0000742 relative_end = std::isnan(end) ? 0 : static_cast<int>(end);
ager@chromium.org5c838252010-02-19 08:53:10 +0000743 } else if (!arg2->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000744 return CallJsBuiltin(isolate, "ArraySlice", args);
ager@chromium.org5c838252010-02-19 08:53:10 +0000745 }
746 }
747 }
748
749 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000750 int k = (relative_start < 0) ? Max(len + relative_start, 0)
751 : Min(relative_start, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000752
753 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000754 int final = (relative_end < 0) ? Max(len + relative_end, 0)
755 : Min(relative_end, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000756
757 // Calculate the length of result array.
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000758 int result_len = Max(final - k, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000759
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000760 ElementsKind kind = object->GetElementsKind();
761 if (IsHoleyElementsKind(kind)) {
762 bool packed = true;
763 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
764 for (int i = k; i < final; i++) {
765 if (!accessor->HasElement(object, object, i, elms)) {
766 packed = false;
767 break;
768 }
769 }
770 if (packed) {
771 kind = GetPackedElementsKind(kind);
772 } else if (!receiver->IsJSArray()) {
773 return CallJsBuiltin(isolate, "ArraySlice", args);
774 }
775 }
776
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000777 JSArray* result_array;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000778 MaybeObject* maybe_array = heap->AllocateJSArrayAndStorage(kind,
779 result_len,
780 result_len);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000781
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000782 DisallowHeapAllocation no_gc;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000783 if (result_len == 0) return maybe_array;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000784 if (!maybe_array->To(&result_array)) return maybe_array;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000785
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000786 ElementsAccessor* accessor = object->GetElementsAccessor();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000787 MaybeObject* maybe_failure = accessor->CopyElements(
788 NULL, k, kind, result_array->elements(), 0, result_len, elms);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000789 ASSERT(!maybe_failure->IsFailure());
790 USE(maybe_failure);
ager@chromium.org5c838252010-02-19 08:53:10 +0000791
ager@chromium.org5c838252010-02-19 08:53:10 +0000792 return result_array;
793}
794
795
796BUILTIN(ArraySplice) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000797 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000798 Object* receiver = *args.receiver();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000799 FixedArrayBase* elms_obj;
800 MaybeObject* maybe_elms =
801 EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
802 if (maybe_elms == NULL) {
803 return CallJsBuiltin(isolate, "ArraySplice", args);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000804 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000805 if (!maybe_elms->To(&elms_obj)) return maybe_elms;
806
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000807 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
808 return CallJsBuiltin(isolate, "ArraySplice", args);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000809 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000810 JSArray* array = JSArray::cast(receiver);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000811 ASSERT(!array->map()->is_observed());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000812
ager@chromium.org5c838252010-02-19 08:53:10 +0000813 int len = Smi::cast(array->length())->value();
814
815 int n_arguments = args.length() - 1;
816
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000817 int relative_start = 0;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000818 if (n_arguments > 0) {
819 Object* arg1 = args[1];
820 if (arg1->IsSmi()) {
821 relative_start = Smi::cast(arg1)->value();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000822 } else if (arg1->IsHeapNumber()) {
823 double start = HeapNumber::cast(arg1)->value();
824 if (start < kMinInt || start > kMaxInt) {
825 return CallJsBuiltin(isolate, "ArraySplice", args);
826 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000827 relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000828 } else if (!arg1->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000829 return CallJsBuiltin(isolate, "ArraySplice", args);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000830 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000831 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000832 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
833 : Min(relative_start, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000834
835 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000836 // given as a request to delete all the elements from the start.
837 // And it differs from the case of undefined delete count.
ager@chromium.org5c838252010-02-19 08:53:10 +0000838 // This does not follow ECMA-262, but we do the same for
839 // compatibility.
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000840 int actual_delete_count;
841 if (n_arguments == 1) {
842 ASSERT(len - actual_start >= 0);
843 actual_delete_count = len - actual_start;
844 } else {
845 int value = 0; // ToInteger(undefined) == 0
846 if (n_arguments > 1) {
847 Object* arg2 = args[2];
848 if (arg2->IsSmi()) {
849 value = Smi::cast(arg2)->value();
850 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000851 return CallJsBuiltin(isolate, "ArraySplice", args);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000852 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000853 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000854 actual_delete_count = Min(Max(value, 0), len - actual_start);
ager@chromium.org5c838252010-02-19 08:53:10 +0000855 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000856
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000857 ElementsKind elements_kind = array->GetElementsKind();
858
859 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
860 int new_length = len - actual_delete_count + item_count;
861
862 // For double mode we do not support changing the length.
863 if (new_length > len && IsFastDoubleElementsKind(elements_kind)) {
864 return CallJsBuiltin(isolate, "ArraySplice", args);
865 }
866
867 if (new_length == 0) {
868 MaybeObject* maybe_array = heap->AllocateJSArrayWithElements(
869 elms_obj, elements_kind, actual_delete_count);
870 if (maybe_array->IsFailure()) return maybe_array;
871 array->set_elements(heap->empty_fixed_array());
872 array->set_length(Smi::FromInt(0));
873 return maybe_array;
874 }
875
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000876 JSArray* result_array = NULL;
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000877 MaybeObject* maybe_array =
878 heap->AllocateJSArrayAndStorage(elements_kind,
879 actual_delete_count,
880 actual_delete_count);
881 if (!maybe_array->To(&result_array)) return maybe_array;
ager@chromium.org5c838252010-02-19 08:53:10 +0000882
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000883 if (actual_delete_count > 0) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000884 DisallowHeapAllocation no_gc;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000885 ElementsAccessor* accessor = array->GetElementsAccessor();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000886 MaybeObject* maybe_failure = accessor->CopyElements(
887 NULL, actual_start, elements_kind, result_array->elements(),
888 0, actual_delete_count, elms_obj);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000889 // Cannot fail since the origin and target array are of the same elements
890 // kind.
891 ASSERT(!maybe_failure->IsFailure());
892 USE(maybe_failure);
ager@chromium.org5c838252010-02-19 08:53:10 +0000893 }
894
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000895 bool elms_changed = false;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000896 if (item_count < actual_delete_count) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000897 // Shrink the array.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000898 const bool trim_array = !heap->lo_space()->Contains(elms_obj) &&
lrn@chromium.org25156de2010-04-06 13:10:27 +0000899 ((actual_start + item_count) <
900 (len - actual_delete_count - actual_start));
901 if (trim_array) {
902 const int delta = actual_delete_count - item_count;
903
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000904 if (elms_obj->IsFixedDoubleArray()) {
905 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
906 MoveDoubleElements(elms, delta, elms, 0, actual_start);
907 } else {
908 FixedArray* elms = FixedArray::cast(elms_obj);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000909 DisallowHeapAllocation no_gc;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000910 heap->MoveElements(elms, delta, 0, actual_start);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000911 }
912
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000913 elms_obj = LeftTrimFixedArray(heap, elms_obj, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000914
915 elms_changed = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000916 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000917 if (elms_obj->IsFixedDoubleArray()) {
918 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
919 MoveDoubleElements(elms, actual_start + item_count,
920 elms, actual_start + actual_delete_count,
921 (len - actual_delete_count - actual_start));
922 FillWithHoles(elms, new_length, len);
923 } else {
924 FixedArray* elms = FixedArray::cast(elms_obj);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000925 DisallowHeapAllocation no_gc;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000926 heap->MoveElements(elms, actual_start + item_count,
927 actual_start + actual_delete_count,
928 (len - actual_delete_count - actual_start));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000929 FillWithHoles(heap, elms, new_length, len);
930 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000931 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000932 } else if (item_count > actual_delete_count) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000933 FixedArray* elms = FixedArray::cast(elms_obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000934 // Currently fixed arrays cannot grow too big, so
935 // we should never hit this case.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000936 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
ager@chromium.org5c838252010-02-19 08:53:10 +0000937
938 // Check if array need to grow.
939 if (new_length > elms->length()) {
940 // New backing storage is needed.
941 int capacity = new_length + (new_length >> 1) + 16;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000942 FixedArray* new_elms;
943 MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
944 if (!maybe_obj->To(&new_elms)) return maybe_obj;
ager@chromium.org5c838252010-02-19 08:53:10 +0000945
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000946 DisallowHeapAllocation no_gc;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000947
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000948 ElementsKind kind = array->GetElementsKind();
949 ElementsAccessor* accessor = array->GetElementsAccessor();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000950 if (actual_start > 0) {
951 // Copy the part before actual_start as is.
952 MaybeObject* maybe_failure = accessor->CopyElements(
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000953 NULL, 0, kind, new_elms, 0, actual_start, elms);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000954 ASSERT(!maybe_failure->IsFailure());
955 USE(maybe_failure);
956 }
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000957 MaybeObject* maybe_failure = accessor->CopyElements(
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +0000958 NULL, actual_start + actual_delete_count, kind, new_elms,
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000959 actual_start + item_count,
960 ElementsAccessor::kCopyToEndAndInitializeToHole, elms);
961 ASSERT(!maybe_failure->IsFailure());
962 USE(maybe_failure);
ager@chromium.org5c838252010-02-19 08:53:10 +0000963
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000964 elms_obj = new_elms;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000965 elms_changed = true;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000966 } else {
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000967 DisallowHeapAllocation no_gc;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000968 heap->MoveElements(elms, actual_start + item_count,
969 actual_start + actual_delete_count,
970 (len - actual_delete_count - actual_start));
ager@chromium.org5c838252010-02-19 08:53:10 +0000971 }
972 }
973
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000974 if (IsFastDoubleElementsKind(elements_kind)) {
975 FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
976 for (int k = actual_start; k < actual_start + item_count; k++) {
977 Object* arg = args[3 + k - actual_start];
978 if (arg->IsSmi()) {
979 elms->set(k, Smi::cast(arg)->value());
980 } else {
981 elms->set(k, HeapNumber::cast(arg)->value());
982 }
983 }
984 } else {
985 FixedArray* elms = FixedArray::cast(elms_obj);
rossberg@chromium.org79e79022013-06-03 15:43:46 +0000986 DisallowHeapAllocation no_gc;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000987 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
988 for (int k = actual_start; k < actual_start + item_count; k++) {
989 elms->set(k, args[3 + k - actual_start], mode);
990 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000991 }
992
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000993 if (elms_changed) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000994 array->set_elements(elms_obj);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000995 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000996 // Set the length.
997 array->set_length(Smi::FromInt(new_length));
998
999 return result_array;
1000}
1001
1002
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001003BUILTIN(ArrayConcat) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 Heap* heap = isolate->heap();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001005 Context* native_context = isolate->context()->native_context();
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001006 JSObject* array_proto =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001007 JSObject::cast(native_context->array_function()->prototype());
1008 if (!ArrayPrototypeHasNoElements(heap, native_context, array_proto)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001009 return CallJsBuiltin(isolate, "ArrayConcat", args);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001010 }
1011
1012 // Iterate through all the arguments performing checks
1013 // and calculating total length.
1014 int n_arguments = args.length();
1015 int result_len = 0;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001016 ElementsKind elements_kind = GetInitialFastElementsKind();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001017 bool has_double = false;
1018 bool is_holey = false;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001019 for (int i = 0; i < n_arguments; i++) {
1020 Object* arg = args[i];
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001021 if (!arg->IsJSArray() ||
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001022 !JSArray::cast(arg)->HasFastElements() ||
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001023 JSArray::cast(arg)->GetPrototype() != array_proto) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001024 return CallJsBuiltin(isolate, "ArrayConcat", args);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001025 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001026 int len = Smi::cast(JSArray::cast(arg)->length())->value();
1027
1028 // We shouldn't overflow when adding another len.
1029 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
1030 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
1031 USE(kHalfOfMaxInt);
1032 result_len += len;
1033 ASSERT(result_len >= 0);
1034
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001035 if (result_len > FixedDoubleArray::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001036 return CallJsBuiltin(isolate, "ArrayConcat", args);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001037 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001038
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001039 ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001040 has_double = has_double || IsFastDoubleElementsKind(arg_kind);
1041 is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
1042 if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) {
1043 elements_kind = arg_kind;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001044 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001045 }
1046
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001047 if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind);
1048
1049 // If a double array is concatted into a fast elements array, the fast
1050 // elements array needs to be initialized to contain proper holes, since
1051 // boxing doubles may cause incremental marking.
1052 ArrayStorageAllocationMode mode =
1053 has_double && IsFastObjectElementsKind(elements_kind)
1054 ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001055 JSArray* result_array;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001056 // Allocate result.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001057 MaybeObject* maybe_array =
1058 heap->AllocateJSArrayAndStorage(elements_kind,
1059 result_len,
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001060 result_len,
1061 mode);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001062 if (!maybe_array->To(&result_array)) return maybe_array;
1063 if (result_len == 0) return result_array;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001064
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001065 int j = 0;
1066 FixedArrayBase* storage = result_array->elements();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001067 ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001068 for (int i = 0; i < n_arguments; i++) {
1069 JSArray* array = JSArray::cast(args[i]);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001070 int len = Smi::cast(array->length())->value();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001071 ElementsKind from_kind = array->GetElementsKind();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001072 if (len > 0) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001073 MaybeObject* maybe_failure =
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001074 accessor->CopyElements(array, 0, from_kind, storage, j, len);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001075 if (maybe_failure->IsFailure()) return maybe_failure;
1076 j += len;
1077 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001078 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001079
1080 ASSERT(j == result_len);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001081
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001082 return result_array;
1083}
1084
1085
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086// -----------------------------------------------------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087// Strict mode poison pills
1088
1089
danno@chromium.org40cb8782011-05-25 07:58:50 +00001090BUILTIN(StrictModePoisonPill) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001091 HandleScope scope(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001092 return isolate->Throw(*isolate->factory()->NewTypeError(
danno@chromium.org40cb8782011-05-25 07:58:50 +00001093 "strict_poison_pill", HandleVector<Object>(NULL, 0)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001094}
1095
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001096
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097// -----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098//
1099
1100
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001101// Searches the hidden prototype chain of the given object for the first
1102// object that is an instance of the given type. If no such object can
1103// be found then Heap::null_value() is returned.
1104static inline Object* FindHidden(Heap* heap,
1105 Object* object,
1106 FunctionTemplateInfo* type) {
1107 if (object->IsInstanceOf(type)) return object;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001108 Object* proto = object->GetPrototype(heap->isolate());
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001109 if (proto->IsJSObject() &&
1110 JSObject::cast(proto)->map()->is_hidden_prototype()) {
1111 return FindHidden(heap, proto, type);
1112 }
1113 return heap->null_value();
1114}
1115
1116
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001117// Returns the holder JSObject if the function can legally be called
1118// with this receiver. Returns Heap::null_value() if the call is
1119// illegal. Any arguments that don't fit the expected type is
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001120// overwritten with undefined. Note that holder and the arguments are
1121// implicitly rewritten with the first object in the hidden prototype
1122// chain that actually has the expected type.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001123static inline Object* TypeCheck(Heap* heap,
1124 int argc,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001125 Object** argv,
1126 FunctionTemplateInfo* info) {
1127 Object* recv = argv[0];
lrn@chromium.org1c092762011-05-09 09:42:16 +00001128 // API calls are only supported with JSObject receivers.
1129 if (!recv->IsJSObject()) return heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130 Object* sig_obj = info->signature();
1131 if (sig_obj->IsUndefined()) return recv;
1132 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
1133 // If necessary, check the receiver
1134 Object* recv_type = sig->receiver();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135 Object* holder = recv;
1136 if (!recv_type->IsUndefined()) {
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001137 holder = FindHidden(heap, holder, FunctionTemplateInfo::cast(recv_type));
1138 if (holder == heap->null_value()) return heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001139 }
1140 Object* args_obj = sig->args();
1141 // If there is no argument signature we're done
1142 if (args_obj->IsUndefined()) return holder;
1143 FixedArray* args = FixedArray::cast(args_obj);
1144 int length = args->length();
mads.s.ager31e71382008-08-13 09:32:07 +00001145 if (argc <= length) length = argc - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146 for (int i = 0; i < length; i++) {
1147 Object* argtype = args->get(i);
1148 if (argtype->IsUndefined()) continue;
1149 Object** arg = &argv[-1 - i];
1150 Object* current = *arg;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001151 current = FindHidden(heap, current, FunctionTemplateInfo::cast(argtype));
1152 if (current == heap->null_value()) current = heap->undefined_value();
1153 *arg = current;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001154 }
1155 return holder;
1156}
1157
1158
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001159template <bool is_construct>
lrn@chromium.org303ada72010-10-27 09:33:13 +00001160MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001161 BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
1162 ASSERT(is_construct == CalledAsConstructor(isolate));
1163 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001165 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001166 Handle<JSFunction> function = args.called_function();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001167 ASSERT(function->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001169 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170 if (is_construct) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001171 Handle<FunctionTemplateInfo> desc(fun_data, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 bool pending_exception = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001173 isolate->factory()->ConfigureInstance(
1174 desc, Handle<JSObject>::cast(args.receiver()), &pending_exception);
1175 ASSERT(isolate->has_pending_exception() == pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176 if (pending_exception) return Failure::Exception();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001177 fun_data = *desc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 }
1179
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001180 Object* raw_holder = TypeCheck(heap, args.length(), &args[0], fun_data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001181
1182 if (raw_holder->IsNull()) {
1183 // This function cannot be called with the given receiver. Abort!
1184 Handle<Object> obj =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001185 isolate->factory()->NewTypeError(
1186 "illegal_invocation", HandleVector(&function, 1));
1187 return isolate->Throw(*obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 }
1189
1190 Object* raw_call_data = fun_data->call_code();
1191 if (!raw_call_data->IsUndefined()) {
1192 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1193 Object* callback_obj = call_data->callback();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001194 v8::FunctionCallback callback =
1195 v8::ToCData<v8::FunctionCallback>(callback_obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196 Object* data_obj = call_data->data();
1197 Object* result;
1198
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001199 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001200 ASSERT(raw_holder->IsJSObject());
1201
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001202 FunctionCallbackArguments custom(isolate,
1203 data_obj,
1204 *function,
1205 raw_holder,
1206 &args[0] - 1,
1207 args.length() - 1,
1208 is_construct);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001210 v8::Handle<v8::Value> value = custom.Call(callback);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211 if (value.IsEmpty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001212 result = heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213 } else {
1214 result = *reinterpret_cast<Object**>(*value);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001215 result->VerifyApiCallResultType();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001216 }
1217
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001218 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219 if (!is_construct || result->IsJSObject()) return result;
1220 }
1221
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001222 return *args.receiver();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001224
1225
1226BUILTIN(HandleApiCall) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001227 return HandleApiCallHelper<false>(args, isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001228}
1229
1230
1231BUILTIN(HandleApiCallConstruct) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001232 return HandleApiCallHelper<true>(args, isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001233}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234
1235
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001236// Helper function to handle calls to non-function objects created through the
1237// API. The object can be called as either a constructor (using new) or just as
1238// a function (without new).
lrn@chromium.org303ada72010-10-27 09:33:13 +00001239MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001240 Isolate* isolate,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001241 bool is_construct_call,
1242 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001243 // Non-functions are never called as constructors. Even if this is an object
1244 // called as a constructor the delegate call is not a construct call.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001245 ASSERT(!CalledAsConstructor(isolate));
1246 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001248 Handle<Object> receiver = args.receiver();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001249
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001250 // Get the object called.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001251 JSObject* obj = JSObject::cast(*receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252
1253 // Get the invocation callback from the function descriptor that was
1254 // used to create the called object.
1255 ASSERT(obj->map()->has_instance_call_handler());
1256 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001257 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258 Object* handler =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001259 constructor->shared()->get_api_func_data()->instance_call_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260 ASSERT(!handler->IsUndefined());
1261 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1262 Object* callback_obj = call_data->callback();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001263 v8::FunctionCallback callback =
1264 v8::ToCData<v8::FunctionCallback>(callback_obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001265
1266 // Get the data for the call and perform the callback.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 Object* result;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001268 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 HandleScope scope(isolate);
1270 LOG(isolate, ApiObjectAccess("call non-function", obj));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001271
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001272 FunctionCallbackArguments custom(isolate,
1273 call_data->data(),
1274 constructor,
1275 obj,
1276 &args[0] - 1,
1277 args.length() - 1,
1278 is_construct_call);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001279 v8::Handle<v8::Value> value = custom.Call(callback);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280 if (value.IsEmpty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001281 result = heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 } else {
1283 result = *reinterpret_cast<Object**>(*value);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001284 result->VerifyApiCallResultType();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 }
1286 }
1287 // Check for exceptions and return result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001288 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001289 return result;
1290}
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001291
1292
1293// Handle calls to non-function objects created through the API. This delegate
1294// function is used when the call is a normal function call.
1295BUILTIN(HandleApiCallAsFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001296 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001297}
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001298
1299
1300// Handle calls to non-function objects created through the API. This delegate
1301// function is used when the call is a construct call.
1302BUILTIN(HandleApiCallAsConstructor) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001304}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305
1306
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1308 LoadIC::GenerateInitialize(masm);
1309}
1310
1311
1312static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1313 LoadIC::GeneratePreMonomorphic(masm);
1314}
1315
1316
1317static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1318 LoadIC::GenerateMiss(masm);
1319}
1320
1321
1322static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1323 LoadIC::GenerateMegamorphic(masm);
1324}
1325
1326
1327static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1328 LoadIC::GenerateNormal(masm);
1329}
1330
1331
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001332static void Generate_LoadIC_Getter_ForDeopt(MacroAssembler* masm) {
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001333 LoadStubCompiler::GenerateLoadViaGetter(
1334 masm, LoadStubCompiler::registers()[0], Handle<JSFunction>());
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00001335}
1336
1337
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001338static void Generate_LoadIC_Slow(MacroAssembler* masm) {
1339 LoadIC::GenerateRuntimeGetProperty(masm);
1340}
1341
1342
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1344 KeyedLoadIC::GenerateInitialize(masm);
1345}
1346
1347
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001348static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
1349 KeyedLoadIC::GenerateRuntimeGetProperty(masm);
1350}
1351
1352
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001354 KeyedLoadIC::GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355}
1356
1357
1358static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1359 KeyedLoadIC::GenerateGeneric(masm);
1360}
1361
1362
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001363static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1364 KeyedLoadIC::GenerateString(masm);
1365}
1366
1367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1369 KeyedLoadIC::GeneratePreMonomorphic(masm);
1370}
1371
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001372
ager@chromium.org5c838252010-02-19 08:53:10 +00001373static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1374 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1375}
1376
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001377
whesse@chromium.org7b260152011-06-20 15:33:18 +00001378static void Generate_KeyedLoadIC_NonStrictArguments(MacroAssembler* masm) {
1379 KeyedLoadIC::GenerateNonStrictArguments(masm);
1380}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001382
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001383static void Generate_StoreIC_Slow(MacroAssembler* masm) {
1384 StoreIC::GenerateSlow(masm);
1385}
1386
1387
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001388static void Generate_StoreIC_Slow_Strict(MacroAssembler* masm) {
1389 StoreIC::GenerateSlow(masm);
1390}
1391
1392
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1394 StoreIC::GenerateInitialize(masm);
1395}
1396
1397
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001398static void Generate_StoreIC_Initialize_Strict(MacroAssembler* masm) {
1399 StoreIC::GenerateInitialize(masm);
1400}
1401
1402
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001403static void Generate_StoreIC_PreMonomorphic(MacroAssembler* masm) {
1404 StoreIC::GeneratePreMonomorphic(masm);
1405}
1406
1407
1408static void Generate_StoreIC_PreMonomorphic_Strict(MacroAssembler* masm) {
1409 StoreIC::GeneratePreMonomorphic(masm);
1410}
1411
1412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1414 StoreIC::GenerateMiss(masm);
1415}
1416
1417
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001418static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1419 StoreIC::GenerateNormal(masm);
1420}
1421
1422
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001423static void Generate_StoreIC_Normal_Strict(MacroAssembler* masm) {
1424 StoreIC::GenerateNormal(masm);
1425}
1426
1427
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001428static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001429 StoreIC::GenerateMegamorphic(masm, kNonStrictMode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001430}
1431
1432
1433static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001434 StoreIC::GenerateMegamorphic(masm, kStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435}
1436
1437
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001438static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001439 StoreIC::GenerateRuntimeSetProperty(masm, kNonStrictMode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001440}
1441
1442
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001443static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001444 StoreIC::GenerateRuntimeSetProperty(masm, kStrictMode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001445}
1446
1447
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001448static void Generate_StoreIC_Setter_ForDeopt(MacroAssembler* masm) {
1449 StoreStubCompiler::GenerateStoreViaSetter(masm, Handle<JSFunction>());
1450}
1451
1452
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001453static void Generate_StoreIC_Generic(MacroAssembler* masm) {
1454 StoreIC::GenerateRuntimeSetProperty(masm, kNonStrictMode);
1455}
1456
1457
1458static void Generate_StoreIC_Generic_Strict(MacroAssembler* masm) {
1459 StoreIC::GenerateRuntimeSetProperty(masm, kStrictMode);
1460}
1461
1462
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001464 KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode);
1465}
1466
1467
1468static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) {
1469 KeyedStoreIC::GenerateGeneric(masm, kStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470}
1471
1472
1473static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00001474 KeyedStoreIC::GenerateMiss(masm);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001475}
1476
1477
1478static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
1479 KeyedStoreIC::GenerateSlow(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480}
1481
1482
mstarzinger@chromium.org2efc3e42013-10-14 08:45:38 +00001483static void Generate_KeyedStoreIC_Slow_Strict(MacroAssembler* masm) {
1484 KeyedStoreIC::GenerateSlow(masm);
1485}
1486
1487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001488static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1489 KeyedStoreIC::GenerateInitialize(masm);
1490}
1491
1492
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001493static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
1494 KeyedStoreIC::GenerateInitialize(masm);
1495}
1496
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001497
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00001498static void Generate_KeyedStoreIC_PreMonomorphic(MacroAssembler* masm) {
1499 KeyedStoreIC::GeneratePreMonomorphic(masm);
1500}
1501
1502
1503static void Generate_KeyedStoreIC_PreMonomorphic_Strict(MacroAssembler* masm) {
1504 KeyedStoreIC::GeneratePreMonomorphic(masm);
1505}
1506
1507
whesse@chromium.org7b260152011-06-20 15:33:18 +00001508static void Generate_KeyedStoreIC_NonStrictArguments(MacroAssembler* masm) {
1509 KeyedStoreIC::GenerateNonStrictArguments(masm);
1510}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001511
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001512
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001513#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org8bb60582008-12-11 12:02:20 +00001514static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1515 Debug::GenerateLoadICDebugBreak(masm);
1516}
1517
1518
1519static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1520 Debug::GenerateStoreICDebugBreak(masm);
1521}
1522
1523
1524static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1525 Debug::GenerateKeyedLoadICDebugBreak(masm);
1526}
1527
1528
1529static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1530 Debug::GenerateKeyedStoreICDebugBreak(masm);
1531}
1532
1533
danno@chromium.orgf005df62013-04-30 16:36:45 +00001534static void Generate_CompareNilIC_DebugBreak(MacroAssembler* masm) {
1535 Debug::GenerateCompareNilICDebugBreak(masm);
1536}
1537
1538
ager@chromium.org8bb60582008-12-11 12:02:20 +00001539static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1540 Debug::GenerateReturnDebugBreak(masm);
1541}
1542
1543
danno@chromium.orgc612e022011-11-10 11:38:15 +00001544static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) {
1545 Debug::GenerateCallFunctionStubDebugBreak(masm);
ager@chromium.org8bb60582008-12-11 12:02:20 +00001546}
ager@chromium.org357bf652010-04-12 11:30:10 +00001547
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001548
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001549static void Generate_CallFunctionStub_Recording_DebugBreak(
1550 MacroAssembler* masm) {
1551 Debug::GenerateCallFunctionStubRecordDebugBreak(masm);
1552}
1553
1554
1555static void Generate_CallConstructStub_DebugBreak(MacroAssembler* masm) {
1556 Debug::GenerateCallConstructStubDebugBreak(masm);
1557}
1558
1559
1560static void Generate_CallConstructStub_Recording_DebugBreak(
1561 MacroAssembler* masm) {
1562 Debug::GenerateCallConstructStubRecordDebugBreak(masm);
1563}
1564
1565
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001566static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1567 Debug::GenerateSlotDebugBreak(masm);
1568}
1569
1570
ager@chromium.org357bf652010-04-12 11:30:10 +00001571static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1572 Debug::GeneratePlainReturnLiveEdit(masm);
1573}
1574
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001575
ager@chromium.org357bf652010-04-12 11:30:10 +00001576static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1577 Debug::GenerateFrameDropperLiveEdit(masm);
1578}
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001579#endif
ager@chromium.org8bb60582008-12-11 12:02:20 +00001580
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001581
1582Builtins::Builtins() : initialized_(false) {
1583 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
1584 memset(names_, 0, sizeof(names_[0]) * builtin_count);
1585}
1586
1587
1588Builtins::~Builtins() {
1589}
1590
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001592#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001593Address const Builtins::c_functions_[cfunction_count] = {
1594 BUILTIN_LIST_C(DEF_ENUM_C)
1595};
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001596#undef DEF_ENUM_C
1597
1598#define DEF_JS_NAME(name, ignore) #name,
1599#define DEF_JS_ARGC(ignore, argc) argc,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001600const char* const Builtins::javascript_names_[id_count] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601 BUILTINS_LIST_JS(DEF_JS_NAME)
1602};
1603
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001604int const Builtins::javascript_argc_[id_count] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605 BUILTINS_LIST_JS(DEF_JS_ARGC)
1606};
1607#undef DEF_JS_NAME
1608#undef DEF_JS_ARGC
1609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001610struct BuiltinDesc {
1611 byte* generator;
1612 byte* c_code;
1613 const char* s_name; // name is only used for generating log information.
1614 int name;
1615 Code::Flags flags;
1616 BuiltinExtraArguments extra_args;
1617};
1618
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001619#define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} }
1620
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001621class BuiltinFunctionTable {
1622 public:
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001623 BuiltinDesc* functions() {
1624 CallOnce(&once_, &Builtins::InitBuiltinFunctionTable);
1625 return functions_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001626 }
1627
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001628 OnceType once_;
1629 BuiltinDesc functions_[Builtins::builtin_count + 1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001630
1631 friend class Builtins;
1632};
1633
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001634static BuiltinFunctionTable builtin_function_table =
1635 BUILTIN_FUNCTION_TABLE_INIT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001636
1637// Define array of pointers to generators and C builtin functions.
1638// We do this in a sort of roundabout way so that we can do the initialization
1639// within the lexical scope of Builtins:: and within a context where
1640// Code::Flags names a non-abstract type.
1641void Builtins::InitBuiltinFunctionTable() {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001642 BuiltinDesc* functions = builtin_function_table.functions_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001643 functions[builtin_count].generator = NULL;
1644 functions[builtin_count].c_code = NULL;
1645 functions[builtin_count].s_name = NULL;
1646 functions[builtin_count].name = builtin_count;
1647 functions[builtin_count].flags = static_cast<Code::Flags>(0);
1648 functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
1649
1650#define DEF_FUNCTION_PTR_C(aname, aextra_args) \
1651 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
1652 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
1653 functions->s_name = #aname; \
1654 functions->name = c_##aname; \
1655 functions->flags = Code::ComputeFlags(Code::BUILTIN); \
1656 functions->extra_args = aextra_args; \
1657 ++functions;
1658
1659#define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
1660 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1661 functions->c_code = NULL; \
1662 functions->s_name = #aname; \
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001663 functions->name = k##aname; \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001664 functions->flags = Code::ComputeFlags(Code::kind, \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001665 state, \
1666 extra); \
1667 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1668 ++functions;
1669
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +00001670#define DEF_FUNCTION_PTR_H(aname, kind, extra) \
1671 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1672 functions->c_code = NULL; \
1673 functions->s_name = #aname; \
1674 functions->name = k##aname; \
1675 functions->flags = Code::ComputeFlags( \
1676 Code::HANDLER, MONOMORPHIC, extra, Code::NORMAL, Code::kind); \
1677 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1678 ++functions;
1679
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001680 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1681 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +00001682 BUILTIN_LIST_H(DEF_FUNCTION_PTR_H)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001683 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1684
1685#undef DEF_FUNCTION_PTR_C
1686#undef DEF_FUNCTION_PTR_A
1687}
1688
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001689
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001690void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001691 ASSERT(!initialized_);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001692 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001693
1694 // Create a scope for the handles in the builtins.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001695 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001696
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001697 const BuiltinDesc* functions = builtin_function_table.functions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001698
1699 // For now we generate builtin adaptor code into a stack-allocated
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001700 // buffer, before copying it into individual code objects. Be careful
1701 // with alignment, some platforms don't like unaligned code.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001702 union { int force_alignment; byte buffer[8*KB]; } u;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001703
1704 // Traverse the list of builtins and generate an adaptor in a
1705 // separate code object for each one.
1706 for (int i = 0; i < builtin_count; i++) {
1707 if (create_heap_objects) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001708 MacroAssembler masm(isolate, u.buffer, sizeof u.buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001709 // Generate the code/adaptor.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001710 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001711 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1712 // We pass all arguments to the generator, but it may not use all of
1713 // them. This works because the first arguments are on top of the
1714 // stack.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001715 ASSERT(!masm.has_frame());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001716 g(&masm, functions[i].name, functions[i].extra_args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001717 // Move the code into the object heap.
1718 CodeDesc desc;
1719 masm.GetCode(&desc);
1720 Code::Flags flags = functions[i].flags;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001721 Object* code = NULL;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001722 {
1723 // During startup it's OK to always allocate and defer GC to later.
1724 // This simplifies things because we don't need to retry.
1725 AlwaysAllocateScope __scope__;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001726 { MaybeObject* maybe_code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 heap->CreateCode(desc, flags, masm.CodeObject());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001728 if (!maybe_code->ToObject(&code)) {
1729 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1730 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001732 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 // Log the event and add the code to the builtins array.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001734 PROFILE(isolate,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 CodeCreateEvent(Logger::BUILTIN_TAG,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001736 Code::cast(code),
1737 functions[i].s_name));
1738 GDBJIT(AddCode(GDBJITInterface::BUILTIN,
1739 functions[i].s_name,
1740 Code::cast(code)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741 builtins_[i] = code;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001742#ifdef ENABLE_DISASSEMBLER
mads.s.ager31e71382008-08-13 09:32:07 +00001743 if (FLAG_print_builtin_code) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001744 CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
1745 PrintF(trace_scope.file(), "Builtin: %s\n", functions[i].s_name);
1746 Code::cast(code)->Disassemble(functions[i].s_name, trace_scope.file());
1747 PrintF(trace_scope.file(), "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00001748 }
1749#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001750 } else {
1751 // Deserializing. The values will be filled in during IterateBuiltins.
1752 builtins_[i] = NULL;
1753 }
1754 names_[i] = functions[i].s_name;
1755 }
1756
1757 // Mark as initialized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001758 initialized_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001759}
1760
1761
1762void Builtins::TearDown() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 initialized_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001764}
1765
1766
1767void Builtins::IterateBuiltins(ObjectVisitor* v) {
1768 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1769}
1770
1771
1772const char* Builtins::Lookup(byte* pc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001773 // may be called during initialization (disassembler!)
1774 if (initialized_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001775 for (int i = 0; i < builtin_count; i++) {
1776 Code* entry = Code::cast(builtins_[i]);
1777 if (entry->contains(pc)) {
1778 return names_[i];
1779 }
1780 }
1781 }
1782 return NULL;
1783}
1784
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001785
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00001786void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
1787 masm->TailCallRuntime(Runtime::kInterrupt, 0, 1);
1788}
1789
1790
1791void Builtins::Generate_StackCheck(MacroAssembler* masm) {
1792 masm->TailCallRuntime(Runtime::kStackGuard, 0, 1);
1793}
1794
1795
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001796#define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
1797Handle<Code> Builtins::name() { \
1798 Code** code_address = \
1799 reinterpret_cast<Code**>(builtin_address(k##name)); \
1800 return Handle<Code>(code_address); \
1801}
1802#define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
1803Handle<Code> Builtins::name() { \
1804 Code** code_address = \
1805 reinterpret_cast<Code**>(builtin_address(k##name)); \
1806 return Handle<Code>(code_address); \
1807}
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +00001808#define DEFINE_BUILTIN_ACCESSOR_H(name, kind, extra) \
1809Handle<Code> Builtins::name() { \
1810 Code** code_address = \
1811 reinterpret_cast<Code**>(builtin_address(k##name)); \
1812 return Handle<Code>(code_address); \
1813}
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001814BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1815BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +00001816BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H)
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001817BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1818#undef DEFINE_BUILTIN_ACCESSOR_C
1819#undef DEFINE_BUILTIN_ACCESSOR_A
1820
1821
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001822} } // namespace v8::internal