1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29
30 #include "api.h"
31 #include "arguments.h"
32 #include "bootstrapper.h"
33 #include "builtins.h"
34 #include "ic-inl.h"
35
36 namespace v8 {
37 namespace internal {
38
39 // ----------------------------------------------------------------------------
40 // Support macros for defining builtins in C.
41 // ----------------------------------------------------------------------------
42 //
43 // A builtin function is defined by writing:
44 //
45 // BUILTIN(name) {
46 // ...
47 // }
48 // BUILTIN_END
49 //
50 // In the body of the builtin function, the variable 'receiver' is visible.
51 // The arguments can be accessed through the Arguments object args.
52 //
53 // args[0]: Receiver (also available as 'receiver')
54 // args[1]: First argument
55 // ...
56 // args[n]: Last argument
57 // args.length(): Number of arguments including the receiver.
58 // ----------------------------------------------------------------------------
59
60
61 // TODO(428): We should consider passing whether or not the
62 // builtin was invoked as a constructor as part of the
63 // arguments. Maybe we also want to pass the called function?
64 #define BUILTIN(name) \
65 static Object* Builtin_##name(Arguments args) { \
66 Handle<Object> receiver = args.at<Object>(0);
67
68
69 #define BUILTIN_END \
70 return Heap::undefined_value(); \
71 }
72
73
CalledAsConstructor()74 static inline bool CalledAsConstructor() {
75 #ifdef DEBUG
76 // Calculate the result using a full stack frame iterator and check
77 // that the state of the stack is as we assume it to be in the
78 // code below.
79 StackFrameIterator it;
80 ASSERT(it.frame()->is_exit());
81 it.Advance();
82 StackFrame* frame = it.frame();
83 bool reference_result = frame->is_construct();
84 #endif
85 Address fp = Top::c_entry_fp(Top::GetCurrentThread());
86 // Because we know fp points to an exit frame we can use the relevant
87 // part of ExitFrame::ComputeCallerState directly.
88 const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
89 Address caller_fp = Memory::Address_at(fp + kCallerOffset);
90 // This inlines the part of StackFrame::ComputeType that grabs the
91 // type of the current frame. Note that StackFrame::ComputeType
92 // has been specialized for each architecture so if any one of them
93 // changes this code has to be changed as well.
94 const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
95 const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
96 Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
97 bool result = (marker == kConstructMarker);
98 ASSERT_EQ(result, reference_result);
99 return result;
100 }
101
102 // ----------------------------------------------------------------------------
103
104
GetCode(JavaScript id,bool * resolved)105 Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
106 Code* code = Builtins::builtin(Builtins::Illegal);
107 *resolved = false;
108
109 if (Top::context() != NULL) {
110 Object* object = Top::builtins()->javascript_builtin(id);
111 if (object->IsJSFunction()) {
112 Handle<JSFunction> function(JSFunction::cast(object));
113 // Make sure the number of parameters match the formal parameter count.
114 ASSERT(function->shared()->formal_parameter_count() ==
115 Builtins::GetArgumentsCount(id));
116 if (function->is_compiled() || CompileLazy(function, CLEAR_EXCEPTION)) {
117 code = function->code();
118 *resolved = true;
119 }
120 }
121 }
122
123 return Handle<Code>(code);
124 }
125
126
BUILTIN(Illegal)127 BUILTIN(Illegal) {
128 UNREACHABLE();
129 }
130 BUILTIN_END
131
132
BUILTIN(EmptyFunction)133 BUILTIN(EmptyFunction) {
134 }
135 BUILTIN_END
136
137
BUILTIN(ArrayCode)138 BUILTIN(ArrayCode) {
139 JSArray* array;
140 if (CalledAsConstructor()) {
141 array = JSArray::cast(*receiver);
142 } else {
143 // Allocate the JS Array
144 JSFunction* constructor =
145 Top::context()->global_context()->array_function();
146 Object* obj = Heap::AllocateJSObject(constructor);
147 if (obj->IsFailure()) return obj;
148 array = JSArray::cast(obj);
149 }
150
151 // 'array' now contains the JSArray we should initialize.
152
153 // Optimize the case where there is one argument and the argument is a
154 // small smi.
155 if (args.length() == 2) {
156 Object* obj = args[1];
157 if (obj->IsSmi()) {
158 int len = Smi::cast(obj)->value();
159 if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
160 Object* obj = Heap::AllocateFixedArrayWithHoles(len);
161 if (obj->IsFailure()) return obj;
162 array->SetContent(FixedArray::cast(obj));
163 return array;
164 }
165 }
166 // Take the argument as the length.
167 obj = array->Initialize(0);
168 if (obj->IsFailure()) return obj;
169 if (args.length() == 2) return array->SetElementsLength(args[1]);
170 }
171
172 // Optimize the case where there are no parameters passed.
173 if (args.length() == 1) return array->Initialize(4);
174
175 // Take the arguments as elements.
176 int number_of_elements = args.length() - 1;
177 Smi* len = Smi::FromInt(number_of_elements);
178 Object* obj = Heap::AllocateFixedArrayWithHoles(len->value());
179 if (obj->IsFailure()) return obj;
180 FixedArray* elms = FixedArray::cast(obj);
181 WriteBarrierMode mode = elms->GetWriteBarrierMode();
182 // Fill in the content
183 for (int index = 0; index < number_of_elements; index++) {
184 elms->set(index, args[index+1], mode);
185 }
186
187 // Set length and elements on the array.
188 array->set_elements(FixedArray::cast(obj));
189 array->set_length(len, SKIP_WRITE_BARRIER);
190
191 return array;
192 }
193 BUILTIN_END
194
195
BUILTIN(ArrayPush)196 BUILTIN(ArrayPush) {
197 JSArray* array = JSArray::cast(*receiver);
198 ASSERT(array->HasFastElements());
199
200 // Make sure we have space for the elements.
201 int len = Smi::cast(array->length())->value();
202
203 // Set new length.
204 int new_length = len + args.length() - 1;
205 FixedArray* elms = FixedArray::cast(array->elements());
206
207 if (new_length <= elms->length()) {
208 // Backing storage has extra space for the provided values.
209 for (int index = 0; index < args.length() - 1; index++) {
210 elms->set(index + len, args[index+1]);
211 }
212 } else {
213 // New backing storage is needed.
214 int capacity = new_length + (new_length >> 1) + 16;
215 Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
216 if (obj->IsFailure()) return obj;
217 FixedArray* new_elms = FixedArray::cast(obj);
218 WriteBarrierMode mode = new_elms->GetWriteBarrierMode();
219 // Fill out the new array with old elements.
220 for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
221 // Add the provided values.
222 for (int index = 0; index < args.length() - 1; index++) {
223 new_elms->set(index + len, args[index+1], mode);
224 }
225 // Set the new backing storage.
226 array->set_elements(new_elms);
227 }
228 // Set the length.
229 array->set_length(Smi::FromInt(new_length), SKIP_WRITE_BARRIER);
230 return array->length();
231 }
232 BUILTIN_END
233
234
BUILTIN(ArrayPop)235 BUILTIN(ArrayPop) {
236 JSArray* array = JSArray::cast(*receiver);
237 ASSERT(array->HasFastElements());
238 Object* undefined = Heap::undefined_value();
239
240 int len = Smi::cast(array->length())->value();
241 if (len == 0) return undefined;
242
243 // Get top element
244 FixedArray* elms = FixedArray::cast(array->elements());
245 Object* top = elms->get(len - 1);
246
247 // Set the length.
248 array->set_length(Smi::FromInt(len - 1), SKIP_WRITE_BARRIER);
249
250 if (!top->IsTheHole()) {
251 // Delete the top element.
252 elms->set_the_hole(len - 1);
253 return top;
254 }
255
256 // Remember to check the prototype chain.
257 JSFunction* array_function =
258 Top::context()->global_context()->array_function();
259 JSObject* prototype = JSObject::cast(array_function->prototype());
260 top = prototype->GetElement(len - 1);
261
262 return top;
263 }
264 BUILTIN_END
265
266
267 // -----------------------------------------------------------------------------
268 //
269
270
271 // Returns the holder JSObject if the function can legally be called
272 // with this receiver. Returns Heap::null_value() if the call is
273 // illegal. Any arguments that don't fit the expected type is
274 // overwritten with undefined. Arguments that do fit the expected
275 // type is overwritten with the object in the prototype chain that
276 // actually has that type.
TypeCheck(int argc,Object ** argv,FunctionTemplateInfo * info)277 static inline Object* TypeCheck(int argc,
278 Object** argv,
279 FunctionTemplateInfo* info) {
280 Object* recv = argv[0];
281 Object* sig_obj = info->signature();
282 if (sig_obj->IsUndefined()) return recv;
283 SignatureInfo* sig = SignatureInfo::cast(sig_obj);
284 // If necessary, check the receiver
285 Object* recv_type = sig->receiver();
286
287 Object* holder = recv;
288 if (!recv_type->IsUndefined()) {
289 for (; holder != Heap::null_value(); holder = holder->GetPrototype()) {
290 if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) {
291 break;
292 }
293 }
294 if (holder == Heap::null_value()) return holder;
295 }
296 Object* args_obj = sig->args();
297 // If there is no argument signature we're done
298 if (args_obj->IsUndefined()) return holder;
299 FixedArray* args = FixedArray::cast(args_obj);
300 int length = args->length();
301 if (argc <= length) length = argc - 1;
302 for (int i = 0; i < length; i++) {
303 Object* argtype = args->get(i);
304 if (argtype->IsUndefined()) continue;
305 Object** arg = &argv[-1 - i];
306 Object* current = *arg;
307 for (; current != Heap::null_value(); current = current->GetPrototype()) {
308 if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) {
309 *arg = current;
310 break;
311 }
312 }
313 if (current == Heap::null_value()) *arg = Heap::undefined_value();
314 }
315 return holder;
316 }
317
318
BUILTIN(HandleApiCall)319 BUILTIN(HandleApiCall) {
320 HandleScope scope;
321 bool is_construct = CalledAsConstructor();
322
323 // TODO(428): Remove use of static variable, handle API callbacks directly.
324 Handle<JSFunction> function =
325 Handle<JSFunction>(JSFunction::cast(Builtins::builtin_passed_function));
326
327 if (is_construct) {
328 Handle<FunctionTemplateInfo> desc =
329 Handle<FunctionTemplateInfo>(
330 FunctionTemplateInfo::cast(function->shared()->function_data()));
331 bool pending_exception = false;
332 Factory::ConfigureInstance(desc, Handle<JSObject>::cast(receiver),
333 &pending_exception);
334 ASSERT(Top::has_pending_exception() == pending_exception);
335 if (pending_exception) return Failure::Exception();
336 }
337
338 FunctionTemplateInfo* fun_data =
339 FunctionTemplateInfo::cast(function->shared()->function_data());
340 Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
341
342 if (raw_holder->IsNull()) {
343 // This function cannot be called with the given receiver. Abort!
344 Handle<Object> obj =
345 Factory::NewTypeError("illegal_invocation", HandleVector(&function, 1));
346 return Top::Throw(*obj);
347 }
348
349 Object* raw_call_data = fun_data->call_code();
350 if (!raw_call_data->IsUndefined()) {
351 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
352 Object* callback_obj = call_data->callback();
353 v8::InvocationCallback callback =
354 v8::ToCData<v8::InvocationCallback>(callback_obj);
355 Object* data_obj = call_data->data();
356 Object* result;
357
358 v8::Local<v8::Object> self =
359 v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
360 Handle<Object> data_handle(data_obj);
361 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
362 ASSERT(raw_holder->IsJSObject());
363 v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
364 Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
365 v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
366 LOG(ApiObjectAccess("call", JSObject::cast(*receiver)));
367 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
368 data,
369 holder,
370 callee,
371 is_construct,
372 reinterpret_cast<void**>(&args[0] - 1),
373 args.length() - 1);
374
375 v8::Handle<v8::Value> value;
376 {
377 // Leaving JavaScript.
378 VMState state(EXTERNAL);
379 value = callback(new_args);
380 }
381 if (value.IsEmpty()) {
382 result = Heap::undefined_value();
383 } else {
384 result = *reinterpret_cast<Object**>(*value);
385 }
386
387 RETURN_IF_SCHEDULED_EXCEPTION();
388 if (!is_construct || result->IsJSObject()) return result;
389 }
390
391 return *receiver;
392 }
393 BUILTIN_END
394
395
396 // Helper function to handle calls to non-function objects created through the
397 // API. The object can be called as either a constructor (using new) or just as
398 // a function (without new).
HandleApiCallAsFunctionOrConstructor(bool is_construct_call,Arguments args)399 static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
400 Arguments args) {
401 // Non-functions are never called as constructors. Even if this is an object
402 // called as a constructor the delegate call is not a construct call.
403 ASSERT(!CalledAsConstructor());
404
405 Handle<Object> receiver = args.at<Object>(0);
406
407 // Get the object called.
408 JSObject* obj = JSObject::cast(*receiver);
409
410 // Get the invocation callback from the function descriptor that was
411 // used to create the called object.
412 ASSERT(obj->map()->has_instance_call_handler());
413 JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
414 Object* template_info = constructor->shared()->function_data();
415 Object* handler =
416 FunctionTemplateInfo::cast(template_info)->instance_call_handler();
417 ASSERT(!handler->IsUndefined());
418 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
419 Object* callback_obj = call_data->callback();
420 v8::InvocationCallback callback =
421 v8::ToCData<v8::InvocationCallback>(callback_obj);
422
423 // Get the data for the call and perform the callback.
424 Object* data_obj = call_data->data();
425 Object* result;
426 { HandleScope scope;
427 v8::Local<v8::Object> self =
428 v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
429 Handle<Object> data_handle(data_obj);
430 v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
431 Handle<JSFunction> callee_handle(constructor);
432 v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
433 LOG(ApiObjectAccess("call non-function", JSObject::cast(*receiver)));
434 v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
435 data,
436 self,
437 callee,
438 is_construct_call,
439 reinterpret_cast<void**>(&args[0] - 1),
440 args.length() - 1);
441 v8::Handle<v8::Value> value;
442 {
443 // Leaving JavaScript.
444 VMState state(EXTERNAL);
445 value = callback(new_args);
446 }
447 if (value.IsEmpty()) {
448 result = Heap::undefined_value();
449 } else {
450 result = *reinterpret_cast<Object**>(*value);
451 }
452 }
453 // Check for exceptions and return result.
454 RETURN_IF_SCHEDULED_EXCEPTION();
455 return result;
456 }
457
458
459 // Handle calls to non-function objects created through the API. This delegate
460 // function is used when the call is a normal function call.
BUILTIN(HandleApiCallAsFunction)461 BUILTIN(HandleApiCallAsFunction) {
462 return HandleApiCallAsFunctionOrConstructor(false, args);
463 }
464 BUILTIN_END
465
466
467 // Handle calls to non-function objects created through the API. This delegate
468 // function is used when the call is a construct call.
BUILTIN(HandleApiCallAsConstructor)469 BUILTIN(HandleApiCallAsConstructor) {
470 return HandleApiCallAsFunctionOrConstructor(true, args);
471 }
472 BUILTIN_END
473
474
475 // TODO(1238487): This is a nasty hack. We need to improve the way we
476 // call builtins considerable to get rid of this and the hairy macros
477 // in builtins.cc.
478 Object* Builtins::builtin_passed_function;
479
480
481
Generate_LoadIC_ArrayLength(MacroAssembler * masm)482 static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
483 LoadIC::GenerateArrayLength(masm);
484 }
485
486
Generate_LoadIC_StringLength(MacroAssembler * masm)487 static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
488 LoadIC::GenerateStringLength(masm);
489 }
490
491
Generate_LoadIC_FunctionPrototype(MacroAssembler * masm)492 static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
493 LoadIC::GenerateFunctionPrototype(masm);
494 }
495
496
Generate_LoadIC_Initialize(MacroAssembler * masm)497 static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
498 LoadIC::GenerateInitialize(masm);
499 }
500
501
Generate_LoadIC_PreMonomorphic(MacroAssembler * masm)502 static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
503 LoadIC::GeneratePreMonomorphic(masm);
504 }
505
506
Generate_LoadIC_Miss(MacroAssembler * masm)507 static void Generate_LoadIC_Miss(MacroAssembler* masm) {
508 LoadIC::GenerateMiss(masm);
509 }
510
511
Generate_LoadIC_Megamorphic(MacroAssembler * masm)512 static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
513 LoadIC::GenerateMegamorphic(masm);
514 }
515
516
Generate_LoadIC_Normal(MacroAssembler * masm)517 static void Generate_LoadIC_Normal(MacroAssembler* masm) {
518 LoadIC::GenerateNormal(masm);
519 }
520
521
Generate_KeyedLoadIC_Initialize(MacroAssembler * masm)522 static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
523 KeyedLoadIC::GenerateInitialize(masm);
524 }
525
526
Generate_KeyedLoadIC_Miss(MacroAssembler * masm)527 static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
528 KeyedLoadIC::GenerateMiss(masm);
529 }
530
531
Generate_KeyedLoadIC_Generic(MacroAssembler * masm)532 static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
533 KeyedLoadIC::GenerateGeneric(masm);
534 }
535
536
Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler * masm)537 static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
538 KeyedLoadIC::GeneratePreMonomorphic(masm);
539 }
540
541
Generate_StoreIC_Initialize(MacroAssembler * masm)542 static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
543 StoreIC::GenerateInitialize(masm);
544 }
545
546
Generate_StoreIC_Miss(MacroAssembler * masm)547 static void Generate_StoreIC_Miss(MacroAssembler* masm) {
548 StoreIC::GenerateMiss(masm);
549 }
550
551
Generate_StoreIC_ExtendStorage(MacroAssembler * masm)552 static void Generate_StoreIC_ExtendStorage(MacroAssembler* masm) {
553 StoreIC::GenerateExtendStorage(masm);
554 }
555
Generate_StoreIC_Megamorphic(MacroAssembler * masm)556 static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
557 StoreIC::GenerateMegamorphic(masm);
558 }
559
560
Generate_KeyedStoreIC_Generic(MacroAssembler * masm)561 static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
562 KeyedStoreIC::GenerateGeneric(masm);
563 }
564
565
Generate_KeyedStoreIC_ExtendStorage(MacroAssembler * masm)566 static void Generate_KeyedStoreIC_ExtendStorage(MacroAssembler* masm) {
567 KeyedStoreIC::GenerateExtendStorage(masm);
568 }
569
570
Generate_KeyedStoreIC_Miss(MacroAssembler * masm)571 static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
572 KeyedStoreIC::GenerateMiss(masm);
573 }
574
575
Generate_KeyedStoreIC_Initialize(MacroAssembler * masm)576 static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
577 KeyedStoreIC::GenerateInitialize(masm);
578 }
579
580
581 #ifdef ENABLE_DEBUGGER_SUPPORT
Generate_LoadIC_DebugBreak(MacroAssembler * masm)582 static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
583 Debug::GenerateLoadICDebugBreak(masm);
584 }
585
586
Generate_StoreIC_DebugBreak(MacroAssembler * masm)587 static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
588 Debug::GenerateStoreICDebugBreak(masm);
589 }
590
591
Generate_KeyedLoadIC_DebugBreak(MacroAssembler * masm)592 static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
593 Debug::GenerateKeyedLoadICDebugBreak(masm);
594 }
595
596
Generate_KeyedStoreIC_DebugBreak(MacroAssembler * masm)597 static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
598 Debug::GenerateKeyedStoreICDebugBreak(masm);
599 }
600
601
Generate_ConstructCall_DebugBreak(MacroAssembler * masm)602 static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
603 Debug::GenerateConstructCallDebugBreak(masm);
604 }
605
606
Generate_Return_DebugBreak(MacroAssembler * masm)607 static void Generate_Return_DebugBreak(MacroAssembler* masm) {
608 Debug::GenerateReturnDebugBreak(masm);
609 }
610
611
Generate_Return_DebugBreakEntry(MacroAssembler * masm)612 static void Generate_Return_DebugBreakEntry(MacroAssembler* masm) {
613 Debug::GenerateReturnDebugBreakEntry(masm);
614 }
615
616
Generate_StubNoRegisters_DebugBreak(MacroAssembler * masm)617 static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
618 Debug::GenerateStubNoRegistersDebugBreak(masm);
619 }
620 #endif
621
622 Object* Builtins::builtins_[builtin_count] = { NULL, };
623 const char* Builtins::names_[builtin_count] = { NULL, };
624
625 #define DEF_ENUM_C(name) FUNCTION_ADDR(Builtin_##name),
626 Address Builtins::c_functions_[cfunction_count] = {
627 BUILTIN_LIST_C(DEF_ENUM_C)
628 };
629 #undef DEF_ENUM_C
630
631 #define DEF_JS_NAME(name, ignore) #name,
632 #define DEF_JS_ARGC(ignore, argc) argc,
633 const char* Builtins::javascript_names_[id_count] = {
634 BUILTINS_LIST_JS(DEF_JS_NAME)
635 };
636
637 int Builtins::javascript_argc_[id_count] = {
638 BUILTINS_LIST_JS(DEF_JS_ARGC)
639 };
640 #undef DEF_JS_NAME
641 #undef DEF_JS_ARGC
642
643 static bool is_initialized = false;
Setup(bool create_heap_objects)644 void Builtins::Setup(bool create_heap_objects) {
645 ASSERT(!is_initialized);
646
647 // Create a scope for the handles in the builtins.
648 HandleScope scope;
649
650 struct BuiltinDesc {
651 byte* generator;
652 byte* c_code;
653 const char* s_name; // name is only used for generating log information.
654 int name;
655 Code::Flags flags;
656 };
657
658 #define DEF_FUNCTION_PTR_C(name) \
659 { FUNCTION_ADDR(Generate_Adaptor), \
660 FUNCTION_ADDR(Builtin_##name), \
661 #name, \
662 c_##name, \
663 Code::ComputeFlags(Code::BUILTIN) \
664 },
665
666 #define DEF_FUNCTION_PTR_A(name, kind, state) \
667 { FUNCTION_ADDR(Generate_##name), \
668 NULL, \
669 #name, \
670 name, \
671 Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state) \
672 },
673
674 // Define array of pointers to generators and C builtin functions.
675 static BuiltinDesc functions[] = {
676 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
677 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
678 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
679 // Terminator:
680 { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0) }
681 };
682
683 #undef DEF_FUNCTION_PTR_C
684 #undef DEF_FUNCTION_PTR_A
685
686 // For now we generate builtin adaptor code into a stack-allocated
687 // buffer, before copying it into individual code objects.
688 byte buffer[4*KB];
689
690 // Traverse the list of builtins and generate an adaptor in a
691 // separate code object for each one.
692 for (int i = 0; i < builtin_count; i++) {
693 if (create_heap_objects) {
694 MacroAssembler masm(buffer, sizeof buffer);
695 // Generate the code/adaptor.
696 typedef void (*Generator)(MacroAssembler*, int);
697 Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
698 // We pass all arguments to the generator, but it may not use all of
699 // them. This works because the first arguments are on top of the
700 // stack.
701 g(&masm, functions[i].name);
702 // Move the code into the object heap.
703 CodeDesc desc;
704 masm.GetCode(&desc);
705 Code::Flags flags = functions[i].flags;
706 Object* code;
707 {
708 // During startup it's OK to always allocate and defer GC to later.
709 // This simplifies things because we don't need to retry.
710 AlwaysAllocateScope __scope__;
711 code = Heap::CreateCode(desc, NULL, flags, masm.CodeObject());
712 if (code->IsFailure()) {
713 v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
714 }
715 }
716 // Add any unresolved jumps or calls to the fixup list in the
717 // bootstrapper.
718 Bootstrapper::AddFixup(Code::cast(code), &masm);
719 // Log the event and add the code to the builtins array.
720 LOG(CodeCreateEvent(Logger::BUILTIN_TAG,
721 Code::cast(code), functions[i].s_name));
722 builtins_[i] = code;
723 #ifdef ENABLE_DISASSEMBLER
724 if (FLAG_print_builtin_code) {
725 PrintF("Builtin: %s\n", functions[i].s_name);
726 Code::cast(code)->Disassemble(functions[i].s_name);
727 PrintF("\n");
728 }
729 #endif
730 } else {
731 // Deserializing. The values will be filled in during IterateBuiltins.
732 builtins_[i] = NULL;
733 }
734 names_[i] = functions[i].s_name;
735 }
736
737 // Mark as initialized.
738 is_initialized = true;
739 }
740
741
TearDown()742 void Builtins::TearDown() {
743 is_initialized = false;
744 }
745
746
IterateBuiltins(ObjectVisitor * v)747 void Builtins::IterateBuiltins(ObjectVisitor* v) {
748 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
749 }
750
751
Lookup(byte * pc)752 const char* Builtins::Lookup(byte* pc) {
753 if (is_initialized) { // may be called during initialization (disassembler!)
754 for (int i = 0; i < builtin_count; i++) {
755 Code* entry = Code::cast(builtins_[i]);
756 if (entry->contains(pc)) {
757 return names_[i];
758 }
759 }
760 }
761 return NULL;
762 }
763
764
765 } } // namespace v8::internal
766