builtins.cc 8.31 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/builtins/builtins.h"
6 7 8 9 10 11 12
#include "src/code-events.h"
#include "src/code-stub-assembler.h"
#include "src/ic/ic-state.h"
#include "src/interface-descriptors.h"
#include "src/isolate.h"
#include "src/macro-assembler.h"
#include "src/objects.h"
13

14 15
namespace v8 {
namespace internal {
16

17 18 19 20
// Forward declarations for C++ builtins.
#define FORWARD_DECLARE(Name) \
  Object* Builtin_##Name(int argc, Object** args, Isolate* isolate);
BUILTIN_LIST_C(FORWARD_DECLARE)
21

22 23 24 25
Builtins::Builtins() : initialized_(false) {
  memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
}

26
Builtins::~Builtins() {}
27

28 29 30 31 32 33 34 35 36 37 38 39
namespace {
void PostBuildProfileAndTracing(Isolate* isolate, Code* code,
                                const char* name) {
  PROFILE(isolate, CodeCreateEvent(CodeEventListener::BUILTIN_TAG,
                                   AbstractCode::cast(code), name));
#ifdef ENABLE_DISASSEMBLER
  if (FLAG_print_builtin_code) {
    CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
    OFStream os(trace_scope.file());
    os << "Builtin: " << name << "\n";
    code->Disassemble(name, os);
    os << "\n";
40
  }
41 42
#endif
}
43

44 45
typedef void (*MacroAssemblerGenerator)(MacroAssembler*);
typedef void (*CodeAssemblerGenerator)(CodeStubAssembler*);
46

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
Code* BuildWithMacroAssembler(Isolate* isolate,
                              MacroAssemblerGenerator generator,
                              Code::Flags flags, const char* s_name) {
  HandleScope scope(isolate);
  const size_t buffer_size = 32 * KB;
  byte buffer[buffer_size];  // NOLINT(runtime/arrays)
  MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
  DCHECK(!masm.has_frame());
  generator(&masm);
  CodeDesc desc;
  masm.GetCode(&desc);
  Handle<Code> code =
      isolate->factory()->NewCode(desc, flags, masm.CodeObject());
  PostBuildProfileAndTracing(isolate, *code, s_name);
  return *code;
}
63

64 65 66 67
Code* BuildAdaptor(Isolate* isolate, Address builtin_address,
                   Builtins::ExitFrameType exit_frame_type, Code::Flags flags,
                   const char* name) {
  HandleScope scope(isolate);
68
  const size_t buffer_size = 32 * KB;
69 70
  byte buffer[buffer_size];  // NOLINT(runtime/arrays)
  MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
71
  DCHECK(!masm.has_frame());
72
  Builtins::Generate_Adaptor(&masm, builtin_address, exit_frame_type);
73 74
  CodeDesc desc;
  masm.GetCode(&desc);
75 76 77 78
  Handle<Code> code =
      isolate->factory()->NewCode(desc, flags, masm.CodeObject());
  PostBuildProfileAndTracing(isolate, *code, name);
  return *code;
79 80
}

81
// Builder for builtins implemented in TurboFan with JS linkage.
82 83 84 85
Code* BuildWithCodeStubAssemblerJS(Isolate* isolate,
                                   CodeAssemblerGenerator generator, int argc,
                                   Code::Flags flags, const char* name) {
  HandleScope scope(isolate);
86
  Zone zone(isolate->allocator());
87 88 89 90 91
  CodeStubAssembler assembler(isolate, &zone, argc, flags, name);
  generator(&assembler);
  Handle<Code> code = assembler.GenerateCode();
  PostBuildProfileAndTracing(isolate, *code, name);
  return *code;
92 93
}

94
// Builder for builtins implemented in TurboFan with CallStub linkage.
95 96 97 98 99
Code* BuildWithCodeStubAssemblerCS(Isolate* isolate,
                                   CodeAssemblerGenerator generator,
                                   CallDescriptors::Key interface_descriptor,
                                   Code::Flags flags, const char* name) {
  HandleScope scope(isolate);
100 101 102
  Zone zone(isolate->allocator());
  // The interface descriptor with given key must be initialized at this point
  // and this construction just queries the details from the descriptors table.
103
  CallInterfaceDescriptor descriptor(isolate, interface_descriptor);
104
  // Ensure descriptor is already initialized.
105
  DCHECK_LE(0, descriptor.GetRegisterParameterCount());
106 107 108 109 110
  CodeStubAssembler assembler(isolate, &zone, descriptor, flags, name);
  generator(&assembler);
  Handle<Code> code = assembler.GenerateCode();
  PostBuildProfileAndTracing(isolate, *code, name);
  return *code;
111
}
112
}  // anonymous namespace
113

114
void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) {
115
  DCHECK(!initialized_);
116 117

  // Create a scope for the handles in the builtins.
118
  HandleScope scope(isolate);
119

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
  if (create_heap_objects) {
    int index = 0;
    const Code::Flags kBuiltinFlags = Code::ComputeFlags(Code::BUILTIN);
    Code* code;
#define BUILD_CPP(Name)                                                     \
  code = BuildAdaptor(isolate, FUNCTION_ADDR(Builtin_##Name), BUILTIN_EXIT, \
                      kBuiltinFlags, #Name);                                \
  builtins_[index++] = code;
#define BUILD_API(Name)                                             \
  code = BuildAdaptor(isolate, FUNCTION_ADDR(Builtin_##Name), EXIT, \
                      kBuiltinFlags, #Name);                        \
  builtins_[index++] = code;
#define BUILD_TFJ(Name, Argc)                                          \
  code = BuildWithCodeStubAssemblerJS(isolate, &Generate_##Name, Argc, \
                                      kBuiltinFlags, #Name);           \
  builtins_[index++] = code;
#define BUILD_TFS(Name, Kind, Extra, InterfaceDescriptor)              \
  { InterfaceDescriptor##Descriptor descriptor(isolate); }             \
  code = BuildWithCodeStubAssemblerCS(                                 \
      isolate, &Generate_##Name, CallDescriptors::InterfaceDescriptor, \
      Code::ComputeFlags(Code::Kind, Extra), #Name);                   \
  builtins_[index++] = code;
#define BUILD_ASM(Name)                                                        \
  code =                                                                       \
      BuildWithMacroAssembler(isolate, Generate_##Name, kBuiltinFlags, #Name); \
  builtins_[index++] = code;
#define BUILD_ASH(Name, Kind, Extra)                                           \
  code = BuildWithMacroAssembler(                                              \
      isolate, Generate_##Name, Code::ComputeFlags(Code::Kind, Extra), #Name); \
  builtins_[index++] = code;

    BUILTIN_LIST(BUILD_CPP, BUILD_API, BUILD_TFJ, BUILD_TFS, BUILD_ASM,
                 BUILD_ASH, BUILD_ASM);

#undef BUILD_CPP
#undef BUILD_API
#undef BUILD_TFJ
#undef BUILD_TFS
#undef BUILD_ASM
#undef BUILD_ASH
    CHECK_EQ(builtin_count, index);
    for (int i = 0; i < builtin_count; i++) {
      Code::cast(builtins_[i])->set_builtin_index(i);
163 164 165 166
    }
  }

  // Mark as initialized.
167
  initialized_ = true;
168 169
}

170
void Builtins::TearDown() { initialized_ = false; }
171 172 173 174 175 176

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

const char* Builtins::Lookup(byte* pc) {
177 178
  // may be called during initialization (disassembler!)
  if (initialized_) {
179 180
    for (int i = 0; i < builtin_count; i++) {
      Code* entry = Code::cast(builtins_[i]);
181
      if (entry->contains(pc)) return name(i);
182 183 184 185 186
    }
  }
  return NULL;
}

187 188 189 190 191 192 193 194 195 196 197 198 199 200
const char* Builtins::name(int index) {
  switch (index) {
#define CASE(Name, ...) \
  case k##Name:         \
    return #Name;
    BUILTIN_LIST_ALL(CASE)
#undef CASE
    default:
      UNREACHABLE();
      break;
  }
  return "";
}

201 202 203
#define DEFINE_BUILTIN_ACCESSOR(Name, ...)                                    \
  Handle<Code> Builtins::Name() {                                             \
    Code** code_address = reinterpret_cast<Code**>(builtin_address(k##Name)); \
204 205
    return Handle<Code>(code_address);                                        \
  }
206 207
BUILTIN_LIST_ALL(DEFINE_BUILTIN_ACCESSOR)
#undef DEFINE_BUILTIN_ACCESSOR
208

209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
// static
bool Builtins::AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target,
                                    Handle<JSObject> target_global_proxy) {
  if (FLAG_allow_unsafe_function_constructor) return true;
  HandleScopeImplementer* impl = isolate->handle_scope_implementer();
  Handle<Context> responsible_context = impl->LastEnteredContext();
  if (responsible_context.is_null()) {
    responsible_context = impl->MicrotaskContext();
    // TODO(jochen): Remove this.
    if (responsible_context.is_null()) {
      return true;
    }
  }
  if (*responsible_context == target->context()) return true;
  return isolate->MayAccess(responsible_context, target_global_proxy);
}

226 227
}  // namespace internal
}  // namespace v8