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/codegen/code-factory.h" 6 7#include "src/builtins/builtins-descriptors.h" 8#include "src/ic/ic.h" 9#include "src/init/bootstrapper.h" 10#include "src/objects/allocation-site-inl.h" 11#include "src/objects/objects-inl.h" 12 13namespace v8 { 14namespace internal { 15 16// static 17Handle<CodeT> CodeFactory::RuntimeCEntry(Isolate* isolate, int result_size) { 18 return CodeFactory::CEntry(isolate, result_size); 19} 20 21#define CENTRY_CODE(RS, SD, AM, BE) \ 22 BUILTIN_CODE(isolate, CEntry_##RS##_##SD##_##AM##_##BE) 23 24// static 25Handle<CodeT> CodeFactory::CEntry(Isolate* isolate, int result_size, 26 SaveFPRegsMode save_doubles, 27 ArgvMode argv_mode, bool builtin_exit_frame) { 28 // Aliases for readability below. 29 const int rs = result_size; 30 const SaveFPRegsMode sd = save_doubles; 31 const ArgvMode am = argv_mode; 32 const bool be = builtin_exit_frame; 33 34 if (rs == 1 && sd == SaveFPRegsMode::kIgnore && am == ArgvMode::kStack && 35 !be) { 36 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit); 37 } else if (rs == 1 && sd == SaveFPRegsMode::kIgnore && 38 am == ArgvMode::kStack && be) { 39 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, BuiltinExit); 40 } else if (rs == 1 && sd == SaveFPRegsMode::kIgnore && 41 am == ArgvMode::kRegister && !be) { 42 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit); 43 } else if (rs == 1 && sd == SaveFPRegsMode::kSave && am == ArgvMode::kStack && 44 !be) { 45 return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, NoBuiltinExit); 46 } else if (rs == 1 && sd == SaveFPRegsMode::kSave && am == ArgvMode::kStack && 47 be) { 48 return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, BuiltinExit); 49 } else if (rs == 2 && sd == SaveFPRegsMode::kIgnore && 50 am == ArgvMode::kStack && !be) { 51 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit); 52 } else if (rs == 2 && sd == SaveFPRegsMode::kIgnore && 53 am == ArgvMode::kStack && be) { 54 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, BuiltinExit); 55 } else if (rs == 2 && sd == SaveFPRegsMode::kIgnore && 56 am == ArgvMode::kRegister && !be) { 57 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit); 58 } else if (rs == 2 && sd == SaveFPRegsMode::kSave && am == ArgvMode::kStack && 59 !be) { 60 return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, NoBuiltinExit); 61 } else if (rs == 2 && sd == SaveFPRegsMode::kSave && am == ArgvMode::kStack && 62 be) { 63 return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, BuiltinExit); 64 } 65 66 UNREACHABLE(); 67} 68 69#undef CENTRY_CODE 70 71// static 72Callable CodeFactory::ApiGetter(Isolate* isolate) { 73 return Builtins::CallableFor(isolate, Builtin::kCallApiGetter); 74} 75 76// static 77Callable CodeFactory::CallApiCallback(Isolate* isolate) { 78 return Builtins::CallableFor(isolate, Builtin::kCallApiCallback); 79} 80 81// static 82Callable CodeFactory::LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode) { 83 return typeof_mode == TypeofMode::kNotInside 84 ? Builtins::CallableFor(isolate, Builtin::kLoadGlobalICTrampoline) 85 : Builtins::CallableFor( 86 isolate, Builtin::kLoadGlobalICInsideTypeofTrampoline); 87} 88 89// static 90Callable CodeFactory::LoadGlobalICInOptimizedCode(Isolate* isolate, 91 TypeofMode typeof_mode) { 92 return typeof_mode == TypeofMode::kNotInside 93 ? Builtins::CallableFor(isolate, Builtin::kLoadGlobalIC) 94 : Builtins::CallableFor(isolate, 95 Builtin::kLoadGlobalICInsideTypeof); 96} 97 98Callable CodeFactory::DefineNamedOwnIC(Isolate* isolate) { 99 return Builtins::CallableFor(isolate, Builtin::kDefineNamedOwnICTrampoline); 100} 101 102Callable CodeFactory::DefineNamedOwnICInOptimizedCode(Isolate* isolate) { 103 return Builtins::CallableFor(isolate, Builtin::kDefineNamedOwnIC); 104} 105 106// static 107Callable CodeFactory::NonPrimitiveToPrimitive(Isolate* isolate, 108 ToPrimitiveHint hint) { 109 return Callable(isolate->builtins()->NonPrimitiveToPrimitive(hint), 110 TypeConversionDescriptor{}); 111} 112 113// static 114Callable CodeFactory::OrdinaryToPrimitive(Isolate* isolate, 115 OrdinaryToPrimitiveHint hint) { 116 return Callable(isolate->builtins()->OrdinaryToPrimitive(hint), 117 TypeConversionDescriptor{}); 118} 119 120// static 121Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags) { 122 switch (flags) { 123 case STRING_ADD_CHECK_NONE: 124 return Builtins::CallableFor(isolate, Builtin::kStringAdd_CheckNone); 125 case STRING_ADD_CONVERT_LEFT: 126 return Builtins::CallableFor(isolate, Builtin::kStringAddConvertLeft); 127 case STRING_ADD_CONVERT_RIGHT: 128 return Builtins::CallableFor(isolate, Builtin::kStringAddConvertRight); 129 } 130 UNREACHABLE(); 131} 132 133// static 134Callable CodeFactory::ResumeGenerator(Isolate* isolate) { 135 return Builtins::CallableFor(isolate, Builtin::kResumeGeneratorTrampoline); 136} 137 138// static 139Callable CodeFactory::FastNewFunctionContext(Isolate* isolate, 140 ScopeType scope_type) { 141 switch (scope_type) { 142 case ScopeType::EVAL_SCOPE: 143 return Builtins::CallableFor(isolate, 144 Builtin::kFastNewFunctionContextEval); 145 case ScopeType::FUNCTION_SCOPE: 146 return Builtins::CallableFor(isolate, 147 Builtin::kFastNewFunctionContextFunction); 148 default: 149 UNREACHABLE(); 150 } 151} 152 153// static 154Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode) { 155 return Callable(isolate->builtins()->Call(mode), CallTrampolineDescriptor{}); 156} 157 158// static 159Callable CodeFactory::Call_WithFeedback(Isolate* isolate, 160 ConvertReceiverMode mode) { 161 switch (mode) { 162 case ConvertReceiverMode::kNullOrUndefined: 163 return Builtins::CallableFor( 164 isolate, Builtin::kCall_ReceiverIsNullOrUndefined_WithFeedback); 165 case ConvertReceiverMode::kNotNullOrUndefined: 166 return Builtins::CallableFor( 167 isolate, Builtin::kCall_ReceiverIsNotNullOrUndefined_WithFeedback); 168 case ConvertReceiverMode::kAny: 169 return Builtins::CallableFor(isolate, 170 Builtin::kCall_ReceiverIsAny_WithFeedback); 171 } 172 UNREACHABLE(); 173} 174 175// static 176Callable CodeFactory::CallWithArrayLike(Isolate* isolate) { 177 return Builtins::CallableFor(isolate, Builtin::kCallWithArrayLike); 178} 179 180// static 181Callable CodeFactory::CallWithSpread(Isolate* isolate) { 182 return Builtins::CallableFor(isolate, Builtin::kCallWithSpread); 183} 184 185// static 186Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) { 187 return Callable(isolate->builtins()->CallFunction(mode), 188 CallTrampolineDescriptor{}); 189} 190 191// static 192Callable CodeFactory::CallVarargs(Isolate* isolate) { 193 return Builtins::CallableFor(isolate, Builtin::kCallVarargs); 194} 195 196// static 197Callable CodeFactory::CallForwardVarargs(Isolate* isolate) { 198 return Builtins::CallableFor(isolate, Builtin::kCallForwardVarargs); 199} 200 201// static 202Callable CodeFactory::CallFunctionForwardVarargs(Isolate* isolate) { 203 return Builtins::CallableFor(isolate, Builtin::kCallFunctionForwardVarargs); 204} 205 206// static 207Callable CodeFactory::Construct(Isolate* isolate) { 208 return Builtins::CallableFor(isolate, Builtin::kConstruct); 209} 210 211// static 212Callable CodeFactory::ConstructWithSpread(Isolate* isolate) { 213 return Builtins::CallableFor(isolate, Builtin::kConstructWithSpread); 214} 215 216// static 217Callable CodeFactory::ConstructFunction(Isolate* isolate) { 218 return Builtins::CallableFor(isolate, Builtin::kConstructFunction); 219} 220 221// static 222Callable CodeFactory::ConstructVarargs(Isolate* isolate) { 223 return Builtins::CallableFor(isolate, Builtin::kConstructVarargs); 224} 225 226// static 227Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) { 228 return Builtins::CallableFor(isolate, Builtin::kConstructForwardVarargs); 229} 230 231// static 232Callable CodeFactory::ConstructFunctionForwardVarargs(Isolate* isolate) { 233 return Builtins::CallableFor(isolate, 234 Builtin::kConstructFunctionForwardVarargs); 235} 236 237// static 238Callable CodeFactory::InterpreterPushArgsThenCall( 239 Isolate* isolate, ConvertReceiverMode receiver_mode, 240 InterpreterPushArgsMode mode) { 241 switch (mode) { 242 case InterpreterPushArgsMode::kArrayFunction: 243 // There is no special-case handling of calls to Array. They will all go 244 // through the kOther case below. 245 UNREACHABLE(); 246 case InterpreterPushArgsMode::kWithFinalSpread: 247 return Builtins::CallableFor( 248 isolate, Builtin::kInterpreterPushArgsThenCallWithFinalSpread); 249 case InterpreterPushArgsMode::kOther: 250 switch (receiver_mode) { 251 case ConvertReceiverMode::kNullOrUndefined: 252 return Builtins::CallableFor( 253 isolate, Builtin::kInterpreterPushUndefinedAndArgsThenCall); 254 case ConvertReceiverMode::kNotNullOrUndefined: 255 case ConvertReceiverMode::kAny: 256 return Builtins::CallableFor(isolate, 257 Builtin::kInterpreterPushArgsThenCall); 258 } 259 } 260 UNREACHABLE(); 261} 262 263// static 264Callable CodeFactory::InterpreterPushArgsThenConstruct( 265 Isolate* isolate, InterpreterPushArgsMode mode) { 266 switch (mode) { 267 case InterpreterPushArgsMode::kArrayFunction: 268 return Builtins::CallableFor( 269 isolate, Builtin::kInterpreterPushArgsThenConstructArrayFunction); 270 case InterpreterPushArgsMode::kWithFinalSpread: 271 return Builtins::CallableFor( 272 isolate, Builtin::kInterpreterPushArgsThenConstructWithFinalSpread); 273 case InterpreterPushArgsMode::kOther: 274 return Builtins::CallableFor(isolate, 275 Builtin::kInterpreterPushArgsThenConstruct); 276 } 277 UNREACHABLE(); 278} 279 280// static 281Callable CodeFactory::InterpreterCEntry(Isolate* isolate, int result_size) { 282 // Note: If we ever use fpregs in the interpreter then we will need to 283 // save fpregs too. 284 Handle<CodeT> code = CodeFactory::CEntry( 285 isolate, result_size, SaveFPRegsMode::kIgnore, ArgvMode::kRegister); 286 if (result_size == 1) { 287 return Callable(code, InterpreterCEntry1Descriptor{}); 288 } else { 289 DCHECK_EQ(result_size, 2); 290 return Callable(code, InterpreterCEntry2Descriptor{}); 291 } 292} 293 294// static 295Callable CodeFactory::InterpreterOnStackReplacement(Isolate* isolate) { 296 return Builtins::CallableFor(isolate, 297 Builtin::kInterpreterOnStackReplacement); 298} 299 300// static 301Callable CodeFactory::InterpreterOnStackReplacement_ToBaseline( 302 Isolate* isolate) { 303 return Builtins::CallableFor( 304 isolate, Builtin::kInterpreterOnStackReplacement_ToBaseline); 305} 306 307// static 308Callable CodeFactory::ArrayNoArgumentConstructor( 309 Isolate* isolate, ElementsKind kind, 310 AllocationSiteOverrideMode override_mode) { 311#define CASE(kind_caps, kind_camel, mode_camel) \ 312 case kind_caps: \ 313 return Builtins::CallableFor( \ 314 isolate, \ 315 Builtin::kArrayNoArgumentConstructor_##kind_camel##_##mode_camel); 316 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) { 317 DCHECK(IsSmiElementsKind(kind)); 318 switch (kind) { 319 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride); 320 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride); 321 default: 322 UNREACHABLE(); 323 } 324 } else { 325 DCHECK(override_mode == DISABLE_ALLOCATION_SITES || 326 !AllocationSite::ShouldTrack(kind)); 327 switch (kind) { 328 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites); 329 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites); 330 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites); 331 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites); 332 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites); 333 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites); 334 default: 335 UNREACHABLE(); 336 } 337 } 338#undef CASE 339} 340 341// static 342Callable CodeFactory::ArraySingleArgumentConstructor( 343 Isolate* isolate, ElementsKind kind, 344 AllocationSiteOverrideMode override_mode) { 345#define CASE(kind_caps, kind_camel, mode_camel) \ 346 case kind_caps: \ 347 return Builtins::CallableFor( \ 348 isolate, \ 349 Builtin::kArraySingleArgumentConstructor_##kind_camel##_##mode_camel) 350 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) { 351 DCHECK(IsSmiElementsKind(kind)); 352 switch (kind) { 353 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride); 354 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride); 355 default: 356 UNREACHABLE(); 357 } 358 } else { 359 DCHECK(override_mode == DISABLE_ALLOCATION_SITES || 360 !AllocationSite::ShouldTrack(kind)); 361 switch (kind) { 362 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites); 363 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites); 364 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites); 365 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites); 366 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites); 367 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites); 368 default: 369 UNREACHABLE(); 370 } 371 } 372#undef CASE 373} 374 375#ifdef V8_IS_TSAN 376// static 377Builtin CodeFactory::GetTSANStoreStub(SaveFPRegsMode fp_mode, int size, 378 std::memory_order order) { 379 if (order == std::memory_order_relaxed) { 380 if (size == kInt8Size) { 381 return fp_mode == SaveFPRegsMode::kIgnore 382 ? Builtin::kTSANRelaxedStore8IgnoreFP 383 : Builtin::kTSANRelaxedStore8SaveFP; 384 } else if (size == kInt16Size) { 385 return fp_mode == SaveFPRegsMode::kIgnore 386 ? Builtin::kTSANRelaxedStore16IgnoreFP 387 : Builtin::kTSANRelaxedStore16SaveFP; 388 } else if (size == kInt32Size) { 389 return fp_mode == SaveFPRegsMode::kIgnore 390 ? Builtin::kTSANRelaxedStore32IgnoreFP 391 : Builtin::kTSANRelaxedStore32SaveFP; 392 } else { 393 CHECK_EQ(size, kInt64Size); 394 return fp_mode == SaveFPRegsMode::kIgnore 395 ? Builtin::kTSANRelaxedStore64IgnoreFP 396 : Builtin::kTSANRelaxedStore64SaveFP; 397 } 398 } else { 399 DCHECK_EQ(order, std::memory_order_seq_cst); 400 if (size == kInt8Size) { 401 return fp_mode == SaveFPRegsMode::kIgnore 402 ? Builtin::kTSANSeqCstStore8IgnoreFP 403 : Builtin::kTSANSeqCstStore8SaveFP; 404 } else if (size == kInt16Size) { 405 return fp_mode == SaveFPRegsMode::kIgnore 406 ? Builtin::kTSANSeqCstStore16IgnoreFP 407 : Builtin::kTSANSeqCstStore16SaveFP; 408 } else if (size == kInt32Size) { 409 return fp_mode == SaveFPRegsMode::kIgnore 410 ? Builtin::kTSANSeqCstStore32IgnoreFP 411 : Builtin::kTSANSeqCstStore32SaveFP; 412 } else { 413 CHECK_EQ(size, kInt64Size); 414 return fp_mode == SaveFPRegsMode::kIgnore 415 ? Builtin::kTSANSeqCstStore64IgnoreFP 416 : Builtin::kTSANSeqCstStore64SaveFP; 417 } 418 } 419} 420 421// static 422Builtin CodeFactory::GetTSANRelaxedLoadStub(SaveFPRegsMode fp_mode, int size) { 423 if (size == kInt32Size) { 424 return fp_mode == SaveFPRegsMode::kIgnore 425 ? Builtin::kTSANRelaxedLoad32IgnoreFP 426 : Builtin::kTSANRelaxedLoad32SaveFP; 427 } else { 428 CHECK_EQ(size, kInt64Size); 429 return fp_mode == SaveFPRegsMode::kIgnore 430 ? Builtin::kTSANRelaxedLoad64IgnoreFP 431 : Builtin::kTSANRelaxedLoad64SaveFP; 432 } 433} 434#endif // V8_IS_TSAN 435 436} // namespace internal 437} // namespace v8 438