The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / builtins.cc @ 40c0f755

History | View | Annotate | Download (22.5 KB)

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 "bootstrapper.h"
32
#include "builtins.h"
33
#include "ic-inl.h"
34

    
35
namespace v8 { namespace internal {
36

    
37
// ----------------------------------------------------------------------------
38
// Support macros for defining builtins in C.
39
// ----------------------------------------------------------------------------
40
//
41
// A builtin function is defined by writing:
42
//
43
//   BUILTIN(name) {
44
//     ...
45
//   }
46
//   BUILTIN_END
47
//
48
// In the body of the builtin function, the variable 'receiver' is visible.
49
// The arguments can be accessed through:
50
//
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.
58
//
59
// __argc__ is the number of arguments including the receiver.
60
// ----------------------------------------------------------------------------
61

    
62

    
63
// 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]);
69

    
70

    
71
// Use an inline function to avoid evaluating the index (n) more than
72
// once in the BUILTIN_ARG macro.
73
static inline Object* __builtin_arg__(int n, int argc, Object** argv) {
74
  ASSERT(n >= 0);
75
  return (argc > n) ? argv[-n] : Heap::undefined_value();
76
}
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

    
89
// 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.
92
static inline bool CalledAsConstructor() {
93
  StackFrameIterator it;
94
  ASSERT(it.frame()->is_exit());
95
  it.Advance();
96
  StackFrame* frame = it.frame();
97
  return frame->is_construct();
98
}
99

    
100

    
101
// ----------------------------------------------------------------------------
102

    
103

    
104
Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
105
  Code* code = Builtins::builtin(Builtins::Illegal);
106
  *resolved = false;
107

    
108
  if (Top::context() != NULL) {
109
    Object* object = Top::builtins()->javascript_builtin(id);
110
    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

    
126
BUILTIN(Illegal) {
127
  UNREACHABLE();
128
}
129
BUILTIN_END
130

    
131

    
132
BUILTIN(EmptyFunction) {
133
}
134
BUILTIN_END
135

    
136

    
137
BUILTIN(ArrayCode) {
138
  JSArray* array;
139
  if (CalledAsConstructor()) {
140
    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.
154
  if (__argc__ == 2) {
155
    Object* obj = BUILTIN_ARG(1);
156
    if (obj->IsSmi()) {
157
      int len = Smi::cast(obj)->value();
158
      if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
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;
168
    if (__argc__ == 2) return array->SetElementsLength(BUILTIN_ARG(1));
169
  }
170

    
171
  // Optimize the case where there are no parameters passed.
172
  if (__argc__ == 1) return array->Initialize(4);
173

    
174
  // Take the arguments as elements.
175
  int number_of_elements = __argc__ - 1;
176
  Smi* len = Smi::FromInt(number_of_elements);
177
  Object* obj = Heap::AllocateFixedArrayWithHoles(len->value());
178
  if (obj->IsFailure()) return obj;
179
  FixedArray* elms = FixedArray::cast(obj);
180
  WriteBarrierMode mode = elms->GetWriteBarrierMode();
181
  // Fill in the content
182
  for (int index = 0; index < number_of_elements; index++) {
183
    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));
188
  array->set_length(len, SKIP_WRITE_BARRIER);
189

    
190
  return array;
191
}
192
BUILTIN_END
193

    
194

    
195
BUILTIN(ArrayPush) {
196
  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.
203
  int new_length = len + __argc__ - 1;
204
  FixedArray* elms = FixedArray::cast(array->elements());
205

    
206
  if (new_length <= elms->length()) {
207
    // Backing storage has extra space for the provided values.
208
    for (int index = 0; index < __argc__ - 1; index++) {
209
      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);
217
    WriteBarrierMode mode = new_elms->GetWriteBarrierMode();
218
    // 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.
221
    for (int index = 0; index < __argc__ - 1; index++) {
222
      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.
228
  array->set_length(Smi::FromInt(new_length), SKIP_WRITE_BARRIER);
229
  return array->length();
230
}
231
BUILTIN_END
232

    
233

    
234
BUILTIN(ArrayPop) {
235
  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.
247
  array->set_length(Smi::FromInt(len - 1), SKIP_WRITE_BARRIER);
248

    
249
  if (!top->IsTheHole()) {
250
    // Delete the top element.
251
    elms->set_the_hole(len - 1);
252
    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
}
263
BUILTIN_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.
276
static 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();
300
  if (argc <= length) length = argc - 1;
301
  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

    
318
BUILTIN(HandleApiCall) {
319
  HandleScope scope;
320
  bool is_construct = CalledAsConstructor();
321

    
322
  // TODO(1238487): This is not nice. We need to get rid of this
323
  // kludgy behavior and start handling API calls in a more direct
324
  // way - maybe compile specialized stubs lazily?.
325
  Handle<JSFunction> function =
326
      Handle<JSFunction>(JSFunction::cast(Builtins::builtin_passed_function));
327

    
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),
374
        __argc__ - 1);
375

    
376
    v8::Handle<v8::Value> value;
377
    {
378
      // Leaving JavaScript.
379
      VMState state(EXTERNAL);
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
}
394
BUILTIN_END
395

    
396

    
397
// Handle calls to non-function objects created through the API that
398
// support calls.
399
BUILTIN(HandleApiCallAsFunction) {
400
  // Non-functions are never called as constructors.
401
  ASSERT(!CalledAsConstructor());
402

    
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,
434
        false,
435
        reinterpret_cast<void**>(__argv__ - 1),
436
        __argc__ - 1);
437
    v8::Handle<v8::Value> value;
438
    {
439
      // Leaving JavaScript.
440
      VMState state(EXTERNAL);
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
}
453
BUILTIN_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.
459
Object* Builtins::builtin_passed_function;
460

    
461

    
462

    
463
static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
464
  LoadIC::GenerateArrayLength(masm);
465
}
466

    
467

    
468
static void Generate_LoadIC_StringLength(MacroAssembler* masm) {
469
  LoadIC::GenerateStringLength(masm);
470
}
471

    
472

    
473
static void Generate_LoadIC_FunctionPrototype(MacroAssembler* masm) {
474
  LoadIC::GenerateFunctionPrototype(masm);
475
}
476

    
477

    
478
static void Generate_LoadIC_Initialize(MacroAssembler* masm) {
479
  LoadIC::GenerateInitialize(masm);
480
}
481

    
482

    
483
static void Generate_LoadIC_PreMonomorphic(MacroAssembler* masm) {
484
  LoadIC::GeneratePreMonomorphic(masm);
485
}
486

    
487

    
488
static void Generate_LoadIC_Miss(MacroAssembler* masm) {
489
  LoadIC::GenerateMiss(masm);
490
}
491

    
492

    
493
static void Generate_LoadIC_Megamorphic(MacroAssembler* masm) {
494
  LoadIC::GenerateMegamorphic(masm);
495
}
496

    
497

    
498
static void Generate_LoadIC_Normal(MacroAssembler* masm) {
499
  LoadIC::GenerateNormal(masm);
500
}
501

    
502

    
503
static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
504
  KeyedLoadIC::GenerateInitialize(masm);
505
}
506

    
507

    
508
static void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
509
  KeyedLoadIC::GenerateMiss(masm);
510
}
511

    
512

    
513
static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
514
  KeyedLoadIC::GenerateGeneric(masm);
515
}
516

    
517

    
518
static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
519
  KeyedLoadIC::GeneratePreMonomorphic(masm);
520
}
521

    
522

    
523
static void Generate_StoreIC_Initialize(MacroAssembler* masm) {
524
  StoreIC::GenerateInitialize(masm);
525
}
526

    
527

    
528
static void Generate_StoreIC_Miss(MacroAssembler* masm) {
529
  StoreIC::GenerateMiss(masm);
530
}
531

    
532

    
533
static void Generate_StoreIC_ExtendStorage(MacroAssembler* masm) {
534
  StoreIC::GenerateExtendStorage(masm);
535
}
536

    
537
static void Generate_StoreIC_Megamorphic(MacroAssembler* masm) {
538
  StoreIC::GenerateMegamorphic(masm);
539
}
540

    
541

    
542
static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
543
  KeyedStoreIC::GenerateGeneric(masm);
544
}
545

    
546

    
547
static void Generate_KeyedStoreIC_ExtendStorage(MacroAssembler* masm) {
548
  KeyedStoreIC::GenerateExtendStorage(masm);
549
}
550

    
551

    
552
static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
553
  KeyedStoreIC::GenerateMiss(masm);
