• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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