1 // 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
36 namespace v8 {
37 namespace internal {
38
39 namespace {
40
41 // Arguments object passed to C++ builtins.
42 template <BuiltinExtraArguments extra_args>
43 class BuiltinArguments : public Arguments {
44 public:
BuiltinArguments(int length,Object ** arguments)45 BuiltinArguments(int length, Object** arguments)
46 : Arguments(length, arguments) { }
47
operator [](int index)48 Object*& operator[] (int index) {
49 ASSERT(index < length());
50 return Arguments::operator[](index);
51 }
52
at(int index)53 template <class S> Handle<S> at(int index) {
54 ASSERT(index < length());
55 return Arguments::at<S>(index);
56 }
57
receiver()58 Handle<Object> receiver() {
59 return Arguments::at<Object>(0);
60 }
61
called_function()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).
length() const69 int length() const {
70 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
71 return Arguments::length();
72 }
73
74 #ifdef DEBUG
Verify()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
85 template <>
length() const86 int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
87 return Arguments::length() - 1;
88 }
89
90 #ifdef DEBUG
91 template <>
Verify()92 void 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;
103 BUILTIN_LIST_C(DEF_ARG_TYPE)
104 #undef DEF_ARG_TYPE
105
106 } // namespace
107
108
109 // ----------------------------------------------------------------------------
110 // Support macro for defining builtins in C++.
111 // ----------------------------------------------------------------------------
112 //
113 // A builtin function is defined by writing:
114 //
115 // BUILTIN(name) {
116 // ...
117 // }
118 //
119 // In the body of the builtin function the arguments can be accessed
120 // through the BuiltinArguments object args.
121
122 #ifdef DEBUG
123
124 #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)
131
132 #else // For release mode.
133
134 #define BUILTIN(name) \
135 static Object* Builtin_##name(name##ArgumentsType args)
136
137 #endif
138
139
CalledAsConstructor()140 static 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
BUILTIN(Illegal)171 BUILTIN(Illegal) {
172 UNREACHABLE();
173 return Heap::undefined_value(); // Make compiler happy.
174 }
175
176
BUILTIN(EmptyFunction)177 BUILTIN(EmptyFunction) {
178 return Heap::undefined_value();
179 }
180
181
BUILTIN(ArrayCodeGeneric)182 BUILTIN(ArrayCodeGeneric) {
183 Counters::array_function_runtime.Increment();
184
185 JSArray* array;
186 if (CalledAsConstructor()) {
187 array = JSArray::cast(*args.receiver());
188 } 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;
228
229 AssertNoAllocation no_gc;
230 FixedArray* elms = FixedArray::cast(obj);
231 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
232 // 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));
239 array->set_length(len);
240
241 return array;
242 }
243
244
BUILTIN(ArrayPush)245 BUILTIN(ArrayPush) {
246 JSArray* array = JSArray::cast(*args.receiver());
247 ASSERT(array->HasFastElements());
248
249 int len = Smi::cast(array->length())->value();
250 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));
257
258 int new_length = len + to_add;
259 FixedArray* elms = FixedArray::cast(array->elements());
260
261 if (new_length > elms->length()) {
262 // 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;
266
267 AssertNoAllocation no_gc;
268 FixedArray* new_elms = FixedArray::cast(obj);
269 WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
270 // Fill out the new array with old elements.
271 for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
272 elms = new_elms;
273 array->set_elements(elms);
274 }
275
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
284 // Set the length.
285 array->set_length(Smi::FromInt(new_length));
286 return Smi::FromInt(new_length);
287 }
288
289
BUILTIN(ArrayPop)290 BUILTIN(ArrayPop) {
291 JSArray* array = JSArray::cast(*args.receiver());
292 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.
303 array->set_length(Smi::FromInt(len - 1));
304
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 }
319
320
GetElementToMove(uint32_t index,FixedArray * elms,JSObject * prototype)321 static 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
BUILTIN(ArrayShift)332 BUILTIN(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
BUILTIN(ArrayUnshift)365 BUILTIN(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
CallJsBuiltin(const char * name,BuiltinArguments<NO_EXTRA_ARGUMENTS> args)429 static 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
BUILTIN(ArraySlice)454 BUILTIN(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
BUILTIN(ArraySplice)532 BUILTIN(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
670 // -----------------------------------------------------------------------------
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.
TypeCheck(int argc,Object ** argv,FunctionTemplateInfo * info)680 static 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
722 template <bool is_construct>
HandleApiCallHelper(BuiltinArguments<NEEDS_CALLED_FUNCTION> args)723 static Object* HandleApiCallHelper(
724 BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
725 ASSERT(is_construct == CalledAsConstructor());
726
727 HandleScope scope;
728 Handle<JSFunction> function = args.called_function();
729
730 if (is_construct) {
731 Handle<FunctionTemplateInfo> desc =
732 Handle<FunctionTemplateInfo>(
733 FunctionTemplateInfo::cast(function->shared()->function_data()));
734 bool pending_exception = false;
735 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
736 &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
761 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);
767 LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
768 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);
780 #ifdef ENABLE_LOGGING_AND_PROFILING
781 state.set_external_callback(v8::ToCData<Address>(callback_obj));
782 #endif
783 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
795 return *args.receiver();
796 }
797
798
BUILTIN(HandleApiCall)799 BUILTIN(HandleApiCall) {
800 return HandleApiCallHelper<false>(args);
801 }
802
803
BUILTIN(HandleApiCallConstruct)804 BUILTIN(HandleApiCallConstruct) {
805 return HandleApiCallHelper<true>(args);
806 }
807
808
809 #ifdef DEBUG
810
VerifyTypeCheck(Handle<JSObject> object,Handle<JSFunction> function)811 static 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
BUILTIN(FastHandleApiCall)826 BUILTIN(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
879 // 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).
HandleApiCallAsFunctionOrConstructor(bool is_construct_call,BuiltinArguments<NO_EXTRA_ARGUMENTS> args)882 static Object* HandleApiCallAsFunctionOrConstructor(
883 bool is_construct_call,
884 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
885 // 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.
892 JSObject* obj = JSObject::cast(*args.receiver());
893
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 =
912 v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver()));
913 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);
917 LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver())));
918 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);
929 #ifdef ENABLE_LOGGING_AND_PROFILING
930 state.set_external_callback(v8::ToCData<Address>(callback_obj));
931 #endif
932 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.
BUILTIN(HandleApiCallAsFunction)948 BUILTIN(HandleApiCallAsFunction) {
949 return HandleApiCallAsFunctionOrConstructor(false, args);
950 }
951
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.
BUILTIN(HandleApiCallAsConstructor)955 BUILTIN(HandleApiCallAsConstructor) {
956 return HandleApiCallAsFunctionOrConstructor(true, args);
957 }
958
959
Generate_LoadIC_ArrayLength(MacroAssembler * masm)960 static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
961 LoadIC::GenerateArrayLength(masm);
962 }
963
964
Generate_LoadIC_StringLength(MacroAssembler * masm)965 static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
966 LoadIC::GenerateStringLength(masm);
967 }
968
969
Generate_LoadIC_FunctionPrototype(MacroAssembler * masm)970 static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
971 LoadIC::GenerateFunctionPrototype(masm);
972 }
973
974
Generate_LoadIC_Initialize(MacroAssembler * masm)975 static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
976 LoadIC::GenerateInitialize(masm);
977 }
978
979
Generate_LoadIC_PreMonomorphic(MacroAssembler * masm)980 static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
981 LoadIC::GeneratePreMonomorphic(masm);
982 }
983
984
Generate_LoadIC_Miss(MacroAssembler * masm)985 static void Generate_LoadIC_Miss(MacroAssembler* masm) {
986 LoadIC::GenerateMiss(masm);
987 }
988
989
Generate_LoadIC_Megamorphic(MacroAssembler * masm)990 static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
991 LoadIC::GenerateMegamorphic(masm);
992 }
993
994
Generate_LoadIC_Normal(MacroAssembler * masm)995 static void Generate_LoadIC_Normal(MacroAssembler* masm) {
996 LoadIC::GenerateNormal(masm);
997 }
998
999
Generate_KeyedLoadIC_Initialize(MacroAssembler * masm)1000 static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1001 KeyedLoadIC::GenerateInitialize(masm);
1002 }
1003
1004
Generate_KeyedLoadIC_Miss(MacroAssembler * masm)1005 static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1006 KeyedLoadIC::GenerateMiss(masm);
1007 }
1008
1009
Generate_KeyedLoadIC_Generic(MacroAssembler * masm)1010 static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1011 KeyedLoadIC::GenerateGeneric(masm);
1012 }
1013
1014
Generate_KeyedLoadIC_String(MacroAssembler * masm)1015 static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1016 KeyedLoadIC::GenerateString(masm);
1017 }
1018
1019
Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler * masm)1020 static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
1021 KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
1022 }
1023
1024
Generate_KeyedLoadIC_ExternalUnsignedByteArray(MacroAssembler * masm)1025 static void Generate_KeyedLoadIC_ExternalUnsignedByteArray(
1026 MacroAssembler* masm) {
1027 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1028 }
1029
1030
Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler * masm)1031 static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) {
1032 KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray);
1033 }
1034
1035
Generate_KeyedLoadIC_ExternalUnsignedShortArray(MacroAssembler * masm)1036 static void Generate_KeyedLoadIC_ExternalUnsignedShortArray(
1037 MacroAssembler* masm) {
1038 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1039 }
1040
1041
Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler * masm)1042 static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) {
1043 KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray);
1044 }
1045
1046
Generate_KeyedLoadIC_ExternalUnsignedIntArray(MacroAssembler * masm)1047 static void Generate_KeyedLoadIC_ExternalUnsignedIntArray(
1048 MacroAssembler* masm) {
1049 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1050 }
1051
1052
Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler * masm)1053 static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) {
1054 KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray);
1055 }
1056
1057
Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler * masm)1058 static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1059 KeyedLoadIC::GeneratePreMonomorphic(masm);
1060 }
1061
Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler * masm)1062 static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1063 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1064 }
1065
1066
Generate_StoreIC_Initialize(MacroAssembler * masm)1067 static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1068 StoreIC::GenerateInitialize(masm);
1069 }
1070
1071
Generate_StoreIC_Miss(MacroAssembler * masm)1072 static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1073 StoreIC::GenerateMiss(masm);
1074 }
1075
1076
Generate_StoreIC_Megamorphic(MacroAssembler * masm)1077 static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
1078 StoreIC::GenerateMegamorphic(masm);
1079 }
1080
1081
Generate_KeyedStoreIC_Generic(MacroAssembler * masm)1082 static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
1083 KeyedStoreIC::GenerateGeneric(masm);
1084 }
1085
1086
Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler * masm)1087 static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) {
1088 KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray);
1089 }
1090
1091
Generate_KeyedStoreIC_ExternalUnsignedByteArray(MacroAssembler * masm)1092 static void Generate_KeyedStoreIC_ExternalUnsignedByteArray(
1093 MacroAssembler* masm) {
1094 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1095 }
1096
1097
Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler * masm)1098 static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) {
1099 KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray);
1100 }
1101
1102
Generate_KeyedStoreIC_ExternalUnsignedShortArray(MacroAssembler * masm)1103 static void Generate_KeyedStoreIC_ExternalUnsignedShortArray(
1104 MacroAssembler* masm) {
1105 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1106 }
1107
1108
Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler * masm)1109 static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) {
1110 KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray);
1111 }
1112
1113
Generate_KeyedStoreIC_ExternalUnsignedIntArray(MacroAssembler * masm)1114 static void Generate_KeyedStoreIC_ExternalUnsignedIntArray(
1115 MacroAssembler* masm) {
1116 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1117 }
1118
1119
Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler * masm)1120 static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) {
1121 KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray);
1122 }
1123
1124
Generate_KeyedStoreIC_Miss(MacroAssembler * masm)1125 static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1126 KeyedStoreIC::GenerateMiss(masm);
1127 }
1128
1129
Generate_KeyedStoreIC_Initialize(MacroAssembler * masm)1130 static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1131 KeyedStoreIC::GenerateInitialize(masm);
1132 }
1133
1134
1135 #ifdef ENABLE_DEBUGGER_SUPPORT
Generate_LoadIC_DebugBreak(MacroAssembler * masm)1136 static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1137 Debug::GenerateLoadICDebugBreak(masm);
1138 }
1139
1140
Generate_StoreIC_DebugBreak(MacroAssembler * masm)1141 static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1142 Debug::GenerateStoreICDebugBreak(masm);
1143 }
1144
1145
Generate_KeyedLoadIC_DebugBreak(MacroAssembler * masm)1146 static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1147 Debug::GenerateKeyedLoadICDebugBreak(masm);
1148 }
1149
1150
Generate_KeyedStoreIC_DebugBreak(MacroAssembler * masm)1151 static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1152 Debug::GenerateKeyedStoreICDebugBreak(masm);
1153 }
1154
1155
Generate_ConstructCall_DebugBreak(MacroAssembler * masm)1156 static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1157 Debug::GenerateConstructCallDebugBreak(masm);
1158 }
1159
1160
Generate_Return_DebugBreak(MacroAssembler * masm)1161 static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1162 Debug::GenerateReturnDebugBreak(masm);
1163 }
1164
1165
Generate_StubNoRegisters_DebugBreak(MacroAssembler * masm)1166 static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
1167 Debug::GenerateStubNoRegistersDebugBreak(masm);
1168 }
1169 #endif
1170
1171 Object* Builtins::builtins_[builtin_count] = { NULL, };
1172 const char* Builtins::names_[builtin_count] = { NULL, };
1173
1174 #define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
1175 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,
1182 const char* Builtins::javascript_names_[id_count] = {
1183 BUILTINS_LIST_JS(DEF_JS_NAME)
1184 };
1185
1186 int Builtins::javascript_argc_[id_count] = {
1187 BUILTINS_LIST_JS(DEF_JS_ARGC)
1188 };
1189 #undef DEF_JS_NAME
1190 #undef DEF_JS_ARGC
1191
1192 static bool is_initialized = false;
Setup(bool create_heap_objects)1193 void 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;
1205 BuiltinExtraArguments extra_args;
1206 };
1207
1208 #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 \
1215 },
1216
1217 #define DEF_FUNCTION_PTR_A(name, kind, state) \
1218 { FUNCTION_ADDR(Generate_##name), \
1219 NULL, \
1220 #name, \
1221 name, \
1222 Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
1223 NO_EXTRA_ARGUMENTS \
1224 },
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:
1232 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
1233 NO_EXTRA_ARGUMENTS }
1234 };
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.
1249 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
1250 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.
1254 g(&masm, functions[i].name, functions[i].extra_args);
1255 // 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 }
1269 // 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
TearDown()1292 void Builtins::TearDown() {
1293 is_initialized = false;
1294 }
1295
1296
IterateBuiltins(ObjectVisitor * v)1297 void Builtins::IterateBuiltins(ObjectVisitor* v) {
1298 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1299 }
1300
1301
Lookup(byte * pc)1302 const 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
1316