1// Copyright 2019 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/codegen/pending-optimization-table.h" 6 7#include "src/base/flags.h" 8#include "src/execution/isolate-inl.h" 9#include "src/heap/heap-inl.h" 10#include "src/objects/hash-table.h" 11#include "src/objects/js-objects.h" 12 13namespace v8 { 14namespace internal { 15 16enum class FunctionStatus : int { 17 kPrepareForOptimize = 1 << 0, 18 kMarkForOptimize = 1 << 1, 19 kAllowHeuristicOptimization = 1 << 2, 20}; 21 22using FunctionStatusFlags = base::Flags<FunctionStatus>; 23 24void PendingOptimizationTable::PreparedForOptimization( 25 Isolate* isolate, Handle<JSFunction> function, 26 bool allow_heuristic_optimization) { 27 DCHECK(FLAG_testing_d8_test_runner); 28 29 FunctionStatusFlags status = FunctionStatus::kPrepareForOptimize; 30 if (allow_heuristic_optimization) { 31 status |= FunctionStatus::kAllowHeuristicOptimization; 32 } 33 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate); 34 35 IsCompiledScope is_compiled_scope; 36 SharedFunctionInfo::EnsureBytecodeArrayAvailable(isolate, shared_info, 37 &is_compiled_scope); 38 39 Handle<ObjectHashTable> table = 40 isolate->heap()->pending_optimize_for_test_bytecode().IsUndefined() 41 ? ObjectHashTable::New(isolate, 1) 42 : handle(ObjectHashTable::cast( 43 isolate->heap()->pending_optimize_for_test_bytecode()), 44 isolate); 45 Handle<Tuple2> tuple = isolate->factory()->NewTuple2( 46 handle(shared_info->GetBytecodeArray(isolate), isolate), 47 handle(Smi::FromInt(status), isolate), AllocationType::kYoung); 48 table = 49 ObjectHashTable::Put(table, handle(function->shared(), isolate), tuple); 50 isolate->heap()->SetPendingOptimizeForTestBytecode(*table); 51} 52 53bool PendingOptimizationTable::IsHeuristicOptimizationAllowed( 54 Isolate* isolate, JSFunction function) { 55 DCHECK(FLAG_testing_d8_test_runner); 56 57 Handle<Object> table = 58 handle(isolate->heap()->pending_optimize_for_test_bytecode(), isolate); 59 Handle<Object> entry = 60 table->IsUndefined() 61 ? handle(ReadOnlyRoots(isolate).the_hole_value(), isolate) 62 : handle(Handle<ObjectHashTable>::cast(table)->Lookup( 63 handle(function.shared(), isolate)), 64 isolate); 65 if (entry->IsTheHole()) { 66 return true; 67 } 68 DCHECK(entry->IsTuple2()); 69 DCHECK(Handle<Tuple2>::cast(entry)->value2().IsSmi()); 70 FunctionStatusFlags status(Smi::ToInt(Handle<Tuple2>::cast(entry)->value2())); 71 return status & FunctionStatus::kAllowHeuristicOptimization; 72} 73 74void PendingOptimizationTable::MarkedForOptimization( 75 Isolate* isolate, Handle<JSFunction> function) { 76 DCHECK(FLAG_testing_d8_test_runner); 77 78 Handle<Object> table = 79 handle(isolate->heap()->pending_optimize_for_test_bytecode(), isolate); 80 Handle<Object> entry = 81 table->IsUndefined() 82 ? handle(ReadOnlyRoots(isolate).the_hole_value(), isolate) 83 : handle(Handle<ObjectHashTable>::cast(table)->Lookup( 84 handle(function->shared(), isolate)), 85 isolate); 86 if (entry->IsTheHole()) { 87 PrintF("Error: Function "); 88 function->ShortPrint(); 89 PrintF( 90 " should be prepared for optimization with " 91 "%%PrepareFunctionForOptimization before " 92 "%%OptimizeFunctionOnNextCall / %%OptimizeOSR "); 93 UNREACHABLE(); 94 } 95 96 DCHECK(entry->IsTuple2()); 97 DCHECK(Handle<Tuple2>::cast(entry)->value2().IsSmi()); 98 FunctionStatusFlags status(Smi::ToInt(Handle<Tuple2>::cast(entry)->value2())); 99 status = status.without(FunctionStatus::kPrepareForOptimize) | 100 FunctionStatus::kMarkForOptimize; 101 Handle<Tuple2>::cast(entry)->set_value2(Smi::FromInt(status)); 102 table = ObjectHashTable::Put(Handle<ObjectHashTable>::cast(table), 103 handle(function->shared(), isolate), entry); 104 isolate->heap()->SetPendingOptimizeForTestBytecode(*table); 105} 106 107void PendingOptimizationTable::FunctionWasOptimized( 108 Isolate* isolate, Handle<JSFunction> function) { 109 DCHECK(FLAG_testing_d8_test_runner); 110 111 if (isolate->heap()->pending_optimize_for_test_bytecode().IsUndefined()) { 112 return; 113 } 114 115 Handle<ObjectHashTable> table = 116 handle(ObjectHashTable::cast( 117 isolate->heap()->pending_optimize_for_test_bytecode()), 118 isolate); 119 Handle<Object> value(table->Lookup(handle(function->shared(), isolate)), 120 isolate); 121 // Remove only if we have already seen %OptimizeFunctionOnNextCall. If it is 122 // optimized for other reasons, still keep holding the bytecode since we may 123 // optimize it later. 124 if (!value->IsTheHole() && 125 Smi::cast(Handle<Tuple2>::cast(value)->value2()).value() == 126 static_cast<int>(FunctionStatus::kMarkForOptimize)) { 127 bool was_present; 128 table = table->Remove(isolate, table, handle(function->shared(), isolate), 129 &was_present); 130 DCHECK(was_present); 131 isolate->heap()->SetPendingOptimizeForTestBytecode(*table); 132 } 133} 134 135} // namespace internal 136} // namespace v8 137