• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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