1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/builtins/builtins.h" 6 #include "src/api.h" 7 #include "src/code-events.h" 8 #include "src/compiler/code-assembler.h" 9 #include "src/ic/ic-state.h" 10 #include "src/interface-descriptors.h" 11 #include "src/isolate.h" 12 #include "src/macro-assembler.h" 13 #include "src/objects-inl.h" 14 15 namespace v8 { 16 namespace internal { 17 18 // Forward declarations for C++ builtins. 19 #define FORWARD_DECLARE(Name) \ 20 Object* Builtin_##Name(int argc, Object** args, Isolate* isolate); 21 BUILTIN_LIST_C(FORWARD_DECLARE) 22 23 Builtins::Builtins() : initialized_(false) { 24 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count); 25 } 26 27 Builtins::~Builtins() {} 28 29 namespace { 30 void PostBuildProfileAndTracing(Isolate* isolate, Code* code, 31 const char* name) { 32 PROFILE(isolate, CodeCreateEvent(CodeEventListener::BUILTIN_TAG, 33 AbstractCode::cast(code), name)); 34 #ifdef ENABLE_DISASSEMBLER 35 if (FLAG_print_builtin_code) { 36 CodeTracer::Scope trace_scope(isolate->GetCodeTracer()); 37 OFStream os(trace_scope.file()); 38 os << "Builtin: " << name << "\n"; 39 code->Disassemble(name, os); 40 os << "\n"; 41 } 42 #endif 43 } 44 45 typedef void (*MacroAssemblerGenerator)(MacroAssembler*); 46 typedef void (*CodeAssemblerGenerator)(compiler::CodeAssemblerState*); 47 48 Code* BuildWithMacroAssembler(Isolate* isolate, 49 MacroAssemblerGenerator generator, 50 Code::Flags flags, const char* s_name) { 51 HandleScope scope(isolate); 52 const size_t buffer_size = 32 * KB; 53 byte buffer[buffer_size]; // NOLINT(runtime/arrays) 54 MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes); 55 DCHECK(!masm.has_frame()); 56 generator(&masm); 57 CodeDesc desc; 58 masm.GetCode(&desc); 59 Handle<Code> code = 60 isolate->factory()->NewCode(desc, flags, masm.CodeObject()); 61 PostBuildProfileAndTracing(isolate, *code, s_name); 62 return *code; 63 } 64 65 Code* BuildAdaptor(Isolate* isolate, Address builtin_address, 66 Builtins::ExitFrameType exit_frame_type, Code::Flags flags, 67 const char* name) { 68 HandleScope scope(isolate); 69 const size_t buffer_size = 32 * KB; 70 byte buffer[buffer_size]; // NOLINT(runtime/arrays) 71 MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes); 72 DCHECK(!masm.has_frame()); 73 Builtins::Generate_Adaptor(&masm, builtin_address, exit_frame_type); 74 CodeDesc desc; 75 masm.GetCode(&desc); 76 Handle<Code> code = 77 isolate->factory()->NewCode(desc, flags, masm.CodeObject()); 78 PostBuildProfileAndTracing(isolate, *code, name); 79 return *code; 80 } 81 82 // Builder for builtins implemented in TurboFan with JS linkage. 83 Code* BuildWithCodeStubAssemblerJS(Isolate* isolate, 84 CodeAssemblerGenerator generator, int argc, 85 Code::Flags flags, const char* name) { 86 HandleScope scope(isolate); 87 Zone zone(isolate->allocator(), ZONE_NAME); 88 const int argc_with_recv = 89 (argc == SharedFunctionInfo::kDontAdaptArgumentsSentinel) ? 0 : argc + 1; 90 compiler::CodeAssemblerState state(isolate, &zone, argc_with_recv, flags, 91 name); 92 generator(&state); 93 Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state); 94 PostBuildProfileAndTracing(isolate, *code, name); 95 return *code; 96 } 97 98 // Builder for builtins implemented in TurboFan with CallStub linkage. 99 Code* BuildWithCodeStubAssemblerCS(Isolate* isolate, 100 CodeAssemblerGenerator generator, 101 CallDescriptors::Key interface_descriptor, 102 Code::Flags flags, const char* name, 103 int result_size) { 104 HandleScope scope(isolate); 105 Zone zone(isolate->allocator(), ZONE_NAME); 106 // The interface descriptor with given key must be initialized at this point 107 // and this construction just queries the details from the descriptors table. 108 CallInterfaceDescriptor descriptor(isolate, interface_descriptor); 109 // Ensure descriptor is already initialized. 110 DCHECK_LE(0, descriptor.GetRegisterParameterCount()); 111 compiler::CodeAssemblerState state(isolate, &zone, descriptor, flags, name, 112 result_size); 113 generator(&state); 114 Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state); 115 PostBuildProfileAndTracing(isolate, *code, name); 116 return *code; 117 } 118 } // anonymous namespace 119 120 void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) { 121 DCHECK(!initialized_); 122 123 // Create a scope for the handles in the builtins. 124 HandleScope scope(isolate); 125 126 if (create_heap_objects) { 127 int index = 0; 128 const Code::Flags kBuiltinFlags = Code::ComputeFlags(Code::BUILTIN); 129 Code* code; 130 #define BUILD_CPP(Name) \ 131 code = BuildAdaptor(isolate, FUNCTION_ADDR(Builtin_##Name), BUILTIN_EXIT, \ 132 kBuiltinFlags, #Name); \ 133 builtins_[index++] = code; 134 #define BUILD_API(Name) \ 135 code = BuildAdaptor(isolate, FUNCTION_ADDR(Builtin_##Name), EXIT, \ 136 kBuiltinFlags, #Name); \ 137 builtins_[index++] = code; 138 #define BUILD_TFJ(Name, Argc) \ 139 code = BuildWithCodeStubAssemblerJS(isolate, &Generate_##Name, Argc, \ 140 kBuiltinFlags, #Name); \ 141 builtins_[index++] = code; 142 #define BUILD_TFS(Name, Kind, Extra, InterfaceDescriptor, result_size) \ 143 { InterfaceDescriptor##Descriptor descriptor(isolate); } \ 144 code = BuildWithCodeStubAssemblerCS( \ 145 isolate, &Generate_##Name, CallDescriptors::InterfaceDescriptor, \ 146 Code::ComputeFlags(Code::Kind, Extra), #Name, result_size); \ 147 builtins_[index++] = code; 148 #define BUILD_ASM(Name) \ 149 code = \ 150 BuildWithMacroAssembler(isolate, Generate_##Name, kBuiltinFlags, #Name); \ 151 builtins_[index++] = code; 152 #define BUILD_ASH(Name, Kind, Extra) \ 153 code = BuildWithMacroAssembler( \ 154 isolate, Generate_##Name, Code::ComputeFlags(Code::Kind, Extra), #Name); \ 155 builtins_[index++] = code; 156 157 BUILTIN_LIST(BUILD_CPP, BUILD_API, BUILD_TFJ, BUILD_TFS, BUILD_ASM, 158 BUILD_ASH, BUILD_ASM); 159 160 #undef BUILD_CPP 161 #undef BUILD_API 162 #undef BUILD_TFJ 163 #undef BUILD_TFS 164 #undef BUILD_ASM 165 #undef BUILD_ASH 166 CHECK_EQ(builtin_count, index); 167 for (int i = 0; i < builtin_count; i++) { 168 Code::cast(builtins_[i])->set_builtin_index(i); 169 } 170 } 171 172 // Mark as initialized. 173 initialized_ = true; 174 } 175 176 void Builtins::TearDown() { initialized_ = false; } 177 178 void Builtins::IterateBuiltins(ObjectVisitor* v) { 179 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count); 180 } 181 182 const char* Builtins::Lookup(byte* pc) { 183 // may be called during initialization (disassembler!) 184 if (initialized_) { 185 for (int i = 0; i < builtin_count; i++) { 186 Code* entry = Code::cast(builtins_[i]); 187 if (entry->contains(pc)) return name(i); 188 } 189 } 190 return NULL; 191 } 192 193 // static 194 const char* Builtins::name(int index) { 195 switch (index) { 196 #define CASE(Name, ...) \ 197 case k##Name: \ 198 return #Name; 199 BUILTIN_LIST_ALL(CASE) 200 #undef CASE 201 default: 202 UNREACHABLE(); 203 break; 204 } 205 return ""; 206 } 207 208 // static 209 Address Builtins::CppEntryOf(int index) { 210 DCHECK(0 <= index && index < builtin_count); 211 switch (index) { 212 #define CASE(Name, ...) \ 213 case k##Name: \ 214 return FUNCTION_ADDR(Builtin_##Name); 215 BUILTIN_LIST_C(CASE) 216 #undef CASE 217 default: 218 return nullptr; 219 } 220 UNREACHABLE(); 221 } 222 223 // static 224 bool Builtins::IsCpp(int index) { 225 DCHECK(0 <= index && index < builtin_count); 226 switch (index) { 227 #define CASE(Name, ...) \ 228 case k##Name: \ 229 return true; 230 #define BUILTIN_LIST_CPP(V) \ 231 BUILTIN_LIST(V, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, \ 232 IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN) 233 BUILTIN_LIST_CPP(CASE) 234 #undef BUILTIN_LIST_CPP 235 #undef CASE 236 default: 237 return false; 238 } 239 UNREACHABLE(); 240 } 241 242 // static 243 bool Builtins::IsApi(int index) { 244 DCHECK(0 <= index && index < builtin_count); 245 switch (index) { 246 #define CASE(Name, ...) \ 247 case k##Name: \ 248 return true; 249 #define BUILTIN_LIST_API(V) \ 250 BUILTIN_LIST(IGNORE_BUILTIN, V, IGNORE_BUILTIN, IGNORE_BUILTIN, \ 251 IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN) 252 BUILTIN_LIST_API(CASE); 253 #undef BUILTIN_LIST_API 254 #undef CASE 255 default: 256 return false; 257 } 258 UNREACHABLE(); 259 } 260 261 // static 262 bool Builtins::HasCppImplementation(int index) { 263 DCHECK(0 <= index && index < builtin_count); 264 switch (index) { 265 #define CASE(Name, ...) \ 266 case k##Name: \ 267 return true; 268 BUILTIN_LIST_C(CASE) 269 #undef CASE 270 default: 271 return false; 272 } 273 UNREACHABLE(); 274 } 275 276 #define DEFINE_BUILTIN_ACCESSOR(Name, ...) \ 277 Handle<Code> Builtins::Name() { \ 278 Code** code_address = reinterpret_cast<Code**>(builtin_address(k##Name)); \ 279 return Handle<Code>(code_address); \ 280 } 281 BUILTIN_LIST_ALL(DEFINE_BUILTIN_ACCESSOR) 282 #undef DEFINE_BUILTIN_ACCESSOR 283 284 // static 285 bool Builtins::AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target, 286 Handle<JSObject> target_global_proxy) { 287 if (FLAG_allow_unsafe_function_constructor) return true; 288 HandleScopeImplementer* impl = isolate->handle_scope_implementer(); 289 Handle<Context> responsible_context = 290 impl->MicrotaskContextIsLastEnteredContext() ? impl->MicrotaskContext() 291 : impl->LastEnteredContext(); 292 // TODO(jochen): Remove this. 293 if (responsible_context.is_null()) { 294 return true; 295 } 296 if (*responsible_context == target->context()) return true; 297 return isolate->MayAccess(responsible_context, target_global_proxy); 298 } 299 300 } // namespace internal 301 } // namespace v8 302