1 // Copyright 2014 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/code-factory.h" 6 7 #include "src/bootstrapper.h" 8 #include "src/builtins/builtins-descriptors.h" 9 #include "src/ic/ic.h" 10 #include "src/objects-inl.h" 11 12 namespace v8 { 13 namespace internal { 14 15 namespace { 16 17 // TODO(ishell): make it (const Stub& stub) once CodeStub::GetCode() is const. 18 template <typename Stub> 19 Callable make_callable(Stub& stub) { 20 typedef typename Stub::Descriptor Descriptor; 21 return Callable(stub.GetCode(), Descriptor{}); 22 } 23 24 } // namespace 25 26 // static 27 Handle<Code> CodeFactory::RuntimeCEntry(Isolate* isolate, int result_size) { 28 return CodeFactory::CEntry(isolate, result_size); 29 } 30 31 #define CENTRY_CODE(RS, SD, AM, BE) \ 32 BUILTIN_CODE(isolate, CEntry_##RS##_##SD##_##AM##_##BE) 33 34 // static 35 Handle<Code> CodeFactory::CEntry(Isolate* isolate, int result_size, 36 SaveFPRegsMode save_doubles, 37 ArgvMode argv_mode, bool builtin_exit_frame) { 38 // Aliases for readability below. 39 const int rs = result_size; 40 const SaveFPRegsMode sd = save_doubles; 41 const ArgvMode am = argv_mode; 42 const bool be = builtin_exit_frame; 43 44 if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvOnStack && !be) { 45 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit); 46 } else if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvOnStack && be) { 47 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, BuiltinExit); 48 } else if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvInRegister && !be) { 49 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit); 50 } else if (rs == 1 && sd == kSaveFPRegs && am == kArgvOnStack && !be) { 51 return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, NoBuiltinExit); 52 } else if (rs == 1 && sd == kSaveFPRegs && am == kArgvOnStack && be) { 53 return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, BuiltinExit); 54 } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvOnStack && !be) { 55 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit); 56 } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvOnStack && be) { 57 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, BuiltinExit); 58 } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvInRegister && !be) { 59 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit); 60 } else if (rs == 2 && sd == kSaveFPRegs && am == kArgvOnStack && !be) { 61 return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, NoBuiltinExit); 62 } else if (rs == 2 && sd == kSaveFPRegs && am == kArgvOnStack && be) { 63 return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, BuiltinExit); 64 } 65 66 UNREACHABLE(); 67 } 68 69 #undef CENTRY_CODE 70 71 // static 72 Callable CodeFactory::ApiGetter(Isolate* isolate) { 73 return Callable(BUILTIN_CODE(isolate, CallApiGetter), ApiGetterDescriptor{}); 74 } 75 76 // static 77 Callable CodeFactory::CallApiCallback(Isolate* isolate, int argc) { 78 switch (argc) { 79 case 0: 80 return Callable(BUILTIN_CODE(isolate, CallApiCallback_Argc0), 81 ApiCallbackDescriptor{}); 82 case 1: 83 return Callable(BUILTIN_CODE(isolate, CallApiCallback_Argc1), 84 ApiCallbackDescriptor{}); 85 default: { 86 CallApiCallbackStub stub(isolate, argc); 87 return make_callable(stub); 88 } 89 } 90 UNREACHABLE(); 91 } 92 93 // static 94 Callable CodeFactory::LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode) { 95 return Callable( 96 typeof_mode == NOT_INSIDE_TYPEOF 97 ? BUILTIN_CODE(isolate, LoadGlobalICTrampoline) 98 : BUILTIN_CODE(isolate, LoadGlobalICInsideTypeofTrampoline), 99 LoadGlobalDescriptor{}); 100 } 101 102 // static 103 Callable CodeFactory::LoadGlobalICInOptimizedCode(Isolate* isolate, 104 TypeofMode typeof_mode) { 105 return Callable(typeof_mode == NOT_INSIDE_TYPEOF 106 ? BUILTIN_CODE(isolate, LoadGlobalIC) 107 : BUILTIN_CODE(isolate, LoadGlobalICInsideTypeof), 108 LoadGlobalWithVectorDescriptor{}); 109 } 110 111 Callable CodeFactory::StoreOwnIC(Isolate* isolate) { 112 // TODO(ishell): Currently we use StoreOwnIC only for storing properties that 113 // already exist in the boilerplate therefore we can use StoreIC. 114 return Callable(BUILTIN_CODE(isolate, StoreICTrampoline), StoreDescriptor{}); 115 } 116 117 Callable CodeFactory::StoreOwnICInOptimizedCode(Isolate* isolate) { 118 // TODO(ishell): Currently we use StoreOwnIC only for storing properties that 119 // already exist in the boilerplate therefore we can use StoreIC. 120 return Callable(BUILTIN_CODE(isolate, StoreIC), StoreWithVectorDescriptor{}); 121 } 122 123 // static 124 Callable CodeFactory::BinaryOperation(Isolate* isolate, Operation op) { 125 switch (op) { 126 case Operation::kShiftRight: 127 return Builtins::CallableFor(isolate, Builtins::kShiftRight); 128 case Operation::kShiftLeft: 129 return Builtins::CallableFor(isolate, Builtins::kShiftLeft); 130 case Operation::kShiftRightLogical: 131 return Builtins::CallableFor(isolate, Builtins::kShiftRightLogical); 132 case Operation::kAdd: 133 return Builtins::CallableFor(isolate, Builtins::kAdd); 134 case Operation::kSubtract: 135 return Builtins::CallableFor(isolate, Builtins::kSubtract); 136 case Operation::kMultiply: 137 return Builtins::CallableFor(isolate, Builtins::kMultiply); 138 case Operation::kDivide: 139 return Builtins::CallableFor(isolate, Builtins::kDivide); 140 case Operation::kModulus: 141 return Builtins::CallableFor(isolate, Builtins::kModulus); 142 case Operation::kBitwiseOr: 143 return Builtins::CallableFor(isolate, Builtins::kBitwiseOr); 144 case Operation::kBitwiseAnd: 145 return Builtins::CallableFor(isolate, Builtins::kBitwiseAnd); 146 case Operation::kBitwiseXor: 147 return Builtins::CallableFor(isolate, Builtins::kBitwiseXor); 148 default: 149 break; 150 } 151 UNREACHABLE(); 152 } 153 154 // static 155 Callable CodeFactory::NonPrimitiveToPrimitive(Isolate* isolate, 156 ToPrimitiveHint hint) { 157 return Callable(isolate->builtins()->NonPrimitiveToPrimitive(hint), 158 TypeConversionDescriptor{}); 159 } 160 161 // static 162 Callable CodeFactory::OrdinaryToPrimitive(Isolate* isolate, 163 OrdinaryToPrimitiveHint hint) { 164 return Callable(isolate->builtins()->OrdinaryToPrimitive(hint), 165 TypeConversionDescriptor{}); 166 } 167 168 // static 169 Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags, 170 PretenureFlag pretenure_flag) { 171 if (pretenure_flag == NOT_TENURED) { 172 switch (flags) { 173 case STRING_ADD_CHECK_NONE: 174 return Builtins::CallableFor(isolate, 175 Builtins::kStringAdd_CheckNone_NotTenured); 176 case STRING_ADD_CONVERT_LEFT: 177 return Builtins::CallableFor( 178 isolate, Builtins::kStringAdd_ConvertLeft_NotTenured); 179 case STRING_ADD_CONVERT_RIGHT: 180 return Builtins::CallableFor( 181 isolate, Builtins::kStringAdd_ConvertRight_NotTenured); 182 } 183 } else { 184 CHECK_EQ(TENURED, pretenure_flag); 185 CHECK_EQ(STRING_ADD_CHECK_NONE, flags); 186 return Builtins::CallableFor(isolate, 187 Builtins::kStringAdd_CheckNone_Tenured); 188 } 189 190 UNREACHABLE(); 191 } 192 193 // static 194 Callable CodeFactory::ResumeGenerator(Isolate* isolate) { 195 return Callable(BUILTIN_CODE(isolate, ResumeGeneratorTrampoline), 196 ResumeGeneratorDescriptor{}); 197 } 198 199 // static 200 Callable CodeFactory::FrameDropperTrampoline(Isolate* isolate) { 201 return Callable(BUILTIN_CODE(isolate, FrameDropperTrampoline), 202 FrameDropperTrampolineDescriptor{}); 203 } 204 205 // static 206 Callable CodeFactory::HandleDebuggerStatement(Isolate* isolate) { 207 return Callable(BUILTIN_CODE(isolate, HandleDebuggerStatement), 208 ContextOnlyDescriptor{}); 209 } 210 211 // static 212 Callable CodeFactory::FastNewFunctionContext(Isolate* isolate, 213 ScopeType scope_type) { 214 return Callable(isolate->builtins()->NewFunctionContext(scope_type), 215 FastNewFunctionContextDescriptor{}); 216 } 217 218 // static 219 Callable CodeFactory::ArgumentAdaptor(Isolate* isolate) { 220 return Callable(BUILTIN_CODE(isolate, ArgumentsAdaptorTrampoline), 221 ArgumentAdaptorDescriptor{}); 222 } 223 224 // static 225 Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode) { 226 return Callable(isolate->builtins()->Call(mode), CallTrampolineDescriptor{}); 227 } 228 229 // static 230 Callable CodeFactory::CallWithArrayLike(Isolate* isolate) { 231 return Callable(BUILTIN_CODE(isolate, CallWithArrayLike), 232 CallWithArrayLikeDescriptor{}); 233 } 234 235 // static 236 Callable CodeFactory::CallWithSpread(Isolate* isolate) { 237 return Callable(BUILTIN_CODE(isolate, CallWithSpread), 238 CallWithSpreadDescriptor{}); 239 } 240 241 // static 242 Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) { 243 return Callable(isolate->builtins()->CallFunction(mode), 244 CallTrampolineDescriptor{}); 245 } 246 247 // static 248 Callable CodeFactory::CallVarargs(Isolate* isolate) { 249 return Callable(BUILTIN_CODE(isolate, CallVarargs), CallVarargsDescriptor{}); 250 } 251 252 // static 253 Callable CodeFactory::CallForwardVarargs(Isolate* isolate) { 254 return Callable(BUILTIN_CODE(isolate, CallForwardVarargs), 255 CallForwardVarargsDescriptor{}); 256 } 257 258 // static 259 Callable CodeFactory::CallFunctionForwardVarargs(Isolate* isolate) { 260 return Callable(BUILTIN_CODE(isolate, CallFunctionForwardVarargs), 261 CallForwardVarargsDescriptor{}); 262 } 263 264 // static 265 Callable CodeFactory::Construct(Isolate* isolate) { 266 return Callable(BUILTIN_CODE(isolate, Construct), JSTrampolineDescriptor{}); 267 } 268 269 // static 270 Callable CodeFactory::ConstructWithSpread(Isolate* isolate) { 271 return Callable(BUILTIN_CODE(isolate, ConstructWithSpread), 272 ConstructWithSpreadDescriptor{}); 273 } 274 275 // static 276 Callable CodeFactory::ConstructFunction(Isolate* isolate) { 277 return Callable(BUILTIN_CODE(isolate, ConstructFunction), 278 JSTrampolineDescriptor{}); 279 } 280 281 // static 282 Callable CodeFactory::ConstructVarargs(Isolate* isolate) { 283 return Callable(BUILTIN_CODE(isolate, ConstructVarargs), 284 ConstructVarargsDescriptor{}); 285 } 286 287 // static 288 Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) { 289 return Callable(BUILTIN_CODE(isolate, ConstructForwardVarargs), 290 ConstructForwardVarargsDescriptor{}); 291 } 292 293 // static 294 Callable CodeFactory::ConstructFunctionForwardVarargs(Isolate* isolate) { 295 return Callable(BUILTIN_CODE(isolate, ConstructFunctionForwardVarargs), 296 ConstructForwardVarargsDescriptor{}); 297 } 298 299 // static 300 Callable CodeFactory::InterpreterPushArgsThenCall( 301 Isolate* isolate, ConvertReceiverMode receiver_mode, 302 InterpreterPushArgsMode mode) { 303 return Callable( 304 isolate->builtins()->InterpreterPushArgsThenCall(receiver_mode, mode), 305 InterpreterPushArgsThenCallDescriptor{}); 306 } 307 308 // static 309 Callable CodeFactory::InterpreterPushArgsThenConstruct( 310 Isolate* isolate, InterpreterPushArgsMode mode) { 311 return Callable(isolate->builtins()->InterpreterPushArgsThenConstruct(mode), 312 InterpreterPushArgsThenConstructDescriptor{}); 313 } 314 315 // static 316 Callable CodeFactory::InterpreterCEntry(Isolate* isolate, int result_size) { 317 // Note: If we ever use fpregs in the interpreter then we will need to 318 // save fpregs too. 319 Handle<Code> code = CodeFactory::CEntry(isolate, result_size, kDontSaveFPRegs, 320 kArgvInRegister); 321 if (result_size == 1) { 322 return Callable(code, InterpreterCEntry1Descriptor{}); 323 } else { 324 DCHECK_EQ(result_size, 2); 325 return Callable(code, InterpreterCEntry2Descriptor{}); 326 } 327 } 328 329 // static 330 Callable CodeFactory::InterpreterOnStackReplacement(Isolate* isolate) { 331 return Callable(BUILTIN_CODE(isolate, InterpreterOnStackReplacement), 332 ContextOnlyDescriptor{}); 333 } 334 335 // static 336 Callable CodeFactory::ArrayNoArgumentConstructor( 337 Isolate* isolate, ElementsKind kind, 338 AllocationSiteOverrideMode override_mode) { 339 #define CASE(kind_caps, kind_camel, mode_camel) \ 340 case kind_caps: \ 341 return Callable( \ 342 BUILTIN_CODE(isolate, \ 343 ArrayNoArgumentConstructor_##kind_camel##_##mode_camel), \ 344 ArrayNoArgumentConstructorDescriptor{}) 345 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) { 346 DCHECK(IsSmiElementsKind(kind)); 347 switch (kind) { 348 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride); 349 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride); 350 default: 351 UNREACHABLE(); 352 } 353 } else { 354 DCHECK(override_mode == DISABLE_ALLOCATION_SITES || 355 !AllocationSite::ShouldTrack(kind)); 356 switch (kind) { 357 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites); 358 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites); 359 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites); 360 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites); 361 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites); 362 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites); 363 default: 364 UNREACHABLE(); 365 } 366 } 367 #undef CASE 368 } 369 370 // static 371 Callable CodeFactory::ArraySingleArgumentConstructor( 372 Isolate* isolate, ElementsKind kind, 373 AllocationSiteOverrideMode override_mode) { 374 #define CASE(kind_caps, kind_camel, mode_camel) \ 375 case kind_caps: \ 376 return Callable( \ 377 BUILTIN_CODE( \ 378 isolate, \ 379 ArraySingleArgumentConstructor_##kind_camel##_##mode_camel), \ 380 ArraySingleArgumentConstructorDescriptor{}) 381 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) { 382 DCHECK(IsSmiElementsKind(kind)); 383 switch (kind) { 384 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride); 385 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride); 386 default: 387 UNREACHABLE(); 388 } 389 } else { 390 DCHECK(override_mode == DISABLE_ALLOCATION_SITES || 391 !AllocationSite::ShouldTrack(kind)); 392 switch (kind) { 393 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites); 394 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites); 395 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites); 396 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites); 397 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites); 398 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites); 399 default: 400 UNREACHABLE(); 401 } 402 } 403 #undef CASE 404 } 405 406 // static 407 Callable CodeFactory::InternalArrayNoArgumentConstructor(Isolate* isolate, 408 ElementsKind kind) { 409 switch (kind) { 410 case PACKED_ELEMENTS: 411 return Callable( 412 BUILTIN_CODE(isolate, InternalArrayNoArgumentConstructor_Packed), 413 ArrayNoArgumentConstructorDescriptor{}); 414 case HOLEY_ELEMENTS: 415 return Callable( 416 BUILTIN_CODE(isolate, InternalArrayNoArgumentConstructor_Holey), 417 ArrayNoArgumentConstructorDescriptor{}); 418 default: 419 UNREACHABLE(); 420 } 421 } 422 423 // static 424 Callable CodeFactory::InternalArraySingleArgumentConstructor( 425 Isolate* isolate, ElementsKind kind) { 426 switch (kind) { 427 case PACKED_ELEMENTS: 428 return Callable( 429 BUILTIN_CODE(isolate, InternalArraySingleArgumentConstructor_Packed), 430 ArraySingleArgumentConstructorDescriptor{}); 431 case HOLEY_ELEMENTS: 432 return Callable( 433 BUILTIN_CODE(isolate, InternalArraySingleArgumentConstructor_Holey), 434 ArraySingleArgumentConstructorDescriptor{}); 435 default: 436 UNREACHABLE(); 437 } 438 } 439 440 } // namespace internal 441 } // namespace v8 442