11cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/compiler/basic-block-instrumentor.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <sstream> 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#include "src/codegen/optimized-compilation-info.h" 101cb0ef41Sopenharmony_ci#include "src/compiler/common-operator.h" 111cb0ef41Sopenharmony_ci#include "src/compiler/graph.h" 121cb0ef41Sopenharmony_ci#include "src/compiler/machine-operator.h" 131cb0ef41Sopenharmony_ci#include "src/compiler/node.h" 141cb0ef41Sopenharmony_ci#include "src/compiler/operator-properties.h" 151cb0ef41Sopenharmony_ci#include "src/compiler/schedule.h" 161cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_cinamespace v8 { 191cb0ef41Sopenharmony_cinamespace internal { 201cb0ef41Sopenharmony_cinamespace compiler { 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci// Find the first place to insert new nodes in a block that's already been 231cb0ef41Sopenharmony_ci// scheduled that won't upset the register allocator. 241cb0ef41Sopenharmony_cistatic NodeVector::iterator FindInsertionPoint(BasicBlock* block) { 251cb0ef41Sopenharmony_ci NodeVector::iterator i = block->begin(); 261cb0ef41Sopenharmony_ci for (; i != block->end(); ++i) { 271cb0ef41Sopenharmony_ci const Operator* op = (*i)->op(); 281cb0ef41Sopenharmony_ci if (OperatorProperties::IsBasicBlockBegin(op)) continue; 291cb0ef41Sopenharmony_ci switch (op->opcode()) { 301cb0ef41Sopenharmony_ci case IrOpcode::kParameter: 311cb0ef41Sopenharmony_ci case IrOpcode::kPhi: 321cb0ef41Sopenharmony_ci case IrOpcode::kEffectPhi: 331cb0ef41Sopenharmony_ci continue; 341cb0ef41Sopenharmony_ci } 351cb0ef41Sopenharmony_ci break; 361cb0ef41Sopenharmony_ci } 371cb0ef41Sopenharmony_ci return i; 381cb0ef41Sopenharmony_ci} 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_cistatic const Operator* IntPtrConstant(CommonOperatorBuilder* common, 411cb0ef41Sopenharmony_ci intptr_t value) { 421cb0ef41Sopenharmony_ci return kSystemPointerSize == 8 431cb0ef41Sopenharmony_ci ? common->Int64Constant(value) 441cb0ef41Sopenharmony_ci : common->Int32Constant(static_cast<int32_t>(value)); 451cb0ef41Sopenharmony_ci} 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci// TODO(dcarney): need to mark code as non-serializable. 481cb0ef41Sopenharmony_cistatic const Operator* PointerConstant(CommonOperatorBuilder* common, 491cb0ef41Sopenharmony_ci const void* ptr) { 501cb0ef41Sopenharmony_ci intptr_t ptr_as_int = reinterpret_cast<intptr_t>(ptr); 511cb0ef41Sopenharmony_ci return IntPtrConstant(common, ptr_as_int); 521cb0ef41Sopenharmony_ci} 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ciBasicBlockProfilerData* BasicBlockInstrumentor::Instrument( 551cb0ef41Sopenharmony_ci OptimizedCompilationInfo* info, Graph* graph, Schedule* schedule, 561cb0ef41Sopenharmony_ci Isolate* isolate) { 571cb0ef41Sopenharmony_ci // Basic block profiling disables concurrent compilation, so handle deref is 581cb0ef41Sopenharmony_ci // fine. 591cb0ef41Sopenharmony_ci AllowHandleDereference allow_handle_dereference; 601cb0ef41Sopenharmony_ci // Skip the exit block in profiles, since the register allocator can't handle 611cb0ef41Sopenharmony_ci // it and entry into it means falling off the end of the function anyway. 621cb0ef41Sopenharmony_ci size_t n_blocks = schedule->RpoBlockCount() - 1; 631cb0ef41Sopenharmony_ci BasicBlockProfilerData* data = BasicBlockProfiler::Get()->NewData(n_blocks); 641cb0ef41Sopenharmony_ci // Set the function name. 651cb0ef41Sopenharmony_ci data->SetFunctionName(info->GetDebugName()); 661cb0ef41Sopenharmony_ci // Capture the schedule string before instrumentation. 671cb0ef41Sopenharmony_ci if (FLAG_turbo_profiling_verbose) { 681cb0ef41Sopenharmony_ci std::ostringstream os; 691cb0ef41Sopenharmony_ci os << *schedule; 701cb0ef41Sopenharmony_ci data->SetSchedule(os); 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci // Check whether we should write counts to a JS heap object or to the 731cb0ef41Sopenharmony_ci // BasicBlockProfilerData directly. The JS heap object is only used for 741cb0ef41Sopenharmony_ci // builtins. 751cb0ef41Sopenharmony_ci bool on_heap_counters = isolate && isolate->IsGeneratingEmbeddedBuiltins(); 761cb0ef41Sopenharmony_ci // Add the increment instructions to the start of every block. 771cb0ef41Sopenharmony_ci CommonOperatorBuilder common(graph->zone()); 781cb0ef41Sopenharmony_ci MachineOperatorBuilder machine(graph->zone()); 791cb0ef41Sopenharmony_ci Node* counters_array = nullptr; 801cb0ef41Sopenharmony_ci if (on_heap_counters) { 811cb0ef41Sopenharmony_ci // Allocation is disallowed here, so rather than referring to an actual 821cb0ef41Sopenharmony_ci // counters array, create a reference to a special marker object. This 831cb0ef41Sopenharmony_ci // object will get fixed up later in the constants table (see 841cb0ef41Sopenharmony_ci // PatchBasicBlockCountersReference). An important and subtle point: we 851cb0ef41Sopenharmony_ci // cannot use the root handle basic_block_counters_marker_handle() and must 861cb0ef41Sopenharmony_ci // create a new separate handle. Otherwise 871cb0ef41Sopenharmony_ci // TurboAssemblerBase::IndirectLoadConstant would helpfully emit a 881cb0ef41Sopenharmony_ci // root-relative load rather than putting this value in the constants table 891cb0ef41Sopenharmony_ci // where we expect it to be for patching. 901cb0ef41Sopenharmony_ci counters_array = graph->NewNode(common.HeapConstant(Handle<HeapObject>::New( 911cb0ef41Sopenharmony_ci ReadOnlyRoots(isolate).basic_block_counters_marker(), isolate))); 921cb0ef41Sopenharmony_ci } else { 931cb0ef41Sopenharmony_ci counters_array = graph->NewNode(PointerConstant(&common, data->counts())); 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci Node* zero = graph->NewNode(common.Int32Constant(0)); 961cb0ef41Sopenharmony_ci Node* one = graph->NewNode(common.Int32Constant(1)); 971cb0ef41Sopenharmony_ci BasicBlockVector* blocks = schedule->rpo_order(); 981cb0ef41Sopenharmony_ci size_t block_number = 0; 991cb0ef41Sopenharmony_ci for (BasicBlockVector::iterator it = blocks->begin(); block_number < n_blocks; 1001cb0ef41Sopenharmony_ci ++it, ++block_number) { 1011cb0ef41Sopenharmony_ci BasicBlock* block = (*it); 1021cb0ef41Sopenharmony_ci // Iteration is already in reverse post-order. 1031cb0ef41Sopenharmony_ci DCHECK_EQ(block->rpo_number(), block_number); 1041cb0ef41Sopenharmony_ci data->SetBlockId(block_number, block->id().ToInt()); 1051cb0ef41Sopenharmony_ci // It is unnecessary to wire effect and control deps for load and store 1061cb0ef41Sopenharmony_ci // since this happens after scheduling. 1071cb0ef41Sopenharmony_ci // Construct increment operation. 1081cb0ef41Sopenharmony_ci int offset_to_counter_value = static_cast<int>(block_number) * kInt32Size; 1091cb0ef41Sopenharmony_ci if (on_heap_counters) { 1101cb0ef41Sopenharmony_ci offset_to_counter_value += ByteArray::kHeaderSize - kHeapObjectTag; 1111cb0ef41Sopenharmony_ci } 1121cb0ef41Sopenharmony_ci Node* offset_to_counter = 1131cb0ef41Sopenharmony_ci graph->NewNode(IntPtrConstant(&common, offset_to_counter_value)); 1141cb0ef41Sopenharmony_ci Node* load = 1151cb0ef41Sopenharmony_ci graph->NewNode(machine.Load(MachineType::Uint32()), counters_array, 1161cb0ef41Sopenharmony_ci offset_to_counter, graph->start(), graph->start()); 1171cb0ef41Sopenharmony_ci Node* inc = graph->NewNode(machine.Int32Add(), load, one); 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci // Branchless saturation, because we've already run the scheduler, so 1201cb0ef41Sopenharmony_ci // introducing extra control flow here would be surprising. 1211cb0ef41Sopenharmony_ci Node* overflow = graph->NewNode(machine.Uint32LessThan(), inc, load); 1221cb0ef41Sopenharmony_ci Node* overflow_mask = graph->NewNode(machine.Int32Sub(), zero, overflow); 1231cb0ef41Sopenharmony_ci Node* saturated_inc = 1241cb0ef41Sopenharmony_ci graph->NewNode(machine.Word32Or(), inc, overflow_mask); 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci Node* store = 1271cb0ef41Sopenharmony_ci graph->NewNode(machine.Store(StoreRepresentation( 1281cb0ef41Sopenharmony_ci MachineRepresentation::kWord32, kNoWriteBarrier)), 1291cb0ef41Sopenharmony_ci counters_array, offset_to_counter, saturated_inc, 1301cb0ef41Sopenharmony_ci graph->start(), graph->start()); 1311cb0ef41Sopenharmony_ci // Insert the new nodes. 1321cb0ef41Sopenharmony_ci static const int kArraySize = 10; 1331cb0ef41Sopenharmony_ci Node* to_insert[kArraySize] = { 1341cb0ef41Sopenharmony_ci counters_array, zero, one, offset_to_counter, 1351cb0ef41Sopenharmony_ci load, inc, overflow, overflow_mask, 1361cb0ef41Sopenharmony_ci saturated_inc, store}; 1371cb0ef41Sopenharmony_ci // The first three Nodes are constant across all blocks. 1381cb0ef41Sopenharmony_ci int insertion_start = block_number == 0 ? 0 : 3; 1391cb0ef41Sopenharmony_ci NodeVector::iterator insertion_point = FindInsertionPoint(block); 1401cb0ef41Sopenharmony_ci block->InsertNodes(insertion_point, &to_insert[insertion_start], 1411cb0ef41Sopenharmony_ci &to_insert[kArraySize]); 1421cb0ef41Sopenharmony_ci // Tell the scheduler about the new nodes. 1431cb0ef41Sopenharmony_ci for (int i = insertion_start; i < kArraySize; ++i) { 1441cb0ef41Sopenharmony_ci schedule->SetBlockForNode(block, to_insert[i]); 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci } 1471cb0ef41Sopenharmony_ci return data; 1481cb0ef41Sopenharmony_ci} 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci} // namespace compiler 1511cb0ef41Sopenharmony_ci} // namespace internal 1521cb0ef41Sopenharmony_ci} // namespace v8 153