blob: c44b2e22159caf917adab0686bd15b94455796a0 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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 "bootstrapper.h"
32#include "builtins.h"
33#include "ic-inl.h"
34
35namespace v8 { namespace internal {
36
37// ----------------------------------------------------------------------------
38// Support macros for defining builtins in C.
39// ----------------------------------------------------------------------------
40//
41// A builtin function is defined by writing:
42//
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000043// BUILTIN(name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044// ...
45// }
46// BUILTIN_END
47//
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000048// In the body of the builtin function, the variable 'receiver' is visible.
49// The arguments can be accessed through:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050//
51// BUILTIN_ARG(0): Receiver (also available as 'receiver')
52// BUILTIN_ARG(1): First argument
53// ...
54// BUILTIN_ARG(n): Last argument
55//
56// and they evaluate to undefined values if too few arguments were
57// passed to the builtin function invocation.
mads.s.ager31e71382008-08-13 09:32:07 +000058//
59// __argc__ is the number of arguments including the receiver.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060// ----------------------------------------------------------------------------
61
62
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000063// TODO(1238487): We should consider passing whether or not the
64// builtin was invoked as a constructor as part of the
65// arguments. Maybe we also want to pass the called function?
66#define BUILTIN(name) \
67 static Object* Builtin_##name(int __argc__, Object** __argv__) { \
68 Handle<Object> receiver(&__argv__[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069
70
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071// Use an inline function to avoid evaluating the index (n) more than
72// once in the BUILTIN_ARG macro.
73static inline Object* __builtin_arg__(int n, int argc, Object** argv) {
74 ASSERT(n >= 0);
mads.s.ager31e71382008-08-13 09:32:07 +000075 return (argc > n) ? argv[-n] : Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000076}
77
78
79// NOTE: Argument 0 is the receiver. The first 'real' argument is
80// argument 1 - BUILTIN_ARG(1).
81#define BUILTIN_ARG(n) (__builtin_arg__(n, __argc__, __argv__))
82
83
84#define BUILTIN_END \
85 return Heap::undefined_value(); \
86}
87
88
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000089// TODO(1238487): Get rid of this function that determines if the
90// builtin is called as a constructor. This may be a somewhat slow
91// operation due to the stack frame iteration.
92static inline bool CalledAsConstructor() {
93 StackFrameIterator it;
94 ASSERT(it.frame()->is_exit());
95 it.Advance();
96 StackFrame* frame = it.frame();
ager@chromium.org7c537e22008-10-16 08:43:32 +000097 return frame->is_construct();
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000098}
99
100
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101// ----------------------------------------------------------------------------
102
103
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000104Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
105 Code* code = Builtins::builtin(Builtins::Illegal);
106 *resolved = false;
107
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000108 if (Top::context() != NULL) {
109 Object* object = Top::builtins()->javascript_builtin(id);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000110 if (object->IsJSFunction()) {
111 Handle<JSFunction> function(JSFunction::cast(object));
112 // Make sure the number of parameters match the formal parameter count.
113 ASSERT(function->shared()->formal_parameter_count() ==
114 Builtins::GetArgumentsCount(id));
115 if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) {
116 code = function->code();
117 *resolved = true;
118 }
119 }
120 }
121
122 return Handle<Code>(code);
123}
124
125
126BUILTIN(Illegal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000127 UNREACHABLE();
128}
129BUILTIN_END
130
131
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000132BUILTIN(EmptyFunction) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000133}
134BUILTIN_END
135
136
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000137BUILTIN(ArrayCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000138 JSArray* array;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000139 if (CalledAsConstructor()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000140 array = JSArray::cast(*receiver);
141 } else {
142 // Allocate the JS Array
143 JSFunction* constructor =
144 Top::context()->global_context()->array_function();
145 Object* obj = Heap::AllocateJSObject(constructor);
146 if (obj->IsFailure()) return obj;
147 array = JSArray::cast(obj);
148 }
149
150 // 'array' now contains the JSArray we should initialize.
151
152 // Optimize the case where there is one argument and the argument is a
153 // small smi.
mads.s.ager31e71382008-08-13 09:32:07 +0000154 if (__argc__ == 2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155 Object* obj = BUILTIN_ARG(1);
156 if (obj->IsSmi()) {
157 int len = Smi::cast(obj)->value();
158 if (len >= 0 && len < JSObject::kMaxFastElementsLength) {
159 Object* obj = Heap::AllocateFixedArrayWithHoles(len);
160 if (obj->IsFailure()) return obj;
161 array->SetContent(FixedArray::cast(obj));
162 return array;
163 }
164 }
165 // Take the argument as the length.
166 obj = array->Initialize(0);
167 if (obj->IsFailure()) return obj;
mads.s.ager31e71382008-08-13 09:32:07 +0000168 if (__argc__ == 2) return array->SetElementsLength(BUILTIN_ARG(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000169 }
170
v8.team.kasperl727e9952008-09-02 14:56:44 +0000171 // Optimize the case where there are no parameters passed.
mads.s.ager31e71382008-08-13 09:32:07 +0000172 if (__argc__ == 1) return array->Initialize(4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000173
174 // Take the arguments as elements.
mads.s.ager31e71382008-08-13 09:32:07 +0000175 int number_of_elements = __argc__ - 1;
176 Smi* len = Smi::FromInt(number_of_elements);
177 Object* obj = Heap::AllocateFixedArrayWithHoles(len->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000178 if (obj->IsFailure()) return obj;
179 FixedArray* elms = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000180 WriteBarrierMode mode = elms->GetWriteBarrierMode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181 // Fill in the content
mads.s.ager31e71382008-08-13 09:32:07 +0000182 for (int index = 0; index < number_of_elements; index++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000183 elms->set(index, BUILTIN_ARG(index+1), mode);
184 }
185
186 // Set length and elements on the array.
187 array->set_elements(FixedArray::cast(obj));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000188 array->set_length(len, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000189
190 return array;
191}
192BUILTIN_END
193
194
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000195BUILTIN(ArrayPush) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000196 JSArray* array = JSArray::cast(*receiver);
197 ASSERT(array->HasFastElements());
198
199 // Make sure we have space for the elements.
200 int len = Smi::cast(array->length())->value();
201
202 // Set new length.
mads.s.ager31e71382008-08-13 09:32:07 +0000203 int new_length = len + __argc__ - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204 FixedArray* elms = FixedArray::cast(array->elements());
205
206 if (new_length <= elms->length()) {
207 // Backing storage has extra space for the provided values.
mads.s.ager31e71382008-08-13 09:32:07 +0000208 for (int index = 0; index < __argc__ - 1; index++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000209 elms->set(index + len, BUILTIN_ARG(index+1));
210 }
211 } else {
212 // New backing storage is needed.
213 int capacity = new_length + (new_length >> 1) + 16;
214 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
215 if (obj->IsFailure()) return obj;
216 FixedArray* new_elms = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000217 WriteBarrierMode mode = new_elms->GetWriteBarrierMode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218 // Fill out the new array with old elements.
219 for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
220 // Add the provided values.
mads.s.ager31e71382008-08-13 09:32:07 +0000221 for (int index = 0; index < __argc__ - 1; index++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 new_elms->set(index + len, BUILTIN_ARG(index+1), mode);
223 }
224 // Set the new backing storage.
225 array->set_elements(new_elms);
226 }
227 // Set the length.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000228 array->set_length(Smi::FromInt(new_length), SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000229 return array->length();
230}
231BUILTIN_END
232
233
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000234BUILTIN(ArrayPop) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235 JSArray* array = JSArray::cast(*receiver);
236 ASSERT(array->HasFastElements());
237 Object* undefined = Heap::undefined_value();
238
239 int len = Smi::cast(array->length())->value();
240 if (len == 0) return undefined;
241
242 // Get top element
243 FixedArray* elms = FixedArray::cast(array->elements());
244 Object* top = elms->get(len - 1);
245
246 // Set the length.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000247 array->set_length(Smi::FromInt(len - 1), SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000248
249 if (!top->IsTheHole()) {
250 // Delete the top element.
251 elms->set_the_hole(len - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252 return top;
253 }
254
255 // Remember to check the prototype chain.
256 JSFunction* array_function =
257 Top::context()->global_context()->array_function();
258 JSObject* prototype = JSObject::cast(array_function->prototype());
259 top = prototype->GetElement(len - 1);
260
261 return top;
262}
263BUILTIN_END
264
265
266// -----------------------------------------------------------------------------
267//
268
269
270// Returns the holder JSObject if the function can legally be called
271// with this receiver. Returns Heap::null_value() if the call is
272// illegal. Any arguments that don't fit the expected type is
273// overwritten with undefined. Arguments that do fit the expected
274// type is overwritten with the object in the prototype chain that
275// actually has that type.
276static inline Object* TypeCheck(int argc,
277 Object** argv,
278 FunctionTemplateInfo* info) {
279 Object* recv = argv[0];
280 Object* sig_obj = info->signature();
281 if (sig_obj->IsUndefined()) return recv;
282 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
283 // If necessary, check the receiver
284 Object* recv_type = sig->receiver();
285
286 Object* holder = recv;
287 if (!recv_type->IsUndefined()) {
288 for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
289 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
290 break;
291 }
292 }
293 if (holder == Heap::null_value()) return holder;
294 }
295 Object* args_obj = sig->args();
296 // If there is no argument signature we're done
297 if (args_obj->IsUndefined()) return holder;
298 FixedArray* args = FixedArray::cast(args_obj);
299 int length = args->length();
mads.s.ager31e71382008-08-13 09:32:07 +0000300 if (argc <= length) length = argc - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000301 for (int i = 0; i < length; i++) {
302 Object* argtype = args->get(i);
303 if (argtype->IsUndefined()) continue;
304 Object** arg = &argv[-1 - i];
305 Object* current = *arg;
306 for (; current != Heap::null_value(); current = current->GetPrototype()) {
307 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
308 *arg = current;
309 break;
310 }
311 }
312 if (current == Heap::null_value()) *arg = Heap::undefined_value();
313 }
314 return holder;
315}
316
317
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000318BUILTIN(HandleApiCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319 HandleScope scope;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000320 bool is_construct = CalledAsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000321
322 // TODO(1238487): This is not nice. We need to get rid of this
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000323 // kludgy behavior and start handling API calls in a more direct
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324 // way - maybe compile specialized stubs lazily?.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325 Handle<JSFunction> function =
326 Handle<JSFunction>(JSFunction::cast(Builtins::builtin_passed_function));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327
328 if (is_construct) {
329 Handle<FunctionTemplateInfo> desc =
330 Handle<FunctionTemplateInfo>(
331 FunctionTemplateInfo::cast(function->shared()->function_data()));
332 bool pending_exception = false;
333 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(receiver),
334 &pending_exception);
335 ASSERT(Top::has_pending_exception() == pending_exception);
336 if (pending_exception) return Failure::Exception();
337 }
338
339 FunctionTemplateInfo* fun_data =
340 FunctionTemplateInfo::cast(function->shared()->function_data());
341 Object* raw_holder = TypeCheck(__argc__, __argv__, fun_data);
342
343 if (raw_holder->IsNull()) {
344 // This function cannot be called with the given receiver. Abort!
345 Handle<Object> obj =
346 Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
347 return Top::Throw(*obj);
348 }
349
350 Object* raw_call_data = fun_data->call_code();
351 if (!raw_call_data->IsUndefined()) {
352 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
353 Object* callback_obj = call_data->callback();
354 v8::InvocationCallback callback =
355 v8::ToCData<v8::InvocationCallback>(callback_obj);
356 Object* data_obj = call_data->data();
357 Object* result;
358
359 v8::Local<v8::Object> self =
360 v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
361 Handle<Object> data_handle(data_obj);
362 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
363 ASSERT(raw_holder->IsJSObject());
364 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
365 Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
366 v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
367 LOG(ApiObjectAccess("call", JSObject::cast(*receiver)));
368 v8::Arguments args = v8::ImplementationUtilities::NewArguments(
369 data,
370 holder,
371 callee,
372 is_construct,
373 reinterpret_cast<void**>(__argv__ - 1),
mads.s.ager31e71382008-08-13 09:32:07 +0000374 __argc__ - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000375
376 v8::Handle<v8::Value> value;
377 {
378 // Leaving JavaScript.
379 VMState state(OTHER);
380 value = callback(args);
381 }
382 if (value.IsEmpty()) {
383 result = Heap::undefined_value();
384 } else {
385 result = *reinterpret_cast<Object**>(*value);
386 }
387
388 RETURN_IF_SCHEDULED_EXCEPTION();
389 if (!is_construct || result->IsJSObject()) return result;
390 }
391
392 return *receiver;
393}
394BUILTIN_END
395
396
397// Handle calls to non-function objects created through the API that
398// support calls.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000399BUILTIN(HandleApiCallAsFunction) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 // Non-functions are never called as constructors.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000401 ASSERT(!CalledAsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402
403 // Get the object called.
404 JSObject* obj = JSObject::cast(*receiver);
405
406 // Get the invocation callback from the function descriptor that was
407 // used to create the called object.
408 ASSERT(obj->map()->has_instance_call_handler());
409 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
410 Object* template_info = constructor->shared()->function_data();
411 Object* handler =
412 FunctionTemplateInfo::cast(template_info)->instance_call_handler();
413 ASSERT(!handler->IsUndefined());
414 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
415 Object* callback_obj = call_data->callback();
416 v8::InvocationCallback callback =
417 v8::ToCData<v8::InvocationCallback>(callback_obj);
418
419 // Get the data for the call and perform the callback.
420 Object* data_obj = call_data->data();
421 Object* result;
422 { HandleScope scope;
423 v8::Local<v8::Object> self =
424 v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
425 Handle<Object> data_handle(data_obj);
426 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
427 Handle<JSFunction> callee_handle(constructor);
428 v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
429 LOG(ApiObjectAccess("call non-function", JSObject::cast(*receiver)));
430 v8::Arguments args = v8::ImplementationUtilities::NewArguments(
431 data,
432 self,
433 callee,
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000434 false,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435 reinterpret_cast<void**>(__argv__ - 1),
mads.s.ager31e71382008-08-13 09:32:07 +0000436 __argc__ - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000437 v8::Handle<v8::Value> value;
438 {
439 // Leaving JavaScript.
440 VMState state(OTHER);
441 value = callback(args);
442 }
443 if (value.IsEmpty()) {
444 result = Heap::undefined_value();
445 } else {
446 result = *reinterpret_cast<Object**>(*value);
447 }
448 }
449 // Check for exceptions and return result.
450 RETURN_IF_SCHEDULED_EXCEPTION();
451 return result;
452}
453BUILTIN_END
454
455
456// TODO(1238487): This is a nasty hack. We need to improve the way we
457// call builtins considerable to get rid of this and the hairy macros
458// in builtins.cc.
459Object* Builtins::builtin_passed_function;
460
461
462
463static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
464 LoadIC::GenerateArrayLength(masm);
465}
466
467
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000468static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
469 LoadIC::GenerateStringLength(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000470}
471
472
473static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
474 LoadIC::GenerateFunctionPrototype(masm);
475}
476
477
478static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
479 LoadIC::GenerateInitialize(masm);
480}
481
482
483static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
484 LoadIC::GeneratePreMonomorphic(masm);
485}
486
487
488static void Generate_LoadIC_Miss(MacroAssembler* masm) {
489 LoadIC::GenerateMiss(masm);
490}
491
492
493static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
494 LoadIC::GenerateMegamorphic(masm);
495}
496
497
498static void Generate_LoadIC_Normal(MacroAssembler* masm) {
499 LoadIC::GenerateNormal(masm);
500}
501
502
503static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
504 KeyedLoadIC::GenerateInitialize(masm);
505}
506
507
508static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
509 KeyedLoadIC::GenerateMiss(masm);
510}
511
512
513static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
514 KeyedLoadIC::GenerateGeneric(masm);
515}
516
517
518static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
519 KeyedLoadIC::GeneratePreMonomorphic(masm);
520}
521
522
523static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
524 StoreIC::GenerateInitialize(masm);
525}
526
527
528static void Generate_StoreIC_Miss(MacroAssembler* masm) {
529 StoreIC::GenerateMiss(masm);
530}
531
532
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000533static void Generate_StoreIC_ExtendStorage(MacroAssembler* masm) {
534 StoreIC::GenerateExtendStorage(masm);
535}
536
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
538 StoreIC::GenerateMegamorphic(masm);
539}
540
541
542static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
543 KeyedStoreIC::GenerateGeneric(masm);
544}
545
546
kasperl@chromium.org1accd572008-10-07 10:57:21 +0000547static void Generate_KeyedStoreIC_ExtendStorage(MacroAssembler* masm) {
548 KeyedStoreIC::GenerateExtendStorage(masm);
549}
550
551
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000552static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
553 KeyedStoreIC::GenerateMiss(masm);
554}
555
556
557static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
558 KeyedStoreIC::GenerateInitialize(masm);
559}
560
561
562Object* Builtins::builtins_[builtin_count] = { NULL, };
563const char* Builtins::names_[builtin_count] = { NULL, };
564
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000565#define DEF_ENUM_C(name) FUNCTION_ADDR(Builtin_##name),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 Address Builtins::c_functions_[cfunction_count] = {
567 BUILTIN_LIST_C(DEF_ENUM_C)
568 };
569#undef DEF_ENUM_C
570
571#define DEF_JS_NAME(name, ignore) #name,
572#define DEF_JS_ARGC(ignore, argc) argc,
573const char* Builtins::javascript_names_[id_count] = {
574 BUILTINS_LIST_JS(DEF_JS_NAME)
575};
576
577int Builtins::javascript_argc_[id_count] = {
578 BUILTINS_LIST_JS(DEF_JS_ARGC)
579};
580#undef DEF_JS_NAME
581#undef DEF_JS_ARGC
582
583static bool is_initialized = false;
584void Builtins::Setup(bool create_heap_objects) {
585 ASSERT(!is_initialized);
586
587 // Create a scope for the handles in the builtins.
588 HandleScope scope;
589
590 struct BuiltinDesc {
591 byte* generator;
592 byte* c_code;
593 const char* s_name; // name is only used for generating log information.
594 int name;
595 Code::Flags flags;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596 };
597
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000598#define DEF_FUNCTION_PTR_C(name) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 { FUNCTION_ADDR(Generate_Adaptor), \
600 FUNCTION_ADDR(Builtin_##name), \
601 #name, \
602 c_##name, \
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000603 Code::ComputeFlags(Code::BUILTIN) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000604 },
605
606#define DEF_FUNCTION_PTR_A(name, kind, state) \
607 { FUNCTION_ADDR(Generate_##name), \
608 NULL, \
609 #name, \
610 name, \
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000611 Code::ComputeFlags(Code::kind, state) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000612 },
613
614 // Define array of pointers to generators and C builtin functions.
615 static BuiltinDesc functions[] = {
616 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
617 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
618 // Terminator:
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000619 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0) }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 };
621
622#undef DEF_FUNCTION_PTR_C
623#undef DEF_FUNCTION_PTR_A
624
625 // For now we generate builtin adaptor code into a stack-allocated
v8.team.kasperl727e9952008-09-02 14:56:44 +0000626 // buffer, before copying it into individual code objects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000627 byte buffer[4*KB];
628
629 // Traverse the list of builtins and generate an adaptor in a
630 // separate code object for each one.
631 for (int i = 0; i < builtin_count; i++) {
632 if (create_heap_objects) {
633 MacroAssembler masm(buffer, sizeof buffer);
634 // Generate the code/adaptor.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000635 typedef void (*Generator)(MacroAssembler*, int);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
637 // We pass all arguments to the generator, but it may not use all of
638 // them. This works because the first arguments are on top of the
639 // stack.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000640 g(&masm, functions[i].name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641 // Move the code into the object heap.
642 CodeDesc desc;
643 masm.GetCode(&desc);
644 Code::Flags flags = functions[i].flags;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000645 Object* code;
646 {
647 // During startup it's OK to always allocate and defer GC to later.
648 // This simplifies things because we don't need to retry.
649 AlwaysAllocateScope __scope__;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000650 code = Heap::CreateCode(desc, NULL, flags, NULL);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000651 if (code->IsFailure()) {
652 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
653 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000654 }
655 // Add any unresolved jumps or calls to the fixup list in the
656 // bootstrapper.
657 Bootstrapper::AddFixup(Code::cast(code), &masm);
658 // Log the event and add the code to the builtins array.
659 LOG(CodeCreateEvent("Builtin", Code::cast(code), functions[i].s_name));
660 builtins_[i] = code;
mads.s.ager31e71382008-08-13 09:32:07 +0000661#ifdef DEBUG
662 if (FLAG_print_builtin_code) {
663 PrintF("Builtin: %s\n", functions[i].s_name);
664 code->Print();
665 PrintF("\n");
666 }
667#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000668 } else {
669 // Deserializing. The values will be filled in during IterateBuiltins.
670 builtins_[i] = NULL;
671 }
672 names_[i] = functions[i].s_name;
673 }
674
675 // Mark as initialized.
676 is_initialized = true;
677}
678
679
680void Builtins::TearDown() {
681 is_initialized = false;
682}
683
684
685void Builtins::IterateBuiltins(ObjectVisitor* v) {
686 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
687}
688
689
690const char* Builtins::Lookup(byte* pc) {
691 if (is_initialized) { // may be called during initialization (disassembler!)
692 for (int i = 0; i < builtin_count; i++) {
693 Code* entry = Code::cast(builtins_[i]);
694 if (entry->contains(pc)) {
695 return names_[i];
696 }
697 }
698 }
699 return NULL;
700}
701
702
703} } // namespace v8::internal