blob: 9db223039fa3aa90cd5f4c8535733811af4d2186 [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
171Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
172 Code* code = Builtins::builtin(Builtins::Illegal);
173 *resolved = false;
174
175 if (Top::context() != NULL) {
176 Object* object = Top::builtins()->javascript_builtin(id);
177 if (object->IsJSFunction()) {
178 Handle<JSFunction> function(JSFunction::cast(object));
179 // Make sure the number of parameters match the formal parameter count.
180 ASSERT(function->shared()->formal_parameter_count() ==
181 Builtins::GetArgumentsCount(id));
182 if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) {
183 code = function->code();
184 *resolved = true;
185 }
186 }
187 }
188
189 return Handle<Code>(code);
190}
191
192
193BUILTIN(Illegal) {
194 UNREACHABLE();
Leon Clarkee46be812010-01-19 14:06:41 +0000195 return Heap::undefined_value(); // Make compiler happy.
Steve Blocka7e24c12009-10-30 11:49:00 +0000196}
Steve Blocka7e24c12009-10-30 11:49:00 +0000197
198
199BUILTIN(EmptyFunction) {
Leon Clarkee46be812010-01-19 14:06:41 +0000200 return Heap::undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000201}
Steve Blocka7e24c12009-10-30 11:49:00 +0000202
203
204BUILTIN(ArrayCodeGeneric) {
205 Counters::array_function_runtime.Increment();
206
207 JSArray* array;
208 if (CalledAsConstructor()) {
Leon Clarkee46be812010-01-19 14:06:41 +0000209 array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 } else {
211 // Allocate the JS Array
212 JSFunction* constructor =
213 Top::context()->global_context()->array_function();
214 Object* obj = Heap::AllocateJSObject(constructor);
215 if (obj->IsFailure()) return obj;
216 array = JSArray::cast(obj);
217 }
218
219 // 'array' now contains the JSArray we should initialize.
220
221 // Optimize the case where there is one argument and the argument is a
222 // small smi.
223 if (args.length() == 2) {
224 Object* obj = args[1];
225 if (obj->IsSmi()) {
226 int len = Smi::cast(obj)->value();
227 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
228 Object* obj = Heap::AllocateFixedArrayWithHoles(len);
229 if (obj->IsFailure()) return obj;
230 array->SetContent(FixedArray::cast(obj));
231 return array;
232 }
233 }
234 // Take the argument as the length.
235 obj = array->Initialize(0);
236 if (obj->IsFailure()) return obj;
237 return array->SetElementsLength(args[1]);
238 }
239
240 // Optimize the case where there are no parameters passed.
241 if (args.length() == 1) {
242 return array->Initialize(JSArray::kPreallocatedArrayElements);
243 }
244
245 // Take the arguments as elements.
246 int number_of_elements = args.length() - 1;
247 Smi* len = Smi::FromInt(number_of_elements);
248 Object* obj = Heap::AllocateFixedArrayWithHoles(len->value());
249 if (obj->IsFailure()) return obj;
250 FixedArray* elms = FixedArray::cast(obj);
251 WriteBarrierMode mode = elms->GetWriteBarrierMode();
252 // Fill in the content
253 for (int index = 0; index < number_of_elements; index++) {
254 elms->set(index, args[index+1], mode);
255 }
256
257 // Set length and elements on the array.
258 array->set_elements(FixedArray::cast(obj));
259 array->set_length(len, SKIP_WRITE_BARRIER);
260
261 return array;
262}
Steve Blocka7e24c12009-10-30 11:49:00 +0000263
264
265BUILTIN(ArrayPush) {
Leon Clarkee46be812010-01-19 14:06:41 +0000266 JSArray* array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000267 ASSERT(array->HasFastElements());
268
269 // Make sure we have space for the elements.
270 int len = Smi::cast(array->length())->value();
271
272 // Set new length.
273 int new_length = len + args.length() - 1;
274 FixedArray* elms = FixedArray::cast(array->elements());
275
276 if (new_length <= elms->length()) {
277 // Backing storage has extra space for the provided values.
278 for (int index = 0; index < args.length() - 1; index++) {
279 elms->set(index + len, args[index+1]);
280 }
281 } else {
282 // New backing storage is needed.
283 int capacity = new_length + (new_length >> 1) + 16;
284 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
285 if (obj->IsFailure()) return obj;
286 FixedArray* new_elms = FixedArray::cast(obj);
287 WriteBarrierMode mode = new_elms->GetWriteBarrierMode();
288 // Fill out the new array with old elements.
289 for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
290 // Add the provided values.
291 for (int index = 0; index < args.length() - 1; index++) {
292 new_elms->set(index + len, args[index+1], mode);
293 }
294 // Set the new backing storage.
295 array->set_elements(new_elms);
296 }
297 // Set the length.
298 array->set_length(Smi::FromInt(new_length), SKIP_WRITE_BARRIER);
299 return array->length();
300}
Steve Blocka7e24c12009-10-30 11:49:00 +0000301
302
303BUILTIN(ArrayPop) {
Leon Clarkee46be812010-01-19 14:06:41 +0000304 JSArray* array = JSArray::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000305 ASSERT(array->HasFastElements());
306 Object* undefined = Heap::undefined_value();
307
308 int len = Smi::cast(array->length())->value();
309 if (len == 0) return undefined;
310
311 // Get top element
312 FixedArray* elms = FixedArray::cast(array->elements());
313 Object* top = elms->get(len - 1);
314
315 // Set the length.
316 array->set_length(Smi::FromInt(len - 1), SKIP_WRITE_BARRIER);
317
318 if (!top->IsTheHole()) {
319 // Delete the top element.
320 elms->set_the_hole(len - 1);
321 return top;
322 }
323
324 // Remember to check the prototype chain.
325 JSFunction* array_function =
326 Top::context()->global_context()->array_function();
327 JSObject* prototype = JSObject::cast(array_function->prototype());
328 top = prototype->GetElement(len - 1);
329
330 return top;
331}
Steve Blocka7e24c12009-10-30 11:49:00 +0000332
333
334// -----------------------------------------------------------------------------
335//
336
337
338// Returns the holder JSObject if the function can legally be called
339// with this receiver. Returns Heap::null_value() if the call is
340// illegal. Any arguments that don't fit the expected type is
341// overwritten with undefined. Arguments that do fit the expected
342// type is overwritten with the object in the prototype chain that
343// actually has that type.
344static inline Object* TypeCheck(int argc,
345 Object** argv,
346 FunctionTemplateInfo* info) {
347 Object* recv = argv[0];
348 Object* sig_obj = info->signature();
349 if (sig_obj->IsUndefined()) return recv;
350 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
351 // If necessary, check the receiver
352 Object* recv_type = sig->receiver();
353
354 Object* holder = recv;
355 if (!recv_type->IsUndefined()) {
356 for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
357 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
358 break;
359 }
360 }
361 if (holder == Heap::null_value()) return holder;
362 }
363 Object* args_obj = sig->args();
364 // If there is no argument signature we're done
365 if (args_obj->IsUndefined()) return holder;
366 FixedArray* args = FixedArray::cast(args_obj);
367 int length = args->length();
368 if (argc <= length) length = argc - 1;
369 for (int i = 0; i < length; i++) {
370 Object* argtype = args->get(i);
371 if (argtype->IsUndefined()) continue;
372 Object** arg = &argv[-1 - i];
373 Object* current = *arg;
374 for (; current != Heap::null_value(); current = current->GetPrototype()) {
375 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
376 *arg = current;
377 break;
378 }
379 }
380 if (current == Heap::null_value()) *arg = Heap::undefined_value();
381 }
382 return holder;
383}
384
385
Leon Clarkee46be812010-01-19 14:06:41 +0000386template <bool is_construct>
387static Object* HandleApiCallHelper(
388 BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
389 ASSERT(is_construct == CalledAsConstructor());
Steve Blocka7e24c12009-10-30 11:49:00 +0000390
Leon Clarkee46be812010-01-19 14:06:41 +0000391 HandleScope scope;
392 Handle<JSFunction> function = args.called_function();
Steve Blocka7e24c12009-10-30 11:49:00 +0000393
394 if (is_construct) {
395 Handle<FunctionTemplateInfo> desc =
396 Handle<FunctionTemplateInfo>(
397 FunctionTemplateInfo::cast(function->shared()->function_data()));
398 bool pending_exception = false;
Leon Clarkee46be812010-01-19 14:06:41 +0000399 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000400 &pending_exception);
401 ASSERT(Top::has_pending_exception() == pending_exception);
402 if (pending_exception) return Failure::Exception();
403 }
404
405 FunctionTemplateInfo* fun_data =
406 FunctionTemplateInfo::cast(function->shared()->function_data());
407 Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
408
409 if (raw_holder->IsNull()) {
410 // This function cannot be called with the given receiver. Abort!
411 Handle<Object> obj =
412 Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
413 return Top::Throw(*obj);
414 }
415
416 Object* raw_call_data = fun_data->call_code();
417 if (!raw_call_data->IsUndefined()) {
418 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
419 Object* callback_obj = call_data->callback();
420 v8::InvocationCallback callback =
421 v8::ToCData<v8::InvocationCallback>(callback_obj);
422 Object* data_obj = call_data->data();
423 Object* result;
424
Steve Blocka7e24c12009-10-30 11:49:00 +0000425 Handle<Object> data_handle(data_obj);
426 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
427 ASSERT(raw_holder->IsJSObject());
428 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
429 Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
430 v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
Leon Clarkee46be812010-01-19 14:06:41 +0000431 LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +0000432 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
433 data,
434 holder,
435 callee,
436 is_construct,
437 reinterpret_cast<void**>(&args[0] - 1),
438 args.length() - 1);
439
440 v8::Handle<v8::Value> value;
441 {
442 // Leaving JavaScript.
443 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000444#ifdef ENABLE_LOGGING_AND_PROFILING
445 state.set_external_callback(v8::ToCData<Address>(callback_obj));
446#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000447 value = callback(new_args);
448 }
449 if (value.IsEmpty()) {
450 result = Heap::undefined_value();
451 } else {
452 result = *reinterpret_cast<Object**>(*value);
453 }
454
455 RETURN_IF_SCHEDULED_EXCEPTION();
456 if (!is_construct || result->IsJSObject()) return result;
457 }
458
Leon Clarkee46be812010-01-19 14:06:41 +0000459 return *args.receiver();
Steve Blocka7e24c12009-10-30 11:49:00 +0000460}
Leon Clarkee46be812010-01-19 14:06:41 +0000461
462
463BUILTIN(HandleApiCall) {
464 return HandleApiCallHelper<false>(args);
465}
466
467
468BUILTIN(HandleApiCallConstruct) {
469 return HandleApiCallHelper<true>(args);
470}
Steve Blocka7e24c12009-10-30 11:49:00 +0000471
472
473// Helper function to handle calls to non-function objects created through the
474// API. The object can be called as either a constructor (using new) or just as
475// a function (without new).
Leon Clarkee46be812010-01-19 14:06:41 +0000476static Object* HandleApiCallAsFunctionOrConstructor(
477 bool is_construct_call,
478 BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000479 // Non-functions are never called as constructors. Even if this is an object
480 // called as a constructor the delegate call is not a construct call.
481 ASSERT(!CalledAsConstructor());
482
483 Handle<Object> receiver = args.at<Object>(0);
484
485 // Get the object called.
Leon Clarkee46be812010-01-19 14:06:41 +0000486 JSObject* obj = JSObject::cast(*args.receiver());
Steve Blocka7e24c12009-10-30 11:49:00 +0000487
488 // Get the invocation callback from the function descriptor that was
489 // used to create the called object.
490 ASSERT(obj->map()->has_instance_call_handler());
491 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
492 Object* template_info = constructor->shared()->function_data();
493 Object* handler =
494 FunctionTemplateInfo::cast(template_info)->instance_call_handler();
495 ASSERT(!handler->IsUndefined());
496 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
497 Object* callback_obj = call_data->callback();
498 v8::InvocationCallback callback =
499 v8::ToCData<v8::InvocationCallback>(callback_obj);
500
501 // Get the data for the call and perform the callback.
502 Object* data_obj = call_data->data();
503 Object* result;
504 { HandleScope scope;
505 v8::Local<v8::Object> self =
Leon Clarkee46be812010-01-19 14:06:41 +0000506 v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000507 Handle<Object> data_handle(data_obj);
508 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
509 Handle<JSFunction> callee_handle(constructor);
510 v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
Leon Clarkee46be812010-01-19 14:06:41 +0000511 LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver())));
Steve Blocka7e24c12009-10-30 11:49:00 +0000512 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
513 data,
514 self,
515 callee,
516 is_construct_call,
517 reinterpret_cast<void**>(&args[0] - 1),
518 args.length() - 1);
519 v8::Handle<v8::Value> value;
520 {
521 // Leaving JavaScript.
522 VMState state(EXTERNAL);
Steve Blockd0582a62009-12-15 09:54:21 +0000523#ifdef ENABLE_LOGGING_AND_PROFILING
524 state.set_external_callback(v8::ToCData<Address>(callback_obj));
525#endif
Steve Blocka7e24c12009-10-30 11:49:00 +0000526 value = callback(new_args);
527 }
528 if (value.IsEmpty()) {
529 result = Heap::undefined_value();
530 } else {
531 result = *reinterpret_cast<Object**>(*value);
532 }
533 }
534 // Check for exceptions and return result.
535 RETURN_IF_SCHEDULED_EXCEPTION();
536 return result;
537}
538
539
540// Handle calls to non-function objects created through the API. This delegate
541// function is used when the call is a normal function call.
542BUILTIN(HandleApiCallAsFunction) {
543 return HandleApiCallAsFunctionOrConstructor(false, args);
544}
Steve Blocka7e24c12009-10-30 11:49:00 +0000545
546
547// Handle calls to non-function objects created through the API. This delegate
548// function is used when the call is a construct call.
549BUILTIN(HandleApiCallAsConstructor) {
550 return HandleApiCallAsFunctionOrConstructor(true, args);
551}
Steve Blocka7e24c12009-10-30 11:49:00 +0000552
553
554static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
555 LoadIC::GenerateArrayLength(masm);
556}
557
558
559static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
560 LoadIC::GenerateStringLength(masm);
561}
562
563
564static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
565 LoadIC::GenerateFunctionPrototype(masm);
566}
567
568
569static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
570 LoadIC::GenerateInitialize(masm);
571}
572
573
574static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
575 LoadIC::GeneratePreMonomorphic(masm);
576}
577
578
579static void Generate_LoadIC_Miss(MacroAssembler* masm) {
580 LoadIC::GenerateMiss(masm);
581}
582
583
584static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
585 LoadIC::GenerateMegamorphic(masm);
586}
587
588
589static void Generate_LoadIC_Normal(MacroAssembler* masm) {
590 LoadIC::GenerateNormal(masm);
591}
592
593
594static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
595 KeyedLoadIC::GenerateInitialize(masm);
596}
597
598
599static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
600 KeyedLoadIC::GenerateMiss(masm);
601}
602
603
604static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
605 KeyedLoadIC::GenerateGeneric(masm);
606}
607
608
Leon Clarkee46be812010-01-19 14:06:41 +0000609static void Generate_KeyedLoadIC_String(MacroAssembler* masm) {
610 KeyedLoadIC::GenerateString(masm);
611}
612
613
Steve Block3ce2e202009-11-05 08:53:23 +0000614static void Generate_KeyedLoadIC_ExternalByteArray(MacroAssembler* masm) {
615 KeyedLoadIC::GenerateExternalArray(masm, kExternalByteArray);
616}
617
618
619static void Generate_KeyedLoadIC_ExternalUnsignedByteArray(
620 MacroAssembler* masm) {
621 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
622}
623
624
625static void Generate_KeyedLoadIC_ExternalShortArray(MacroAssembler* masm) {
626 KeyedLoadIC::GenerateExternalArray(masm, kExternalShortArray);
627}
628
629
630static void Generate_KeyedLoadIC_ExternalUnsignedShortArray(
631 MacroAssembler* masm) {
632 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
633}
634
635
636static void Generate_KeyedLoadIC_ExternalIntArray(MacroAssembler* masm) {
637 KeyedLoadIC::GenerateExternalArray(masm, kExternalIntArray);
638}
639
640
641static void Generate_KeyedLoadIC_ExternalUnsignedIntArray(
642 MacroAssembler* masm) {
643 KeyedLoadIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
644}
645
646
647static void Generate_KeyedLoadIC_ExternalFloatArray(MacroAssembler* masm) {
648 KeyedLoadIC::GenerateExternalArray(masm, kExternalFloatArray);
649}
650
651
Steve Blocka7e24c12009-10-30 11:49:00 +0000652static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
653 KeyedLoadIC::GeneratePreMonomorphic(masm);
654}
655
656
657static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
658 StoreIC::GenerateInitialize(masm);
659}
660
661
662static void Generate_StoreIC_Miss(MacroAssembler* masm) {
663 StoreIC::GenerateMiss(masm);
664}
665
666
667static void Generate_StoreIC_ExtendStorage(MacroAssembler* masm) {
668 StoreIC::GenerateExtendStorage(masm);
669}
670
671static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
672 StoreIC::GenerateMegamorphic(masm);
673}
674
675
676static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
677 KeyedStoreIC::GenerateGeneric(masm);
678}
679
680
Steve Block3ce2e202009-11-05 08:53:23 +0000681static void Generate_KeyedStoreIC_ExternalByteArray(MacroAssembler* masm) {
682 KeyedStoreIC::GenerateExternalArray(masm, kExternalByteArray);
683}
684
685
686static void Generate_KeyedStoreIC_ExternalUnsignedByteArray(
687 MacroAssembler* masm) {
688 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedByteArray);
689}
690
691
692static void Generate_KeyedStoreIC_ExternalShortArray(MacroAssembler* masm) {
693 KeyedStoreIC::GenerateExternalArray(masm, kExternalShortArray);
694}
695
696
697static void Generate_KeyedStoreIC_ExternalUnsignedShortArray(
698 MacroAssembler* masm) {
699 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedShortArray);
700}
701
702
703static void Generate_KeyedStoreIC_ExternalIntArray(MacroAssembler* masm) {
704 KeyedStoreIC::GenerateExternalArray(masm, kExternalIntArray);
705}
706
707
708static void Generate_KeyedStoreIC_ExternalUnsignedIntArray(
709 MacroAssembler* masm) {
710 KeyedStoreIC::GenerateExternalArray(masm, kExternalUnsignedIntArray);
711}
712
713
714static void Generate_KeyedStoreIC_ExternalFloatArray(MacroAssembler* masm) {
715 KeyedStoreIC::GenerateExternalArray(masm, kExternalFloatArray);
716}
717
718
Steve Blocka7e24c12009-10-30 11:49:00 +0000719static void Generate_KeyedStoreIC_ExtendStorage(MacroAssembler* masm) {
720 KeyedStoreIC::GenerateExtendStorage(masm);
721}
722
723
724static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
725 KeyedStoreIC::GenerateMiss(masm);
726}
727
728
729static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
730 KeyedStoreIC::GenerateInitialize(masm);
731}
732
733
734#ifdef ENABLE_DEBUGGER_SUPPORT
735static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
736 Debug::GenerateLoadICDebugBreak(masm);
737}
738
739
740static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
741 Debug::GenerateStoreICDebugBreak(masm);
742}
743
744
745static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
746 Debug::GenerateKeyedLoadICDebugBreak(masm);
747}
748
749
750static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
751 Debug::GenerateKeyedStoreICDebugBreak(masm);
752}
753
754
755static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
756 Debug::GenerateConstructCallDebugBreak(masm);
757}
758
759
760static void Generate_Return_DebugBreak(MacroAssembler* masm) {
761 Debug::GenerateReturnDebugBreak(masm);
762}
763
764
765static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
766 Debug::GenerateStubNoRegistersDebugBreak(masm);
767}
768#endif
769
770Object* Builtins::builtins_[builtin_count] = { NULL, };
771const char* Builtins::names_[builtin_count] = { NULL, };
772
Leon Clarkee46be812010-01-19 14:06:41 +0000773#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Steve Blocka7e24c12009-10-30 11:49:00 +0000774 Address Builtins::c_functions_[cfunction_count] = {
775 BUILTIN_LIST_C(DEF_ENUM_C)
776 };
777#undef DEF_ENUM_C
778
779#define DEF_JS_NAME(name, ignore) #name,
780#define DEF_JS_ARGC(ignore, argc) argc,
781const char* Builtins::javascript_names_[id_count] = {
782 BUILTINS_LIST_JS(DEF_JS_NAME)
783};
784
785int Builtins::javascript_argc_[id_count] = {
786 BUILTINS_LIST_JS(DEF_JS_ARGC)
787};
788#undef DEF_JS_NAME
789#undef DEF_JS_ARGC
790
791static bool is_initialized = false;
792void Builtins::Setup(bool create_heap_objects) {
793 ASSERT(!is_initialized);
794
795 // Create a scope for the handles in the builtins.
796 HandleScope scope;
797
798 struct BuiltinDesc {
799 byte* generator;
800 byte* c_code;
801 const char* s_name; // name is only used for generating log information.
802 int name;
803 Code::Flags flags;
Leon Clarkee46be812010-01-19 14:06:41 +0000804 BuiltinExtraArguments extra_args;
Steve Blocka7e24c12009-10-30 11:49:00 +0000805 };
806
Leon Clarkee46be812010-01-19 14:06:41 +0000807#define DEF_FUNCTION_PTR_C(name, extra_args) \
808 { FUNCTION_ADDR(Generate_Adaptor), \
809 FUNCTION_ADDR(Builtin_##name), \
810 #name, \
811 c_##name, \
812 Code::ComputeFlags(Code::BUILTIN), \
813 extra_args \
Steve Blocka7e24c12009-10-30 11:49:00 +0000814 },
815
816#define DEF_FUNCTION_PTR_A(name, kind, state) \
817 { FUNCTION_ADDR(Generate_##name), \
818 NULL, \
819 #name, \
820 name, \
Leon Clarkee46be812010-01-19 14:06:41 +0000821 Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
822 NO_EXTRA_ARGUMENTS \
Steve Blocka7e24c12009-10-30 11:49:00 +0000823 },
824
825 // Define array of pointers to generators and C builtin functions.
826 static BuiltinDesc functions[] = {
827 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
828 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
829 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
830 // Terminator:
Leon Clarkee46be812010-01-19 14:06:41 +0000831 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
832 NO_EXTRA_ARGUMENTS }
Steve Blocka7e24c12009-10-30 11:49:00 +0000833 };
834
835#undef DEF_FUNCTION_PTR_C
836#undef DEF_FUNCTION_PTR_A
837
838 // For now we generate builtin adaptor code into a stack-allocated
839 // buffer, before copying it into individual code objects.
840 byte buffer[4*KB];
841
842 // Traverse the list of builtins and generate an adaptor in a
843 // separate code object for each one.
844 for (int i = 0; i < builtin_count; i++) {
845 if (create_heap_objects) {
846 MacroAssembler masm(buffer, sizeof buffer);
847 // Generate the code/adaptor.
Leon Clarkee46be812010-01-19 14:06:41 +0000848 typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Steve Blocka7e24c12009-10-30 11:49:00 +0000849 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
850 // We pass all arguments to the generator, but it may not use all of
851 // them. This works because the first arguments are on top of the
852 // stack.
Leon Clarkee46be812010-01-19 14:06:41 +0000853 g(&masm, functions[i].name, functions[i].extra_args);
Steve Blocka7e24c12009-10-30 11:49:00 +0000854 // Move the code into the object heap.
855 CodeDesc desc;
856 masm.GetCode(&desc);
857 Code::Flags flags = functions[i].flags;
858 Object* code;
859 {
860 // During startup it's OK to always allocate and defer GC to later.
861 // This simplifies things because we don't need to retry.
862 AlwaysAllocateScope __scope__;
863 code = Heap::CreateCode(desc, NULL, flags, masm.CodeObject());
864 if (code->IsFailure()) {
865 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
866 }
867 }
868 // Add any unresolved jumps or calls to the fixup list in the
869 // bootstrapper.
870 Bootstrapper::AddFixup(Code::cast(code), &masm);
871 // Log the event and add the code to the builtins array.
872 LOG(CodeCreateEvent(Logger::BUILTIN_TAG,
873 Code::cast(code), functions[i].s_name));
874 builtins_[i] = code;
875#ifdef ENABLE_DISASSEMBLER
876 if (FLAG_print_builtin_code) {
877 PrintF("Builtin: %s\n", functions[i].s_name);
878 Code::cast(code)->Disassemble(functions[i].s_name);
879 PrintF("\n");
880 }
881#endif
882 } else {
883 // Deserializing. The values will be filled in during IterateBuiltins.
884 builtins_[i] = NULL;
885 }
886 names_[i] = functions[i].s_name;
887 }
888
889 // Mark as initialized.
890 is_initialized = true;
891}
892
893
894void Builtins::TearDown() {
895 is_initialized = false;
896}
897
898
899void Builtins::IterateBuiltins(ObjectVisitor* v) {
900 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
901}
902
903
904const char* Builtins::Lookup(byte* pc) {
905 if (is_initialized) { // may be called during initialization (disassembler!)
906 for (int i = 0; i < builtin_count; i++) {
907 Code* entry = Code::cast(builtins_[i]);
908 if (entry->contains(pc)) {
909 return names_[i];
910 }
911 }
912 }
913 return NULL;
914}
915
916
917} } // namespace v8::internal