blob: ae3dab46c3f3038a4a8157691211f1b7ec8e16ce [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"
Ben Murdochb8e0da22011-05-16 14:20:40 +010034#include "gdb-jit.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035#include "ic-inl.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010036#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000037
38namespace v8 {
39namespace internal {
40
Leon Clarkee46be812010-01-19 14:06:41 +000041namespace {
42
43// Arguments object passed to C++ builtins.
44template <BuiltinExtraArguments extra_args>
45class BuiltinArguments : public Arguments {
46 public:
47 BuiltinArguments(int length, Object** arguments)
48 : Arguments(length, arguments) { }
49
50 Object*& operator[] (int index) {
51 ASSERT(index < length());
52 return Arguments::operator[](index);
53 }
54
55 template <class S> Handle<S> at(int index) {
56 ASSERT(index < length());
57 return Arguments::at<S>(index);
58 }
59
60 Handle<Object> receiver() {
61 return Arguments::at<Object>(0);
62 }
63
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).
71 int length() const {
72 STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
73 return Arguments::length();
74 }
75
76#ifdef DEBUG
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
87template <>
88int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
89 return Arguments::length() - 1;
90}
91
92#ifdef DEBUG
93template <>
94void 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;
105BUILTIN_LIST_C(DEF_ARG_TYPE)
106#undef DEF_ARG_TYPE
107
108} // namespace
109
Steve Blocka7e24c12009-10-30 11:49:00 +0000110// ----------------------------------------------------------------------------
Leon Clarkee46be812010-01-19 14:06:41 +0000111// Support macro for defining builtins in C++.
Steve Blocka7e24c12009-10-30 11:49:00 +0000112// ----------------------------------------------------------------------------
113//
114// A builtin function is defined by writing:
115//
116// BUILTIN(name) {
117// ...
118// }
Steve Blocka7e24c12009-10-30 11:49:00 +0000119//
Leon Clarkee46be812010-01-19 14:06:41 +0000120// In the body of the builtin function the arguments can be accessed
121// through the BuiltinArguments object args.
Steve Blocka7e24c12009-10-30 11:49:00 +0000122
Leon Clarkee46be812010-01-19 14:06:41 +0000123#ifdef DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +0000124
Steve Block44f0eee2011-05-26 01:26:41 +0100125#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)
Steve Blocka7e24c12009-10-30 11:49:00 +0000136
Leon Clarkee46be812010-01-19 14:06:41 +0000137#else // For release mode.
Steve Blocka7e24c12009-10-30 11:49:00 +0000138
Steve Block44f0eee2011-05-26 01:26:41 +0100139#define BUILTIN(name) \
140 static MaybeObject* Builtin_##name(name##ArgumentsType args, Isolate* isolate)
Leon Clarkee46be812010-01-19 14:06:41 +0000141
142#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000143
144
Steve Block44f0eee2011-05-26 01:26:41 +0100145static inline bool CalledAsConstructor(Isolate* isolate) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000146#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
Steve Block44f0eee2011-05-26 01:26:41 +0100156 Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
Steve Blocka7e24c12009-10-30 11:49:00 +0000157 // 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
Steve Blocka7e24c12009-10-30 11:49:00 +0000175BUILTIN(Illegal) {
176 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +0100177 return isolate->heap()->undefined_value(); // Make compiler happy.
Steve Blocka7e24c12009-10-30 11:49:00 +0000178}
Steve Blocka7e24c12009-10-30 11:49:00 +0000179
180
181BUILTIN(EmptyFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +0100182 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000183}
Steve Blocka7e24c12009-10-30 11:49:00 +0000184
185
186BUILTIN(ArrayCodeGeneric) {
Steve Block44f0eee2011-05-26 01:26:41 +0100187 Heap* heap = isolate->heap();
188 isolate->counters()->array_function_runtime()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +0000189
190 JSArray* array;
Steve Block44f0eee2011-05-26 01:26:41 +0100191 if (CalledAsConstructor(isolate)) {
Leon Clarkee46be812010-01-19 14:06:41 +0000192 array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000193 } else {
194 // Allocate the JS Array
195 JSFunction* constructor =
Steve Block44f0eee2011-05-26 01:26:41 +0100196 isolate->context()->global_context()->array_function();
John Reck59135872010-11-02 12:39:01 -0700197 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100198 { MaybeObject* maybe_obj = heap->AllocateJSObject(constructor);
John Reck59135872010-11-02 12:39:01 -0700199 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
200 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000201 array = JSArray::cast(obj);
202 }
203
204 // 'array' now contains the JSArray we should initialize.
Steve Block8defd9f2010-07-08 12:39:36 +0100205 ASSERT(array->HasFastElements());
Steve Blocka7e24c12009-10-30 11:49:00 +0000206
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) {
John Reck59135872010-11-02 12:39:01 -0700214 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100215 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
John Reck59135872010-11-02 12:39:01 -0700216 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
217 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000218 array->SetContent(FixedArray::cast(obj));
219 return array;
220 }
221 }
222 // Take the argument as the length.
John Reck59135872010-11-02 12:39:01 -0700223 { MaybeObject* maybe_obj = array->Initialize(0);
224 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
225 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000226 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);
John Reck59135872010-11-02 12:39:01 -0700237 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100238 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len->value());
John Reck59135872010-11-02 12:39:01 -0700239 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
240 }
Leon Clarke4515c472010-02-03 11:58:03 +0000241
242 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000243 FixedArray* elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000244 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +0000245 // 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));
Leon Clarke4515c472010-02-03 11:58:03 +0000252 array->set_length(len);
Steve Blocka7e24c12009-10-30 11:49:00 +0000253
254 return array;
255}
Steve Blocka7e24c12009-10-30 11:49:00 +0000256
257
Steve Block44f0eee2011-05-26 01:26:41 +0100258MUST_USE_RESULT static MaybeObject* AllocateJSArray(Heap* heap) {
Steve Block6ded16b2010-05-10 14:33:55 +0100259 JSFunction* array_function =
Steve Block44f0eee2011-05-26 01:26:41 +0100260 heap->isolate()->context()->global_context()->array_function();
John Reck59135872010-11-02 12:39:01 -0700261 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100262 { MaybeObject* maybe_result = heap->AllocateJSObject(array_function);
John Reck59135872010-11-02 12:39:01 -0700263 if (!maybe_result->ToObject(&result)) return maybe_result;
264 }
Steve Block6ded16b2010-05-10 14:33:55 +0100265 return result;
266}
267
268
Steve Block44f0eee2011-05-26 01:26:41 +0100269MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray(Heap* heap) {
John Reck59135872010-11-02 12:39:01 -0700270 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100271 { MaybeObject* maybe_result = AllocateJSArray(heap);
John Reck59135872010-11-02 12:39:01 -0700272 if (!maybe_result->ToObject(&result)) return maybe_result;
273 }
Steve Block6ded16b2010-05-10 14:33:55 +0100274 JSArray* result_array = JSArray::cast(result);
275 result_array->set_length(Smi::FromInt(0));
Steve Block44f0eee2011-05-26 01:26:41 +0100276 result_array->set_elements(heap->empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +0100277 return result_array;
278}
279
280
Steve Block44f0eee2011-05-26 01:26:41 +0100281static void CopyElements(Heap* heap,
282 AssertNoAllocation* no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100283 FixedArray* dst,
284 int dst_index,
285 FixedArray* src,
286 int src_index,
287 int len) {
288 ASSERT(dst != src); // Use MoveElements instead.
Steve Block44f0eee2011-05-26 01:26:41 +0100289 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100290 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) {
Steve Block44f0eee2011-05-26 01:26:41 +0100296 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
Steve Block6ded16b2010-05-10 14:33:55 +0100297 }
298}
299
300
Steve Block44f0eee2011-05-26 01:26:41 +0100301static void MoveElements(Heap* heap,
302 AssertNoAllocation* no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100303 FixedArray* dst,
304 int dst_index,
305 FixedArray* src,
306 int src_index,
307 int len) {
Steve Block44f0eee2011-05-26 01:26:41 +0100308 ASSERT(dst->map() != HEAP->fixed_cow_array_map());
Steve Block6ded16b2010-05-10 14:33:55 +0100309 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) {
Steve Block44f0eee2011-05-26 01:26:41 +0100314 heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
Steve Block6ded16b2010-05-10 14:33:55 +0100315 }
316}
317
318
Steve Block44f0eee2011-05-26 01:26:41 +0100319static 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);
Steve Block6ded16b2010-05-10 14:33:55 +0100322}
323
324
Steve Block44f0eee2011-05-26 01:26:41 +0100325static FixedArray* LeftTrimFixedArray(Heap* heap,
326 FixedArray* elms,
327 int to_trim) {
328 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
Steve Block791712a2010-08-27 10:21:07 +0100329 // For now this trick is only applied to fixed arrays in new and paged space.
Steve Block6ded16b2010-05-10 14:33:55 +0100330 // In large object space the object's start must coincide with chunk
331 // and thus the trick is just not applicable.
Steve Block44f0eee2011-05-26 01:26:41 +0100332 ASSERT(!HEAP->lo_space()->Contains(elms));
Steve Block6ded16b2010-05-10 14:33:55 +0100333
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
Steve Block791712a2010-08-27 10:21:07 +0100342 if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
Steve Block44f0eee2011-05-26 01:26:41 +0100343 !heap->new_space()->Contains(elms)) {
Steve Block791712a2010-08-27 10:21:07 +0100344 // 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 }
Steve Block6ded16b2010-05-10 14:33:55 +0100353 // 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.
Steve Block44f0eee2011-05-26 01:26:41 +0100356 heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
Steve Block6ded16b2010-05-10 14:33:55 +0100357
Steve Block44f0eee2011-05-26 01:26:41 +0100358 former_start[to_trim] = heap->fixed_array_map();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100359 former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
Steve Block6ded16b2010-05-10 14:33:55 +0100360
Steve Block791712a2010-08-27 10:21:07 +0100361 return FixedArray::cast(HeapObject::FromAddress(
362 elms->address() + to_trim * kPointerSize));
Steve Block6ded16b2010-05-10 14:33:55 +0100363}
364
365
Steve Block44f0eee2011-05-26 01:26:41 +0100366static bool ArrayPrototypeHasNoElements(Heap* heap,
367 Context* global_context,
Kristian Monsen25f61362010-05-21 11:50:48 +0100368 JSObject* array_proto) {
Steve Block6ded16b2010-05-10 14:33:55 +0100369 // This method depends on non writability of Object and Array prototype
370 // fields.
Steve Block44f0eee2011-05-26 01:26:41 +0100371 if (array_proto->elements() != heap->empty_fixed_array()) return false;
Steve Block6ded16b2010-05-10 14:33:55 +0100372 // Hidden prototype
Kristian Monsen25f61362010-05-21 11:50:48 +0100373 array_proto = JSObject::cast(array_proto->GetPrototype());
Steve Block44f0eee2011-05-26 01:26:41 +0100374 ASSERT(array_proto->elements() == heap->empty_fixed_array());
Steve Block6ded16b2010-05-10 14:33:55 +0100375 // Object.prototype
Steve Block1e0659c2011-05-24 12:43:12 +0100376 Object* proto = array_proto->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +0100377 if (proto == heap->null_value()) return false;
Steve Block1e0659c2011-05-24 12:43:12 +0100378 array_proto = JSObject::cast(proto);
Kristian Monsen25f61362010-05-21 11:50:48 +0100379 if (array_proto != global_context->initial_object_prototype()) return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100380 if (array_proto->elements() != heap->empty_fixed_array()) return false;
Kristian Monsen25f61362010-05-21 11:50:48 +0100381 ASSERT(array_proto->GetPrototype()->IsNull());
Steve Block6ded16b2010-05-10 14:33:55 +0100382 return true;
383}
384
385
John Reck59135872010-11-02 12:39:01 -0700386MUST_USE_RESULT
387static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
Steve Block44f0eee2011-05-26 01:26:41 +0100388 Heap* heap, Object* receiver) {
Iain Merrick75681382010-08-19 15:07:18 +0100389 if (!receiver->IsJSArray()) return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100390 JSArray* array = JSArray::cast(receiver);
Steve Block9fac8402011-05-12 15:51:54 +0100391 HeapObject* elms = array->elements();
Steve Block44f0eee2011-05-26 01:26:41 +0100392 if (elms->map() == heap->fixed_array_map()) return elms;
393 if (elms->map() == heap->fixed_cow_array_map()) {
Iain Merrick75681382010-08-19 15:07:18 +0100394 return array->EnsureWritableFastElements();
Steve Block6ded16b2010-05-10 14:33:55 +0100395 }
Iain Merrick75681382010-08-19 15:07:18 +0100396 return NULL;
Steve Block6ded16b2010-05-10 14:33:55 +0100397}
398
399
Steve Block44f0eee2011-05-26 01:26:41 +0100400static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
401 JSArray* receiver) {
402 Context* global_context = heap->isolate()->context()->global_context();
Kristian Monsen25f61362010-05-21 11:50:48 +0100403 JSObject* array_proto =
404 JSObject::cast(global_context->array_function()->prototype());
Iain Merrick75681382010-08-19 15:07:18 +0100405 return receiver->GetPrototype() == array_proto &&
Steve Block44f0eee2011-05-26 01:26:41 +0100406 ArrayPrototypeHasNoElements(heap, global_context, array_proto);
Kristian Monsen25f61362010-05-21 11:50:48 +0100407}
408
409
John Reck59135872010-11-02 12:39:01 -0700410MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
Steve Block44f0eee2011-05-26 01:26:41 +0100411 Isolate* isolate,
John Reck59135872010-11-02 12:39:01 -0700412 const char* name,
413 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Block44f0eee2011-05-26 01:26:41 +0100414 HandleScope handleScope(isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100415
416 Handle<Object> js_builtin =
Steve Block44f0eee2011-05-26 01:26:41 +0100417 GetProperty(Handle<JSObject>(
418 isolate->global_context()->builtins()),
419 name);
Steve Block6ded16b2010-05-10 14:33:55 +0100420 ASSERT(js_builtin->IsJSFunction());
421 Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
Kristian Monsen25f61362010-05-21 11:50:48 +0100422 ScopedVector<Object**> argv(args.length() - 1);
Steve Block6ded16b2010-05-10 14:33:55 +0100423 int n_args = args.length() - 1;
424 for (int i = 0; i < n_args; i++) {
425 argv[i] = args.at<Object>(i + 1).location();
426 }
427 bool pending_exception = false;
428 Handle<Object> result = Execution::Call(function,
429 args.receiver(),
430 n_args,
431 argv.start(),
432 &pending_exception);
Steve Block6ded16b2010-05-10 14:33:55 +0100433 if (pending_exception) return Failure::Exception();
434 return *result;
435}
436
437
Steve Blocka7e24c12009-10-30 11:49:00 +0000438BUILTIN(ArrayPush) {
Steve Block44f0eee2011-05-26 01:26:41 +0100439 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100440 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700441 Object* elms_obj;
442 { MaybeObject* maybe_elms_obj =
Steve Block44f0eee2011-05-26 01:26:41 +0100443 EnsureJSArrayWithWritableFastElements(heap, receiver);
444 if (maybe_elms_obj == NULL) {
445 return CallJsBuiltin(isolate, "ArrayPush", args);
446 }
John Reck59135872010-11-02 12:39:01 -0700447 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
448 }
Iain Merrick75681382010-08-19 15:07:18 +0100449 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100450 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000451
Steve Blocka7e24c12009-10-30 11:49:00 +0000452 int len = Smi::cast(array->length())->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000453 int to_add = args.length() - 1;
454 if (to_add == 0) {
455 return Smi::FromInt(len);
456 }
457 // Currently fixed arrays cannot grow too big, so
458 // we should never hit this case.
459 ASSERT(to_add <= (Smi::kMaxValue - len));
Steve Blocka7e24c12009-10-30 11:49:00 +0000460
Andrei Popescu402d9372010-02-26 13:31:12 +0000461 int new_length = len + to_add;
Steve Blocka7e24c12009-10-30 11:49:00 +0000462
Andrei Popescu402d9372010-02-26 13:31:12 +0000463 if (new_length > elms->length()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000464 // New backing storage is needed.
465 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700466 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100467 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
John Reck59135872010-11-02 12:39:01 -0700468 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
469 }
Steve Block6ded16b2010-05-10 14:33:55 +0100470 FixedArray* new_elms = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +0000471
472 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100473 if (len > 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100474 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, len);
Steve Block6ded16b2010-05-10 14:33:55 +0100475 }
Steve Block44f0eee2011-05-26 01:26:41 +0100476 FillWithHoles(heap, new_elms, new_length, capacity);
Steve Block6ded16b2010-05-10 14:33:55 +0100477
Andrei Popescu402d9372010-02-26 13:31:12 +0000478 elms = new_elms;
479 array->set_elements(elms);
Steve Blocka7e24c12009-10-30 11:49:00 +0000480 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000481
Steve Block6ded16b2010-05-10 14:33:55 +0100482 // Add the provided values.
Andrei Popescu402d9372010-02-26 13:31:12 +0000483 AssertNoAllocation no_gc;
484 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
Andrei Popescu402d9372010-02-26 13:31:12 +0000485 for (int index = 0; index < to_add; index++) {
486 elms->set(index + len, args[index + 1], mode);
487 }
488
Steve Blocka7e24c12009-10-30 11:49:00 +0000489 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000490 array->set_length(Smi::FromInt(new_length));
Andrei Popescu402d9372010-02-26 13:31:12 +0000491 return Smi::FromInt(new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +0000492}
Steve Blocka7e24c12009-10-30 11:49:00 +0000493
494
495BUILTIN(ArrayPop) {
Steve Block44f0eee2011-05-26 01:26:41 +0100496 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100497 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700498 Object* elms_obj;
499 { MaybeObject* maybe_elms_obj =
Steve Block44f0eee2011-05-26 01:26:41 +0100500 EnsureJSArrayWithWritableFastElements(heap, receiver);
501 if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
John Reck59135872010-11-02 12:39:01 -0700502 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
503 }
Iain Merrick75681382010-08-19 15:07:18 +0100504 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100505 JSArray* array = JSArray::cast(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +0000506
507 int len = Smi::cast(array->length())->value();
Steve Block44f0eee2011-05-26 01:26:41 +0100508 if (len == 0) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000509
510 // Get top element
John Reck59135872010-11-02 12:39:01 -0700511 MaybeObject* top = elms->get(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000512
513 // Set the length.
Leon Clarke4515c472010-02-03 11:58:03 +0000514 array->set_length(Smi::FromInt(len - 1));
Steve Blocka7e24c12009-10-30 11:49:00 +0000515
516 if (!top->IsTheHole()) {
517 // Delete the top element.
518 elms->set_the_hole(len - 1);
519 return top;
520 }
521
Kristian Monsen25f61362010-05-21 11:50:48 +0100522 top = array->GetPrototype()->GetElement(len - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000523
524 return top;
525}
Steve Blocka7e24c12009-10-30 11:49:00 +0000526
527
Andrei Popescu402d9372010-02-26 13:31:12 +0000528BUILTIN(ArrayShift) {
Steve Block44f0eee2011-05-26 01:26:41 +0100529 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100530 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700531 Object* elms_obj;
532 { MaybeObject* maybe_elms_obj =
Steve Block44f0eee2011-05-26 01:26:41 +0100533 EnsureJSArrayWithWritableFastElements(heap, receiver);
534 if (maybe_elms_obj == NULL)
535 return CallJsBuiltin(isolate, "ArrayShift", args);
John Reck59135872010-11-02 12:39:01 -0700536 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
537 }
Steve Block44f0eee2011-05-26 01:26:41 +0100538 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
539 return CallJsBuiltin(isolate, "ArrayShift", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100540 }
Iain Merrick75681382010-08-19 15:07:18 +0100541 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100542 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000543 ASSERT(array->HasFastElements());
544
545 int len = Smi::cast(array->length())->value();
Steve Block44f0eee2011-05-26 01:26:41 +0100546 if (len == 0) return heap->undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000547
Andrei Popescu402d9372010-02-26 13:31:12 +0000548 // Get first element
549 Object* first = elms->get(0);
550 if (first->IsTheHole()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100551 first = heap->undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000552 }
553
Steve Block44f0eee2011-05-26 01:26:41 +0100554 if (!heap->lo_space()->Contains(elms)) {
Steve Block791712a2010-08-27 10:21:07 +0100555 // As elms still in the same space they used to be,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100556 // there is no need to update region dirty mark.
Steve Block44f0eee2011-05-26 01:26:41 +0100557 array->set_elements(LeftTrimFixedArray(heap, elms, 1), SKIP_WRITE_BARRIER);
Steve Block6ded16b2010-05-10 14:33:55 +0100558 } else {
559 // Shift the elements.
560 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100561 MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
562 elms->set(len - 1, heap->the_hole_value());
Andrei Popescu402d9372010-02-26 13:31:12 +0000563 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000564
565 // Set the length.
566 array->set_length(Smi::FromInt(len - 1));
567
568 return first;
569}
570
571
572BUILTIN(ArrayUnshift) {
Steve Block44f0eee2011-05-26 01:26:41 +0100573 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100574 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700575 Object* elms_obj;
576 { MaybeObject* maybe_elms_obj =
Steve Block44f0eee2011-05-26 01:26:41 +0100577 EnsureJSArrayWithWritableFastElements(heap, receiver);
578 if (maybe_elms_obj == NULL)
579 return CallJsBuiltin(isolate, "ArrayUnshift", args);
John Reck59135872010-11-02 12:39:01 -0700580 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
581 }
Steve Block44f0eee2011-05-26 01:26:41 +0100582 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
583 return CallJsBuiltin(isolate, "ArrayUnshift", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100584 }
Iain Merrick75681382010-08-19 15:07:18 +0100585 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100586 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000587 ASSERT(array->HasFastElements());
588
589 int len = Smi::cast(array->length())->value();
590 int to_add = args.length() - 1;
Andrei Popescu402d9372010-02-26 13:31:12 +0000591 int new_length = len + to_add;
592 // Currently fixed arrays cannot grow too big, so
593 // we should never hit this case.
594 ASSERT(to_add <= (Smi::kMaxValue - len));
595
Andrei Popescu402d9372010-02-26 13:31:12 +0000596 if (new_length > elms->length()) {
597 // New backing storage is needed.
598 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700599 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +0100600 { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
John Reck59135872010-11-02 12:39:01 -0700601 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
602 }
Steve Block6ded16b2010-05-10 14:33:55 +0100603 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000604
605 AssertNoAllocation no_gc;
Steve Block6ded16b2010-05-10 14:33:55 +0100606 if (len > 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100607 CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len);
Steve Block6ded16b2010-05-10 14:33:55 +0100608 }
Steve Block44f0eee2011-05-26 01:26:41 +0100609 FillWithHoles(heap, new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000610
611 elms = new_elms;
612 array->set_elements(elms);
613 } else {
614 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100615 MoveElements(heap, &no_gc, elms, to_add, elms, 0, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000616 }
617
618 // Add the provided values.
619 AssertNoAllocation no_gc;
620 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
621 for (int i = 0; i < to_add; i++) {
622 elms->set(i, args[i + 1], mode);
623 }
624
625 // Set the length.
626 array->set_length(Smi::FromInt(new_length));
627 return Smi::FromInt(new_length);
628}
629
630
Andrei Popescu402d9372010-02-26 13:31:12 +0000631BUILTIN(ArraySlice) {
Steve Block44f0eee2011-05-26 01:26:41 +0100632 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100633 Object* receiver = *args.receiver();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100634 FixedArray* elms;
635 int len = -1;
Steve Block9fac8402011-05-12 15:51:54 +0100636 if (receiver->IsJSArray()) {
637 JSArray* array = JSArray::cast(receiver);
638 if (!array->HasFastElements() ||
Steve Block44f0eee2011-05-26 01:26:41 +0100639 !IsJSArrayFastElementMovingAllowed(heap, array)) {
640 return CallJsBuiltin(isolate, "ArraySlice", args);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100641 }
Steve Block9fac8402011-05-12 15:51:54 +0100642
643 elms = FixedArray::cast(array->elements());
644 len = Smi::cast(array->length())->value();
645 } else {
646 // Array.slice(arguments, ...) is quite a common idiom (notably more
647 // than 50% of invocations in Web apps). Treat it in C++ as well.
648 Map* arguments_map =
Steve Block44f0eee2011-05-26 01:26:41 +0100649 isolate->context()->global_context()->arguments_boilerplate()->map();
Steve Block9fac8402011-05-12 15:51:54 +0100650
651 bool is_arguments_object_with_fast_elements =
652 receiver->IsJSObject()
653 && JSObject::cast(receiver)->map() == arguments_map
654 && JSObject::cast(receiver)->HasFastElements();
655 if (!is_arguments_object_with_fast_elements) {
Steve Block44f0eee2011-05-26 01:26:41 +0100656 return CallJsBuiltin(isolate, "ArraySlice", args);
Steve Block9fac8402011-05-12 15:51:54 +0100657 }
658 elms = FixedArray::cast(JSObject::cast(receiver)->elements());
Ben Murdochb8e0da22011-05-16 14:20:40 +0100659 Object* len_obj = JSObject::cast(receiver)
Steve Block44f0eee2011-05-26 01:26:41 +0100660 ->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100661 if (!len_obj->IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100662 return CallJsBuiltin(isolate, "ArraySlice", args);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100663 }
664 len = Smi::cast(len_obj)->value();
665 if (len > elms->length()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100666 return CallJsBuiltin(isolate, "ArraySlice", args);
Ben Murdochb8e0da22011-05-16 14:20:40 +0100667 }
668 for (int i = 0; i < len; i++) {
Steve Block44f0eee2011-05-26 01:26:41 +0100669 if (elms->get(i) == heap->the_hole_value()) {
670 return CallJsBuiltin(isolate, "ArraySlice", args);
Steve Block9fac8402011-05-12 15:51:54 +0100671 }
672 }
Ben Murdochb0fe1622011-05-05 13:52:32 +0100673 }
674 ASSERT(len >= 0);
Andrei Popescu402d9372010-02-26 13:31:12 +0000675 int n_arguments = args.length() - 1;
676
677 // Note carefully choosen defaults---if argument is missing,
Steve Block6ded16b2010-05-10 14:33:55 +0100678 // it's undefined which gets converted to 0 for relative_start
679 // and to len for relative_end.
680 int relative_start = 0;
681 int relative_end = len;
Andrei Popescu402d9372010-02-26 13:31:12 +0000682 if (n_arguments > 0) {
683 Object* arg1 = args[1];
684 if (arg1->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100685 relative_start = Smi::cast(arg1)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000686 } else if (!arg1->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100687 return CallJsBuiltin(isolate, "ArraySlice", args);
Andrei Popescu402d9372010-02-26 13:31:12 +0000688 }
689 if (n_arguments > 1) {
690 Object* arg2 = args[2];
691 if (arg2->IsSmi()) {
Steve Block6ded16b2010-05-10 14:33:55 +0100692 relative_end = Smi::cast(arg2)->value();
Andrei Popescu402d9372010-02-26 13:31:12 +0000693 } else if (!arg2->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100694 return CallJsBuiltin(isolate, "ArraySlice", args);
Andrei Popescu402d9372010-02-26 13:31:12 +0000695 }
696 }
697 }
698
699 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
Steve Block6ded16b2010-05-10 14:33:55 +0100700 int k = (relative_start < 0) ? Max(len + relative_start, 0)
701 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000702
703 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
Steve Block6ded16b2010-05-10 14:33:55 +0100704 int final = (relative_end < 0) ? Max(len + relative_end, 0)
705 : Min(relative_end, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000706
707 // Calculate the length of result array.
708 int result_len = final - k;
Steve Block6ded16b2010-05-10 14:33:55 +0100709 if (result_len <= 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100710 return AllocateEmptyJSArray(heap);
Andrei Popescu402d9372010-02-26 13:31:12 +0000711 }
712
John Reck59135872010-11-02 12:39:01 -0700713 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100714 { MaybeObject* maybe_result = AllocateJSArray(heap);
John Reck59135872010-11-02 12:39:01 -0700715 if (!maybe_result->ToObject(&result)) return maybe_result;
716 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000717 JSArray* result_array = JSArray::cast(result);
718
John Reck59135872010-11-02 12:39:01 -0700719 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +0100720 heap->AllocateUninitializedFixedArray(result_len);
John Reck59135872010-11-02 12:39:01 -0700721 if (!maybe_result->ToObject(&result)) return maybe_result;
722 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000723 FixedArray* result_elms = FixedArray::cast(result);
724
Andrei Popescu402d9372010-02-26 13:31:12 +0000725 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100726 CopyElements(heap, &no_gc, result_elms, 0, elms, k, result_len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000727
728 // Set elements.
729 result_array->set_elements(result_elms);
730
731 // Set the length.
732 result_array->set_length(Smi::FromInt(result_len));
733 return result_array;
734}
735
736
737BUILTIN(ArraySplice) {
Steve Block44f0eee2011-05-26 01:26:41 +0100738 Heap* heap = isolate->heap();
Steve Block6ded16b2010-05-10 14:33:55 +0100739 Object* receiver = *args.receiver();
John Reck59135872010-11-02 12:39:01 -0700740 Object* elms_obj;
741 { MaybeObject* maybe_elms_obj =
Steve Block44f0eee2011-05-26 01:26:41 +0100742 EnsureJSArrayWithWritableFastElements(heap, receiver);
743 if (maybe_elms_obj == NULL)
744 return CallJsBuiltin(isolate, "ArraySplice", args);
John Reck59135872010-11-02 12:39:01 -0700745 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
746 }
Steve Block44f0eee2011-05-26 01:26:41 +0100747 if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
748 return CallJsBuiltin(isolate, "ArraySplice", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100749 }
Iain Merrick75681382010-08-19 15:07:18 +0100750 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100751 JSArray* array = JSArray::cast(receiver);
Andrei Popescu402d9372010-02-26 13:31:12 +0000752 ASSERT(array->HasFastElements());
753
754 int len = Smi::cast(array->length())->value();
755
756 int n_arguments = args.length() - 1;
757
Steve Block6ded16b2010-05-10 14:33:55 +0100758 int relative_start = 0;
Steve Block1e0659c2011-05-24 12:43:12 +0100759 if (n_arguments > 0) {
760 Object* arg1 = args[1];
761 if (arg1->IsSmi()) {
762 relative_start = Smi::cast(arg1)->value();
763 } else if (!arg1->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100764 return CallJsBuiltin(isolate, "ArraySplice", args);
Steve Block1e0659c2011-05-24 12:43:12 +0100765 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000766 }
Steve Block6ded16b2010-05-10 14:33:55 +0100767 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
768 : Min(relative_start, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000769
770 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
Steve Block1e0659c2011-05-24 12:43:12 +0100771 // given as a request to delete all the elements from the start.
772 // And it differs from the case of undefined delete count.
Andrei Popescu402d9372010-02-26 13:31:12 +0000773 // This does not follow ECMA-262, but we do the same for
774 // compatibility.
Steve Block1e0659c2011-05-24 12:43:12 +0100775 int actual_delete_count;
776 if (n_arguments == 1) {
777 ASSERT(len - actual_start >= 0);
778 actual_delete_count = len - actual_start;
779 } else {
780 int value = 0; // ToInteger(undefined) == 0
781 if (n_arguments > 1) {
782 Object* arg2 = args[2];
783 if (arg2->IsSmi()) {
784 value = Smi::cast(arg2)->value();
785 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100786 return CallJsBuiltin(isolate, "ArraySplice", args);
Steve Block1e0659c2011-05-24 12:43:12 +0100787 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000788 }
Steve Block1e0659c2011-05-24 12:43:12 +0100789 actual_delete_count = Min(Max(value, 0), len - actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000790 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000791
Steve Block6ded16b2010-05-10 14:33:55 +0100792 JSArray* result_array = NULL;
793 if (actual_delete_count == 0) {
John Reck59135872010-11-02 12:39:01 -0700794 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100795 { MaybeObject* maybe_result = AllocateEmptyJSArray(heap);
John Reck59135872010-11-02 12:39:01 -0700796 if (!maybe_result->ToObject(&result)) return maybe_result;
797 }
Steve Block6ded16b2010-05-10 14:33:55 +0100798 result_array = JSArray::cast(result);
799 } else {
800 // Allocate result array.
John Reck59135872010-11-02 12:39:01 -0700801 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100802 { MaybeObject* maybe_result = AllocateJSArray(heap);
John Reck59135872010-11-02 12:39:01 -0700803 if (!maybe_result->ToObject(&result)) return maybe_result;
804 }
Steve Block6ded16b2010-05-10 14:33:55 +0100805 result_array = JSArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000806
John Reck59135872010-11-02 12:39:01 -0700807 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +0100808 heap->AllocateUninitializedFixedArray(actual_delete_count);
John Reck59135872010-11-02 12:39:01 -0700809 if (!maybe_result->ToObject(&result)) return maybe_result;
810 }
Steve Block6ded16b2010-05-10 14:33:55 +0100811 FixedArray* result_elms = FixedArray::cast(result);
Andrei Popescu402d9372010-02-26 13:31:12 +0000812
Steve Block6ded16b2010-05-10 14:33:55 +0100813 AssertNoAllocation no_gc;
814 // Fill newly created array.
Steve Block44f0eee2011-05-26 01:26:41 +0100815 CopyElements(heap,
816 &no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100817 result_elms, 0,
818 elms, actual_start,
819 actual_delete_count);
Andrei Popescu402d9372010-02-26 13:31:12 +0000820
Steve Block6ded16b2010-05-10 14:33:55 +0100821 // Set elements.
822 result_array->set_elements(result_elms);
Andrei Popescu402d9372010-02-26 13:31:12 +0000823
Steve Block6ded16b2010-05-10 14:33:55 +0100824 // Set the length.
825 result_array->set_length(Smi::FromInt(actual_delete_count));
Andrei Popescu402d9372010-02-26 13:31:12 +0000826 }
827
Steve Block6ded16b2010-05-10 14:33:55 +0100828 int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
Andrei Popescu402d9372010-02-26 13:31:12 +0000829
Steve Block6ded16b2010-05-10 14:33:55 +0100830 int new_length = len - actual_delete_count + item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000831
Steve Block6ded16b2010-05-10 14:33:55 +0100832 if (item_count < actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000833 // Shrink the array.
Steve Block44f0eee2011-05-26 01:26:41 +0100834 const bool trim_array = !heap->lo_space()->Contains(elms) &&
Steve Block6ded16b2010-05-10 14:33:55 +0100835 ((actual_start + item_count) <
836 (len - actual_delete_count - actual_start));
837 if (trim_array) {
838 const int delta = actual_delete_count - item_count;
Andrei Popescu402d9372010-02-26 13:31:12 +0000839
Steve Block6ded16b2010-05-10 14:33:55 +0100840 if (actual_start > 0) {
841 Object** start = elms->data_start();
842 memmove(start + delta, start, actual_start * kPointerSize);
843 }
844
Steve Block44f0eee2011-05-26 01:26:41 +0100845 elms = LeftTrimFixedArray(heap, elms, delta);
Steve Block6ded16b2010-05-10 14:33:55 +0100846 array->set_elements(elms, SKIP_WRITE_BARRIER);
847 } else {
848 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100849 MoveElements(heap, &no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100850 elms, actual_start + item_count,
851 elms, actual_start + actual_delete_count,
852 (len - actual_delete_count - actual_start));
Steve Block44f0eee2011-05-26 01:26:41 +0100853 FillWithHoles(heap, elms, new_length, len);
Andrei Popescu402d9372010-02-26 13:31:12 +0000854 }
Steve Block6ded16b2010-05-10 14:33:55 +0100855 } else if (item_count > actual_delete_count) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000856 // Currently fixed arrays cannot grow too big, so
857 // we should never hit this case.
Steve Block6ded16b2010-05-10 14:33:55 +0100858 ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
Andrei Popescu402d9372010-02-26 13:31:12 +0000859
860 // Check if array need to grow.
861 if (new_length > elms->length()) {
862 // New backing storage is needed.
863 int capacity = new_length + (new_length >> 1) + 16;
John Reck59135872010-11-02 12:39:01 -0700864 Object* obj;
865 { MaybeObject* maybe_obj =
Steve Block44f0eee2011-05-26 01:26:41 +0100866 heap->AllocateUninitializedFixedArray(capacity);
John Reck59135872010-11-02 12:39:01 -0700867 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
868 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000869 FixedArray* new_elms = FixedArray::cast(obj);
Andrei Popescu402d9372010-02-26 13:31:12 +0000870
Steve Block6ded16b2010-05-10 14:33:55 +0100871 AssertNoAllocation no_gc;
872 // Copy the part before actual_start as is.
873 if (actual_start > 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100874 CopyElements(heap, &no_gc, new_elms, 0, elms, 0, actual_start);
Andrei Popescu402d9372010-02-26 13:31:12 +0000875 }
Steve Block6ded16b2010-05-10 14:33:55 +0100876 const int to_copy = len - actual_delete_count - actual_start;
877 if (to_copy > 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100878 CopyElements(heap, &no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100879 new_elms, actual_start + item_count,
880 elms, actual_start + actual_delete_count,
881 to_copy);
882 }
Steve Block44f0eee2011-05-26 01:26:41 +0100883 FillWithHoles(heap, new_elms, new_length, capacity);
Andrei Popescu402d9372010-02-26 13:31:12 +0000884
Andrei Popescu402d9372010-02-26 13:31:12 +0000885 elms = new_elms;
886 array->set_elements(elms);
Steve Block6ded16b2010-05-10 14:33:55 +0100887 } else {
888 AssertNoAllocation no_gc;
Steve Block44f0eee2011-05-26 01:26:41 +0100889 MoveElements(heap, &no_gc,
Steve Block6ded16b2010-05-10 14:33:55 +0100890 elms, actual_start + item_count,
891 elms, actual_start + actual_delete_count,
892 (len - actual_delete_count - actual_start));
Andrei Popescu402d9372010-02-26 13:31:12 +0000893 }
894 }
895
Steve Block6ded16b2010-05-10 14:33:55 +0100896 AssertNoAllocation no_gc;
897 WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
898 for (int k = actual_start; k < actual_start + item_count; k++) {
899 elms->set(k, args[3 + k - actual_start], mode);
Andrei Popescu402d9372010-02-26 13:31:12 +0000900 }
901
902 // Set the length.
903 array->set_length(Smi::FromInt(new_length));
904
905 return result_array;
906}
907
908
Steve Block6ded16b2010-05-10 14:33:55 +0100909BUILTIN(ArrayConcat) {
Steve Block44f0eee2011-05-26 01:26:41 +0100910 Heap* heap = isolate->heap();
911 Context* global_context = isolate->context()->global_context();
Kristian Monsen25f61362010-05-21 11:50:48 +0100912 JSObject* array_proto =
913 JSObject::cast(global_context->array_function()->prototype());
Steve Block44f0eee2011-05-26 01:26:41 +0100914 if (!ArrayPrototypeHasNoElements(heap, global_context, array_proto)) {
915 return CallJsBuiltin(isolate, "ArrayConcat", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100916 }
917
918 // Iterate through all the arguments performing checks
919 // and calculating total length.
920 int n_arguments = args.length();
921 int result_len = 0;
922 for (int i = 0; i < n_arguments; i++) {
923 Object* arg = args[i];
Kristian Monsen25f61362010-05-21 11:50:48 +0100924 if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()
925 || JSArray::cast(arg)->GetPrototype() != array_proto) {
Steve Block44f0eee2011-05-26 01:26:41 +0100926 return CallJsBuiltin(isolate, "ArrayConcat", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100927 }
928
929 int len = Smi::cast(JSArray::cast(arg)->length())->value();
930
931 // We shouldn't overflow when adding another len.
932 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
933 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
934 USE(kHalfOfMaxInt);
935 result_len += len;
936 ASSERT(result_len >= 0);
937
938 if (result_len > FixedArray::kMaxLength) {
Steve Block44f0eee2011-05-26 01:26:41 +0100939 return CallJsBuiltin(isolate, "ArrayConcat", args);
Steve Block6ded16b2010-05-10 14:33:55 +0100940 }
941 }
942
943 if (result_len == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +0100944 return AllocateEmptyJSArray(heap);
Steve Block6ded16b2010-05-10 14:33:55 +0100945 }
946
947 // Allocate result.
John Reck59135872010-11-02 12:39:01 -0700948 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +0100949 { MaybeObject* maybe_result = AllocateJSArray(heap);
John Reck59135872010-11-02 12:39:01 -0700950 if (!maybe_result->ToObject(&result)) return maybe_result;
951 }
Steve Block6ded16b2010-05-10 14:33:55 +0100952 JSArray* result_array = JSArray::cast(result);
953
John Reck59135872010-11-02 12:39:01 -0700954 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +0100955 heap->AllocateUninitializedFixedArray(result_len);
John Reck59135872010-11-02 12:39:01 -0700956 if (!maybe_result->ToObject(&result)) return maybe_result;
957 }
Steve Block6ded16b2010-05-10 14:33:55 +0100958 FixedArray* result_elms = FixedArray::cast(result);
959
960 // Copy data.
961 AssertNoAllocation no_gc;
962 int start_pos = 0;
963 for (int i = 0; i < n_arguments; i++) {
964 JSArray* array = JSArray::cast(args[i]);
965 int len = Smi::cast(array->length())->value();
966 if (len > 0) {
967 FixedArray* elms = FixedArray::cast(array->elements());
Steve Block44f0eee2011-05-26 01:26:41 +0100968 CopyElements(heap, &no_gc, result_elms, start_pos, elms, 0, len);
Steve Block6ded16b2010-05-10 14:33:55 +0100969 start_pos += len;
970 }
971 }
972 ASSERT(start_pos == result_len);
973
974 // Set the length and elements.
975 result_array->set_length(Smi::FromInt(result_len));
976 result_array->set_elements(result_elms);
977
978 return result_array;
979}
980
981
Steve Blocka7e24c12009-10-30 11:49:00 +0000982// -----------------------------------------------------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100983// Strict mode poison pills
984
985
986BUILTIN(StrictArgumentsCallee) {
987 HandleScope scope;
988 return isolate->Throw(*isolate->factory()->NewTypeError(
989 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
990}
991
992
993BUILTIN(StrictArgumentsCaller) {
994 HandleScope scope;
995 return isolate->Throw(*isolate->factory()->NewTypeError(
996 "strict_arguments_caller", HandleVector<Object>(NULL, 0)));
997}
998
999
1000BUILTIN(StrictFunctionCaller) {
1001 HandleScope scope;
1002 return isolate->Throw(*isolate->factory()->NewTypeError(
1003 "strict_function_caller", HandleVector<Object>(NULL, 0)));
1004}
1005
1006
1007BUILTIN(StrictFunctionArguments) {
1008 HandleScope scope;
1009 return isolate->Throw(*isolate->factory()->NewTypeError(
1010 "strict_function_arguments", HandleVector<Object>(NULL, 0)));
1011}
1012
1013
1014// -----------------------------------------------------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001015//
1016
1017
1018// Returns the holder JSObject if the function can legally be called
1019// with this receiver. Returns Heap::null_value() if the call is
1020// illegal. Any arguments that don't fit the expected type is
1021// overwritten with undefined. Arguments that do fit the expected
1022// type is overwritten with the object in the prototype chain that
1023// actually has that type.
Steve Block44f0eee2011-05-26 01:26:41 +01001024static inline Object* TypeCheck(Heap* heap,
1025 int argc,
Steve Blocka7e24c12009-10-30 11:49:00 +00001026 Object** argv,
1027 FunctionTemplateInfo* info) {
1028 Object* recv = argv[0];
1029 Object* sig_obj = info->signature();
1030 if (sig_obj->IsUndefined()) return recv;
1031 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
1032 // If necessary, check the receiver
1033 Object* recv_type = sig->receiver();
1034
1035 Object* holder = recv;
1036 if (!recv_type->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001037 for (; holder != heap->null_value(); holder = holder->GetPrototype()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001038 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
1039 break;
1040 }
1041 }
Steve Block44f0eee2011-05-26 01:26:41 +01001042 if (holder == heap->null_value()) return holder;
Steve Blocka7e24c12009-10-30 11:49:00 +00001043 }
1044 Object* args_obj = sig->args();
1045 // If there is no argument signature we're done
1046 if (args_obj->IsUndefined()) return holder;
1047 FixedArray* args = FixedArray::cast(args_obj);
1048 int length = args->length();
1049 if (argc <= length) length = argc - 1;
1050 for (int i = 0; i < length; i++) {
1051 Object* argtype = args->get(i);
1052 if (argtype->IsUndefined()) continue;
1053 Object** arg = &argv[-1 - i];
1054 Object* current = *arg;
Steve Block44f0eee2011-05-26 01:26:41 +01001055 for (; current != heap->null_value(); current = current->GetPrototype()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001056 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
1057 *arg = current;
1058 break;
1059 }
1060 }
Steve Block44f0eee2011-05-26 01:26:41 +01001061 if (current == heap->null_value()) *arg = heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001062 }
1063 return holder;
1064}
1065
1066
Leon Clarkee46be812010-01-19 14:06:41 +00001067template <bool is_construct>
John Reck59135872010-11-02 12:39:01 -07001068MUST_USE_RESULT static MaybeObject* HandleApiCallHelper(
Steve Block44f0eee2011-05-26 01:26:41 +01001069 BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
1070 ASSERT(is_construct == CalledAsConstructor(isolate));
1071 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001072
Steve Block44f0eee2011-05-26 01:26:41 +01001073 HandleScope scope(isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00001074 Handle<JSFunction> function = args.called_function();
Steve Block6ded16b2010-05-10 14:33:55 +01001075 ASSERT(function->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001076
Steve Block6ded16b2010-05-10 14:33:55 +01001077 FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
Steve Blocka7e24c12009-10-30 11:49:00 +00001078 if (is_construct) {
Steve Block44f0eee2011-05-26 01:26:41 +01001079 Handle<FunctionTemplateInfo> desc(fun_data, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001080 bool pending_exception = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001081 isolate->factory()->ConfigureInstance(
1082 desc, Handle<JSObject>::cast(args.receiver()), &pending_exception);
1083 ASSERT(isolate->has_pending_exception() == pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +00001084 if (pending_exception) return Failure::Exception();
Steve Block6ded16b2010-05-10 14:33:55 +01001085 fun_data = *desc;
Steve Blocka7e24c12009-10-30 11:49:00 +00001086 }
1087
Steve Block44f0eee2011-05-26 01:26:41 +01001088 Object* raw_holder = TypeCheck(heap, args.length(), &args[0], fun_data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001089
1090 if (raw_holder->IsNull()) {
1091 // This function cannot be called with the given receiver. Abort!
1092 Handle<Object> obj =
Steve Block44f0eee2011-05-26 01:26:41 +01001093 isolate->factory()->NewTypeError(
1094 "illegal_invocation", HandleVector(&function, 1));
1095 return isolate->Throw(*obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00001096 }
1097
1098 Object* raw_call_data = fun_data->call_code();
1099 if (!raw_call_data->IsUndefined()) {
1100 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
1101 Object* callback_obj = call_data->callback();
1102 v8::InvocationCallback callback =
1103 v8::ToCData<v8::InvocationCallback>(callback_obj);
1104 Object* data_obj = call_data->data();
1105 Object* result;
1106
Steve Block44f0eee2011-05-26 01:26:41 +01001107 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001108 ASSERT(raw_holder->IsJSObject());
1109
Steve Block44f0eee2011-05-26 01:26:41 +01001110 CustomArguments custom(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001111 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1112 data_obj, *function, raw_holder);
1113
Steve Blocka7e24c12009-10-30 11:49:00 +00001114 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001115 custom.end(),
1116 &args[0] - 1,
1117 args.length() - 1,
1118 is_construct);
Steve Blocka7e24c12009-10-30 11:49:00 +00001119
1120 v8::Handle<v8::Value> value;
1121 {
1122 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001123 VMState state(isolate, EXTERNAL);
1124 ExternalCallbackScope call_scope(isolate,
1125 v8::ToCData<Address>(callback_obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00001126 value = callback(new_args);
1127 }
1128 if (value.IsEmpty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001129 result = heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001130 } else {
1131 result = *reinterpret_cast<Object**>(*value);
1132 }
1133
Steve Block44f0eee2011-05-26 01:26:41 +01001134 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001135 if (!is_construct || result->IsJSObject()) return result;
1136 }
1137
Leon Clarkee46be812010-01-19 14:06:41 +00001138 return *args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +00001139}
Leon Clarkee46be812010-01-19 14:06:41 +00001140
1141
1142BUILTIN(HandleApiCall) {
Steve Block44f0eee2011-05-26 01:26:41 +01001143 return HandleApiCallHelper<false>(args, isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00001144}
1145
1146
1147BUILTIN(HandleApiCallConstruct) {
Steve Block44f0eee2011-05-26 01:26:41 +01001148 return HandleApiCallHelper<true>(args, isolate);
Leon Clarkee46be812010-01-19 14:06:41 +00001149}
Steve Blocka7e24c12009-10-30 11:49:00 +00001150
1151
Andrei Popescu402d9372010-02-26 13:31:12 +00001152#ifdef DEBUG
1153
1154static void VerifyTypeCheck(Handle<JSObject> object,
1155 Handle<JSFunction> function) {
Steve Block6ded16b2010-05-10 14:33:55 +01001156 ASSERT(function->shared()->IsApiFunction());
1157 FunctionTemplateInfo* info = function->shared()->get_api_func_data();
Andrei Popescu402d9372010-02-26 13:31:12 +00001158 if (info->signature()->IsUndefined()) return;
1159 SignatureInfo* signature = SignatureInfo::cast(info->signature());
1160 Object* receiver_type = signature->receiver();
1161 if (receiver_type->IsUndefined()) return;
1162 FunctionTemplateInfo* type = FunctionTemplateInfo::cast(receiver_type);
1163 ASSERT(object->IsInstanceOf(type));
1164}
1165
1166#endif
1167
1168
1169BUILTIN(FastHandleApiCall) {
Steve Block44f0eee2011-05-26 01:26:41 +01001170 ASSERT(!CalledAsConstructor(isolate));
1171 Heap* heap = isolate->heap();
Andrei Popescu402d9372010-02-26 13:31:12 +00001172 const bool is_construct = false;
1173
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001174 // We expect four more arguments: callback, function, call data, and holder.
Andrei Popescu402d9372010-02-26 13:31:12 +00001175 const int args_length = args.length() - 4;
1176 ASSERT(args_length >= 0);
1177
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001178 Object* callback_obj = args[args_length];
Andrei Popescu402d9372010-02-26 13:31:12 +00001179
1180 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001181 &args[args_length + 1],
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001182 &args[0] - 1,
1183 args_length - 1,
1184 is_construct);
Andrei Popescu402d9372010-02-26 13:31:12 +00001185
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001186#ifdef DEBUG
1187 VerifyTypeCheck(Utils::OpenHandle(*new_args.Holder()),
1188 Utils::OpenHandle(*new_args.Callee()));
1189#endif
Steve Block44f0eee2011-05-26 01:26:41 +01001190 HandleScope scope(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00001191 Object* result;
1192 v8::Handle<v8::Value> value;
1193 {
1194 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001195 VMState state(isolate, EXTERNAL);
1196 ExternalCallbackScope call_scope(isolate,
1197 v8::ToCData<Address>(callback_obj));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001198 v8::InvocationCallback callback =
1199 v8::ToCData<v8::InvocationCallback>(callback_obj);
1200
Andrei Popescu402d9372010-02-26 13:31:12 +00001201 value = callback(new_args);
1202 }
1203 if (value.IsEmpty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001204 result = heap->undefined_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00001205 } else {
1206 result = *reinterpret_cast<Object**>(*value);
1207 }
1208
Steve Block44f0eee2011-05-26 01:26:41 +01001209 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Andrei Popescu402d9372010-02-26 13:31:12 +00001210 return result;
1211}
1212
1213
Steve Blocka7e24c12009-10-30 11:49:00 +00001214// Helper function to handle calls to non-function objects created through the
1215// API. The object can be called as either a constructor (using new) or just as
1216// a function (without new).
John Reck59135872010-11-02 12:39:01 -07001217MUST_USE_RESULT static MaybeObject* HandleApiCallAsFunctionOrConstructor(
Steve Block44f0eee2011-05-26 01:26:41 +01001218 Isolate* isolate,
Leon Clarkee46be812010-01-19 14:06:41 +00001219 bool is_construct_call,
1220 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001221 // Non-functions are never called as constructors. Even if this is an object
1222 // called as a constructor the delegate call is not a construct call.
Steve Block44f0eee2011-05-26 01:26:41 +01001223 ASSERT(!CalledAsConstructor(isolate));
1224 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001225
1226 Handle<Object> receiver = args.at<Object>(0);
1227
1228 // Get the object called.
Leon Clarkee46be812010-01-19 14:06:41 +00001229 JSObject* obj = JSObject::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +00001230
1231 // Get the invocation callback from the function descriptor that was
1232 // used to create the called object.
1233 ASSERT(obj->map()->has_instance_call_handler());
1234 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01001235 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00001236 Object* handler =
Steve Block6ded16b2010-05-10 14:33:55 +01001237 constructor->shared()->get_api_func_data()->instance_call_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00001238 ASSERT(!handler->IsUndefined());
1239 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
1240 Object* callback_obj = call_data->callback();
1241 v8::InvocationCallback callback =
1242 v8::ToCData<v8::InvocationCallback>(callback_obj);
1243
1244 // Get the data for the call and perform the callback.
Steve Blocka7e24c12009-10-30 11:49:00 +00001245 Object* result;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001246 {
Steve Block44f0eee2011-05-26 01:26:41 +01001247 HandleScope scope(isolate);
1248 LOG(isolate, ApiObjectAccess("call non-function", obj));
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001249
Steve Block44f0eee2011-05-26 01:26:41 +01001250 CustomArguments custom(isolate);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001251 v8::ImplementationUtilities::PrepareArgumentsData(custom.end(),
1252 call_data->data(), constructor, obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00001253 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001254 custom.end(),
1255 &args[0] - 1,
1256 args.length() - 1,
1257 is_construct_call);
Steve Blocka7e24c12009-10-30 11:49:00 +00001258 v8::Handle<v8::Value> value;
1259 {
1260 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001261 VMState state(isolate, EXTERNAL);
1262 ExternalCallbackScope call_scope(isolate,
1263 v8::ToCData<Address>(callback_obj));
Steve Blocka7e24c12009-10-30 11:49:00 +00001264 value = callback(new_args);
1265 }
1266 if (value.IsEmpty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001267 result = heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001268 } else {
1269 result = *reinterpret_cast<Object**>(*value);
1270 }
1271 }
1272 // Check for exceptions and return result.
Steve Block44f0eee2011-05-26 01:26:41 +01001273 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001274 return result;
1275}
1276
1277
1278// Handle calls to non-function objects created through the API. This delegate
1279// function is used when the call is a normal function call.
1280BUILTIN(HandleApiCallAsFunction) {
Steve Block44f0eee2011-05-26 01:26:41 +01001281 return HandleApiCallAsFunctionOrConstructor(isolate, false, args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001282}
Steve Blocka7e24c12009-10-30 11:49:00 +00001283
1284
1285// Handle calls to non-function objects created through the API. This delegate
1286// function is used when the call is a construct call.
1287BUILTIN(HandleApiCallAsConstructor) {
Steve Block44f0eee2011-05-26 01:26:41 +01001288 return HandleApiCallAsFunctionOrConstructor(isolate, true, args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001289}
Steve Blocka7e24c12009-10-30 11:49:00 +00001290
1291
1292static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
1293 LoadIC::GenerateArrayLength(masm);
1294}
1295
1296
1297static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
Steve Block1e0659c2011-05-24 12:43:12 +01001298 LoadIC::GenerateStringLength(masm, false);
1299}
1300
1301
1302static void Generate_LoadIC_StringWrapperLength(MacroAssembler* masm) {
1303 LoadIC::GenerateStringLength(masm, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001304}
1305
1306
1307static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
1308 LoadIC::GenerateFunctionPrototype(masm);
1309}
1310
1311
1312static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
1313 LoadIC::GenerateInitialize(masm);
1314}
1315
1316
1317static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
1318 LoadIC::GeneratePreMonomorphic(masm);
1319}
1320
1321
1322static void Generate_LoadIC_Miss(MacroAssembler* masm) {
1323 LoadIC::GenerateMiss(masm);
1324}
1325
1326
1327static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
1328 LoadIC::GenerateMegamorphic(masm);
1329}
1330
1331
1332static void Generate_LoadIC_Normal(MacroAssembler* masm) {
1333 LoadIC::GenerateNormal(masm);
1334}
1335
1336
1337static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
1338 KeyedLoadIC::GenerateInitialize(masm);
1339}
1340
1341
1342static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
1343 KeyedLoadIC::GenerateMiss(masm);
1344}
1345
1346
1347static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
1348 KeyedLoadIC::GenerateGeneric(masm);
1349}
1350
1351
Leon Clarkee46be812010-01-19 14:06:41 +00001352static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
1353 KeyedLoadIC::GenerateString(masm);
1354}
1355
1356
Steve Blocka7e24c12009-10-30 11:49:00 +00001357static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
1358 KeyedLoadIC::GeneratePreMonomorphic(masm);
1359}
1360
Andrei Popescu402d9372010-02-26 13:31:12 +00001361static void Generate_KeyedLoadIC_IndexedInterceptor(MacroAssembler* masm) {
1362 KeyedLoadIC::GenerateIndexedInterceptor(masm);
1363}
1364
Steve Blocka7e24c12009-10-30 11:49:00 +00001365
1366static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
1367 StoreIC::GenerateInitialize(masm);
1368}
1369
1370
Steve Block1e0659c2011-05-24 12:43:12 +01001371static void Generate_StoreIC_Initialize_Strict(MacroAssembler* masm) {
1372 StoreIC::GenerateInitialize(masm);
1373}
1374
1375
Steve Blocka7e24c12009-10-30 11:49:00 +00001376static void Generate_StoreIC_Miss(MacroAssembler* masm) {
1377 StoreIC::GenerateMiss(masm);
1378}
1379
1380
Steve Block8defd9f2010-07-08 12:39:36 +01001381static void Generate_StoreIC_Normal(MacroAssembler* masm) {
1382 StoreIC::GenerateNormal(masm);
1383}
1384
1385
Steve Block1e0659c2011-05-24 12:43:12 +01001386static void Generate_StoreIC_Normal_Strict(MacroAssembler* masm) {
1387 StoreIC::GenerateNormal(masm);
1388}
1389
1390
Steve Blocka7e24c12009-10-30 11:49:00 +00001391static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001392 StoreIC::GenerateMegamorphic(masm, kNonStrictMode);
Steve Block1e0659c2011-05-24 12:43:12 +01001393}
1394
1395
1396static void Generate_StoreIC_Megamorphic_Strict(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001397 StoreIC::GenerateMegamorphic(masm, kStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001398}
1399
1400
Steve Block6ded16b2010-05-10 14:33:55 +01001401static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
1402 StoreIC::GenerateArrayLength(masm);
1403}
1404
1405
Steve Block1e0659c2011-05-24 12:43:12 +01001406static void Generate_StoreIC_ArrayLength_Strict(MacroAssembler* masm) {
1407 StoreIC::GenerateArrayLength(masm);
1408}
1409
1410
Ben Murdochb0fe1622011-05-05 13:52:32 +01001411static void Generate_StoreIC_GlobalProxy(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001412 StoreIC::GenerateGlobalProxy(masm, kNonStrictMode);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001413}
1414
1415
Steve Block1e0659c2011-05-24 12:43:12 +01001416static void Generate_StoreIC_GlobalProxy_Strict(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001417 StoreIC::GenerateGlobalProxy(masm, kStrictMode);
Steve Block1e0659c2011-05-24 12:43:12 +01001418}
1419
1420
Steve Blocka7e24c12009-10-30 11:49:00 +00001421static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001422 KeyedStoreIC::GenerateGeneric(masm, kNonStrictMode);
1423}
1424
1425
1426static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) {
1427 KeyedStoreIC::GenerateGeneric(masm, kStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001428}
1429
1430
Steve Blocka7e24c12009-10-30 11:49:00 +00001431static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
1432 KeyedStoreIC::GenerateMiss(masm);
1433}
1434
1435
1436static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
1437 KeyedStoreIC::GenerateInitialize(masm);
1438}
1439
1440
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001441static void Generate_KeyedStoreIC_Initialize_Strict(MacroAssembler* masm) {
1442 KeyedStoreIC::GenerateInitialize(masm);
1443}
1444
1445
Steve Blocka7e24c12009-10-30 11:49:00 +00001446#ifdef ENABLE_DEBUGGER_SUPPORT
1447static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
1448 Debug::GenerateLoadICDebugBreak(masm);
1449}
1450
1451
1452static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
1453 Debug::GenerateStoreICDebugBreak(masm);
1454}
1455
1456
1457static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
1458 Debug::GenerateKeyedLoadICDebugBreak(masm);
1459}
1460
1461
1462static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
1463 Debug::GenerateKeyedStoreICDebugBreak(masm);
1464}
1465
1466
1467static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
1468 Debug::GenerateConstructCallDebugBreak(masm);
1469}
1470
1471
1472static void Generate_Return_DebugBreak(MacroAssembler* masm) {
1473 Debug::GenerateReturnDebugBreak(masm);
1474}
1475
1476
1477static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
1478 Debug::GenerateStubNoRegistersDebugBreak(masm);
1479}
Steve Block6ded16b2010-05-10 14:33:55 +01001480
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001481
1482static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
1483 Debug::GenerateSlotDebugBreak(masm);
1484}
1485
1486
Steve Block6ded16b2010-05-10 14:33:55 +01001487static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
1488 Debug::GeneratePlainReturnLiveEdit(masm);
1489}
1490
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001491
Steve Block6ded16b2010-05-10 14:33:55 +01001492static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
1493 Debug::GenerateFrameDropperLiveEdit(masm);
1494}
Steve Blocka7e24c12009-10-30 11:49:00 +00001495#endif
1496
Steve Block44f0eee2011-05-26 01:26:41 +01001497
1498Builtins::Builtins() : initialized_(false) {
1499 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
1500 memset(names_, 0, sizeof(names_[0]) * builtin_count);
1501}
1502
1503
1504Builtins::~Builtins() {
1505}
1506
Steve Blocka7e24c12009-10-30 11:49:00 +00001507
Leon Clarkee46be812010-01-19 14:06:41 +00001508#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Steve Block44f0eee2011-05-26 01:26:41 +01001509Address const Builtins::c_functions_[cfunction_count] = {
1510 BUILTIN_LIST_C(DEF_ENUM_C)
1511};
Steve Blocka7e24c12009-10-30 11:49:00 +00001512#undef DEF_ENUM_C
1513
1514#define DEF_JS_NAME(name, ignore) #name,
1515#define DEF_JS_ARGC(ignore, argc) argc,
Steve Block44f0eee2011-05-26 01:26:41 +01001516const char* const Builtins::javascript_names_[id_count] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00001517 BUILTINS_LIST_JS(DEF_JS_NAME)
1518};
1519
Steve Block44f0eee2011-05-26 01:26:41 +01001520int const Builtins::javascript_argc_[id_count] = {
Steve Blocka7e24c12009-10-30 11:49:00 +00001521 BUILTINS_LIST_JS(DEF_JS_ARGC)
1522};
1523#undef DEF_JS_NAME
1524#undef DEF_JS_ARGC
1525
Steve Block44f0eee2011-05-26 01:26:41 +01001526struct BuiltinDesc {
1527 byte* generator;
1528 byte* c_code;
1529 const char* s_name; // name is only used for generating log information.
1530 int name;
1531 Code::Flags flags;
1532 BuiltinExtraArguments extra_args;
1533};
1534
1535class BuiltinFunctionTable {
1536 public:
1537 BuiltinFunctionTable() {
1538 Builtins::InitBuiltinFunctionTable();
1539 }
1540
1541 static const BuiltinDesc* functions() { return functions_; }
1542
1543 private:
1544 static BuiltinDesc functions_[Builtins::builtin_count + 1];
1545
1546 friend class Builtins;
1547};
1548
1549BuiltinDesc BuiltinFunctionTable::functions_[Builtins::builtin_count + 1];
1550
1551static const BuiltinFunctionTable builtin_function_table_init;
1552
1553// Define array of pointers to generators and C builtin functions.
1554// We do this in a sort of roundabout way so that we can do the initialization
1555// within the lexical scope of Builtins:: and within a context where
1556// Code::Flags names a non-abstract type.
1557void Builtins::InitBuiltinFunctionTable() {
1558 BuiltinDesc* functions = BuiltinFunctionTable::functions_;
1559 functions[builtin_count].generator = NULL;
1560 functions[builtin_count].c_code = NULL;
1561 functions[builtin_count].s_name = NULL;
1562 functions[builtin_count].name = builtin_count;
1563 functions[builtin_count].flags = static_cast<Code::Flags>(0);
1564 functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
1565
1566#define DEF_FUNCTION_PTR_C(aname, aextra_args) \
1567 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \
1568 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \
1569 functions->s_name = #aname; \
1570 functions->name = c_##aname; \
1571 functions->flags = Code::ComputeFlags(Code::BUILTIN); \
1572 functions->extra_args = aextra_args; \
1573 ++functions;
1574
1575#define DEF_FUNCTION_PTR_A(aname, kind, state, extra) \
1576 functions->generator = FUNCTION_ADDR(Generate_##aname); \
1577 functions->c_code = NULL; \
1578 functions->s_name = #aname; \
1579 functions->name = k##aname; \
1580 functions->flags = Code::ComputeFlags(Code::kind, \
1581 NOT_IN_LOOP, \
1582 state, \
1583 extra); \
1584 functions->extra_args = NO_EXTRA_ARGUMENTS; \
1585 ++functions;
1586
1587 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
1588 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
1589 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
1590
1591#undef DEF_FUNCTION_PTR_C
1592#undef DEF_FUNCTION_PTR_A
1593}
1594
Steve Blocka7e24c12009-10-30 11:49:00 +00001595void Builtins::Setup(bool create_heap_objects) {
Steve Block44f0eee2011-05-26 01:26:41 +01001596 ASSERT(!initialized_);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001597 Isolate* isolate = Isolate::Current();
1598 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001599
1600 // Create a scope for the handles in the builtins.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001601 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001602
Steve Block44f0eee2011-05-26 01:26:41 +01001603 const BuiltinDesc* functions = BuiltinFunctionTable::functions();
Steve Blocka7e24c12009-10-30 11:49:00 +00001604
1605 // For now we generate builtin adaptor code into a stack-allocated
1606 // buffer, before copying it into individual code objects.
1607 byte buffer[4*KB];
1608
1609 // Traverse the list of builtins and generate an adaptor in a
1610 // separate code object for each one.
1611 for (int i = 0; i < builtin_count; i++) {
1612 if (create_heap_objects) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001613 MacroAssembler masm(isolate, buffer, sizeof buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00001614 // Generate the code/adaptor.
Leon Clarkee46be812010-01-19 14:06:41 +00001615 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Steve Blocka7e24c12009-10-30 11:49:00 +00001616 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
1617 // We pass all arguments to the generator, but it may not use all of
1618 // them. This works because the first arguments are on top of the
1619 // stack.
Leon Clarkee46be812010-01-19 14:06:41 +00001620 g(&masm, functions[i].name, functions[i].extra_args);
Steve Blocka7e24c12009-10-30 11:49:00 +00001621 // Move the code into the object heap.
1622 CodeDesc desc;
1623 masm.GetCode(&desc);
1624 Code::Flags flags = functions[i].flags;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001625 Object* code = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00001626 {
1627 // During startup it's OK to always allocate and defer GC to later.
1628 // This simplifies things because we don't need to retry.
1629 AlwaysAllocateScope __scope__;
John Reck59135872010-11-02 12:39:01 -07001630 { MaybeObject* maybe_code =
Steve Block44f0eee2011-05-26 01:26:41 +01001631 heap->CreateCode(desc, flags, masm.CodeObject());
John Reck59135872010-11-02 12:39:01 -07001632 if (!maybe_code->ToObject(&code)) {
1633 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
1634 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001635 }
1636 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001637 // Log the event and add the code to the builtins array.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001638 PROFILE(isolate,
Steve Block44f0eee2011-05-26 01:26:41 +01001639 CodeCreateEvent(Logger::BUILTIN_TAG,
Ben Murdochb8e0da22011-05-16 14:20:40 +01001640 Code::cast(code),
1641 functions[i].s_name));
1642 GDBJIT(AddCode(GDBJITInterface::BUILTIN,
1643 functions[i].s_name,
1644 Code::cast(code)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001645 builtins_[i] = code;
1646#ifdef ENABLE_DISASSEMBLER
1647 if (FLAG_print_builtin_code) {
1648 PrintF("Builtin: %s\n", functions[i].s_name);
1649 Code::cast(code)->Disassemble(functions[i].s_name);
1650 PrintF("\n");
1651 }
1652#endif
1653 } else {
1654 // Deserializing. The values will be filled in during IterateBuiltins.
1655 builtins_[i] = NULL;
1656 }
1657 names_[i] = functions[i].s_name;
1658 }
1659
1660 // Mark as initialized.
Steve Block44f0eee2011-05-26 01:26:41 +01001661 initialized_ = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001662}
1663
1664
1665void Builtins::TearDown() {
Steve Block44f0eee2011-05-26 01:26:41 +01001666 initialized_ = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001667}
1668
1669
1670void Builtins::IterateBuiltins(ObjectVisitor* v) {
1671 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
1672}
1673
1674
1675const char* Builtins::Lookup(byte* pc) {
Steve Block44f0eee2011-05-26 01:26:41 +01001676 // may be called during initialization (disassembler!)
1677 if (initialized_) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001678 for (int i = 0; i < builtin_count; i++) {
1679 Code* entry = Code::cast(builtins_[i]);
1680 if (entry->contains(pc)) {
1681 return names_[i];
1682 }
1683 }
1684 }
1685 return NULL;
1686}
1687
Ben Murdochb0fe1622011-05-05 13:52:32 +01001688
Steve Block44f0eee2011-05-26 01:26:41 +01001689#define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \
1690Handle<Code> Builtins::name() { \
1691 Code** code_address = \
1692 reinterpret_cast<Code**>(builtin_address(k##name)); \
1693 return Handle<Code>(code_address); \
1694}
1695#define DEFINE_BUILTIN_ACCESSOR_A(name, kind, state, extra) \
1696Handle<Code> Builtins::name() { \
1697 Code** code_address = \
1698 reinterpret_cast<Code**>(builtin_address(k##name)); \
1699 return Handle<Code>(code_address); \
1700}
1701BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C)
1702BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A)
1703BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A)
1704#undef DEFINE_BUILTIN_ACCESSOR_C
1705#undef DEFINE_BUILTIN_ACCESSOR_A
1706
1707
Steve Blocka7e24c12009-10-30 11:49:00 +00001708} } // namespace v8::internal