blob: 9a0fbd27049116ae81666b5a8eea536c82c892fc [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.
198
199 // Optimize the case where there is one argument and the argument is a
200 // small smi.
201 if (args.length() == 2) {
202 Object* obj = args[1];
203 if (obj->IsSmi()) {
204 int len = Smi::cast(obj)->value();
205 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
206 Object* obj = Heap::AllocateFixedArrayWithHoles(len);
207 if (obj->IsFailure()) return obj;
208 array->SetContent(FixedArray::cast(obj));
209 return array;
210 }
211 }
212 // Take the argument as the length.
213 obj = array->Initialize(0);
214 if (obj->IsFailure()) return obj;
215 return array->SetElementsLength(args[1]);
216 }
217
218 // Optimize the case where there are no parameters passed.
219 if (args.length() == 1) {
220 return array->Initialize(JSArray::kPreallocatedArrayElements);
221 }
222
223 // Take the arguments as elements.
224 int number_of_elements = args.length() - 1;
225 Smi* len = Smi::FromInt(number_of_elements);
226 Object* obj = Heap::AllocateFixedArrayWithHoles(len->value());
227 if (obj->IsFailure()) return obj;
Leon Clarke4515c472010-02-03 11:58:03 +0000228
229 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000230 FixedArray* elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000231 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 // Fill in the content
233 for (int index = 0; index < number_of_elements; index++) {
234 elms->set(index, args[index+1], mode);
235 }
236
237 // Set length and elements on the array.
238 array->set_elements(FixedArray::cast(obj));
Leon Clarke4515c472010-02-03 11:58:03 +0000239 array->set_length(len);
Steve Blocka7e24c12009-10-30 11:49:00 +0000240
241 return array;
242}
Steve Blocka7e24c12009-10-30 11:49:00 +0000243
244
Steve Block6ded16b2010-05-10 14:33:55 +0100245static Object* AllocateJSArray() {
246 JSFunction* array_function =
247 Top::context()->global_context()->array_function();
248 Object* result = Heap::AllocateJSObject(array_function);
249 if (result->IsFailure()) return result;
250 return result;
251}
252
253
254static Object* AllocateEmptyJSArray() {
255 Object* result = AllocateJSArray();
256 if (result->IsFailure()) return result;
257 JSArray* result_array = JSArray::cast(result);
258 result_array->set_length(Smi::FromInt(0));
259 result_array->set_elements(Heap::empty_fixed_array());
260 return result_array;
261}
262
263
264static void CopyElements(AssertNoAllocation* no_gc,
265 FixedArray* dst,
266 int dst_index,
267 FixedArray* src,
268 int src_index,
269 int len) {
270 ASSERT(dst != src); // Use MoveElements instead.
271 ASSERT(len > 0);
272 CopyWords(dst->data_start() + dst_index,
273 src->data_start() + src_index,
274 len);
275 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
276 if (mode == UPDATE_WRITE_BARRIER) {
277 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
278 }
279}
280
281
282static void MoveElements(AssertNoAllocation* no_gc,
283 FixedArray* dst,
284 int dst_index,
285 FixedArray* src,
286 int src_index,
287 int len) {
288 memmove(dst->data_start() + dst_index,
289 src->data_start() + src_index,
290 len * kPointerSize);
291 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
292 if (mode == UPDATE_WRITE_BARRIER) {
293 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
294 }
295}
296
297
298static void FillWithHoles(FixedArray* dst, int from, int to) {
299 MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from);
300}
301
302
303static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
304 // For now this trick is only applied to fixed arrays in new space.
305 // In large object space the object's start must coincide with chunk
306 // and thus the trick is just not applicable.
307 // In old space we do not use this trick to avoid dealing with
308 // remembered sets.
309 ASSERT(Heap::new_space()->Contains(elms));
310
311 STATIC_ASSERT(FixedArray::kMapOffset == 0);
312 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
313 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
314
315 Object** former_start = HeapObject::RawField(elms, 0);
316
317 const int len = elms->length();
318
319 // Technically in new space this write might be omitted (except for
320 // debug mode which iterates through the heap), but to play safer
321 // we still do it.
322 Heap::CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
323
324 former_start[to_trim] = Heap::fixed_array_map();
325 former_start[to_trim + 1] = reinterpret_cast<Object*>(len - to_trim);
326
327 ASSERT_EQ(elms->address() + to_trim * kPointerSize,
328 (elms + to_trim * kPointerSize)->address());
329 return elms + to_trim * kPointerSize;
330}
331
332
Kristian Monsen25f61362010-05-21 11:50:48 +0100333static bool ArrayPrototypeHasNoElements(Context* global_context,
334 JSObject* array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100335 // This method depends on non writability of Object and Array prototype
336 // fields.
Kristian Monsen25f61362010-05-21 11:50:48 +0100337 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
Steve Block6ded16b2010-05-10 14:33:55 +0100338 // Hidden prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100339 array_proto = JSObject::cast(array_proto->GetPrototype());
340 ASSERT(array_proto->elements() == Heap::empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +0100341 // Object.prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100342 array_proto = JSObject::cast(array_proto->GetPrototype());
343 if (array_proto != global_context->initial_object_prototype()) return false;
344 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
345 ASSERT(array_proto->GetPrototype()->IsNull());
Steve Block6ded16b2010-05-10 14:33:55 +0100346 return true;
347}
348
349
350static bool IsJSArrayWithFastElements(Object* receiver,
351 FixedArray** elements) {
352 if (!receiver->IsJSArray()) {
353 return false;
354 }
355
356 JSArray* array = JSArray::cast(receiver);
357
358 HeapObject* elms = HeapObject::cast(array->elements());
359 if (elms->map() != Heap::fixed_array_map()) {
360 return false;
361 }
362
363 *elements = FixedArray::cast(elms);
364 return true;
365}
366
367
Kristian Monsen25f61362010-05-21 11:50:48 +0100368static bool IsFastElementMovingAllowed(Object* receiver,
369 FixedArray** elements) {
370 if (!IsJSArrayWithFastElements(receiver, elements)) return false;
371
372 Context* global_context = Top::context()->global_context();
373 JSObject* array_proto =
374 JSObject::cast(global_context->array_function()->prototype());
375 if (JSArray::cast(receiver)->GetPrototype() != array_proto) return false;
376 return ArrayPrototypeHasNoElements(global_context, array_proto);
377}
378
379
Steve Block6ded16b2010-05-10 14:33:55 +0100380static Object* CallJsBuiltin(const char* name,
381 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
382 HandleScope handleScope;
383
384 Handle<Object> js_builtin =
385 GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
386 name);
387 ASSERT(js_builtin->IsJSFunction());
388 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
Kristian Monsen25f61362010-05-21 11:50:48 +0100389 ScopedVector<Object**> argv(args.length() - 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100390 int n_args = args.length() - 1;
391 for (int i = 0; i < n_args; i++) {
392 argv[i] = args.at<Object>(i + 1).location();
393 }
394 bool pending_exception = false;
395 Handle<Object> result = Execution::Call(function,
396 args.receiver(),
397 n_args,
398 argv.start(),
399 &pending_exception);
Steve Block6ded16b2010-05-10 14:33:55 +0100400 if (pending_exception) return Failure::Exception();
401 return *result;
402}
403
404
Steve Blocka7e24c12009-10-30 11:49:00 +0000405BUILTIN(ArrayPush) {
Steve Block6ded16b2010-05-10 14:33:55 +0100406 Object* receiver = *args.receiver();
407 FixedArray* elms = NULL;
408 if (!IsJSArrayWithFastElements(receiver, &elms)) {
409 return CallJsBuiltin("ArrayPush", args);
410 }
411 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000412
Steve Blocka7e24c12009-10-30 11:49:00 +0000413 int len = Smi::cast(array->length())->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000414 int to_add = args.length() - 1;
415 if (to_add == 0) {
416 return Smi::FromInt(len);
417 }
418 // Currently fixed arrays cannot grow too big, so
419 // we should never hit this case.
420 ASSERT(to_add <= (Smi::kMaxValue - len));
Steve Blocka7e24c12009-10-30 11:49:00 +0000421
Andrei Popescu402d9372010-02-26 13:31:12 +0000422 int new_length = len + to_add;
Steve Blocka7e24c12009-10-30 11:49:00 +0000423
Andrei Popescu402d9372010-02-26 13:31:12 +0000424 if (new_length > elms->length()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000425 // New backing storage is needed.
426 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100427 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +0000428 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +0100429 FixedArray* new_elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000430
431 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100432 if (len > 0) {
433 CopyElements(&no_gc, new_elms, 0, elms, 0, len);
434 }
435 FillWithHoles(new_elms, new_length, capacity);
436
Andrei Popescu402d9372010-02-26 13:31:12 +0000437 elms = new_elms;
438 array->set_elements(elms);
Steve Blocka7e24c12009-10-30 11:49:00 +0000439 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000440
Steve Block6ded16b2010-05-10 14:33:55 +0100441 // Add the provided values.
Andrei Popescu402d9372010-02-26 13:31:12 +0000442 AssertNoAllocation no_gc;
443 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Andrei Popescu402d9372010-02-26 13:31:12 +0000444 for (int index = 0; index < to_add; index++) {
445 elms->set(index + len, args[index + 1], mode);
446 }
447
Steve Blocka7e24c12009-10-30 11:49:00 +0000448 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000449 array->set_length(Smi::FromInt(new_length));
Andrei Popescu402d9372010-02-26 13:31:12 +0000450 return Smi::FromInt(new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000451}
Steve Blocka7e24c12009-10-30 11:49:00 +0000452
453
454BUILTIN(ArrayPop) {
Steve Block6ded16b2010-05-10 14:33:55 +0100455 Object* receiver = *args.receiver();
456 FixedArray* elms = NULL;
457 if (!IsJSArrayWithFastElements(receiver, &elms)) {
458 return CallJsBuiltin("ArrayPop", args);
459 }
460 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000461
462 int len = Smi::cast(array->length())->value();
Steve Block6ded16b2010-05-10 14:33:55 +0100463 if (len == 0) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000464
465 // Get top element
Steve Blocka7e24c12009-10-30 11:49:00 +0000466 Object* top = elms->get(len - 1);
467
468 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000469 array->set_length(Smi::FromInt(len - 1));
Steve Blocka7e24c12009-10-30 11:49:00 +0000470
471 if (!top->IsTheHole()) {
472 // Delete the top element.
473 elms->set_the_hole(len - 1);
474 return top;
475 }
476
Kristian Monsen25f61362010-05-21 11:50:48 +0100477 top = array->GetPrototype()->GetElement(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000478
479 return top;
480}
Steve Blocka7e24c12009-10-30 11:49:00 +0000481
482
Andrei Popescu402d9372010-02-26 13:31:12 +0000483BUILTIN(ArrayShift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100484 Object* receiver = *args.receiver();
485 FixedArray* elms = NULL;
Kristian Monsen25f61362010-05-21 11:50:48 +0100486 if (!IsFastElementMovingAllowed(receiver, &elms)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100487 return CallJsBuiltin("ArrayShift", args);
488 }
489 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000490 ASSERT(array->HasFastElements());
491
492 int len = Smi::cast(array->length())->value();
493 if (len == 0) return Heap::undefined_value();
494
Andrei Popescu402d9372010-02-26 13:31:12 +0000495 // Get first element
496 Object* first = elms->get(0);
497 if (first->IsTheHole()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100498 first = Heap::undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000499 }
500
Steve Block6ded16b2010-05-10 14:33:55 +0100501 if (Heap::new_space()->Contains(elms)) {
502 // As elms still in the same space they used to be (new space),
503 // there is no need to update remembered set.
504 array->set_elements(LeftTrimFixedArray(elms, 1), SKIP_WRITE_BARRIER);
505 } else {
506 // Shift the elements.
507 AssertNoAllocation no_gc;
508 MoveElements(&no_gc, elms, 0, elms, 1, len - 1);
509 elms->set(len - 1, Heap::the_hole_value());
Andrei Popescu402d9372010-02-26 13:31:12 +0000510 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000511
512 // Set the length.
513 array->set_length(Smi::FromInt(len - 1));
514
515 return first;
516}
517
518
519BUILTIN(ArrayUnshift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100520 Object* receiver = *args.receiver();
521 FixedArray* elms = NULL;
Kristian Monsen25f61362010-05-21 11:50:48 +0100522 if (!IsFastElementMovingAllowed(receiver, &elms)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100523 return CallJsBuiltin("ArrayUnshift", args);
524 }
525 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000526 ASSERT(array->HasFastElements());
527
528 int len = Smi::cast(array->length())->value();
529 int to_add = args.length() - 1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000530 int new_length = len + to_add;
531 // Currently fixed arrays cannot grow too big, so
532 // we should never hit this case.
533 ASSERT(to_add <= (Smi::kMaxValue - len));
534
Andrei Popescu402d9372010-02-26 13:31:12 +0000535 if (new_length > elms->length()) {
536 // New backing storage is needed.
537 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100538 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000539 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +0100540 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000541
542 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100543 if (len > 0) {
544 CopyElements(&no_gc, new_elms, to_add, elms, 0, len);
545 }
546 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000547
548 elms = new_elms;
549 array->set_elements(elms);
550 } else {
551 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100552 MoveElements(&no_gc, elms, to_add, elms, 0, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000553 }
554
555 // Add the provided values.
556 AssertNoAllocation no_gc;
557 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
558 for (int i = 0; i < to_add; i++) {
559 elms->set(i, args[i + 1], mode);
560 }
561
562 // Set the length.
563 array->set_length(Smi::FromInt(new_length));
564 return Smi::FromInt(new_length);
565}
566
567
Andrei Popescu402d9372010-02-26 13:31:12 +0000568BUILTIN(ArraySlice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100569 Object* receiver = *args.receiver();
570 FixedArray* elms = NULL;
Kristian Monsen25f61362010-05-21 11:50:48 +0100571 if (!IsFastElementMovingAllowed(receiver, &elms)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100572 return CallJsBuiltin("ArraySlice", args);
573 }
574 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000575 ASSERT(array->HasFastElements());
576
577 int len = Smi::cast(array->length())->value();
578
579 int n_arguments = args.length() - 1;
580
581 // Note carefully choosen defaults---if argument is missing,
Steve Block6ded16b2010-05-10 14:33:55 +0100582 // it's undefined which gets converted to 0 for relative_start
583 // and to len for relative_end.
584 int relative_start = 0;
585 int relative_end = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000586 if (n_arguments > 0) {
587 Object* arg1 = args[1];
588 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100589 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000590 } else if (!arg1->IsUndefined()) {
591 return CallJsBuiltin("ArraySlice", args);
592 }
593 if (n_arguments > 1) {
594 Object* arg2 = args[2];
595 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100596 relative_end = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000597 } else if (!arg2->IsUndefined()) {
598 return CallJsBuiltin("ArraySlice", args);
599 }
600 }
601 }
602
603 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
Steve Block6ded16b2010-05-10 14:33:55 +0100604 int k = (relative_start < 0) ? Max(len + relative_start, 0)
605 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000606
607 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
Steve Block6ded16b2010-05-10 14:33:55 +0100608 int final = (relative_end < 0) ? Max(len + relative_end, 0)
609 : Min(relative_end, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000610
611 // Calculate the length of result array.
612 int result_len = final - k;
Steve Block6ded16b2010-05-10 14:33:55 +0100613 if (result_len <= 0) {
614 return AllocateEmptyJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000615 }
616
Steve Block6ded16b2010-05-10 14:33:55 +0100617 Object* result = AllocateJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000618 if (result->IsFailure()) return result;
619 JSArray* result_array = JSArray::cast(result);
620
Steve Block6ded16b2010-05-10 14:33:55 +0100621 result = Heap::AllocateUninitializedFixedArray(result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000622 if (result->IsFailure()) return result;
623 FixedArray* result_elms = FixedArray::cast(result);
624
Andrei Popescu402d9372010-02-26 13:31:12 +0000625 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100626 CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000627
628 // Set elements.
629 result_array->set_elements(result_elms);
630
631 // Set the length.
632 result_array->set_length(Smi::FromInt(result_len));
633 return result_array;
634}
635
636
637BUILTIN(ArraySplice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100638 Object* receiver = *args.receiver();
639 FixedArray* elms = NULL;
Kristian Monsen25f61362010-05-21 11:50:48 +0100640 if (!IsFastElementMovingAllowed(receiver, &elms)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100641 return CallJsBuiltin("ArraySplice", args);
642 }
643 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000644 ASSERT(array->HasFastElements());
645
646 int len = Smi::cast(array->length())->value();
647
648 int n_arguments = args.length() - 1;
649
650 // SpiderMonkey and JSC return undefined in the case where no
651 // arguments are given instead of using the implicit undefined
652 // arguments. This does not follow ECMA-262, but we do the same for
653 // compatibility.
654 // TraceMonkey follows ECMA-262 though.
655 if (n_arguments == 0) {
656 return Heap::undefined_value();
657 }
658
Steve Block6ded16b2010-05-10 14:33:55 +0100659 int relative_start = 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000660 Object* arg1 = args[1];
661 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100662 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000663 } else if (!arg1->IsUndefined()) {
664 return CallJsBuiltin("ArraySplice", args);
665 }
Steve Block6ded16b2010-05-10 14:33:55 +0100666 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
667 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000668
669 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
670 // given differently from when an undefined delete count is given.
671 // This does not follow ECMA-262, but we do the same for
672 // compatibility.
Steve Block6ded16b2010-05-10 14:33:55 +0100673 int delete_count = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000674 if (n_arguments > 1) {
675 Object* arg2 = args[2];
676 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100677 delete_count = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000678 } else {
679 return CallJsBuiltin("ArraySplice", args);
680 }
681 }
Steve Block6ded16b2010-05-10 14:33:55 +0100682 int actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000683
Steve Block6ded16b2010-05-10 14:33:55 +0100684 JSArray* result_array = NULL;
685 if (actual_delete_count == 0) {
686 Object* result = AllocateEmptyJSArray();
687 if (result->IsFailure()) return result;
688 result_array = JSArray::cast(result);
689 } else {
690 // Allocate result array.
691 Object* result = AllocateJSArray();
692 if (result->IsFailure()) return result;
693 result_array = JSArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000694
Steve Block6ded16b2010-05-10 14:33:55 +0100695 result = Heap::AllocateUninitializedFixedArray(actual_delete_count);
696 if (result->IsFailure()) return result;
697 FixedArray* result_elms = FixedArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000698
Steve Block6ded16b2010-05-10 14:33:55 +0100699 AssertNoAllocation no_gc;
700 // Fill newly created array.
701 CopyElements(&no_gc,
702 result_elms, 0,
703 elms, actual_start,
704 actual_delete_count);
Andrei Popescu402d9372010-02-26 13:31:12 +0000705
Steve Block6ded16b2010-05-10 14:33:55 +0100706 // Set elements.
707 result_array->set_elements(result_elms);
Andrei Popescu402d9372010-02-26 13:31:12 +0000708
Steve Block6ded16b2010-05-10 14:33:55 +0100709 // Set the length.
710 result_array->set_length(Smi::FromInt(actual_delete_count));
Andrei Popescu402d9372010-02-26 13:31:12 +0000711 }
712
Steve Block6ded16b2010-05-10 14:33:55 +0100713 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000714
Steve Block6ded16b2010-05-10 14:33:55 +0100715 int new_length = len - actual_delete_count + item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000716
Steve Block6ded16b2010-05-10 14:33:55 +0100717 if (item_count < actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000718 // Shrink the array.
Steve Block6ded16b2010-05-10 14:33:55 +0100719 const bool trim_array = Heap::new_space()->Contains(elms) &&
720 ((actual_start + item_count) <
721 (len - actual_delete_count - actual_start));
722 if (trim_array) {
723 const int delta = actual_delete_count - item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000724
Steve Block6ded16b2010-05-10 14:33:55 +0100725 if (actual_start > 0) {
726 Object** start = elms->data_start();
727 memmove(start + delta, start, actual_start * kPointerSize);
728 }
729
730 elms = LeftTrimFixedArray(elms, delta);
731 array->set_elements(elms, SKIP_WRITE_BARRIER);
732 } else {
733 AssertNoAllocation no_gc;
734 MoveElements(&no_gc,
735 elms, actual_start + item_count,
736 elms, actual_start + actual_delete_count,
737 (len - actual_delete_count - actual_start));
738 FillWithHoles(elms, new_length, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000739 }
Steve Block6ded16b2010-05-10 14:33:55 +0100740 } else if (item_count > actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000741 // Currently fixed arrays cannot grow too big, so
742 // we should never hit this case.
Steve Block6ded16b2010-05-10 14:33:55 +0100743 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
Andrei Popescu402d9372010-02-26 13:31:12 +0000744
745 // Check if array need to grow.
746 if (new_length > elms->length()) {
747 // New backing storage is needed.
748 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100749 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000750 if (obj->IsFailure()) return obj;
Andrei Popescu402d9372010-02-26 13:31:12 +0000751 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000752
Steve Block6ded16b2010-05-10 14:33:55 +0100753 AssertNoAllocation no_gc;
754 // Copy the part before actual_start as is.
755 if (actual_start > 0) {
756 CopyElements(&no_gc, new_elms, 0, elms, 0, actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000757 }
Steve Block6ded16b2010-05-10 14:33:55 +0100758 const int to_copy = len - actual_delete_count - actual_start;
759 if (to_copy > 0) {
760 CopyElements(&no_gc,
761 new_elms, actual_start + item_count,
762 elms, actual_start + actual_delete_count,
763 to_copy);
764 }
765 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000766
Andrei Popescu402d9372010-02-26 13:31:12 +0000767 elms = new_elms;
768 array->set_elements(elms);
Steve Block6ded16b2010-05-10 14:33:55 +0100769 } else {
770 AssertNoAllocation no_gc;
771 MoveElements(&no_gc,
772 elms, actual_start + item_count,
773 elms, actual_start + actual_delete_count,
774 (len - actual_delete_count - actual_start));
Andrei Popescu402d9372010-02-26 13:31:12 +0000775 }
776 }
777
Steve Block6ded16b2010-05-10 14:33:55 +0100778 AssertNoAllocation no_gc;
779 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
780 for (int k = actual_start; k < actual_start + item_count; k++) {
781 elms->set(k, args[3 + k - actual_start], mode);
Andrei Popescu402d9372010-02-26 13:31:12 +0000782 }
783
784 // Set the length.
785 array->set_length(Smi::FromInt(new_length));
786
787 return result_array;
788}
789
790
Steve Block6ded16b2010-05-10 14:33:55 +0100791BUILTIN(ArrayConcat) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100792 Context* global_context = Top::context()->global_context();
793 JSObject* array_proto =
794 JSObject::cast(global_context->array_function()->prototype());
795 if (!ArrayPrototypeHasNoElements(global_context, array_proto)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100796 return CallJsBuiltin("ArrayConcat", args);
797 }
798
799 // Iterate through all the arguments performing checks
800 // and calculating total length.
801 int n_arguments = args.length();
802 int result_len = 0;
803 for (int i = 0; i < n_arguments; i++) {
804 Object* arg = args[i];
Kristian Monsen25f61362010-05-21 11:50:48 +0100805 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
806 || JSArray::cast(arg)->GetPrototype() != array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100807 return CallJsBuiltin("ArrayConcat", args);
808 }
809
810 int len = Smi::cast(JSArray::cast(arg)->length())->value();
811
812 // We shouldn't overflow when adding another len.
813 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
814 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
815 USE(kHalfOfMaxInt);
816 result_len += len;
817 ASSERT(result_len >= 0);
818
819 if (result_len > FixedArray::kMaxLength) {
820 return CallJsBuiltin("ArrayConcat", args);
821 }
822 }
823
824 if (result_len == 0) {
825 return AllocateEmptyJSArray();
826 }
827
828 // Allocate result.
829 Object* result = AllocateJSArray();
830 if (result->IsFailure()) return result;
831 JSArray* result_array = JSArray::cast(result);
832
833 result = Heap::AllocateUninitializedFixedArray(result_len);
834 if (result->IsFailure()) return result;
835 FixedArray* result_elms = FixedArray::cast(result);
836
837 // Copy data.
838 AssertNoAllocation no_gc;
839 int start_pos = 0;
840 for (int i = 0; i < n_arguments; i++) {
841 JSArray* array = JSArray::cast(args[i]);
842 int len = Smi::cast(array->length())->value();
843 if (len > 0) {
844 FixedArray* elms = FixedArray::cast(array->elements());
845 CopyElements(&no_gc, result_elms, start_pos, elms, 0, len);
846 start_pos += len;
847 }
848 }
849 ASSERT(start_pos == result_len);
850
851 // Set the length and elements.
852 result_array->set_length(Smi::FromInt(result_len));
853 result_array->set_elements(result_elms);
854
855 return result_array;
856}
857
858
Steve Blocka7e24c12009-10-30 11:49:00 +0000859// -----------------------------------------------------------------------------
860//
861
862
863// Returns the holder JSObject if the function can legally be called
864// with this receiver. Returns Heap::null_value() if the call is
865// illegal. Any arguments that don't fit the expected type is
866// overwritten with undefined. Arguments that do fit the expected
867// type is overwritten with the object in the prototype chain that
868// actually has that type.
869static inline Object* TypeCheck(int argc,
870 Object** argv,
871 FunctionTemplateInfo* info) {
872 Object* recv = argv[0];
873 Object* sig_obj = info->signature();
874 if (sig_obj->IsUndefined()) return recv;
875 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
876 // If necessary, check the receiver
877 Object* recv_type = sig->receiver();
878
879 Object* holder = recv;
880 if (!recv_type->IsUndefined()) {
881 for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
882 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
883 break;
884 }
885 }
886 if (holder == Heap::null_value()) return holder;
887 }
888 Object* args_obj = sig->args();
889 // If there is no argument signature we're done
890 if (args_obj->IsUndefined()) return holder;
891 FixedArray* args = FixedArray::cast(args_obj);
892 int length = args->length();
893 if (argc <= length) length = argc - 1;
894 for (int i = 0; i < length; i++) {
895 Object* argtype = args->get(i);
896 if (argtype->IsUndefined()) continue;
897 Object** arg = &argv[-1 - i];
898 Object* current = *arg;
899 for (; current != Heap::null_value(); current = current->GetPrototype()) {
900 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
901 *arg = current;
902 break;
903 }
904 }
905 if (current == Heap::null_value()) *arg = Heap::undefined_value();
906 }
907 return holder;
908}
909
910
Leon Clarkee46be812010-01-19 14:06:41 +0000911template <bool is_construct>
912static Object* HandleApiCallHelper(
913 BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
914 ASSERT(is_construct == CalledAsConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +0000915
Leon Clarkee46be812010-01-19 14:06:41 +0000916 HandleScope scope;
917 Handle<JSFunction> function = args.called_function();
Steve Block6ded16b2010-05-10 14:33:55 +0100918 ASSERT(function->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +0000919
Steve Block6ded16b2010-05-10 14:33:55 +0100920 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
Steve Blocka7e24c12009-10-30 11:49:00 +0000921 if (is_construct) {
Steve Block6ded16b2010-05-10 14:33:55 +0100922 Handle<FunctionTemplateInfo> desc(fun_data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000923 bool pending_exception = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000924 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000925 &pending_exception);
926 ASSERT(Top::has_pending_exception() == pending_exception);
927 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +0100928 fun_data = *desc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000929 }
930
Steve Blocka7e24c12009-10-30 11:49:00 +0000931 Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
932
933 if (raw_holder->IsNull()) {
934 // This function cannot be called with the given receiver. Abort!
935 Handle<Object> obj =
936 Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
937 return Top::Throw(*obj);
938 }
939
940 Object* raw_call_data = fun_data->call_code();
941 if (!raw_call_data->IsUndefined()) {
942 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
943 Object* callback_obj = call_data->callback();
944 v8::InvocationCallback callback =
945 v8::ToCData<v8::InvocationCallback>(callback_obj);
946 Object* data_obj = call_data->data();
947 Object* result;
948
Steve Blocka7e24c12009-10-30 11:49:00 +0000949 Handle<Object> data_handle(data_obj);
950 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
951 ASSERT(raw_holder->IsJSObject());
952 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
953 Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
954 v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
Leon Clarkee46be812010-01-19 14:06:41 +0000955 LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +0000956 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
957 data,
958 holder,
959 callee,
960 is_construct,
961 reinterpret_cast<void**>(&args[0] - 1),
962 args.length() - 1);
963
964 v8::Handle<v8::Value> value;
965 {
966 // Leaving JavaScript.
967 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000968#ifdef ENABLE_LOGGING_AND_PROFILING
969 state.set_external_callback(v8::ToCData<Address>(callback_obj));
970#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000971 value = callback(new_args);
972 }
973 if (value.IsEmpty()) {
974 result = Heap::undefined_value();
975 } else {
976 result = *reinterpret_cast<Object**>(*value);
977 }
978
979 RETURN_IF_SCHEDULED_EXCEPTION();
980 if (!is_construct || result->IsJSObject()) return result;
981 }
982
Leon Clarkee46be812010-01-19 14:06:41 +0000983 return *args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +0000984}
Leon Clarkee46be812010-01-19 14:06:41 +0000985
986
987BUILTIN(HandleApiCall) {
988 return HandleApiCallHelper<false>(args);
989}
990
991
992BUILTIN(HandleApiCallConstruct) {
993 return HandleApiCallHelper<true>(args);
994}
Steve Blocka7e24c12009-10-30 11:49:00 +0000995
996
Andrei Popescu402d9372010-02-26 13:31:12 +0000997#ifdef DEBUG
998
999static void VerifyTypeCheck(Handle<JSObject> object,
1000 Handle<JSFunction> function) {
Steve Block6ded16b2010-05-10 14:33:55 +01001001 ASSERT(function->shared()->IsApiFunction());
1002 FunctionTemplateInfo* info = function->shared()->get_api_func_data();
Andrei Popescu402d9372010-02-26 13:31:12 +00001003 if (info->signature()->IsUndefined()) return;
1004 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1005 Object* receiver_type = signature->receiver();
1006 if (receiver_type->IsUndefined()) return;
1007 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
1008 ASSERT(object->IsInstanceOf(type));
1009}
1010
1011#endif
1012
1013
1014BUILTIN(FastHandleApiCall) {
1015 ASSERT(!CalledAsConstructor());
1016 const bool is_construct = false;
1017
1018 // We expect four more arguments: function, callback, call data, and holder.
1019 const int args_length = args.length() - 4;
1020 ASSERT(args_length >= 0);
1021
1022 Handle<JSFunction> function = args.at<JSFunction>(args_length);
1023 Object* callback_obj = args[args_length + 1];
1024 Handle<Object> data_handle = args.at<Object>(args_length + 2);
1025 Handle<JSObject> checked_holder = args.at<JSObject>(args_length + 3);
1026
1027#ifdef DEBUG
1028 VerifyTypeCheck(checked_holder, function);
1029#endif
1030
1031 v8::Local<v8::Object> holder = v8::Utils::ToLocal(checked_holder);
1032 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
1033 v8::InvocationCallback callback =
1034 v8::ToCData<v8::InvocationCallback>(callback_obj);
1035 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
1036
1037 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1038 data,
1039 holder,
1040 callee,
1041 is_construct,
1042 reinterpret_cast<void**>(&args[0] - 1),
1043 args_length - 1);
1044
1045 HandleScope scope;
1046 Object* result;
1047 v8::Handle<v8::Value> value;
1048 {
1049 // Leaving JavaScript.
1050 VMState state(EXTERNAL);
1051#ifdef ENABLE_LOGGING_AND_PROFILING
1052 state.set_external_callback(v8::ToCData<Address>(callback_obj));
1053#endif
1054 value = callback(new_args);
1055 }
1056 if (value.IsEmpty()) {
1057 result = Heap::undefined_value();
1058 } else {
1059 result = *reinterpret_cast<Object**>(*value);
1060 }
1061
1062 RETURN_IF_SCHEDULED_EXCEPTION();
1063 return result;
1064}
1065
1066
Steve Blocka7e24c12009-10-30 11:49:00 +00001067// Helper function to handle calls to non-function objects created through the
1068// API. The object can be called as either a constructor (using new) or just as
1069// a function (without new).
Leon Clarkee46be812010-01-19 14:06:41 +00001070static Object* HandleApiCallAsFunctionOrConstructor(
1071 bool is_construct_call,
1072 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001073 // Non-functions are never called as constructors. Even if this is an object
1074 // called as a constructor the delegate call is not a construct call.
1075 ASSERT(!CalledAsConstructor());
1076
1077 Handle<Object> receiver = args.at<Object>(0);
1078
1079 // Get the object called.
Leon Clarkee46be812010-01-19 14:06:41 +00001080 JSObject* obj = JSObject::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +00001081
1082 // Get the invocation callback from the function descriptor that was
1083 // used to create the called object.
1084 ASSERT(obj->map()->has_instance_call_handler());
1085 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01001086 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001087 Object* handler =
Steve Block6ded16b2010-05-10 14:33:55 +01001088 constructor->shared()->get_api_func_data()->instance_call_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00001089 ASSERT(!handler->IsUndefined());
1090 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1091 Object* callback_obj = call_data->callback();
1092 v8::InvocationCallback callback =
1093 v8::ToCData<v8::InvocationCallback>(callback_obj);
1094
1095 // Get the data for the call and perform the callback.
1096 Object* data_obj = call_data->data();
1097 Object* result;
1098 { HandleScope scope;
1099 v8::Local<v8::Object> self =
Leon Clarkee46be812010-01-19 14:06:41 +00001100 v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001101 Handle<Object> data_handle(data_obj);
1102 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
1103 Handle<JSFunction> callee_handle(constructor);
1104 v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
Leon Clarkee46be812010-01-19 14:06:41 +00001105 LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001106 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1107 data,
1108 self,
1109 callee,
1110 is_construct_call,
1111 reinterpret_cast<void**>(&args[0] - 1),
1112 args.length() - 1);
1113 v8::Handle<v8::Value> value;
1114 {
1115 // Leaving JavaScript.
1116 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +00001117#ifdef ENABLE_LOGGING_AND_PROFILING
1118 state.set_external_callback(v8::ToCData<Address>(callback_obj));
1119#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001120 value = callback(new_args);
1121 }
1122 if (value.IsEmpty()) {
1123 result = Heap::undefined_value();
1124 } else {
1125 result = *reinterpret_cast<Object**>(*value);
1126 }
1127 }
1128 // Check for exceptions and return result.
1129 RETURN_IF_SCHEDULED_EXCEPTION();
1130 return result;
1131}
1132
1133
1134// Handle calls to non-function objects created through the API. This delegate
1135// function is used when the call is a normal function call.
1136BUILTIN(HandleApiCallAsFunction) {
1137 return HandleApiCallAsFunctionOrConstructor(false, args);
1138}
Steve Blocka7e24c12009-10-30 11:49:00 +00001139
1140
1141// Handle calls to non-function objects created through the API. This delegate
1142// function is used when the call is a construct call.
1143BUILTIN(HandleApiCallAsConstructor) {
1144 return HandleApiCallAsFunctionOrConstructor(true, args);
1145}
Steve Blocka7e24c12009-10-30 11:49:00 +00001146
1147
1148static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1149 LoadIC::GenerateArrayLength(masm);
1150}
1151
1152
1153static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
1154 LoadIC::GenerateStringLength(masm);
1155}
1156
1157
1158static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1159 LoadIC::GenerateFunctionPrototype(masm);
1160}
1161
1162
1163static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1164 LoadIC::GenerateInitialize(masm);
1165}
1166
1167
1168static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1169 LoadIC::GeneratePreMonomorphic(masm);
1170}
1171
1172
1173static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1174 LoadIC::GenerateMiss(masm);
1175}
1176
1177
1178static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1179 LoadIC::GenerateMegamorphic(masm);
1180}
1181
1182
1183static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1184 LoadIC::GenerateNormal(masm);
1185}
1186
1187
1188static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1189 KeyedLoadIC::GenerateInitialize(masm);
1190}
1191
1192
1193static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1194 KeyedLoadIC::GenerateMiss(masm);
1195}
1196
1197
1198static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1199 KeyedLoadIC::GenerateGeneric(masm);
1200}
1201
1202
Leon Clarkee46be812010-01-19 14:06:41 +00001203static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1204 KeyedLoadIC::GenerateString(masm);
1205}
1206
1207
Steve Block3ce2e202009-11-05 08:53:23 +00001208static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
1209 KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
1210}
1211
1212
1213static void Generate_KeyedLoadIC_ExternalUnsignedByteArray(
1214 MacroAssembler* masm) {
1215 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1216}
1217
1218
1219static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) {
1220 KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray);
1221}
1222
1223
1224static void Generate_KeyedLoadIC_ExternalUnsignedShortArray(
1225 MacroAssembler* masm) {
1226 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1227}
1228
1229
1230static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) {
1231 KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray);
1232}
1233
1234
1235static void Generate_KeyedLoadIC_ExternalUnsignedIntArray(
1236 MacroAssembler* masm) {
1237 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1238}
1239
1240
1241static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) {
1242 KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray);
1243}
1244
1245
Steve Blocka7e24c12009-10-30 11:49:00 +00001246static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1247 KeyedLoadIC::GeneratePreMonomorphic(masm);
1248}
1249
Andrei Popescu402d9372010-02-26 13:31:12 +00001250static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1251 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1252}
1253
Steve Blocka7e24c12009-10-30 11:49:00 +00001254
1255static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1256 StoreIC::GenerateInitialize(masm);
1257}
1258
1259
1260static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1261 StoreIC::GenerateMiss(masm);
1262}
1263
1264
Steve Blocka7e24c12009-10-30 11:49:00 +00001265static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
1266 StoreIC::GenerateMegamorphic(masm);
1267}
1268
1269
Steve Block6ded16b2010-05-10 14:33:55 +01001270static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1271 StoreIC::GenerateArrayLength(masm);
1272}
1273
1274
Steve Blocka7e24c12009-10-30 11:49:00 +00001275static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
1276 KeyedStoreIC::GenerateGeneric(masm);
1277}
1278
1279
Steve Block3ce2e202009-11-05 08:53:23 +00001280static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) {
1281 KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray);
1282}
1283
1284
1285static void Generate_KeyedStoreIC_ExternalUnsignedByteArray(
1286 MacroAssembler* masm) {
1287 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1288}
1289
1290
1291static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) {
1292 KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray);
1293}
1294
1295
1296static void Generate_KeyedStoreIC_ExternalUnsignedShortArray(
1297 MacroAssembler* masm) {
1298 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1299}
1300
1301
1302static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) {
1303 KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray);
1304}
1305
1306
1307static void Generate_KeyedStoreIC_ExternalUnsignedIntArray(
1308 MacroAssembler* masm) {
1309 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1310}
1311
1312
1313static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) {
1314 KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray);
1315}
1316
1317
Steve Blocka7e24c12009-10-30 11:49:00 +00001318static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1319 KeyedStoreIC::GenerateMiss(masm);
1320}
1321
1322
1323static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1324 KeyedStoreIC::GenerateInitialize(masm);
1325}
1326
1327
1328#ifdef ENABLE_DEBUGGER_SUPPORT
1329static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1330 Debug::GenerateLoadICDebugBreak(masm);
1331}
1332
1333
1334static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1335 Debug::GenerateStoreICDebugBreak(masm);
1336}
1337
1338
1339static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1340 Debug::GenerateKeyedLoadICDebugBreak(masm);
1341}
1342
1343
1344static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1345 Debug::GenerateKeyedStoreICDebugBreak(masm);
1346}
1347
1348
1349static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1350 Debug::GenerateConstructCallDebugBreak(masm);
1351}
1352
1353
1354static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1355 Debug::GenerateReturnDebugBreak(masm);
1356}
1357
1358
1359static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
1360 Debug::GenerateStubNoRegistersDebugBreak(masm);
1361}
Steve Block6ded16b2010-05-10 14:33:55 +01001362
1363static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1364 Debug::GeneratePlainReturnLiveEdit(masm);
1365}
1366
1367static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1368 Debug::GenerateFrameDropperLiveEdit(masm);
1369}
Steve Blocka7e24c12009-10-30 11:49:00 +00001370#endif
1371
1372Object* Builtins::builtins_[builtin_count] = { NULL, };
1373const char* Builtins::names_[builtin_count] = { NULL, };
1374
Leon Clarkee46be812010-01-19 14:06:41 +00001375#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Steve Blocka7e24c12009-10-30 11:49:00 +00001376 Address Builtins::c_functions_[cfunction_count] = {
1377 BUILTIN_LIST_C(DEF_ENUM_C)
1378 };
1379#undef DEF_ENUM_C
1380
1381#define DEF_JS_NAME(name, ignore) #name,
1382#define DEF_JS_ARGC(ignore, argc) argc,
1383const char* Builtins::javascript_names_[id_count] = {
1384 BUILTINS_LIST_JS(DEF_JS_NAME)
1385};
1386
1387int Builtins::javascript_argc_[id_count] = {
1388 BUILTINS_LIST_JS(DEF_JS_ARGC)
1389};
1390#undef DEF_JS_NAME
1391#undef DEF_JS_ARGC
1392
1393static bool is_initialized = false;
1394void Builtins::Setup(bool create_heap_objects) {
1395 ASSERT(!is_initialized);
1396
1397 // Create a scope for the handles in the builtins.
1398 HandleScope scope;
1399
1400 struct BuiltinDesc {
1401 byte* generator;
1402 byte* c_code;
1403 const char* s_name; // name is only used for generating log information.
1404 int name;
1405 Code::Flags flags;
Leon Clarkee46be812010-01-19 14:06:41 +00001406 BuiltinExtraArguments extra_args;
Steve Blocka7e24c12009-10-30 11:49:00 +00001407 };
1408
Leon Clarkee46be812010-01-19 14:06:41 +00001409#define DEF_FUNCTION_PTR_C(name, extra_args) \
1410 { FUNCTION_ADDR(Generate_Adaptor), \
1411 FUNCTION_ADDR(Builtin_##name), \
1412 #name, \
1413 c_##name, \
1414 Code::ComputeFlags(Code::BUILTIN), \
1415 extra_args \
Steve Blocka7e24c12009-10-30 11:49:00 +00001416 },
1417
1418#define DEF_FUNCTION_PTR_A(name, kind, state) \
1419 { FUNCTION_ADDR(Generate_##name), \
1420 NULL, \
1421 #name, \
1422 name, \
Leon Clarkee46be812010-01-19 14:06:41 +00001423 Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
1424 NO_EXTRA_ARGUMENTS \
Steve Blocka7e24c12009-10-30 11:49:00 +00001425 },
1426
1427 // Define array of pointers to generators and C builtin functions.
1428 static BuiltinDesc functions[] = {
1429 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1430 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1431 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1432 // Terminator:
Leon Clarkee46be812010-01-19 14:06:41 +00001433 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
1434 NO_EXTRA_ARGUMENTS }
Steve Blocka7e24c12009-10-30 11:49:00 +00001435 };
1436
1437#undef DEF_FUNCTION_PTR_C
1438#undef DEF_FUNCTION_PTR_A
1439
1440 // For now we generate builtin adaptor code into a stack-allocated
1441 // buffer, before copying it into individual code objects.
1442 byte buffer[4*KB];
1443
1444 // Traverse the list of builtins and generate an adaptor in a
1445 // separate code object for each one.
1446 for (int i = 0; i < builtin_count; i++) {
1447 if (create_heap_objects) {
1448 MacroAssembler masm(buffer, sizeof buffer);
1449 // Generate the code/adaptor.
Leon Clarkee46be812010-01-19 14:06:41 +00001450 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001451 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1452 // We pass all arguments to the generator, but it may not use all of
1453 // them. This works because the first arguments are on top of the
1454 // stack.
Leon Clarkee46be812010-01-19 14:06:41 +00001455 g(&masm, functions[i].name, functions[i].extra_args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001456 // Move the code into the object heap.
1457 CodeDesc desc;
1458 masm.GetCode(&desc);
1459 Code::Flags flags = functions[i].flags;
1460 Object* code;
1461 {
1462 // During startup it's OK to always allocate and defer GC to later.
1463 // This simplifies things because we don't need to retry.
1464 AlwaysAllocateScope __scope__;
1465 code = Heap::CreateCode(desc, NULL, flags, masm.CodeObject());
1466 if (code->IsFailure()) {
1467 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1468 }
1469 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001470 // Log the event and add the code to the builtins array.
Steve Block6ded16b2010-05-10 14:33:55 +01001471 PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
1472 Code::cast(code), functions[i].s_name));
Steve Blocka7e24c12009-10-30 11:49:00 +00001473 builtins_[i] = code;
1474#ifdef ENABLE_DISASSEMBLER
1475 if (FLAG_print_builtin_code) {
1476 PrintF("Builtin: %s\n", functions[i].s_name);
1477 Code::cast(code)->Disassemble(functions[i].s_name);
1478 PrintF("\n");
1479 }
1480#endif
1481 } else {
1482 // Deserializing. The values will be filled in during IterateBuiltins.
1483 builtins_[i] = NULL;
1484 }
1485 names_[i] = functions[i].s_name;
1486 }
1487
1488 // Mark as initialized.
1489 is_initialized = true;
1490}
1491
1492
1493void Builtins::TearDown() {
1494 is_initialized = false;
1495}
1496
1497
1498void Builtins::IterateBuiltins(ObjectVisitor* v) {
1499 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1500}
1501
1502
1503const char* Builtins::Lookup(byte* pc) {
1504 if (is_initialized) { // may be called during initialization (disassembler!)
1505 for (int i = 0; i < builtin_count; i++) {
1506 Code* entry = Code::cast(builtins_[i]);
1507 if (entry->contains(pc)) {
1508 return names_[i];
1509 }
1510 }
1511 }
1512 return NULL;
1513}
1514
1515
1516} } // namespace v8::internal