blob: ee98769b47f446f1735874b34fc727bfcc95aa1c [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
245BUILTIN(ArrayPush) {
Leon Clarkee46be812010-01-19 14:06:41 +0000246 JSArray* array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000247 ASSERT(array->HasFastElements());
248
Steve Blocka7e24c12009-10-30 11:49:00 +0000249 int len = Smi::cast(array->length())->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000250 int to_add = args.length() - 1;
251 if (to_add == 0) {
252 return Smi::FromInt(len);
253 }
254 // Currently fixed arrays cannot grow too big, so
255 // we should never hit this case.
256 ASSERT(to_add <= (Smi::kMaxValue - len));
Steve Blocka7e24c12009-10-30 11:49:00 +0000257
Andrei Popescu402d9372010-02-26 13:31:12 +0000258 int new_length = len + to_add;
Steve Blocka7e24c12009-10-30 11:49:00 +0000259 FixedArray* elms = FixedArray::cast(array->elements());
260
Andrei Popescu402d9372010-02-26 13:31:12 +0000261 if (new_length > elms->length()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000262 // New backing storage is needed.
263 int capacity = new_length + (new_length >> 1) + 16;
264 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
265 if (obj->IsFailure()) return obj;
Leon Clarke4515c472010-02-03 11:58:03 +0000266
267 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000268 FixedArray* new_elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000269 WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000270 // Fill out the new array with old elements.
271 for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
Andrei Popescu402d9372010-02-26 13:31:12 +0000272 elms = new_elms;
273 array->set_elements(elms);
Steve Blocka7e24c12009-10-30 11:49:00 +0000274 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000275
276 AssertNoAllocation no_gc;
277 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
278
279 // Add the provided values.
280 for (int index = 0; index < to_add; index++) {
281 elms->set(index + len, args[index + 1], mode);
282 }
283
Steve Blocka7e24c12009-10-30 11:49:00 +0000284 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000285 array->set_length(Smi::FromInt(new_length));
Andrei Popescu402d9372010-02-26 13:31:12 +0000286 return Smi::FromInt(new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000287}
Steve Blocka7e24c12009-10-30 11:49:00 +0000288
289
290BUILTIN(ArrayPop) {
Leon Clarkee46be812010-01-19 14:06:41 +0000291 JSArray* array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000292 ASSERT(array->HasFastElements());
293 Object* undefined = Heap::undefined_value();
294
295 int len = Smi::cast(array->length())->value();
296 if (len == 0) return undefined;
297
298 // Get top element
299 FixedArray* elms = FixedArray::cast(array->elements());
300 Object* top = elms->get(len - 1);
301
302 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000303 array->set_length(Smi::FromInt(len - 1));
Steve Blocka7e24c12009-10-30 11:49:00 +0000304
305 if (!top->IsTheHole()) {
306 // Delete the top element.
307 elms->set_the_hole(len - 1);
308 return top;
309 }
310
311 // Remember to check the prototype chain.
312 JSFunction* array_function =
313 Top::context()->global_context()->array_function();
314 JSObject* prototype = JSObject::cast(array_function->prototype());
315 top = prototype->GetElement(len - 1);
316
317 return top;
318}
Steve Blocka7e24c12009-10-30 11:49:00 +0000319
320
Andrei Popescu402d9372010-02-26 13:31:12 +0000321static Object* GetElementToMove(uint32_t index,
322 FixedArray* elms,
323 JSObject* prototype) {
324 Object* e = elms->get(index);
325 if (e->IsTheHole() && prototype->HasElement(index)) {
326 e = prototype->GetElement(index);
327 }
328 return e;
329}
330
331
332BUILTIN(ArrayShift) {
333 JSArray* array = JSArray::cast(*args.receiver());
334 ASSERT(array->HasFastElements());
335
336 int len = Smi::cast(array->length())->value();
337 if (len == 0) return Heap::undefined_value();
338
339 // Fetch the prototype.
340 JSFunction* array_function =
341 Top::context()->global_context()->array_function();
342 JSObject* prototype = JSObject::cast(array_function->prototype());
343
344 FixedArray* elms = FixedArray::cast(array->elements());
345
346 // Get first element
347 Object* first = elms->get(0);
348 if (first->IsTheHole()) {
349 first = prototype->GetElement(0);
350 }
351
352 // Shift the elements.
353 for (int i = 0; i < len - 1; i++) {
354 elms->set(i, GetElementToMove(i + 1, elms, prototype));
355 }
356 elms->set(len - 1, Heap::the_hole_value());
357
358 // Set the length.
359 array->set_length(Smi::FromInt(len - 1));
360
361 return first;
362}
363
364
365BUILTIN(ArrayUnshift) {
366 JSArray* array = JSArray::cast(*args.receiver());
367 ASSERT(array->HasFastElements());
368
369 int len = Smi::cast(array->length())->value();
370 int to_add = args.length() - 1;
371 // Note that we cannot quit early if to_add == 0 as
372 // values should be lifted from prototype into
373 // the array.
374
375 int new_length = len + to_add;
376 // Currently fixed arrays cannot grow too big, so
377 // we should never hit this case.
378 ASSERT(to_add <= (Smi::kMaxValue - len));
379
380 FixedArray* elms = FixedArray::cast(array->elements());
381
382 // Fetch the prototype.
383 JSFunction* array_function =
384 Top::context()->global_context()->array_function();
385 JSObject* prototype = JSObject::cast(array_function->prototype());
386
387 if (new_length > elms->length()) {
388 // New backing storage is needed.
389 int capacity = new_length + (new_length >> 1) + 16;
390 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
391 if (obj->IsFailure()) return obj;
392
393 AssertNoAllocation no_gc;
394 FixedArray* new_elms = FixedArray::cast(obj);
395 WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
396 // Fill out the new array with old elements.
397 for (int i = 0; i < len; i++)
398 new_elms->set(to_add + i,
399 GetElementToMove(i, elms, prototype),
400 mode);
401
402 elms = new_elms;
403 array->set_elements(elms);
404 } else {
405 AssertNoAllocation no_gc;
406 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
407
408 // Move elements to the right
409 for (int i = 0; i < len; i++) {
410 elms->set(new_length - i - 1,
411 GetElementToMove(len - i - 1, elms, prototype),
412 mode);
413 }
414 }
415
416 // Add the provided values.
417 AssertNoAllocation no_gc;
418 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
419 for (int i = 0; i < to_add; i++) {
420 elms->set(i, args[i + 1], mode);
421 }
422
423 // Set the length.
424 array->set_length(Smi::FromInt(new_length));
425 return Smi::FromInt(new_length);
426}
427
428
429static Object* CallJsBuiltin(const char* name,
430 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
431 HandleScope handleScope;
432
433 Handle<Object> js_builtin =
434 GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
435 name);
436 ASSERT(js_builtin->IsJSFunction());
437 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
438 Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
439 int n_args = args.length() - 1;
440 for (int i = 0; i < n_args; i++) {
441 argv[i] = &args[i + 1];
442 }
443 bool pending_exception = false;
444 Handle<Object> result = Execution::Call(function,
445 args.receiver(),
446 n_args,
447 argv.start(),
448 &pending_exception);
449 if (pending_exception) return Failure::Exception();
450 return *result;
451}
452
453
454BUILTIN(ArraySlice) {
455 JSArray* array = JSArray::cast(*args.receiver());
456 ASSERT(array->HasFastElements());
457
458 int len = Smi::cast(array->length())->value();
459
460 int n_arguments = args.length() - 1;
461
462 // Note carefully choosen defaults---if argument is missing,
463 // it's undefined which gets converted to 0 for relativeStart
464 // and to len for relativeEnd.
465 int relativeStart = 0;
466 int relativeEnd = len;
467 if (n_arguments > 0) {
468 Object* arg1 = args[1];
469 if (arg1->IsSmi()) {
470 relativeStart = Smi::cast(arg1)->value();
471 } else if (!arg1->IsUndefined()) {
472 return CallJsBuiltin("ArraySlice", args);
473 }
474 if (n_arguments > 1) {
475 Object* arg2 = args[2];
476 if (arg2->IsSmi()) {
477 relativeEnd = Smi::cast(arg2)->value();
478 } else if (!arg2->IsUndefined()) {
479 return CallJsBuiltin("ArraySlice", args);
480 }
481 }
482 }
483
484 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
485 int k = (relativeStart < 0) ? Max(len + relativeStart, 0)
486 : Min(relativeStart, len);
487
488 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
489 int final = (relativeEnd < 0) ? Max(len + relativeEnd, 0)
490 : Min(relativeEnd, len);
491
492 // Calculate the length of result array.
493 int result_len = final - k;
494 if (result_len < 0) {
495 result_len = 0;
496 }
497
498 JSFunction* array_function =
499 Top::context()->global_context()->array_function();
500 Object* result = Heap::AllocateJSObject(array_function);
501 if (result->IsFailure()) return result;
502 JSArray* result_array = JSArray::cast(result);
503
504 result = Heap::AllocateFixedArrayWithHoles(result_len);
505 if (result->IsFailure()) return result;
506 FixedArray* result_elms = FixedArray::cast(result);
507
508 FixedArray* elms = FixedArray::cast(array->elements());
509
510 // Fetch the prototype.
511 JSObject* prototype = JSObject::cast(array_function->prototype());
512
513 AssertNoAllocation no_gc;
514 WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc);
515
516 // Fill newly created array.
517 for (int i = 0; i < result_len; i++) {
518 result_elms->set(i,
519 GetElementToMove(k + i, elms, prototype),
520 mode);
521 }
522
523 // Set elements.
524 result_array->set_elements(result_elms);
525
526 // Set the length.
527 result_array->set_length(Smi::FromInt(result_len));
528 return result_array;
529}
530
531
532BUILTIN(ArraySplice) {
533 JSArray* array = JSArray::cast(*args.receiver());
534 ASSERT(array->HasFastElements());
535
536 int len = Smi::cast(array->length())->value();
537
538 int n_arguments = args.length() - 1;
539
540 // SpiderMonkey and JSC return undefined in the case where no
541 // arguments are given instead of using the implicit undefined
542 // arguments. This does not follow ECMA-262, but we do the same for
543 // compatibility.
544 // TraceMonkey follows ECMA-262 though.
545 if (n_arguments == 0) {
546 return Heap::undefined_value();
547 }
548
549 int relativeStart = 0;
550 Object* arg1 = args[1];
551 if (arg1->IsSmi()) {
552 relativeStart = Smi::cast(arg1)->value();
553 } else if (!arg1->IsUndefined()) {
554 return CallJsBuiltin("ArraySplice", args);
555 }
556 int actualStart = (relativeStart < 0) ? Max(len + relativeStart, 0)
557 : Min(relativeStart, len);
558
559 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
560 // given differently from when an undefined delete count is given.
561 // This does not follow ECMA-262, but we do the same for
562 // compatibility.
563 int deleteCount = len;
564 if (n_arguments > 1) {
565 Object* arg2 = args[2];
566 if (arg2->IsSmi()) {
567 deleteCount = Smi::cast(arg2)->value();
568 } else {
569 return CallJsBuiltin("ArraySplice", args);
570 }
571 }
572 int actualDeleteCount = Min(Max(deleteCount, 0), len - actualStart);
573
574 JSFunction* array_function =
575 Top::context()->global_context()->array_function();
576
577 // Allocate result array.
578 Object* result = Heap::AllocateJSObject(array_function);
579 if (result->IsFailure()) return result;
580 JSArray* result_array = JSArray::cast(result);
581
582 result = Heap::AllocateFixedArrayWithHoles(actualDeleteCount);
583 if (result->IsFailure()) return result;
584 FixedArray* result_elms = FixedArray::cast(result);
585
586 FixedArray* elms = FixedArray::cast(array->elements());
587
588 // Fetch the prototype.
589 JSObject* prototype = JSObject::cast(array_function->prototype());
590
591 AssertNoAllocation no_gc;
592 WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc);
593
594 // Fill newly created array.
595 for (int k = 0; k < actualDeleteCount; k++) {
596 result_elms->set(k,
597 GetElementToMove(actualStart + k, elms, prototype),
598 mode);
599 }
600
601 // Set elements.
602 result_array->set_elements(result_elms);
603
604 // Set the length.
605 result_array->set_length(Smi::FromInt(actualDeleteCount));
606
607 int itemCount = (n_arguments > 1) ? (n_arguments - 2) : 0;
608
609 int new_length = len - actualDeleteCount + itemCount;
610
611 mode = elms->GetWriteBarrierMode(no_gc);
612 if (itemCount < actualDeleteCount) {
613 // Shrink the array.
614 for (int k = actualStart; k < (len - actualDeleteCount); k++) {
615 elms->set(k + itemCount,
616 GetElementToMove(k + actualDeleteCount, elms, prototype),
617 mode);
618 }
619
620 for (int k = len; k > new_length; k--) {
621 elms->set(k - 1, Heap::the_hole_value());
622 }
623 } else if (itemCount > actualDeleteCount) {
624 // Currently fixed arrays cannot grow too big, so
625 // we should never hit this case.
626 ASSERT((itemCount - actualDeleteCount) <= (Smi::kMaxValue - len));
627
628 FixedArray* source_elms = elms;
629
630 // Check if array need to grow.
631 if (new_length > elms->length()) {
632 // New backing storage is needed.
633 int capacity = new_length + (new_length >> 1) + 16;
634 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
635 if (obj->IsFailure()) return obj;
636
637 FixedArray* new_elms = FixedArray::cast(obj);
638 mode = new_elms->GetWriteBarrierMode(no_gc);
639
640 // Copy the part before actualStart as is.
641 for (int k = 0; k < actualStart; k++) {
642 new_elms->set(k, elms->get(k), mode);
643 }
644
645 source_elms = elms;
646 elms = new_elms;
647 array->set_elements(elms);
648 }
649
650 for (int k = len - actualDeleteCount; k > actualStart; k--) {
651 elms->set(k + itemCount - 1,
652 GetElementToMove(k + actualDeleteCount - 1,
653 source_elms,
654 prototype),
655 mode);
656 }
657 }
658
659 for (int k = actualStart; k < actualStart + itemCount; k++) {
660 elms->set(k, args[3 + k - actualStart], mode);
661 }
662
663 // Set the length.
664 array->set_length(Smi::FromInt(new_length));
665
666 return result_array;
667}
668
669
Steve Blocka7e24c12009-10-30 11:49:00 +0000670// -----------------------------------------------------------------------------
671//
672
673
674// Returns the holder JSObject if the function can legally be called
675// with this receiver. Returns Heap::null_value() if the call is
676// illegal. Any arguments that don't fit the expected type is
677// overwritten with undefined. Arguments that do fit the expected
678// type is overwritten with the object in the prototype chain that
679// actually has that type.
680static inline Object* TypeCheck(int argc,
681 Object** argv,
682 FunctionTemplateInfo* info) {
683 Object* recv = argv[0];
684 Object* sig_obj = info->signature();
685 if (sig_obj->IsUndefined()) return recv;
686 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
687 // If necessary, check the receiver
688 Object* recv_type = sig->receiver();
689
690 Object* holder = recv;
691 if (!recv_type->IsUndefined()) {
692 for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
693 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
694 break;
695 }
696 }
697 if (holder == Heap::null_value()) return holder;
698 }
699 Object* args_obj = sig->args();
700 // If there is no argument signature we're done
701 if (args_obj->IsUndefined()) return holder;
702 FixedArray* args = FixedArray::cast(args_obj);
703 int length = args->length();
704 if (argc <= length) length = argc - 1;
705 for (int i = 0; i < length; i++) {
706 Object* argtype = args->get(i);
707 if (argtype->IsUndefined()) continue;
708 Object** arg = &argv[-1 - i];
709 Object* current = *arg;
710 for (; current != Heap::null_value(); current = current->GetPrototype()) {
711 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
712 *arg = current;
713 break;
714 }
715 }
716 if (current == Heap::null_value()) *arg = Heap::undefined_value();
717 }
718 return holder;
719}
720
721
Leon Clarkee46be812010-01-19 14:06:41 +0000722template <bool is_construct>
723static Object* HandleApiCallHelper(
724 BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
725 ASSERT(is_construct == CalledAsConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +0000726
Leon Clarkee46be812010-01-19 14:06:41 +0000727 HandleScope scope;
728 Handle<JSFunction> function = args.called_function();
Steve Blocka7e24c12009-10-30 11:49:00 +0000729
730 if (is_construct) {
731 Handle<FunctionTemplateInfo> desc =
732 Handle<FunctionTemplateInfo>(
733 FunctionTemplateInfo::cast(function->shared()->function_data()));
734 bool pending_exception = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000735 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000736 &pending_exception);
737 ASSERT(Top::has_pending_exception() == pending_exception);
738 if (pending_exception) return Failure::Exception();
739 }
740
741 FunctionTemplateInfo* fun_data =
742 FunctionTemplateInfo::cast(function->shared()->function_data());
743 Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
744
745 if (raw_holder->IsNull()) {
746 // This function cannot be called with the given receiver. Abort!
747 Handle<Object> obj =
748 Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
749 return Top::Throw(*obj);
750 }
751
752 Object* raw_call_data = fun_data->call_code();
753 if (!raw_call_data->IsUndefined()) {
754 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
755 Object* callback_obj = call_data->callback();
756 v8::InvocationCallback callback =
757 v8::ToCData<v8::InvocationCallback>(callback_obj);
758 Object* data_obj = call_data->data();
759 Object* result;
760
Steve Blocka7e24c12009-10-30 11:49:00 +0000761 Handle<Object> data_handle(data_obj);
762 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
763 ASSERT(raw_holder->IsJSObject());
764 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
765 Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
766 v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
Leon Clarkee46be812010-01-19 14:06:41 +0000767 LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +0000768 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
769 data,
770 holder,
771 callee,
772 is_construct,
773 reinterpret_cast<void**>(&args[0] - 1),
774 args.length() - 1);
775
776 v8::Handle<v8::Value> value;
777 {
778 // Leaving JavaScript.
779 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000780#ifdef ENABLE_LOGGING_AND_PROFILING
781 state.set_external_callback(v8::ToCData<Address>(callback_obj));
782#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000783 value = callback(new_args);
784 }
785 if (value.IsEmpty()) {
786 result = Heap::undefined_value();
787 } else {
788 result = *reinterpret_cast<Object**>(*value);
789 }
790
791 RETURN_IF_SCHEDULED_EXCEPTION();
792 if (!is_construct || result->IsJSObject()) return result;
793 }
794
Leon Clarkee46be812010-01-19 14:06:41 +0000795 return *args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +0000796}
Leon Clarkee46be812010-01-19 14:06:41 +0000797
798
799BUILTIN(HandleApiCall) {
800 return HandleApiCallHelper<false>(args);
801}
802
803
804BUILTIN(HandleApiCallConstruct) {
805 return HandleApiCallHelper<true>(args);
806}
Steve Blocka7e24c12009-10-30 11:49:00 +0000807
808
Andrei Popescu402d9372010-02-26 13:31:12 +0000809#ifdef DEBUG
810
811static void VerifyTypeCheck(Handle<JSObject> object,
812 Handle<JSFunction> function) {
813 FunctionTemplateInfo* info =
814 FunctionTemplateInfo::cast(function->shared()->function_data());
815 if (info->signature()->IsUndefined()) return;
816 SignatureInfo* signature = SignatureInfo::cast(info->signature());
817 Object* receiver_type = signature->receiver();
818 if (receiver_type->IsUndefined()) return;
819 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
820 ASSERT(object->IsInstanceOf(type));
821}
822
823#endif
824
825
826BUILTIN(FastHandleApiCall) {
827 ASSERT(!CalledAsConstructor());
828 const bool is_construct = false;
829
830 // We expect four more arguments: function, callback, call data, and holder.
831 const int args_length = args.length() - 4;
832 ASSERT(args_length >= 0);
833
834 Handle<JSFunction> function = args.at<JSFunction>(args_length);
835 Object* callback_obj = args[args_length + 1];
836 Handle<Object> data_handle = args.at<Object>(args_length + 2);
837 Handle<JSObject> checked_holder = args.at<JSObject>(args_length + 3);
838
839#ifdef DEBUG
840 VerifyTypeCheck(checked_holder, function);
841#endif
842
843 v8::Local<v8::Object> holder = v8::Utils::ToLocal(checked_holder);
844 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
845 v8::InvocationCallback callback =
846 v8::ToCData<v8::InvocationCallback>(callback_obj);
847 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
848
849 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
850 data,
851 holder,
852 callee,
853 is_construct,
854 reinterpret_cast<void**>(&args[0] - 1),
855 args_length - 1);
856
857 HandleScope scope;
858 Object* result;
859 v8::Handle<v8::Value> value;
860 {
861 // Leaving JavaScript.
862 VMState state(EXTERNAL);
863#ifdef ENABLE_LOGGING_AND_PROFILING
864 state.set_external_callback(v8::ToCData<Address>(callback_obj));
865#endif
866 value = callback(new_args);
867 }
868 if (value.IsEmpty()) {
869 result = Heap::undefined_value();
870 } else {
871 result = *reinterpret_cast<Object**>(*value);
872 }
873
874 RETURN_IF_SCHEDULED_EXCEPTION();
875 return result;
876}
877
878
Steve Blocka7e24c12009-10-30 11:49:00 +0000879// Helper function to handle calls to non-function objects created through the
880// API. The object can be called as either a constructor (using new) or just as
881// a function (without new).
Leon Clarkee46be812010-01-19 14:06:41 +0000882static Object* HandleApiCallAsFunctionOrConstructor(
883 bool is_construct_call,
884 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000885 // Non-functions are never called as constructors. Even if this is an object
886 // called as a constructor the delegate call is not a construct call.
887 ASSERT(!CalledAsConstructor());
888
889 Handle<Object> receiver = args.at<Object>(0);
890
891 // Get the object called.
Leon Clarkee46be812010-01-19 14:06:41 +0000892 JSObject* obj = JSObject::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000893
894 // Get the invocation callback from the function descriptor that was
895 // used to create the called object.
896 ASSERT(obj->map()->has_instance_call_handler());
897 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
898 Object* template_info = constructor->shared()->function_data();
899 Object* handler =
900 FunctionTemplateInfo::cast(template_info)->instance_call_handler();
901 ASSERT(!handler->IsUndefined());
902 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
903 Object* callback_obj = call_data->callback();
904 v8::InvocationCallback callback =
905 v8::ToCData<v8::InvocationCallback>(callback_obj);
906
907 // Get the data for the call and perform the callback.
908 Object* data_obj = call_data->data();
909 Object* result;
910 { HandleScope scope;
911 v8::Local<v8::Object> self =
Leon Clarkee46be812010-01-19 14:06:41 +0000912 v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000913 Handle<Object> data_handle(data_obj);
914 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
915 Handle<JSFunction> callee_handle(constructor);
916 v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
Leon Clarkee46be812010-01-19 14:06:41 +0000917 LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +0000918 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
919 data,
920 self,
921 callee,
922 is_construct_call,
923 reinterpret_cast<void**>(&args[0] - 1),
924 args.length() - 1);
925 v8::Handle<v8::Value> value;
926 {
927 // Leaving JavaScript.
928 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000929#ifdef ENABLE_LOGGING_AND_PROFILING
930 state.set_external_callback(v8::ToCData<Address>(callback_obj));
931#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000932 value = callback(new_args);
933 }
934 if (value.IsEmpty()) {
935 result = Heap::undefined_value();
936 } else {
937 result = *reinterpret_cast<Object**>(*value);
938 }
939 }
940 // Check for exceptions and return result.
941 RETURN_IF_SCHEDULED_EXCEPTION();
942 return result;
943}
944
945
946// Handle calls to non-function objects created through the API. This delegate
947// function is used when the call is a normal function call.
948BUILTIN(HandleApiCallAsFunction) {
949 return HandleApiCallAsFunctionOrConstructor(false, args);
950}
Steve Blocka7e24c12009-10-30 11:49:00 +0000951
952
953// Handle calls to non-function objects created through the API. This delegate
954// function is used when the call is a construct call.
955BUILTIN(HandleApiCallAsConstructor) {
956 return HandleApiCallAsFunctionOrConstructor(true, args);
957}
Steve Blocka7e24c12009-10-30 11:49:00 +0000958
959
960static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
961 LoadIC::GenerateArrayLength(masm);
962}
963
964
965static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
966 LoadIC::GenerateStringLength(masm);
967}
968
969
970static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
971 LoadIC::GenerateFunctionPrototype(masm);
972}
973
974
975static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
976 LoadIC::GenerateInitialize(masm);
977}
978
979
980static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
981 LoadIC::GeneratePreMonomorphic(masm);
982}
983
984
985static void Generate_LoadIC_Miss(MacroAssembler* masm) {
986 LoadIC::GenerateMiss(masm);
987}
988
989
990static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
991 LoadIC::GenerateMegamorphic(masm);
992}
993
994
995static void Generate_LoadIC_Normal(MacroAssembler* masm) {
996 LoadIC::GenerateNormal(masm);
997}
998
999
1000static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1001 KeyedLoadIC::GenerateInitialize(masm);
1002}
1003
1004
1005static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1006 KeyedLoadIC::GenerateMiss(masm);
1007}
1008
1009
1010static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1011 KeyedLoadIC::GenerateGeneric(masm);
1012}
1013
1014
Leon Clarkee46be812010-01-19 14:06:41 +00001015static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1016 KeyedLoadIC::GenerateString(masm);
1017}
1018
1019
Steve Block3ce2e202009-11-05 08:53:23 +00001020static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
1021 KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
1022}
1023
1024
1025static void Generate_KeyedLoadIC_ExternalUnsignedByteArray(
1026 MacroAssembler* masm) {
1027 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1028}
1029
1030
1031static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) {
1032 KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray);
1033}
1034
1035
1036static void Generate_KeyedLoadIC_ExternalUnsignedShortArray(
1037 MacroAssembler* masm) {
1038 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1039}
1040
1041
1042static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) {
1043 KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray);
1044}
1045
1046
1047static void Generate_KeyedLoadIC_ExternalUnsignedIntArray(
1048 MacroAssembler* masm) {
1049 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1050}
1051
1052
1053static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) {
1054 KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray);
1055}
1056
1057
Steve Blocka7e24c12009-10-30 11:49:00 +00001058static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1059 KeyedLoadIC::GeneratePreMonomorphic(masm);
1060}
1061
Andrei Popescu402d9372010-02-26 13:31:12 +00001062static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1063 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1064}
1065
Steve Blocka7e24c12009-10-30 11:49:00 +00001066
1067static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1068 StoreIC::GenerateInitialize(masm);
1069}
1070
1071
1072static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1073 StoreIC::GenerateMiss(masm);
1074}
1075
1076
Steve Blocka7e24c12009-10-30 11:49:00 +00001077static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
1078 StoreIC::GenerateMegamorphic(masm);
1079}
1080
1081
1082static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
1083 KeyedStoreIC::GenerateGeneric(masm);
1084}
1085
1086
Steve Block3ce2e202009-11-05 08:53:23 +00001087static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) {
1088 KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray);
1089}
1090
1091
1092static void Generate_KeyedStoreIC_ExternalUnsignedByteArray(
1093 MacroAssembler* masm) {
1094 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1095}
1096
1097
1098static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) {
1099 KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray);
1100}
1101
1102
1103static void Generate_KeyedStoreIC_ExternalUnsignedShortArray(
1104 MacroAssembler* masm) {
1105 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1106}
1107
1108
1109static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) {
1110 KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray);
1111}
1112
1113
1114static void Generate_KeyedStoreIC_ExternalUnsignedIntArray(
1115 MacroAssembler* masm) {
1116 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1117}
1118
1119
1120static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) {
1121 KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray);
1122}
1123
1124
Steve Blocka7e24c12009-10-30 11:49:00 +00001125static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1126 KeyedStoreIC::GenerateMiss(masm);
1127}
1128
1129
1130static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1131 KeyedStoreIC::GenerateInitialize(masm);
1132}
1133
1134
1135#ifdef ENABLE_DEBUGGER_SUPPORT
1136static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1137 Debug::GenerateLoadICDebugBreak(masm);
1138}
1139
1140
1141static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1142 Debug::GenerateStoreICDebugBreak(masm);
1143}
1144
1145
1146static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1147 Debug::GenerateKeyedLoadICDebugBreak(masm);
1148}
1149
1150
1151static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1152 Debug::GenerateKeyedStoreICDebugBreak(masm);
1153}
1154
1155
1156static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1157 Debug::GenerateConstructCallDebugBreak(masm);
1158}
1159
1160
1161static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1162 Debug::GenerateReturnDebugBreak(masm);
1163}
1164
1165
1166static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
1167 Debug::GenerateStubNoRegistersDebugBreak(masm);
1168}
1169#endif
1170
1171Object* Builtins::builtins_[builtin_count] = { NULL, };
1172const char* Builtins::names_[builtin_count] = { NULL, };
1173
Leon Clarkee46be812010-01-19 14:06:41 +00001174#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Steve Blocka7e24c12009-10-30 11:49:00 +00001175 Address Builtins::c_functions_[cfunction_count] = {
1176 BUILTIN_LIST_C(DEF_ENUM_C)
1177 };
1178#undef DEF_ENUM_C
1179
1180#define DEF_JS_NAME(name, ignore) #name,
1181#define DEF_JS_ARGC(ignore, argc) argc,
1182const char* Builtins::javascript_names_[id_count] = {
1183 BUILTINS_LIST_JS(DEF_JS_NAME)
1184};
1185
1186int Builtins::javascript_argc_[id_count] = {
1187 BUILTINS_LIST_JS(DEF_JS_ARGC)
1188};
1189#undef DEF_JS_NAME
1190#undef DEF_JS_ARGC
1191
1192static bool is_initialized = false;
1193void Builtins::Setup(bool create_heap_objects) {
1194 ASSERT(!is_initialized);
1195
1196 // Create a scope for the handles in the builtins.
1197 HandleScope scope;
1198
1199 struct BuiltinDesc {
1200 byte* generator;
1201 byte* c_code;
1202 const char* s_name; // name is only used for generating log information.
1203 int name;
1204 Code::Flags flags;
Leon Clarkee46be812010-01-19 14:06:41 +00001205 BuiltinExtraArguments extra_args;
Steve Blocka7e24c12009-10-30 11:49:00 +00001206 };
1207
Leon Clarkee46be812010-01-19 14:06:41 +00001208#define DEF_FUNCTION_PTR_C(name, extra_args) \
1209 { FUNCTION_ADDR(Generate_Adaptor), \
1210 FUNCTION_ADDR(Builtin_##name), \
1211 #name, \
1212 c_##name, \
1213 Code::ComputeFlags(Code::BUILTIN), \
1214 extra_args \
Steve Blocka7e24c12009-10-30 11:49:00 +00001215 },
1216
1217#define DEF_FUNCTION_PTR_A(name, kind, state) \
1218 { FUNCTION_ADDR(Generate_##name), \
1219 NULL, \
1220 #name, \
1221 name, \
Leon Clarkee46be812010-01-19 14:06:41 +00001222 Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
1223 NO_EXTRA_ARGUMENTS \
Steve Blocka7e24c12009-10-30 11:49:00 +00001224 },
1225
1226 // Define array of pointers to generators and C builtin functions.
1227 static BuiltinDesc functions[] = {
1228 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1229 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1230 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1231 // Terminator:
Leon Clarkee46be812010-01-19 14:06:41 +00001232 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
1233 NO_EXTRA_ARGUMENTS }
Steve Blocka7e24c12009-10-30 11:49:00 +00001234 };
1235
1236#undef DEF_FUNCTION_PTR_C
1237#undef DEF_FUNCTION_PTR_A
1238
1239 // For now we generate builtin adaptor code into a stack-allocated
1240 // buffer, before copying it into individual code objects.
1241 byte buffer[4*KB];
1242
1243 // Traverse the list of builtins and generate an adaptor in a
1244 // separate code object for each one.
1245 for (int i = 0; i < builtin_count; i++) {
1246 if (create_heap_objects) {
1247 MacroAssembler masm(buffer, sizeof buffer);
1248 // Generate the code/adaptor.
Leon Clarkee46be812010-01-19 14:06:41 +00001249 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001250 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1251 // We pass all arguments to the generator, but it may not use all of
1252 // them. This works because the first arguments are on top of the
1253 // stack.
Leon Clarkee46be812010-01-19 14:06:41 +00001254 g(&masm, functions[i].name, functions[i].extra_args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001255 // Move the code into the object heap.
1256 CodeDesc desc;
1257 masm.GetCode(&desc);
1258 Code::Flags flags = functions[i].flags;
1259 Object* code;
1260 {
1261 // During startup it's OK to always allocate and defer GC to later.
1262 // This simplifies things because we don't need to retry.
1263 AlwaysAllocateScope __scope__;
1264 code = Heap::CreateCode(desc, NULL, flags, masm.CodeObject());
1265 if (code->IsFailure()) {
1266 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1267 }
1268 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001269 // Log the event and add the code to the builtins array.
1270 LOG(CodeCreateEvent(Logger::BUILTIN_TAG,
1271 Code::cast(code), functions[i].s_name));
1272 builtins_[i] = code;
1273#ifdef ENABLE_DISASSEMBLER
1274 if (FLAG_print_builtin_code) {
1275 PrintF("Builtin: %s\n", functions[i].s_name);
1276 Code::cast(code)->Disassemble(functions[i].s_name);
1277 PrintF("\n");
1278 }
1279#endif
1280 } else {
1281 // Deserializing. The values will be filled in during IterateBuiltins.
1282 builtins_[i] = NULL;
1283 }
1284 names_[i] = functions[i].s_name;
1285 }
1286
1287 // Mark as initialized.
1288 is_initialized = true;
1289}
1290
1291
1292void Builtins::TearDown() {
1293 is_initialized = false;
1294}
1295
1296
1297void Builtins::IterateBuiltins(ObjectVisitor* v) {
1298 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1299}
1300
1301
1302const char* Builtins::Lookup(byte* pc) {
1303 if (is_initialized) { // may be called during initialization (disassembler!)
1304 for (int i = 0; i < builtin_count; i++) {
1305 Code* entry = Code::cast(builtins_[i]);
1306 if (entry->contains(pc)) {
1307 return names_[i];
1308 }
1309 }
1310 }
1311 return NULL;
1312}
1313
1314
1315} } // namespace v8::internal