blob: ad52ea18b89fac1817f645c126eb581f54f2cc0e [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
33#include "builtins.h"
34#include "ic-inl.h"
35
36namespace v8 {
37namespace internal {
38
Leon Clarkee46be812010-01-19 14:06:41 +000039namespace {
40
41// Arguments object passed to C++ builtins.
42template <BuiltinExtraArguments extra_args>
43class BuiltinArguments : public Arguments {
44 public:
45 BuiltinArguments(int length, Object** arguments)
46 : Arguments(length, arguments) { }
47
48 Object*& operator[] (int index) {
49 ASSERT(index < length());
50 return Arguments::operator[](index);
51 }
52
53 template <class S> Handle<S> at(int index) {
54 ASSERT(index < length());
55 return Arguments::at<S>(index);
56 }
57
58 Handle<Object> receiver() {
59 return Arguments::at<Object>(0);
60 }
61
62 Handle<JSFunction> called_function() {
63 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
64 return Arguments::at<JSFunction>(Arguments::length() - 1);
65 }
66
67 // Gets the total number of arguments including the receiver (but
68 // excluding extra arguments).
69 int length() const {
70 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
71 return Arguments::length();
72 }
73
74#ifdef DEBUG
75 void Verify() {
76 // Check we have at least the receiver.
77 ASSERT(Arguments::length() >= 1);
78 }
79#endif
80};
81
82
83// Specialize BuiltinArguments for the called function extra argument.
84
85template <>
86int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
87 return Arguments::length() - 1;
88}
89
90#ifdef DEBUG
91template <>
92void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
93 // Check we have at least the receiver and the called function.
94 ASSERT(Arguments::length() >= 2);
95 // Make sure cast to JSFunction succeeds.
96 called_function();
97}
98#endif
99
100
101#define DEF_ARG_TYPE(name, spec) \
102 typedef BuiltinArguments<spec> name##ArgumentsType;
103BUILTIN_LIST_C(DEF_ARG_TYPE)
104#undef DEF_ARG_TYPE
105
106} // namespace
107
108
Steve Blocka7e24c12009-10-30 11:49:00 +0000109// ----------------------------------------------------------------------------
Leon Clarkee46be812010-01-19 14:06:41 +0000110// Support macro for defining builtins in C++.
Steve Blocka7e24c12009-10-30 11:49:00 +0000111// ----------------------------------------------------------------------------
112//
113// A builtin function is defined by writing:
114//
115// BUILTIN(name) {
116// ...
117// }
Steve Blocka7e24c12009-10-30 11:49:00 +0000118//
Leon Clarkee46be812010-01-19 14:06:41 +0000119// In the body of the builtin function the arguments can be accessed
120// through the BuiltinArguments object args.
Steve Blocka7e24c12009-10-30 11:49:00 +0000121
Leon Clarkee46be812010-01-19 14:06:41 +0000122#ifdef DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +0000123
Leon Clarkee46be812010-01-19 14:06:41 +0000124#define BUILTIN(name) \
125 static Object* Builtin_Impl_##name(name##ArgumentsType args); \
126 static Object* Builtin_##name(name##ArgumentsType args) { \
127 args.Verify(); \
128 return Builtin_Impl_##name(args); \
129 } \
130 static Object* Builtin_Impl_##name(name##ArgumentsType args)
Steve Blocka7e24c12009-10-30 11:49:00 +0000131
Leon Clarkee46be812010-01-19 14:06:41 +0000132#else // For release mode.
Steve Blocka7e24c12009-10-30 11:49:00 +0000133
Leon Clarkee46be812010-01-19 14:06:41 +0000134#define BUILTIN(name) \
135 static Object* Builtin_##name(name##ArgumentsType args)
136
137#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000138
139
140static inline bool CalledAsConstructor() {
141#ifdef DEBUG
142 // Calculate the result using a full stack frame iterator and check
143 // that the state of the stack is as we assume it to be in the
144 // code below.
145 StackFrameIterator it;
146 ASSERT(it.frame()->is_exit());
147 it.Advance();
148 StackFrame* frame = it.frame();
149 bool reference_result = frame->is_construct();
150#endif
151 Address fp = Top::c_entry_fp(Top::GetCurrentThread());
152 // Because we know fp points to an exit frame we can use the relevant
153 // part of ExitFrame::ComputeCallerState directly.
154 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
155 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
156 // This inlines the part of StackFrame::ComputeType that grabs the
157 // type of the current frame. Note that StackFrame::ComputeType
158 // has been specialized for each architecture so if any one of them
159 // changes this code has to be changed as well.
160 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
161 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
162 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
163 bool result = (marker == kConstructMarker);
164 ASSERT_EQ(result, reference_result);
165 return result;
166}
167
168// ----------------------------------------------------------------------------
169
170
Steve Blocka7e24c12009-10-30 11:49:00 +0000171BUILTIN(Illegal) {
172 UNREACHABLE();
Leon Clarkee46be812010-01-19 14:06:41 +0000173 return Heap::undefined_value(); // Make compiler happy.
Steve Blocka7e24c12009-10-30 11:49:00 +0000174}
Steve Blocka7e24c12009-10-30 11:49:00 +0000175
176
177BUILTIN(EmptyFunction) {
Leon Clarkee46be812010-01-19 14:06:41 +0000178 return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000179}
Steve Blocka7e24c12009-10-30 11:49:00 +0000180
181
182BUILTIN(ArrayCodeGeneric) {
183 Counters::array_function_runtime.Increment();
184
185 JSArray* array;
186 if (CalledAsConstructor()) {
Leon Clarkee46be812010-01-19 14:06:41 +0000187 array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000188 } else {
189 // Allocate the JS Array
190 JSFunction* constructor =
191 Top::context()->global_context()->array_function();
192 Object* obj = Heap::AllocateJSObject(constructor);
193 if (obj->IsFailure()) return obj;
194 array = JSArray::cast(obj);
195 }
196
197 // 'array' now contains the JSArray we should initialize.
Steve Block8defd9f2010-07-08 12:39:36 +0100198 ASSERT(array->HasFastElements());
Steve Blocka7e24c12009-10-30 11:49:00 +0000199
200 // Optimize the case where there is one argument and the argument is a
201 // small smi.
202 if (args.length() == 2) {
203 Object* obj = args[1];
204 if (obj->IsSmi()) {
205 int len = Smi::cast(obj)->value();
206 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
207 Object* obj = Heap::AllocateFixedArrayWithHoles(len);
208 if (obj->IsFailure()) return obj;
209 array->SetContent(FixedArray::cast(obj));
210 return array;
211 }
212 }
213 // Take the argument as the length.
214 obj = array->Initialize(0);
215 if (obj->IsFailure()) return obj;
216 return array->SetElementsLength(args[1]);
217 }
218
219 // Optimize the case where there are no parameters passed.
220 if (args.length() == 1) {
221 return array->Initialize(JSArray::kPreallocatedArrayElements);
222 }
223
224 // Take the arguments as elements.
225 int number_of_elements = args.length() - 1;
226 Smi* len = Smi::FromInt(number_of_elements);
227 Object* obj = Heap::AllocateFixedArrayWithHoles(len->value());
228 if (obj->IsFailure()) return obj;
Leon Clarke4515c472010-02-03 11:58:03 +0000229
230 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000231 FixedArray* elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000232 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 // Fill in the content
234 for (int index = 0; index < number_of_elements; index++) {
235 elms->set(index, args[index+1], mode);
236 }
237
238 // Set length and elements on the array.
239 array->set_elements(FixedArray::cast(obj));
Leon Clarke4515c472010-02-03 11:58:03 +0000240 array->set_length(len);
Steve Blocka7e24c12009-10-30 11:49:00 +0000241
242 return array;
243}
Steve Blocka7e24c12009-10-30 11:49:00 +0000244
245
Steve Block6ded16b2010-05-10 14:33:55 +0100246static Object* AllocateJSArray() {
247 JSFunction* array_function =
248 Top::context()->global_context()->array_function();
249 Object* result = Heap::AllocateJSObject(array_function);
250 if (result->IsFailure()) return result;
251 return result;
252}
253
254
255static Object* AllocateEmptyJSArray() {
256 Object* result = AllocateJSArray();
257 if (result->IsFailure()) return result;
258 JSArray* result_array = JSArray::cast(result);
259 result_array->set_length(Smi::FromInt(0));
260 result_array->set_elements(Heap::empty_fixed_array());
261 return result_array;
262}
263
264
265static void CopyElements(AssertNoAllocation* no_gc,
266 FixedArray* dst,
267 int dst_index,
268 FixedArray* src,
269 int src_index,
270 int len) {
271 ASSERT(dst != src); // Use MoveElements instead.
272 ASSERT(len > 0);
273 CopyWords(dst->data_start() + dst_index,
274 src->data_start() + src_index,
275 len);
276 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
277 if (mode == UPDATE_WRITE_BARRIER) {
278 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
279 }
280}
281
282
283static void MoveElements(AssertNoAllocation* no_gc,
284 FixedArray* dst,
285 int dst_index,
286 FixedArray* src,
287 int src_index,
288 int len) {
289 memmove(dst->data_start() + dst_index,
290 src->data_start() + src_index,
291 len * kPointerSize);
292 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
293 if (mode == UPDATE_WRITE_BARRIER) {
294 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
295 }
296}
297
298
299static void FillWithHoles(FixedArray* dst, int from, int to) {
300 MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from);
301}
302
303
304static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
305 // For now this trick is only applied to fixed arrays in new space.
306 // In large object space the object's start must coincide with chunk
307 // and thus the trick is just not applicable.
308 // In old space we do not use this trick to avoid dealing with
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100309 // region dirty marks.
Steve Block6ded16b2010-05-10 14:33:55 +0100310 ASSERT(Heap::new_space()->Contains(elms));
311
312 STATIC_ASSERT(FixedArray::kMapOffset == 0);
313 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
314 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
315
316 Object** former_start = HeapObject::RawField(elms, 0);
317
318 const int len = elms->length();
319
320 // Technically in new space this write might be omitted (except for
321 // debug mode which iterates through the heap), but to play safer
322 // we still do it.
323 Heap::CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
324
325 former_start[to_trim] = Heap::fixed_array_map();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100326 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
Steve Block6ded16b2010-05-10 14:33:55 +0100327
328 ASSERT_EQ(elms->address() + to_trim * kPointerSize,
329 (elms + to_trim * kPointerSize)->address());
330 return elms + to_trim * kPointerSize;
331}
332
333
Kristian Monsen25f61362010-05-21 11:50:48 +0100334static bool ArrayPrototypeHasNoElements(Context* global_context,
335 JSObject* array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100336 // This method depends on non writability of Object and Array prototype
337 // fields.
Kristian Monsen25f61362010-05-21 11:50:48 +0100338 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
Steve Block6ded16b2010-05-10 14:33:55 +0100339 // Hidden prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100340 array_proto = JSObject::cast(array_proto->GetPrototype());
341 ASSERT(array_proto->elements() == Heap::empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +0100342 // Object.prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100343 array_proto = JSObject::cast(array_proto->GetPrototype());
344 if (array_proto != global_context->initial_object_prototype()) return false;
345 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
346 ASSERT(array_proto->GetPrototype()->IsNull());
Steve Block6ded16b2010-05-10 14:33:55 +0100347 return true;
348}
349
350
351static bool IsJSArrayWithFastElements(Object* receiver,
352 FixedArray** elements) {
353 if (!receiver->IsJSArray()) {
354 return false;
355 }
356
357 JSArray* array = JSArray::cast(receiver);
358
359 HeapObject* elms = HeapObject::cast(array->elements());
360 if (elms->map() != Heap::fixed_array_map()) {
361 return false;
362 }
363
364 *elements = FixedArray::cast(elms);
365 return true;
366}
367
368
Kristian Monsen25f61362010-05-21 11:50:48 +0100369static bool IsFastElementMovingAllowed(Object* receiver,
370 FixedArray** elements) {
371 if (!IsJSArrayWithFastElements(receiver, elements)) return false;
372
373 Context* global_context = Top::context()->global_context();
374 JSObject* array_proto =
375 JSObject::cast(global_context->array_function()->prototype());
376 if (JSArray::cast(receiver)->GetPrototype() != array_proto) return false;
377 return ArrayPrototypeHasNoElements(global_context, array_proto);
378}
379
380
Steve Block6ded16b2010-05-10 14:33:55 +0100381static Object* CallJsBuiltin(const char* name,
382 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
383 HandleScope handleScope;
384
385 Handle<Object> js_builtin =
386 GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
387 name);
388 ASSERT(js_builtin->IsJSFunction());
389 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
Kristian Monsen25f61362010-05-21 11:50:48 +0100390 ScopedVector<Object**> argv(args.length() - 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100391 int n_args = args.length() - 1;
392 for (int i = 0; i < n_args; i++) {
393 argv[i] = args.at<Object>(i + 1).location();
394 }
395 bool pending_exception = false;
396 Handle<Object> result = Execution::Call(function,
397 args.receiver(),
398 n_args,
399 argv.start(),
400 &pending_exception);
Steve Block6ded16b2010-05-10 14:33:55 +0100401 if (pending_exception) return Failure::Exception();
402 return *result;
403}
404
405
Steve Blocka7e24c12009-10-30 11:49:00 +0000406BUILTIN(ArrayPush) {
Steve Block6ded16b2010-05-10 14:33:55 +0100407 Object* receiver = *args.receiver();
408 FixedArray* elms = NULL;
409 if (!IsJSArrayWithFastElements(receiver, &elms)) {
410 return CallJsBuiltin("ArrayPush", args);
411 }
412 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000413
Steve Blocka7e24c12009-10-30 11:49:00 +0000414 int len = Smi::cast(array->length())->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000415 int to_add = args.length() - 1;
416 if (to_add == 0) {
417 return Smi::FromInt(len);
418 }
419 // Currently fixed arrays cannot grow too big, so
420 // we should never hit this case.
421 ASSERT(to_add <= (Smi::kMaxValue - len));
Steve Blocka7e24c12009-10-30 11:49:00 +0000422
Andrei Popescu402d9372010-02-26 13:31:12 +0000423 int new_length = len + to_add;
Steve Blocka7e24c12009-10-30 11:49:00 +0000424
Andrei Popescu402d9372010-02-26 13:31:12 +0000425 if (new_length > elms->length()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000426 // New backing storage is needed.
427 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100428 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +0000429 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +0100430 FixedArray* new_elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000431
432 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100433 if (len > 0) {
434 CopyElements(&no_gc, new_elms, 0, elms, 0, len);
435 }
436 FillWithHoles(new_elms, new_length, capacity);
437
Andrei Popescu402d9372010-02-26 13:31:12 +0000438 elms = new_elms;
439 array->set_elements(elms);
Steve Blocka7e24c12009-10-30 11:49:00 +0000440 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000441
Steve Block6ded16b2010-05-10 14:33:55 +0100442 // Add the provided values.
Andrei Popescu402d9372010-02-26 13:31:12 +0000443 AssertNoAllocation no_gc;
444 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Andrei Popescu402d9372010-02-26 13:31:12 +0000445 for (int index = 0; index < to_add; index++) {
446 elms->set(index + len, args[index + 1], mode);
447 }
448
Steve Blocka7e24c12009-10-30 11:49:00 +0000449 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000450 array->set_length(Smi::FromInt(new_length));
Andrei Popescu402d9372010-02-26 13:31:12 +0000451 return Smi::FromInt(new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000452}
Steve Blocka7e24c12009-10-30 11:49:00 +0000453
454
455BUILTIN(ArrayPop) {
Steve Block6ded16b2010-05-10 14:33:55 +0100456 Object* receiver = *args.receiver();
457 FixedArray* elms = NULL;
458 if (!IsJSArrayWithFastElements(receiver, &elms)) {
459 return CallJsBuiltin("ArrayPop", args);
460 }
461 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000462
463 int len = Smi::cast(array->length())->value();
Steve Block6ded16b2010-05-10 14:33:55 +0100464 if (len == 0) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000465
466 // Get top element
Steve Blocka7e24c12009-10-30 11:49:00 +0000467 Object* top = elms->get(len - 1);
468
469 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000470 array->set_length(Smi::FromInt(len - 1));
Steve Blocka7e24c12009-10-30 11:49:00 +0000471
472 if (!top->IsTheHole()) {
473 // Delete the top element.
474 elms->set_the_hole(len - 1);
475 return top;
476 }
477
Kristian Monsen25f61362010-05-21 11:50:48 +0100478 top = array->GetPrototype()->GetElement(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000479
480 return top;
481}
Steve Blocka7e24c12009-10-30 11:49:00 +0000482
483
Andrei Popescu402d9372010-02-26 13:31:12 +0000484BUILTIN(ArrayShift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100485 Object* receiver = *args.receiver();
486 FixedArray* elms = NULL;
Kristian Monsen25f61362010-05-21 11:50:48 +0100487 if (!IsFastElementMovingAllowed(receiver, &elms)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100488 return CallJsBuiltin("ArrayShift", args);
489 }
490 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000491 ASSERT(array->HasFastElements());
492
493 int len = Smi::cast(array->length())->value();
494 if (len == 0) return Heap::undefined_value();
495
Andrei Popescu402d9372010-02-26 13:31:12 +0000496 // Get first element
497 Object* first = elms->get(0);
498 if (first->IsTheHole()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100499 first = Heap::undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000500 }
501
Steve Block6ded16b2010-05-10 14:33:55 +0100502 if (Heap::new_space()->Contains(elms)) {
503 // As elms still in the same space they used to be (new space),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100504 // there is no need to update region dirty mark.
Steve Block6ded16b2010-05-10 14:33:55 +0100505 array->set_elements(LeftTrimFixedArray(elms, 1), SKIP_WRITE_BARRIER);
506 } else {
507 // Shift the elements.
508 AssertNoAllocation no_gc;
509 MoveElements(&no_gc, elms, 0, elms, 1, len - 1);
510 elms->set(len - 1, Heap::the_hole_value());
Andrei Popescu402d9372010-02-26 13:31:12 +0000511 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000512
513 // Set the length.
514 array->set_length(Smi::FromInt(len - 1));
515
516 return first;
517}
518
519
520BUILTIN(ArrayUnshift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100521 Object* receiver = *args.receiver();
522 FixedArray* elms = NULL;
Kristian Monsen25f61362010-05-21 11:50:48 +0100523 if (!IsFastElementMovingAllowed(receiver, &elms)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100524 return CallJsBuiltin("ArrayUnshift", args);
525 }
526 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000527 ASSERT(array->HasFastElements());
528
529 int len = Smi::cast(array->length())->value();
530 int to_add = args.length() - 1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000531 int new_length = len + to_add;
532 // Currently fixed arrays cannot grow too big, so
533 // we should never hit this case.
534 ASSERT(to_add <= (Smi::kMaxValue - len));
535
Andrei Popescu402d9372010-02-26 13:31:12 +0000536 if (new_length > elms->length()) {
537 // New backing storage is needed.
538 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100539 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000540 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +0100541 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000542
543 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100544 if (len > 0) {
545 CopyElements(&no_gc, new_elms, to_add, elms, 0, len);
546 }
547 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000548
549 elms = new_elms;
550 array->set_elements(elms);
551 } else {
552 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100553 MoveElements(&no_gc, elms, to_add, elms, 0, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000554 }
555
556 // Add the provided values.
557 AssertNoAllocation no_gc;
558 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
559 for (int i = 0; i < to_add; i++) {
560 elms->set(i, args[i + 1], mode);
561 }
562
563 // Set the length.
564 array->set_length(Smi::FromInt(new_length));
565 return Smi::FromInt(new_length);
566}
567
568
Andrei Popescu402d9372010-02-26 13:31:12 +0000569BUILTIN(ArraySlice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100570 Object* receiver = *args.receiver();
571 FixedArray* elms = NULL;
Kristian Monsen25f61362010-05-21 11:50:48 +0100572 if (!IsFastElementMovingAllowed(receiver, &elms)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100573 return CallJsBuiltin("ArraySlice", args);
574 }
575 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000576 ASSERT(array->HasFastElements());
577
578 int len = Smi::cast(array->length())->value();
579
580 int n_arguments = args.length() - 1;
581
582 // Note carefully choosen defaults---if argument is missing,
Steve Block6ded16b2010-05-10 14:33:55 +0100583 // it's undefined which gets converted to 0 for relative_start
584 // and to len for relative_end.
585 int relative_start = 0;
586 int relative_end = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000587 if (n_arguments > 0) {
588 Object* arg1 = args[1];
589 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100590 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000591 } else if (!arg1->IsUndefined()) {
592 return CallJsBuiltin("ArraySlice", args);
593 }
594 if (n_arguments > 1) {
595 Object* arg2 = args[2];
596 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100597 relative_end = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000598 } else if (!arg2->IsUndefined()) {
599 return CallJsBuiltin("ArraySlice", args);
600 }
601 }
602 }
603
604 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
Steve Block6ded16b2010-05-10 14:33:55 +0100605 int k = (relative_start < 0) ? Max(len + relative_start, 0)
606 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000607
608 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
Steve Block6ded16b2010-05-10 14:33:55 +0100609 int final = (relative_end < 0) ? Max(len + relative_end, 0)
610 : Min(relative_end, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000611
612 // Calculate the length of result array.
613 int result_len = final - k;
Steve Block6ded16b2010-05-10 14:33:55 +0100614 if (result_len <= 0) {
615 return AllocateEmptyJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000616 }
617
Steve Block6ded16b2010-05-10 14:33:55 +0100618 Object* result = AllocateJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000619 if (result->IsFailure()) return result;
620 JSArray* result_array = JSArray::cast(result);
621
Steve Block6ded16b2010-05-10 14:33:55 +0100622 result = Heap::AllocateUninitializedFixedArray(result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000623 if (result->IsFailure()) return result;
624 FixedArray* result_elms = FixedArray::cast(result);
625
Andrei Popescu402d9372010-02-26 13:31:12 +0000626 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100627 CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000628
629 // Set elements.
630 result_array->set_elements(result_elms);
631
632 // Set the length.
633 result_array->set_length(Smi::FromInt(result_len));
634 return result_array;
635}
636
637
638BUILTIN(ArraySplice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100639 Object* receiver = *args.receiver();
640 FixedArray* elms = NULL;
Kristian Monsen25f61362010-05-21 11:50:48 +0100641 if (!IsFastElementMovingAllowed(receiver, &elms)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100642 return CallJsBuiltin("ArraySplice", args);
643 }
644 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000645 ASSERT(array->HasFastElements());
646
647 int len = Smi::cast(array->length())->value();
648
649 int n_arguments = args.length() - 1;
650
651 // SpiderMonkey and JSC return undefined in the case where no
652 // arguments are given instead of using the implicit undefined
653 // arguments. This does not follow ECMA-262, but we do the same for
654 // compatibility.
655 // TraceMonkey follows ECMA-262 though.
656 if (n_arguments == 0) {
657 return Heap::undefined_value();
658 }
659
Steve Block6ded16b2010-05-10 14:33:55 +0100660 int relative_start = 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000661 Object* arg1 = args[1];
662 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100663 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000664 } else if (!arg1->IsUndefined()) {
665 return CallJsBuiltin("ArraySplice", args);
666 }
Steve Block6ded16b2010-05-10 14:33:55 +0100667 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
668 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000669
670 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
671 // given differently from when an undefined delete count is given.
672 // This does not follow ECMA-262, but we do the same for
673 // compatibility.
Steve Block6ded16b2010-05-10 14:33:55 +0100674 int delete_count = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000675 if (n_arguments > 1) {
676 Object* arg2 = args[2];
677 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100678 delete_count = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000679 } else {
680 return CallJsBuiltin("ArraySplice", args);
681 }
682 }
Steve Block6ded16b2010-05-10 14:33:55 +0100683 int actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000684
Steve Block6ded16b2010-05-10 14:33:55 +0100685 JSArray* result_array = NULL;
686 if (actual_delete_count == 0) {
687 Object* result = AllocateEmptyJSArray();
688 if (result->IsFailure()) return result;
689 result_array = JSArray::cast(result);
690 } else {
691 // Allocate result array.
692 Object* result = AllocateJSArray();
693 if (result->IsFailure()) return result;
694 result_array = JSArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000695
Steve Block6ded16b2010-05-10 14:33:55 +0100696 result = Heap::AllocateUninitializedFixedArray(actual_delete_count);
697 if (result->IsFailure()) return result;
698 FixedArray* result_elms = FixedArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000699
Steve Block6ded16b2010-05-10 14:33:55 +0100700 AssertNoAllocation no_gc;
701 // Fill newly created array.
702 CopyElements(&no_gc,
703 result_elms, 0,
704 elms, actual_start,
705 actual_delete_count);
Andrei Popescu402d9372010-02-26 13:31:12 +0000706
Steve Block6ded16b2010-05-10 14:33:55 +0100707 // Set elements.
708 result_array->set_elements(result_elms);
Andrei Popescu402d9372010-02-26 13:31:12 +0000709
Steve Block6ded16b2010-05-10 14:33:55 +0100710 // Set the length.
711 result_array->set_length(Smi::FromInt(actual_delete_count));
Andrei Popescu402d9372010-02-26 13:31:12 +0000712 }
713
Steve Block6ded16b2010-05-10 14:33:55 +0100714 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000715
Steve Block6ded16b2010-05-10 14:33:55 +0100716 int new_length = len - actual_delete_count + item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000717
Steve Block6ded16b2010-05-10 14:33:55 +0100718 if (item_count < actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000719 // Shrink the array.
Steve Block6ded16b2010-05-10 14:33:55 +0100720 const bool trim_array = Heap::new_space()->Contains(elms) &&
721 ((actual_start + item_count) <
722 (len - actual_delete_count - actual_start));
723 if (trim_array) {
724 const int delta = actual_delete_count - item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000725
Steve Block6ded16b2010-05-10 14:33:55 +0100726 if (actual_start > 0) {
727 Object** start = elms->data_start();
728 memmove(start + delta, start, actual_start * kPointerSize);
729 }
730
731 elms = LeftTrimFixedArray(elms, delta);
732 array->set_elements(elms, SKIP_WRITE_BARRIER);
733 } else {
734 AssertNoAllocation no_gc;
735 MoveElements(&no_gc,
736 elms, actual_start + item_count,
737 elms, actual_start + actual_delete_count,
738 (len - actual_delete_count - actual_start));
739 FillWithHoles(elms, new_length, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000740 }
Steve Block6ded16b2010-05-10 14:33:55 +0100741 } else if (item_count > actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000742 // Currently fixed arrays cannot grow too big, so
743 // we should never hit this case.
Steve Block6ded16b2010-05-10 14:33:55 +0100744 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
Andrei Popescu402d9372010-02-26 13:31:12 +0000745
746 // Check if array need to grow.
747 if (new_length > elms->length()) {
748 // New backing storage is needed.
749 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100750 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000751 if (obj->IsFailure()) return obj;
Andrei Popescu402d9372010-02-26 13:31:12 +0000752 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000753
Steve Block6ded16b2010-05-10 14:33:55 +0100754 AssertNoAllocation no_gc;
755 // Copy the part before actual_start as is.
756 if (actual_start > 0) {
757 CopyElements(&no_gc, new_elms, 0, elms, 0, actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000758 }
Steve Block6ded16b2010-05-10 14:33:55 +0100759 const int to_copy = len - actual_delete_count - actual_start;
760 if (to_copy > 0) {
761 CopyElements(&no_gc,
762 new_elms, actual_start + item_count,
763 elms, actual_start + actual_delete_count,
764 to_copy);
765 }
766 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000767
Andrei Popescu402d9372010-02-26 13:31:12 +0000768 elms = new_elms;
769 array->set_elements(elms);
Steve Block6ded16b2010-05-10 14:33:55 +0100770 } else {
771 AssertNoAllocation no_gc;
772 MoveElements(&no_gc,
773 elms, actual_start + item_count,
774 elms, actual_start + actual_delete_count,
775 (len - actual_delete_count - actual_start));
Andrei Popescu402d9372010-02-26 13:31:12 +0000776 }
777 }
778
Steve Block6ded16b2010-05-10 14:33:55 +0100779 AssertNoAllocation no_gc;
780 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
781 for (int k = actual_start; k < actual_start + item_count; k++) {
782 elms->set(k, args[3 + k - actual_start], mode);
Andrei Popescu402d9372010-02-26 13:31:12 +0000783 }
784
785 // Set the length.
786 array->set_length(Smi::FromInt(new_length));
787
788 return result_array;
789}
790
791
Steve Block6ded16b2010-05-10 14:33:55 +0100792BUILTIN(ArrayConcat) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100793 Context* global_context = Top::context()->global_context();
794 JSObject* array_proto =
795 JSObject::cast(global_context->array_function()->prototype());
796 if (!ArrayPrototypeHasNoElements(global_context, array_proto)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100797 return CallJsBuiltin("ArrayConcat", args);
798 }
799
800 // Iterate through all the arguments performing checks
801 // and calculating total length.
802 int n_arguments = args.length();
803 int result_len = 0;
804 for (int i = 0; i < n_arguments; i++) {
805 Object* arg = args[i];
Kristian Monsen25f61362010-05-21 11:50:48 +0100806 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
807 || JSArray::cast(arg)->GetPrototype() != array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100808 return CallJsBuiltin("ArrayConcat", args);
809 }
810
811 int len = Smi::cast(JSArray::cast(arg)->length())->value();
812
813 // We shouldn't overflow when adding another len.
814 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
815 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
816 USE(kHalfOfMaxInt);
817 result_len += len;
818 ASSERT(result_len >= 0);
819
820 if (result_len > FixedArray::kMaxLength) {
821 return CallJsBuiltin("ArrayConcat", args);
822 }
823 }
824
825 if (result_len == 0) {
826 return AllocateEmptyJSArray();
827 }
828
829 // Allocate result.
830 Object* result = AllocateJSArray();
831 if (result->IsFailure()) return result;
832 JSArray* result_array = JSArray::cast(result);
833
834 result = Heap::AllocateUninitializedFixedArray(result_len);
835 if (result->IsFailure()) return result;
836 FixedArray* result_elms = FixedArray::cast(result);
837
838 // Copy data.
839 AssertNoAllocation no_gc;
840 int start_pos = 0;
841 for (int i = 0; i < n_arguments; i++) {
842 JSArray* array = JSArray::cast(args[i]);
843 int len = Smi::cast(array->length())->value();
844 if (len > 0) {
845 FixedArray* elms = FixedArray::cast(array->elements());
846 CopyElements(&no_gc, result_elms, start_pos, elms, 0, len);
847 start_pos += len;
848 }
849 }
850 ASSERT(start_pos == result_len);
851
852 // Set the length and elements.
853 result_array->set_length(Smi::FromInt(result_len));
854 result_array->set_elements(result_elms);
855
856 return result_array;
857}
858
859
Steve Blocka7e24c12009-10-30 11:49:00 +0000860// -----------------------------------------------------------------------------
861//
862
863
864// Returns the holder JSObject if the function can legally be called
865// with this receiver. Returns Heap::null_value() if the call is
866// illegal. Any arguments that don't fit the expected type is
867// overwritten with undefined. Arguments that do fit the expected
868// type is overwritten with the object in the prototype chain that
869// actually has that type.
870static inline Object* TypeCheck(int argc,
871 Object** argv,
872 FunctionTemplateInfo* info) {
873 Object* recv = argv[0];
874 Object* sig_obj = info->signature();
875 if (sig_obj->IsUndefined()) return recv;
876 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
877 // If necessary, check the receiver
878 Object* recv_type = sig->receiver();
879
880 Object* holder = recv;
881 if (!recv_type->IsUndefined()) {
882 for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
883 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
884 break;
885 }
886 }
887 if (holder == Heap::null_value()) return holder;
888 }
889 Object* args_obj = sig->args();
890 // If there is no argument signature we're done
891 if (args_obj->IsUndefined()) return holder;
892 FixedArray* args = FixedArray::cast(args_obj);
893 int length = args->length();
894 if (argc <= length) length = argc - 1;
895 for (int i = 0; i < length; i++) {
896 Object* argtype = args->get(i);
897 if (argtype->IsUndefined()) continue;
898 Object** arg = &argv[-1 - i];
899 Object* current = *arg;
900 for (; current != Heap::null_value(); current = current->GetPrototype()) {
901 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
902 *arg = current;
903 break;
904 }
905 }
906 if (current == Heap::null_value()) *arg = Heap::undefined_value();
907 }
908 return holder;
909}
910
911
Leon Clarkee46be812010-01-19 14:06:41 +0000912template <bool is_construct>
913static Object* HandleApiCallHelper(
914 BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
915 ASSERT(is_construct == CalledAsConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +0000916
Leon Clarkee46be812010-01-19 14:06:41 +0000917 HandleScope scope;
918 Handle<JSFunction> function = args.called_function();
Steve Block6ded16b2010-05-10 14:33:55 +0100919 ASSERT(function->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +0000920
Steve Block6ded16b2010-05-10 14:33:55 +0100921 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
Steve Blocka7e24c12009-10-30 11:49:00 +0000922 if (is_construct) {
Steve Block6ded16b2010-05-10 14:33:55 +0100923 Handle<FunctionTemplateInfo> desc(fun_data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000924 bool pending_exception = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000925 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000926 &pending_exception);
927 ASSERT(Top::has_pending_exception() == pending_exception);
928 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +0100929 fun_data = *desc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000930 }
931
Steve Blocka7e24c12009-10-30 11:49:00 +0000932 Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
933
934 if (raw_holder->IsNull()) {
935 // This function cannot be called with the given receiver. Abort!
936 Handle<Object> obj =
937 Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
938 return Top::Throw(*obj);
939 }
940
941 Object* raw_call_data = fun_data->call_code();
942 if (!raw_call_data->IsUndefined()) {
943 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
944 Object* callback_obj = call_data->callback();
945 v8::InvocationCallback callback =
946 v8::ToCData<v8::InvocationCallback>(callback_obj);
947 Object* data_obj = call_data->data();
948 Object* result;
949
Steve Blocka7e24c12009-10-30 11:49:00 +0000950 Handle<Object> data_handle(data_obj);
951 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
952 ASSERT(raw_holder->IsJSObject());
953 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
954 Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
955 v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
Leon Clarkee46be812010-01-19 14:06:41 +0000956 LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +0000957 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
958 data,
959 holder,
960 callee,
961 is_construct,
962 reinterpret_cast<void**>(&args[0] - 1),
963 args.length() - 1);
964
965 v8::Handle<v8::Value> value;
966 {
967 // Leaving JavaScript.
968 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000969#ifdef ENABLE_LOGGING_AND_PROFILING
970 state.set_external_callback(v8::ToCData<Address>(callback_obj));
971#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000972 value = callback(new_args);
973 }
974 if (value.IsEmpty()) {
975 result = Heap::undefined_value();
976 } else {
977 result = *reinterpret_cast<Object**>(*value);
978 }
979
980 RETURN_IF_SCHEDULED_EXCEPTION();
981 if (!is_construct || result->IsJSObject()) return result;
982 }
983
Leon Clarkee46be812010-01-19 14:06:41 +0000984 return *args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +0000985}
Leon Clarkee46be812010-01-19 14:06:41 +0000986
987
988BUILTIN(HandleApiCall) {
989 return HandleApiCallHelper<false>(args);
990}
991
992
993BUILTIN(HandleApiCallConstruct) {
994 return HandleApiCallHelper<true>(args);
995}
Steve Blocka7e24c12009-10-30 11:49:00 +0000996
997
Andrei Popescu402d9372010-02-26 13:31:12 +0000998#ifdef DEBUG
999
1000static void VerifyTypeCheck(Handle<JSObject> object,
1001 Handle<JSFunction> function) {
Steve Block6ded16b2010-05-10 14:33:55 +01001002 ASSERT(function->shared()->IsApiFunction());
1003 FunctionTemplateInfo* info = function->shared()->get_api_func_data();
Andrei Popescu402d9372010-02-26 13:31:12 +00001004 if (info->signature()->IsUndefined()) return;
1005 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1006 Object* receiver_type = signature->receiver();
1007 if (receiver_type->IsUndefined()) return;
1008 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
1009 ASSERT(object->IsInstanceOf(type));
1010}
1011
1012#endif
1013
1014
1015BUILTIN(FastHandleApiCall) {
1016 ASSERT(!CalledAsConstructor());
1017 const bool is_construct = false;
1018
1019 // We expect four more arguments: function, callback, call data, and holder.
1020 const int args_length = args.length() - 4;
1021 ASSERT(args_length >= 0);
1022
1023 Handle<JSFunction> function = args.at<JSFunction>(args_length);
1024 Object* callback_obj = args[args_length + 1];
1025 Handle<Object> data_handle = args.at<Object>(args_length + 2);
1026 Handle<JSObject> checked_holder = args.at<JSObject>(args_length + 3);
1027
1028#ifdef DEBUG
1029 VerifyTypeCheck(checked_holder, function);
1030#endif
1031
1032 v8::Local<v8::Object> holder = v8::Utils::ToLocal(checked_holder);
1033 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
1034 v8::InvocationCallback callback =
1035 v8::ToCData<v8::InvocationCallback>(callback_obj);
1036 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
1037
1038 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1039 data,
1040 holder,
1041 callee,
1042 is_construct,
1043 reinterpret_cast<void**>(&args[0] - 1),
1044 args_length - 1);
1045
1046 HandleScope scope;
1047 Object* result;
1048 v8::Handle<v8::Value> value;
1049 {
1050 // Leaving JavaScript.
1051 VMState state(EXTERNAL);
1052#ifdef ENABLE_LOGGING_AND_PROFILING
1053 state.set_external_callback(v8::ToCData<Address>(callback_obj));
1054#endif
1055 value = callback(new_args);
1056 }
1057 if (value.IsEmpty()) {
1058 result = Heap::undefined_value();
1059 } else {
1060 result = *reinterpret_cast<Object**>(*value);
1061 }
1062
1063 RETURN_IF_SCHEDULED_EXCEPTION();
1064 return result;
1065}
1066
1067
Steve Blocka7e24c12009-10-30 11:49:00 +00001068// Helper function to handle calls to non-function objects created through the
1069// API. The object can be called as either a constructor (using new) or just as
1070// a function (without new).
Leon Clarkee46be812010-01-19 14:06:41 +00001071static Object* HandleApiCallAsFunctionOrConstructor(
1072 bool is_construct_call,
1073 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001074 // Non-functions are never called as constructors. Even if this is an object
1075 // called as a constructor the delegate call is not a construct call.
1076 ASSERT(!CalledAsConstructor());
1077
1078 Handle<Object> receiver = args.at<Object>(0);
1079
1080 // Get the object called.
Leon Clarkee46be812010-01-19 14:06:41 +00001081 JSObject* obj = JSObject::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +00001082
1083 // Get the invocation callback from the function descriptor that was
1084 // used to create the called object.
1085 ASSERT(obj->map()->has_instance_call_handler());
1086 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01001087 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001088 Object* handler =
Steve Block6ded16b2010-05-10 14:33:55 +01001089 constructor->shared()->get_api_func_data()->instance_call_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00001090 ASSERT(!handler->IsUndefined());
1091 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1092 Object* callback_obj = call_data->callback();
1093 v8::InvocationCallback callback =
1094 v8::ToCData<v8::InvocationCallback>(callback_obj);
1095
1096 // Get the data for the call and perform the callback.
1097 Object* data_obj = call_data->data();
1098 Object* result;
1099 { HandleScope scope;
1100 v8::Local<v8::Object> self =
Leon Clarkee46be812010-01-19 14:06:41 +00001101 v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001102 Handle<Object> data_handle(data_obj);
1103 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
1104 Handle<JSFunction> callee_handle(constructor);
1105 v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
Leon Clarkee46be812010-01-19 14:06:41 +00001106 LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001107 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1108 data,
1109 self,
1110 callee,
1111 is_construct_call,
1112 reinterpret_cast<void**>(&args[0] - 1),
1113 args.length() - 1);
1114 v8::Handle<v8::Value> value;
1115 {
1116 // Leaving JavaScript.
1117 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +00001118#ifdef ENABLE_LOGGING_AND_PROFILING
1119 state.set_external_callback(v8::ToCData<Address>(callback_obj));
1120#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001121 value = callback(new_args);
1122 }
1123 if (value.IsEmpty()) {
1124 result = Heap::undefined_value();
1125 } else {
1126 result = *reinterpret_cast<Object**>(*value);
1127 }
1128 }
1129 // Check for exceptions and return result.
1130 RETURN_IF_SCHEDULED_EXCEPTION();
1131 return result;
1132}
1133
1134
1135// Handle calls to non-function objects created through the API. This delegate
1136// function is used when the call is a normal function call.
1137BUILTIN(HandleApiCallAsFunction) {
1138 return HandleApiCallAsFunctionOrConstructor(false, args);
1139}
Steve Blocka7e24c12009-10-30 11:49:00 +00001140
1141
1142// Handle calls to non-function objects created through the API. This delegate
1143// function is used when the call is a construct call.
1144BUILTIN(HandleApiCallAsConstructor) {
1145 return HandleApiCallAsFunctionOrConstructor(true, args);
1146}
Steve Blocka7e24c12009-10-30 11:49:00 +00001147
1148
1149static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1150 LoadIC::GenerateArrayLength(masm);
1151}
1152
1153
1154static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
1155 LoadIC::GenerateStringLength(masm);
1156}
1157
1158
1159static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1160 LoadIC::GenerateFunctionPrototype(masm);
1161}
1162
1163
1164static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1165 LoadIC::GenerateInitialize(masm);
1166}
1167
1168
1169static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1170 LoadIC::GeneratePreMonomorphic(masm);
1171}
1172
1173
1174static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1175 LoadIC::GenerateMiss(masm);
1176}
1177
1178
1179static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1180 LoadIC::GenerateMegamorphic(masm);
1181}
1182
1183
1184static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1185 LoadIC::GenerateNormal(masm);
1186}
1187
1188
1189static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1190 KeyedLoadIC::GenerateInitialize(masm);
1191}
1192
1193
1194static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1195 KeyedLoadIC::GenerateMiss(masm);
1196}
1197
1198
1199static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1200 KeyedLoadIC::GenerateGeneric(masm);
1201}
1202
1203
Leon Clarkee46be812010-01-19 14:06:41 +00001204static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1205 KeyedLoadIC::GenerateString(masm);
1206}
1207
1208
Steve Block3ce2e202009-11-05 08:53:23 +00001209static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
1210 KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
1211}
1212
1213
1214static void Generate_KeyedLoadIC_ExternalUnsignedByteArray(
1215 MacroAssembler* masm) {
1216 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1217}
1218
1219
1220static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) {
1221 KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray);
1222}
1223
1224
1225static void Generate_KeyedLoadIC_ExternalUnsignedShortArray(
1226 MacroAssembler* masm) {
1227 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1228}
1229
1230
1231static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) {
1232 KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray);
1233}
1234
1235
1236static void Generate_KeyedLoadIC_ExternalUnsignedIntArray(
1237 MacroAssembler* masm) {
1238 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1239}
1240
1241
1242static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) {
1243 KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray);
1244}
1245
1246
Steve Blocka7e24c12009-10-30 11:49:00 +00001247static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1248 KeyedLoadIC::GeneratePreMonomorphic(masm);
1249}
1250
Andrei Popescu402d9372010-02-26 13:31:12 +00001251static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1252 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1253}
1254
Steve Blocka7e24c12009-10-30 11:49:00 +00001255
1256static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1257 StoreIC::GenerateInitialize(masm);
1258}
1259
1260
1261static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1262 StoreIC::GenerateMiss(masm);
1263}
1264
1265
Steve Block8defd9f2010-07-08 12:39:36 +01001266static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1267 StoreIC::GenerateNormal(masm);
1268}
1269
1270
Steve Blocka7e24c12009-10-30 11:49:00 +00001271static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
1272 StoreIC::GenerateMegamorphic(masm);
1273}
1274
1275
Steve Block6ded16b2010-05-10 14:33:55 +01001276static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1277 StoreIC::GenerateArrayLength(masm);
1278}
1279
1280
Steve Blocka7e24c12009-10-30 11:49:00 +00001281static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
1282 KeyedStoreIC::GenerateGeneric(masm);
1283}
1284
1285
Steve Block3ce2e202009-11-05 08:53:23 +00001286static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) {
1287 KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray);
1288}
1289
1290
1291static void Generate_KeyedStoreIC_ExternalUnsignedByteArray(
1292 MacroAssembler* masm) {
1293 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1294}
1295
1296
1297static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) {
1298 KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray);
1299}
1300
1301
1302static void Generate_KeyedStoreIC_ExternalUnsignedShortArray(
1303 MacroAssembler* masm) {
1304 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1305}
1306
1307
1308static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) {
1309 KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray);
1310}
1311
1312
1313static void Generate_KeyedStoreIC_ExternalUnsignedIntArray(
1314 MacroAssembler* masm) {
1315 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1316}
1317
1318
1319static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) {
1320 KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray);
1321}
1322
1323
Steve Blocka7e24c12009-10-30 11:49:00 +00001324static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1325 KeyedStoreIC::GenerateMiss(masm);
1326}
1327
1328
1329static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1330 KeyedStoreIC::GenerateInitialize(masm);
1331}
1332
1333
1334#ifdef ENABLE_DEBUGGER_SUPPORT
1335static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1336 Debug::GenerateLoadICDebugBreak(masm);
1337}
1338
1339
1340static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1341 Debug::GenerateStoreICDebugBreak(masm);
1342}
1343
1344
1345static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1346 Debug::GenerateKeyedLoadICDebugBreak(masm);
1347}
1348
1349
1350static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1351 Debug::GenerateKeyedStoreICDebugBreak(masm);
1352}
1353
1354
1355static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1356 Debug::GenerateConstructCallDebugBreak(masm);
1357}
1358
1359
1360static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1361 Debug::GenerateReturnDebugBreak(masm);
1362}
1363
1364
1365static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
1366 Debug::GenerateStubNoRegistersDebugBreak(masm);
1367}
Steve Block6ded16b2010-05-10 14:33:55 +01001368
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001369
1370static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1371 Debug::GenerateSlotDebugBreak(masm);
1372}
1373
1374
Steve Block6ded16b2010-05-10 14:33:55 +01001375static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1376 Debug::GeneratePlainReturnLiveEdit(masm);
1377}
1378
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001379
Steve Block6ded16b2010-05-10 14:33:55 +01001380static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1381 Debug::GenerateFrameDropperLiveEdit(masm);
1382}
Steve Blocka7e24c12009-10-30 11:49:00 +00001383#endif
1384
1385Object* Builtins::builtins_[builtin_count] = { NULL, };
1386const char* Builtins::names_[builtin_count] = { NULL, };
1387
Leon Clarkee46be812010-01-19 14:06:41 +00001388#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Steve Blocka7e24c12009-10-30 11:49:00 +00001389 Address Builtins::c_functions_[cfunction_count] = {
1390 BUILTIN_LIST_C(DEF_ENUM_C)
1391 };
1392#undef DEF_ENUM_C
1393
1394#define DEF_JS_NAME(name, ignore) #name,
1395#define DEF_JS_ARGC(ignore, argc) argc,
1396const char* Builtins::javascript_names_[id_count] = {
1397 BUILTINS_LIST_JS(DEF_JS_NAME)
1398};
1399
1400int Builtins::javascript_argc_[id_count] = {
1401 BUILTINS_LIST_JS(DEF_JS_ARGC)
1402};
1403#undef DEF_JS_NAME
1404#undef DEF_JS_ARGC
1405
1406static bool is_initialized = false;
1407void Builtins::Setup(bool create_heap_objects) {
1408 ASSERT(!is_initialized);
1409
1410 // Create a scope for the handles in the builtins.
1411 HandleScope scope;
1412
1413 struct BuiltinDesc {
1414 byte* generator;
1415 byte* c_code;
1416 const char* s_name; // name is only used for generating log information.
1417 int name;
1418 Code::Flags flags;
Leon Clarkee46be812010-01-19 14:06:41 +00001419 BuiltinExtraArguments extra_args;
Steve Blocka7e24c12009-10-30 11:49:00 +00001420 };
1421
Leon Clarkee46be812010-01-19 14:06:41 +00001422#define DEF_FUNCTION_PTR_C(name, extra_args) \
1423 { FUNCTION_ADDR(Generate_Adaptor), \
1424 FUNCTION_ADDR(Builtin_##name), \
1425 #name, \
1426 c_##name, \
1427 Code::ComputeFlags(Code::BUILTIN), \
1428 extra_args \
Steve Blocka7e24c12009-10-30 11:49:00 +00001429 },
1430
1431#define DEF_FUNCTION_PTR_A(name, kind, state) \
1432 { FUNCTION_ADDR(Generate_##name), \
1433 NULL, \
1434 #name, \
1435 name, \
Leon Clarkee46be812010-01-19 14:06:41 +00001436 Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
1437 NO_EXTRA_ARGUMENTS \
Steve Blocka7e24c12009-10-30 11:49:00 +00001438 },
1439
1440 // Define array of pointers to generators and C builtin functions.
1441 static BuiltinDesc functions[] = {
1442 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1443 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1444 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1445 // Terminator:
Leon Clarkee46be812010-01-19 14:06:41 +00001446 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
1447 NO_EXTRA_ARGUMENTS }
Steve Blocka7e24c12009-10-30 11:49:00 +00001448 };
1449
1450#undef DEF_FUNCTION_PTR_C
1451#undef DEF_FUNCTION_PTR_A
1452
1453 // For now we generate builtin adaptor code into a stack-allocated
1454 // buffer, before copying it into individual code objects.
1455 byte buffer[4*KB];
1456
1457 // Traverse the list of builtins and generate an adaptor in a
1458 // separate code object for each one.
1459 for (int i = 0; i < builtin_count; i++) {
1460 if (create_heap_objects) {
1461 MacroAssembler masm(buffer, sizeof buffer);
1462 // Generate the code/adaptor.
Leon Clarkee46be812010-01-19 14:06:41 +00001463 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001464 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1465 // We pass all arguments to the generator, but it may not use all of
1466 // them. This works because the first arguments are on top of the
1467 // stack.
Leon Clarkee46be812010-01-19 14:06:41 +00001468 g(&masm, functions[i].name, functions[i].extra_args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001469 // Move the code into the object heap.
1470 CodeDesc desc;
1471 masm.GetCode(&desc);
1472 Code::Flags flags = functions[i].flags;
1473 Object* code;
1474 {
1475 // During startup it's OK to always allocate and defer GC to later.
1476 // This simplifies things because we don't need to retry.
1477 AlwaysAllocateScope __scope__;
1478 code = Heap::CreateCode(desc, NULL, flags, masm.CodeObject());
1479 if (code->IsFailure()) {
1480 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1481 }
1482 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001483 // Log the event and add the code to the builtins array.
Steve Block6ded16b2010-05-10 14:33:55 +01001484 PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
1485 Code::cast(code), functions[i].s_name));
Steve Blocka7e24c12009-10-30 11:49:00 +00001486 builtins_[i] = code;
1487#ifdef ENABLE_DISASSEMBLER
1488 if (FLAG_print_builtin_code) {
1489 PrintF("Builtin: %s\n", functions[i].s_name);
1490 Code::cast(code)->Disassemble(functions[i].s_name);
1491 PrintF("\n");
1492 }
1493#endif
1494 } else {
1495 // Deserializing. The values will be filled in during IterateBuiltins.
1496 builtins_[i] = NULL;
1497 }
1498 names_[i] = functions[i].s_name;
1499 }
1500
1501 // Mark as initialized.
1502 is_initialized = true;
1503}
1504
1505
1506void Builtins::TearDown() {
1507 is_initialized = false;
1508}
1509
1510
1511void Builtins::IterateBuiltins(ObjectVisitor* v) {
1512 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1513}
1514
1515
1516const char* Builtins::Lookup(byte* pc) {
1517 if (is_initialized) { // may be called during initialization (disassembler!)
1518 for (int i = 0; i < builtin_count; i++) {
1519 Code* entry = Code::cast(builtins_[i]);
1520 if (entry->contains(pc)) {
1521 return names_[i];
1522 }
1523 }
1524 }
1525 return NULL;
1526}
1527
1528
1529} } // namespace v8::internal