554
}
555

    
556

    
557
static void Generate_KeyedStoreIC_Initialize(MacroAssembler* masm) {
558
  KeyedStoreIC::GenerateInitialize(masm);
559
}
560

    
561

    
562
static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
563
  Debug::GenerateLoadICDebugBreak(masm);
564
}
565

    
566

    
567
static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
568
  Debug::GenerateStoreICDebugBreak(masm);
569
}
570

    
571

    
572
static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
573
  Debug::GenerateKeyedLoadICDebugBreak(masm);
574
}
575

    
576

    
577
static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
578
  Debug::GenerateKeyedStoreICDebugBreak(masm);
579
}
580

    
581

    
582
static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
583
  Debug::GenerateConstructCallDebugBreak(masm);
584
}
585

    
586

    
587
static void Generate_Return_DebugBreak(MacroAssembler* masm) {
588
  Debug::GenerateReturnDebugBreak(masm);
589
}
590

    
591

    
592
static void Generate_Return_DebugBreakEntry(MacroAssembler* masm) {
593
  Debug::GenerateReturnDebugBreakEntry(masm);
594
}
595

    
596

    
597
static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
598
  Debug::GenerateStubNoRegistersDebugBreak(masm);
599
}
600

    
601

    
602
Object* Builtins::builtins_[builtin_count] = { NULL, };
603
const char* Builtins::names_[builtin_count] = { NULL, };
604

    
605
#define DEF_ENUM_C(name) FUNCTION_ADDR(Builtin_##name),
606
  Address Builtins::c_functions_[cfunction_count] = {
607
    BUILTIN_LIST_C(DEF_ENUM_C)
608
  };
