blob: d403a951cfb1c4ed0795cdb941c03a9c91a9ccda [file] [log] [blame]
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000031#include "arguments.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "bootstrapper.h"
33#include "builtins.h"
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000034#include "gdb-jit.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "ic-inl.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037
kasperl@chromium.org71affb52009-05-26 05:44:31 +000038namespace v8 {
39namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000041namespace {
42
43// Arguments object passed to C++ builtins.
44template <BuiltinExtraArguments extra_args>
45class BuiltinArguments : public Arguments {
46 public:
47 BuiltinArguments(int length, Object** arguments)
48 : Arguments(length, arguments) { }
49
50 Object*& operator[] (int index) {
51 ASSERT(index < length());
52 return Arguments::operator[](index);
53 }
54
55 template <class S> Handle<S> at(int index) {
56 ASSERT(index < length());
57 return Arguments::at<S>(index);
58 }
59
60 Handle<Object> receiver() {
61 return Arguments::at<Object>(0);
62 }
63
64 Handle<JSFunction> called_function() {
65 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
66 return Arguments::at<JSFunction>(Arguments::length() - 1);
67 }
68
69 // Gets the total number of arguments including the receiver (but
70 // excluding extra arguments).
71 int length() const {
72 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
73 return Arguments::length();
74 }
75
76#ifdef DEBUG
77 void Verify() {
78 // Check we have at least the receiver.
79 ASSERT(Arguments::length() >= 1);
80 }
81#endif
82};
83
84
85// Specialize BuiltinArguments for the called function extra argument.
86
87template <>
88int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
89 return Arguments::length() - 1;
90}
91
92#ifdef DEBUG
93template <>
94void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
95 // Check we have at least the receiver and the called function.
96 ASSERT(Arguments::length() >= 2);
97 // Make sure cast to JSFunction succeeds.
98 called_function();
99}
100#endif
101
102
103#define DEF_ARG_TYPE(name, spec) \
104 typedef BuiltinArguments<spec> name##ArgumentsType;
105BUILTIN_LIST_C(DEF_ARG_TYPE)
106#undef DEF_ARG_TYPE
107
108} // namespace
109
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000110// ----------------------------------------------------------------------------
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000111// Support macro for defining builtins in C++.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112// ----------------------------------------------------------------------------
113//
114// A builtin function is defined by writing:
115//
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000116// BUILTIN(name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000117// ...
118// }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000119//
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000120// In the body of the builtin function the arguments can be accessed
121// through the BuiltinArguments object args.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000123#ifdef DEBUG
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000125#define BUILTIN(name) \
126 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
127 name##ArgumentsType args, Isolate* isolate); \
128 MUST_USE_RESULT static MaybeObject* Builtin_##name( \
129 name##ArgumentsType args, Isolate* isolate) { \
130 ASSERT(isolate == Isolate::Current()); \
131 args.Verify(); \
132 return Builtin_Impl_##name(args, isolate); \
133 } \
134 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
135 name##ArgumentsType args, Isolate* isolate)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137#else // For release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139#define BUILTIN(name) \
140 static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141
142#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143
144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145static inline bool CalledAsConstructor(Isolate* isolate) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000146#ifdef DEBUG
147 // Calculate the result using a full stack frame iterator and check
148 // that the state of the stack is as we assume it to be in the
149 // code below.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000150 StackFrameIterator it;
151 ASSERT(it.frame()->is_exit());
152 it.Advance();
153 StackFrame* frame = it.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000154 bool reference_result = frame->is_construct();
155#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000156 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000157 // Because we know fp points to an exit frame we can use the relevant
158 // part of ExitFrame::ComputeCallerState directly.
159 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
160 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
161 // This inlines the part of StackFrame::ComputeType that grabs the
162 // type of the current frame. Note that StackFrame::ComputeType
163 // has been specialized for each architecture so if any one of them
164 // changes this code has to be changed as well.
165 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
166 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
167 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
168 bool result = (marker == kConstructMarker);
169 ASSERT_EQ(result, reference_result);
170 return result;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000171}
172
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173// ----------------------------------------------------------------------------
174
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000175BUILTIN(Illegal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000176 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000177 return isolate->heap()->undefined_value(); // Make compiler happy.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000178}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000179
180
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000181BUILTIN(EmptyFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000182 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000184
185
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000186BUILTIN(ArrayCodeGeneric) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000187 Heap* heap = isolate->heap();
188 isolate->counters()->array_function_runtime()->Increment();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000190 JSArray* array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000191 if (CalledAsConstructor(isolate)) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000192 array = JSArray::cast(*args.receiver());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193 } else {
194 // Allocate the JS Array
195 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000196 isolate->context()->global_context()->array_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000197 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000198 { MaybeObject* maybe_obj = heap->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000199 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
200 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000201 array = JSArray::cast(obj);
202 }
203
204 // 'array' now contains the JSArray we should initialize.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000205 ASSERT(array->HasFastElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206
207 // Optimize the case where there is one argument and the argument is a
208 // small smi.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000209 if (args.length() == 2) {
210 Object* obj = args[1];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000211 if (obj->IsSmi()) {
212 int len = Smi::cast(obj)->value();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000213 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000214 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000215 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000216 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
217 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218 array->SetContent(FixedArray::cast(obj));
219 return array;
220 }
221 }
222 // Take the argument as the length.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000223 { MaybeObject* maybe_obj = array->Initialize(0);
224 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
225 }
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000226 return array->SetElementsLength(args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227 }
228
v8.team.kasperl727e9952008-09-02 14:56:44 +0000229 // Optimize the case where there are no parameters passed.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000230 if (args.length() == 1) {
231 return array->Initialize(JSArray::kPreallocatedArrayElements);
232 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000233
234 // Take the arguments as elements.
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000235 int number_of_elements = args.length() - 1;
mads.s.ager31e71382008-08-13 09:32:07 +0000236 Smi* len = Smi::FromInt(number_of_elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000237 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000238 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len->value());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000239 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
240 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000241
242 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000243 FixedArray* elms = FixedArray::cast(obj);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000244 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245 // Fill in the content
mads.s.ager31e71382008-08-13 09:32:07 +0000246 for (int index = 0; index < number_of_elements; index++) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000247 elms->set(index, args[index+1], mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000248 }
249
250 // Set length and elements on the array.
251 array->set_elements(FixedArray::cast(obj));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000252 array->set_length(len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253
254 return array;
255}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000256
257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000258MUST_USE_RESULT static MaybeObject* AllocateJSArray(Heap* heap) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000259 JSFunction* array_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000260 heap->isolate()->context()->global_context()->array_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000261 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000262 { MaybeObject* maybe_result = heap->AllocateJSObject(array_function);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000263 if (!maybe_result->ToObject(&result)) return maybe_result;
264 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000265 return result;
266}
267
268
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000269MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray(Heap* heap) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000270 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000271 { MaybeObject* maybe_result = AllocateJSArray(heap);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000272 if (!maybe_result->ToObject(&result)) return maybe_result;
273 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000274 JSArray* result_array = JSArray::cast(result);
275 result_array->set_length(Smi::FromInt(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000276 result_array->set_elements(heap->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000277 return result_array;
278}
279
280
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281static void CopyElements(Heap* heap,
282 AssertNoAllocation* no_gc,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000283 FixedArray* dst,
284 int dst_index,
285 FixedArray* src,
286 int src_index,
287 int len) {
288 ASSERT(dst != src); // Use MoveElements instead.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
lrn@chromium.org25156de2010-04-06 13:10:27 +0000290 ASSERT(len > 0);
291 CopyWords(dst->data_start() + dst_index,
292 src->data_start() + src_index,
293 len);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000294 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
295 if (mode == UPDATE_WRITE_BARRIER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000296 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000297 }
298}
299
300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301static void MoveElements(Heap* heap,
302 AssertNoAllocation* no_gc,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000303 FixedArray* dst,
304 int dst_index,
305 FixedArray* src,
306 int src_index,
307 int len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000308 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000309 memmove(dst->data_start() + dst_index,
310 src->data_start() + src_index,
311 len * kPointerSize);
312 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
313 if (mode == UPDATE_WRITE_BARRIER) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000315 }
316}
317
318
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000319static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) {
320 ASSERT(dst->map() != heap->fixed_cow_array_map());
321 MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000322}
323
324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325static FixedArray* LeftTrimFixedArray(Heap* heap,
326 FixedArray* elms,
327 int to_trim) {
328 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000329 // For now this trick is only applied to fixed arrays in new and paged space.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000330 // In large object space the object's start must coincide with chunk
331 // and thus the trick is just not applicable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 ASSERT(!HEAP->lo_space()->Contains(elms));
lrn@chromium.org25156de2010-04-06 13:10:27 +0000333
334 STATIC_ASSERT(FixedArray::kMapOffset == 0);
335 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
336 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
337
338 Object** former_start = HeapObject::RawField(elms, 0);
339
340 const int len = elms->length();
341
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000342 if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000343 !heap->new_space()->Contains(elms)) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000344 // If we are doing a big trim in old space then we zap the space that was
345 // formerly part of the array so that the GC (aided by the card-based
346 // remembered set) won't find pointers to new-space there.
347 Object** zap = reinterpret_cast<Object**>(elms->address());
348 zap++; // Header of filler must be at least one word so skip that.
349 for (int i = 1; i < to_trim; i++) {
350 *zap++ = Smi::FromInt(0);
351 }
352 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000353 // Technically in new space this write might be omitted (except for
354 // debug mode which iterates through the heap), but to play safer
355 // we still do it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000356 heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000357
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000358 former_start[to_trim] = heap->fixed_array_map();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000359 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000360
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000361 return FixedArray::cast(HeapObject::FromAddress(
362 elms->address() + to_trim * kPointerSize));
lrn@chromium.org25156de2010-04-06 13:10:27 +0000363}
364
365
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366static bool ArrayPrototypeHasNoElements(Heap* heap,
367 Context* global_context,
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000368 JSObject* array_proto) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000369 // This method depends on non writability of Object and Array prototype
370 // fields.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000371 if (array_proto->elements() != heap->empty_fixed_array()) return false;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000372 // Hidden prototype
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000373 array_proto = JSObject::cast(array_proto->GetPrototype());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000374 ASSERT(array_proto->elements() == heap->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000375 // Object.prototype
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000376 Object* proto = array_proto->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 if (proto == heap->null_value()) return false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000378 array_proto = JSObject::cast(proto);
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000379 if (array_proto != global_context->initial_object_prototype()) return false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000380 if (array_proto->elements() != heap->empty_fixed_array()) return false;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000381 return array_proto->GetPrototype()->IsNull();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000382}
383
384
lrn@chromium.org303ada72010-10-27 09:33:13 +0000385MUST_USE_RESULT
386static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000387 Heap* heap, Object* receiver) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000388 if (!receiver->IsJSArray()) return NULL;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000389 JSArray* array = JSArray::cast(receiver);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000390 HeapObject* elms = array->elements();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000391 if (elms->map() == heap->fixed_array_map()) return elms;
392 if (elms->map() == heap->fixed_cow_array_map()) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000393 return array->EnsureWritableFastElements();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000394 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000395 return NULL;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000396}
397
398
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
400 JSArray* receiver) {
401 Context* global_context = heap->isolate()->context()->global_context();
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000402 JSObject* array_proto =
403 JSObject::cast(global_context->array_function()->prototype());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000404 return receiver->GetPrototype() == array_proto &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 ArrayPrototypeHasNoElements(heap, global_context, array_proto);
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000406}
407
408
lrn@chromium.org303ada72010-10-27 09:33:13 +0000409MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000410 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000411 const char* name,
412 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 HandleScope handleScope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000414
415 Handle<Object> js_builtin =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 GetProperty(Handle<JSObject>(
417 isolate->global_context()->builtins()),
418 name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000419 ASSERT(js_builtin->IsJSFunction());
420 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000421 ScopedVector<Object**> argv(args.length() - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000422 int n_args = args.length() - 1;
423 for (int i = 0; i < n_args; i++) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000424 argv[i] = args.at<Object>(i + 1).location();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000425 }
426 bool pending_exception = false;
427 Handle<Object> result = Execution::Call(function,
428 args.receiver(),
429 n_args,
430 argv.start(),
431 &pending_exception);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000432 if (pending_exception) return Failure::Exception();
433 return *result;
434}
435
436
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000437BUILTIN(ArrayPush) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000438 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000439 Object* receiver = *args.receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000440 Object* elms_obj;
441 { MaybeObject* maybe_elms_obj =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000442 EnsureJSArrayWithWritableFastElements(heap, receiver);
443 if (maybe_elms_obj == NULL) {
444 return CallJsBuiltin(isolate, "ArrayPush", args);
445 }
lrn@chromium.org303ada72010-10-27 09:33:13 +0000446 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
447 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000448 FixedArray* elms = FixedArray::cast(elms_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000449 JSArray* array = JSArray::cast(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000451 int len = Smi::cast(array->length())->value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000452 int to_add = args.length() - 1;
453 if (to_add == 0) {
454 return Smi::FromInt(len);
455 }
456 // Currently fixed arrays cannot grow too big, so
457 // we should never hit this case.
458 ASSERT(to_add <= (Smi::kMaxValue - len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459
ager@chromium.org5c838252010-02-19 08:53:10 +0000460 int new_length = len + to_add;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461
ager@chromium.org5c838252010-02-19 08:53:10 +0000462 if (new_length > elms->length()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000463 // New backing storage is needed.
464 int capacity = new_length + (new_length >> 1) + 16;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000465 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000467 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
468 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000469 FixedArray* new_elms = FixedArray::cast(obj);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000470
471 AssertNoAllocation no_gc;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000472 if (len > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000473 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, len);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000474 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000475 FillWithHoles(heap, new_elms, new_length, capacity);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000476
ager@chromium.org5c838252010-02-19 08:53:10 +0000477 elms = new_elms;
478 array->set_elements(elms);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000479 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000480
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000481 // Add the provided values.
ager@chromium.org5c838252010-02-19 08:53:10 +0000482 AssertNoAllocation no_gc;
483 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
ager@chromium.org5c838252010-02-19 08:53:10 +0000484 for (int index = 0; index < to_add; index++) {
485 elms->set(index + len, args[index + 1], mode);
486 }
487
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000488 // Set the length.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000489 array->set_length(Smi::FromInt(new_length));
ager@chromium.org5c838252010-02-19 08:53:10 +0000490 return Smi::FromInt(new_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492
493
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000494BUILTIN(ArrayPop) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000495 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000496 Object* receiver = *args.receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000497 Object* elms_obj;
498 { MaybeObject* maybe_elms_obj =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000499 EnsureJSArrayWithWritableFastElements(heap, receiver);
500 if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000501 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
502 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000503 FixedArray* elms = FixedArray::cast(elms_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000504 JSArray* array = JSArray::cast(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505
506 int len = Smi::cast(array->length())->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000507 if (len == 0) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508
509 // Get top element
lrn@chromium.org303ada72010-10-27 09:33:13 +0000510 MaybeObject* top = elms->get(len - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000511
512 // Set the length.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000513 array->set_length(Smi::FromInt(len - 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000514
515 if (!top->IsTheHole()) {
516 // Delete the top element.
517 elms->set_the_hole(len - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518 return top;
519 }
520
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000521 top = array->GetPrototype()->GetElement(len - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522
523 return top;
524}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000525
526
ager@chromium.org5c838252010-02-19 08:53:10 +0000527BUILTIN(ArrayShift) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000529 Object* receiver = *args.receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000530 Object* elms_obj;
531 { MaybeObject* maybe_elms_obj =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000532 EnsureJSArrayWithWritableFastElements(heap, receiver);
533 if (maybe_elms_obj == NULL)
534 return CallJsBuiltin(isolate, "ArrayShift", args);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000535 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
536 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000537 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
538 return CallJsBuiltin(isolate, "ArrayShift", args);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000539 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000540 FixedArray* elms = FixedArray::cast(elms_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000541 JSArray* array = JSArray::cast(receiver);
ager@chromium.org5c838252010-02-19 08:53:10 +0000542 ASSERT(array->HasFastElements());
543
544 int len = Smi::cast(array->length())->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 if (len == 0) return heap->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000546
ager@chromium.org5c838252010-02-19 08:53:10 +0000547 // Get first element
548 Object* first = elms->get(0);
549 if (first->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000550 first = heap->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000551 }
552
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000553 if (!heap->lo_space()->Contains(elms)) {
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000554 // As elms still in the same space they used to be,
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000555 // there is no need to update region dirty mark.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 array->set_elements(LeftTrimFixedArray(heap, elms, 1), SKIP_WRITE_BARRIER);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000557 } else {
558 // Shift the elements.
559 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
561 elms->set(len - 1, heap->the_hole_value());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000562 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000563
564 // Set the length.
565 array->set_length(Smi::FromInt(len - 1));
566
567 return first;
568}
569
570
571BUILTIN(ArrayUnshift) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000573 Object* receiver = *args.receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000574 Object* elms_obj;
575 { MaybeObject* maybe_elms_obj =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 EnsureJSArrayWithWritableFastElements(heap, receiver);
577 if (maybe_elms_obj == NULL)
578 return CallJsBuiltin(isolate, "ArrayUnshift", args);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000579 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
580 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000581 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
582 return CallJsBuiltin(isolate, "ArrayUnshift", args);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000583 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000584 FixedArray* elms = FixedArray::cast(elms_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000585 JSArray* array = JSArray::cast(receiver);
ager@chromium.org5c838252010-02-19 08:53:10 +0000586 ASSERT(array->HasFastElements());
587
588 int len = Smi::cast(array->length())->value();
589 int to_add = args.length() - 1;
ager@chromium.org5c838252010-02-19 08:53:10 +0000590 int new_length = len + to_add;
591 // Currently fixed arrays cannot grow too big, so
592 // we should never hit this case.
593 ASSERT(to_add <= (Smi::kMaxValue - len));
594
ager@chromium.org5c838252010-02-19 08:53:10 +0000595 if (new_length > elms->length()) {
596 // New backing storage is needed.
597 int capacity = new_length + (new_length >> 1) + 16;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000598 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000600 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
601 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000602 FixedArray* new_elms = FixedArray::cast(obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000603
604 AssertNoAllocation no_gc;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000605 if (len > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000606 CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000607 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 FillWithHoles(heap, new_elms, new_length, capacity);
ager@chromium.org5c838252010-02-19 08:53:10 +0000609
610 elms = new_elms;
611 array->set_elements(elms);
612 } else {
613 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000615 }
616
617 // Add the provided values.
618 AssertNoAllocation no_gc;
619 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
620 for (int i = 0; i < to_add; i++) {
621 elms->set(i, args[i + 1], mode);
622 }
623
624 // Set the length.
625 array->set_length(Smi::FromInt(new_length));
626 return Smi::FromInt(new_length);
627}
628
629
ager@chromium.org5c838252010-02-19 08:53:10 +0000630BUILTIN(ArraySlice) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000632 Object* receiver = *args.receiver();
whesse@chromium.org023421e2010-12-21 12:19:12 +0000633 FixedArray* elms;
634 int len = -1;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000635 if (receiver->IsJSArray()) {
636 JSArray* array = JSArray::cast(receiver);
637 if (!array->HasFastElements() ||
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 !IsJSArrayFastElementMovingAllowed(heap, array)) {
639 return CallJsBuiltin(isolate, "ArraySlice", args);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000640 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000641
642 elms = FixedArray::cast(array->elements());
643 len = Smi::cast(array->length())->value();
644 } else {
645 // Array.slice(arguments, ...) is quite a common idiom (notably more
646 // than 50% of invocations in Web apps). Treat it in C++ as well.
647 Map* arguments_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000648 isolate->context()->global_context()->arguments_boilerplate()->map();
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000649
650 bool is_arguments_object_with_fast_elements =
651 receiver->IsJSObject()
652 && JSObject::cast(receiver)->map() == arguments_map
653 && JSObject::cast(receiver)->HasFastElements();
654 if (!is_arguments_object_with_fast_elements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000655 return CallJsBuiltin(isolate, "ArraySlice", args);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000656 }
657 elms = FixedArray::cast(JSObject::cast(receiver)->elements());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000658 Object* len_obj = JSObject::cast(receiver)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000659 ->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000660 if (!len_obj->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000661 return CallJsBuiltin(isolate, "ArraySlice", args);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000662 }
663 len = Smi::cast(len_obj)->value();
664 if (len > elms->length()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000665 return CallJsBuiltin(isolate, "ArraySlice", args);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +0000666 }
667 for (int i = 0; i < len; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000668 if (elms->get(i) == heap->the_hole_value()) {
669 return CallJsBuiltin(isolate, "ArraySlice", args);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +0000670 }
671 }
whesse@chromium.org023421e2010-12-21 12:19:12 +0000672 }
673 ASSERT(len >= 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000674 int n_arguments = args.length() - 1;
675
676 // Note carefully choosen defaults---if argument is missing,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000677 // it's undefined which gets converted to 0 for relative_start
678 // and to len for relative_end.
679 int relative_start = 0;
680 int relative_end = len;
ager@chromium.org5c838252010-02-19 08:53:10 +0000681 if (n_arguments > 0) {
682 Object* arg1 = args[1];
683 if (arg1->IsSmi()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000684 relative_start = Smi::cast(arg1)->value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000685 } else if (!arg1->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000686 return CallJsBuiltin(isolate, "ArraySlice", args);
ager@chromium.org5c838252010-02-19 08:53:10 +0000687 }
688 if (n_arguments > 1) {
689 Object* arg2 = args[2];
690 if (arg2->IsSmi()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000691 relative_end = Smi::cast(arg2)->value();
ager@chromium.org5c838252010-02-19 08:53:10 +0000692 } else if (!arg2->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000693 return CallJsBuiltin(isolate, "ArraySlice", args);
ager@chromium.org5c838252010-02-19 08:53:10 +0000694 }
695 }
696 }
697
698 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000699 int k = (relative_start < 0) ? Max(len + relative_start, 0)
700 : Min(relative_start, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000701
702 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000703 int final = (relative_end < 0) ? Max(len + relative_end, 0)
704 : Min(relative_end, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000705
706 // Calculate the length of result array.
707 int result_len = final - k;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000708 if (result_len <= 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000709 return AllocateEmptyJSArray(heap);
ager@chromium.org5c838252010-02-19 08:53:10 +0000710 }
711
lrn@chromium.org303ada72010-10-27 09:33:13 +0000712 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000713 { MaybeObject* maybe_result = AllocateJSArray(heap);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000714 if (!maybe_result->ToObject(&result)) return maybe_result;
715 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000716 JSArray* result_array = JSArray::cast(result);
717
lrn@chromium.org303ada72010-10-27 09:33:13 +0000718 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000719 heap->AllocateUninitializedFixedArray(result_len);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000720 if (!maybe_result->ToObject(&result)) return maybe_result;
721 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000722 FixedArray* result_elms = FixedArray::cast(result);
723
ager@chromium.org5c838252010-02-19 08:53:10 +0000724 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000725 CopyElements(heap, &no_gc, result_elms, 0, elms, k, result_len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000726
727 // Set elements.
728 result_array->set_elements(result_elms);
729
730 // Set the length.
731 result_array->set_length(Smi::FromInt(result_len));
732 return result_array;
733}
734
735
736BUILTIN(ArraySplice) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000737 Heap* heap = isolate->heap();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000738 Object* receiver = *args.receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000739 Object* elms_obj;
740 { MaybeObject* maybe_elms_obj =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000741 EnsureJSArrayWithWritableFastElements(heap, receiver);
742 if (maybe_elms_obj == NULL)
743 return CallJsBuiltin(isolate, "ArraySplice", args);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000744 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
745 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000746 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
747 return CallJsBuiltin(isolate, "ArraySplice", args);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000748 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000749 FixedArray* elms = FixedArray::cast(elms_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000750 JSArray* array = JSArray::cast(receiver);
ager@chromium.org5c838252010-02-19 08:53:10 +0000751 ASSERT(array->HasFastElements());
752
753 int len = Smi::cast(array->length())->value();
754
755 int n_arguments = args.length() - 1;
756
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000757 int relative_start = 0;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000758 if (n_arguments > 0) {
759 Object* arg1 = args[1];
760 if (arg1->IsSmi()) {
761 relative_start = Smi::cast(arg1)->value();
762 } else if (!arg1->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000763 return CallJsBuiltin(isolate, "ArraySplice", args);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000764 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000765 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000766 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
767 : Min(relative_start, len);
ager@chromium.org5c838252010-02-19 08:53:10 +0000768
769 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000770 // given as a request to delete all the elements from the start.
771 // And it differs from the case of undefined delete count.
ager@chromium.org5c838252010-02-19 08:53:10 +0000772 // This does not follow ECMA-262, but we do the same for
773 // compatibility.
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000774 int actual_delete_count;
775 if (n_arguments == 1) {
776 ASSERT(len - actual_start >= 0);
777 actual_delete_count = len - actual_start;
778 } else {
779 int value = 0; // ToInteger(undefined) == 0
780 if (n_arguments > 1) {
781 Object* arg2 = args[2];
782 if (arg2->IsSmi()) {
783 value = Smi::cast(arg2)->value();
784 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000785 return CallJsBuiltin(isolate, "ArraySplice", args);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000786 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000787 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +0000788 actual_delete_count = Min(Max(value, 0), len - actual_start);
ager@chromium.org5c838252010-02-19 08:53:10 +0000789 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000790
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000791 JSArray* result_array = NULL;
792 if (actual_delete_count == 0) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000793 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000794 { MaybeObject* maybe_result = AllocateEmptyJSArray(heap);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000795 if (!maybe_result->ToObject(&result)) return maybe_result;
796 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000797 result_array = JSArray::cast(result);
798 } else {
799 // Allocate result array.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000800 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000801 { MaybeObject* maybe_result = AllocateJSArray(heap);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000802 if (!maybe_result->ToObject(&result)) return maybe_result;
803 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000804 result_array = JSArray::cast(result);
ager@chromium.org5c838252010-02-19 08:53:10 +0000805
lrn@chromium.org303ada72010-10-27 09:33:13 +0000806 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000807 heap->AllocateUninitializedFixedArray(actual_delete_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000808 if (!maybe_result->ToObject(&result)) return maybe_result;
809 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000810 FixedArray* result_elms = FixedArray::cast(result);
ager@chromium.org5c838252010-02-19 08:53:10 +0000811
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000812 AssertNoAllocation no_gc;
813 // Fill newly created array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000814 CopyElements(heap,
815 &no_gc,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000816 result_elms, 0,
817 elms, actual_start,
818 actual_delete_count);
819
820 // Set elements.
821 result_array->set_elements(result_elms);
822
823 // Set the length.
824 result_array->set_length(Smi::FromInt(actual_delete_count));
ager@chromium.org5c838252010-02-19 08:53:10 +0000825 }
826
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000827 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
ager@chromium.org5c838252010-02-19 08:53:10 +0000828
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000829 int new_length = len - actual_delete_count + item_count;
ager@chromium.org5c838252010-02-19 08:53:10 +0000830
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000831 if (item_count < actual_delete_count) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000832 // Shrink the array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000833 const bool trim_array = !heap->lo_space()->Contains(elms) &&
lrn@chromium.org25156de2010-04-06 13:10:27 +0000834 ((actual_start + item_count) <
835 (len - actual_delete_count - actual_start));
836 if (trim_array) {
837 const int delta = actual_delete_count - item_count;
838
839 if (actual_start > 0) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000840 AssertNoAllocation no_gc;
841 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000842 }
843
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 elms = LeftTrimFixedArray(heap, elms, delta);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000845 array->set_elements(elms, SKIP_WRITE_BARRIER);
846 } else {
847 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000848 MoveElements(heap, &no_gc,
lrn@chromium.org25156de2010-04-06 13:10:27 +0000849 elms, actual_start + item_count,
850 elms, actual_start + actual_delete_count,
851 (len - actual_delete_count - actual_start));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000852 FillWithHoles(heap, elms, new_length, len);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000853 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000854 } else if (item_count > actual_delete_count) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000855 // Currently fixed arrays cannot grow too big, so
856 // we should never hit this case.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000857 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
ager@chromium.org5c838252010-02-19 08:53:10 +0000858
859 // Check if array need to grow.
860 if (new_length > elms->length()) {
861 // New backing storage is needed.
862 int capacity = new_length + (new_length >> 1) + 16;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000863 Object* obj;
864 { MaybeObject* maybe_obj =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 heap->AllocateUninitializedFixedArray(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000866 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
867 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000868 FixedArray* new_elms = FixedArray::cast(obj);
ager@chromium.org5c838252010-02-19 08:53:10 +0000869
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000870 AssertNoAllocation no_gc;
871 // Copy the part before actual_start as is.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000872 if (actual_start > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000873 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, actual_start);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000874 }
875 const int to_copy = len - actual_delete_count - actual_start;
876 if (to_copy > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000877 CopyElements(heap, &no_gc,
lrn@chromium.org25156de2010-04-06 13:10:27 +0000878 new_elms, actual_start + item_count,
879 elms, actual_start + actual_delete_count,
880 to_copy);
881 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000882 FillWithHoles(heap, new_elms, new_length, capacity);
ager@chromium.org5c838252010-02-19 08:53:10 +0000883
ager@chromium.org5c838252010-02-19 08:53:10 +0000884 elms = new_elms;
885 array->set_elements(elms);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000886 } else {
887 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000888 MoveElements(heap, &no_gc,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000889 elms, actual_start + item_count,
890 elms, actual_start + actual_delete_count,
891 (len - actual_delete_count - actual_start));
ager@chromium.org5c838252010-02-19 08:53:10 +0000892 }
893 }
894
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000895 AssertNoAllocation no_gc;
896 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
897 for (int k = actual_start; k < actual_start + item_count; k++) {
898 elms->set(k, args[3 + k - actual_start], mode);
ager@chromium.org5c838252010-02-19 08:53:10 +0000899 }
900
901 // Set the length.
902 array->set_length(Smi::FromInt(new_length));
903
904 return result_array;
905}
906
907
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000908BUILTIN(ArrayConcat) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 Heap* heap = isolate->heap();
910 Context* global_context = isolate->context()->global_context();
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000911 JSObject* array_proto =
912 JSObject::cast(global_context->array_function()->prototype());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 if (!ArrayPrototypeHasNoElements(heap, global_context, array_proto)) {
914 return CallJsBuiltin(isolate, "ArrayConcat", args);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000915 }
916
917 // Iterate through all the arguments performing checks
918 // and calculating total length.
919 int n_arguments = args.length();
920 int result_len = 0;
921 for (int i = 0; i < n_arguments; i++) {
922 Object* arg = args[i];
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000923 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
924 || JSArray::cast(arg)->GetPrototype() != array_proto) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 return CallJsBuiltin(isolate, "ArrayConcat", args);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000926 }
927
928 int len = Smi::cast(JSArray::cast(arg)->length())->value();
929
930 // We shouldn't overflow when adding another len.
931 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
932 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
933 USE(kHalfOfMaxInt);
934 result_len += len;
935 ASSERT(result_len >= 0);
936
937 if (result_len > FixedArray::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000938 return CallJsBuiltin(isolate, "ArrayConcat", args);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000939 }
940 }
941
942 if (result_len == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000943 return AllocateEmptyJSArray(heap);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000944 }
945
946 // Allocate result.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000947 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000948 { MaybeObject* maybe_result = AllocateJSArray(heap);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000949 if (!maybe_result->ToObject(&result)) return maybe_result;
950 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000951 JSArray* result_array = JSArray::cast(result);
952
lrn@chromium.org303ada72010-10-27 09:33:13 +0000953 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000954 heap->AllocateUninitializedFixedArray(result_len);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000955 if (!maybe_result->ToObject(&result)) return maybe_result;
956 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000957 FixedArray* result_elms = FixedArray::cast(result);
958
959 // Copy data.
960 AssertNoAllocation no_gc;
961 int start_pos = 0;
962 for (int i = 0; i < n_arguments; i++) {
963 JSArray* array = JSArray::cast(args[i]);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000964 int len = Smi::cast(array->length())->value();
lrn@chromium.org25156de2010-04-06 13:10:27 +0000965 if (len > 0) {
966 FixedArray* elms = FixedArray::cast(array->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000967 CopyElements(heap, &no_gc, result_elms, start_pos, elms, 0, len);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000968 start_pos += len;
969 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000970 }
971 ASSERT(start_pos == result_len);
972
973 // Set the length and elements.
974 result_array->set_length(Smi::FromInt(result_len));
975 result_array->set_elements(result_elms);
976
977 return result_array;
978}
979
980
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981// -----------------------------------------------------------------------------
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000982// Strict mode poison pills
983
984
danno@chromium.org40cb8782011-05-25 07:58:50 +0000985BUILTIN(StrictModePoisonPill) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000986 HandleScope scope;
987 return isolate->Throw(*isolate->factory()->NewTypeError(
danno@chromium.org40cb8782011-05-25 07:58:50 +0000988 "strict_poison_pill", HandleVector<Object>(NULL, 0)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000989}
990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991// -----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992//
993
994
995// Returns the holder JSObject if the function can legally be called
996// with this receiver. Returns Heap::null_value() if the call is
997// illegal. Any arguments that don't fit the expected type is
998// overwritten with undefined. Arguments that do fit the expected
999// type is overwritten with the object in the prototype chain that
1000// actually has that type.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001001static inline Object* TypeCheck(Heap* heap,
1002 int argc,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 Object** argv,
1004 FunctionTemplateInfo* info) {
1005 Object* recv = argv[0];
lrn@chromium.org1c092762011-05-09 09:42:16 +00001006 // API calls are only supported with JSObject receivers.
1007 if (!recv->IsJSObject()) return heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008 Object* sig_obj = info->signature();
1009 if (sig_obj->IsUndefined()) return recv;
1010 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
1011 // If necessary, check the receiver
1012 Object* recv_type = sig->receiver();
1013
1014 Object* holder = recv;
1015 if (!recv_type->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001016 for (; holder != heap->null_value(); holder = holder->GetPrototype()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
1018 break;
1019 }
1020 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001021 if (holder == heap->null_value()) return holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022 }
1023 Object* args_obj = sig->args();
1024 // If there is no argument signature we're done
1025 if (args_obj->IsUndefined()) return holder;
1026 FixedArray* args = FixedArray::cast(args_obj);
1027 int length = args->length();
mads.s.ager31e71382008-08-13 09:32:07 +00001028 if (argc <= length) length = argc - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029 for (int i = 0; i < length; i++) {
1030 Object* argtype = args->get(i);
1031 if (argtype->IsUndefined()) continue;
1032 Object** arg = &argv[-1 - i];
1033 Object* current = *arg;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001034 for (; current != heap->null_value(); current = current->GetPrototype()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001035 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
1036 *arg = current;
1037 break;
1038 }
1039 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001040 if (current == heap->null_value()) *arg = heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041 }
1042 return holder;
1043}
1044
1045
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001046template <bool is_construct>
lrn@chromium.org303ada72010-10-27 09:33:13 +00001047MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001048 BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
1049 ASSERT(is_construct == CalledAsConstructor(isolate));
1050 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001053 Handle<JSFunction> function = args.called_function();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001054 ASSERT(function->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001055
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001056 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 if (is_construct) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001058 Handle<FunctionTemplateInfo> desc(fun_data, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059 bool pending_exception = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 isolate->factory()->ConfigureInstance(
1061 desc, Handle<JSObject>::cast(args.receiver()), &pending_exception);
1062 ASSERT(isolate->has_pending_exception() == pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063 if (pending_exception) return Failure::Exception();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001064 fun_data = *desc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065 }
1066
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 Object* raw_holder = TypeCheck(heap, args.length(), &args[0], fun_data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068
1069 if (raw_holder->IsNull()) {
1070 // This function cannot be called with the given receiver. Abort!
1071 Handle<Object> obj =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 isolate->factory()->NewTypeError(
1073 "illegal_invocation", HandleVector(&function, 1));
1074 return isolate->Throw(*obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 }
1076
1077 Object* raw_call_data = fun_data->call_code();
1078 if (!raw_call_data->IsUndefined()) {
1079 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1080 Object* callback_obj = call_data->callback();
1081 v8::InvocationCallback callback =
1082 v8::ToCData<v8::InvocationCallback>(callback_obj);
1083 Object* data_obj = call_data->data();
1084 Object* result;
1085
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001086 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001087 ASSERT(raw_holder->IsJSObject());
1088
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 CustomArguments custom(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001090 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1091 data_obj, *function, raw_holder);
1092
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001093 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001094 custom.end(),
1095 &args[0] - 1,
1096 args.length() - 1,
1097 is_construct);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098
1099 v8::Handle<v8::Value> value;
1100 {
1101 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 VMState state(isolate, EXTERNAL);
1103 ExternalCallbackScope call_scope(isolate,
1104 v8::ToCData<Address>(callback_obj));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001105 value = callback(new_args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106 }
1107 if (value.IsEmpty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001108 result = heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001109 } else {
1110 result = *reinterpret_cast<Object**>(*value);
1111 }
1112
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001114 if (!is_construct || result->IsJSObject()) return result;
1115 }
1116
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001117 return *args.receiver();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001118}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001119
1120
1121BUILTIN(HandleApiCall) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001122 return HandleApiCallHelper<false>(args, isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001123}
1124
1125
1126BUILTIN(HandleApiCallConstruct) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001127 return HandleApiCallHelper<true>(args, isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001128}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129
1130
ager@chromium.org5c838252010-02-19 08:53:10 +00001131#ifdef DEBUG
1132
1133static void VerifyTypeCheck(Handle<JSObject> object,
1134 Handle<JSFunction> function) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001135 ASSERT(function->shared()->IsApiFunction());
1136 FunctionTemplateInfo* info = function->shared()->get_api_func_data();
ager@chromium.org5c838252010-02-19 08:53:10 +00001137 if (info->signature()->IsUndefined()) return;
1138 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1139 Object* receiver_type = signature->receiver();
1140 if (receiver_type->IsUndefined()) return;
1141 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
1142 ASSERT(object->IsInstanceOf(type));
1143}
1144
1145#endif
1146
1147
1148BUILTIN(FastHandleApiCall) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001149 ASSERT(!CalledAsConstructor(isolate));
1150 Heap* heap = isolate->heap();
ager@chromium.org5c838252010-02-19 08:53:10 +00001151 const bool is_construct = false;
1152
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001153 // We expect four more arguments: callback, function, call data, and holder.
ager@chromium.org5c838252010-02-19 08:53:10 +00001154 const int args_length = args.length() - 4;
1155 ASSERT(args_length >= 0);
1156
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001157 Object* callback_obj = args[args_length];
ager@chromium.org5c838252010-02-19 08:53:10 +00001158
1159 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001160 &args[args_length + 1],
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001161 &args[0] - 1,
1162 args_length - 1,
1163 is_construct);
ager@chromium.org5c838252010-02-19 08:53:10 +00001164
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001165#ifdef DEBUG
1166 VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()),
1167 Utils::OpenHandle(*new_args.Callee()));
1168#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001169 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00001170 Object* result;
1171 v8::Handle<v8::Value> value;
1172 {
1173 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001174 VMState state(isolate, EXTERNAL);
1175 ExternalCallbackScope call_scope(isolate,
1176 v8::ToCData<Address>(callback_obj));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001177 v8::InvocationCallback callback =
1178 v8::ToCData<v8::InvocationCallback>(callback_obj);
1179
ager@chromium.org5c838252010-02-19 08:53:10 +00001180 value = callback(new_args);
1181 }
1182 if (value.IsEmpty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001183 result = heap->undefined_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00001184 } else {
1185 result = *reinterpret_cast<Object**>(*value);
1186 }
1187
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001188 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00001189 return result;
1190}
1191
1192
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001193// Helper function to handle calls to non-function objects created through the
1194// API. The object can be called as either a constructor (using new) or just as
1195// a function (without new).
lrn@chromium.org303ada72010-10-27 09:33:13 +00001196MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001197 Isolate* isolate,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001198 bool is_construct_call,
1199 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001200 // Non-functions are never called as constructors. Even if this is an object
1201 // called as a constructor the delegate call is not a construct call.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001202 ASSERT(!CalledAsConstructor(isolate));
1203 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001205 Handle<Object> receiver = args.receiver();
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001206
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001207 // Get the object called.
rossberg@chromium.org717967f2011-07-20 13:44:42 +00001208 JSObject* obj = JSObject::cast(*receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209
1210 // Get the invocation callback from the function descriptor that was
1211 // used to create the called object.
1212 ASSERT(obj->map()->has_instance_call_handler());
1213 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001214 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 Object* handler =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001216 constructor->shared()->get_api_func_data()->instance_call_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001217 ASSERT(!handler->IsUndefined());
1218 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1219 Object* callback_obj = call_data->callback();
1220 v8::InvocationCallback callback =
1221 v8::ToCData<v8::InvocationCallback>(callback_obj);
1222
1223 // Get the data for the call and perform the callback.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001224 Object* result;
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001225 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001226 HandleScope scope(isolate);
1227 LOG(isolate, ApiObjectAccess("call non-function", obj));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001229 CustomArguments custom(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001230 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1231 call_data->data(), constructor, obj);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001232 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001233 custom.end(),
1234 &args[0] - 1,
1235 args.length() - 1,
1236 is_construct_call);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 v8::Handle<v8::Value> value;
1238 {
1239 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001240 VMState state(isolate, EXTERNAL);
1241 ExternalCallbackScope call_scope(isolate,
1242 v8::ToCData<Address>(callback_obj));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001243 value = callback(new_args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 }
1245 if (value.IsEmpty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001246 result = heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247 } else {
1248 result = *reinterpret_cast<Object**>(*value);
1249 }
1250 }
1251 // Check for exceptions and return result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001252 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253 return result;
1254}
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001255
1256
1257// Handle calls to non-function objects created through the API. This delegate
1258// function is used when the call is a normal function call.
1259BUILTIN(HandleApiCallAsFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001260 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001261}
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001262
1263
1264// Handle calls to non-function objects created through the API. This delegate
1265// function is used when the call is a construct call.
1266BUILTIN(HandleApiCallAsConstructor) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00001268}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269
1270
1271static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1272 LoadIC::GenerateArrayLength(masm);
1273}
1274
1275
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001276static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001277 LoadIC::GenerateStringLength(masm, false);
1278}
1279
1280
1281static void Generate_LoadIC_StringWrapperLength(MacroAssembler* masm) {
1282 LoadIC::GenerateStringLength(masm, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283}
1284
1285
1286static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1287 LoadIC::GenerateFunctionPrototype(masm);
1288}
1289
1290
1291static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1292 LoadIC::GenerateInitialize(masm);
1293}
1294
1295
1296static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1297 LoadIC::GeneratePreMonomorphic(masm);
1298}
1299
1300
1301static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1302 LoadIC::GenerateMiss(masm);
1303}
1304
1305
1306static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1307 LoadIC::GenerateMegamorphic(masm);
1308}
1309
1310
1311static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1312 LoadIC::GenerateNormal(masm);
1313}
1314
1315
1316static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1317 KeyedLoadIC::GenerateInitialize(masm);
1318}
1319
1320
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001321static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
1322 KeyedLoadIC::GenerateRuntimeGetProperty(masm);
1323}
1324
1325
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001327 KeyedLoadIC::GenerateMiss(masm, false);
1328}
1329
1330
1331static void Generate_KeyedLoadIC_MissForceGeneric(MacroAssembler* masm) {
1332 KeyedLoadIC::GenerateMiss(masm, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333}
1334
1335
1336static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1337 KeyedLoadIC::GenerateGeneric(masm);
1338}
1339
1340
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001341static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1342 KeyedLoadIC::GenerateString(masm);
1343}
1344
1345
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1347 KeyedLoadIC::GeneratePreMonomorphic(masm);
1348}
1349
ager@chromium.org5c838252010-02-19 08:53:10 +00001350static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1351 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1352}
1353
whesse@chromium.org7b260152011-06-20 15:33:18 +00001354static void Generate_KeyedLoadIC_NonStrictArguments(MacroAssembler* masm) {
1355 KeyedLoadIC::GenerateNonStrictArguments(masm);
1356}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357
1358static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1359 StoreIC::GenerateInitialize(masm);
1360}
1361
1362
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001363static void Generate_StoreIC_Initialize_Strict(MacroAssembler* masm) {
1364 StoreIC::GenerateInitialize(masm);
1365}
1366
1367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1369 StoreIC::GenerateMiss(masm);
1370}
1371
1372
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001373static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1374 StoreIC::GenerateNormal(masm);
1375}
1376
1377
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001378static void Generate_StoreIC_Normal_Strict(MacroAssembler* masm) {
1379 StoreIC::GenerateNormal(masm);
1380}
1381
1382
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001383static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001384 StoreIC::GenerateMegamorphic(masm, kNonStrictMode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001385}
1386
1387
1388static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001389 StoreIC::GenerateMegamorphic(masm, kStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390}
1391
1392
ager@chromium.org5c838252010-02-19 08:53:10 +00001393static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1394 StoreIC::GenerateArrayLength(masm);
1395}
1396
1397
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001398static void Generate_StoreIC_ArrayLength_Strict(MacroAssembler* masm) {
1399 StoreIC::GenerateArrayLength(masm);
1400}
1401
1402
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001403static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001404 StoreIC::GenerateGlobalProxy(masm, kNonStrictMode);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001405}
1406
1407
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001408static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001409 StoreIC::GenerateGlobalProxy(masm, kStrictMode);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001410}
1411
1412
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001414 KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode);
1415}
1416
1417
1418static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) {
1419 KeyedStoreIC::GenerateGeneric(masm, kStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420}
1421
1422
1423static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001424 KeyedStoreIC::GenerateMiss(masm, false);
1425}
1426
1427
1428static void Generate_KeyedStoreIC_MissForceGeneric(MacroAssembler* masm) {
1429 KeyedStoreIC::GenerateMiss(masm, true);
1430}
1431
1432
1433static void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) {
1434 KeyedStoreIC::GenerateSlow(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435}
1436
1437
1438static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1439 KeyedStoreIC::GenerateInitialize(masm);
1440}
1441
1442
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001443static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
1444 KeyedStoreIC::GenerateInitialize(masm);
1445}
1446
whesse@chromium.org7b260152011-06-20 15:33:18 +00001447static void Generate_KeyedStoreIC_NonStrictArguments(MacroAssembler* masm) {
1448 KeyedStoreIC::GenerateNonStrictArguments(masm);
1449}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001450
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001451#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org8bb60582008-12-11 12:02:20 +00001452static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1453 Debug::GenerateLoadICDebugBreak(masm);
1454}
1455
1456
1457static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1458 Debug::GenerateStoreICDebugBreak(masm);
1459}
1460
1461
1462static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1463 Debug::GenerateKeyedLoadICDebugBreak(masm);
1464}
1465
1466
1467static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1468 Debug::GenerateKeyedStoreICDebugBreak(masm);
1469}
1470
1471
1472static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1473 Debug::GenerateConstructCallDebugBreak(masm);
1474}
1475
1476
1477static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1478 Debug::GenerateReturnDebugBreak(masm);
1479}
1480
1481
ager@chromium.org8bb60582008-12-11 12:02:20 +00001482static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
1483 Debug::GenerateStubNoRegistersDebugBreak(masm);
1484}
ager@chromium.org357bf652010-04-12 11:30:10 +00001485
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001486
1487static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1488 Debug::GenerateSlotDebugBreak(masm);
1489}
1490
1491
ager@chromium.org357bf652010-04-12 11:30:10 +00001492static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1493 Debug::GeneratePlainReturnLiveEdit(masm);
1494}
1495
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001496
ager@chromium.org357bf652010-04-12 11:30:10 +00001497static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1498 Debug::GenerateFrameDropperLiveEdit(masm);
1499}
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001500#endif
ager@chromium.org8bb60582008-12-11 12:02:20 +00001501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001502
1503Builtins::Builtins() : initialized_(false) {
1504 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
1505 memset(names_, 0, sizeof(names_[0]) * builtin_count);
1506}
1507
1508
1509Builtins::~Builtins() {
1510}
1511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001512
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001513#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001514Address const Builtins::c_functions_[cfunction_count] = {
1515 BUILTIN_LIST_C(DEF_ENUM_C)
1516};
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517#undef DEF_ENUM_C
1518
1519#define DEF_JS_NAME(name, ignore) #name,
1520#define DEF_JS_ARGC(ignore, argc) argc,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001521const char* const Builtins::javascript_names_[id_count] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001522 BUILTINS_LIST_JS(DEF_JS_NAME)
1523};
1524
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001525int const Builtins::javascript_argc_[id_count] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526 BUILTINS_LIST_JS(DEF_JS_ARGC)
1527};
1528#undef DEF_JS_NAME
1529#undef DEF_JS_ARGC
1530
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001531struct BuiltinDesc {
1532 byte* generator;
1533 byte* c_code;
1534 const char* s_name; // name is only used for generating log information.
1535 int name;
1536 Code::Flags flags;
1537 BuiltinExtraArguments extra_args;
1538};
1539
1540class BuiltinFunctionTable {
1541 public:
1542 BuiltinFunctionTable() {
1543 Builtins::InitBuiltinFunctionTable();
1544 }
1545
1546 static const BuiltinDesc* functions() { return functions_; }
1547
1548 private:
1549 static BuiltinDesc functions_[Builtins::builtin_count + 1];
1550
1551 friend class Builtins;
1552};
1553
1554BuiltinDesc BuiltinFunctionTable::functions_[Builtins::builtin_count + 1];
1555
1556static const BuiltinFunctionTable builtin_function_table_init;
1557
1558// Define array of pointers to generators and C builtin functions.
1559// We do this in a sort of roundabout way so that we can do the initialization
1560// within the lexical scope of Builtins:: and within a context where
1561// Code::Flags names a non-abstract type.
1562void Builtins::InitBuiltinFunctionTable() {
1563 BuiltinDesc* functions = BuiltinFunctionTable::functions_;
1564 functions[builtin_count].generator = NULL;
1565 functions[builtin_count].c_code = NULL;
1566 functions[builtin_count].s_name = NULL;
1567 functions[builtin_count].name = builtin_count;
1568 functions[builtin_count].flags = static_cast<Code::Flags>(0);
1569 functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
1570
1571#define DEF_FUNCTION_PTR_C(aname, aextra_args) \
1572 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
1573 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
1574 functions->s_name = #aname; \
1575 functions->name = c_##aname; \
1576 functions->flags = Code::ComputeFlags(Code::BUILTIN); \
1577 functions->extra_args = aextra_args; \
1578 ++functions;
1579
1580#define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
1581 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1582 functions->c_code = NULL; \
1583 functions->s_name = #aname; \
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001584 functions->name = k##aname; \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001585 functions->flags = Code::ComputeFlags(Code::kind, \
1586 NOT_IN_LOOP, \
1587 state, \
1588 extra); \
1589 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1590 ++functions;
1591
1592 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1593 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1594 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1595
1596#undef DEF_FUNCTION_PTR_C
1597#undef DEF_FUNCTION_PTR_A
1598}
1599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600void Builtins::Setup(bool create_heap_objects) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001601 ASSERT(!initialized_);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001602 Isolate* isolate = Isolate::Current();
1603 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604
1605 // Create a scope for the handles in the builtins.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001606 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001608 const BuiltinDesc* functions = BuiltinFunctionTable::functions();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001609
1610 // For now we generate builtin adaptor code into a stack-allocated
v8.team.kasperl727e9952008-09-02 14:56:44 +00001611 // buffer, before copying it into individual code objects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612 byte buffer[4*KB];
1613
1614 // Traverse the list of builtins and generate an adaptor in a
1615 // separate code object for each one.
1616 for (int i = 0; i < builtin_count; i++) {
1617 if (create_heap_objects) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001618 MacroAssembler masm(isolate, buffer, sizeof buffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619 // Generate the code/adaptor.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001620 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1622 // We pass all arguments to the generator, but it may not use all of
1623 // them. This works because the first arguments are on top of the
1624 // stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001625 g(&masm, functions[i].name, functions[i].extra_args);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 // Move the code into the object heap.
1627 CodeDesc desc;
1628 masm.GetCode(&desc);
1629 Code::Flags flags = functions[i].flags;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001630 Object* code = NULL;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001631 {
1632 // During startup it's OK to always allocate and defer GC to later.
1633 // This simplifies things because we don't need to retry.
1634 AlwaysAllocateScope __scope__;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001635 { MaybeObject* maybe_code =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001636 heap->CreateCode(desc, flags, masm.CodeObject());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001637 if (!maybe_code->ToObject(&code)) {
1638 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1639 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001641 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001642 // Log the event and add the code to the builtins array.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001643 PROFILE(isolate,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001644 CodeCreateEvent(Logger::BUILTIN_TAG,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +00001645 Code::cast(code),
1646 functions[i].s_name));
1647 GDBJIT(AddCode(GDBJITInterface::BUILTIN,
1648 functions[i].s_name,
1649 Code::cast(code)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001650 builtins_[i] = code;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001651#ifdef ENABLE_DISASSEMBLER
mads.s.ager31e71382008-08-13 09:32:07 +00001652 if (FLAG_print_builtin_code) {
1653 PrintF("Builtin: %s\n", functions[i].s_name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001654 Code::cast(code)->Disassemble(functions[i].s_name);
mads.s.ager31e71382008-08-13 09:32:07 +00001655 PrintF("\n");
1656 }
1657#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001658 } else {
1659 // Deserializing. The values will be filled in during IterateBuiltins.
1660 builtins_[i] = NULL;
1661 }
1662 names_[i] = functions[i].s_name;
1663 }
1664
1665 // Mark as initialized.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001666 initialized_ = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001667}
1668
1669
1670void Builtins::TearDown() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001671 initialized_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001672}
1673
1674
1675void Builtins::IterateBuiltins(ObjectVisitor* v) {
1676 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1677}
1678
1679
1680const char* Builtins::Lookup(byte* pc) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 // may be called during initialization (disassembler!)
1682 if (initialized_) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001683 for (int i = 0; i < builtin_count; i++) {
1684 Code* entry = Code::cast(builtins_[i]);
1685 if (entry->contains(pc)) {
1686 return names_[i];
1687 }
1688 }
1689 }
1690 return NULL;
1691}
1692
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001693
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001694#define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
1695Handle<Code> Builtins::name() { \
1696 Code** code_address = \
1697 reinterpret_cast<Code**>(builtin_address(k##name)); \
1698 return Handle<Code>(code_address); \
1699}
1700#define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
1701Handle<Code> Builtins::name() { \
1702 Code** code_address = \
1703 reinterpret_cast<Code**>(builtin_address(k##name)); \
1704 return Handle<Code>(code_address); \
1705}
1706BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1707BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1708BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1709#undef DEFINE_BUILTIN_ACCESSOR_C
1710#undef DEFINE_BUILTIN_ACCESSOR_A
1711
1712
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001713} } // namespace v8::internal