1 // Copyright 2016 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-stub-assembler.h" 6 #include "src/code-factory.h" 7 #include "src/frames-inl.h" 8 #include "src/frames.h" 9 #include "src/ic/stub-cache.h" 10 11 namespace v8 { 12 namespace internal { 13 14 using compiler::Node; 15 CodeStubAssembler(Isolate * isolate,Zone * zone,const CallInterfaceDescriptor & descriptor,Code::Flags flags,const char * name,size_t result_size)16 CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone, 17 const CallInterfaceDescriptor& descriptor, 18 Code::Flags flags, const char* name, 19 size_t result_size) 20 : compiler::CodeAssembler(isolate, zone, descriptor, flags, name, 21 result_size) {} 22 CodeStubAssembler(Isolate * isolate,Zone * zone,int parameter_count,Code::Flags flags,const char * name)23 CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone, 24 int parameter_count, Code::Flags flags, 25 const char* name) 26 : compiler::CodeAssembler(isolate, zone, parameter_count, flags, name) {} 27 Assert(Node * condition)28 void CodeStubAssembler::Assert(Node* condition) { 29 #if defined(DEBUG) 30 Label ok(this); 31 Comment("[ Assert"); 32 GotoIf(condition, &ok); 33 DebugBreak(); 34 Goto(&ok); 35 Bind(&ok); 36 Comment("] Assert"); 37 #endif 38 } 39 BooleanMapConstant()40 Node* CodeStubAssembler::BooleanMapConstant() { 41 return HeapConstant(isolate()->factory()->boolean_map()); 42 } 43 EmptyStringConstant()44 Node* CodeStubAssembler::EmptyStringConstant() { 45 return LoadRoot(Heap::kempty_stringRootIndex); 46 } 47 HeapNumberMapConstant()48 Node* CodeStubAssembler::HeapNumberMapConstant() { 49 return HeapConstant(isolate()->factory()->heap_number_map()); 50 } 51 NoContextConstant()52 Node* CodeStubAssembler::NoContextConstant() { 53 return SmiConstant(Smi::FromInt(0)); 54 } 55 NullConstant()56 Node* CodeStubAssembler::NullConstant() { 57 return LoadRoot(Heap::kNullValueRootIndex); 58 } 59 UndefinedConstant()60 Node* CodeStubAssembler::UndefinedConstant() { 61 return LoadRoot(Heap::kUndefinedValueRootIndex); 62 } 63 TheHoleConstant()64 Node* CodeStubAssembler::TheHoleConstant() { 65 return LoadRoot(Heap::kTheHoleValueRootIndex); 66 } 67 HashSeed()68 Node* CodeStubAssembler::HashSeed() { 69 return SmiToWord32(LoadRoot(Heap::kHashSeedRootIndex)); 70 } 71 StaleRegisterConstant()72 Node* CodeStubAssembler::StaleRegisterConstant() { 73 return LoadRoot(Heap::kStaleRegisterRootIndex); 74 } 75 Float64Round(Node * x)76 Node* CodeStubAssembler::Float64Round(Node* x) { 77 Node* one = Float64Constant(1.0); 78 Node* one_half = Float64Constant(0.5); 79 80 Variable var_x(this, MachineRepresentation::kFloat64); 81 Label return_x(this); 82 83 // Round up {x} towards Infinity. 84 var_x.Bind(Float64Ceil(x)); 85 86 GotoIf(Float64LessThanOrEqual(Float64Sub(var_x.value(), one_half), x), 87 &return_x); 88 var_x.Bind(Float64Sub(var_x.value(), one)); 89 Goto(&return_x); 90 91 Bind(&return_x); 92 return var_x.value(); 93 } 94 Float64Ceil(Node * x)95 Node* CodeStubAssembler::Float64Ceil(Node* x) { 96 if (IsFloat64RoundUpSupported()) { 97 return Float64RoundUp(x); 98 } 99 100 Node* one = Float64Constant(1.0); 101 Node* zero = Float64Constant(0.0); 102 Node* two_52 = Float64Constant(4503599627370496.0E0); 103 Node* minus_two_52 = Float64Constant(-4503599627370496.0E0); 104 105 Variable var_x(this, MachineRepresentation::kFloat64); 106 Label return_x(this), return_minus_x(this); 107 var_x.Bind(x); 108 109 // Check if {x} is greater than zero. 110 Label if_xgreaterthanzero(this), if_xnotgreaterthanzero(this); 111 Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero, 112 &if_xnotgreaterthanzero); 113 114 Bind(&if_xgreaterthanzero); 115 { 116 // Just return {x} unless it's in the range ]0,2^52[. 117 GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x); 118 119 // Round positive {x} towards Infinity. 120 var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52)); 121 GotoUnless(Float64LessThan(var_x.value(), x), &return_x); 122 var_x.Bind(Float64Add(var_x.value(), one)); 123 Goto(&return_x); 124 } 125 126 Bind(&if_xnotgreaterthanzero); 127 { 128 // Just return {x} unless it's in the range ]-2^52,0[ 129 GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x); 130 GotoUnless(Float64LessThan(x, zero), &return_x); 131 132 // Round negated {x} towards Infinity and return the result negated. 133 Node* minus_x = Float64Neg(x); 134 var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52)); 135 GotoUnless(Float64GreaterThan(var_x.value(), minus_x), &return_minus_x); 136 var_x.Bind(Float64Sub(var_x.value(), one)); 137 Goto(&return_minus_x); 138 } 139 140 Bind(&return_minus_x); 141 var_x.Bind(Float64Neg(var_x.value())); 142 Goto(&return_x); 143 144 Bind(&return_x); 145 return var_x.value(); 146 } 147 Float64Floor(Node * x)148 Node* CodeStubAssembler::Float64Floor(Node* x) { 149 if (IsFloat64RoundDownSupported()) { 150 return Float64RoundDown(x); 151 } 152 153 Node* one = Float64Constant(1.0); 154 Node* zero = Float64Constant(0.0); 155 Node* two_52 = Float64Constant(4503599627370496.0E0); 156 Node* minus_two_52 = Float64Constant(-4503599627370496.0E0); 157 158 Variable var_x(this, MachineRepresentation::kFloat64); 159 Label return_x(this), return_minus_x(this); 160 var_x.Bind(x); 161 162 // Check if {x} is greater than zero. 163 Label if_xgreaterthanzero(this), if_xnotgreaterthanzero(this); 164 Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero, 165 &if_xnotgreaterthanzero); 166 167 Bind(&if_xgreaterthanzero); 168 { 169 // Just return {x} unless it's in the range ]0,2^52[. 170 GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x); 171 172 // Round positive {x} towards -Infinity. 173 var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52)); 174 GotoUnless(Float64GreaterThan(var_x.value(), x), &return_x); 175 var_x.Bind(Float64Sub(var_x.value(), one)); 176 Goto(&return_x); 177 } 178 179 Bind(&if_xnotgreaterthanzero); 180 { 181 // Just return {x} unless it's in the range ]-2^52,0[ 182 GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x); 183 GotoUnless(Float64LessThan(x, zero), &return_x); 184 185 // Round negated {x} towards -Infinity and return the result negated. 186 Node* minus_x = Float64Neg(x); 187 var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52)); 188 GotoUnless(Float64LessThan(var_x.value(), minus_x), &return_minus_x); 189 var_x.Bind(Float64Add(var_x.value(), one)); 190 Goto(&return_minus_x); 191 } 192 193 Bind(&return_minus_x); 194 var_x.Bind(Float64Neg(var_x.value())); 195 Goto(&return_x); 196 197 Bind(&return_x); 198 return var_x.value(); 199 } 200 Float64Trunc(Node * x)201 Node* CodeStubAssembler::Float64Trunc(Node* x) { 202 if (IsFloat64RoundTruncateSupported()) { 203 return Float64RoundTruncate(x); 204 } 205 206 Node* one = Float64Constant(1.0); 207 Node* zero = Float64Constant(0.0); 208 Node* two_52 = Float64Constant(4503599627370496.0E0); 209 Node* minus_two_52 = Float64Constant(-4503599627370496.0E0); 210 211 Variable var_x(this, MachineRepresentation::kFloat64); 212 Label return_x(this), return_minus_x(this); 213 var_x.Bind(x); 214 215 // Check if {x} is greater than 0. 216 Label if_xgreaterthanzero(this), if_xnotgreaterthanzero(this); 217 Branch(Float64GreaterThan(x, zero), &if_xgreaterthanzero, 218 &if_xnotgreaterthanzero); 219 220 Bind(&if_xgreaterthanzero); 221 { 222 if (IsFloat64RoundDownSupported()) { 223 var_x.Bind(Float64RoundDown(x)); 224 } else { 225 // Just return {x} unless it's in the range ]0,2^52[. 226 GotoIf(Float64GreaterThanOrEqual(x, two_52), &return_x); 227 228 // Round positive {x} towards -Infinity. 229 var_x.Bind(Float64Sub(Float64Add(two_52, x), two_52)); 230 GotoUnless(Float64GreaterThan(var_x.value(), x), &return_x); 231 var_x.Bind(Float64Sub(var_x.value(), one)); 232 } 233 Goto(&return_x); 234 } 235 236 Bind(&if_xnotgreaterthanzero); 237 { 238 if (IsFloat64RoundUpSupported()) { 239 var_x.Bind(Float64RoundUp(x)); 240 Goto(&return_x); 241 } else { 242 // Just return {x} unless its in the range ]-2^52,0[. 243 GotoIf(Float64LessThanOrEqual(x, minus_two_52), &return_x); 244 GotoUnless(Float64LessThan(x, zero), &return_x); 245 246 // Round negated {x} towards -Infinity and return result negated. 247 Node* minus_x = Float64Neg(x); 248 var_x.Bind(Float64Sub(Float64Add(two_52, minus_x), two_52)); 249 GotoUnless(Float64GreaterThan(var_x.value(), minus_x), &return_minus_x); 250 var_x.Bind(Float64Sub(var_x.value(), one)); 251 Goto(&return_minus_x); 252 } 253 } 254 255 Bind(&return_minus_x); 256 var_x.Bind(Float64Neg(var_x.value())); 257 Goto(&return_x); 258 259 Bind(&return_x); 260 return var_x.value(); 261 } 262 SmiFromWord32(Node * value)263 Node* CodeStubAssembler::SmiFromWord32(Node* value) { 264 value = ChangeInt32ToIntPtr(value); 265 return WordShl(value, SmiShiftBitsConstant()); 266 } 267 SmiTag(Node * value)268 Node* CodeStubAssembler::SmiTag(Node* value) { 269 int32_t constant_value; 270 if (ToInt32Constant(value, constant_value) && Smi::IsValid(constant_value)) { 271 return SmiConstant(Smi::FromInt(constant_value)); 272 } 273 return WordShl(value, SmiShiftBitsConstant()); 274 } 275 SmiUntag(Node * value)276 Node* CodeStubAssembler::SmiUntag(Node* value) { 277 return WordSar(value, SmiShiftBitsConstant()); 278 } 279 SmiToWord32(Node * value)280 Node* CodeStubAssembler::SmiToWord32(Node* value) { 281 Node* result = WordSar(value, SmiShiftBitsConstant()); 282 if (Is64()) { 283 result = TruncateInt64ToInt32(result); 284 } 285 return result; 286 } 287 SmiToFloat64(Node * value)288 Node* CodeStubAssembler::SmiToFloat64(Node* value) { 289 return ChangeInt32ToFloat64(SmiToWord32(value)); 290 } 291 SmiAdd(Node * a,Node * b)292 Node* CodeStubAssembler::SmiAdd(Node* a, Node* b) { return IntPtrAdd(a, b); } 293 SmiAddWithOverflow(Node * a,Node * b)294 Node* CodeStubAssembler::SmiAddWithOverflow(Node* a, Node* b) { 295 return IntPtrAddWithOverflow(a, b); 296 } 297 SmiSub(Node * a,Node * b)298 Node* CodeStubAssembler::SmiSub(Node* a, Node* b) { return IntPtrSub(a, b); } 299 SmiSubWithOverflow(Node * a,Node * b)300 Node* CodeStubAssembler::SmiSubWithOverflow(Node* a, Node* b) { 301 return IntPtrSubWithOverflow(a, b); 302 } 303 SmiEqual(Node * a,Node * b)304 Node* CodeStubAssembler::SmiEqual(Node* a, Node* b) { return WordEqual(a, b); } 305 SmiAboveOrEqual(Node * a,Node * b)306 Node* CodeStubAssembler::SmiAboveOrEqual(Node* a, Node* b) { 307 return UintPtrGreaterThanOrEqual(a, b); 308 } 309 SmiLessThan(Node * a,Node * b)310 Node* CodeStubAssembler::SmiLessThan(Node* a, Node* b) { 311 return IntPtrLessThan(a, b); 312 } 313 SmiLessThanOrEqual(Node * a,Node * b)314 Node* CodeStubAssembler::SmiLessThanOrEqual(Node* a, Node* b) { 315 return IntPtrLessThanOrEqual(a, b); 316 } 317 SmiMin(Node * a,Node * b)318 Node* CodeStubAssembler::SmiMin(Node* a, Node* b) { 319 // TODO(bmeurer): Consider using Select once available. 320 Variable min(this, MachineRepresentation::kTagged); 321 Label if_a(this), if_b(this), join(this); 322 BranchIfSmiLessThan(a, b, &if_a, &if_b); 323 Bind(&if_a); 324 min.Bind(a); 325 Goto(&join); 326 Bind(&if_b); 327 min.Bind(b); 328 Goto(&join); 329 Bind(&join); 330 return min.value(); 331 } 332 WordIsSmi(Node * a)333 Node* CodeStubAssembler::WordIsSmi(Node* a) { 334 return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask)), IntPtrConstant(0)); 335 } 336 WordIsPositiveSmi(Node * a)337 Node* CodeStubAssembler::WordIsPositiveSmi(Node* a) { 338 return WordEqual(WordAnd(a, IntPtrConstant(kSmiTagMask | kSmiSignMask)), 339 IntPtrConstant(0)); 340 } 341 AllocateRawUnaligned(Node * size_in_bytes,AllocationFlags flags,Node * top_address,Node * limit_address)342 Node* CodeStubAssembler::AllocateRawUnaligned(Node* size_in_bytes, 343 AllocationFlags flags, 344 Node* top_address, 345 Node* limit_address) { 346 Node* top = Load(MachineType::Pointer(), top_address); 347 Node* limit = Load(MachineType::Pointer(), limit_address); 348 349 // If there's not enough space, call the runtime. 350 Variable result(this, MachineRepresentation::kTagged); 351 Label runtime_call(this, Label::kDeferred), no_runtime_call(this); 352 Label merge_runtime(this, &result); 353 354 Node* new_top = IntPtrAdd(top, size_in_bytes); 355 Branch(UintPtrGreaterThanOrEqual(new_top, limit), &runtime_call, 356 &no_runtime_call); 357 358 Bind(&runtime_call); 359 // AllocateInTargetSpace does not use the context. 360 Node* context = SmiConstant(Smi::FromInt(0)); 361 362 Node* runtime_result; 363 if (flags & kPretenured) { 364 Node* runtime_flags = SmiConstant( 365 Smi::FromInt(AllocateDoubleAlignFlag::encode(false) | 366 AllocateTargetSpace::encode(AllocationSpace::OLD_SPACE))); 367 runtime_result = CallRuntime(Runtime::kAllocateInTargetSpace, context, 368 SmiTag(size_in_bytes), runtime_flags); 369 } else { 370 runtime_result = CallRuntime(Runtime::kAllocateInNewSpace, context, 371 SmiTag(size_in_bytes)); 372 } 373 result.Bind(runtime_result); 374 Goto(&merge_runtime); 375 376 // When there is enough space, return `top' and bump it up. 377 Bind(&no_runtime_call); 378 Node* no_runtime_result = top; 379 StoreNoWriteBarrier(MachineType::PointerRepresentation(), top_address, 380 new_top); 381 no_runtime_result = BitcastWordToTagged( 382 IntPtrAdd(no_runtime_result, IntPtrConstant(kHeapObjectTag))); 383 result.Bind(no_runtime_result); 384 Goto(&merge_runtime); 385 386 Bind(&merge_runtime); 387 return result.value(); 388 } 389 AllocateRawAligned(Node * size_in_bytes,AllocationFlags flags,Node * top_address,Node * limit_address)390 Node* CodeStubAssembler::AllocateRawAligned(Node* size_in_bytes, 391 AllocationFlags flags, 392 Node* top_address, 393 Node* limit_address) { 394 Node* top = Load(MachineType::Pointer(), top_address); 395 Node* limit = Load(MachineType::Pointer(), limit_address); 396 Variable adjusted_size(this, MachineType::PointerRepresentation()); 397 adjusted_size.Bind(size_in_bytes); 398 if (flags & kDoubleAlignment) { 399 // TODO(epertoso): Simd128 alignment. 400 Label aligned(this), not_aligned(this), merge(this, &adjusted_size); 401 Branch(WordAnd(top, IntPtrConstant(kDoubleAlignmentMask)), ¬_aligned, 402 &aligned); 403 404 Bind(¬_aligned); 405 Node* not_aligned_size = 406 IntPtrAdd(size_in_bytes, IntPtrConstant(kPointerSize)); 407 adjusted_size.Bind(not_aligned_size); 408 Goto(&merge); 409 410 Bind(&aligned); 411 Goto(&merge); 412 413 Bind(&merge); 414 } 415 416 Variable address(this, MachineRepresentation::kTagged); 417 address.Bind(AllocateRawUnaligned(adjusted_size.value(), kNone, top, limit)); 418 419 Label needs_filler(this), doesnt_need_filler(this), 420 merge_address(this, &address); 421 Branch(IntPtrEqual(adjusted_size.value(), size_in_bytes), &doesnt_need_filler, 422 &needs_filler); 423 424 Bind(&needs_filler); 425 // Store a filler and increase the address by kPointerSize. 426 // TODO(epertoso): this code assumes that we only align to kDoubleSize. Change 427 // it when Simd128 alignment is supported. 428 StoreNoWriteBarrier(MachineType::PointerRepresentation(), top, 429 LoadRoot(Heap::kOnePointerFillerMapRootIndex)); 430 address.Bind(BitcastWordToTagged( 431 IntPtrAdd(address.value(), IntPtrConstant(kPointerSize)))); 432 Goto(&merge_address); 433 434 Bind(&doesnt_need_filler); 435 Goto(&merge_address); 436 437 Bind(&merge_address); 438 // Update the top. 439 StoreNoWriteBarrier(MachineType::PointerRepresentation(), top_address, 440 IntPtrAdd(top, adjusted_size.value())); 441 return address.value(); 442 } 443 Allocate(Node * size_in_bytes,AllocationFlags flags)444 Node* CodeStubAssembler::Allocate(Node* size_in_bytes, AllocationFlags flags) { 445 bool const new_space = !(flags & kPretenured); 446 Node* top_address = ExternalConstant( 447 new_space 448 ? ExternalReference::new_space_allocation_top_address(isolate()) 449 : ExternalReference::old_space_allocation_top_address(isolate())); 450 Node* limit_address = ExternalConstant( 451 new_space 452 ? ExternalReference::new_space_allocation_limit_address(isolate()) 453 : ExternalReference::old_space_allocation_limit_address(isolate())); 454 455 #ifdef V8_HOST_ARCH_32_BIT 456 if (flags & kDoubleAlignment) { 457 return AllocateRawAligned(size_in_bytes, flags, top_address, limit_address); 458 } 459 #endif 460 461 return AllocateRawUnaligned(size_in_bytes, flags, top_address, limit_address); 462 } 463 Allocate(int size_in_bytes,AllocationFlags flags)464 Node* CodeStubAssembler::Allocate(int size_in_bytes, AllocationFlags flags) { 465 return CodeStubAssembler::Allocate(IntPtrConstant(size_in_bytes), flags); 466 } 467 InnerAllocate(Node * previous,Node * offset)468 Node* CodeStubAssembler::InnerAllocate(Node* previous, Node* offset) { 469 return BitcastWordToTagged(IntPtrAdd(previous, offset)); 470 } 471 InnerAllocate(Node * previous,int offset)472 Node* CodeStubAssembler::InnerAllocate(Node* previous, int offset) { 473 return InnerAllocate(previous, IntPtrConstant(offset)); 474 } 475 LoadFromFrame(int offset,MachineType rep)476 compiler::Node* CodeStubAssembler::LoadFromFrame(int offset, MachineType rep) { 477 Node* frame_pointer = LoadFramePointer(); 478 return Load(rep, frame_pointer, IntPtrConstant(offset)); 479 } 480 LoadFromParentFrame(int offset,MachineType rep)481 compiler::Node* CodeStubAssembler::LoadFromParentFrame(int offset, 482 MachineType rep) { 483 Node* frame_pointer = LoadParentFramePointer(); 484 return Load(rep, frame_pointer, IntPtrConstant(offset)); 485 } 486 LoadBufferObject(Node * buffer,int offset,MachineType rep)487 Node* CodeStubAssembler::LoadBufferObject(Node* buffer, int offset, 488 MachineType rep) { 489 return Load(rep, buffer, IntPtrConstant(offset)); 490 } 491 LoadObjectField(Node * object,int offset,MachineType rep)492 Node* CodeStubAssembler::LoadObjectField(Node* object, int offset, 493 MachineType rep) { 494 return Load(rep, object, IntPtrConstant(offset - kHeapObjectTag)); 495 } 496 LoadObjectField(Node * object,Node * offset,MachineType rep)497 Node* CodeStubAssembler::LoadObjectField(Node* object, Node* offset, 498 MachineType rep) { 499 return Load(rep, object, IntPtrSub(offset, IntPtrConstant(kHeapObjectTag))); 500 } 501 LoadHeapNumberValue(Node * object)502 Node* CodeStubAssembler::LoadHeapNumberValue(Node* object) { 503 return LoadObjectField(object, HeapNumber::kValueOffset, 504 MachineType::Float64()); 505 } 506 LoadMap(Node * object)507 Node* CodeStubAssembler::LoadMap(Node* object) { 508 return LoadObjectField(object, HeapObject::kMapOffset); 509 } 510 LoadInstanceType(Node * object)511 Node* CodeStubAssembler::LoadInstanceType(Node* object) { 512 return LoadMapInstanceType(LoadMap(object)); 513 } 514 AssertInstanceType(Node * object,InstanceType instance_type)515 void CodeStubAssembler::AssertInstanceType(Node* object, 516 InstanceType instance_type) { 517 Assert(Word32Equal(LoadInstanceType(object), Int32Constant(instance_type))); 518 } 519 LoadProperties(Node * object)520 Node* CodeStubAssembler::LoadProperties(Node* object) { 521 return LoadObjectField(object, JSObject::kPropertiesOffset); 522 } 523 LoadElements(Node * object)524 Node* CodeStubAssembler::LoadElements(Node* object) { 525 return LoadObjectField(object, JSObject::kElementsOffset); 526 } 527 LoadFixedArrayBaseLength(Node * array)528 Node* CodeStubAssembler::LoadFixedArrayBaseLength(Node* array) { 529 return LoadObjectField(array, FixedArrayBase::kLengthOffset); 530 } 531 LoadMapBitField(Node * map)532 Node* CodeStubAssembler::LoadMapBitField(Node* map) { 533 return LoadObjectField(map, Map::kBitFieldOffset, MachineType::Uint8()); 534 } 535 LoadMapBitField2(Node * map)536 Node* CodeStubAssembler::LoadMapBitField2(Node* map) { 537 return LoadObjectField(map, Map::kBitField2Offset, MachineType::Uint8()); 538 } 539 LoadMapBitField3(Node * map)540 Node* CodeStubAssembler::LoadMapBitField3(Node* map) { 541 return LoadObjectField(map, Map::kBitField3Offset, MachineType::Uint32()); 542 } 543 LoadMapInstanceType(Node * map)544 Node* CodeStubAssembler::LoadMapInstanceType(Node* map) { 545 return LoadObjectField(map, Map::kInstanceTypeOffset, MachineType::Uint8()); 546 } 547 LoadMapDescriptors(Node * map)548 Node* CodeStubAssembler::LoadMapDescriptors(Node* map) { 549 return LoadObjectField(map, Map::kDescriptorsOffset); 550 } 551 LoadMapPrototype(Node * map)552 Node* CodeStubAssembler::LoadMapPrototype(Node* map) { 553 return LoadObjectField(map, Map::kPrototypeOffset); 554 } 555 LoadMapInstanceSize(Node * map)556 Node* CodeStubAssembler::LoadMapInstanceSize(Node* map) { 557 return LoadObjectField(map, Map::kInstanceSizeOffset, MachineType::Uint8()); 558 } 559 LoadMapInobjectProperties(Node * map)560 Node* CodeStubAssembler::LoadMapInobjectProperties(Node* map) { 561 // See Map::GetInObjectProperties() for details. 562 STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE); 563 Assert(Int32GreaterThanOrEqual(LoadMapInstanceType(map), 564 Int32Constant(FIRST_JS_OBJECT_TYPE))); 565 return LoadObjectField( 566 map, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset, 567 MachineType::Uint8()); 568 } 569 LoadNameHashField(Node * name)570 Node* CodeStubAssembler::LoadNameHashField(Node* name) { 571 return LoadObjectField(name, Name::kHashFieldOffset, MachineType::Uint32()); 572 } 573 LoadNameHash(Node * name,Label * if_hash_not_computed)574 Node* CodeStubAssembler::LoadNameHash(Node* name, Label* if_hash_not_computed) { 575 Node* hash_field = LoadNameHashField(name); 576 if (if_hash_not_computed != nullptr) { 577 GotoIf(WordEqual( 578 Word32And(hash_field, Int32Constant(Name::kHashNotComputedMask)), 579 Int32Constant(0)), 580 if_hash_not_computed); 581 } 582 return Word32Shr(hash_field, Int32Constant(Name::kHashShift)); 583 } 584 LoadStringLength(Node * object)585 Node* CodeStubAssembler::LoadStringLength(Node* object) { 586 return LoadObjectField(object, String::kLengthOffset); 587 } 588 LoadJSValueValue(Node * object)589 Node* CodeStubAssembler::LoadJSValueValue(Node* object) { 590 return LoadObjectField(object, JSValue::kValueOffset); 591 } 592 LoadWeakCellValue(Node * weak_cell,Label * if_cleared)593 Node* CodeStubAssembler::LoadWeakCellValue(Node* weak_cell, Label* if_cleared) { 594 Node* value = LoadObjectField(weak_cell, WeakCell::kValueOffset); 595 if (if_cleared != nullptr) { 596 GotoIf(WordEqual(value, IntPtrConstant(0)), if_cleared); 597 } 598 return value; 599 } 600 AllocateUninitializedFixedArray(Node * length)601 Node* CodeStubAssembler::AllocateUninitializedFixedArray(Node* length) { 602 Node* header_size = IntPtrConstant(FixedArray::kHeaderSize); 603 Node* data_size = WordShl(length, IntPtrConstant(kPointerSizeLog2)); 604 Node* total_size = IntPtrAdd(data_size, header_size); 605 606 Node* result = Allocate(total_size, kNone); 607 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kFixedArrayMapRootIndex)); 608 StoreObjectFieldNoWriteBarrier(result, FixedArray::kLengthOffset, 609 SmiTag(length)); 610 611 return result; 612 } 613 LoadFixedArrayElement(Node * object,Node * index_node,int additional_offset,ParameterMode parameter_mode)614 Node* CodeStubAssembler::LoadFixedArrayElement(Node* object, Node* index_node, 615 int additional_offset, 616 ParameterMode parameter_mode) { 617 int32_t header_size = 618 FixedArray::kHeaderSize + additional_offset - kHeapObjectTag; 619 Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_ELEMENTS, 620 parameter_mode, header_size); 621 return Load(MachineType::AnyTagged(), object, offset); 622 } 623 LoadFixedDoubleArrayElement(Node * object,Node * index_node,MachineType machine_type,int additional_offset,ParameterMode parameter_mode)624 Node* CodeStubAssembler::LoadFixedDoubleArrayElement( 625 Node* object, Node* index_node, MachineType machine_type, 626 int additional_offset, ParameterMode parameter_mode) { 627 int32_t header_size = 628 FixedDoubleArray::kHeaderSize + additional_offset - kHeapObjectTag; 629 Node* offset = ElementOffsetFromIndex(index_node, FAST_HOLEY_DOUBLE_ELEMENTS, 630 parameter_mode, header_size); 631 return Load(machine_type, object, offset); 632 } 633 LoadNativeContext(Node * context)634 Node* CodeStubAssembler::LoadNativeContext(Node* context) { 635 return LoadFixedArrayElement(context, 636 Int32Constant(Context::NATIVE_CONTEXT_INDEX)); 637 } 638 LoadJSArrayElementsMap(ElementsKind kind,Node * native_context)639 Node* CodeStubAssembler::LoadJSArrayElementsMap(ElementsKind kind, 640 Node* native_context) { 641 return LoadFixedArrayElement(native_context, 642 Int32Constant(Context::ArrayMapIndex(kind))); 643 } 644 StoreHeapNumberValue(Node * object,Node * value)645 Node* CodeStubAssembler::StoreHeapNumberValue(Node* object, Node* value) { 646 return StoreNoWriteBarrier( 647 MachineRepresentation::kFloat64, object, 648 IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag), value); 649 } 650 StoreObjectField(Node * object,int offset,Node * value)651 Node* CodeStubAssembler::StoreObjectField( 652 Node* object, int offset, Node* value) { 653 return Store(MachineRepresentation::kTagged, object, 654 IntPtrConstant(offset - kHeapObjectTag), value); 655 } 656 StoreObjectFieldNoWriteBarrier(Node * object,int offset,Node * value,MachineRepresentation rep)657 Node* CodeStubAssembler::StoreObjectFieldNoWriteBarrier( 658 Node* object, int offset, Node* value, MachineRepresentation rep) { 659 return StoreNoWriteBarrier(rep, object, 660 IntPtrConstant(offset - kHeapObjectTag), value); 661 } 662 StoreMapNoWriteBarrier(Node * object,Node * map)663 Node* CodeStubAssembler::StoreMapNoWriteBarrier(Node* object, Node* map) { 664 return StoreNoWriteBarrier( 665 MachineRepresentation::kTagged, object, 666 IntPtrConstant(HeapNumber::kMapOffset - kHeapObjectTag), map); 667 } 668 StoreFixedArrayElement(Node * object,Node * index_node,Node * value,WriteBarrierMode barrier_mode,ParameterMode parameter_mode)669 Node* CodeStubAssembler::StoreFixedArrayElement(Node* object, Node* index_node, 670 Node* value, 671 WriteBarrierMode barrier_mode, 672 ParameterMode parameter_mode) { 673 DCHECK(barrier_mode == SKIP_WRITE_BARRIER || 674 barrier_mode == UPDATE_WRITE_BARRIER); 675 Node* offset = 676 ElementOffsetFromIndex(index_node, FAST_HOLEY_ELEMENTS, parameter_mode, 677 FixedArray::kHeaderSize - kHeapObjectTag); 678 MachineRepresentation rep = MachineRepresentation::kTagged; 679 if (barrier_mode == SKIP_WRITE_BARRIER) { 680 return StoreNoWriteBarrier(rep, object, offset, value); 681 } else { 682 return Store(rep, object, offset, value); 683 } 684 } 685 StoreFixedDoubleArrayElement(Node * object,Node * index_node,Node * value,ParameterMode parameter_mode)686 Node* CodeStubAssembler::StoreFixedDoubleArrayElement( 687 Node* object, Node* index_node, Node* value, ParameterMode parameter_mode) { 688 Node* offset = 689 ElementOffsetFromIndex(index_node, FAST_DOUBLE_ELEMENTS, parameter_mode, 690 FixedArray::kHeaderSize - kHeapObjectTag); 691 MachineRepresentation rep = MachineRepresentation::kFloat64; 692 return StoreNoWriteBarrier(rep, object, offset, value); 693 } 694 AllocateHeapNumber()695 Node* CodeStubAssembler::AllocateHeapNumber() { 696 Node* result = Allocate(HeapNumber::kSize, kNone); 697 StoreMapNoWriteBarrier(result, HeapNumberMapConstant()); 698 return result; 699 } 700 AllocateHeapNumberWithValue(Node * value)701 Node* CodeStubAssembler::AllocateHeapNumberWithValue(Node* value) { 702 Node* result = AllocateHeapNumber(); 703 StoreHeapNumberValue(result, value); 704 return result; 705 } 706 AllocateSeqOneByteString(int length)707 Node* CodeStubAssembler::AllocateSeqOneByteString(int length) { 708 Node* result = Allocate(SeqOneByteString::SizeFor(length)); 709 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kOneByteStringMapRootIndex)); 710 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset, 711 SmiConstant(Smi::FromInt(length))); 712 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldOffset, 713 IntPtrConstant(String::kEmptyHashField), 714 MachineRepresentation::kWord32); 715 return result; 716 } 717 AllocateSeqOneByteString(Node * context,Node * length)718 Node* CodeStubAssembler::AllocateSeqOneByteString(Node* context, Node* length) { 719 Variable var_result(this, MachineRepresentation::kTagged); 720 721 // Compute the SeqOneByteString size and check if it fits into new space. 722 Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), 723 if_join(this); 724 Node* size = WordAnd( 725 IntPtrAdd( 726 IntPtrAdd(length, IntPtrConstant(SeqOneByteString::kHeaderSize)), 727 IntPtrConstant(kObjectAlignmentMask)), 728 IntPtrConstant(~kObjectAlignmentMask)); 729 Branch(IntPtrLessThanOrEqual(size, 730 IntPtrConstant(Page::kMaxRegularHeapObjectSize)), 731 &if_sizeissmall, &if_notsizeissmall); 732 733 Bind(&if_sizeissmall); 734 { 735 // Just allocate the SeqOneByteString in new space. 736 Node* result = Allocate(size); 737 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kOneByteStringMapRootIndex)); 738 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kLengthOffset, 739 SmiFromWord(length)); 740 StoreObjectFieldNoWriteBarrier(result, SeqOneByteString::kHashFieldOffset, 741 IntPtrConstant(String::kEmptyHashField), 742 MachineRepresentation::kWord32); 743 var_result.Bind(result); 744 Goto(&if_join); 745 } 746 747 Bind(&if_notsizeissmall); 748 { 749 // We might need to allocate in large object space, go to the runtime. 750 Node* result = CallRuntime(Runtime::kAllocateSeqOneByteString, context, 751 SmiFromWord(length)); 752 var_result.Bind(result); 753 Goto(&if_join); 754 } 755 756 Bind(&if_join); 757 return var_result.value(); 758 } 759 AllocateSeqTwoByteString(int length)760 Node* CodeStubAssembler::AllocateSeqTwoByteString(int length) { 761 Node* result = Allocate(SeqTwoByteString::SizeFor(length)); 762 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kStringMapRootIndex)); 763 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset, 764 SmiConstant(Smi::FromInt(length))); 765 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldOffset, 766 IntPtrConstant(String::kEmptyHashField), 767 MachineRepresentation::kWord32); 768 return result; 769 } 770 AllocateSeqTwoByteString(Node * context,Node * length)771 Node* CodeStubAssembler::AllocateSeqTwoByteString(Node* context, Node* length) { 772 Variable var_result(this, MachineRepresentation::kTagged); 773 774 // Compute the SeqTwoByteString size and check if it fits into new space. 775 Label if_sizeissmall(this), if_notsizeissmall(this, Label::kDeferred), 776 if_join(this); 777 Node* size = WordAnd( 778 IntPtrAdd(IntPtrAdd(WordShl(length, 1), 779 IntPtrConstant(SeqTwoByteString::kHeaderSize)), 780 IntPtrConstant(kObjectAlignmentMask)), 781 IntPtrConstant(~kObjectAlignmentMask)); 782 Branch(IntPtrLessThanOrEqual(size, 783 IntPtrConstant(Page::kMaxRegularHeapObjectSize)), 784 &if_sizeissmall, &if_notsizeissmall); 785 786 Bind(&if_sizeissmall); 787 { 788 // Just allocate the SeqTwoByteString in new space. 789 Node* result = Allocate(size); 790 StoreMapNoWriteBarrier(result, LoadRoot(Heap::kStringMapRootIndex)); 791 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kLengthOffset, 792 SmiFromWord(length)); 793 StoreObjectFieldNoWriteBarrier(result, SeqTwoByteString::kHashFieldOffset, 794 IntPtrConstant(String::kEmptyHashField), 795 MachineRepresentation::kWord32); 796 var_result.Bind(result); 797 Goto(&if_join); 798 } 799 800 Bind(&if_notsizeissmall); 801 { 802 // We might need to allocate in large object space, go to the runtime. 803 Node* result = CallRuntime(Runtime::kAllocateSeqTwoByteString, context, 804 SmiFromWord(length)); 805 var_result.Bind(result); 806 Goto(&if_join); 807 } 808 809 Bind(&if_join); 810 return var_result.value(); 811 } 812 AllocateJSArray(ElementsKind kind,Node * array_map,Node * capacity_node,Node * length_node,compiler::Node * allocation_site,ParameterMode mode)813 Node* CodeStubAssembler::AllocateJSArray(ElementsKind kind, Node* array_map, 814 Node* capacity_node, Node* length_node, 815 compiler::Node* allocation_site, 816 ParameterMode mode) { 817 bool is_double = IsFastDoubleElementsKind(kind); 818 int base_size = JSArray::kSize + FixedArray::kHeaderSize; 819 int elements_offset = JSArray::kSize; 820 821 Comment("begin allocation of JSArray"); 822 823 if (allocation_site != nullptr) { 824 base_size += AllocationMemento::kSize; 825 elements_offset += AllocationMemento::kSize; 826 } 827 828 int32_t capacity; 829 bool constant_capacity = ToInt32Constant(capacity_node, capacity); 830 Node* total_size = 831 ElementOffsetFromIndex(capacity_node, kind, mode, base_size); 832 833 // Allocate both array and elements object, and initialize the JSArray. 834 Heap* heap = isolate()->heap(); 835 Node* array = Allocate(total_size); 836 StoreMapNoWriteBarrier(array, array_map); 837 Node* empty_properties = 838 HeapConstant(Handle<HeapObject>(heap->empty_fixed_array())); 839 StoreObjectFieldNoWriteBarrier(array, JSArray::kPropertiesOffset, 840 empty_properties); 841 StoreObjectFieldNoWriteBarrier( 842 array, JSArray::kLengthOffset, 843 mode == SMI_PARAMETERS ? length_node : SmiTag(length_node)); 844 845 if (allocation_site != nullptr) { 846 InitializeAllocationMemento(array, JSArray::kSize, allocation_site); 847 } 848 849 // Setup elements object. 850 Node* elements = InnerAllocate(array, elements_offset); 851 StoreObjectFieldNoWriteBarrier(array, JSArray::kElementsOffset, elements); 852 Handle<Map> elements_map(is_double ? heap->fixed_double_array_map() 853 : heap->fixed_array_map()); 854 StoreMapNoWriteBarrier(elements, HeapConstant(elements_map)); 855 StoreObjectFieldNoWriteBarrier( 856 elements, FixedArray::kLengthOffset, 857 mode == SMI_PARAMETERS ? capacity_node : SmiTag(capacity_node)); 858 859 int const first_element_offset = FixedArray::kHeaderSize - kHeapObjectTag; 860 Node* hole = HeapConstant(Handle<HeapObject>(heap->the_hole_value())); 861 Node* double_hole = 862 Is64() ? Int64Constant(kHoleNanInt64) : Int32Constant(kHoleNanLower32); 863 DCHECK_EQ(kHoleNanLower32, kHoleNanUpper32); 864 if (constant_capacity && capacity <= kElementLoopUnrollThreshold) { 865 for (int i = 0; i < capacity; ++i) { 866 if (is_double) { 867 Node* offset = ElementOffsetFromIndex(Int32Constant(i), kind, mode, 868 first_element_offset); 869 // Don't use doubles to store the hole double, since manipulating the 870 // signaling NaN used for the hole in C++, e.g. with bit_cast, will 871 // change its value on ia32 (the x87 stack is used to return values 872 // and stores to the stack silently clear the signalling bit). 873 // 874 // TODO(danno): When we have a Float32/Float64 wrapper class that 875 // preserves double bits during manipulation, remove this code/change 876 // this to an indexed Float64 store. 877 if (Is64()) { 878 StoreNoWriteBarrier(MachineRepresentation::kWord64, elements, offset, 879 double_hole); 880 } else { 881 StoreNoWriteBarrier(MachineRepresentation::kWord32, elements, offset, 882 double_hole); 883 offset = ElementOffsetFromIndex(Int32Constant(i), kind, mode, 884 first_element_offset + kPointerSize); 885 StoreNoWriteBarrier(MachineRepresentation::kWord32, elements, offset, 886 double_hole); 887 } 888 } else { 889 StoreFixedArrayElement(elements, Int32Constant(i), hole, 890 SKIP_WRITE_BARRIER); 891 } 892 } 893 } else { 894 Variable current(this, MachineRepresentation::kTagged); 895 Label test(this); 896 Label decrement(this, ¤t); 897 Label done(this); 898 Node* limit = IntPtrAdd(elements, IntPtrConstant(first_element_offset)); 899 current.Bind( 900 IntPtrAdd(limit, ElementOffsetFromIndex(capacity_node, kind, mode, 0))); 901 902 Branch(WordEqual(current.value(), limit), &done, &decrement); 903 904 Bind(&decrement); 905 current.Bind(IntPtrSub( 906 current.value(), 907 Int32Constant(IsFastDoubleElementsKind(kind) ? kDoubleSize 908 : kPointerSize))); 909 if (is_double) { 910 // Don't use doubles to store the hole double, since manipulating the 911 // signaling NaN used for the hole in C++, e.g. with bit_cast, will 912 // change its value on ia32 (the x87 stack is used to return values 913 // and stores to the stack silently clear the signalling bit). 914 // 915 // TODO(danno): When we have a Float32/Float64 wrapper class that 916 // preserves double bits during manipulation, remove this code/change 917 // this to an indexed Float64 store. 918 if (Is64()) { 919 StoreNoWriteBarrier(MachineRepresentation::kWord64, current.value(), 920 double_hole); 921 } else { 922 StoreNoWriteBarrier(MachineRepresentation::kWord32, current.value(), 923 double_hole); 924 StoreNoWriteBarrier( 925 MachineRepresentation::kWord32, 926 IntPtrAdd(current.value(), Int32Constant(kPointerSize)), 927 double_hole); 928 } 929 } else { 930 StoreNoWriteBarrier(MachineRepresentation::kTagged, current.value(), 931 hole); 932 } 933 Node* compare = WordNotEqual(current.value(), limit); 934 Branch(compare, &decrement, &done); 935 936 Bind(&done); 937 } 938 939 return array; 940 } 941 InitializeAllocationMemento(compiler::Node * base_allocation,int base_allocation_size,compiler::Node * allocation_site)942 void CodeStubAssembler::InitializeAllocationMemento( 943 compiler::Node* base_allocation, int base_allocation_size, 944 compiler::Node* allocation_site) { 945 StoreObjectFieldNoWriteBarrier( 946 base_allocation, AllocationMemento::kMapOffset + base_allocation_size, 947 HeapConstant(Handle<Map>(isolate()->heap()->allocation_memento_map()))); 948 StoreObjectFieldNoWriteBarrier( 949 base_allocation, 950 AllocationMemento::kAllocationSiteOffset + base_allocation_size, 951 allocation_site); 952 if (FLAG_allocation_site_pretenuring) { 953 Node* count = LoadObjectField(allocation_site, 954 AllocationSite::kPretenureCreateCountOffset); 955 Node* incremented_count = IntPtrAdd(count, SmiConstant(Smi::FromInt(1))); 956 StoreObjectFieldNoWriteBarrier(allocation_site, 957 AllocationSite::kPretenureCreateCountOffset, 958 incremented_count); 959 } 960 } 961 TruncateTaggedToFloat64(Node * context,Node * value)962 Node* CodeStubAssembler::TruncateTaggedToFloat64(Node* context, Node* value) { 963 // We might need to loop once due to ToNumber conversion. 964 Variable var_value(this, MachineRepresentation::kTagged), 965 var_result(this, MachineRepresentation::kFloat64); 966 Label loop(this, &var_value), done_loop(this, &var_result); 967 var_value.Bind(value); 968 Goto(&loop); 969 Bind(&loop); 970 { 971 // Load the current {value}. 972 value = var_value.value(); 973 974 // Check if the {value} is a Smi or a HeapObject. 975 Label if_valueissmi(this), if_valueisnotsmi(this); 976 Branch(WordIsSmi(value), &if_valueissmi, &if_valueisnotsmi); 977 978 Bind(&if_valueissmi); 979 { 980 // Convert the Smi {value}. 981 var_result.Bind(SmiToFloat64(value)); 982 Goto(&done_loop); 983 } 984 985 Bind(&if_valueisnotsmi); 986 { 987 // Check if {value} is a HeapNumber. 988 Label if_valueisheapnumber(this), 989 if_valueisnotheapnumber(this, Label::kDeferred); 990 Branch(WordEqual(LoadMap(value), HeapNumberMapConstant()), 991 &if_valueisheapnumber, &if_valueisnotheapnumber); 992 993 Bind(&if_valueisheapnumber); 994 { 995 // Load the floating point value. 996 var_result.Bind(LoadHeapNumberValue(value)); 997 Goto(&done_loop); 998 } 999 1000 Bind(&if_valueisnotheapnumber); 1001 { 1002 // Convert the {value} to a Number first. 1003 Callable callable = CodeFactory::NonNumberToNumber(isolate()); 1004 var_value.Bind(CallStub(callable, context, value)); 1005 Goto(&loop); 1006 } 1007 } 1008 } 1009 Bind(&done_loop); 1010 return var_result.value(); 1011 } 1012 TruncateTaggedToWord32(Node * context,Node * value)1013 Node* CodeStubAssembler::TruncateTaggedToWord32(Node* context, Node* value) { 1014 // We might need to loop once due to ToNumber conversion. 1015 Variable var_value(this, MachineRepresentation::kTagged), 1016 var_result(this, MachineRepresentation::kWord32); 1017 Label loop(this, &var_value), done_loop(this, &var_result); 1018 var_value.Bind(value); 1019 Goto(&loop); 1020 Bind(&loop); 1021 { 1022 // Load the current {value}. 1023 value = var_value.value(); 1024 1025 // Check if the {value} is a Smi or a HeapObject. 1026 Label if_valueissmi(this), if_valueisnotsmi(this); 1027 Branch(WordIsSmi(value), &if_valueissmi, &if_valueisnotsmi); 1028 1029 Bind(&if_valueissmi); 1030 { 1031 // Convert the Smi {value}. 1032 var_result.Bind(SmiToWord32(value)); 1033 Goto(&done_loop); 1034 } 1035 1036 Bind(&if_valueisnotsmi); 1037 { 1038 // Check if {value} is a HeapNumber. 1039 Label if_valueisheapnumber(this), 1040 if_valueisnotheapnumber(this, Label::kDeferred); 1041 Branch(WordEqual(LoadMap(value), HeapNumberMapConstant()), 1042 &if_valueisheapnumber, &if_valueisnotheapnumber); 1043 1044 Bind(&if_valueisheapnumber); 1045 { 1046 // Truncate the floating point value. 1047 var_result.Bind(TruncateHeapNumberValueToWord32(value)); 1048 Goto(&done_loop); 1049 } 1050 1051 Bind(&if_valueisnotheapnumber); 1052 { 1053 // Convert the {value} to a Number first. 1054 Callable callable = CodeFactory::NonNumberToNumber(isolate()); 1055 var_value.Bind(CallStub(callable, context, value)); 1056 Goto(&loop); 1057 } 1058 } 1059 } 1060 Bind(&done_loop); 1061 return var_result.value(); 1062 } 1063 TruncateHeapNumberValueToWord32(Node * object)1064 Node* CodeStubAssembler::TruncateHeapNumberValueToWord32(Node* object) { 1065 Node* value = LoadHeapNumberValue(object); 1066 return TruncateFloat64ToWord32(value); 1067 } 1068 ChangeFloat64ToTagged(Node * value)1069 Node* CodeStubAssembler::ChangeFloat64ToTagged(Node* value) { 1070 Node* value32 = RoundFloat64ToInt32(value); 1071 Node* value64 = ChangeInt32ToFloat64(value32); 1072 1073 Label if_valueisint32(this), if_valueisheapnumber(this), if_join(this); 1074 1075 Label if_valueisequal(this), if_valueisnotequal(this); 1076 Branch(Float64Equal(value, value64), &if_valueisequal, &if_valueisnotequal); 1077 Bind(&if_valueisequal); 1078 { 1079 GotoUnless(Word32Equal(value32, Int32Constant(0)), &if_valueisint32); 1080 BranchIfInt32LessThan(Float64ExtractHighWord32(value), Int32Constant(0), 1081 &if_valueisheapnumber, &if_valueisint32); 1082 } 1083 Bind(&if_valueisnotequal); 1084 Goto(&if_valueisheapnumber); 1085 1086 Variable var_result(this, MachineRepresentation::kTagged); 1087 Bind(&if_valueisint32); 1088 { 1089 if (Is64()) { 1090 Node* result = SmiTag(ChangeInt32ToInt64(value32)); 1091 var_result.Bind(result); 1092 Goto(&if_join); 1093 } else { 1094 Node* pair = Int32AddWithOverflow(value32, value32); 1095 Node* overflow = Projection(1, pair); 1096 Label if_overflow(this, Label::kDeferred), if_notoverflow(this); 1097 Branch(overflow, &if_overflow, &if_notoverflow); 1098 Bind(&if_overflow); 1099 Goto(&if_valueisheapnumber); 1100 Bind(&if_notoverflow); 1101 { 1102 Node* result = Projection(0, pair); 1103 var_result.Bind(result); 1104 Goto(&if_join); 1105 } 1106 } 1107 } 1108 Bind(&if_valueisheapnumber); 1109 { 1110 Node* result = AllocateHeapNumberWithValue(value); 1111 var_result.Bind(result); 1112 Goto(&if_join); 1113 } 1114 Bind(&if_join); 1115 return var_result.value(); 1116 } 1117 ChangeInt32ToTagged(Node * value)1118 Node* CodeStubAssembler::ChangeInt32ToTagged(Node* value) { 1119 if (Is64()) { 1120 return SmiTag(ChangeInt32ToInt64(value)); 1121 } 1122 Variable var_result(this, MachineRepresentation::kTagged); 1123 Node* pair = Int32AddWithOverflow(value, value); 1124 Node* overflow = Projection(1, pair); 1125 Label if_overflow(this, Label::kDeferred), if_notoverflow(this), 1126 if_join(this); 1127 Branch(overflow, &if_overflow, &if_notoverflow); 1128 Bind(&if_overflow); 1129 { 1130 Node* value64 = ChangeInt32ToFloat64(value); 1131 Node* result = AllocateHeapNumberWithValue(value64); 1132 var_result.Bind(result); 1133 } 1134 Goto(&if_join); 1135 Bind(&if_notoverflow); 1136 { 1137 Node* result = Projection(0, pair); 1138 var_result.Bind(result); 1139 } 1140 Goto(&if_join); 1141 Bind(&if_join); 1142 return var_result.value(); 1143 } 1144 ChangeUint32ToTagged(Node * value)1145 Node* CodeStubAssembler::ChangeUint32ToTagged(Node* value) { 1146 Label if_overflow(this, Label::kDeferred), if_not_overflow(this), 1147 if_join(this); 1148 Variable var_result(this, MachineRepresentation::kTagged); 1149 // If {value} > 2^31 - 1, we need to store it in a HeapNumber. 1150 Branch(Int32LessThan(value, Int32Constant(0)), &if_overflow, 1151 &if_not_overflow); 1152 Bind(&if_not_overflow); 1153 { 1154 if (Is64()) { 1155 var_result.Bind(SmiTag(ChangeUint32ToUint64(value))); 1156 } else { 1157 // If tagging {value} results in an overflow, we need to use a HeapNumber 1158 // to represent it. 1159 Node* pair = Int32AddWithOverflow(value, value); 1160 Node* overflow = Projection(1, pair); 1161 GotoIf(overflow, &if_overflow); 1162 1163 Node* result = Projection(0, pair); 1164 var_result.Bind(result); 1165 } 1166 } 1167 Goto(&if_join); 1168 1169 Bind(&if_overflow); 1170 { 1171 Node* float64_value = ChangeUint32ToFloat64(value); 1172 var_result.Bind(AllocateHeapNumberWithValue(float64_value)); 1173 } 1174 Goto(&if_join); 1175 1176 Bind(&if_join); 1177 return var_result.value(); 1178 } 1179 ToThisString(Node * context,Node * value,char const * method_name)1180 Node* CodeStubAssembler::ToThisString(Node* context, Node* value, 1181 char const* method_name) { 1182 Variable var_value(this, MachineRepresentation::kTagged); 1183 var_value.Bind(value); 1184 1185 // Check if the {value} is a Smi or a HeapObject. 1186 Label if_valueissmi(this, Label::kDeferred), if_valueisnotsmi(this), 1187 if_valueisstring(this); 1188 Branch(WordIsSmi(value), &if_valueissmi, &if_valueisnotsmi); 1189 Bind(&if_valueisnotsmi); 1190 { 1191 // Load the instance type of the {value}. 1192 Node* value_instance_type = LoadInstanceType(value); 1193 1194 // Check if the {value} is already String. 1195 Label if_valueisnotstring(this, Label::kDeferred); 1196 Branch( 1197 Int32LessThan(value_instance_type, Int32Constant(FIRST_NONSTRING_TYPE)), 1198 &if_valueisstring, &if_valueisnotstring); 1199 Bind(&if_valueisnotstring); 1200 { 1201 // Check if the {value} is null. 1202 Label if_valueisnullorundefined(this, Label::kDeferred), 1203 if_valueisnotnullorundefined(this, Label::kDeferred), 1204 if_valueisnotnull(this, Label::kDeferred); 1205 Branch(WordEqual(value, NullConstant()), &if_valueisnullorundefined, 1206 &if_valueisnotnull); 1207 Bind(&if_valueisnotnull); 1208 { 1209 // Check if the {value} is undefined. 1210 Branch(WordEqual(value, UndefinedConstant()), 1211 &if_valueisnullorundefined, &if_valueisnotnullorundefined); 1212 Bind(&if_valueisnotnullorundefined); 1213 { 1214 // Convert the {value} to a String. 1215 Callable callable = CodeFactory::ToString(isolate()); 1216 var_value.Bind(CallStub(callable, context, value)); 1217 Goto(&if_valueisstring); 1218 } 1219 } 1220 1221 Bind(&if_valueisnullorundefined); 1222 { 1223 // The {value} is either null or undefined. 1224 CallRuntime(Runtime::kThrowCalledOnNullOrUndefined, context, 1225 HeapConstant(factory()->NewStringFromAsciiChecked( 1226 method_name, TENURED))); 1227 Goto(&if_valueisstring); // Never reached. 1228 } 1229 } 1230 } 1231 Bind(&if_valueissmi); 1232 { 1233 // The {value} is a Smi, convert it to a String. 1234 Callable callable = CodeFactory::NumberToString(isolate()); 1235 var_value.Bind(CallStub(callable, context, value)); 1236 Goto(&if_valueisstring); 1237 } 1238 Bind(&if_valueisstring); 1239 return var_value.value(); 1240 } 1241 StringCharCodeAt(Node * string,Node * index)1242 Node* CodeStubAssembler::StringCharCodeAt(Node* string, Node* index) { 1243 // Translate the {index} into a Word. 1244 index = SmiToWord(index); 1245 1246 // We may need to loop in case of cons or sliced strings. 1247 Variable var_index(this, MachineType::PointerRepresentation()); 1248 Variable var_result(this, MachineRepresentation::kWord32); 1249 Variable var_string(this, MachineRepresentation::kTagged); 1250 Variable* loop_vars[] = {&var_index, &var_string}; 1251 Label done_loop(this, &var_result), loop(this, 2, loop_vars); 1252 var_string.Bind(string); 1253 var_index.Bind(index); 1254 Goto(&loop); 1255 Bind(&loop); 1256 { 1257 // Load the current {index}. 1258 index = var_index.value(); 1259 1260 // Load the current {string}. 1261 string = var_string.value(); 1262 1263 // Load the instance type of the {string}. 1264 Node* string_instance_type = LoadInstanceType(string); 1265 1266 // Check if the {string} is a SeqString. 1267 Label if_stringissequential(this), if_stringisnotsequential(this); 1268 Branch(Word32Equal(Word32And(string_instance_type, 1269 Int32Constant(kStringRepresentationMask)), 1270 Int32Constant(kSeqStringTag)), 1271 &if_stringissequential, &if_stringisnotsequential); 1272 1273 Bind(&if_stringissequential); 1274 { 1275 // Check if the {string} is a TwoByteSeqString or a OneByteSeqString. 1276 Label if_stringistwobyte(this), if_stringisonebyte(this); 1277 Branch(Word32Equal(Word32And(string_instance_type, 1278 Int32Constant(kStringEncodingMask)), 1279 Int32Constant(kTwoByteStringTag)), 1280 &if_stringistwobyte, &if_stringisonebyte); 1281 1282 Bind(&if_stringisonebyte); 1283 { 1284 var_result.Bind( 1285 Load(MachineType::Uint8(), string, 1286 IntPtrAdd(index, IntPtrConstant(SeqOneByteString::kHeaderSize - 1287 kHeapObjectTag)))); 1288 Goto(&done_loop); 1289 } 1290 1291 Bind(&if_stringistwobyte); 1292 { 1293 var_result.Bind( 1294 Load(MachineType::Uint16(), string, 1295 IntPtrAdd(WordShl(index, IntPtrConstant(1)), 1296 IntPtrConstant(SeqTwoByteString::kHeaderSize - 1297 kHeapObjectTag)))); 1298 Goto(&done_loop); 1299 } 1300 } 1301 1302 Bind(&if_stringisnotsequential); 1303 { 1304 // Check if the {string} is a ConsString. 1305 Label if_stringiscons(this), if_stringisnotcons(this); 1306 Branch(Word32Equal(Word32And(string_instance_type, 1307 Int32Constant(kStringRepresentationMask)), 1308 Int32Constant(kConsStringTag)), 1309 &if_stringiscons, &if_stringisnotcons); 1310 1311 Bind(&if_stringiscons); 1312 { 1313 // Check whether the right hand side is the empty string (i.e. if 1314 // this is really a flat string in a cons string). If that is not 1315 // the case we flatten the string first. 1316 Label if_rhsisempty(this), if_rhsisnotempty(this, Label::kDeferred); 1317 Node* rhs = LoadObjectField(string, ConsString::kSecondOffset); 1318 Branch(WordEqual(rhs, EmptyStringConstant()), &if_rhsisempty, 1319 &if_rhsisnotempty); 1320 1321 Bind(&if_rhsisempty); 1322 { 1323 // Just operate on the left hand side of the {string}. 1324 var_string.Bind(LoadObjectField(string, ConsString::kFirstOffset)); 1325 Goto(&loop); 1326 } 1327 1328 Bind(&if_rhsisnotempty); 1329 { 1330 // Flatten the {string} and lookup in the resulting string. 1331 var_string.Bind(CallRuntime(Runtime::kFlattenString, 1332 NoContextConstant(), string)); 1333 Goto(&loop); 1334 } 1335 } 1336 1337 Bind(&if_stringisnotcons); 1338 { 1339 // Check if the {string} is an ExternalString. 1340 Label if_stringisexternal(this), if_stringisnotexternal(this); 1341 Branch(Word32Equal(Word32And(string_instance_type, 1342 Int32Constant(kStringRepresentationMask)), 1343 Int32Constant(kExternalStringTag)), 1344 &if_stringisexternal, &if_stringisnotexternal); 1345 1346 Bind(&if_stringisexternal); 1347 { 1348 // Check if the {string} is a short external string. 1349 Label if_stringisshort(this), 1350 if_stringisnotshort(this, Label::kDeferred); 1351 Branch(Word32Equal(Word32And(string_instance_type, 1352 Int32Constant(kShortExternalStringMask)), 1353 Int32Constant(0)), 1354 &if_stringisshort, &if_stringisnotshort); 1355 1356 Bind(&if_stringisshort); 1357 { 1358 // Load the actual resource data from the {string}. 1359 Node* string_resource_data = 1360 LoadObjectField(string, ExternalString::kResourceDataOffset, 1361 MachineType::Pointer()); 1362 1363 // Check if the {string} is a TwoByteExternalString or a 1364 // OneByteExternalString. 1365 Label if_stringistwobyte(this), if_stringisonebyte(this); 1366 Branch(Word32Equal(Word32And(string_instance_type, 1367 Int32Constant(kStringEncodingMask)), 1368 Int32Constant(kTwoByteStringTag)), 1369 &if_stringistwobyte, &if_stringisonebyte); 1370 1371 Bind(&if_stringisonebyte); 1372 { 1373 var_result.Bind( 1374 Load(MachineType::Uint8(), string_resource_data, index)); 1375 Goto(&done_loop); 1376 } 1377 1378 Bind(&if_stringistwobyte); 1379 { 1380 var_result.Bind(Load(MachineType::Uint16(), string_resource_data, 1381 WordShl(index, IntPtrConstant(1)))); 1382 Goto(&done_loop); 1383 } 1384 } 1385 1386 Bind(&if_stringisnotshort); 1387 { 1388 // The {string} might be compressed, call the runtime. 1389 var_result.Bind(SmiToWord32( 1390 CallRuntime(Runtime::kExternalStringGetChar, 1391 NoContextConstant(), string, SmiTag(index)))); 1392 Goto(&done_loop); 1393 } 1394 } 1395 1396 Bind(&if_stringisnotexternal); 1397 { 1398 // The {string} is a SlicedString, continue with its parent. 1399 Node* string_offset = 1400 SmiToWord(LoadObjectField(string, SlicedString::kOffsetOffset)); 1401 Node* string_parent = 1402 LoadObjectField(string, SlicedString::kParentOffset); 1403 var_index.Bind(IntPtrAdd(index, string_offset)); 1404 var_string.Bind(string_parent); 1405 Goto(&loop); 1406 } 1407 } 1408 } 1409 } 1410 1411 Bind(&done_loop); 1412 return var_result.value(); 1413 } 1414 StringFromCharCode(Node * code)1415 Node* CodeStubAssembler::StringFromCharCode(Node* code) { 1416 Variable var_result(this, MachineRepresentation::kTagged); 1417 1418 // Check if the {code} is a one-byte char code. 1419 Label if_codeisonebyte(this), if_codeistwobyte(this, Label::kDeferred), 1420 if_done(this); 1421 Branch(Int32LessThanOrEqual(code, Int32Constant(String::kMaxOneByteCharCode)), 1422 &if_codeisonebyte, &if_codeistwobyte); 1423 Bind(&if_codeisonebyte); 1424 { 1425 // Load the isolate wide single character string cache. 1426 Node* cache = LoadRoot(Heap::kSingleCharacterStringCacheRootIndex); 1427 1428 // Check if we have an entry for the {code} in the single character string 1429 // cache already. 1430 Label if_entryisundefined(this, Label::kDeferred), 1431 if_entryisnotundefined(this); 1432 Node* entry = LoadFixedArrayElement(cache, code); 1433 Branch(WordEqual(entry, UndefinedConstant()), &if_entryisundefined, 1434 &if_entryisnotundefined); 1435 1436 Bind(&if_entryisundefined); 1437 { 1438 // Allocate a new SeqOneByteString for {code} and store it in the {cache}. 1439 Node* result = AllocateSeqOneByteString(1); 1440 StoreNoWriteBarrier( 1441 MachineRepresentation::kWord8, result, 1442 IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag), code); 1443 StoreFixedArrayElement(cache, code, result); 1444 var_result.Bind(result); 1445 Goto(&if_done); 1446 } 1447 1448 Bind(&if_entryisnotundefined); 1449 { 1450 // Return the entry from the {cache}. 1451 var_result.Bind(entry); 1452 Goto(&if_done); 1453 } 1454 } 1455 1456 Bind(&if_codeistwobyte); 1457 { 1458 // Allocate a new SeqTwoByteString for {code}. 1459 Node* result = AllocateSeqTwoByteString(1); 1460 StoreNoWriteBarrier( 1461 MachineRepresentation::kWord16, result, 1462 IntPtrConstant(SeqTwoByteString::kHeaderSize - kHeapObjectTag), code); 1463 var_result.Bind(result); 1464 Goto(&if_done); 1465 } 1466 1467 Bind(&if_done); 1468 return var_result.value(); 1469 } 1470 BitFieldDecode(Node * word32,uint32_t shift,uint32_t mask)1471 Node* CodeStubAssembler::BitFieldDecode(Node* word32, uint32_t shift, 1472 uint32_t mask) { 1473 return Word32Shr(Word32And(word32, Int32Constant(mask)), 1474 Int32Constant(shift)); 1475 } 1476 SetCounter(StatsCounter * counter,int value)1477 void CodeStubAssembler::SetCounter(StatsCounter* counter, int value) { 1478 if (FLAG_native_code_counters && counter->Enabled()) { 1479 Node* counter_address = ExternalConstant(ExternalReference(counter)); 1480 StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address, 1481 Int32Constant(value)); 1482 } 1483 } 1484 IncrementCounter(StatsCounter * counter,int delta)1485 void CodeStubAssembler::IncrementCounter(StatsCounter* counter, int delta) { 1486 DCHECK(delta > 0); 1487 if (FLAG_native_code_counters && counter->Enabled()) { 1488 Node* counter_address = ExternalConstant(ExternalReference(counter)); 1489 Node* value = Load(MachineType::Int32(), counter_address); 1490 value = Int32Add(value, Int32Constant(delta)); 1491 StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address, value); 1492 } 1493 } 1494 DecrementCounter(StatsCounter * counter,int delta)1495 void CodeStubAssembler::DecrementCounter(StatsCounter* counter, int delta) { 1496 DCHECK(delta > 0); 1497 if (FLAG_native_code_counters && counter->Enabled()) { 1498 Node* counter_address = ExternalConstant(ExternalReference(counter)); 1499 Node* value = Load(MachineType::Int32(), counter_address); 1500 value = Int32Sub(value, Int32Constant(delta)); 1501 StoreNoWriteBarrier(MachineRepresentation::kWord32, counter_address, value); 1502 } 1503 } 1504 TryToName(Node * key,Label * if_keyisindex,Variable * var_index,Label * if_keyisunique,Label * if_bailout)1505 void CodeStubAssembler::TryToName(Node* key, Label* if_keyisindex, 1506 Variable* var_index, Label* if_keyisunique, 1507 Label* if_bailout) { 1508 DCHECK_EQ(MachineRepresentation::kWord32, var_index->rep()); 1509 Comment("TryToName"); 1510 1511 Label if_keyissmi(this), if_keyisnotsmi(this); 1512 Branch(WordIsSmi(key), &if_keyissmi, &if_keyisnotsmi); 1513 Bind(&if_keyissmi); 1514 { 1515 // Negative smi keys are named properties. Handle in the runtime. 1516 GotoUnless(WordIsPositiveSmi(key), if_bailout); 1517 1518 var_index->Bind(SmiToWord32(key)); 1519 Goto(if_keyisindex); 1520 } 1521 1522 Bind(&if_keyisnotsmi); 1523 1524 Node* key_instance_type = LoadInstanceType(key); 1525 // Symbols are unique. 1526 GotoIf(Word32Equal(key_instance_type, Int32Constant(SYMBOL_TYPE)), 1527 if_keyisunique); 1528 1529 Label if_keyisinternalized(this); 1530 Node* bits = 1531 WordAnd(key_instance_type, 1532 Int32Constant(kIsNotStringMask | kIsNotInternalizedMask)); 1533 Branch(Word32Equal(bits, Int32Constant(kStringTag | kInternalizedTag)), 1534 &if_keyisinternalized, if_bailout); 1535 Bind(&if_keyisinternalized); 1536 1537 // Check whether the key is an array index passed in as string. Handle 1538 // uniform with smi keys if so. 1539 // TODO(verwaest): Also support non-internalized strings. 1540 Node* hash = LoadNameHashField(key); 1541 Node* bit = Word32And(hash, Int32Constant(Name::kIsNotArrayIndexMask)); 1542 GotoIf(Word32NotEqual(bit, Int32Constant(0)), if_keyisunique); 1543 // Key is an index. Check if it is small enough to be encoded in the 1544 // hash_field. Handle too big array index in runtime. 1545 bit = Word32And(hash, Int32Constant(Name::kContainsCachedArrayIndexMask)); 1546 GotoIf(Word32NotEqual(bit, Int32Constant(0)), if_bailout); 1547 var_index->Bind(BitFieldDecode<Name::ArrayIndexValueBits>(hash)); 1548 Goto(if_keyisindex); 1549 } 1550 1551 template <typename Dictionary> EntryToIndex(Node * entry,int field_index)1552 Node* CodeStubAssembler::EntryToIndex(Node* entry, int field_index) { 1553 Node* entry_index = Int32Mul(entry, Int32Constant(Dictionary::kEntrySize)); 1554 return Int32Add(entry_index, 1555 Int32Constant(Dictionary::kElementsStartIndex + field_index)); 1556 } 1557 1558 template <typename Dictionary> NameDictionaryLookup(Node * dictionary,Node * unique_name,Label * if_found,Variable * var_name_index,Label * if_not_found,int inlined_probes)1559 void CodeStubAssembler::NameDictionaryLookup(Node* dictionary, 1560 Node* unique_name, Label* if_found, 1561 Variable* var_name_index, 1562 Label* if_not_found, 1563 int inlined_probes) { 1564 DCHECK_EQ(MachineRepresentation::kWord32, var_name_index->rep()); 1565 Comment("NameDictionaryLookup"); 1566 1567 Node* capacity = SmiToWord32(LoadFixedArrayElement( 1568 dictionary, Int32Constant(Dictionary::kCapacityIndex))); 1569 Node* mask = Int32Sub(capacity, Int32Constant(1)); 1570 Node* hash = LoadNameHash(unique_name); 1571 1572 // See Dictionary::FirstProbe(). 1573 Node* count = Int32Constant(0); 1574 Node* entry = Word32And(hash, mask); 1575 1576 for (int i = 0; i < inlined_probes; i++) { 1577 Node* index = EntryToIndex<Dictionary>(entry); 1578 var_name_index->Bind(index); 1579 1580 Node* current = LoadFixedArrayElement(dictionary, index); 1581 GotoIf(WordEqual(current, unique_name), if_found); 1582 1583 // See Dictionary::NextProbe(). 1584 count = Int32Constant(i + 1); 1585 entry = Word32And(Int32Add(entry, count), mask); 1586 } 1587 1588 Node* undefined = UndefinedConstant(); 1589 1590 Variable var_count(this, MachineRepresentation::kWord32); 1591 Variable var_entry(this, MachineRepresentation::kWord32); 1592 Variable* loop_vars[] = {&var_count, &var_entry, var_name_index}; 1593 Label loop(this, 3, loop_vars); 1594 var_count.Bind(count); 1595 var_entry.Bind(entry); 1596 Goto(&loop); 1597 Bind(&loop); 1598 { 1599 Node* count = var_count.value(); 1600 Node* entry = var_entry.value(); 1601 1602 Node* index = EntryToIndex<Dictionary>(entry); 1603 var_name_index->Bind(index); 1604 1605 Node* current = LoadFixedArrayElement(dictionary, index); 1606 GotoIf(WordEqual(current, undefined), if_not_found); 1607 GotoIf(WordEqual(current, unique_name), if_found); 1608 1609 // See Dictionary::NextProbe(). 1610 count = Int32Add(count, Int32Constant(1)); 1611 entry = Word32And(Int32Add(entry, count), mask); 1612 1613 var_count.Bind(count); 1614 var_entry.Bind(entry); 1615 Goto(&loop); 1616 } 1617 } 1618 1619 // Instantiate template methods to workaround GCC compilation issue. 1620 template void CodeStubAssembler::NameDictionaryLookup<NameDictionary>( 1621 Node*, Node*, Label*, Variable*, Label*, int); 1622 template void CodeStubAssembler::NameDictionaryLookup<GlobalDictionary>( 1623 Node*, Node*, Label*, Variable*, Label*, int); 1624 ComputeIntegerHash(Node * key,Node * seed)1625 Node* CodeStubAssembler::ComputeIntegerHash(Node* key, Node* seed) { 1626 // See v8::internal::ComputeIntegerHash() 1627 Node* hash = key; 1628 hash = Word32Xor(hash, seed); 1629 hash = Int32Add(Word32Xor(hash, Int32Constant(0xffffffff)), 1630 Word32Shl(hash, Int32Constant(15))); 1631 hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(12))); 1632 hash = Int32Add(hash, Word32Shl(hash, Int32Constant(2))); 1633 hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(4))); 1634 hash = Int32Mul(hash, Int32Constant(2057)); 1635 hash = Word32Xor(hash, Word32Shr(hash, Int32Constant(16))); 1636 return Word32And(hash, Int32Constant(0x3fffffff)); 1637 } 1638 1639 template <typename Dictionary> NumberDictionaryLookup(Node * dictionary,Node * key,Label * if_found,Variable * var_entry,Label * if_not_found)1640 void CodeStubAssembler::NumberDictionaryLookup(Node* dictionary, Node* key, 1641 Label* if_found, 1642 Variable* var_entry, 1643 Label* if_not_found) { 1644 DCHECK_EQ(MachineRepresentation::kWord32, var_entry->rep()); 1645 Comment("NumberDictionaryLookup"); 1646 1647 Node* capacity = SmiToWord32(LoadFixedArrayElement( 1648 dictionary, Int32Constant(Dictionary::kCapacityIndex))); 1649 Node* mask = Int32Sub(capacity, Int32Constant(1)); 1650 1651 Node* seed; 1652 if (Dictionary::ShapeT::UsesSeed) { 1653 seed = HashSeed(); 1654 } else { 1655 seed = Int32Constant(kZeroHashSeed); 1656 } 1657 Node* hash = ComputeIntegerHash(key, seed); 1658 Node* key_as_float64 = ChangeUint32ToFloat64(key); 1659 1660 // See Dictionary::FirstProbe(). 1661 Node* count = Int32Constant(0); 1662 Node* entry = Word32And(hash, mask); 1663 1664 Node* undefined = UndefinedConstant(); 1665 Node* the_hole = TheHoleConstant(); 1666 1667 Variable var_count(this, MachineRepresentation::kWord32); 1668 Variable* loop_vars[] = {&var_count, var_entry}; 1669 Label loop(this, 2, loop_vars); 1670 var_count.Bind(count); 1671 var_entry->Bind(entry); 1672 Goto(&loop); 1673 Bind(&loop); 1674 { 1675 Node* count = var_count.value(); 1676 Node* entry = var_entry->value(); 1677 1678 Node* index = EntryToIndex<Dictionary>(entry); 1679 Node* current = LoadFixedArrayElement(dictionary, index); 1680 GotoIf(WordEqual(current, undefined), if_not_found); 1681 Label next_probe(this); 1682 { 1683 Label if_currentissmi(this), if_currentisnotsmi(this); 1684 Branch(WordIsSmi(current), &if_currentissmi, &if_currentisnotsmi); 1685 Bind(&if_currentissmi); 1686 { 1687 Node* current_value = SmiToWord32(current); 1688 Branch(Word32Equal(current_value, key), if_found, &next_probe); 1689 } 1690 Bind(&if_currentisnotsmi); 1691 { 1692 GotoIf(WordEqual(current, the_hole), &next_probe); 1693 // Current must be the Number. 1694 Node* current_value = LoadHeapNumberValue(current); 1695 Branch(Float64Equal(current_value, key_as_float64), if_found, 1696 &next_probe); 1697 } 1698 } 1699 1700 Bind(&next_probe); 1701 // See Dictionary::NextProbe(). 1702 count = Int32Add(count, Int32Constant(1)); 1703 entry = Word32And(Int32Add(entry, count), mask); 1704 1705 var_count.Bind(count); 1706 var_entry->Bind(entry); 1707 Goto(&loop); 1708 } 1709 } 1710 TryLookupProperty(Node * object,Node * map,Node * instance_type,Node * unique_name,Label * if_found_fast,Label * if_found_dict,Label * if_found_global,Variable * var_meta_storage,Variable * var_name_index,Label * if_not_found,Label * if_bailout)1711 void CodeStubAssembler::TryLookupProperty( 1712 Node* object, Node* map, Node* instance_type, Node* unique_name, 1713 Label* if_found_fast, Label* if_found_dict, Label* if_found_global, 1714 Variable* var_meta_storage, Variable* var_name_index, Label* if_not_found, 1715 Label* if_bailout) { 1716 DCHECK_EQ(MachineRepresentation::kTagged, var_meta_storage->rep()); 1717 DCHECK_EQ(MachineRepresentation::kWord32, var_name_index->rep()); 1718 1719 Label if_objectisspecial(this); 1720 STATIC_ASSERT(JS_GLOBAL_OBJECT_TYPE <= LAST_SPECIAL_RECEIVER_TYPE); 1721 GotoIf(Int32LessThanOrEqual(instance_type, 1722 Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)), 1723 &if_objectisspecial); 1724 1725 Node* bit_field = LoadMapBitField(map); 1726 Node* mask = Int32Constant(1 << Map::kHasNamedInterceptor | 1727 1 << Map::kIsAccessCheckNeeded); 1728 Assert(Word32Equal(Word32And(bit_field, mask), Int32Constant(0))); 1729 1730 Node* bit_field3 = LoadMapBitField3(map); 1731 Node* bit = BitFieldDecode<Map::DictionaryMap>(bit_field3); 1732 Label if_isfastmap(this), if_isslowmap(this); 1733 Branch(Word32Equal(bit, Int32Constant(0)), &if_isfastmap, &if_isslowmap); 1734 Bind(&if_isfastmap); 1735 { 1736 Comment("DescriptorArrayLookup"); 1737 Node* nof = BitFieldDecode<Map::NumberOfOwnDescriptorsBits>(bit_field3); 1738 // Bail out to the runtime for large numbers of own descriptors. The stub 1739 // only does linear search, which becomes too expensive in that case. 1740 { 1741 static const int32_t kMaxLinear = 210; 1742 GotoIf(Int32GreaterThan(nof, Int32Constant(kMaxLinear)), if_bailout); 1743 } 1744 Node* descriptors = LoadMapDescriptors(map); 1745 var_meta_storage->Bind(descriptors); 1746 1747 Variable var_descriptor(this, MachineRepresentation::kWord32); 1748 Label loop(this, &var_descriptor); 1749 var_descriptor.Bind(Int32Constant(0)); 1750 Goto(&loop); 1751 Bind(&loop); 1752 { 1753 Node* index = var_descriptor.value(); 1754 Node* name_offset = Int32Constant(DescriptorArray::ToKeyIndex(0)); 1755 Node* factor = Int32Constant(DescriptorArray::kDescriptorSize); 1756 GotoIf(Word32Equal(index, nof), if_not_found); 1757 1758 Node* name_index = Int32Add(name_offset, Int32Mul(index, factor)); 1759 Node* name = LoadFixedArrayElement(descriptors, name_index); 1760 1761 var_name_index->Bind(name_index); 1762 GotoIf(WordEqual(name, unique_name), if_found_fast); 1763 1764 var_descriptor.Bind(Int32Add(index, Int32Constant(1))); 1765 Goto(&loop); 1766 } 1767 } 1768 Bind(&if_isslowmap); 1769 { 1770 Node* dictionary = LoadProperties(object); 1771 var_meta_storage->Bind(dictionary); 1772 1773 NameDictionaryLookup<NameDictionary>(dictionary, unique_name, if_found_dict, 1774 var_name_index, if_not_found); 1775 } 1776 Bind(&if_objectisspecial); 1777 { 1778 // Handle global object here and other special objects in runtime. 1779 GotoUnless(Word32Equal(instance_type, Int32Constant(JS_GLOBAL_OBJECT_TYPE)), 1780 if_bailout); 1781 1782 // Handle interceptors and access checks in runtime. 1783 Node* bit_field = LoadMapBitField(map); 1784 Node* mask = Int32Constant(1 << Map::kHasNamedInterceptor | 1785 1 << Map::kIsAccessCheckNeeded); 1786 GotoIf(Word32NotEqual(Word32And(bit_field, mask), Int32Constant(0)), 1787 if_bailout); 1788 1789 Node* dictionary = LoadProperties(object); 1790 var_meta_storage->Bind(dictionary); 1791 1792 NameDictionaryLookup<GlobalDictionary>( 1793 dictionary, unique_name, if_found_global, var_name_index, if_not_found); 1794 } 1795 } 1796 TryHasOwnProperty(compiler::Node * object,compiler::Node * map,compiler::Node * instance_type,compiler::Node * unique_name,Label * if_found,Label * if_not_found,Label * if_bailout)1797 void CodeStubAssembler::TryHasOwnProperty(compiler::Node* object, 1798 compiler::Node* map, 1799 compiler::Node* instance_type, 1800 compiler::Node* unique_name, 1801 Label* if_found, Label* if_not_found, 1802 Label* if_bailout) { 1803 Comment("TryHasOwnProperty"); 1804 Variable var_meta_storage(this, MachineRepresentation::kTagged); 1805 Variable var_name_index(this, MachineRepresentation::kWord32); 1806 1807 Label if_found_global(this); 1808 TryLookupProperty(object, map, instance_type, unique_name, if_found, if_found, 1809 &if_found_global, &var_meta_storage, &var_name_index, 1810 if_not_found, if_bailout); 1811 Bind(&if_found_global); 1812 { 1813 Variable var_value(this, MachineRepresentation::kTagged); 1814 Variable var_details(this, MachineRepresentation::kWord32); 1815 // Check if the property cell is not deleted. 1816 LoadPropertyFromGlobalDictionary(var_meta_storage.value(), 1817 var_name_index.value(), &var_value, 1818 &var_details, if_not_found); 1819 Goto(if_found); 1820 } 1821 } 1822 LoadPropertyFromFastObject(Node * object,Node * map,Node * descriptors,Node * name_index,Variable * var_details,Variable * var_value)1823 void CodeStubAssembler::LoadPropertyFromFastObject(Node* object, Node* map, 1824 Node* descriptors, 1825 Node* name_index, 1826 Variable* var_details, 1827 Variable* var_value) { 1828 DCHECK_EQ(MachineRepresentation::kWord32, var_details->rep()); 1829 DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep()); 1830 Comment("[ LoadPropertyFromFastObject"); 1831 1832 const int name_to_details_offset = 1833 (DescriptorArray::kDescriptorDetails - DescriptorArray::kDescriptorKey) * 1834 kPointerSize; 1835 const int name_to_value_offset = 1836 (DescriptorArray::kDescriptorValue - DescriptorArray::kDescriptorKey) * 1837 kPointerSize; 1838 1839 Node* details = SmiToWord32( 1840 LoadFixedArrayElement(descriptors, name_index, name_to_details_offset)); 1841 var_details->Bind(details); 1842 1843 Node* location = BitFieldDecode<PropertyDetails::LocationField>(details); 1844 1845 Label if_in_field(this), if_in_descriptor(this), done(this); 1846 Branch(Word32Equal(location, Int32Constant(kField)), &if_in_field, 1847 &if_in_descriptor); 1848 Bind(&if_in_field); 1849 { 1850 Node* field_index = 1851 BitFieldDecode<PropertyDetails::FieldIndexField>(details); 1852 Node* representation = 1853 BitFieldDecode<PropertyDetails::RepresentationField>(details); 1854 1855 Node* inobject_properties = LoadMapInobjectProperties(map); 1856 1857 Label if_inobject(this), if_backing_store(this); 1858 Variable var_double_value(this, MachineRepresentation::kFloat64); 1859 Label rebox_double(this, &var_double_value); 1860 BranchIfInt32LessThan(field_index, inobject_properties, &if_inobject, 1861 &if_backing_store); 1862 Bind(&if_inobject); 1863 { 1864 Comment("if_inobject"); 1865 Node* field_offset = ChangeInt32ToIntPtr( 1866 Int32Mul(Int32Sub(LoadMapInstanceSize(map), 1867 Int32Sub(inobject_properties, field_index)), 1868 Int32Constant(kPointerSize))); 1869 1870 Label if_double(this), if_tagged(this); 1871 BranchIfWord32NotEqual(representation, 1872 Int32Constant(Representation::kDouble), &if_tagged, 1873 &if_double); 1874 Bind(&if_tagged); 1875 { 1876 var_value->Bind(LoadObjectField(object, field_offset)); 1877 Goto(&done); 1878 } 1879 Bind(&if_double); 1880 { 1881 if (FLAG_unbox_double_fields) { 1882 var_double_value.Bind( 1883 LoadObjectField(object, field_offset, MachineType::Float64())); 1884 } else { 1885 Node* mutable_heap_number = LoadObjectField(object, field_offset); 1886 var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number)); 1887 } 1888 Goto(&rebox_double); 1889 } 1890 } 1891 Bind(&if_backing_store); 1892 { 1893 Comment("if_backing_store"); 1894 Node* properties = LoadProperties(object); 1895 field_index = Int32Sub(field_index, inobject_properties); 1896 Node* value = LoadFixedArrayElement(properties, field_index); 1897 1898 Label if_double(this), if_tagged(this); 1899 BranchIfWord32NotEqual(representation, 1900 Int32Constant(Representation::kDouble), &if_tagged, 1901 &if_double); 1902 Bind(&if_tagged); 1903 { 1904 var_value->Bind(value); 1905 Goto(&done); 1906 } 1907 Bind(&if_double); 1908 { 1909 var_double_value.Bind(LoadHeapNumberValue(value)); 1910 Goto(&rebox_double); 1911 } 1912 } 1913 Bind(&rebox_double); 1914 { 1915 Comment("rebox_double"); 1916 Node* heap_number = AllocateHeapNumber(); 1917 StoreHeapNumberValue(heap_number, var_double_value.value()); 1918 var_value->Bind(heap_number); 1919 Goto(&done); 1920 } 1921 } 1922 Bind(&if_in_descriptor); 1923 { 1924 Node* value = 1925 LoadFixedArrayElement(descriptors, name_index, name_to_value_offset); 1926 var_value->Bind(value); 1927 Goto(&done); 1928 } 1929 Bind(&done); 1930 1931 Comment("] LoadPropertyFromFastObject"); 1932 } 1933 LoadPropertyFromNameDictionary(Node * dictionary,Node * name_index,Variable * var_details,Variable * var_value)1934 void CodeStubAssembler::LoadPropertyFromNameDictionary(Node* dictionary, 1935 Node* name_index, 1936 Variable* var_details, 1937 Variable* var_value) { 1938 Comment("LoadPropertyFromNameDictionary"); 1939 1940 const int name_to_details_offset = 1941 (NameDictionary::kEntryDetailsIndex - NameDictionary::kEntryKeyIndex) * 1942 kPointerSize; 1943 const int name_to_value_offset = 1944 (NameDictionary::kEntryValueIndex - NameDictionary::kEntryKeyIndex) * 1945 kPointerSize; 1946 1947 Node* details = SmiToWord32( 1948 LoadFixedArrayElement(dictionary, name_index, name_to_details_offset)); 1949 1950 var_details->Bind(details); 1951 var_value->Bind( 1952 LoadFixedArrayElement(dictionary, name_index, name_to_value_offset)); 1953 1954 Comment("] LoadPropertyFromNameDictionary"); 1955 } 1956 LoadPropertyFromGlobalDictionary(Node * dictionary,Node * name_index,Variable * var_details,Variable * var_value,Label * if_deleted)1957 void CodeStubAssembler::LoadPropertyFromGlobalDictionary(Node* dictionary, 1958 Node* name_index, 1959 Variable* var_details, 1960 Variable* var_value, 1961 Label* if_deleted) { 1962 Comment("[ LoadPropertyFromGlobalDictionary"); 1963 1964 const int name_to_value_offset = 1965 (GlobalDictionary::kEntryValueIndex - GlobalDictionary::kEntryKeyIndex) * 1966 kPointerSize; 1967 1968 Node* property_cell = 1969 LoadFixedArrayElement(dictionary, name_index, name_to_value_offset); 1970 1971 Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset); 1972 GotoIf(WordEqual(value, TheHoleConstant()), if_deleted); 1973 1974 var_value->Bind(value); 1975 1976 Node* details = 1977 SmiToWord32(LoadObjectField(property_cell, PropertyCell::kDetailsOffset)); 1978 var_details->Bind(details); 1979 1980 Comment("] LoadPropertyFromGlobalDictionary"); 1981 } 1982 TryGetOwnProperty(Node * context,Node * receiver,Node * object,Node * map,Node * instance_type,Node * unique_name,Label * if_found_value,Variable * var_value,Label * if_not_found,Label * if_bailout)1983 void CodeStubAssembler::TryGetOwnProperty( 1984 Node* context, Node* receiver, Node* object, Node* map, Node* instance_type, 1985 Node* unique_name, Label* if_found_value, Variable* var_value, 1986 Label* if_not_found, Label* if_bailout) { 1987 DCHECK_EQ(MachineRepresentation::kTagged, var_value->rep()); 1988 Comment("TryGetOwnProperty"); 1989 1990 Variable var_meta_storage(this, MachineRepresentation::kTagged); 1991 Variable var_entry(this, MachineRepresentation::kWord32); 1992 1993 Label if_found_fast(this), if_found_dict(this), if_found_global(this); 1994 1995 Variable var_details(this, MachineRepresentation::kWord32); 1996 Variable* vars[] = {var_value, &var_details}; 1997 Label if_found(this, 2, vars); 1998 1999 TryLookupProperty(object, map, instance_type, unique_name, &if_found_fast, 2000 &if_found_dict, &if_found_global, &var_meta_storage, 2001 &var_entry, if_not_found, if_bailout); 2002 Bind(&if_found_fast); 2003 { 2004 Node* descriptors = var_meta_storage.value(); 2005 Node* name_index = var_entry.value(); 2006 2007 LoadPropertyFromFastObject(object, map, descriptors, name_index, 2008 &var_details, var_value); 2009 Goto(&if_found); 2010 } 2011 Bind(&if_found_dict); 2012 { 2013 Node* dictionary = var_meta_storage.value(); 2014 Node* entry = var_entry.value(); 2015 LoadPropertyFromNameDictionary(dictionary, entry, &var_details, var_value); 2016 Goto(&if_found); 2017 } 2018 Bind(&if_found_global); 2019 { 2020 Node* dictionary = var_meta_storage.value(); 2021 Node* entry = var_entry.value(); 2022 2023 LoadPropertyFromGlobalDictionary(dictionary, entry, &var_details, var_value, 2024 if_not_found); 2025 Goto(&if_found); 2026 } 2027 // Here we have details and value which could be an accessor. 2028 Bind(&if_found); 2029 { 2030 Node* details = var_details.value(); 2031 Node* kind = BitFieldDecode<PropertyDetails::KindField>(details); 2032 2033 Label if_accessor(this); 2034 Branch(Word32Equal(kind, Int32Constant(kData)), if_found_value, 2035 &if_accessor); 2036 Bind(&if_accessor); 2037 { 2038 Node* accessor_pair = var_value->value(); 2039 GotoIf(Word32Equal(LoadInstanceType(accessor_pair), 2040 Int32Constant(ACCESSOR_INFO_TYPE)), 2041 if_bailout); 2042 AssertInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE); 2043 Node* getter = 2044 LoadObjectField(accessor_pair, AccessorPair::kGetterOffset); 2045 Node* getter_map = LoadMap(getter); 2046 Node* instance_type = LoadMapInstanceType(getter_map); 2047 // FunctionTemplateInfo getters are not supported yet. 2048 GotoIf(Word32Equal(instance_type, 2049 Int32Constant(FUNCTION_TEMPLATE_INFO_TYPE)), 2050 if_bailout); 2051 2052 // Return undefined if the {getter} is not callable. 2053 var_value->Bind(UndefinedConstant()); 2054 GotoIf(Word32Equal(Word32And(LoadMapBitField(getter_map), 2055 Int32Constant(1 << Map::kIsCallable)), 2056 Int32Constant(0)), 2057 if_found_value); 2058 2059 // Call the accessor. 2060 Callable callable = CodeFactory::Call(isolate()); 2061 Node* result = CallJS(callable, context, getter, receiver); 2062 var_value->Bind(result); 2063 Goto(if_found_value); 2064 } 2065 } 2066 } 2067 TryLookupElement(Node * object,Node * map,Node * instance_type,Node * index,Label * if_found,Label * if_not_found,Label * if_bailout)2068 void CodeStubAssembler::TryLookupElement(Node* object, Node* map, 2069 Node* instance_type, Node* index, 2070 Label* if_found, Label* if_not_found, 2071 Label* if_bailout) { 2072 // Handle special objects in runtime. 2073 GotoIf(Int32LessThanOrEqual(instance_type, 2074 Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)), 2075 if_bailout); 2076 2077 Node* bit_field2 = LoadMapBitField2(map); 2078 Node* elements_kind = BitFieldDecode<Map::ElementsKindBits>(bit_field2); 2079 2080 // TODO(verwaest): Support other elements kinds as well. 2081 Label if_isobjectorsmi(this), if_isdouble(this), if_isdictionary(this), 2082 if_isfaststringwrapper(this), if_isslowstringwrapper(this); 2083 // clang-format off 2084 int32_t values[] = { 2085 // Handled by {if_isobjectorsmi}. 2086 FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS, 2087 FAST_HOLEY_ELEMENTS, 2088 // Handled by {if_isdouble}. 2089 FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, 2090 // Handled by {if_isdictionary}. 2091 DICTIONARY_ELEMENTS, 2092 // Handled by {if_isfaststringwrapper}. 2093 FAST_STRING_WRAPPER_ELEMENTS, 2094 // Handled by {if_isslowstringwrapper}. 2095 SLOW_STRING_WRAPPER_ELEMENTS, 2096 // Handled by {if_not_found}. 2097 NO_ELEMENTS, 2098 }; 2099 Label* labels[] = { 2100 &if_isobjectorsmi, &if_isobjectorsmi, &if_isobjectorsmi, 2101 &if_isobjectorsmi, 2102 &if_isdouble, &if_isdouble, 2103 &if_isdictionary, 2104 &if_isfaststringwrapper, 2105 &if_isslowstringwrapper, 2106 if_not_found, 2107 }; 2108 // clang-format on 2109 STATIC_ASSERT(arraysize(values) == arraysize(labels)); 2110 Switch(elements_kind, if_bailout, values, labels, arraysize(values)); 2111 2112 Bind(&if_isobjectorsmi); 2113 { 2114 Node* elements = LoadElements(object); 2115 Node* length = LoadFixedArrayBaseLength(elements); 2116 2117 GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found); 2118 2119 Node* element = LoadFixedArrayElement(elements, index); 2120 Node* the_hole = TheHoleConstant(); 2121 Branch(WordEqual(element, the_hole), if_not_found, if_found); 2122 } 2123 Bind(&if_isdouble); 2124 { 2125 Node* elements = LoadElements(object); 2126 Node* length = LoadFixedArrayBaseLength(elements); 2127 2128 GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found); 2129 2130 if (kPointerSize == kDoubleSize) { 2131 Node* element = 2132 LoadFixedDoubleArrayElement(elements, index, MachineType::Uint64()); 2133 Node* the_hole = Int64Constant(kHoleNanInt64); 2134 Branch(Word64Equal(element, the_hole), if_not_found, if_found); 2135 } else { 2136 Node* element_upper = 2137 LoadFixedDoubleArrayElement(elements, index, MachineType::Uint32(), 2138 kIeeeDoubleExponentWordOffset); 2139 Branch(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)), 2140 if_not_found, if_found); 2141 } 2142 } 2143 Bind(&if_isdictionary); 2144 { 2145 Variable var_entry(this, MachineRepresentation::kWord32); 2146 Node* elements = LoadElements(object); 2147 NumberDictionaryLookup<SeededNumberDictionary>(elements, index, if_found, 2148 &var_entry, if_not_found); 2149 } 2150 Bind(&if_isfaststringwrapper); 2151 { 2152 AssertInstanceType(object, JS_VALUE_TYPE); 2153 Node* string = LoadJSValueValue(object); 2154 Assert(Int32LessThan(LoadInstanceType(string), 2155 Int32Constant(FIRST_NONSTRING_TYPE))); 2156 Node* length = LoadStringLength(string); 2157 GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found); 2158 Goto(&if_isobjectorsmi); 2159 } 2160 Bind(&if_isslowstringwrapper); 2161 { 2162 AssertInstanceType(object, JS_VALUE_TYPE); 2163 Node* string = LoadJSValueValue(object); 2164 Assert(Int32LessThan(LoadInstanceType(string), 2165 Int32Constant(FIRST_NONSTRING_TYPE))); 2166 Node* length = LoadStringLength(string); 2167 GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found); 2168 Goto(&if_isdictionary); 2169 } 2170 } 2171 2172 // Instantiate template methods to workaround GCC compilation issue. 2173 template void CodeStubAssembler::NumberDictionaryLookup<SeededNumberDictionary>( 2174 Node*, Node*, Label*, Variable*, Label*); 2175 template void CodeStubAssembler::NumberDictionaryLookup< 2176 UnseededNumberDictionary>(Node*, Node*, Label*, Variable*, Label*); 2177 OrdinaryHasInstance(Node * context,Node * callable,Node * object)2178 Node* CodeStubAssembler::OrdinaryHasInstance(Node* context, Node* callable, 2179 Node* object) { 2180 Variable var_result(this, MachineRepresentation::kTagged); 2181 Label return_false(this), return_true(this), 2182 return_runtime(this, Label::kDeferred), return_result(this); 2183 2184 // Goto runtime if {object} is a Smi. 2185 GotoIf(WordIsSmi(object), &return_runtime); 2186 2187 // Load map of {object}. 2188 Node* object_map = LoadMap(object); 2189 2190 // Lookup the {callable} and {object} map in the global instanceof cache. 2191 // Note: This is safe because we clear the global instanceof cache whenever 2192 // we change the prototype of any object. 2193 Node* instanceof_cache_function = 2194 LoadRoot(Heap::kInstanceofCacheFunctionRootIndex); 2195 Node* instanceof_cache_map = LoadRoot(Heap::kInstanceofCacheMapRootIndex); 2196 { 2197 Label instanceof_cache_miss(this); 2198 GotoUnless(WordEqual(instanceof_cache_function, callable), 2199 &instanceof_cache_miss); 2200 GotoUnless(WordEqual(instanceof_cache_map, object_map), 2201 &instanceof_cache_miss); 2202 var_result.Bind(LoadRoot(Heap::kInstanceofCacheAnswerRootIndex)); 2203 Goto(&return_result); 2204 Bind(&instanceof_cache_miss); 2205 } 2206 2207 // Goto runtime if {callable} is a Smi. 2208 GotoIf(WordIsSmi(callable), &return_runtime); 2209 2210 // Load map of {callable}. 2211 Node* callable_map = LoadMap(callable); 2212 2213 // Goto runtime if {callable} is not a JSFunction. 2214 Node* callable_instance_type = LoadMapInstanceType(callable_map); 2215 GotoUnless( 2216 Word32Equal(callable_instance_type, Int32Constant(JS_FUNCTION_TYPE)), 2217 &return_runtime); 2218 2219 // Goto runtime if {callable} is not a constructor or has 2220 // a non-instance "prototype". 2221 Node* callable_bitfield = LoadMapBitField(callable_map); 2222 GotoUnless( 2223 Word32Equal(Word32And(callable_bitfield, 2224 Int32Constant((1 << Map::kHasNonInstancePrototype) | 2225 (1 << Map::kIsConstructor))), 2226 Int32Constant(1 << Map::kIsConstructor)), 2227 &return_runtime); 2228 2229 // Get the "prototype" (or initial map) of the {callable}. 2230 Node* callable_prototype = 2231 LoadObjectField(callable, JSFunction::kPrototypeOrInitialMapOffset); 2232 { 2233 Variable var_callable_prototype(this, MachineRepresentation::kTagged); 2234 Label callable_prototype_valid(this); 2235 var_callable_prototype.Bind(callable_prototype); 2236 2237 // Resolve the "prototype" if the {callable} has an initial map. Afterwards 2238 // the {callable_prototype} will be either the JSReceiver prototype object 2239 // or the hole value, which means that no instances of the {callable} were 2240 // created so far and hence we should return false. 2241 Node* callable_prototype_instance_type = 2242 LoadInstanceType(callable_prototype); 2243 GotoUnless( 2244 Word32Equal(callable_prototype_instance_type, Int32Constant(MAP_TYPE)), 2245 &callable_prototype_valid); 2246 var_callable_prototype.Bind( 2247 LoadObjectField(callable_prototype, Map::kPrototypeOffset)); 2248 Goto(&callable_prototype_valid); 2249 Bind(&callable_prototype_valid); 2250 callable_prototype = var_callable_prototype.value(); 2251 } 2252 2253 // Update the global instanceof cache with the current {object} map and 2254 // {callable}. The cached answer will be set when it is known below. 2255 StoreRoot(Heap::kInstanceofCacheFunctionRootIndex, callable); 2256 StoreRoot(Heap::kInstanceofCacheMapRootIndex, object_map); 2257 2258 // Loop through the prototype chain looking for the {callable} prototype. 2259 Variable var_object_map(this, MachineRepresentation::kTagged); 2260 var_object_map.Bind(object_map); 2261 Label loop(this, &var_object_map); 2262 Goto(&loop); 2263 Bind(&loop); 2264 { 2265 Node* object_map = var_object_map.value(); 2266 2267 // Check if the current {object} needs to be access checked. 2268 Node* object_bitfield = LoadMapBitField(object_map); 2269 GotoUnless( 2270 Word32Equal(Word32And(object_bitfield, 2271 Int32Constant(1 << Map::kIsAccessCheckNeeded)), 2272 Int32Constant(0)), 2273 &return_runtime); 2274 2275 // Check if the current {object} is a proxy. 2276 Node* object_instance_type = LoadMapInstanceType(object_map); 2277 GotoIf(Word32Equal(object_instance_type, Int32Constant(JS_PROXY_TYPE)), 2278 &return_runtime); 2279 2280 // Check the current {object} prototype. 2281 Node* object_prototype = LoadMapPrototype(object_map); 2282 GotoIf(WordEqual(object_prototype, NullConstant()), &return_false); 2283 GotoIf(WordEqual(object_prototype, callable_prototype), &return_true); 2284 2285 // Continue with the prototype. 2286 var_object_map.Bind(LoadMap(object_prototype)); 2287 Goto(&loop); 2288 } 2289 2290 Bind(&return_true); 2291 StoreRoot(Heap::kInstanceofCacheAnswerRootIndex, BooleanConstant(true)); 2292 var_result.Bind(BooleanConstant(true)); 2293 Goto(&return_result); 2294 2295 Bind(&return_false); 2296 StoreRoot(Heap::kInstanceofCacheAnswerRootIndex, BooleanConstant(false)); 2297 var_result.Bind(BooleanConstant(false)); 2298 Goto(&return_result); 2299 2300 Bind(&return_runtime); 2301 { 2302 // Invalidate the global instanceof cache. 2303 StoreRoot(Heap::kInstanceofCacheFunctionRootIndex, SmiConstant(0)); 2304 // Fallback to the runtime implementation. 2305 var_result.Bind( 2306 CallRuntime(Runtime::kOrdinaryHasInstance, context, callable, object)); 2307 } 2308 Goto(&return_result); 2309 2310 Bind(&return_result); 2311 return var_result.value(); 2312 } 2313 ElementOffsetFromIndex(Node * index_node,ElementsKind kind,ParameterMode mode,int base_size)2314 compiler::Node* CodeStubAssembler::ElementOffsetFromIndex(Node* index_node, 2315 ElementsKind kind, 2316 ParameterMode mode, 2317 int base_size) { 2318 bool is_double = IsFastDoubleElementsKind(kind); 2319 int element_size_shift = is_double ? kDoubleSizeLog2 : kPointerSizeLog2; 2320 int element_size = 1 << element_size_shift; 2321 int const kSmiShiftBits = kSmiShiftSize + kSmiTagSize; 2322 int32_t index = 0; 2323 bool constant_index = false; 2324 if (mode == SMI_PARAMETERS) { 2325 element_size_shift -= kSmiShiftBits; 2326 intptr_t temp = 0; 2327 constant_index = ToIntPtrConstant(index_node, temp); 2328 index = temp >> kSmiShiftBits; 2329 } else { 2330 constant_index = ToInt32Constant(index_node, index); 2331 } 2332 if (constant_index) { 2333 return IntPtrConstant(base_size + element_size * index); 2334 } 2335 if (Is64() && mode == INTEGER_PARAMETERS) { 2336 index_node = ChangeInt32ToInt64(index_node); 2337 } 2338 if (base_size == 0) { 2339 return (element_size_shift >= 0) 2340 ? WordShl(index_node, IntPtrConstant(element_size_shift)) 2341 : WordShr(index_node, IntPtrConstant(-element_size_shift)); 2342 } 2343 return IntPtrAdd( 2344 IntPtrConstant(base_size), 2345 (element_size_shift >= 0) 2346 ? WordShl(index_node, IntPtrConstant(element_size_shift)) 2347 : WordShr(index_node, IntPtrConstant(-element_size_shift))); 2348 } 2349 LoadTypeFeedbackVectorForStub()2350 compiler::Node* CodeStubAssembler::LoadTypeFeedbackVectorForStub() { 2351 Node* function = 2352 LoadFromParentFrame(JavaScriptFrameConstants::kFunctionOffset); 2353 Node* literals = LoadObjectField(function, JSFunction::kLiteralsOffset); 2354 return LoadObjectField(literals, LiteralsArray::kFeedbackVectorOffset); 2355 } 2356 LoadReceiverMap(compiler::Node * receiver)2357 compiler::Node* CodeStubAssembler::LoadReceiverMap(compiler::Node* receiver) { 2358 Variable var_receiver_map(this, MachineRepresentation::kTagged); 2359 // TODO(ishell): defer blocks when it works. 2360 Label load_smi_map(this /*, Label::kDeferred*/), load_receiver_map(this), 2361 if_result(this); 2362 2363 Branch(WordIsSmi(receiver), &load_smi_map, &load_receiver_map); 2364 Bind(&load_smi_map); 2365 { 2366 var_receiver_map.Bind(LoadRoot(Heap::kHeapNumberMapRootIndex)); 2367 Goto(&if_result); 2368 } 2369 Bind(&load_receiver_map); 2370 { 2371 var_receiver_map.Bind(LoadMap(receiver)); 2372 Goto(&if_result); 2373 } 2374 Bind(&if_result); 2375 return var_receiver_map.value(); 2376 } 2377 TryMonomorphicCase(const LoadICParameters * p,compiler::Node * receiver_map,Label * if_handler,Variable * var_handler,Label * if_miss)2378 compiler::Node* CodeStubAssembler::TryMonomorphicCase( 2379 const LoadICParameters* p, compiler::Node* receiver_map, Label* if_handler, 2380 Variable* var_handler, Label* if_miss) { 2381 DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep()); 2382 2383 // TODO(ishell): add helper class that hides offset computations for a series 2384 // of loads. 2385 int32_t header_size = FixedArray::kHeaderSize - kHeapObjectTag; 2386 Node* offset = ElementOffsetFromIndex(p->slot, FAST_HOLEY_ELEMENTS, 2387 SMI_PARAMETERS, header_size); 2388 Node* feedback = Load(MachineType::AnyTagged(), p->vector, offset); 2389 2390 // Try to quickly handle the monomorphic case without knowing for sure 2391 // if we have a weak cell in feedback. We do know it's safe to look 2392 // at WeakCell::kValueOffset. 2393 GotoUnless(WordEqual(receiver_map, LoadWeakCellValue(feedback)), if_miss); 2394 2395 Node* handler = Load(MachineType::AnyTagged(), p->vector, 2396 IntPtrAdd(offset, IntPtrConstant(kPointerSize))); 2397 2398 var_handler->Bind(handler); 2399 Goto(if_handler); 2400 return feedback; 2401 } 2402 HandlePolymorphicCase(const LoadICParameters * p,compiler::Node * receiver_map,compiler::Node * feedback,Label * if_handler,Variable * var_handler,Label * if_miss,int unroll_count)2403 void CodeStubAssembler::HandlePolymorphicCase( 2404 const LoadICParameters* p, compiler::Node* receiver_map, 2405 compiler::Node* feedback, Label* if_handler, Variable* var_handler, 2406 Label* if_miss, int unroll_count) { 2407 DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep()); 2408 2409 // Iterate {feedback} array. 2410 const int kEntrySize = 2; 2411 2412 for (int i = 0; i < unroll_count; i++) { 2413 Label next_entry(this); 2414 Node* cached_map = LoadWeakCellValue( 2415 LoadFixedArrayElement(feedback, Int32Constant(i * kEntrySize))); 2416 GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry); 2417 2418 // Found, now call handler. 2419 Node* handler = 2420 LoadFixedArrayElement(feedback, Int32Constant(i * kEntrySize + 1)); 2421 var_handler->Bind(handler); 2422 Goto(if_handler); 2423 2424 Bind(&next_entry); 2425 } 2426 Node* length = SmiToWord32(LoadFixedArrayBaseLength(feedback)); 2427 2428 // Loop from {unroll_count}*kEntrySize to {length}. 2429 Variable var_index(this, MachineRepresentation::kWord32); 2430 Label loop(this, &var_index); 2431 var_index.Bind(Int32Constant(unroll_count * kEntrySize)); 2432 Goto(&loop); 2433 Bind(&loop); 2434 { 2435 Node* index = var_index.value(); 2436 GotoIf(Int32GreaterThanOrEqual(index, length), if_miss); 2437 2438 Node* cached_map = 2439 LoadWeakCellValue(LoadFixedArrayElement(feedback, index)); 2440 2441 Label next_entry(this); 2442 GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry); 2443 2444 // Found, now call handler. 2445 Node* handler = LoadFixedArrayElement(feedback, index, kPointerSize); 2446 var_handler->Bind(handler); 2447 Goto(if_handler); 2448 2449 Bind(&next_entry); 2450 var_index.Bind(Int32Add(index, Int32Constant(kEntrySize))); 2451 Goto(&loop); 2452 } 2453 } 2454 StubCachePrimaryOffset(compiler::Node * name,Code::Flags flags,compiler::Node * map)2455 compiler::Node* CodeStubAssembler::StubCachePrimaryOffset(compiler::Node* name, 2456 Code::Flags flags, 2457 compiler::Node* map) { 2458 // See v8::internal::StubCache::PrimaryOffset(). 2459 STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift); 2460 // Compute the hash of the name (use entire hash field). 2461 Node* hash_field = LoadNameHashField(name); 2462 Assert(WordEqual( 2463 Word32And(hash_field, Int32Constant(Name::kHashNotComputedMask)), 2464 Int32Constant(0))); 2465 2466 // Using only the low bits in 64-bit mode is unlikely to increase the 2467 // risk of collision even if the heap is spread over an area larger than 2468 // 4Gb (and not at all if it isn't). 2469 Node* hash = Int32Add(hash_field, map); 2470 // We always set the in_loop bit to zero when generating the lookup code 2471 // so do it here too so the hash codes match. 2472 uint32_t iflags = 2473 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); 2474 // Base the offset on a simple combination of name, flags, and map. 2475 hash = Word32Xor(hash, Int32Constant(iflags)); 2476 uint32_t mask = (StubCache::kPrimaryTableSize - 1) 2477 << StubCache::kCacheIndexShift; 2478 return Word32And(hash, Int32Constant(mask)); 2479 } 2480 StubCacheSecondaryOffset(compiler::Node * name,Code::Flags flags,compiler::Node * seed)2481 compiler::Node* CodeStubAssembler::StubCacheSecondaryOffset( 2482 compiler::Node* name, Code::Flags flags, compiler::Node* seed) { 2483 // See v8::internal::StubCache::SecondaryOffset(). 2484 2485 // Use the seed from the primary cache in the secondary cache. 2486 Node* hash = Int32Sub(seed, name); 2487 // We always set the in_loop bit to zero when generating the lookup code 2488 // so do it here too so the hash codes match. 2489 uint32_t iflags = 2490 (static_cast<uint32_t>(flags) & ~Code::kFlagsNotUsedInLookup); 2491 hash = Int32Add(hash, Int32Constant(iflags)); 2492 int32_t mask = (StubCache::kSecondaryTableSize - 1) 2493 << StubCache::kCacheIndexShift; 2494 return Word32And(hash, Int32Constant(mask)); 2495 } 2496 2497 enum CodeStubAssembler::StubCacheTable : int { 2498 kPrimary = static_cast<int>(StubCache::kPrimary), 2499 kSecondary = static_cast<int>(StubCache::kSecondary) 2500 }; 2501 TryProbeStubCacheTable(StubCache * stub_cache,StubCacheTable table_id,compiler::Node * entry_offset,compiler::Node * name,Code::Flags flags,compiler::Node * map,Label * if_handler,Variable * var_handler,Label * if_miss)2502 void CodeStubAssembler::TryProbeStubCacheTable( 2503 StubCache* stub_cache, StubCacheTable table_id, 2504 compiler::Node* entry_offset, compiler::Node* name, Code::Flags flags, 2505 compiler::Node* map, Label* if_handler, Variable* var_handler, 2506 Label* if_miss) { 2507 StubCache::Table table = static_cast<StubCache::Table>(table_id); 2508 #ifdef DEBUG 2509 if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) { 2510 Goto(if_miss); 2511 return; 2512 } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) { 2513 Goto(if_miss); 2514 return; 2515 } 2516 #endif 2517 // The {table_offset} holds the entry offset times four (due to masking 2518 // and shifting optimizations). 2519 const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift; 2520 entry_offset = Int32Mul(entry_offset, Int32Constant(kMultiplier)); 2521 2522 // Check that the key in the entry matches the name. 2523 Node* key_base = 2524 ExternalConstant(ExternalReference(stub_cache->key_reference(table))); 2525 Node* entry_key = Load(MachineType::Pointer(), key_base, entry_offset); 2526 GotoIf(WordNotEqual(name, entry_key), if_miss); 2527 2528 // Get the map entry from the cache. 2529 DCHECK_EQ(kPointerSize * 2, stub_cache->map_reference(table).address() - 2530 stub_cache->key_reference(table).address()); 2531 Node* entry_map = 2532 Load(MachineType::Pointer(), key_base, 2533 Int32Add(entry_offset, Int32Constant(kPointerSize * 2))); 2534 GotoIf(WordNotEqual(map, entry_map), if_miss); 2535 2536 // Check that the flags match what we're looking for. 2537 DCHECK_EQ(kPointerSize, stub_cache->value_reference(table).address() - 2538 stub_cache->key_reference(table).address()); 2539 Node* code = Load(MachineType::Pointer(), key_base, 2540 Int32Add(entry_offset, Int32Constant(kPointerSize))); 2541 2542 Node* code_flags = 2543 LoadObjectField(code, Code::kFlagsOffset, MachineType::Uint32()); 2544 GotoIf(Word32NotEqual(Int32Constant(flags), 2545 Word32And(code_flags, 2546 Int32Constant(~Code::kFlagsNotUsedInLookup))), 2547 if_miss); 2548 2549 // We found the handler. 2550 var_handler->Bind(code); 2551 Goto(if_handler); 2552 } 2553 TryProbeStubCache(StubCache * stub_cache,Code::Flags flags,compiler::Node * receiver,compiler::Node * name,Label * if_handler,Variable * var_handler,Label * if_miss)2554 void CodeStubAssembler::TryProbeStubCache( 2555 StubCache* stub_cache, Code::Flags flags, compiler::Node* receiver, 2556 compiler::Node* name, Label* if_handler, Variable* var_handler, 2557 Label* if_miss) { 2558 Label try_secondary(this), miss(this); 2559 2560 Counters* counters = isolate()->counters(); 2561 IncrementCounter(counters->megamorphic_stub_cache_probes(), 1); 2562 2563 // Check that the {receiver} isn't a smi. 2564 GotoIf(WordIsSmi(receiver), &miss); 2565 2566 Node* receiver_map = LoadMap(receiver); 2567 2568 // Probe the primary table. 2569 Node* primary_offset = StubCachePrimaryOffset(name, flags, receiver_map); 2570 TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name, flags, 2571 receiver_map, if_handler, var_handler, &try_secondary); 2572 2573 Bind(&try_secondary); 2574 { 2575 // Probe the secondary table. 2576 Node* secondary_offset = 2577 StubCacheSecondaryOffset(name, flags, primary_offset); 2578 TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name, 2579 flags, receiver_map, if_handler, var_handler, &miss); 2580 } 2581 2582 Bind(&miss); 2583 { 2584 IncrementCounter(counters->megamorphic_stub_cache_misses(), 1); 2585 Goto(if_miss); 2586 } 2587 } 2588 LoadIC(const LoadICParameters * p)2589 void CodeStubAssembler::LoadIC(const LoadICParameters* p) { 2590 Variable var_handler(this, MachineRepresentation::kTagged); 2591 // TODO(ishell): defer blocks when it works. 2592 Label if_handler(this, &var_handler), try_polymorphic(this), 2593 try_megamorphic(this /*, Label::kDeferred*/), 2594 miss(this /*, Label::kDeferred*/); 2595 2596 Node* receiver_map = LoadReceiverMap(p->receiver); 2597 2598 // Check monomorphic case. 2599 Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler, 2600 &var_handler, &try_polymorphic); 2601 Bind(&if_handler); 2602 { 2603 LoadWithVectorDescriptor descriptor(isolate()); 2604 TailCallStub(descriptor, var_handler.value(), p->context, p->receiver, 2605 p->name, p->slot, p->vector); 2606 } 2607 2608 Bind(&try_polymorphic); 2609 { 2610 // Check polymorphic case. 2611 GotoUnless( 2612 WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), 2613 &try_megamorphic); 2614 HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler, 2615 &miss, 2); 2616 } 2617 2618 Bind(&try_megamorphic); 2619 { 2620 // Check megamorphic case. 2621 GotoUnless( 2622 WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), 2623 &miss); 2624 2625 Code::Flags code_flags = 2626 Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(Code::LOAD_IC)); 2627 2628 TryProbeStubCache(isolate()->stub_cache(), code_flags, p->receiver, p->name, 2629 &if_handler, &var_handler, &miss); 2630 } 2631 Bind(&miss); 2632 { 2633 TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name, 2634 p->slot, p->vector); 2635 } 2636 } 2637 LoadGlobalIC(const LoadICParameters * p)2638 void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) { 2639 Label try_handler(this), miss(this); 2640 Node* weak_cell = 2641 LoadFixedArrayElement(p->vector, p->slot, 0, SMI_PARAMETERS); 2642 AssertInstanceType(weak_cell, WEAK_CELL_TYPE); 2643 2644 // Load value or try handler case if the {weak_cell} is cleared. 2645 Node* property_cell = LoadWeakCellValue(weak_cell, &try_handler); 2646 AssertInstanceType(property_cell, PROPERTY_CELL_TYPE); 2647 2648 Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset); 2649 GotoIf(WordEqual(value, TheHoleConstant()), &miss); 2650 Return(value); 2651 2652 Bind(&try_handler); 2653 { 2654 Node* handler = 2655 LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS); 2656 GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)), 2657 &miss); 2658 2659 // In this case {handler} must be a Code object. 2660 AssertInstanceType(handler, CODE_TYPE); 2661 LoadWithVectorDescriptor descriptor(isolate()); 2662 Node* native_context = LoadNativeContext(p->context); 2663 Node* receiver = LoadFixedArrayElement( 2664 native_context, Int32Constant(Context::EXTENSION_INDEX)); 2665 Node* fake_name = IntPtrConstant(0); 2666 TailCallStub(descriptor, handler, p->context, receiver, fake_name, p->slot, 2667 p->vector); 2668 } 2669 Bind(&miss); 2670 { 2671 TailCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context, p->slot, 2672 p->vector); 2673 } 2674 } 2675 2676 } // namespace internal 2677 } // namespace v8 2678