1 // Copyright 2015 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/interpreter/interpreter-assembler.h" 6 7 #include <limits> 8 #include <ostream> 9 10 #include "src/code-factory.h" 11 #include "src/frames.h" 12 #include "src/interface-descriptors.h" 13 #include "src/interpreter/bytecodes.h" 14 #include "src/interpreter/interpreter.h" 15 #include "src/machine-type.h" 16 #include "src/macro-assembler.h" 17 #include "src/zone/zone.h" 18 19 namespace v8 { 20 namespace internal { 21 namespace interpreter { 22 23 using compiler::Node; 24 25 InterpreterAssembler::InterpreterAssembler(Isolate* isolate, Zone* zone, 26 Bytecode bytecode, 27 OperandScale operand_scale) 28 : CodeStubAssembler(isolate, zone, InterpreterDispatchDescriptor(isolate), 29 Code::ComputeFlags(Code::BYTECODE_HANDLER), 30 Bytecodes::ToString(bytecode), 31 Bytecodes::ReturnCount(bytecode)), 32 bytecode_(bytecode), 33 operand_scale_(operand_scale), 34 bytecode_offset_(this, MachineType::PointerRepresentation()), 35 interpreted_frame_pointer_(this, MachineType::PointerRepresentation()), 36 accumulator_(this, MachineRepresentation::kTagged), 37 accumulator_use_(AccumulatorUse::kNone), 38 made_call_(false), 39 disable_stack_check_across_call_(false), 40 stack_pointer_before_call_(nullptr) { 41 accumulator_.Bind(Parameter(InterpreterDispatchDescriptor::kAccumulator)); 42 bytecode_offset_.Bind( 43 Parameter(InterpreterDispatchDescriptor::kBytecodeOffset)); 44 if (FLAG_trace_ignition) { 45 TraceBytecode(Runtime::kInterpreterTraceBytecodeEntry); 46 } 47 } 48 49 InterpreterAssembler::~InterpreterAssembler() { 50 // If the following check fails the handler does not use the 51 // accumulator in the way described in the bytecode definitions in 52 // bytecodes.h. 53 DCHECK_EQ(accumulator_use_, Bytecodes::GetAccumulatorUse(bytecode_)); 54 } 55 56 Node* InterpreterAssembler::GetInterpretedFramePointer() { 57 if (!interpreted_frame_pointer_.IsBound()) { 58 interpreted_frame_pointer_.Bind(LoadParentFramePointer()); 59 } 60 return interpreted_frame_pointer_.value(); 61 } 62 63 Node* InterpreterAssembler::GetAccumulatorUnchecked() { 64 return accumulator_.value(); 65 } 66 67 Node* InterpreterAssembler::GetAccumulator() { 68 DCHECK(Bytecodes::ReadsAccumulator(bytecode_)); 69 accumulator_use_ = accumulator_use_ | AccumulatorUse::kRead; 70 return GetAccumulatorUnchecked(); 71 } 72 73 void InterpreterAssembler::SetAccumulator(Node* value) { 74 DCHECK(Bytecodes::WritesAccumulator(bytecode_)); 75 accumulator_use_ = accumulator_use_ | AccumulatorUse::kWrite; 76 accumulator_.Bind(value); 77 } 78 79 Node* InterpreterAssembler::GetContext() { 80 return LoadRegister(Register::current_context()); 81 } 82 83 void InterpreterAssembler::SetContext(Node* value) { 84 StoreRegister(value, Register::current_context()); 85 } 86 87 Node* InterpreterAssembler::GetContextAtDepth(Node* context, Node* depth) { 88 Variable cur_context(this, MachineRepresentation::kTaggedPointer); 89 cur_context.Bind(context); 90 91 Variable cur_depth(this, MachineRepresentation::kWord32); 92 cur_depth.Bind(depth); 93 94 Label context_found(this); 95 96 Variable* context_search_loop_variables[2] = {&cur_depth, &cur_context}; 97 Label context_search(this, 2, context_search_loop_variables); 98 99 // Fast path if the depth is 0. 100 Branch(Word32Equal(depth, Int32Constant(0)), &context_found, &context_search); 101 102 // Loop until the depth is 0. 103 Bind(&context_search); 104 { 105 cur_depth.Bind(Int32Sub(cur_depth.value(), Int32Constant(1))); 106 cur_context.Bind( 107 LoadContextElement(cur_context.value(), Context::PREVIOUS_INDEX)); 108 109 Branch(Word32Equal(cur_depth.value(), Int32Constant(0)), &context_found, 110 &context_search); 111 } 112 113 Bind(&context_found); 114 return cur_context.value(); 115 } 116 117 void InterpreterAssembler::GotoIfHasContextExtensionUpToDepth(Node* context, 118 Node* depth, 119 Label* target) { 120 Variable cur_context(this, MachineRepresentation::kTaggedPointer); 121 cur_context.Bind(context); 122 123 Variable cur_depth(this, MachineRepresentation::kWord32); 124 cur_depth.Bind(depth); 125 126 Variable* context_search_loop_variables[2] = {&cur_depth, &cur_context}; 127 Label context_search(this, 2, context_search_loop_variables); 128 129 // Loop until the depth is 0. 130 Goto(&context_search); 131 Bind(&context_search); 132 { 133 // TODO(leszeks): We only need to do this check if the context had a sloppy 134 // eval, we could pass in a context chain bitmask to figure out which 135 // contexts actually need to be checked. 136 137 Node* extension_slot = 138 LoadContextElement(cur_context.value(), Context::EXTENSION_INDEX); 139 140 // Jump to the target if the extension slot is not a hole. 141 GotoIf(WordNotEqual(extension_slot, TheHoleConstant()), target); 142 143 cur_depth.Bind(Int32Sub(cur_depth.value(), Int32Constant(1))); 144 cur_context.Bind( 145 LoadContextElement(cur_context.value(), Context::PREVIOUS_INDEX)); 146 147 GotoIf(Word32NotEqual(cur_depth.value(), Int32Constant(0)), 148 &context_search); 149 } 150 } 151 152 Node* InterpreterAssembler::BytecodeOffset() { 153 return bytecode_offset_.value(); 154 } 155 156 Node* InterpreterAssembler::BytecodeArrayTaggedPointer() { 157 if (made_call_) { 158 // If we have made a call, restore bytecode array from stack frame in case 159 // the debugger has swapped us to the patched debugger bytecode array. 160 return LoadRegister(Register::bytecode_array()); 161 } else { 162 return Parameter(InterpreterDispatchDescriptor::kBytecodeArray); 163 } 164 } 165 166 Node* InterpreterAssembler::DispatchTableRawPointer() { 167 return Parameter(InterpreterDispatchDescriptor::kDispatchTable); 168 } 169 170 Node* InterpreterAssembler::RegisterLocation(Node* reg_index) { 171 return IntPtrAdd(GetInterpretedFramePointer(), 172 RegisterFrameOffset(reg_index)); 173 } 174 175 Node* InterpreterAssembler::RegisterFrameOffset(Node* index) { 176 return WordShl(index, kPointerSizeLog2); 177 } 178 179 Node* InterpreterAssembler::LoadRegister(Register reg) { 180 return Load(MachineType::AnyTagged(), GetInterpretedFramePointer(), 181 IntPtrConstant(reg.ToOperand() << kPointerSizeLog2)); 182 } 183 184 Node* InterpreterAssembler::LoadRegister(Node* reg_index) { 185 return Load(MachineType::AnyTagged(), GetInterpretedFramePointer(), 186 RegisterFrameOffset(reg_index)); 187 } 188 189 Node* InterpreterAssembler::StoreRegister(Node* value, Register reg) { 190 return StoreNoWriteBarrier( 191 MachineRepresentation::kTagged, GetInterpretedFramePointer(), 192 IntPtrConstant(reg.ToOperand() << kPointerSizeLog2), value); 193 } 194 195 Node* InterpreterAssembler::StoreRegister(Node* value, Node* reg_index) { 196 return StoreNoWriteBarrier(MachineRepresentation::kTagged, 197 GetInterpretedFramePointer(), 198 RegisterFrameOffset(reg_index), value); 199 } 200 201 Node* InterpreterAssembler::NextRegister(Node* reg_index) { 202 // Register indexes are negative, so the next index is minus one. 203 return IntPtrAdd(reg_index, IntPtrConstant(-1)); 204 } 205 206 Node* InterpreterAssembler::OperandOffset(int operand_index) { 207 return IntPtrConstant( 208 Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale())); 209 } 210 211 Node* InterpreterAssembler::BytecodeOperandUnsignedByte(int operand_index) { 212 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); 213 DCHECK_EQ(OperandSize::kByte, Bytecodes::GetOperandSize( 214 bytecode_, operand_index, operand_scale())); 215 Node* operand_offset = OperandOffset(operand_index); 216 return Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(), 217 IntPtrAdd(BytecodeOffset(), operand_offset)); 218 } 219 220 Node* InterpreterAssembler::BytecodeOperandSignedByte(int operand_index) { 221 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); 222 DCHECK_EQ(OperandSize::kByte, Bytecodes::GetOperandSize( 223 bytecode_, operand_index, operand_scale())); 224 Node* operand_offset = OperandOffset(operand_index); 225 Node* load = Load(MachineType::Int8(), BytecodeArrayTaggedPointer(), 226 IntPtrAdd(BytecodeOffset(), operand_offset)); 227 228 // Ensure that we sign extend to full pointer size 229 if (kPointerSize == 8) { 230 load = ChangeInt32ToInt64(load); 231 } 232 return load; 233 } 234 235 compiler::Node* InterpreterAssembler::BytecodeOperandReadUnaligned( 236 int relative_offset, MachineType result_type) { 237 static const int kMaxCount = 4; 238 DCHECK(!TargetSupportsUnalignedAccess()); 239 240 int count; 241 switch (result_type.representation()) { 242 case MachineRepresentation::kWord16: 243 count = 2; 244 break; 245 case MachineRepresentation::kWord32: 246 count = 4; 247 break; 248 default: 249 UNREACHABLE(); 250 break; 251 } 252 MachineType msb_type = 253 result_type.IsSigned() ? MachineType::Int8() : MachineType::Uint8(); 254 255 #if V8_TARGET_LITTLE_ENDIAN 256 const int kStep = -1; 257 int msb_offset = count - 1; 258 #elif V8_TARGET_BIG_ENDIAN 259 const int kStep = 1; 260 int msb_offset = 0; 261 #else 262 #error "Unknown Architecture" 263 #endif 264 265 // Read the most signicant bytecode into bytes[0] and then in order 266 // down to least significant in bytes[count - 1]. 267 DCHECK(count <= kMaxCount); 268 compiler::Node* bytes[kMaxCount]; 269 for (int i = 0; i < count; i++) { 270 MachineType machine_type = (i == 0) ? msb_type : MachineType::Uint8(); 271 Node* offset = IntPtrConstant(relative_offset + msb_offset + i * kStep); 272 Node* array_offset = IntPtrAdd(BytecodeOffset(), offset); 273 bytes[i] = Load(machine_type, BytecodeArrayTaggedPointer(), array_offset); 274 } 275 276 // Pack LSB to MSB. 277 Node* result = bytes[--count]; 278 for (int i = 1; --count >= 0; i++) { 279 Node* shift = Int32Constant(i * kBitsPerByte); 280 Node* value = Word32Shl(bytes[count], shift); 281 result = Word32Or(value, result); 282 } 283 return result; 284 } 285 286 Node* InterpreterAssembler::BytecodeOperandUnsignedShort(int operand_index) { 287 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); 288 DCHECK_EQ( 289 OperandSize::kShort, 290 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale())); 291 int operand_offset = 292 Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale()); 293 if (TargetSupportsUnalignedAccess()) { 294 return Load(MachineType::Uint16(), BytecodeArrayTaggedPointer(), 295 IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset))); 296 } else { 297 return BytecodeOperandReadUnaligned(operand_offset, MachineType::Uint16()); 298 } 299 } 300 301 Node* InterpreterAssembler::BytecodeOperandSignedShort(int operand_index) { 302 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); 303 DCHECK_EQ( 304 OperandSize::kShort, 305 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale())); 306 int operand_offset = 307 Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale()); 308 Node* load; 309 if (TargetSupportsUnalignedAccess()) { 310 load = Load(MachineType::Int16(), BytecodeArrayTaggedPointer(), 311 IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset))); 312 } else { 313 load = BytecodeOperandReadUnaligned(operand_offset, MachineType::Int16()); 314 } 315 316 // Ensure that we sign extend to full pointer size 317 if (kPointerSize == 8) { 318 load = ChangeInt32ToInt64(load); 319 } 320 return load; 321 } 322 323 Node* InterpreterAssembler::BytecodeOperandUnsignedQuad(int operand_index) { 324 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); 325 DCHECK_EQ(OperandSize::kQuad, Bytecodes::GetOperandSize( 326 bytecode_, operand_index, operand_scale())); 327 int operand_offset = 328 Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale()); 329 if (TargetSupportsUnalignedAccess()) { 330 return Load(MachineType::Uint32(), BytecodeArrayTaggedPointer(), 331 IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset))); 332 } else { 333 return BytecodeOperandReadUnaligned(operand_offset, MachineType::Uint32()); 334 } 335 } 336 337 Node* InterpreterAssembler::BytecodeOperandSignedQuad(int operand_index) { 338 DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(bytecode_)); 339 DCHECK_EQ(OperandSize::kQuad, Bytecodes::GetOperandSize( 340 bytecode_, operand_index, operand_scale())); 341 int operand_offset = 342 Bytecodes::GetOperandOffset(bytecode_, operand_index, operand_scale()); 343 Node* load; 344 if (TargetSupportsUnalignedAccess()) { 345 load = Load(MachineType::Int32(), BytecodeArrayTaggedPointer(), 346 IntPtrAdd(BytecodeOffset(), IntPtrConstant(operand_offset))); 347 } else { 348 load = BytecodeOperandReadUnaligned(operand_offset, MachineType::Int32()); 349 } 350 351 // Ensure that we sign extend to full pointer size 352 if (kPointerSize == 8) { 353 load = ChangeInt32ToInt64(load); 354 } 355 return load; 356 } 357 358 Node* InterpreterAssembler::BytecodeSignedOperand(int operand_index, 359 OperandSize operand_size) { 360 DCHECK(!Bytecodes::IsUnsignedOperandType( 361 Bytecodes::GetOperandType(bytecode_, operand_index))); 362 switch (operand_size) { 363 case OperandSize::kByte: 364 return BytecodeOperandSignedByte(operand_index); 365 case OperandSize::kShort: 366 return BytecodeOperandSignedShort(operand_index); 367 case OperandSize::kQuad: 368 return BytecodeOperandSignedQuad(operand_index); 369 case OperandSize::kNone: 370 UNREACHABLE(); 371 } 372 return nullptr; 373 } 374 375 Node* InterpreterAssembler::BytecodeUnsignedOperand(int operand_index, 376 OperandSize operand_size) { 377 DCHECK(Bytecodes::IsUnsignedOperandType( 378 Bytecodes::GetOperandType(bytecode_, operand_index))); 379 switch (operand_size) { 380 case OperandSize::kByte: 381 return BytecodeOperandUnsignedByte(operand_index); 382 case OperandSize::kShort: 383 return BytecodeOperandUnsignedShort(operand_index); 384 case OperandSize::kQuad: 385 return BytecodeOperandUnsignedQuad(operand_index); 386 case OperandSize::kNone: 387 UNREACHABLE(); 388 } 389 return nullptr; 390 } 391 392 Node* InterpreterAssembler::BytecodeOperandCount(int operand_index) { 393 DCHECK_EQ(OperandType::kRegCount, 394 Bytecodes::GetOperandType(bytecode_, operand_index)); 395 OperandSize operand_size = 396 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); 397 return BytecodeUnsignedOperand(operand_index, operand_size); 398 } 399 400 Node* InterpreterAssembler::BytecodeOperandFlag(int operand_index) { 401 DCHECK_EQ(OperandType::kFlag8, 402 Bytecodes::GetOperandType(bytecode_, operand_index)); 403 OperandSize operand_size = 404 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); 405 DCHECK_EQ(operand_size, OperandSize::kByte); 406 return BytecodeUnsignedOperand(operand_index, operand_size); 407 } 408 409 Node* InterpreterAssembler::BytecodeOperandUImm(int operand_index) { 410 DCHECK_EQ(OperandType::kUImm, 411 Bytecodes::GetOperandType(bytecode_, operand_index)); 412 OperandSize operand_size = 413 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); 414 return BytecodeUnsignedOperand(operand_index, operand_size); 415 } 416 417 Node* InterpreterAssembler::BytecodeOperandImm(int operand_index) { 418 DCHECK_EQ(OperandType::kImm, 419 Bytecodes::GetOperandType(bytecode_, operand_index)); 420 OperandSize operand_size = 421 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); 422 return BytecodeSignedOperand(operand_index, operand_size); 423 } 424 425 Node* InterpreterAssembler::BytecodeOperandIdx(int operand_index) { 426 DCHECK(OperandType::kIdx == 427 Bytecodes::GetOperandType(bytecode_, operand_index)); 428 OperandSize operand_size = 429 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); 430 return BytecodeUnsignedOperand(operand_index, operand_size); 431 } 432 433 Node* InterpreterAssembler::BytecodeOperandReg(int operand_index) { 434 DCHECK(Bytecodes::IsRegisterOperandType( 435 Bytecodes::GetOperandType(bytecode_, operand_index))); 436 OperandSize operand_size = 437 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); 438 return BytecodeSignedOperand(operand_index, operand_size); 439 } 440 441 Node* InterpreterAssembler::BytecodeOperandRuntimeId(int operand_index) { 442 DCHECK(OperandType::kRuntimeId == 443 Bytecodes::GetOperandType(bytecode_, operand_index)); 444 OperandSize operand_size = 445 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); 446 DCHECK_EQ(operand_size, OperandSize::kShort); 447 return BytecodeUnsignedOperand(operand_index, operand_size); 448 } 449 450 Node* InterpreterAssembler::BytecodeOperandIntrinsicId(int operand_index) { 451 DCHECK(OperandType::kIntrinsicId == 452 Bytecodes::GetOperandType(bytecode_, operand_index)); 453 OperandSize operand_size = 454 Bytecodes::GetOperandSize(bytecode_, operand_index, operand_scale()); 455 DCHECK_EQ(operand_size, OperandSize::kByte); 456 return BytecodeUnsignedOperand(operand_index, operand_size); 457 } 458 459 Node* InterpreterAssembler::LoadConstantPoolEntry(Node* index) { 460 Node* constant_pool = LoadObjectField(BytecodeArrayTaggedPointer(), 461 BytecodeArray::kConstantPoolOffset); 462 Node* entry_offset = 463 IntPtrAdd(IntPtrConstant(FixedArray::kHeaderSize - kHeapObjectTag), 464 WordShl(index, kPointerSizeLog2)); 465 return Load(MachineType::AnyTagged(), constant_pool, entry_offset); 466 } 467 468 Node* InterpreterAssembler::LoadAndUntagConstantPoolEntry(Node* index) { 469 Node* constant_pool = LoadObjectField(BytecodeArrayTaggedPointer(), 470 BytecodeArray::kConstantPoolOffset); 471 int offset = FixedArray::kHeaderSize - kHeapObjectTag; 472 #if V8_TARGET_LITTLE_ENDIAN 473 if (Is64()) { 474 offset += kPointerSize / 2; 475 } 476 #endif 477 Node* entry_offset = 478 IntPtrAdd(IntPtrConstant(offset), WordShl(index, kPointerSizeLog2)); 479 if (Is64()) { 480 return ChangeInt32ToInt64( 481 Load(MachineType::Int32(), constant_pool, entry_offset)); 482 } else { 483 return SmiUntag( 484 Load(MachineType::AnyTagged(), constant_pool, entry_offset)); 485 } 486 } 487 488 Node* InterpreterAssembler::LoadTypeFeedbackVector() { 489 Node* function = LoadRegister(Register::function_closure()); 490 Node* literals = LoadObjectField(function, JSFunction::kLiteralsOffset); 491 Node* vector = 492 LoadObjectField(literals, LiteralsArray::kFeedbackVectorOffset); 493 return vector; 494 } 495 496 void InterpreterAssembler::CallPrologue() { 497 StoreRegister(SmiTag(BytecodeOffset()), Register::bytecode_offset()); 498 499 if (FLAG_debug_code && !disable_stack_check_across_call_) { 500 DCHECK(stack_pointer_before_call_ == nullptr); 501 stack_pointer_before_call_ = LoadStackPointer(); 502 } 503 made_call_ = true; 504 } 505 506 void InterpreterAssembler::CallEpilogue() { 507 if (FLAG_debug_code && !disable_stack_check_across_call_) { 508 Node* stack_pointer_after_call = LoadStackPointer(); 509 Node* stack_pointer_before_call = stack_pointer_before_call_; 510 stack_pointer_before_call_ = nullptr; 511 AbortIfWordNotEqual(stack_pointer_before_call, stack_pointer_after_call, 512 kUnexpectedStackPointer); 513 } 514 } 515 516 Node* InterpreterAssembler::IncrementCallCount(Node* type_feedback_vector, 517 Node* slot_id) { 518 Comment("increment call count"); 519 Node* call_count_slot = IntPtrAdd(slot_id, IntPtrConstant(1)); 520 Node* call_count = 521 LoadFixedArrayElement(type_feedback_vector, call_count_slot); 522 Node* new_count = SmiAdd(call_count, SmiTag(Int32Constant(1))); 523 // Count is Smi, so we don't need a write barrier. 524 return StoreFixedArrayElement(type_feedback_vector, call_count_slot, 525 new_count, SKIP_WRITE_BARRIER); 526 } 527 528 Node* InterpreterAssembler::CallJSWithFeedback(Node* function, Node* context, 529 Node* first_arg, Node* arg_count, 530 Node* slot_id, 531 Node* type_feedback_vector, 532 TailCallMode tail_call_mode) { 533 // Static checks to assert it is safe to examine the type feedback element. 534 // We don't know that we have a weak cell. We might have a private symbol 535 // or an AllocationSite, but the memory is safe to examine. 536 // AllocationSite::kTransitionInfoOffset - contains a Smi or pointer to 537 // FixedArray. 538 // WeakCell::kValueOffset - contains a JSFunction or Smi(0) 539 // Symbol::kHashFieldSlot - if the low bit is 1, then the hash is not 540 // computed, meaning that it can't appear to be a pointer. If the low bit is 541 // 0, then hash is computed, but the 0 bit prevents the field from appearing 542 // to be a pointer. 543 STATIC_ASSERT(WeakCell::kSize >= kPointerSize); 544 STATIC_ASSERT(AllocationSite::kTransitionInfoOffset == 545 WeakCell::kValueOffset && 546 WeakCell::kValueOffset == Symbol::kHashFieldSlot); 547 548 Variable return_value(this, MachineRepresentation::kTagged); 549 Label call_function(this), extra_checks(this, Label::kDeferred), call(this), 550 end(this); 551 552 // The checks. First, does function match the recorded monomorphic target? 553 Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id); 554 Node* feedback_value = LoadWeakCellValueUnchecked(feedback_element); 555 Node* is_monomorphic = WordEqual(function, feedback_value); 556 GotoUnless(is_monomorphic, &extra_checks); 557 558 // The compare above could have been a SMI/SMI comparison. Guard against 559 // this convincing us that we have a monomorphic JSFunction. 560 Node* is_smi = TaggedIsSmi(function); 561 Branch(is_smi, &extra_checks, &call_function); 562 563 Bind(&call_function); 564 { 565 // Increment the call count. 566 IncrementCallCount(type_feedback_vector, slot_id); 567 568 // Call using call function builtin. 569 Callable callable = CodeFactory::InterpreterPushArgsAndCall( 570 isolate(), tail_call_mode, CallableType::kJSFunction); 571 Node* code_target = HeapConstant(callable.code()); 572 Node* ret_value = CallStub(callable.descriptor(), code_target, context, 573 arg_count, first_arg, function); 574 return_value.Bind(ret_value); 575 Goto(&end); 576 } 577 578 Bind(&extra_checks); 579 { 580 Label check_initialized(this), mark_megamorphic(this), 581 create_allocation_site(this); 582 583 Comment("check if megamorphic"); 584 // Check if it is a megamorphic target. 585 Node* is_megamorphic = WordEqual( 586 feedback_element, 587 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate()))); 588 GotoIf(is_megamorphic, &call); 589 590 Comment("check if it is an allocation site"); 591 Node* is_allocation_site = WordEqual( 592 LoadMap(feedback_element), LoadRoot(Heap::kAllocationSiteMapRootIndex)); 593 GotoUnless(is_allocation_site, &check_initialized); 594 595 // If it is not the Array() function, mark megamorphic. 596 Node* context_slot = 597 LoadFixedArrayElement(LoadNativeContext(context), 598 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); 599 Node* is_array_function = WordEqual(context_slot, function); 600 GotoUnless(is_array_function, &mark_megamorphic); 601 602 // It is a monomorphic Array function. Increment the call count. 603 IncrementCallCount(type_feedback_vector, slot_id); 604 605 // Call ArrayConstructorStub. 606 Callable callable_call = 607 CodeFactory::InterpreterPushArgsAndConstructArray(isolate()); 608 Node* code_target_call = HeapConstant(callable_call.code()); 609 Node* ret_value = 610 CallStub(callable_call.descriptor(), code_target_call, context, 611 arg_count, function, feedback_element, first_arg); 612 return_value.Bind(ret_value); 613 Goto(&end); 614 615 Bind(&check_initialized); 616 { 617 Comment("check if uninitialized"); 618 // Check if it is uninitialized target first. 619 Node* is_uninitialized = WordEqual( 620 feedback_element, 621 HeapConstant(TypeFeedbackVector::UninitializedSentinel(isolate()))); 622 GotoUnless(is_uninitialized, &mark_megamorphic); 623 624 Comment("handle_unitinitialized"); 625 // If it is not a JSFunction mark it as megamorphic. 626 Node* is_smi = TaggedIsSmi(function); 627 GotoIf(is_smi, &mark_megamorphic); 628 629 // Check if function is an object of JSFunction type. 630 Node* instance_type = LoadInstanceType(function); 631 Node* is_js_function = 632 WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)); 633 GotoUnless(is_js_function, &mark_megamorphic); 634 635 // Check if it is the Array() function. 636 Node* context_slot = 637 LoadFixedArrayElement(LoadNativeContext(context), 638 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); 639 Node* is_array_function = WordEqual(context_slot, function); 640 GotoIf(is_array_function, &create_allocation_site); 641 642 // Check if the function belongs to the same native context. 643 Node* native_context = LoadNativeContext( 644 LoadObjectField(function, JSFunction::kContextOffset)); 645 Node* is_same_native_context = 646 WordEqual(native_context, LoadNativeContext(context)); 647 GotoUnless(is_same_native_context, &mark_megamorphic); 648 649 CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id), 650 function); 651 652 // Call using call function builtin. 653 Goto(&call_function); 654 } 655 656 Bind(&create_allocation_site); 657 { 658 CreateAllocationSiteInFeedbackVector(type_feedback_vector, 659 SmiTag(slot_id)); 660 661 // Call using CallFunction builtin. CallICs have a PREMONOMORPHIC state. 662 // They start collecting feedback only when a call is executed the second 663 // time. So, do not pass any feedback here. 664 Goto(&call_function); 665 } 666 667 Bind(&mark_megamorphic); 668 { 669 // Mark it as a megamorphic. 670 // MegamorphicSentinel is created as a part of Heap::InitialObjects 671 // and will not move during a GC. So it is safe to skip write barrier. 672 DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex)); 673 StoreFixedArrayElement( 674 type_feedback_vector, slot_id, 675 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())), 676 SKIP_WRITE_BARRIER); 677 Goto(&call); 678 } 679 } 680 681 Bind(&call); 682 { 683 Comment("Increment call count and call using Call builtin"); 684 // Increment the call count. 685 IncrementCallCount(type_feedback_vector, slot_id); 686 687 // Call using call builtin. 688 Callable callable_call = CodeFactory::InterpreterPushArgsAndCall( 689 isolate(), tail_call_mode, CallableType::kAny); 690 Node* code_target_call = HeapConstant(callable_call.code()); 691 Node* ret_value = CallStub(callable_call.descriptor(), code_target_call, 692 context, arg_count, first_arg, function); 693 return_value.Bind(ret_value); 694 Goto(&end); 695 } 696 697 Bind(&end); 698 return return_value.value(); 699 } 700 701 Node* InterpreterAssembler::CallJS(Node* function, Node* context, 702 Node* first_arg, Node* arg_count, 703 TailCallMode tail_call_mode) { 704 Callable callable = CodeFactory::InterpreterPushArgsAndCall( 705 isolate(), tail_call_mode, CallableType::kAny); 706 Node* code_target = HeapConstant(callable.code()); 707 return CallStub(callable.descriptor(), code_target, context, arg_count, 708 first_arg, function); 709 } 710 711 Node* InterpreterAssembler::CallConstruct(Node* constructor, Node* context, 712 Node* new_target, Node* first_arg, 713 Node* arg_count, Node* slot_id, 714 Node* type_feedback_vector) { 715 Variable return_value(this, MachineRepresentation::kTagged); 716 Variable allocation_feedback(this, MachineRepresentation::kTagged); 717 Label call_construct_function(this, &allocation_feedback), 718 extra_checks(this, Label::kDeferred), call_construct(this), end(this); 719 720 // Slot id of 0 is used to indicate no type feedback is available. 721 STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0); 722 Node* is_feedback_unavailable = Word32Equal(slot_id, Int32Constant(0)); 723 GotoIf(is_feedback_unavailable, &call_construct); 724 725 // Check that the constructor is not a smi. 726 Node* is_smi = TaggedIsSmi(constructor); 727 GotoIf(is_smi, &call_construct); 728 729 // Check that constructor is a JSFunction. 730 Node* instance_type = LoadInstanceType(constructor); 731 Node* is_js_function = 732 WordEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)); 733 GotoUnless(is_js_function, &call_construct); 734 735 // Check if it is a monomorphic constructor. 736 Node* feedback_element = LoadFixedArrayElement(type_feedback_vector, slot_id); 737 Node* feedback_value = LoadWeakCellValueUnchecked(feedback_element); 738 Node* is_monomorphic = WordEqual(constructor, feedback_value); 739 allocation_feedback.Bind(UndefinedConstant()); 740 Branch(is_monomorphic, &call_construct_function, &extra_checks); 741 742 Bind(&call_construct_function); 743 { 744 Comment("call using callConstructFunction"); 745 IncrementCallCount(type_feedback_vector, slot_id); 746 Callable callable_function = CodeFactory::InterpreterPushArgsAndConstruct( 747 isolate(), CallableType::kJSFunction); 748 return_value.Bind(CallStub(callable_function.descriptor(), 749 HeapConstant(callable_function.code()), context, 750 arg_count, new_target, constructor, 751 allocation_feedback.value(), first_arg)); 752 Goto(&end); 753 } 754 755 Bind(&extra_checks); 756 { 757 Label check_allocation_site(this), check_initialized(this), 758 initialize(this), mark_megamorphic(this); 759 760 // Check if it is a megamorphic target. 761 Comment("check if megamorphic"); 762 Node* is_megamorphic = WordEqual( 763 feedback_element, 764 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate()))); 765 GotoIf(is_megamorphic, &call_construct_function); 766 767 Comment("check if weak cell"); 768 Node* is_weak_cell = WordEqual(LoadMap(feedback_element), 769 LoadRoot(Heap::kWeakCellMapRootIndex)); 770 GotoUnless(is_weak_cell, &check_allocation_site); 771 772 // If the weak cell is cleared, we have a new chance to become 773 // monomorphic. 774 Comment("check if weak cell is cleared"); 775 Node* is_smi = TaggedIsSmi(feedback_value); 776 Branch(is_smi, &initialize, &mark_megamorphic); 777 778 Bind(&check_allocation_site); 779 { 780 Comment("check if it is an allocation site"); 781 Node* is_allocation_site = 782 WordEqual(LoadObjectField(feedback_element, 0), 783 LoadRoot(Heap::kAllocationSiteMapRootIndex)); 784 GotoUnless(is_allocation_site, &check_initialized); 785 786 // Make sure the function is the Array() function. 787 Node* context_slot = 788 LoadFixedArrayElement(LoadNativeContext(context), 789 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); 790 Node* is_array_function = WordEqual(context_slot, constructor); 791 GotoUnless(is_array_function, &mark_megamorphic); 792 793 allocation_feedback.Bind(feedback_element); 794 Goto(&call_construct_function); 795 } 796 797 Bind(&check_initialized); 798 { 799 // Check if it is uninitialized. 800 Comment("check if uninitialized"); 801 Node* is_uninitialized = WordEqual( 802 feedback_element, LoadRoot(Heap::kuninitialized_symbolRootIndex)); 803 Branch(is_uninitialized, &initialize, &mark_megamorphic); 804 } 805 806 Bind(&initialize); 807 { 808 Label create_allocation_site(this), create_weak_cell(this); 809 Comment("initialize the feedback element"); 810 // Create an allocation site if the function is an array function, 811 // otherwise create a weak cell. 812 Node* context_slot = 813 LoadFixedArrayElement(LoadNativeContext(context), 814 Int32Constant(Context::ARRAY_FUNCTION_INDEX)); 815 Node* is_array_function = WordEqual(context_slot, constructor); 816 Branch(is_array_function, &create_allocation_site, &create_weak_cell); 817 818 Bind(&create_allocation_site); 819 { 820 Node* site = CreateAllocationSiteInFeedbackVector(type_feedback_vector, 821 SmiTag(slot_id)); 822 allocation_feedback.Bind(site); 823 Goto(&call_construct_function); 824 } 825 826 Bind(&create_weak_cell); 827 { 828 CreateWeakCellInFeedbackVector(type_feedback_vector, SmiTag(slot_id), 829 constructor); 830 Goto(&call_construct_function); 831 } 832 } 833 834 Bind(&mark_megamorphic); 835 { 836 // MegamorphicSentinel is an immortal immovable object so 837 // write-barrier is not needed. 838 Comment("transition to megamorphic"); 839 DCHECK(Heap::RootIsImmortalImmovable(Heap::kmegamorphic_symbolRootIndex)); 840 StoreFixedArrayElement( 841 type_feedback_vector, slot_id, 842 HeapConstant(TypeFeedbackVector::MegamorphicSentinel(isolate())), 843 SKIP_WRITE_BARRIER); 844 Goto(&call_construct_function); 845 } 846 } 847 848 Bind(&call_construct); 849 { 850 Comment("call using callConstruct builtin"); 851 Callable callable = CodeFactory::InterpreterPushArgsAndConstruct( 852 isolate(), CallableType::kAny); 853 Node* code_target = HeapConstant(callable.code()); 854 return_value.Bind(CallStub(callable.descriptor(), code_target, context, 855 arg_count, new_target, constructor, 856 UndefinedConstant(), first_arg)); 857 Goto(&end); 858 } 859 860 Bind(&end); 861 return return_value.value(); 862 } 863 864 Node* InterpreterAssembler::CallRuntimeN(Node* function_id, Node* context, 865 Node* first_arg, Node* arg_count, 866 int result_size) { 867 Callable callable = CodeFactory::InterpreterCEntry(isolate(), result_size); 868 Node* code_target = HeapConstant(callable.code()); 869 870 // Get the function entry from the function id. 871 Node* function_table = ExternalConstant( 872 ExternalReference::runtime_function_table_address(isolate())); 873 Node* function_offset = 874 Int32Mul(function_id, Int32Constant(sizeof(Runtime::Function))); 875 Node* function = IntPtrAdd(function_table, function_offset); 876 Node* function_entry = 877 Load(MachineType::Pointer(), function, 878 IntPtrConstant(offsetof(Runtime::Function, entry))); 879 880 return CallStub(callable.descriptor(), code_target, context, arg_count, 881 first_arg, function_entry, result_size); 882 } 883 884 void InterpreterAssembler::UpdateInterruptBudget(Node* weight) { 885 // TODO(rmcilroy): It might be worthwhile to only update the budget for 886 // backwards branches. Those are distinguishable by the {JumpLoop} bytecode. 887 888 Label ok(this), interrupt_check(this, Label::kDeferred), end(this); 889 Node* budget_offset = 890 IntPtrConstant(BytecodeArray::kInterruptBudgetOffset - kHeapObjectTag); 891 892 // Update budget by |weight| and check if it reaches zero. 893 Variable new_budget(this, MachineRepresentation::kWord32); 894 Node* old_budget = 895 Load(MachineType::Int32(), BytecodeArrayTaggedPointer(), budget_offset); 896 new_budget.Bind(Int32Add(old_budget, weight)); 897 Node* condition = 898 Int32GreaterThanOrEqual(new_budget.value(), Int32Constant(0)); 899 Branch(condition, &ok, &interrupt_check); 900 901 // Perform interrupt and reset budget. 902 Bind(&interrupt_check); 903 { 904 CallRuntime(Runtime::kInterrupt, GetContext()); 905 new_budget.Bind(Int32Constant(Interpreter::InterruptBudget())); 906 Goto(&ok); 907 } 908 909 // Update budget. 910 Bind(&ok); 911 StoreNoWriteBarrier(MachineRepresentation::kWord32, 912 BytecodeArrayTaggedPointer(), budget_offset, 913 new_budget.value()); 914 } 915 916 Node* InterpreterAssembler::Advance() { 917 return Advance(Bytecodes::Size(bytecode_, operand_scale_)); 918 } 919 920 Node* InterpreterAssembler::Advance(int delta) { 921 return Advance(IntPtrConstant(delta)); 922 } 923 924 Node* InterpreterAssembler::Advance(Node* delta) { 925 if (FLAG_trace_ignition) { 926 TraceBytecode(Runtime::kInterpreterTraceBytecodeExit); 927 } 928 Node* next_offset = IntPtrAdd(BytecodeOffset(), delta); 929 bytecode_offset_.Bind(next_offset); 930 return next_offset; 931 } 932 933 Node* InterpreterAssembler::Jump(Node* delta) { 934 DCHECK(!Bytecodes::IsStarLookahead(bytecode_, operand_scale_)); 935 936 UpdateInterruptBudget(delta); 937 Node* new_bytecode_offset = Advance(delta); 938 Node* target_bytecode = LoadBytecode(new_bytecode_offset); 939 return DispatchToBytecode(target_bytecode, new_bytecode_offset); 940 } 941 942 void InterpreterAssembler::JumpConditional(Node* condition, Node* delta) { 943 Label match(this), no_match(this); 944 945 Branch(condition, &match, &no_match); 946 Bind(&match); 947 Jump(delta); 948 Bind(&no_match); 949 Dispatch(); 950 } 951 952 void InterpreterAssembler::JumpIfWordEqual(Node* lhs, Node* rhs, Node* delta) { 953 JumpConditional(WordEqual(lhs, rhs), delta); 954 } 955 956 void InterpreterAssembler::JumpIfWordNotEqual(Node* lhs, Node* rhs, 957 Node* delta) { 958 JumpConditional(WordNotEqual(lhs, rhs), delta); 959 } 960 961 Node* InterpreterAssembler::LoadBytecode(compiler::Node* bytecode_offset) { 962 Node* bytecode = 963 Load(MachineType::Uint8(), BytecodeArrayTaggedPointer(), bytecode_offset); 964 if (kPointerSize == 8) { 965 bytecode = ChangeUint32ToUint64(bytecode); 966 } 967 return bytecode; 968 } 969 970 Node* InterpreterAssembler::StarDispatchLookahead(Node* target_bytecode) { 971 Label do_inline_star(this), done(this); 972 973 Variable var_bytecode(this, MachineType::PointerRepresentation()); 974 var_bytecode.Bind(target_bytecode); 975 976 Node* star_bytecode = IntPtrConstant(static_cast<int>(Bytecode::kStar)); 977 Node* is_star = WordEqual(target_bytecode, star_bytecode); 978 Branch(is_star, &do_inline_star, &done); 979 980 Bind(&do_inline_star); 981 { 982 InlineStar(); 983 var_bytecode.Bind(LoadBytecode(BytecodeOffset())); 984 Goto(&done); 985 } 986 Bind(&done); 987 return var_bytecode.value(); 988 } 989 990 void InterpreterAssembler::InlineStar() { 991 Bytecode previous_bytecode = bytecode_; 992 AccumulatorUse previous_acc_use = accumulator_use_; 993 994 bytecode_ = Bytecode::kStar; 995 accumulator_use_ = AccumulatorUse::kNone; 996 997 if (FLAG_trace_ignition) { 998 TraceBytecode(Runtime::kInterpreterTraceBytecodeEntry); 999 } 1000 StoreRegister(GetAccumulator(), BytecodeOperandReg(0)); 1001 1002 DCHECK_EQ(accumulator_use_, Bytecodes::GetAccumulatorUse(bytecode_)); 1003 1004 Advance(); 1005 bytecode_ = previous_bytecode; 1006 accumulator_use_ = previous_acc_use; 1007 } 1008 1009 Node* InterpreterAssembler::Dispatch() { 1010 Node* target_offset = Advance(); 1011 Node* target_bytecode = LoadBytecode(target_offset); 1012 1013 if (Bytecodes::IsStarLookahead(bytecode_, operand_scale_)) { 1014 target_bytecode = StarDispatchLookahead(target_bytecode); 1015 } 1016 return DispatchToBytecode(target_bytecode, BytecodeOffset()); 1017 } 1018 1019 Node* InterpreterAssembler::DispatchToBytecode(Node* target_bytecode, 1020 Node* new_bytecode_offset) { 1021 if (FLAG_trace_ignition_dispatches) { 1022 TraceBytecodeDispatch(target_bytecode); 1023 } 1024 1025 Node* target_code_entry = 1026 Load(MachineType::Pointer(), DispatchTableRawPointer(), 1027 WordShl(target_bytecode, IntPtrConstant(kPointerSizeLog2))); 1028 1029 return DispatchToBytecodeHandlerEntry(target_code_entry, new_bytecode_offset); 1030 } 1031 1032 Node* InterpreterAssembler::DispatchToBytecodeHandler(Node* handler, 1033 Node* bytecode_offset) { 1034 Node* handler_entry = 1035 IntPtrAdd(handler, IntPtrConstant(Code::kHeaderSize - kHeapObjectTag)); 1036 return DispatchToBytecodeHandlerEntry(handler_entry, bytecode_offset); 1037 } 1038 1039 Node* InterpreterAssembler::DispatchToBytecodeHandlerEntry( 1040 Node* handler_entry, Node* bytecode_offset) { 1041 InterpreterDispatchDescriptor descriptor(isolate()); 1042 Node* args[] = {GetAccumulatorUnchecked(), bytecode_offset, 1043 BytecodeArrayTaggedPointer(), DispatchTableRawPointer()}; 1044 return TailCallBytecodeDispatch(descriptor, handler_entry, args); 1045 } 1046 1047 void InterpreterAssembler::DispatchWide(OperandScale operand_scale) { 1048 // Dispatching a wide bytecode requires treating the prefix 1049 // bytecode a base pointer into the dispatch table and dispatching 1050 // the bytecode that follows relative to this base. 1051 // 1052 // Indices 0-255 correspond to bytecodes with operand_scale == 0 1053 // Indices 256-511 correspond to bytecodes with operand_scale == 1 1054 // Indices 512-767 correspond to bytecodes with operand_scale == 2 1055 Node* next_bytecode_offset = Advance(1); 1056 Node* next_bytecode = LoadBytecode(next_bytecode_offset); 1057 1058 if (FLAG_trace_ignition_dispatches) { 1059 TraceBytecodeDispatch(next_bytecode); 1060 } 1061 1062 Node* base_index; 1063 switch (operand_scale) { 1064 case OperandScale::kDouble: 1065 base_index = IntPtrConstant(1 << kBitsPerByte); 1066 break; 1067 case OperandScale::kQuadruple: 1068 base_index = IntPtrConstant(2 << kBitsPerByte); 1069 break; 1070 default: 1071 UNREACHABLE(); 1072 base_index = nullptr; 1073 } 1074 Node* target_index = IntPtrAdd(base_index, next_bytecode); 1075 Node* target_code_entry = 1076 Load(MachineType::Pointer(), DispatchTableRawPointer(), 1077 WordShl(target_index, kPointerSizeLog2)); 1078 1079 DispatchToBytecodeHandlerEntry(target_code_entry, next_bytecode_offset); 1080 } 1081 1082 Node* InterpreterAssembler::TruncateTaggedToWord32WithFeedback( 1083 Node* context, Node* value, Variable* var_type_feedback) { 1084 // We might need to loop once due to ToNumber conversion. 1085 Variable var_value(this, MachineRepresentation::kTagged), 1086 var_result(this, MachineRepresentation::kWord32); 1087 Variable* loop_vars[] = {&var_value, var_type_feedback}; 1088 Label loop(this, 2, loop_vars), done_loop(this, &var_result); 1089 var_value.Bind(value); 1090 var_type_feedback->Bind(Int32Constant(BinaryOperationFeedback::kNone)); 1091 Goto(&loop); 1092 Bind(&loop); 1093 { 1094 // Load the current {value}. 1095 value = var_value.value(); 1096 1097 // Check if the {value} is a Smi or a HeapObject. 1098 Label if_valueissmi(this), if_valueisnotsmi(this); 1099 Branch(TaggedIsSmi(value), &if_valueissmi, &if_valueisnotsmi); 1100 1101 Bind(&if_valueissmi); 1102 { 1103 // Convert the Smi {value}. 1104 var_result.Bind(SmiToWord32(value)); 1105 var_type_feedback->Bind( 1106 Word32Or(var_type_feedback->value(), 1107 Int32Constant(BinaryOperationFeedback::kSignedSmall))); 1108 Goto(&done_loop); 1109 } 1110 1111 Bind(&if_valueisnotsmi); 1112 { 1113 // Check if {value} is a HeapNumber. 1114 Label if_valueisheapnumber(this), 1115 if_valueisnotheapnumber(this, Label::kDeferred); 1116 Node* value_map = LoadMap(value); 1117 Branch(WordEqual(value_map, HeapNumberMapConstant()), 1118 &if_valueisheapnumber, &if_valueisnotheapnumber); 1119 1120 Bind(&if_valueisheapnumber); 1121 { 1122 // Truncate the floating point value. 1123 var_result.Bind(TruncateHeapNumberValueToWord32(value)); 1124 var_type_feedback->Bind( 1125 Word32Or(var_type_feedback->value(), 1126 Int32Constant(BinaryOperationFeedback::kNumber))); 1127 Goto(&done_loop); 1128 } 1129 1130 Bind(&if_valueisnotheapnumber); 1131 { 1132 // We do not require an Or with earlier feedback here because once we 1133 // convert the value to a number, we cannot reach this path. We can 1134 // only reach this path on the first pass when the feedback is kNone. 1135 CSA_ASSERT(this, 1136 Word32Equal(var_type_feedback->value(), 1137 Int32Constant(BinaryOperationFeedback::kNone))); 1138 1139 Label if_valueisoddball(this), 1140 if_valueisnotoddball(this, Label::kDeferred); 1141 Node* is_oddball = Word32Equal(LoadMapInstanceType(value_map), 1142 Int32Constant(ODDBALL_TYPE)); 1143 Branch(is_oddball, &if_valueisoddball, &if_valueisnotoddball); 1144 1145 Bind(&if_valueisoddball); 1146 { 1147 // Convert Oddball to a Number and perform checks again. 1148 var_value.Bind(LoadObjectField(value, Oddball::kToNumberOffset)); 1149 var_type_feedback->Bind( 1150 Int32Constant(BinaryOperationFeedback::kNumberOrOddball)); 1151 Goto(&loop); 1152 } 1153 1154 Bind(&if_valueisnotoddball); 1155 { 1156 // Convert the {value} to a Number first. 1157 Callable callable = CodeFactory::NonNumberToNumber(isolate()); 1158 var_value.Bind(CallStub(callable, context, value)); 1159 var_type_feedback->Bind(Int32Constant(BinaryOperationFeedback::kAny)); 1160 Goto(&loop); 1161 } 1162 } 1163 } 1164 } 1165 Bind(&done_loop); 1166 return var_result.value(); 1167 } 1168 1169 void InterpreterAssembler::UpdateInterruptBudgetOnReturn() { 1170 // TODO(rmcilroy): Investigate whether it is worth supporting self 1171 // optimization of primitive functions like FullCodegen. 1172 1173 // Update profiling count by -BytecodeOffset to simulate backedge to start of 1174 // function. 1175 Node* profiling_weight = 1176 Int32Sub(Int32Constant(kHeapObjectTag + BytecodeArray::kHeaderSize), 1177 BytecodeOffset()); 1178 UpdateInterruptBudget(profiling_weight); 1179 } 1180 1181 Node* InterpreterAssembler::StackCheckTriggeredInterrupt() { 1182 Node* sp = LoadStackPointer(); 1183 Node* stack_limit = Load( 1184 MachineType::Pointer(), 1185 ExternalConstant(ExternalReference::address_of_stack_limit(isolate()))); 1186 return UintPtrLessThan(sp, stack_limit); 1187 } 1188 1189 Node* InterpreterAssembler::LoadOSRNestingLevel() { 1190 Node* offset = 1191 IntPtrConstant(BytecodeArray::kOSRNestingLevelOffset - kHeapObjectTag); 1192 return Load(MachineType::Int8(), BytecodeArrayTaggedPointer(), offset); 1193 } 1194 1195 void InterpreterAssembler::Abort(BailoutReason bailout_reason) { 1196 disable_stack_check_across_call_ = true; 1197 Node* abort_id = SmiTag(Int32Constant(bailout_reason)); 1198 CallRuntime(Runtime::kAbort, GetContext(), abort_id); 1199 disable_stack_check_across_call_ = false; 1200 } 1201 1202 void InterpreterAssembler::AbortIfWordNotEqual(Node* lhs, Node* rhs, 1203 BailoutReason bailout_reason) { 1204 Label ok(this), abort(this, Label::kDeferred); 1205 Branch(WordEqual(lhs, rhs), &ok, &abort); 1206 1207 Bind(&abort); 1208 Abort(bailout_reason); 1209 Goto(&ok); 1210 1211 Bind(&ok); 1212 } 1213 1214 void InterpreterAssembler::TraceBytecode(Runtime::FunctionId function_id) { 1215 CallRuntime(function_id, GetContext(), BytecodeArrayTaggedPointer(), 1216 SmiTag(BytecodeOffset()), GetAccumulatorUnchecked()); 1217 } 1218 1219 void InterpreterAssembler::TraceBytecodeDispatch(Node* target_bytecode) { 1220 Node* counters_table = ExternalConstant( 1221 ExternalReference::interpreter_dispatch_counters(isolate())); 1222 Node* source_bytecode_table_index = IntPtrConstant( 1223 static_cast<int>(bytecode_) * (static_cast<int>(Bytecode::kLast) + 1)); 1224 1225 Node* counter_offset = 1226 WordShl(IntPtrAdd(source_bytecode_table_index, target_bytecode), 1227 IntPtrConstant(kPointerSizeLog2)); 1228 Node* old_counter = 1229 Load(MachineType::IntPtr(), counters_table, counter_offset); 1230 1231 Label counter_ok(this), counter_saturated(this, Label::kDeferred); 1232 1233 Node* counter_reached_max = WordEqual( 1234 old_counter, IntPtrConstant(std::numeric_limits<uintptr_t>::max())); 1235 Branch(counter_reached_max, &counter_saturated, &counter_ok); 1236 1237 Bind(&counter_ok); 1238 { 1239 Node* new_counter = IntPtrAdd(old_counter, IntPtrConstant(1)); 1240 StoreNoWriteBarrier(MachineType::PointerRepresentation(), counters_table, 1241 counter_offset, new_counter); 1242 Goto(&counter_saturated); 1243 } 1244 1245 Bind(&counter_saturated); 1246 } 1247 1248 // static 1249 bool InterpreterAssembler::TargetSupportsUnalignedAccess() { 1250 #if V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 1251 return false; 1252 #elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_X87 || \ 1253 V8_TARGET_ARCH_S390 || V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || \ 1254 V8_TARGET_ARCH_PPC 1255 return true; 1256 #else 1257 #error "Unknown Architecture" 1258 #endif 1259 } 1260 1261 Node* InterpreterAssembler::RegisterCount() { 1262 Node* bytecode_array = LoadRegister(Register::bytecode_array()); 1263 Node* frame_size = LoadObjectField( 1264 bytecode_array, BytecodeArray::kFrameSizeOffset, MachineType::Int32()); 1265 return Word32Sar(frame_size, Int32Constant(kPointerSizeLog2)); 1266 } 1267 1268 Node* InterpreterAssembler::ExportRegisterFile(Node* array) { 1269 if (FLAG_debug_code) { 1270 Node* array_size = LoadAndUntagFixedArrayBaseLength(array); 1271 AbortIfWordNotEqual( 1272 array_size, RegisterCount(), kInvalidRegisterFileInGenerator); 1273 } 1274 1275 Variable var_index(this, MachineRepresentation::kWord32); 1276 var_index.Bind(Int32Constant(0)); 1277 1278 // Iterate over register file and write values into array. 1279 // The mapping of register to array index must match that used in 1280 // BytecodeGraphBuilder::VisitResumeGenerator. 1281 Label loop(this, &var_index), done_loop(this); 1282 Goto(&loop); 1283 Bind(&loop); 1284 { 1285 Node* index = var_index.value(); 1286 Node* condition = Int32LessThan(index, RegisterCount()); 1287 GotoUnless(condition, &done_loop); 1288 1289 Node* reg_index = 1290 Int32Sub(Int32Constant(Register(0).ToOperand()), index); 1291 Node* value = LoadRegister(ChangeInt32ToIntPtr(reg_index)); 1292 1293 StoreFixedArrayElement(array, index, value); 1294 1295 var_index.Bind(Int32Add(index, Int32Constant(1))); 1296 Goto(&loop); 1297 } 1298 Bind(&done_loop); 1299 1300 return array; 1301 } 1302 1303 Node* InterpreterAssembler::ImportRegisterFile(Node* array) { 1304 if (FLAG_debug_code) { 1305 Node* array_size = LoadAndUntagFixedArrayBaseLength(array); 1306 AbortIfWordNotEqual( 1307 array_size, RegisterCount(), kInvalidRegisterFileInGenerator); 1308 } 1309 1310 Variable var_index(this, MachineRepresentation::kWord32); 1311 var_index.Bind(Int32Constant(0)); 1312 1313 // Iterate over array and write values into register file. Also erase the 1314 // array contents to not keep them alive artificially. 1315 Label loop(this, &var_index), done_loop(this); 1316 Goto(&loop); 1317 Bind(&loop); 1318 { 1319 Node* index = var_index.value(); 1320 Node* condition = Int32LessThan(index, RegisterCount()); 1321 GotoUnless(condition, &done_loop); 1322 1323 Node* value = LoadFixedArrayElement(array, index); 1324 1325 Node* reg_index = 1326 Int32Sub(Int32Constant(Register(0).ToOperand()), index); 1327 StoreRegister(value, ChangeInt32ToIntPtr(reg_index)); 1328 1329 StoreFixedArrayElement(array, index, StaleRegisterConstant()); 1330 1331 var_index.Bind(Int32Add(index, Int32Constant(1))); 1332 Goto(&loop); 1333 } 1334 Bind(&done_loop); 1335 1336 return array; 1337 } 1338 1339 } // namespace interpreter 1340 } // namespace internal 1341 } // namespace v8 1342