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
34 Handle<ObjectHashTable> table =
35 isolate->heap()->pending_optimize_for_test_bytecode().IsUndefined()
36 ? ObjectHashTable::New(isolate, 1)
37 : handle(ObjectHashTable::cast(
38 isolate->heap()->pending_optimize_for_test_bytecode()),
39 isolate);
40 Handle<Tuple2> tuple = isolate->factory()->NewTuple2(
41 handle(function->shared().GetBytecodeArray(), isolate),
42 handle(Smi::FromInt(status), isolate), AllocationType::kYoung);
43 table =
44 ObjectHashTable::Put(table, handle(function->shared(), isolate), tuple);
45 isolate->heap()->SetPendingOptimizeForTestBytecode(*table);
46 }
47
IsHeuristicOptimizationAllowed(Isolate * isolate,JSFunction function)48 bool PendingOptimizationTable::IsHeuristicOptimizationAllowed(
49 Isolate* isolate, JSFunction function) {
50 DCHECK(FLAG_testing_d8_test_runner);
51
52 Handle<Object> table =
53 handle(isolate->heap()->pending_optimize_for_test_bytecode(), isolate);
54 Handle<Object> entry =
55 table->IsUndefined()
56 ? handle(ReadOnlyRoots(isolate).the_hole_value(), isolate)
57 : handle(Handle<ObjectHashTable>::cast(table)->Lookup(
58 handle(function.shared(), isolate)),
59 isolate);
60 if (entry->IsTheHole()) {
61 return true;
62 }
63 DCHECK(entry->IsTuple2());
64 DCHECK(Handle<Tuple2>::cast(entry)->value2().IsSmi());
65 FunctionStatusFlags status(Smi::ToInt(Handle<Tuple2>::cast(entry)->value2()));
66 return status & FunctionStatus::kAllowHeuristicOptimization;
67 }
68
MarkedForOptimization(Isolate * isolate,Handle<JSFunction> function)69 void PendingOptimizationTable::MarkedForOptimization(
70 Isolate* isolate, Handle<JSFunction> function) {
71 DCHECK(FLAG_testing_d8_test_runner);
72
73 Handle<Object> table =
74 handle(isolate->heap()->pending_optimize_for_test_bytecode(), isolate);
75 Handle<Object> entry =
76 table->IsUndefined()
77 ? handle(ReadOnlyRoots(isolate).the_hole_value(), isolate)
78 : handle(Handle<ObjectHashTable>::cast(table)->Lookup(
79 handle(function->shared(), isolate)),
80 isolate);
81 if (entry->IsTheHole()) {
82 PrintF("Error: Function ");
83 function->ShortPrint();
84 PrintF(
85 " should be prepared for optimization with "
86 "%%PrepareFunctionForOptimization before "
87 "%%OptimizeFunctionOnNextCall / %%OptimizeOSR ");
88 UNREACHABLE();
89 }
90
91 DCHECK(entry->IsTuple2());
92 DCHECK(Handle<Tuple2>::cast(entry)->value2().IsSmi());
93 FunctionStatusFlags status(Smi::ToInt(Handle<Tuple2>::cast(entry)->value2()));
94 status = status.without(FunctionStatus::kPrepareForOptimize) |
95 FunctionStatus::kMarkForOptimize;
96 Handle<Tuple2>::cast(entry)->set_value2(Smi::FromInt(status));
97 table = ObjectHashTable::Put(Handle<ObjectHashTable>::cast(table),
98 handle(function->shared(), isolate), entry);
99 isolate->heap()->SetPendingOptimizeForTestBytecode(*table);
100 }
101
FunctionWasOptimized(Isolate * isolate,Handle<JSFunction> function)102 void PendingOptimizationTable::FunctionWasOptimized(
103 Isolate* isolate, Handle<JSFunction> function) {
104 DCHECK(FLAG_testing_d8_test_runner);
105
106 if (isolate->heap()->pending_optimize_for_test_bytecode().IsUndefined()) {
107 return;
108 }
109
110 Handle<ObjectHashTable> table =
111 handle(ObjectHashTable::cast(
112 isolate->heap()->pending_optimize_for_test_bytecode()),
113 isolate);
114 Handle<Object> value(table->Lookup(handle(function->shared(), isolate)),
115 isolate);
116 // Remove only if we have already seen %OptimizeFunctionOnNextCall. If it is
117 // optimized for other reasons, still keep holding the bytecode since we may
118 // optimize it later.
119 if (!value->IsTheHole() &&
120 Smi::cast(Handle<Tuple2>::cast(value)->value2()).value() ==
121 static_cast<int>(FunctionStatus::kMarkForOptimize)) {
122 bool was_present;
123 table = table->Remove(isolate, table, handle(function->shared(), isolate),
124 &was_present);
125 DCHECK(was_present);
126 isolate->heap()->SetPendingOptimizeForTestBytecode(*table);
127 }
128 }
129
130 } // namespace internal
131 } // namespace v8
132