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
13 namespace v8 {
14 namespace internal {
15
16 enum class FunctionStatus : int {
17 kPrepareForOptimize = 1 << 0,
18 kMarkForOptimize = 1 << 1,
19 kAllowHeuristicOptimization = 1 << 2,
20 };
21
22 using FunctionStatusFlags = base::Flags<FunctionStatus>;
23
PreparedForOptimization(Isolate * isolate,Handle<JSFunction> function,bool allow_heuristic_optimization)24 void 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
IsHeuristicOptimizationAllowed(Isolate * isolate,JSFunction function)53 bool 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
MarkedForOptimization(Isolate * isolate,Handle<JSFunction> function)74 void 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
FunctionWasOptimized(Isolate * isolate,Handle<JSFunction> function)107 void 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