609
#undef DEF_ENUM_C
610

    
611
#define DEF_JS_NAME(name, ignore) #name,
612
#define DEF_JS_ARGC(ignore, argc) argc,
613
const char* Builtins::javascript_names_[id_count] = {
614
  BUILTINS_LIST_JS(DEF_JS_NAME)
615
};
616

    
617
int Builtins::javascript_argc_[id_count] = {
618
  BUILTINS_LIST_JS(DEF_JS_ARGC)
619
};
620
#undef DEF_JS_NAME
621
#undef DEF_JS_ARGC
622

    
623
static bool is_initialized = false;
624
void Builtins::Setup(bool create_heap_objects) {
625
  ASSERT(!is_initialized);
626

    
627
  // Create a scope for the handles in the builtins.
628
  HandleScope scope;
629

    
630
  struct BuiltinDesc {
631
    byte* generator;
632
    byte* c_code;
633
    const char* s_name;  // name is only used for generating log information.
634
    int name;
635
    Code::Flags flags;
636
  };
637

    
638
#define DEF_FUNCTION_PTR_C(name)         \
639
    { FUNCTION_ADDR(Generate_Adaptor),   \
640
      FUNCTION_ADDR(Builtin_##name),     \
641
      #name,                             \
642
      c_##name,                          \
643
      Code::ComputeFlags(Code::BUILTIN)  \
644
    },
645

    
646
#define DEF_FUNCTION_PTR_A(name, kind, state) \
647
    { FUNCTION_ADDR(Generate_##name),         \
648
      NULL,                                   \
649
      #name,                                  \
650
      name,                                   \
651
      Code::ComputeFlags(Code::kind, state)   \
652
    },
653

    
654
  // Define array of pointers to generators and C builtin functions.
655
  static BuiltinDesc functions[] = {
656
      BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
657
      BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
658
      BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
659
      // Terminator:
660
      { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0) }
661
  };
662

    
663
#undef DEF_FUNCTION_PTR_C
664
#undef DEF_FUNCTION_PTR_A
665

    
666
  // For now we generate builtin adaptor code into a stack-allocated
667
  // buffer, before copying it into individual code objects.
668
  byte buffer[4*KB];
669

    
670
  // Traverse the list of builtins and generate an adaptor in a
671
  // separate code object for each one.
672
  for (int i = 0; i < builtin_count; i++) {
673
    if (create_heap_objects) {
674
      MacroAssembler masm(buffer, sizeof buffer);
675
      // Generate the code/adaptor.
676
      typedef void (*Generator)(MacroAssembler*, int);
677
      Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
678
      // We pass all arguments to the generator, but it may not use all of
679
      // them.  This works because the first arguments are on top of the
680
      // stack.
681
      g(&masm, functions[i].name);
682
      // Move the code into the object heap.
683
      CodeDesc desc;
684
      masm.GetCode(&desc);
685
      Code::Flags flags =  functions[i].flags;
686
      Object* code;
687
      {
688
        // During startup it's OK to always allocate and defer GC to later.
689
        // This simplifies things because we don't need to retry.
690
        AlwaysAllocateScope __scope__;
691
        code = Heap::CreateCode(desc, NULL, flags, masm.CodeObject());
692
        if (code->IsFailure()) {
693
          v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
694
        }
695
      }
696
      // Add any unresolved jumps or calls to the fixup list in the
697
      // bootstrapper.
698
      Bootstrapper::AddFixup(Code::cast(code), &masm);
699
      // Log the event and add the code to the builtins array.
700
      LOG(CodeCreateEvent("Builtin", Code::cast(code), functions[i].s_name));
701
      builtins_[i] = code;
702
#ifdef ENABLE_DISASSEMBLER
703
      if (FLAG_print_builtin_code) {
704
        PrintF("Builtin: %s\n", functions[i].s_name);
705
        Code::cast(code)->Disassemble(functions[i].s_name);
706
        PrintF("\n");
707
      }
708
#endif
709
    } else {
710
      // Deserializing. The values will be filled in during IterateBuiltins.
711
      builtins_[i] = NULL;
712
    }
713
    names_[i] = functions[i].s_name;
714
  }
715

    
716
  // Mark as initialized.
717
  is_initialized = true;
718
}
719

    
720

    
721
void Builtins::TearDown() {
722
  is_initialized = false;
723
}
724

    
725

    
726
void Builtins::IterateBuiltins(ObjectVisitor* v) {
727
  v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
728
}
729

    
730

    
731
const char* Builtins::Lookup(byte* pc) {
732
  if (is_initialized) {  // may be called during initialization (disassembler!)
733
    for (int i = 0; i < builtin_count; i++) {
734
      Code* entry = Code::cast(builtins_[i]);
735
      if (entry->contains(pc)) {
736
        return names_[i];
737
      }
738
    }
739
  }
740
  return NULL;
741
}
742

    
743

    
744
} }  // namespace v8::internal