blob: eedee9f44784f1abaf3be9d130f0c5883ac9a276 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
33#include "builtins.h"
34#include "ic-inl.h"
35
36namespace v8 {
37namespace internal {
38
Leon Clarkee46be812010-01-19 14:06:41 +000039namespace {
40
41// Arguments object passed to C++ builtins.
42template <BuiltinExtraArguments extra_args>
43class BuiltinArguments : public Arguments {
44 public:
45 BuiltinArguments(int length, Object** arguments)
46 : Arguments(length, arguments) { }
47
48 Object*& operator[] (int index) {
49 ASSERT(index < length());
50 return Arguments::operator[](index);
51 }
52
53 template <class S> Handle<S> at(int index) {
54 ASSERT(index < length());
55 return Arguments::at<S>(index);
56 }
57
58 Handle<Object> receiver() {
59 return Arguments::at<Object>(0);
60 }
61
62 Handle<JSFunction> called_function() {
63 STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
64 return Arguments::at<JSFunction>(Arguments::length() - 1);
65 }
66
67 // Gets the total number of arguments including the receiver (but
68 // excluding extra arguments).
69 int length() const {
70 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
71 return Arguments::length();
72 }
73
74#ifdef DEBUG
75 void Verify() {
76 // Check we have at least the receiver.
77 ASSERT(Arguments::length() >= 1);
78 }
79#endif
80};
81
82
83// Specialize BuiltinArguments for the called function extra argument.
84
85template <>
86int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
87 return Arguments::length() - 1;
88}
89
90#ifdef DEBUG
91template <>
92void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
93 // Check we have at least the receiver and the called function.
94 ASSERT(Arguments::length() >= 2);
95 // Make sure cast to JSFunction succeeds.
96 called_function();
97}
98#endif
99
100
101#define DEF_ARG_TYPE(name, spec) \
102 typedef BuiltinArguments<spec> name##ArgumentsType;
103BUILTIN_LIST_C(DEF_ARG_TYPE)
104#undef DEF_ARG_TYPE
105
106} // namespace
107
108
Steve Blocka7e24c12009-10-30 11:49:00 +0000109// ----------------------------------------------------------------------------
Leon Clarkee46be812010-01-19 14:06:41 +0000110// Support macro for defining builtins in C++.
Steve Blocka7e24c12009-10-30 11:49:00 +0000111// ----------------------------------------------------------------------------
112//
113// A builtin function is defined by writing:
114//
115// BUILTIN(name) {
116// ...
117// }
Steve Blocka7e24c12009-10-30 11:49:00 +0000118//
Leon Clarkee46be812010-01-19 14:06:41 +0000119// In the body of the builtin function the arguments can be accessed
120// through the BuiltinArguments object args.
Steve Blocka7e24c12009-10-30 11:49:00 +0000121
Leon Clarkee46be812010-01-19 14:06:41 +0000122#ifdef DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +0000123
Leon Clarkee46be812010-01-19 14:06:41 +0000124#define BUILTIN(name) \
125 static Object* Builtin_Impl_##name(name##ArgumentsType args); \
126 static Object* Builtin_##name(name##ArgumentsType args) { \
127 args.Verify(); \
128 return Builtin_Impl_##name(args); \
129 } \
130 static Object* Builtin_Impl_##name(name##ArgumentsType args)
Steve Blocka7e24c12009-10-30 11:49:00 +0000131
Leon Clarkee46be812010-01-19 14:06:41 +0000132#else // For release mode.
Steve Blocka7e24c12009-10-30 11:49:00 +0000133
Leon Clarkee46be812010-01-19 14:06:41 +0000134#define BUILTIN(name) \
135 static Object* Builtin_##name(name##ArgumentsType args)
136
137#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000138
139
140static inline bool CalledAsConstructor() {
141#ifdef DEBUG
142 // Calculate the result using a full stack frame iterator and check
143 // that the state of the stack is as we assume it to be in the
144 // code below.
145 StackFrameIterator it;
146 ASSERT(it.frame()->is_exit());
147 it.Advance();
148 StackFrame* frame = it.frame();
149 bool reference_result = frame->is_construct();
150#endif
151 Address fp = Top::c_entry_fp(Top::GetCurrentThread());
152 // Because we know fp points to an exit frame we can use the relevant
153 // part of ExitFrame::ComputeCallerState directly.
154 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
155 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
156 // This inlines the part of StackFrame::ComputeType that grabs the
157 // type of the current frame. Note that StackFrame::ComputeType
158 // has been specialized for each architecture so if any one of them
159 // changes this code has to be changed as well.
160 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
161 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
162 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
163 bool result = (marker == kConstructMarker);
164 ASSERT_EQ(result, reference_result);
165 return result;
166}
167
168// ----------------------------------------------------------------------------
169
170
Steve Blocka7e24c12009-10-30 11:49:00 +0000171BUILTIN(Illegal) {
172 UNREACHABLE();
Leon Clarkee46be812010-01-19 14:06:41 +0000173 return Heap::undefined_value(); // Make compiler happy.
Steve Blocka7e24c12009-10-30 11:49:00 +0000174}
Steve Blocka7e24c12009-10-30 11:49:00 +0000175
176
177BUILTIN(EmptyFunction) {
Leon Clarkee46be812010-01-19 14:06:41 +0000178 return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000179}
Steve Blocka7e24c12009-10-30 11:49:00 +0000180
181
182BUILTIN(ArrayCodeGeneric) {
183 Counters::array_function_runtime.Increment();
184
185 JSArray* array;
186 if (CalledAsConstructor()) {
Leon Clarkee46be812010-01-19 14:06:41 +0000187 array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000188 } else {
189 // Allocate the JS Array
190 JSFunction* constructor =
191 Top::context()->global_context()->array_function();
192 Object* obj = Heap::AllocateJSObject(constructor);
193 if (obj->IsFailure()) return obj;
194 array = JSArray::cast(obj);
195 }
196
197 // 'array' now contains the JSArray we should initialize.
Steve Block8defd9f2010-07-08 12:39:36 +0100198 ASSERT(array->HasFastElements());
Steve Blocka7e24c12009-10-30 11:49:00 +0000199
200 // Optimize the case where there is one argument and the argument is a
201 // small smi.
202 if (args.length() == 2) {
203 Object* obj = args[1];
204 if (obj->IsSmi()) {
205 int len = Smi::cast(obj)->value();
206 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
207 Object* obj = Heap::AllocateFixedArrayWithHoles(len);
208 if (obj->IsFailure()) return obj;
209 array->SetContent(FixedArray::cast(obj));
210 return array;
211 }
212 }
213 // Take the argument as the length.
214 obj = array->Initialize(0);
215 if (obj->IsFailure()) return obj;
216 return array->SetElementsLength(args[1]);
217 }
218
219 // Optimize the case where there are no parameters passed.
220 if (args.length() == 1) {
221 return array->Initialize(JSArray::kPreallocatedArrayElements);
222 }
223
224 // Take the arguments as elements.
225 int number_of_elements = args.length() - 1;
226 Smi* len = Smi::FromInt(number_of_elements);
227 Object* obj = Heap::AllocateFixedArrayWithHoles(len->value());
228 if (obj->IsFailure()) return obj;
Leon Clarke4515c472010-02-03 11:58:03 +0000229
230 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000231 FixedArray* elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000232 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 // Fill in the content
234 for (int index = 0; index < number_of_elements; index++) {
235 elms->set(index, args[index+1], mode);
236 }
237
238 // Set length and elements on the array.
239 array->set_elements(FixedArray::cast(obj));
Leon Clarke4515c472010-02-03 11:58:03 +0000240 array->set_length(len);
Steve Blocka7e24c12009-10-30 11:49:00 +0000241
242 return array;
243}
Steve Blocka7e24c12009-10-30 11:49:00 +0000244
245
Steve Block6ded16b2010-05-10 14:33:55 +0100246static Object* AllocateJSArray() {
247 JSFunction* array_function =
248 Top::context()->global_context()->array_function();
249 Object* result = Heap::AllocateJSObject(array_function);
250 if (result->IsFailure()) return result;
251 return result;
252}
253
254
255static Object* AllocateEmptyJSArray() {
256 Object* result = AllocateJSArray();
257 if (result->IsFailure()) return result;
258 JSArray* result_array = JSArray::cast(result);
259 result_array->set_length(Smi::FromInt(0));
260 result_array->set_elements(Heap::empty_fixed_array());
261 return result_array;
262}
263
264
265static void CopyElements(AssertNoAllocation* no_gc,
266 FixedArray* dst,
267 int dst_index,
268 FixedArray* src,
269 int src_index,
270 int len) {
271 ASSERT(dst != src); // Use MoveElements instead.
Iain Merrick75681382010-08-19 15:07:18 +0100272 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100273 ASSERT(len > 0);
274 CopyWords(dst->data_start() + dst_index,
275 src->data_start() + src_index,
276 len);
277 WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
278 if (mode == UPDATE_WRITE_BARRIER) {
279 Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
280 }
281}
282
283
284static void MoveElements(AssertNoAllocation* no_gc,
285 FixedArray* dst,
286 int dst_index,
287 FixedArray* src,
288 int src_index,
289 int len) {
Iain Merrick75681382010-08-19 15:07:18 +0100290 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100291 memmove(dst->data_start() + dst_index,
292 src->data_start() + src_index,
293 len * kPointerSize);
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
301static void FillWithHoles(FixedArray* dst, int from, int to) {
Iain Merrick75681382010-08-19 15:07:18 +0100302 ASSERT(dst->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100303 MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from);
304}
305
306
307static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
Iain Merrick75681382010-08-19 15:07:18 +0100308 ASSERT(elms->map() != Heap::fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100309 // For now this trick is only applied to fixed arrays in new space.
310 // In large object space the object's start must coincide with chunk
311 // and thus the trick is just not applicable.
312 // In old space we do not use this trick to avoid dealing with
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100313 // region dirty marks.
Steve Block6ded16b2010-05-10 14:33:55 +0100314 ASSERT(Heap::new_space()->Contains(elms));
315
316 STATIC_ASSERT(FixedArray::kMapOffset == 0);
317 STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
318 STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
319
320 Object** former_start = HeapObject::RawField(elms, 0);
321
322 const int len = elms->length();
323
324 // Technically in new space this write might be omitted (except for
325 // debug mode which iterates through the heap), but to play safer
326 // we still do it.
327 Heap::CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
328
329 former_start[to_trim] = Heap::fixed_array_map();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100330 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
Steve Block6ded16b2010-05-10 14:33:55 +0100331
332 ASSERT_EQ(elms->address() + to_trim * kPointerSize,
333 (elms + to_trim * kPointerSize)->address());
334 return elms + to_trim * kPointerSize;
335}
336
337
Kristian Monsen25f61362010-05-21 11:50:48 +0100338static bool ArrayPrototypeHasNoElements(Context* global_context,
339 JSObject* array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100340 // This method depends on non writability of Object and Array prototype
341 // fields.
Kristian Monsen25f61362010-05-21 11:50:48 +0100342 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
Steve Block6ded16b2010-05-10 14:33:55 +0100343 // Hidden prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100344 array_proto = JSObject::cast(array_proto->GetPrototype());
345 ASSERT(array_proto->elements() == Heap::empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +0100346 // Object.prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100347 array_proto = JSObject::cast(array_proto->GetPrototype());
348 if (array_proto != global_context->initial_object_prototype()) return false;
349 if (array_proto->elements() != Heap::empty_fixed_array()) return false;
350 ASSERT(array_proto->GetPrototype()->IsNull());
Steve Block6ded16b2010-05-10 14:33:55 +0100351 return true;
352}
353
354
Iain Merrick75681382010-08-19 15:07:18 +0100355static inline Object* EnsureJSArrayWithWritableFastElements(Object* receiver) {
356 if (!receiver->IsJSArray()) return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100357 JSArray* array = JSArray::cast(receiver);
Steve Block6ded16b2010-05-10 14:33:55 +0100358 HeapObject* elms = HeapObject::cast(array->elements());
Iain Merrick75681382010-08-19 15:07:18 +0100359 if (elms->map() == Heap::fixed_array_map()) return elms;
360 if (elms->map() == Heap::fixed_cow_array_map()) {
361 return array->EnsureWritableFastElements();
Steve Block6ded16b2010-05-10 14:33:55 +0100362 }
Iain Merrick75681382010-08-19 15:07:18 +0100363 return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100364}
365
366
Iain Merrick75681382010-08-19 15:07:18 +0100367static inline bool IsJSArrayFastElementMovingAllowed(JSArray* receiver) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100368 Context* global_context = Top::context()->global_context();
369 JSObject* array_proto =
370 JSObject::cast(global_context->array_function()->prototype());
Iain Merrick75681382010-08-19 15:07:18 +0100371 return receiver->GetPrototype() == array_proto &&
372 ArrayPrototypeHasNoElements(global_context, array_proto);
Kristian Monsen25f61362010-05-21 11:50:48 +0100373}
374
375
Steve Block6ded16b2010-05-10 14:33:55 +0100376static Object* CallJsBuiltin(const char* name,
377 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
378 HandleScope handleScope;
379
380 Handle<Object> js_builtin =
381 GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
382 name);
383 ASSERT(js_builtin->IsJSFunction());
384 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
Kristian Monsen25f61362010-05-21 11:50:48 +0100385 ScopedVector<Object**> argv(args.length() - 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100386 int n_args = args.length() - 1;
387 for (int i = 0; i < n_args; i++) {
388 argv[i] = args.at<Object>(i + 1).location();
389 }
390 bool pending_exception = false;
391 Handle<Object> result = Execution::Call(function,
392 args.receiver(),
393 n_args,
394 argv.start(),
395 &pending_exception);
Steve Block6ded16b2010-05-10 14:33:55 +0100396 if (pending_exception) return Failure::Exception();
397 return *result;
398}
399
400
Steve Blocka7e24c12009-10-30 11:49:00 +0000401BUILTIN(ArrayPush) {
Steve Block6ded16b2010-05-10 14:33:55 +0100402 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100403 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
404 if (elms_obj == NULL) return CallJsBuiltin("ArrayPush", args);
405 if (elms_obj->IsFailure()) return elms_obj;
406 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100407 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000408
Steve Blocka7e24c12009-10-30 11:49:00 +0000409 int len = Smi::cast(array->length())->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000410 int to_add = args.length() - 1;
411 if (to_add == 0) {
412 return Smi::FromInt(len);
413 }
414 // Currently fixed arrays cannot grow too big, so
415 // we should never hit this case.
416 ASSERT(to_add <= (Smi::kMaxValue - len));
Steve Blocka7e24c12009-10-30 11:49:00 +0000417
Andrei Popescu402d9372010-02-26 13:31:12 +0000418 int new_length = len + to_add;
Steve Blocka7e24c12009-10-30 11:49:00 +0000419
Andrei Popescu402d9372010-02-26 13:31:12 +0000420 if (new_length > elms->length()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000421 // New backing storage is needed.
422 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100423 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +0000424 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +0100425 FixedArray* new_elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000426
427 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100428 if (len > 0) {
429 CopyElements(&no_gc, new_elms, 0, elms, 0, len);
430 }
431 FillWithHoles(new_elms, new_length, capacity);
432
Andrei Popescu402d9372010-02-26 13:31:12 +0000433 elms = new_elms;
434 array->set_elements(elms);
Steve Blocka7e24c12009-10-30 11:49:00 +0000435 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000436
Steve Block6ded16b2010-05-10 14:33:55 +0100437 // Add the provided values.
Andrei Popescu402d9372010-02-26 13:31:12 +0000438 AssertNoAllocation no_gc;
439 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Andrei Popescu402d9372010-02-26 13:31:12 +0000440 for (int index = 0; index < to_add; index++) {
441 elms->set(index + len, args[index + 1], mode);
442 }
443
Steve Blocka7e24c12009-10-30 11:49:00 +0000444 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000445 array->set_length(Smi::FromInt(new_length));
Andrei Popescu402d9372010-02-26 13:31:12 +0000446 return Smi::FromInt(new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000447}
Steve Blocka7e24c12009-10-30 11:49:00 +0000448
449
450BUILTIN(ArrayPop) {
Steve Block6ded16b2010-05-10 14:33:55 +0100451 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100452 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
453 if (elms_obj == NULL) return CallJsBuiltin("ArrayPop", args);
454 if (elms_obj->IsFailure()) return elms_obj;
455 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100456 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000457
458 int len = Smi::cast(array->length())->value();
Steve Block6ded16b2010-05-10 14:33:55 +0100459 if (len == 0) return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000460
461 // Get top element
Steve Blocka7e24c12009-10-30 11:49:00 +0000462 Object* top = elms->get(len - 1);
463
464 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000465 array->set_length(Smi::FromInt(len - 1));
Steve Blocka7e24c12009-10-30 11:49:00 +0000466
467 if (!top->IsTheHole()) {
468 // Delete the top element.
469 elms->set_the_hole(len - 1);
470 return top;
471 }
472
Kristian Monsen25f61362010-05-21 11:50:48 +0100473 top = array->GetPrototype()->GetElement(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000474
475 return top;
476}
Steve Blocka7e24c12009-10-30 11:49:00 +0000477
478
Andrei Popescu402d9372010-02-26 13:31:12 +0000479BUILTIN(ArrayShift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100480 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100481 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
482 if (elms_obj->IsFailure()) return elms_obj;
483 if (elms_obj == NULL ||
484 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100485 return CallJsBuiltin("ArrayShift", args);
486 }
Iain Merrick75681382010-08-19 15:07:18 +0100487 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100488 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000489 ASSERT(array->HasFastElements());
490
491 int len = Smi::cast(array->length())->value();
492 if (len == 0) return Heap::undefined_value();
493
Andrei Popescu402d9372010-02-26 13:31:12 +0000494 // Get first element
495 Object* first = elms->get(0);
496 if (first->IsTheHole()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100497 first = Heap::undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000498 }
499
Steve Block6ded16b2010-05-10 14:33:55 +0100500 if (Heap::new_space()->Contains(elms)) {
501 // As elms still in the same space they used to be (new space),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100502 // there is no need to update region dirty mark.
Steve Block6ded16b2010-05-10 14:33:55 +0100503 array->set_elements(LeftTrimFixedArray(elms, 1), SKIP_WRITE_BARRIER);
504 } else {
505 // Shift the elements.
506 AssertNoAllocation no_gc;
507 MoveElements(&no_gc, elms, 0, elms, 1, len - 1);
508 elms->set(len - 1, Heap::the_hole_value());
Andrei Popescu402d9372010-02-26 13:31:12 +0000509 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000510
511 // Set the length.
512 array->set_length(Smi::FromInt(len - 1));
513
514 return first;
515}
516
517
518BUILTIN(ArrayUnshift) {
Steve Block6ded16b2010-05-10 14:33:55 +0100519 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100520 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
521 if (elms_obj->IsFailure()) return elms_obj;
522 if (elms_obj == NULL ||
523 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100524 return CallJsBuiltin("ArrayUnshift", args);
525 }
Iain Merrick75681382010-08-19 15:07:18 +0100526 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100527 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000528 ASSERT(array->HasFastElements());
529
530 int len = Smi::cast(array->length())->value();
531 int to_add = args.length() - 1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000532 int new_length = len + to_add;
533 // Currently fixed arrays cannot grow too big, so
534 // we should never hit this case.
535 ASSERT(to_add <= (Smi::kMaxValue - len));
536
Andrei Popescu402d9372010-02-26 13:31:12 +0000537 if (new_length > elms->length()) {
538 // New backing storage is needed.
539 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100540 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000541 if (obj->IsFailure()) return obj;
Steve Block6ded16b2010-05-10 14:33:55 +0100542 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000543
544 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100545 if (len > 0) {
546 CopyElements(&no_gc, new_elms, to_add, elms, 0, len);
547 }
548 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000549
550 elms = new_elms;
551 array->set_elements(elms);
552 } else {
553 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100554 MoveElements(&no_gc, elms, to_add, elms, 0, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000555 }
556
557 // Add the provided values.
558 AssertNoAllocation no_gc;
559 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
560 for (int i = 0; i < to_add; i++) {
561 elms->set(i, args[i + 1], mode);
562 }
563
564 // Set the length.
565 array->set_length(Smi::FromInt(new_length));
566 return Smi::FromInt(new_length);
567}
568
569
Andrei Popescu402d9372010-02-26 13:31:12 +0000570BUILTIN(ArraySlice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100571 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100572 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
573 if (elms_obj->IsFailure()) return elms_obj;
574 if (elms_obj == NULL ||
575 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100576 return CallJsBuiltin("ArraySlice", args);
577 }
Iain Merrick75681382010-08-19 15:07:18 +0100578 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100579 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000580 ASSERT(array->HasFastElements());
581
582 int len = Smi::cast(array->length())->value();
583
584 int n_arguments = args.length() - 1;
585
586 // Note carefully choosen defaults---if argument is missing,
Steve Block6ded16b2010-05-10 14:33:55 +0100587 // it's undefined which gets converted to 0 for relative_start
588 // and to len for relative_end.
589 int relative_start = 0;
590 int relative_end = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000591 if (n_arguments > 0) {
592 Object* arg1 = args[1];
593 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100594 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000595 } else if (!arg1->IsUndefined()) {
596 return CallJsBuiltin("ArraySlice", args);
597 }
598 if (n_arguments > 1) {
599 Object* arg2 = args[2];
600 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100601 relative_end = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000602 } else if (!arg2->IsUndefined()) {
603 return CallJsBuiltin("ArraySlice", args);
604 }
605 }
606 }
607
608 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
Steve Block6ded16b2010-05-10 14:33:55 +0100609 int k = (relative_start < 0) ? Max(len + relative_start, 0)
610 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000611
612 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
Steve Block6ded16b2010-05-10 14:33:55 +0100613 int final = (relative_end < 0) ? Max(len + relative_end, 0)
614 : Min(relative_end, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000615
616 // Calculate the length of result array.
617 int result_len = final - k;
Steve Block6ded16b2010-05-10 14:33:55 +0100618 if (result_len <= 0) {
619 return AllocateEmptyJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000620 }
621
Steve Block6ded16b2010-05-10 14:33:55 +0100622 Object* result = AllocateJSArray();
Andrei Popescu402d9372010-02-26 13:31:12 +0000623 if (result->IsFailure()) return result;
624 JSArray* result_array = JSArray::cast(result);
625
Steve Block6ded16b2010-05-10 14:33:55 +0100626 result = Heap::AllocateUninitializedFixedArray(result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000627 if (result->IsFailure()) return result;
628 FixedArray* result_elms = FixedArray::cast(result);
629
Andrei Popescu402d9372010-02-26 13:31:12 +0000630 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100631 CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000632
633 // Set elements.
634 result_array->set_elements(result_elms);
635
636 // Set the length.
637 result_array->set_length(Smi::FromInt(result_len));
638 return result_array;
639}
640
641
642BUILTIN(ArraySplice) {
Steve Block6ded16b2010-05-10 14:33:55 +0100643 Object* receiver = *args.receiver();
Iain Merrick75681382010-08-19 15:07:18 +0100644 Object* elms_obj = EnsureJSArrayWithWritableFastElements(receiver);
645 if (elms_obj->IsFailure()) return elms_obj;
646 if (elms_obj == NULL ||
647 !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
Steve Block6ded16b2010-05-10 14:33:55 +0100648 return CallJsBuiltin("ArraySplice", args);
649 }
Iain Merrick75681382010-08-19 15:07:18 +0100650 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100651 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000652 ASSERT(array->HasFastElements());
653
654 int len = Smi::cast(array->length())->value();
655
656 int n_arguments = args.length() - 1;
657
658 // SpiderMonkey and JSC return undefined in the case where no
659 // arguments are given instead of using the implicit undefined
660 // arguments. This does not follow ECMA-262, but we do the same for
661 // compatibility.
662 // TraceMonkey follows ECMA-262 though.
663 if (n_arguments == 0) {
664 return Heap::undefined_value();
665 }
666
Steve Block6ded16b2010-05-10 14:33:55 +0100667 int relative_start = 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000668 Object* arg1 = args[1];
669 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100670 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000671 } else if (!arg1->IsUndefined()) {
672 return CallJsBuiltin("ArraySplice", args);
673 }
Steve Block6ded16b2010-05-10 14:33:55 +0100674 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
675 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000676
677 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
678 // given differently from when an undefined delete count is given.
679 // This does not follow ECMA-262, but we do the same for
680 // compatibility.
Steve Block6ded16b2010-05-10 14:33:55 +0100681 int delete_count = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000682 if (n_arguments > 1) {
683 Object* arg2 = args[2];
684 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100685 delete_count = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000686 } else {
687 return CallJsBuiltin("ArraySplice", args);
688 }
689 }
Steve Block6ded16b2010-05-10 14:33:55 +0100690 int actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000691
Steve Block6ded16b2010-05-10 14:33:55 +0100692 JSArray* result_array = NULL;
693 if (actual_delete_count == 0) {
694 Object* result = AllocateEmptyJSArray();
695 if (result->IsFailure()) return result;
696 result_array = JSArray::cast(result);
697 } else {
698 // Allocate result array.
699 Object* result = AllocateJSArray();
700 if (result->IsFailure()) return result;
701 result_array = JSArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000702
Steve Block6ded16b2010-05-10 14:33:55 +0100703 result = Heap::AllocateUninitializedFixedArray(actual_delete_count);
704 if (result->IsFailure()) return result;
705 FixedArray* result_elms = FixedArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000706
Steve Block6ded16b2010-05-10 14:33:55 +0100707 AssertNoAllocation no_gc;
708 // Fill newly created array.
709 CopyElements(&no_gc,
710 result_elms, 0,
711 elms, actual_start,
712 actual_delete_count);
Andrei Popescu402d9372010-02-26 13:31:12 +0000713
Steve Block6ded16b2010-05-10 14:33:55 +0100714 // Set elements.
715 result_array->set_elements(result_elms);
Andrei Popescu402d9372010-02-26 13:31:12 +0000716
Steve Block6ded16b2010-05-10 14:33:55 +0100717 // Set the length.
718 result_array->set_length(Smi::FromInt(actual_delete_count));
Andrei Popescu402d9372010-02-26 13:31:12 +0000719 }
720
Steve Block6ded16b2010-05-10 14:33:55 +0100721 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000722
Steve Block6ded16b2010-05-10 14:33:55 +0100723 int new_length = len - actual_delete_count + item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000724
Steve Block6ded16b2010-05-10 14:33:55 +0100725 if (item_count < actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000726 // Shrink the array.
Steve Block6ded16b2010-05-10 14:33:55 +0100727 const bool trim_array = Heap::new_space()->Contains(elms) &&
728 ((actual_start + item_count) <
729 (len - actual_delete_count - actual_start));
730 if (trim_array) {
731 const int delta = actual_delete_count - item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000732
Steve Block6ded16b2010-05-10 14:33:55 +0100733 if (actual_start > 0) {
734 Object** start = elms->data_start();
735 memmove(start + delta, start, actual_start * kPointerSize);
736 }
737
738 elms = LeftTrimFixedArray(elms, delta);
739 array->set_elements(elms, SKIP_WRITE_BARRIER);
740 } else {
741 AssertNoAllocation no_gc;
742 MoveElements(&no_gc,
743 elms, actual_start + item_count,
744 elms, actual_start + actual_delete_count,
745 (len - actual_delete_count - actual_start));
746 FillWithHoles(elms, new_length, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000747 }
Steve Block6ded16b2010-05-10 14:33:55 +0100748 } else if (item_count > actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000749 // Currently fixed arrays cannot grow too big, so
750 // we should never hit this case.
Steve Block6ded16b2010-05-10 14:33:55 +0100751 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
Andrei Popescu402d9372010-02-26 13:31:12 +0000752
753 // Check if array need to grow.
754 if (new_length > elms->length()) {
755 // New backing storage is needed.
756 int capacity = new_length + (new_length >> 1) + 16;
Steve Block6ded16b2010-05-10 14:33:55 +0100757 Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000758 if (obj->IsFailure()) return obj;
Andrei Popescu402d9372010-02-26 13:31:12 +0000759 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000760
Steve Block6ded16b2010-05-10 14:33:55 +0100761 AssertNoAllocation no_gc;
762 // Copy the part before actual_start as is.
763 if (actual_start > 0) {
764 CopyElements(&no_gc, new_elms, 0, elms, 0, actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000765 }
Steve Block6ded16b2010-05-10 14:33:55 +0100766 const int to_copy = len - actual_delete_count - actual_start;
767 if (to_copy > 0) {
768 CopyElements(&no_gc,
769 new_elms, actual_start + item_count,
770 elms, actual_start + actual_delete_count,
771 to_copy);
772 }
773 FillWithHoles(new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000774
Andrei Popescu402d9372010-02-26 13:31:12 +0000775 elms = new_elms;
776 array->set_elements(elms);
Steve Block6ded16b2010-05-10 14:33:55 +0100777 } else {
778 AssertNoAllocation no_gc;
779 MoveElements(&no_gc,
780 elms, actual_start + item_count,
781 elms, actual_start + actual_delete_count,
782 (len - actual_delete_count - actual_start));
Andrei Popescu402d9372010-02-26 13:31:12 +0000783 }
784 }
785
Steve Block6ded16b2010-05-10 14:33:55 +0100786 AssertNoAllocation no_gc;
787 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
788 for (int k = actual_start; k < actual_start + item_count; k++) {
789 elms->set(k, args[3 + k - actual_start], mode);
Andrei Popescu402d9372010-02-26 13:31:12 +0000790 }
791
792 // Set the length.
793 array->set_length(Smi::FromInt(new_length));
794
795 return result_array;
796}
797
798
Steve Block6ded16b2010-05-10 14:33:55 +0100799BUILTIN(ArrayConcat) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100800 Context* global_context = Top::context()->global_context();
801 JSObject* array_proto =
802 JSObject::cast(global_context->array_function()->prototype());
803 if (!ArrayPrototypeHasNoElements(global_context, array_proto)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100804 return CallJsBuiltin("ArrayConcat", args);
805 }
806
807 // Iterate through all the arguments performing checks
808 // and calculating total length.
809 int n_arguments = args.length();
810 int result_len = 0;
811 for (int i = 0; i < n_arguments; i++) {
812 Object* arg = args[i];
Kristian Monsen25f61362010-05-21 11:50:48 +0100813 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
814 || JSArray::cast(arg)->GetPrototype() != array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100815 return CallJsBuiltin("ArrayConcat", args);
816 }
817
818 int len = Smi::cast(JSArray::cast(arg)->length())->value();
819
820 // We shouldn't overflow when adding another len.
821 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
822 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
823 USE(kHalfOfMaxInt);
824 result_len += len;
825 ASSERT(result_len >= 0);
826
827 if (result_len > FixedArray::kMaxLength) {
828 return CallJsBuiltin("ArrayConcat", args);
829 }
830 }
831
832 if (result_len == 0) {
833 return AllocateEmptyJSArray();
834 }
835
836 // Allocate result.
837 Object* result = AllocateJSArray();
838 if (result->IsFailure()) return result;
839 JSArray* result_array = JSArray::cast(result);
840
841 result = Heap::AllocateUninitializedFixedArray(result_len);
842 if (result->IsFailure()) return result;
843 FixedArray* result_elms = FixedArray::cast(result);
844
845 // Copy data.
846 AssertNoAllocation no_gc;
847 int start_pos = 0;
848 for (int i = 0; i < n_arguments; i++) {
849 JSArray* array = JSArray::cast(args[i]);
850 int len = Smi::cast(array->length())->value();
851 if (len > 0) {
852 FixedArray* elms = FixedArray::cast(array->elements());
853 CopyElements(&no_gc, result_elms, start_pos, elms, 0, len);
854 start_pos += len;
855 }
856 }
857 ASSERT(start_pos == result_len);
858
859 // Set the length and elements.
860 result_array->set_length(Smi::FromInt(result_len));
861 result_array->set_elements(result_elms);
862
863 return result_array;
864}
865
866
Steve Blocka7e24c12009-10-30 11:49:00 +0000867// -----------------------------------------------------------------------------
868//
869
870
871// Returns the holder JSObject if the function can legally be called
872// with this receiver. Returns Heap::null_value() if the call is
873// illegal. Any arguments that don't fit the expected type is
874// overwritten with undefined. Arguments that do fit the expected
875// type is overwritten with the object in the prototype chain that
876// actually has that type.
877static inline Object* TypeCheck(int argc,
878 Object** argv,
879 FunctionTemplateInfo* info) {
880 Object* recv = argv[0];
881 Object* sig_obj = info->signature();
882 if (sig_obj->IsUndefined()) return recv;
883 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
884 // If necessary, check the receiver
885 Object* recv_type = sig->receiver();
886
887 Object* holder = recv;
888 if (!recv_type->IsUndefined()) {
889 for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
890 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
891 break;
892 }
893 }
894 if (holder == Heap::null_value()) return holder;
895 }
896 Object* args_obj = sig->args();
897 // If there is no argument signature we're done
898 if (args_obj->IsUndefined()) return holder;
899 FixedArray* args = FixedArray::cast(args_obj);
900 int length = args->length();
901 if (argc <= length) length = argc - 1;
902 for (int i = 0; i < length; i++) {
903 Object* argtype = args->get(i);
904 if (argtype->IsUndefined()) continue;
905 Object** arg = &argv[-1 - i];
906 Object* current = *arg;
907 for (; current != Heap::null_value(); current = current->GetPrototype()) {
908 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
909 *arg = current;
910 break;
911 }
912 }
913 if (current == Heap::null_value()) *arg = Heap::undefined_value();
914 }
915 return holder;
916}
917
918
Leon Clarkee46be812010-01-19 14:06:41 +0000919template <bool is_construct>
920static Object* HandleApiCallHelper(
921 BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
922 ASSERT(is_construct == CalledAsConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +0000923
Leon Clarkee46be812010-01-19 14:06:41 +0000924 HandleScope scope;
925 Handle<JSFunction> function = args.called_function();
Steve Block6ded16b2010-05-10 14:33:55 +0100926 ASSERT(function->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +0000927
Steve Block6ded16b2010-05-10 14:33:55 +0100928 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
Steve Blocka7e24c12009-10-30 11:49:00 +0000929 if (is_construct) {
Steve Block6ded16b2010-05-10 14:33:55 +0100930 Handle<FunctionTemplateInfo> desc(fun_data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000931 bool pending_exception = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000932 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000933 &pending_exception);
934 ASSERT(Top::has_pending_exception() == pending_exception);
935 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +0100936 fun_data = *desc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000937 }
938
Steve Blocka7e24c12009-10-30 11:49:00 +0000939 Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
940
941 if (raw_holder->IsNull()) {
942 // This function cannot be called with the given receiver. Abort!
943 Handle<Object> obj =
944 Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
945 return Top::Throw(*obj);
946 }
947
948 Object* raw_call_data = fun_data->call_code();
949 if (!raw_call_data->IsUndefined()) {
950 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
951 Object* callback_obj = call_data->callback();
952 v8::InvocationCallback callback =
953 v8::ToCData<v8::InvocationCallback>(callback_obj);
954 Object* data_obj = call_data->data();
955 Object* result;
956
Steve Blocka7e24c12009-10-30 11:49:00 +0000957 Handle<Object> data_handle(data_obj);
958 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
959 ASSERT(raw_holder->IsJSObject());
960 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
961 Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
962 v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
Leon Clarkee46be812010-01-19 14:06:41 +0000963 LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +0000964 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
965 data,
966 holder,
967 callee,
968 is_construct,
969 reinterpret_cast<void**>(&args[0] - 1),
970 args.length() - 1);
971
972 v8::Handle<v8::Value> value;
973 {
974 // Leaving JavaScript.
975 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000976#ifdef ENABLE_LOGGING_AND_PROFILING
977 state.set_external_callback(v8::ToCData<Address>(callback_obj));
978#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000979 value = callback(new_args);
980 }
981 if (value.IsEmpty()) {
982 result = Heap::undefined_value();
983 } else {
984 result = *reinterpret_cast<Object**>(*value);
985 }
986
987 RETURN_IF_SCHEDULED_EXCEPTION();
988 if (!is_construct || result->IsJSObject()) return result;
989 }
990
Leon Clarkee46be812010-01-19 14:06:41 +0000991 return *args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +0000992}
Leon Clarkee46be812010-01-19 14:06:41 +0000993
994
995BUILTIN(HandleApiCall) {
996 return HandleApiCallHelper<false>(args);
997}
998
999
1000BUILTIN(HandleApiCallConstruct) {
1001 return HandleApiCallHelper<true>(args);
1002}
Steve Blocka7e24c12009-10-30 11:49:00 +00001003
1004
Andrei Popescu402d9372010-02-26 13:31:12 +00001005#ifdef DEBUG
1006
1007static void VerifyTypeCheck(Handle<JSObject> object,
1008 Handle<JSFunction> function) {
Steve Block6ded16b2010-05-10 14:33:55 +01001009 ASSERT(function->shared()->IsApiFunction());
1010 FunctionTemplateInfo* info = function->shared()->get_api_func_data();
Andrei Popescu402d9372010-02-26 13:31:12 +00001011 if (info->signature()->IsUndefined()) return;
1012 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1013 Object* receiver_type = signature->receiver();
1014 if (receiver_type->IsUndefined()) return;
1015 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
1016 ASSERT(object->IsInstanceOf(type));
1017}
1018
1019#endif
1020
1021
1022BUILTIN(FastHandleApiCall) {
1023 ASSERT(!CalledAsConstructor());
1024 const bool is_construct = false;
1025
1026 // We expect four more arguments: function, callback, call data, and holder.
1027 const int args_length = args.length() - 4;
1028 ASSERT(args_length >= 0);
1029
1030 Handle<JSFunction> function = args.at<JSFunction>(args_length);
1031 Object* callback_obj = args[args_length + 1];
1032 Handle<Object> data_handle = args.at<Object>(args_length + 2);
1033 Handle<JSObject> checked_holder = args.at<JSObject>(args_length + 3);
1034
1035#ifdef DEBUG
1036 VerifyTypeCheck(checked_holder, function);
1037#endif
1038
1039 v8::Local<v8::Object> holder = v8::Utils::ToLocal(checked_holder);
1040 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
1041 v8::InvocationCallback callback =
1042 v8::ToCData<v8::InvocationCallback>(callback_obj);
1043 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
1044
1045 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1046 data,
1047 holder,
1048 callee,
1049 is_construct,
1050 reinterpret_cast<void**>(&args[0] - 1),
1051 args_length - 1);
1052
1053 HandleScope scope;
1054 Object* result;
1055 v8::Handle<v8::Value> value;
1056 {
1057 // Leaving JavaScript.
1058 VMState state(EXTERNAL);
1059#ifdef ENABLE_LOGGING_AND_PROFILING
1060 state.set_external_callback(v8::ToCData<Address>(callback_obj));
1061#endif
1062 value = callback(new_args);
1063 }
1064 if (value.IsEmpty()) {
1065 result = Heap::undefined_value();
1066 } else {
1067 result = *reinterpret_cast<Object**>(*value);
1068 }
1069
1070 RETURN_IF_SCHEDULED_EXCEPTION();
1071 return result;
1072}
1073
1074
Steve Blocka7e24c12009-10-30 11:49:00 +00001075// Helper function to handle calls to non-function objects created through the
1076// API. The object can be called as either a constructor (using new) or just as
1077// a function (without new).
Leon Clarkee46be812010-01-19 14:06:41 +00001078static Object* HandleApiCallAsFunctionOrConstructor(
1079 bool is_construct_call,
1080 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001081 // Non-functions are never called as constructors. Even if this is an object
1082 // called as a constructor the delegate call is not a construct call.
1083 ASSERT(!CalledAsConstructor());
1084
1085 Handle<Object> receiver = args.at<Object>(0);
1086
1087 // Get the object called.
Leon Clarkee46be812010-01-19 14:06:41 +00001088 JSObject* obj = JSObject::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +00001089
1090 // Get the invocation callback from the function descriptor that was
1091 // used to create the called object.
1092 ASSERT(obj->map()->has_instance_call_handler());
1093 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01001094 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001095 Object* handler =
Steve Block6ded16b2010-05-10 14:33:55 +01001096 constructor->shared()->get_api_func_data()->instance_call_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00001097 ASSERT(!handler->IsUndefined());
1098 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1099 Object* callback_obj = call_data->callback();
1100 v8::InvocationCallback callback =
1101 v8::ToCData<v8::InvocationCallback>(callback_obj);
1102
1103 // Get the data for the call and perform the callback.
1104 Object* data_obj = call_data->data();
1105 Object* result;
1106 { HandleScope scope;
1107 v8::Local<v8::Object> self =
Leon Clarkee46be812010-01-19 14:06:41 +00001108 v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001109 Handle<Object> data_handle(data_obj);
1110 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
1111 Handle<JSFunction> callee_handle(constructor);
1112 v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
Leon Clarkee46be812010-01-19 14:06:41 +00001113 LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +00001114 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
1115 data,
1116 self,
1117 callee,
1118 is_construct_call,
1119 reinterpret_cast<void**>(&args[0] - 1),
1120 args.length() - 1);
1121 v8::Handle<v8::Value> value;
1122 {
1123 // Leaving JavaScript.
1124 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +00001125#ifdef ENABLE_LOGGING_AND_PROFILING
1126 state.set_external_callback(v8::ToCData<Address>(callback_obj));
1127#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00001128 value = callback(new_args);
1129 }
1130 if (value.IsEmpty()) {
1131 result = Heap::undefined_value();
1132 } else {
1133 result = *reinterpret_cast<Object**>(*value);
1134 }
1135 }
1136 // Check for exceptions and return result.
1137 RETURN_IF_SCHEDULED_EXCEPTION();
1138 return result;
1139}
1140
1141
1142// Handle calls to non-function objects created through the API. This delegate
1143// function is used when the call is a normal function call.
1144BUILTIN(HandleApiCallAsFunction) {
1145 return HandleApiCallAsFunctionOrConstructor(false, args);
1146}
Steve Blocka7e24c12009-10-30 11:49:00 +00001147
1148
1149// Handle calls to non-function objects created through the API. This delegate
1150// function is used when the call is a construct call.
1151BUILTIN(HandleApiCallAsConstructor) {
1152 return HandleApiCallAsFunctionOrConstructor(true, args);
1153}
Steve Blocka7e24c12009-10-30 11:49:00 +00001154
1155
1156static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1157 LoadIC::GenerateArrayLength(masm);
1158}
1159
1160
1161static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
1162 LoadIC::GenerateStringLength(masm);
1163}
1164
1165
1166static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1167 LoadIC::GenerateFunctionPrototype(masm);
1168}
1169
1170
1171static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1172 LoadIC::GenerateInitialize(masm);
1173}
1174
1175
1176static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1177 LoadIC::GeneratePreMonomorphic(masm);
1178}
1179
1180
1181static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1182 LoadIC::GenerateMiss(masm);
1183}
1184
1185
1186static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1187 LoadIC::GenerateMegamorphic(masm);
1188}
1189
1190
1191static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1192 LoadIC::GenerateNormal(masm);
1193}
1194
1195
1196static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1197 KeyedLoadIC::GenerateInitialize(masm);
1198}
1199
1200
1201static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1202 KeyedLoadIC::GenerateMiss(masm);
1203}
1204
1205
1206static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1207 KeyedLoadIC::GenerateGeneric(masm);
1208}
1209
1210
Leon Clarkee46be812010-01-19 14:06:41 +00001211static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1212 KeyedLoadIC::GenerateString(masm);
1213}
1214
1215
Steve Block3ce2e202009-11-05 08:53:23 +00001216static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
1217 KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
1218}
1219
1220
1221static void Generate_KeyedLoadIC_ExternalUnsignedByteArray(
1222 MacroAssembler* masm) {
1223 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1224}
1225
1226
1227static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) {
1228 KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray);
1229}
1230
1231
1232static void Generate_KeyedLoadIC_ExternalUnsignedShortArray(
1233 MacroAssembler* masm) {
1234 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1235}
1236
1237
1238static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) {
1239 KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray);
1240}
1241
1242
1243static void Generate_KeyedLoadIC_ExternalUnsignedIntArray(
1244 MacroAssembler* masm) {
1245 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1246}
1247
1248
1249static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) {
1250 KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray);
1251}
1252
1253
Steve Blocka7e24c12009-10-30 11:49:00 +00001254static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1255 KeyedLoadIC::GeneratePreMonomorphic(masm);
1256}
1257
Andrei Popescu402d9372010-02-26 13:31:12 +00001258static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1259 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1260}
1261
Steve Blocka7e24c12009-10-30 11:49:00 +00001262
1263static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1264 StoreIC::GenerateInitialize(masm);
1265}
1266
1267
1268static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1269 StoreIC::GenerateMiss(masm);
1270}
1271
1272
Steve Block8defd9f2010-07-08 12:39:36 +01001273static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1274 StoreIC::GenerateNormal(masm);
1275}
1276
1277
Steve Blocka7e24c12009-10-30 11:49:00 +00001278static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
1279 StoreIC::GenerateMegamorphic(masm);
1280}
1281
1282
Steve Block6ded16b2010-05-10 14:33:55 +01001283static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1284 StoreIC::GenerateArrayLength(masm);
1285}
1286
1287
Steve Blocka7e24c12009-10-30 11:49:00 +00001288static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
1289 KeyedStoreIC::GenerateGeneric(masm);
1290}
1291
1292
Steve Block3ce2e202009-11-05 08:53:23 +00001293static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) {
1294 KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray);
1295}
1296
1297
1298static void Generate_KeyedStoreIC_ExternalUnsignedByteArray(
1299 MacroAssembler* masm) {
1300 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
1301}
1302
1303
1304static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) {
1305 KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray);
1306}
1307
1308
1309static void Generate_KeyedStoreIC_ExternalUnsignedShortArray(
1310 MacroAssembler* masm) {
1311 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
1312}
1313
1314
1315static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) {
1316 KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray);
1317}
1318
1319
1320static void Generate_KeyedStoreIC_ExternalUnsignedIntArray(
1321 MacroAssembler* masm) {
1322 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
1323}
1324
1325
1326static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) {
1327 KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray);
1328}
1329
1330
Steve Blocka7e24c12009-10-30 11:49:00 +00001331static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1332 KeyedStoreIC::GenerateMiss(masm);
1333}
1334
1335
1336static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1337 KeyedStoreIC::GenerateInitialize(masm);
1338}
1339
1340
1341#ifdef ENABLE_DEBUGGER_SUPPORT
1342static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1343 Debug::GenerateLoadICDebugBreak(masm);
1344}
1345
1346
1347static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1348 Debug::GenerateStoreICDebugBreak(masm);
1349}
1350
1351
1352static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1353 Debug::GenerateKeyedLoadICDebugBreak(masm);
1354}
1355
1356
1357static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1358 Debug::GenerateKeyedStoreICDebugBreak(masm);
1359}
1360
1361
1362static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1363 Debug::GenerateConstructCallDebugBreak(masm);
1364}
1365
1366
1367static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1368 Debug::GenerateReturnDebugBreak(masm);
1369}
1370
1371
1372static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
1373 Debug::GenerateStubNoRegistersDebugBreak(masm);
1374}
Steve Block6ded16b2010-05-10 14:33:55 +01001375
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001376
1377static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1378 Debug::GenerateSlotDebugBreak(masm);
1379}
1380
1381
Steve Block6ded16b2010-05-10 14:33:55 +01001382static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1383 Debug::GeneratePlainReturnLiveEdit(masm);
1384}
1385
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001386
Steve Block6ded16b2010-05-10 14:33:55 +01001387static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1388 Debug::GenerateFrameDropperLiveEdit(masm);
1389}
Steve Blocka7e24c12009-10-30 11:49:00 +00001390#endif
1391
1392Object* Builtins::builtins_[builtin_count] = { NULL, };
1393const char* Builtins::names_[builtin_count] = { NULL, };
1394
Leon Clarkee46be812010-01-19 14:06:41 +00001395#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Steve Blocka7e24c12009-10-30 11:49:00 +00001396 Address Builtins::c_functions_[cfunction_count] = {
1397 BUILTIN_LIST_C(DEF_ENUM_C)
1398 };
1399#undef DEF_ENUM_C
1400
1401#define DEF_JS_NAME(name, ignore) #name,
1402#define DEF_JS_ARGC(ignore, argc) argc,
1403const char* Builtins::javascript_names_[id_count] = {
1404 BUILTINS_LIST_JS(DEF_JS_NAME)
1405};
1406
1407int Builtins::javascript_argc_[id_count] = {
1408 BUILTINS_LIST_JS(DEF_JS_ARGC)
1409};
1410#undef DEF_JS_NAME
1411#undef DEF_JS_ARGC
1412
1413static bool is_initialized = false;
1414void Builtins::Setup(bool create_heap_objects) {
1415 ASSERT(!is_initialized);
1416
1417 // Create a scope for the handles in the builtins.
1418 HandleScope scope;
1419
1420 struct BuiltinDesc {
1421 byte* generator;
1422 byte* c_code;
1423 const char* s_name; // name is only used for generating log information.
1424 int name;
1425 Code::Flags flags;
Leon Clarkee46be812010-01-19 14:06:41 +00001426 BuiltinExtraArguments extra_args;
Steve Blocka7e24c12009-10-30 11:49:00 +00001427 };
1428
Leon Clarkee46be812010-01-19 14:06:41 +00001429#define DEF_FUNCTION_PTR_C(name, extra_args) \
1430 { FUNCTION_ADDR(Generate_Adaptor), \
1431 FUNCTION_ADDR(Builtin_##name), \
1432 #name, \
1433 c_##name, \
1434 Code::ComputeFlags(Code::BUILTIN), \
1435 extra_args \
Steve Blocka7e24c12009-10-30 11:49:00 +00001436 },
1437
1438#define DEF_FUNCTION_PTR_A(name, kind, state) \
1439 { FUNCTION_ADDR(Generate_##name), \
1440 NULL, \
1441 #name, \
1442 name, \
Leon Clarkee46be812010-01-19 14:06:41 +00001443 Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
1444 NO_EXTRA_ARGUMENTS \
Steve Blocka7e24c12009-10-30 11:49:00 +00001445 },
1446
1447 // Define array of pointers to generators and C builtin functions.
1448 static BuiltinDesc functions[] = {
1449 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1450 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1451 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1452 // Terminator:
Leon Clarkee46be812010-01-19 14:06:41 +00001453 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
1454 NO_EXTRA_ARGUMENTS }
Steve Blocka7e24c12009-10-30 11:49:00 +00001455 };
1456
1457#undef DEF_FUNCTION_PTR_C
1458#undef DEF_FUNCTION_PTR_A
1459
1460 // For now we generate builtin adaptor code into a stack-allocated
1461 // buffer, before copying it into individual code objects.
1462 byte buffer[4*KB];
1463
1464 // Traverse the list of builtins and generate an adaptor in a
1465 // separate code object for each one.
1466 for (int i = 0; i < builtin_count; i++) {
1467 if (create_heap_objects) {
1468 MacroAssembler masm(buffer, sizeof buffer);
1469 // Generate the code/adaptor.
Leon Clarkee46be812010-01-19 14:06:41 +00001470 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001471 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1472 // We pass all arguments to the generator, but it may not use all of
1473 // them. This works because the first arguments are on top of the
1474 // stack.
Leon Clarkee46be812010-01-19 14:06:41 +00001475 g(&masm, functions[i].name, functions[i].extra_args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001476 // Move the code into the object heap.
1477 CodeDesc desc;
1478 masm.GetCode(&desc);
1479 Code::Flags flags = functions[i].flags;
1480 Object* code;
1481 {
1482 // During startup it's OK to always allocate and defer GC to later.
1483 // This simplifies things because we don't need to retry.
1484 AlwaysAllocateScope __scope__;
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001485 code = Heap::CreateCode(desc, flags, masm.CodeObject());
Steve Blocka7e24c12009-10-30 11:49:00 +00001486 if (code->IsFailure()) {
1487 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1488 }
1489 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001490 // Log the event and add the code to the builtins array.
Steve Block6ded16b2010-05-10 14:33:55 +01001491 PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
1492 Code::cast(code), functions[i].s_name));
Steve Blocka7e24c12009-10-30 11:49:00 +00001493 builtins_[i] = code;
1494#ifdef ENABLE_DISASSEMBLER
1495 if (FLAG_print_builtin_code) {
1496 PrintF("Builtin: %s\n", functions[i].s_name);
1497 Code::cast(code)->Disassemble(functions[i].s_name);
1498 PrintF("\n");
1499 }
1500#endif
1501 } else {
1502 // Deserializing. The values will be filled in during IterateBuiltins.
1503 builtins_[i] = NULL;
1504 }
1505 names_[i] = functions[i].s_name;
1506 }
1507
1508 // Mark as initialized.
1509 is_initialized = true;
1510}
1511
1512
1513void Builtins::TearDown() {
1514 is_initialized = false;
1515}
1516
1517
1518void Builtins::IterateBuiltins(ObjectVisitor* v) {
1519 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1520}
1521
1522
1523const char* Builtins::Lookup(byte* pc) {
1524 if (is_initialized) { // may be called during initialization (disassembler!)
1525 for (int i = 0; i < builtin_count; i++) {
1526 Code* entry = Code::cast(builtins_[i]);
1527 if (entry->contains(pc)) {
1528 return names_[i];
1529 }
1530 }
1531 }
1532 return NULL;
1533}
1534
1535
1536} } // namespace v8::internal