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 "gdb-jit.h"
35 #include "ic-inl.h"
36 #include "vm-state-inl.h"
37
38 namespace v8 {
39 namespace internal {
40
41 namespace {
42
43 // Arguments object passed to C++ builtins.
44 template <BuiltinExtraArguments extra_args>
45 class BuiltinArguments : public Arguments {
46 public:
BuiltinArguments(int length,Object ** arguments)47 BuiltinArguments(int length, Object** arguments)
48 : Arguments(length, arguments) { }
49
operator [](int index)50 Object*& operator[] (int index) {
51 ASSERT(index < length());
52 return Arguments::operator[](index);
53 }
54
at(int index)55 template <class S> Handle<S> at(int index) {
56 ASSERT(index < length());
57 return Arguments::at<S>(index);
58 }
59
receiver()60 Handle<Object> receiver() {
61 return Arguments::at<Object>(0);
62 }
63
called_function()64 Handle<JSFunction> called_function() {
65 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
66 return Arguments::at<JSFunction>(Arguments::length() - 1);
67 }
68
69 // Gets the total number of arguments including the receiver (but
70 // excluding extra arguments).
length() const71 int length() const {
72 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
73 return Arguments::length();
74 }
75
76 #ifdef DEBUG
Verify()77 void Verify() {
78 // Check we have at least the receiver.
79 ASSERT(Arguments::length() >= 1);
80 }
81 #endif
82 };
83
84
85 // Specialize BuiltinArguments for the called function extra argument.
86
87 template <>
length() const88 int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
89 return Arguments::length() - 1;
90 }
91
92 #ifdef DEBUG
93 template <>
Verify()94 void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
95 // Check we have at least the receiver and the called function.
96 ASSERT(Arguments::length() >= 2);
97 // Make sure cast to JSFunction succeeds.
98 called_function();
99 }
100 #endif
101
102
103 #define DEF_ARG_TYPE(name, spec) \
104 typedef BuiltinArguments<spec> name##ArgumentsType;
105 BUILTIN_LIST_C(DEF_ARG_TYPE)
106 #undef DEF_ARG_TYPE
107
108 } // namespace
109
110 // ----------------------------------------------------------------------------
111 // Support macro for defining builtins in C++.
112 // ----------------------------------------------------------------------------
113 //
114 // A builtin function is defined by writing:
115 //
116 // BUILTIN(name) {
117 // ...
118 // }
119 //
120 // In the body of the builtin function the arguments can be accessed
121 // through the BuiltinArguments object args.
122
123 #ifdef DEBUG
124
125 #define BUILTIN(name) \
126 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
127 name##ArgumentsType args, Isolate* isolate); \
128 MUST_USE_RESULT static MaybeObject* Builtin_##name( \
129 name##ArgumentsType args, Isolate* isolate) { \
130 ASSERT(isolate == Isolate::Current()); \
131 args.Verify(); \
132 return Builtin_Impl_##name(args, isolate); \
133 } \
134 MUST_USE_RESULT static MaybeObject* Builtin_Impl_##name( \
135 name##ArgumentsType args, Isolate* isolate)
136
137 #else // For release mode.
138
139 #define BUILTIN(name) \
140 static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate)
141
142 #endif
143
144
CalledAsConstructor(Isolate * isolate)145 static inline bool CalledAsConstructor(Isolate* isolate) {
146 #ifdef DEBUG
147 // Calculate the result using a full stack frame iterator and check
148 // that the state of the stack is as we assume it to be in the
149 // code below.
150 StackFrameIterator it;
151 ASSERT(it.frame()->is_exit());
152 it.Advance();
153 StackFrame* frame = it.frame();
154 bool reference_result = frame->is_construct();
155 #endif
156 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
157 // Because we know fp points to an exit frame we can use the relevant
158 // part of ExitFrame::ComputeCallerState directly.
159 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
160 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
161 // This inlines the part of StackFrame::ComputeType that grabs the
162 // type of the current frame. Note that StackFrame::ComputeType
163 // has been specialized for each architecture so if any one of them
164 // changes this code has to be changed as well.
165 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
166 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
167 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
168 bool result = (marker == kConstructMarker);
169 ASSERT_EQ(result, reference_result);
170 return result;
171 }
172
173 // ----------------------------------------------------------------------------
174
BUILTIN(Illegal)175 BUILTIN(Illegal) {
176 UNREACHABLE();
177 return isolate->heap()->undefined_value(); // Make compiler happy.
178 }
179
180
BUILTIN(EmptyFunction)181 BUILTIN(EmptyFunction) {
182 return isolate->heap()->undefined_value();
183 }
184
185
BUILTIN(ArrayCodeGeneric)186 BUILTIN(ArrayCodeGeneric) {
187 Heap* heap = isolate->heap();
188 isolate->counters()->array_function_runtime()->Increment();
189
190 JSArray* array;
191 if (CalledAsConstructor(isolate)) {
192 array = JSArray::cast(*args.receiver());
193 } else {
194 // Allocate the JS Array
195 JSFunction* constructor =
196 isolate->context()->global_context()->array_function();
197 Object* obj;
198 { MaybeObject* maybe_obj = heap->AllocateJSObject(constructor);
199 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
200 }
201 array = JSArray::cast(obj);
202 }
203
204 // 'array' now contains the JSArray we should initialize.
205 ASSERT(array->HasFastElements());
206
207 // Optimize the case where there is one argument and the argument is a
208 // small smi.
209 if (args.length() == 2) {
210 Object* obj = args[1];
211 if (obj->IsSmi()) {
212 int len = Smi::cast(obj)->value();
213 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
214 Object* obj;
215 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
216 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
217 }
218 array->SetContent(FixedArray::cast(obj));
219 return array;
220 }
221 }
222 // Take the argument as the length.
223 { MaybeObject* maybe_obj = array->Initialize(0);
224 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
225 }
226 return array->SetElementsLength(args[1]);
227 }
228
229 // Optimize the case where there are no parameters passed.
230 if (args.length() == 1) {
231 return array->Initialize(JSArray::kPreallocatedArrayElements);
232 }
233
234 // Take the arguments as elements.
235 int number_of_elements = args.length() - 1;
236 Smi* len = Smi::FromInt(number_of_elements);
237 Object* obj;
238 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len->value());
239 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
240 }
241
242 AssertNoAllocation no_gc;
243 FixedArray* elms = FixedArray::cast(obj);
244 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
245 // Fill in the content
246 for (int index = 0; index < number_of_elements; index++) {
247 elms->set(index, args[index+1], mode);
248 }
249
250 // Set length and elements on the array.
251 array->set_elements(FixedArray::cast(obj));
252 array->set_length(len);
253
254 return array;
255 }
256
257
AllocateJSArray(Heap * heap)258 MUST_USE_RESULT static MaybeObject* AllocateJSArray(Heap* heap) {
259 JSFunction* array_function =
260 heap->isolate()->context()->global_context()->array_function();
261 Object* result;
262 { MaybeObject* maybe_result = heap->AllocateJSObject(array_function);
263 if (!maybe_result->ToObject(&result)) return maybe_result;
264 }
265 return result;
266 }
267
268
AllocateEmptyJSArray(Heap * heap)269 MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray(Heap* heap) {
270 Object* result;
271 { MaybeObject* maybe_result = AllocateJSArray(heap);
272 if (!maybe_result->ToObject(&result)) return maybe_result;
273 }
274 JSArray* result_array = JSArray::cast(result);
275 result_array->set_length(Smi::FromInt(0));
276 result_array->set_elements(heap->empty_fixed_array());
277 return result_array;
278 }
279
280
CopyElements(Heap * heap,AssertNoAllocation * no_gc,FixedArray * dst,int dst_index,FixedArray * src,int src_index,int len)281 static void CopyElements(Heap* heap,
282 AssertNoAllocation* no_gc,
283 FixedArray* dst,
284 int dst_index,
285 FixedArray* src,
286 int src_index,
287 int len) {
288 ASSERT(dst != src); // Use MoveElements instead.
289 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
290 ASSERT(len > 0);
291 CopyWords(dst->data_start() + dst_index,
292 src->data_start() + src_index,
293 len);
294 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
295 if (mode == UPDATE_WRITE_BARRIER) {
296 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
297 }
298 }
299
300
MoveElements(Heap * heap,AssertNoAllocation * no_gc,FixedArray * dst,int dst_index,FixedArray * src,int src_index,int len)301 static void MoveElements(Heap* heap,
302 AssertNoAllocation* no_gc,
303 FixedArray* dst,
304 int dst_index,
305 FixedArray* src,
306 int src_index,
307 int len) {
308 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
309 memmove(dst->data_start() + dst_index,
310 src->data_start() + src_index,
311 len * kPointerSize);
312 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
313 if (mode == UPDATE_WRITE_BARRIER) {
314 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
315 }
316 }
317
318
FillWithHoles(Heap * heap,FixedArray * dst,int from,int to)319 static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) {
320 ASSERT(dst->map() != heap->fixed_cow_array_map());
321 MemsetPointer(dst->data_start() + from, heap->the_hole_value(), to - from);
322 }
323
324
LeftTrimFixedArray(Heap * heap,FixedArray * elms,int to_trim)325 static FixedArray* LeftTrimFixedArray(Heap* heap,
326 FixedArray* elms,
327 int to_trim) {
328 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
329 // For now this trick is only applied to fixed arrays in new and paged space.
330 // In large object space the object's start must coincide with chunk
331 // and thus the trick is just not applicable.
332 ASSERT(!HEAP->lo_space()->Contains(elms));
333
334 STATIC_ASSERT(FixedArray::kMapOffset == 0);
335 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
336 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
337
338 Object** former_start = HeapObject::RawField(elms, 0);
339
340 const int len = elms->length();
341
342 if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
343 !heap->new_space()->Contains(elms)) {
344 // If we are doing a big trim in old space then we zap the space that was
345 // formerly part of the array so that the GC (aided by the card-based
346 // remembered set) won't find pointers to new-space there.
347 Object** zap = reinterpret_cast<Object**>(elms->address());
348 zap++; // Header of filler must be at least one word so skip that.
349 for (int i = 1; i < to_trim; i++) {
350 *zap++ = Smi::FromInt(0);
351 }
352 }
353 // Technically in new space this write might be omitted (except for
354 // debug mode which iterates through the heap), but to play safer
355 // we still do it.
356 heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
357
358 former_start[to_trim] = heap->fixed_array_map();
359 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
360
361 return FixedArray::cast(HeapObject::FromAddress(
362 elms->address() + to_trim * kPointerSize));
363 }
364
365
ArrayPrototypeHasNoElements(Heap * heap,Context * global_context,JSObject * array_proto)366 static bool ArrayPrototypeHasNoElements(Heap* heap,
367 Context* global_context,
368 JSObject* array_proto) {
369 // This method depends on non writability of Object and Array prototype
370 // fields.
371 if (array_proto->elements() != heap->empty_fixed_array()) return false;
372 // Hidden prototype
373 array_proto = JSObject::cast(array_proto->GetPrototype());
374 ASSERT(array_proto->elements() == heap->empty_fixed_array());
375 // Object.prototype
376 Object* proto = array_proto->GetPrototype();
377 if (proto == heap->null_value()) return false;
378 array_proto = JSObject::cast(proto);
379 if (array_proto != global_context->initial_object_prototype()) return false;
380 if (array_proto->elements() != heap->empty_fixed_array()) return false;
381 return array_proto->GetPrototype()->IsNull();
382 }
383
384
385 MUST_USE_RESULT
EnsureJSArrayWithWritableFastElements(Heap * heap,Object * receiver)386 static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
387 Heap* heap, Object* receiver) {
388 if (!receiver->IsJSArray()) return NULL;
389 JSArray* array = JSArray::cast(receiver);
390 HeapObject* elms = array->elements();
391 if (elms->map() == heap->fixed_array_map()) return elms;
392 if (elms->map() == heap->fixed_cow_array_map()) {
393 return array->EnsureWritableFastElements();
394 }
395 return NULL;
396 }
397
398
IsJSArrayFastElementMovingAllowed(Heap * heap,JSArray * receiver)399 static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
400 JSArray* receiver) {
401 Context* global_context = heap->isolate()->context()->global_context();
402 JSObject* array_proto =
403 JSObject::cast(global_context->array_function()->prototype());
404 return receiver->GetPrototype() == array_proto &&
405 ArrayPrototypeHasNoElements(heap, global_context, array_proto);
406 }
407
408
CallJsBuiltin(Isolate * isolate,const char * name,BuiltinArguments<NO_EXTRA_ARGUMENTS> args)409 MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
410 Isolate* isolate,
411 const char* name,
412 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
413 HandleScope handleScope(isolate);
414
415 Handle<Object> js_builtin =
416 GetProperty(Handle<JSObject>(
417 isolate->global_context()->builtins()),
418 name);
419 ASSERT(js_builtin->IsJSFunction());
420 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
421 ScopedVector<Object**> argv(args.length() - 1);
422 int n_args = args.length() - 1;
423 for (int i = 0; i < n_args; i++) {
424 argv[i] = args.at<Object>(i + 1).location();
425 }
426 bool pending_exception = false;
427 Handle<Object> result = Execution::Call(function,
428 args.receiver(),
429 n_args,
430 argv.start(),
431 &pending_exception);
432 if (pending_exception) return Failure::Exception();
433 return *result;
434 }
435
436
BUILTIN(ArrayPush)437 BUILTIN(ArrayPush) {
438 Heap* heap = isolate->heap();
439 Object* receiver = *args.receiver();
440 Object* elms_obj;
441 { MaybeObject* maybe_elms_obj =
442 EnsureJSArrayWithWritableFastElements(heap, receiver);
443 if (maybe_elms_obj == NULL) {
444 return CallJsBuiltin(isolate, "ArrayPush", args);
445 }
446 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
447 }
448 FixedArray* elms = FixedArray::cast(elms_obj);
449 JSArray* array = JSArray::cast(receiver);
450
451 int len = Smi::cast(array->length())->value();
452 int to_add = args.length() - 1;
453 if (to_add == 0) {
454 return Smi::FromInt(len);
455 }
456 // Currently fixed arrays cannot grow too big, so
457 // we should never hit this case.
458 ASSERT(to_add <= (Smi::kMaxValue - len));
459
460 int new_length = len + to_add;
461
462 if (new_length > elms->length()) {
463 // New backing storage is needed.
464 int capacity = new_length + (new_length >> 1) + 16;
465 Object* obj;
466 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
467 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
468 }
469 FixedArray* new_elms = FixedArray::cast(obj);
470
471 AssertNoAllocation no_gc;
472 if (len > 0) {
473 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, len);
474 }
475 FillWithHoles(heap, new_elms, new_length, capacity);
476
477 elms = new_elms;
478 array->set_elements(elms);
479 }
480
481 // Add the provided values.
482 AssertNoAllocation no_gc;
483 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
484 for (int index = 0; index < to_add; index++) {
485 elms->set(index + len, args[index + 1], mode);
486 }
487
488 // Set the length.
489 array->set_length(Smi::FromInt(new_length));
490 return Smi::FromInt(new_length);
491 }
492
493
BUILTIN(ArrayPop)494 BUILTIN(ArrayPop) {
495 Heap* heap = isolate->heap();
496 Object* receiver = *args.receiver();
497 Object* elms_obj;
498 { MaybeObject* maybe_elms_obj =
499 EnsureJSArrayWithWritableFastElements(heap, receiver);
500 if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
501 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
502 }
503 FixedArray* elms = FixedArray::cast(elms_obj);
504 JSArray* array = JSArray::cast(receiver);
505
506 int len = Smi::cast(array->length())->value();
507 if (len == 0) return heap->undefined_value();
508
509 // Get top element
510 MaybeObject* top = elms->get(len - 1);
511
512 // Set the length.
513 array->set_length(Smi::FromInt(len - 1));
514
515 if (!top->IsTheHole()) {
516 // Delete the top element.
517 elms->set_the_hole(len - 1);
518 return top;
519 }
520
521 top = array->GetPrototype()->GetElement(len - 1);
522
523 return top;
524 }
525
526
BUILTIN(ArrayShift)527 BUILTIN(ArrayShift) {
528 Heap* heap = isolate->heap();
529 Object* receiver = *args.receiver();
530 Object* elms_obj;
531 { MaybeObject* maybe_elms_obj =
532 EnsureJSArrayWithWritableFastElements(heap, receiver);
533 if (maybe_elms_obj == NULL)
534 return CallJsBuiltin(isolate, "ArrayShift", args);
535 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
536 }
537 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
538 return CallJsBuiltin(isolate, "ArrayShift", args);
539 }
540 FixedArray* elms = FixedArray::cast(elms_obj);
541 JSArray* array = JSArray::cast(receiver);
542 ASSERT(array->HasFastElements());
543
544 int len = Smi::cast(array->length())->value();
545 if (len == 0) return heap->undefined_value();
546
547 // Get first element
548 Object* first = elms->get(0);
549 if (first->IsTheHole()) {
550 first = heap->undefined_value();
551 }
552
553 if (!heap->lo_space()->Contains(elms)) {
554 // As elms still in the same space they used to be,
555 // there is no need to update region dirty mark.
556 array->set_elements(LeftTrimFixedArray(heap, elms, 1), SKIP_WRITE_BARRIER);
557 } else {
558 // Shift the elements.
559 AssertNoAllocation no_gc;
560 MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
561 elms->set(len - 1, heap->the_hole_value());
562 }
563
564 // Set the length.
565 array->set_length(Smi::FromInt(len - 1));
566
567 return first;
568 }
569
570
BUILTIN(ArrayUnshift)571 BUILTIN(ArrayUnshift) {
572 Heap* heap = isolate->heap();
573 Object* receiver = *args.receiver();
574 Object* elms_obj;
575 { MaybeObject* maybe_elms_obj =
576 EnsureJSArrayWithWritableFastElements(heap, receiver);
577 if (maybe_elms_obj == NULL)
578 return CallJsBuiltin(isolate, "ArrayUnshift", args);
579 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
580 }
581 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
582 return CallJsBuiltin(isolate, "ArrayUnshift", args);
583 }
584 FixedArray* elms = FixedArray::cast(elms_obj);
585 JSArray* array = JSArray::cast(receiver);
586 ASSERT(array->HasFastElements());
587
588 int len = Smi::cast(array->length())->value();
589 int to_add = args.length() - 1;
590 int new_length = len + to_add;
591 // Currently fixed arrays cannot grow too big, so
592 // we should never hit this case.
593 ASSERT(to_add <= (Smi::kMaxValue - len));
594
595 if (new_length > elms->length()) {
596 // New backing storage is needed.
597 int capacity = new_length + (new_length >> 1) + 16;
598 Object* obj;
599 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
600 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
601 }
602 FixedArray* new_elms = FixedArray::cast(obj);
603
604 AssertNoAllocation no_gc;
605 if (len > 0) {
606 CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len);
607 }
608 FillWithHoles(heap, new_elms, new_length, capacity);
609
610 elms = new_elms;
611 array->set_elements(elms);
612 } else {
613 AssertNoAllocation no_gc;
614 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len);
615 }
616
617 // Add the provided values.
618 AssertNoAllocation no_gc;
619 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
620 for (int i = 0; i < to_add; i++) {
621 elms->set(i, args[i + 1], mode);
622 }
623
624 // Set the length.
625 array->set_length(Smi::FromInt(new_length));
626 return Smi::FromInt(new_length);
627 }
628
629
BUILTIN(ArraySlice)630 BUILTIN(ArraySlice) {
631 Heap* heap = isolate->heap();
632 Object* receiver = *args.receiver();
633 FixedArray* elms;
634 int len = -1;
635 if (receiver->IsJSArray()) {
636 JSArray* array = JSArray::cast(receiver);
637 if (!array->HasFastElements() ||
638 !IsJSArrayFastElementMovingAllowed(heap, array)) {
639 return CallJsBuiltin(isolate, "ArraySlice", args);
640 }
641
642 elms = FixedArray::cast(array->elements());
643 len = Smi::cast(array->length())->value();
644 } else {
645 // Array.slice(arguments, ...) is quite a common idiom (notably more
646 // than 50% of invocations in Web apps). Treat it in C++ as well.
647 Map* arguments_map =
648 isolate->context()->global_context()->arguments_boilerplate()->map();
649
650 bool is_arguments_object_with_fast_elements =
651 receiver->IsJSObject()
652 && JSObject::cast(receiver)->map() == arguments_map
653 && JSObject::cast(receiver)->HasFastElements();
654 if (!is_arguments_object_with_fast_elements) {
655 return CallJsBuiltin(isolate, "ArraySlice", args);
656 }
657 elms = FixedArray::cast(JSObject::cast(receiver)->elements());
658 Object* len_obj = JSObject::cast(receiver)
659 ->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
660 if (!len_obj->IsSmi()) {
661 return CallJsBuiltin(isolate, "ArraySlice", args);
662 }
663 len = Smi::cast(len_obj)->value();
664 if (len > elms->length()) {
665 return CallJsBuiltin(isolate, "ArraySlice", args);
666 }
667 for (int i = 0; i < len; i++) {
668 if (elms->get(i) == heap->the_hole_value()) {
669 return CallJsBuiltin(isolate, "ArraySlice", args);
670 }
671 }
672 }
673 ASSERT(len >= 0);
674 int n_arguments = args.length() - 1;
675
676 // Note carefully choosen defaults---if argument is missing,
677 // it's undefined which gets converted to 0 for relative_start
678 // and to len for relative_end.
679 int relative_start = 0;
680 int relative_end = len;
681 if (n_arguments > 0) {
682 Object* arg1 = args[1];
683 if (arg1->IsSmi()) {
684 relative_start = Smi::cast(arg1)->value();
685 } else if (!arg1->IsUndefined()) {
686 return CallJsBuiltin(isolate, "ArraySlice", args);
687 }
688 if (n_arguments > 1) {
689 Object* arg2 = args[2];
690 if (arg2->IsSmi()) {
691 relative_end = Smi::cast(arg2)->value();
692 } else if (!arg2->IsUndefined()) {
693 return CallJsBuiltin(isolate, "ArraySlice", args);
694 }
695 }
696 }
697
698 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
699 int k = (relative_start < 0) ? Max(len + relative_start, 0)
700 : Min(relative_start, len);
701
702 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
703 int final = (relative_end < 0) ? Max(len + relative_end, 0)
704 : Min(relative_end, len);
705
706 // Calculate the length of result array.
707 int result_len = final - k;
708 if (result_len <= 0) {
709 return AllocateEmptyJSArray(heap);
710 }
711
712 Object* result;
713 { MaybeObject* maybe_result = AllocateJSArray(heap);
714 if (!maybe_result->ToObject(&result)) return maybe_result;
715 }
716 JSArray* result_array = JSArray::cast(result);
717
718 { MaybeObject* maybe_result =
719 heap->AllocateUninitializedFixedArray(result_len);
720 if (!maybe_result->ToObject(&result)) return maybe_result;
721 }
722 FixedArray* result_elms = FixedArray::cast(result);
723
724 AssertNoAllocation no_gc;
725 CopyElements(heap, &no_gc, result_elms, 0, elms, k, result_len);
726
727 // Set elements.
728 result_array->set_elements(result_elms);
729
730 // Set the length.
731 result_array->set_length(Smi::FromInt(result_len));
732 return result_array;
733 }
734
735
BUILTIN(ArraySplice)736 BUILTIN(ArraySplice) {
737 Heap* heap = isolate->heap();
738 Object* receiver = *args.receiver();
739 Object* elms_obj;
740 { MaybeObject* maybe_elms_obj =
741 EnsureJSArrayWithWritableFastElements(heap, receiver);
742 if (maybe_elms_obj == NULL)
743 return CallJsBuiltin(isolate, "ArraySplice", args);
744 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
745 }
746 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
747 return CallJsBuiltin(isolate, "ArraySplice", args);
748 }
749 FixedArray* elms = FixedArray::cast(elms_obj);
750 JSArray* array = JSArray::cast(receiver);
751 ASSERT(array->HasFastElements());
752
753 int len = Smi::cast(array->length())->value();
754
755 int n_arguments = args.length() - 1;
756
757 int relative_start = 0;
758 if (n_arguments > 0) {
759 Object* arg1 = args[1];
760 if (arg1->IsSmi()) {
761 relative_start = Smi::cast(arg1)->value();
762 } else if (!arg1->IsUndefined()) {
763 return CallJsBuiltin(isolate, "ArraySplice", args);
764 }
765 }
766 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
767 : Min(relative_start, len);
768
769 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
770 // given as a request to delete all the elements from the start.
771 // And it differs from the case of undefined delete count.
772 // This does not follow ECMA-262, but we do the same for
773 // compatibility.
774 int actual_delete_count;
775 if (n_arguments == 1) {
776 ASSERT(len - actual_start >= 0);
777 actual_delete_count = len - actual_start;
778 } else {
779 int value = 0; // ToInteger(undefined) == 0
780 if (n_arguments > 1) {
781 Object* arg2 = args[2];
782 if (arg2->IsSmi()) {
783 value = Smi::cast(arg2)->value();
784 } else {
785 return CallJsBuiltin(isolate, "ArraySplice", args);
786 }
787 }
788 actual_delete_count = Min(Max(value, 0), len - actual_start);
789 }
790
791 JSArray* result_array = NULL;
792 if (actual_delete_count == 0) {
793 Object* result;
794 { MaybeObject* maybe_result = AllocateEmptyJSArray(heap);
795 if (!maybe_result->ToObject(&result)) return maybe_result;
796 }
797 result_array = JSArray::cast(result);
798 } else {
799 // Allocate result array.
800 Object* result;
801 { MaybeObject* maybe_result = AllocateJSArray(heap);
802 if (!maybe_result->ToObject(&result)) return maybe_result;
803 }
804 result_array = JSArray::cast(result);
805
806 { MaybeObject* maybe_result =
807 heap->AllocateUninitializedFixedArray(actual_delete_count);
808 if (!maybe_result->ToObject(&result)) return maybe_result;
809 }
810 FixedArray* result_elms = FixedArray::cast(result);
811
812 AssertNoAllocation no_gc;
813 // Fill newly created array.
814 CopyElements(heap,
815 &no_gc,
816 result_elms, 0,
817 elms, actual_start,
818 actual_delete_count);
819
820 // Set elements.
821 result_array->set_elements(result_elms);
822
823 // Set the length.
824 result_array->set_length(Smi::FromInt(actual_delete_count));
825 }
826
827 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
828
829 int new_length = len - actual_delete_count + item_count;
830
831 if (item_count < actual_delete_count) {
832 // Shrink the array.
833 const bool trim_array = !heap->lo_space()->Contains(elms) &&
834 ((actual_start + item_count) <
835 (len - actual_delete_count - actual_start));
836 if (trim_array) {
837 const int delta = actual_delete_count - item_count;
838
839 if (actual_start > 0) {
840 AssertNoAllocation no_gc;
841 MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
842 }
843
844 elms = LeftTrimFixedArray(heap, elms, delta);
845 array->set_elements(elms, SKIP_WRITE_BARRIER);
846 } else {
847 AssertNoAllocation no_gc;
848 MoveElements(heap, &no_gc,
849 elms, actual_start + item_count,
850 elms, actual_start + actual_delete_count,
851 (len - actual_delete_count - actual_start));
852 FillWithHoles(heap, elms, new_length, len);
853 }
854 } else if (item_count > actual_delete_count) {
855 // Currently fixed arrays cannot grow too big, so
856 // we should never hit this case.
857 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
858
859 // Check if array need to grow.
860 if (new_length > elms->length()) {
861 // New backing storage is needed.
862 int capacity = new_length + (new_length >> 1) + 16;
863 Object* obj;
864 { MaybeObject* maybe_obj =
865 heap->AllocateUninitializedFixedArray(capacity);
866 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
867 }
868 FixedArray* new_elms = FixedArray::cast(obj);
869
870 AssertNoAllocation no_gc;
871 // Copy the part before actual_start as is.
872 if (actual_start > 0) {
873 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, actual_start);
874 }
875 const int to_copy = len - actual_delete_count - actual_start;
876 if (to_copy > 0) {
877 CopyElements(heap, &no_gc,
878 new_elms, actual_start + item_count,
879 elms, actual_start + actual_delete_count,
880 to_copy);
881 }
882 FillWithHoles(heap, new_elms, new_length, capacity);
883
884 elms = new_elms;
885 array->set_elements(elms);
886 } else {
887 AssertNoAllocation no_gc;
888 MoveElements(heap, &no_gc,
889 elms, actual_start + item_count,
890 elms, actual_start + actual_delete_count,
891 (len - actual_delete_count - actual_start));
892 }
893 }
894
895 AssertNoAllocation no_gc;
896 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
897 for (int k = actual_start; k < actual_start + item_count; k++) {
898 elms->set(k, args[3 + k - actual_start], mode);
899 }
900
901 // Set the length.
902 array->set_length(Smi::FromInt(new_length));
903
904 return result_array;
905 }
906
907
BUILTIN(ArrayConcat)908 BUILTIN(ArrayConcat) {
909 Heap* heap = isolate->heap();
910 Context* global_context = isolate->context()->global_context();
911 JSObject* array_proto =
912 JSObject::cast(global_context->array_function()->prototype());
913 if (!ArrayPrototypeHasNoElements(heap, global_context, array_proto)) {
914 return CallJsBuiltin(isolate, "ArrayConcat", args);
915 }
916
917 // Iterate through all the arguments performing checks
918 // and calculating total length.
919 int n_arguments = args.length();
920 int result_len = 0;
921 for (int i = 0; i < n_arguments; i++) {
922 Object* arg = args[i];
923 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
924 || JSArray::cast(arg)->GetPrototype() != array_proto) {
925 return CallJsBuiltin(isolate, "ArrayConcat", args);
926 }
927
928 int len = Smi::cast(JSArray::cast(arg)->length())->value();
929
930 // We shouldn't overflow when adding another len.
931 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
932 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
933 USE(kHalfOfMaxInt);
934 result_len += len;
935 ASSERT(result_len >= 0);
936
937 if (result_len > FixedArray::kMaxLength) {
938 return CallJsBuiltin(isolate, "ArrayConcat", args);
939 }
940 }
941
942 if (result_len == 0) {
943 return AllocateEmptyJSArray(heap);
944 }
945
946 // Allocate result.
947 Object* result;
948 { MaybeObject* maybe_result = AllocateJSArray(heap);
949 if (!maybe_result->ToObject(&result)) return maybe_result;
950 }
951 JSArray* result_array = JSArray::cast(result);
952
953 { MaybeObject* maybe_result =
954 heap->AllocateUninitializedFixedArray(result_len);
955 if (!maybe_result->ToObject(&result)) return maybe_result;
956 }
957 FixedArray* result_elms = FixedArray::cast(result);
958
959 // Copy data.
960 AssertNoAllocation no_gc;
961 int start_pos = 0;
962 for (int i = 0; i < n_arguments; i++) {
963 JSArray* array = JSArray::cast(args[i]);
964 int len = Smi::cast(array->length())->value();
965 if (len > 0) {
966 FixedArray* elms = FixedArray::cast(array->elements());
967 CopyElements(heap, &no_gc, result_elms, start_pos, elms, 0, len);
968 start_pos += len;
969 }
970 }
971 ASSERT(start_pos == result_len);
972
973 // Set the length and elements.
974 result_array->set_length(Smi::FromInt(result_len));
975 result_array->set_elements(result_elms);
976
977 return result_array;
978 }
979
980
981 // -----------------------------------------------------------------------------
982 // Strict mode poison pills
983
984
BUILTIN(StrictArgumentsCallee)985 BUILTIN(StrictArgumentsCallee) {
986 HandleScope scope;
987 return isolate->Throw(*isolate->factory()->NewTypeError(
988 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
989 }
990
991
BUILTIN(StrictArgumentsCaller)992 BUILTIN(StrictArgumentsCaller) {
993 HandleScope scope;
994 return isolate->Throw(*isolate->factory()->NewTypeError(
995 "strict_arguments_caller", HandleVector<Object>(NULL, 0)));
996 }
997
998
BUILTIN(StrictFunctionCaller)999 BUILTIN(StrictFunctionCaller) {
1000 HandleScope scope;
1001 return isolate->Throw(*isolate->factory()->NewTypeError(
1002 "strict_function_caller", HandleVector<Object>(NULL, 0)));
1003 }
1004
1005
BUILTIN(StrictFunctionArguments)1006 BUILTIN(StrictFunctionArguments) {
1007 HandleScope scope;
1008 return isolate->Throw(*isolate->factory()->NewTypeError(
1009 "strict_function_arguments", HandleVector<Object>(NULL, 0)));
1010 }
1011
1012
1013 // -----------------------------------------------------------------------------
1014 //
1015
1016
1017 // Returns the holder JSObject if the function can legally be called
1018 // with this receiver. Returns Heap::null_value() if the call is
1019 // illegal. Any arguments that don't fit the expected type is
1020 // overwritten with undefined. Arguments that do fit the expected
1021 // type is overwritten with the object in the prototype chain that
1022 // actually has that type.
TypeCheck(Heap * heap,int argc,Object ** argv,FunctionTemplateInfo * info)1023 static inline Object* TypeCheck(Heap* heap,
1024 int argc,
1025 Object** argv,
1026 FunctionTemplateInfo* info) {
1027 Object* recv = argv[0];
1028 Object* sig_obj = info->signature();
1029 if (sig_obj->IsUndefined()) return recv;
1030 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
1031 // If necessary, check the receiver
1032 Object* recv_type = sig->receiver();
1033
1034 Object* holder = recv;
1035 if (!recv_type->IsUndefined()) {
1036 for (; holder != heap->null_value(); holder = holder->GetPrototype()) {
1037 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
1038 break;
1039 }
1040 }
1041 if (holder == heap->null_value()) return holder;
1042 }
1043 Object* args_obj = sig->args();
1044 // If there is no argument signature we're done
1045 if (args_obj->IsUndefined()) return holder;
1046 FixedArray* args = FixedArray::cast(args_obj);
1047 int length = args->length();
1048 if (argc <= length) length = argc - 1;
1049 for (int i = 0; i < length; i++) {
1050 Object* argtype = args->get(i);
1051 if (argtype->IsUndefined()) continue;
1052 Object** arg = &argv[-1 - i];
1053 Object* current = *arg;
1054 for (; current != heap->null_value(); current = current->GetPrototype()) {
1055 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
1056 *arg = current;
1057 break;
1058 }
1059 }
1060 if (current == heap->null_value()) *arg = heap->undefined_value();
1061 }
1062 return holder;
1063 }
1064
1065
1066 template <bool is_construct>
HandleApiCallHelper(BuiltinArguments<NEEDS_CALLED_FUNCTION> args,Isolate * isolate)1067 MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
1068 BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
1069 ASSERT(is_construct == CalledAsConstructor(isolate));
1070 Heap* heap = isolate->heap();
1071
1072 HandleScope scope(isolate);
1073 Handle<JSFunction> function = args.called_function();
1074 ASSERT(function->shared()->IsApiFunction());
1075
1076 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
1077 if (is_construct) {
1078 Handle<FunctionTemplateInfo> desc(fun_data, isolate);
1079 bool pending_exception = false;
1080 isolate->factory()->ConfigureInstance(
1081 desc, Handle<JSObject>::cast(args.receiver()), &pending_exception);
1082 ASSERT(isolate->has_pending_exception() == pending_exception);
1083 if (pending_exception) return Failure::Exception();
1084 fun_data = *desc;
1085 }
1086
1087 Object* raw_holder = TypeCheck(heap, args.length(), &args[0], fun_data);
1088
1089 if (raw_holder->IsNull()) {
1090 // This function cannot be called with the given receiver. Abort!
1091 Handle<Object> obj =
1092 isolate->factory()->NewTypeError(
1093 "illegal_invocation", HandleVector(&function, 1));
1094 return isolate->Throw(*obj);
1095 }
1096
1097 Object* raw_call_data = fun_data->call_code();
1098 if (!raw_call_data->IsUndefined()) {
1099 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1100 Object* callback_obj = call_data->callback();
1101 v8::InvocationCallback callback =
1102 v8::ToCData<v8::InvocationCallback>(callback_obj);
1103 Object* data_obj = call_data->data();
1104 Object* result;
1105
1106 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
1107 ASSERT(raw_holder->IsJSObject());
1108
1109 CustomArguments custom(isolate);
1110 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1111 data_obj, *function, raw_holder);
1112
1113 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1114 custom.end(),
1115 &args[0] - 1,
1116 args.length() - 1,
1117 is_construct);
1118
1119 v8::Handle<v8::Value> value;
1120 {
1121 // Leaving JavaScript.
1122 VMState state(isolate, EXTERNAL);
1123 ExternalCallbackScope call_scope(isolate,
1124 v8::ToCData<Address>(callback_obj));
1125 value = callback(new_args);
1126 }
1127 if (value.IsEmpty()) {
1128 result = heap->undefined_value();
1129 } else {
1130 result = *reinterpret_cast<Object**>(*value);
1131 }
1132
1133 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1134 if (!is_construct || result->IsJSObject()) return result;
1135 }
1136
1137 return *args.receiver();
1138 }
1139
1140
BUILTIN(HandleApiCall)1141 BUILTIN(HandleApiCall) {
1142 return HandleApiCallHelper<false>(args, isolate);
1143 }
1144
1145
BUILTIN(HandleApiCallConstruct)1146 BUILTIN(HandleApiCallConstruct) {
1147 return HandleApiCallHelper<true>(args, isolate);
1148 }
1149
1150
1151 #ifdef DEBUG
1152
VerifyTypeCheck(Handle<JSObject> object,Handle<JSFunction> function)1153 static void VerifyTypeCheck(Handle<JSObject> object,
1154 Handle<JSFunction> function) {
1155 ASSERT(function->shared()->IsApiFunction());
1156 FunctionTemplateInfo* info = function->shared()->get_api_func_data();
1157 if (info->signature()->IsUndefined()) return;
1158 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1159 Object* receiver_type = signature->receiver();
1160 if (receiver_type->IsUndefined()) return;
1161 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
1162 ASSERT(object->IsInstanceOf(type));
1163 }
1164
1165 #endif
1166
1167
BUILTIN(FastHandleApiCall)1168 BUILTIN(FastHandleApiCall) {
1169 ASSERT(!CalledAsConstructor(isolate));
1170 Heap* heap = isolate->heap();
1171 const bool is_construct = false;
1172
1173 // We expect four more arguments: callback, function, call data, and holder.
1174 const int args_length = args.length() - 4;
1175 ASSERT(args_length >= 0);
1176
1177 Object* callback_obj = args[args_length];
1178
1179 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1180 &args[args_length + 1],
1181 &args[0] - 1,
1182 args_length - 1,
1183 is_construct);
1184
1185 #ifdef DEBUG
1186 VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()),
1187 Utils::OpenHandle(*new_args.Callee()));
1188 #endif
1189 HandleScope scope(isolate);
1190 Object* result;
1191 v8::Handle<v8::Value> value;
1192 {
1193 // Leaving JavaScript.
1194 VMState state(isolate, EXTERNAL);
1195 ExternalCallbackScope call_scope(isolate,
1196 v8::ToCData<Address>(callback_obj));
1197 v8::InvocationCallback callback =
1198 v8::ToCData<v8::InvocationCallback>(callback_obj);
1199
1200 value = callback(new_args);
1201 }
1202 if (value.IsEmpty()) {
1203 result = heap->undefined_value();
1204 } else {
1205 result = *reinterpret_cast<Object**>(*value);
1206 }
1207
1208 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1209 return result;
1210 }
1211
1212
1213 // Helper function to handle calls to non-function objects created through the
1214 // API. The object can be called as either a constructor (using new) or just as
1215 // a function (without new).
HandleApiCallAsFunctionOrConstructor(Isolate * isolate,bool is_construct_call,BuiltinArguments<NO_EXTRA_ARGUMENTS> args)1216 MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
1217 Isolate* isolate,
1218 bool is_construct_call,
1219 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
1220 // Non-functions are never called as constructors. Even if this is an object
1221 // called as a constructor the delegate call is not a construct call.
1222 ASSERT(!CalledAsConstructor(isolate));
1223 Heap* heap = isolate->heap();
1224
1225 Handle<Object> receiver = args.at<Object>(0);
1226
1227 // Get the object called.
1228 JSObject* obj = JSObject::cast(*args.receiver());
1229
1230 // Get the invocation callback from the function descriptor that was
1231 // used to create the called object.
1232 ASSERT(obj->map()->has_instance_call_handler());
1233 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
1234 ASSERT(constructor->shared()->IsApiFunction());
1235 Object* handler =
1236 constructor->shared()->get_api_func_data()->instance_call_handler();
1237 ASSERT(!handler->IsUndefined());
1238 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1239 Object* callback_obj = call_data->callback();
1240 v8::InvocationCallback callback =
1241 v8::ToCData<v8::InvocationCallback>(callback_obj);
1242
1243 // Get the data for the call and perform the callback.
1244 Object* result;
1245 {
1246 HandleScope scope(isolate);
1247 LOG(isolate, ApiObjectAccess("call non-function", obj));
1248
1249 CustomArguments custom(isolate);
1250 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1251 call_data->data(), constructor, obj);
1252 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1253 custom.end(),
1254 &args[0] - 1,
1255 args.length() - 1,
1256 is_construct_call);
1257 v8::Handle<v8::Value> value;
1258 {
1259 // Leaving JavaScript.
1260 VMState state(isolate, EXTERNAL);
1261 ExternalCallbackScope call_scope(isolate,
1262 v8::ToCData<Address>(callback_obj));
1263 value = callback(new_args);
1264 }
1265 if (value.IsEmpty()) {
1266 result = heap->undefined_value();
1267 } else {
1268 result = *reinterpret_cast<Object**>(*value);
1269 }
1270 }
1271 // Check for exceptions and return result.
1272 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
1273 return result;
1274 }
1275
1276
1277 // Handle calls to non-function objects created through the API. This delegate
1278 // function is used when the call is a normal function call.
BUILTIN(HandleApiCallAsFunction)1279 BUILTIN(HandleApiCallAsFunction) {
1280 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
1281 }
1282
1283
1284 // Handle calls to non-function objects created through the API. This delegate
1285 // function is used when the call is a construct call.
BUILTIN(HandleApiCallAsConstructor)1286 BUILTIN(HandleApiCallAsConstructor) {
1287 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
1288 }
1289
1290
Generate_LoadIC_ArrayLength(MacroAssembler * masm)1291 static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1292 LoadIC::GenerateArrayLength(masm);
1293 }
1294
1295
Generate_LoadIC_StringLength(MacroAssembler * masm)1296 static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
1297 LoadIC::GenerateStringLength(masm, false);
1298 }
1299
1300
Generate_LoadIC_StringWrapperLength(MacroAssembler * masm)1301 static void Generate_LoadIC_StringWrapperLength(MacroAssembler* masm) {
1302 LoadIC::GenerateStringLength(masm, true);
1303 }
1304
1305
Generate_LoadIC_FunctionPrototype(MacroAssembler * masm)1306 static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1307 LoadIC::GenerateFunctionPrototype(masm);
1308 }
1309
1310
Generate_LoadIC_Initialize(MacroAssembler * masm)1311 static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1312 LoadIC::GenerateInitialize(masm);
1313 }
1314
1315
Generate_LoadIC_PreMonomorphic(MacroAssembler * masm)1316 static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1317 LoadIC::GeneratePreMonomorphic(masm);
1318 }
1319
1320
Generate_LoadIC_Miss(MacroAssembler * masm)1321 static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1322 LoadIC::GenerateMiss(masm);
1323 }
1324
1325
Generate_LoadIC_Megamorphic(MacroAssembler * masm)1326 static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1327 LoadIC::GenerateMegamorphic(masm);
1328 }
1329
1330
Generate_LoadIC_Normal(MacroAssembler * masm)1331 static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1332 LoadIC::GenerateNormal(masm);
1333 }
1334
1335
Generate_KeyedLoadIC_Initialize(MacroAssembler * masm)1336 static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1337 KeyedLoadIC::GenerateInitialize(masm);
1338 }
1339
1340
Generate_KeyedLoadIC_Miss(MacroAssembler * masm)1341 static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1342 KeyedLoadIC::GenerateMiss(masm);
1343 }
1344
1345
Generate_KeyedLoadIC_Generic(MacroAssembler * masm)1346 static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1347 KeyedLoadIC::GenerateGeneric(masm);
1348 }
1349
1350
Generate_KeyedLoadIC_String(MacroAssembler * masm)1351 static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1352 KeyedLoadIC::GenerateString(masm);
1353 }
1354
1355
Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler * masm)1356 static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1357 KeyedLoadIC::GeneratePreMonomorphic(masm);
1358 }
1359
Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler * masm)1360 static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1361 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1362 }
1363
1364
Generate_StoreIC_Initialize(MacroAssembler * masm)1365 static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1366 StoreIC::GenerateInitialize(masm);
1367 }
1368
1369
Generate_StoreIC_Initialize_Strict(MacroAssembler * masm)1370 static void Generate_StoreIC_Initialize_Strict(MacroAssembler* masm) {
1371 StoreIC::GenerateInitialize(masm);
1372 }
1373
1374
Generate_StoreIC_Miss(MacroAssembler * masm)1375 static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1376 StoreIC::GenerateMiss(masm);
1377 }
1378
1379
Generate_StoreIC_Normal(MacroAssembler * masm)1380 static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1381 StoreIC::GenerateNormal(masm);
1382 }
1383
1384
Generate_StoreIC_Normal_Strict(MacroAssembler * masm)1385 static void Generate_StoreIC_Normal_Strict(MacroAssembler* masm) {
1386 StoreIC::GenerateNormal(masm);
1387 }
1388
1389
Generate_StoreIC_Megamorphic(MacroAssembler * masm)1390 static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
1391 StoreIC::GenerateMegamorphic(masm, kNonStrictMode);
1392 }
1393
1394
Generate_StoreIC_Megamorphic_Strict(MacroAssembler * masm)1395 static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) {
1396 StoreIC::GenerateMegamorphic(masm, kStrictMode);
1397 }
1398
1399
Generate_StoreIC_ArrayLength(MacroAssembler * masm)1400 static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1401 StoreIC::GenerateArrayLength(masm);
1402 }
1403
1404
Generate_StoreIC_ArrayLength_Strict(MacroAssembler * masm)1405 static void Generate_StoreIC_ArrayLength_Strict(MacroAssembler* masm) {
1406 StoreIC::GenerateArrayLength(masm);
1407 }
1408
1409
Generate_StoreIC_GlobalProxy(MacroAssembler * masm)1410 static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
1411 StoreIC::GenerateGlobalProxy(masm, kNonStrictMode);
1412 }
1413
1414
Generate_StoreIC_GlobalProxy_Strict(MacroAssembler * masm)1415 static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
1416 StoreIC::GenerateGlobalProxy(masm, kStrictMode);
1417 }
1418
1419
Generate_KeyedStoreIC_Generic(MacroAssembler * masm)1420 static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
1421 KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode);
1422 }
1423
1424
Generate_KeyedStoreIC_Generic_Strict(MacroAssembler * masm)1425 static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) {
1426 KeyedStoreIC::GenerateGeneric(masm, kStrictMode);
1427 }
1428
1429
Generate_KeyedStoreIC_Miss(MacroAssembler * masm)1430 static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1431 KeyedStoreIC::GenerateMiss(masm);
1432 }
1433
1434
Generate_KeyedStoreIC_Initialize(MacroAssembler * masm)1435 static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1436 KeyedStoreIC::GenerateInitialize(masm);
1437 }
1438
1439
Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler * masm)1440 static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
1441 KeyedStoreIC::GenerateInitialize(masm);
1442 }
1443
1444
1445 #ifdef ENABLE_DEBUGGER_SUPPORT
Generate_LoadIC_DebugBreak(MacroAssembler * masm)1446 static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1447 Debug::GenerateLoadICDebugBreak(masm);
1448 }
1449
1450
Generate_StoreIC_DebugBreak(MacroAssembler * masm)1451 static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1452 Debug::GenerateStoreICDebugBreak(masm);
1453 }
1454
1455
Generate_KeyedLoadIC_DebugBreak(MacroAssembler * masm)1456 static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1457 Debug::GenerateKeyedLoadICDebugBreak(masm);
1458 }
1459
1460
Generate_KeyedStoreIC_DebugBreak(MacroAssembler * masm)1461 static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1462 Debug::GenerateKeyedStoreICDebugBreak(masm);
1463 }
1464
1465
Generate_ConstructCall_DebugBreak(MacroAssembler * masm)1466 static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1467 Debug::GenerateConstructCallDebugBreak(masm);
1468 }
1469
1470
Generate_Return_DebugBreak(MacroAssembler * masm)1471 static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1472 Debug::GenerateReturnDebugBreak(masm);
1473 }
1474
1475
Generate_StubNoRegisters_DebugBreak(MacroAssembler * masm)1476 static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
1477 Debug::GenerateStubNoRegistersDebugBreak(masm);
1478 }
1479
1480
Generate_Slot_DebugBreak(MacroAssembler * masm)1481 static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1482 Debug::GenerateSlotDebugBreak(masm);
1483 }
1484
1485
Generate_PlainReturn_LiveEdit(MacroAssembler * masm)1486 static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1487 Debug::GeneratePlainReturnLiveEdit(masm);
1488 }
1489
1490
Generate_FrameDropper_LiveEdit(MacroAssembler * masm)1491 static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1492 Debug::GenerateFrameDropperLiveEdit(masm);
1493 }
1494 #endif
1495
1496
Builtins()1497 Builtins::Builtins() : initialized_(false) {
1498 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
1499 memset(names_, 0, sizeof(names_[0]) * builtin_count);
1500 }
1501
1502
~Builtins()1503 Builtins::~Builtins() {
1504 }
1505
1506
1507 #define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
1508 Address const Builtins::c_functions_[cfunction_count] = {
1509 BUILTIN_LIST_C(DEF_ENUM_C)
1510 };
1511 #undef DEF_ENUM_C
1512
1513 #define DEF_JS_NAME(name, ignore) #name,
1514 #define DEF_JS_ARGC(ignore, argc) argc,
1515 const char* const Builtins::javascript_names_[id_count] = {
1516 BUILTINS_LIST_JS(DEF_JS_NAME)
1517 };
1518
1519 int const Builtins::javascript_argc_[id_count] = {
1520 BUILTINS_LIST_JS(DEF_JS_ARGC)
1521 };
1522 #undef DEF_JS_NAME
1523 #undef DEF_JS_ARGC
1524
1525 struct BuiltinDesc {
1526 byte* generator;
1527 byte* c_code;
1528 const char* s_name; // name is only used for generating log information.
1529 int name;
1530 Code::Flags flags;
1531 BuiltinExtraArguments extra_args;
1532 };
1533
1534 class BuiltinFunctionTable {
1535 public:
BuiltinFunctionTable()1536 BuiltinFunctionTable() {
1537 Builtins::InitBuiltinFunctionTable();
1538 }
1539
functions()1540 static const BuiltinDesc* functions() { return functions_; }
1541
1542 private:
1543 static BuiltinDesc functions_[Builtins::builtin_count + 1];
1544
1545 friend class Builtins;
1546 };
1547
1548 BuiltinDesc BuiltinFunctionTable::functions_[Builtins::builtin_count + 1];
1549
1550 static const BuiltinFunctionTable builtin_function_table_init;
1551
1552 // Define array of pointers to generators and C builtin functions.
1553 // We do this in a sort of roundabout way so that we can do the initialization
1554 // within the lexical scope of Builtins:: and within a context where
1555 // Code::Flags names a non-abstract type.
InitBuiltinFunctionTable()1556 void Builtins::InitBuiltinFunctionTable() {
1557 BuiltinDesc* functions = BuiltinFunctionTable::functions_;
1558 functions[builtin_count].generator = NULL;
1559 functions[builtin_count].c_code = NULL;
1560 functions[builtin_count].s_name = NULL;
1561 functions[builtin_count].name = builtin_count;
1562 functions[builtin_count].flags = static_cast<Code::Flags>(0);
1563 functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
1564
1565 #define DEF_FUNCTION_PTR_C(aname, aextra_args) \
1566 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
1567 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
1568 functions->s_name = #aname; \
1569 functions->name = c_##aname; \
1570 functions->flags = Code::ComputeFlags(Code::BUILTIN); \
1571 functions->extra_args = aextra_args; \
1572 ++functions;
1573
1574 #define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
1575 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1576 functions->c_code = NULL; \
1577 functions->s_name = #aname; \
1578 functions->name = k##aname; \
1579 functions->flags = Code::ComputeFlags(Code::kind, \
1580 NOT_IN_LOOP, \
1581 state, \
1582 extra); \
1583 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1584 ++functions;
1585
1586 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1587 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1588 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1589
1590 #undef DEF_FUNCTION_PTR_C
1591 #undef DEF_FUNCTION_PTR_A
1592 }
1593
Setup(bool create_heap_objects)1594 void Builtins::Setup(bool create_heap_objects) {
1595 ASSERT(!initialized_);
1596 Isolate* isolate = Isolate::Current();
1597 Heap* heap = isolate->heap();
1598
1599 // Create a scope for the handles in the builtins.
1600 HandleScope scope(isolate);
1601
1602 const BuiltinDesc* functions = BuiltinFunctionTable::functions();
1603
1604 // For now we generate builtin adaptor code into a stack-allocated
1605 // buffer, before copying it into individual code objects.
1606 byte buffer[4*KB];
1607
1608 // Traverse the list of builtins and generate an adaptor in a
1609 // separate code object for each one.
1610 for (int i = 0; i < builtin_count; i++) {
1611 if (create_heap_objects) {
1612 MacroAssembler masm(isolate, buffer, sizeof buffer);
1613 // Generate the code/adaptor.
1614 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
1615 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1616 // We pass all arguments to the generator, but it may not use all of
1617 // them. This works because the first arguments are on top of the
1618 // stack.
1619 g(&masm, functions[i].name, functions[i].extra_args);
1620 // Move the code into the object heap.
1621 CodeDesc desc;
1622 masm.GetCode(&desc);
1623 Code::Flags flags = functions[i].flags;
1624 Object* code = NULL;
1625 {
1626 // During startup it's OK to always allocate and defer GC to later.
1627 // This simplifies things because we don't need to retry.
1628 AlwaysAllocateScope __scope__;
1629 { MaybeObject* maybe_code =
1630 heap->CreateCode(desc, flags, masm.CodeObject());
1631 if (!maybe_code->ToObject(&code)) {
1632 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1633 }
1634 }
1635 }
1636 // Log the event and add the code to the builtins array.
1637 PROFILE(isolate,
1638 CodeCreateEvent(Logger::BUILTIN_TAG,
1639 Code::cast(code),
1640 functions[i].s_name));
1641 GDBJIT(AddCode(GDBJITInterface::BUILTIN,
1642 functions[i].s_name,
1643 Code::cast(code)));
1644 builtins_[i] = code;
1645 #ifdef ENABLE_DISASSEMBLER
1646 if (FLAG_print_builtin_code) {
1647 PrintF("Builtin: %s\n", functions[i].s_name);
1648 Code::cast(code)->Disassemble(functions[i].s_name);
1649 PrintF("\n");
1650 }
1651 #endif
1652 } else {
1653 // Deserializing. The values will be filled in during IterateBuiltins.
1654 builtins_[i] = NULL;
1655 }
1656 names_[i] = functions[i].s_name;
1657 }
1658
1659 // Mark as initialized.
1660 initialized_ = true;
1661 }
1662
1663
TearDown()1664 void Builtins::TearDown() {
1665 initialized_ = false;
1666 }
1667
1668
IterateBuiltins(ObjectVisitor * v)1669 void Builtins::IterateBuiltins(ObjectVisitor* v) {
1670 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1671 }
1672
1673
Lookup(byte * pc)1674 const char* Builtins::Lookup(byte* pc) {
1675 // may be called during initialization (disassembler!)
1676 if (initialized_) {
1677 for (int i = 0; i < builtin_count; i++) {
1678 Code* entry = Code::cast(builtins_[i]);
1679 if (entry->contains(pc)) {
1680 return names_[i];
1681 }
1682 }
1683 }
1684 return NULL;
1685 }
1686
1687
1688 #define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
1689 Handle<Code> Builtins::name() { \
1690 Code** code_address = \
1691 reinterpret_cast<Code**>(builtin_address(k##name)); \
1692 return Handle<Code>(code_address); \
1693 }
1694 #define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
1695 Handle<Code> Builtins::name() { \
1696 Code** code_address = \
1697 reinterpret_cast<Code**>(builtin_address(k##name)); \
1698 return Handle<Code>(code_address); \
1699 }
1700 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1701 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1702 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1703 #undef DEFINE_BUILTIN_ACCESSOR_C
1704 #undef DEFINE_BUILTIN_ACCESSOR_A
1705
1706
1707 } } // namespace v8::internal
1708