1// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/compiler/frontend/bytecode_fingerprints.h"
6
7#include "vm/compiler/frontend/bytecode_reader.h"
8#include "vm/constants_kbc.h"
9#include "vm/hash.h"
10
11namespace dart {
12namespace kernel {
13
14static uint32_t CombineObject(uint32_t hash, const Object& obj) {
15 if (obj.IsAbstractType()) {
16 return CombineHashes(hash, AbstractType::Cast(obj).Hash());
17 } else if (obj.IsClass()) {
18 return CombineHashes(hash, Class::Cast(obj).id());
19 } else if (obj.IsFunction()) {
20 return CombineHashes(
21 hash, AbstractType::Handle(Function::Cast(obj).result_type()).Hash());
22 } else if (obj.IsField()) {
23 return CombineHashes(hash,
24 AbstractType::Handle(Field::Cast(obj).type()).Hash());
25 } else {
26 return CombineHashes(hash, static_cast<uint32_t>(obj.GetClassId()));
27 }
28}
29
30typedef uint32_t (*Fp)(uint32_t fp,
31 const KBCInstr* instr,
32 const ObjectPool& pool,
33 int32_t value);
34
35static uint32_t Fp___(uint32_t fp,
36 const KBCInstr* instr,
37 const ObjectPool& pool,
38 int32_t value) {
39 return fp;
40}
41
42static uint32_t Fptgt(uint32_t fp,
43 const KBCInstr* instr,
44 const ObjectPool& pool,
45 int32_t value) {
46 return CombineHashes(fp, value);
47}
48
49static uint32_t Fplit(uint32_t fp,
50 const KBCInstr* instr,
51 const ObjectPool& pool,
52 int32_t value) {
53 return CombineObject(fp, Object::Handle(pool.ObjectAt(value)));
54}
55
56static uint32_t Fpreg(uint32_t fp,
57 const KBCInstr* instr,
58 const ObjectPool& pool,
59 int32_t value) {
60 return CombineHashes(fp, value);
61}
62
63static uint32_t Fpxeg(uint32_t fp,
64 const KBCInstr* instr,
65 const ObjectPool& pool,
66 int32_t value) {
67 return CombineHashes(fp, value);
68}
69
70static uint32_t Fpnum(uint32_t fp,
71 const KBCInstr* instr,
72 const ObjectPool& pool,
73 int32_t value) {
74 return CombineHashes(fp, value);
75}
76
77static uint32_t Fingerprint0(uint32_t fp,
78 const KBCInstr* instr,
79 const ObjectPool& pool,
80 Fp op1,
81 Fp op2,
82 Fp op3) {
83 return fp;
84}
85
86static uint32_t FingerprintA(uint32_t fp,
87 const KBCInstr* instr,
88 const ObjectPool& pool,
89 Fp op1,
90 Fp op2,
91 Fp op3) {
92 fp = op1(fp, instr, pool, KernelBytecode::DecodeA(instr));
93 return fp;
94}
95
96static uint32_t FingerprintD(uint32_t fp,
97 const KBCInstr* instr,
98 const ObjectPool& pool,
99 Fp op1,
100 Fp op2,
101 Fp op3) {
102 fp = op1(fp, instr, pool, KernelBytecode::DecodeD(instr));
103 return fp;
104}
105
106static uint32_t FingerprintX(uint32_t fp,
107 const KBCInstr* instr,
108 const ObjectPool& pool,
109 Fp op1,
110 Fp op2,
111 Fp op3) {
112 fp = op1(fp, instr, pool, KernelBytecode::DecodeX(instr));
113 return fp;
114}
115
116static uint32_t FingerprintT(uint32_t fp,
117 const KBCInstr* instr,
118 const ObjectPool& pool,
119 Fp op1,
120 Fp op2,
121 Fp op3) {
122 fp = op1(fp, instr, pool, KernelBytecode::DecodeT(instr));
123 return fp;
124}
125
126static uint32_t FingerprintA_E(uint32_t fp,
127 const KBCInstr* instr,
128 const ObjectPool& pool,
129 Fp op1,
130 Fp op2,
131 Fp op3) {
132 fp = op1(fp, instr, pool, KernelBytecode::DecodeA(instr));
133 fp = op2(fp, instr, pool, KernelBytecode::DecodeE(instr));
134 return fp;
135}
136
137static uint32_t FingerprintA_Y(uint32_t fp,
138 const KBCInstr* instr,
139 const ObjectPool& pool,
140 Fp op1,
141 Fp op2,
142 Fp op3) {
143 fp = op1(fp, instr, pool, KernelBytecode::DecodeA(instr));
144 fp = op2(fp, instr, pool, KernelBytecode::DecodeY(instr));
145 return fp;
146}
147
148static uint32_t FingerprintD_F(uint32_t fp,
149 const KBCInstr* instr,
150 const ObjectPool& pool,
151 Fp op1,
152 Fp op2,
153 Fp op3) {
154 fp = op1(fp, instr, pool, KernelBytecode::DecodeD(instr));
155 fp = op2(fp, instr, pool, KernelBytecode::DecodeF(instr));
156 return fp;
157}
158
159static uint32_t FingerprintA_B_C(uint32_t fp,
160 const KBCInstr* instr,
161 const ObjectPool& pool,
162 Fp op1,
163 Fp op2,
164 Fp op3) {
165 fp = op1(fp, instr, pool, KernelBytecode::DecodeA(instr));
166 fp = op2(fp, instr, pool, KernelBytecode::DecodeB(instr));
167 fp = op3(fp, instr, pool, KernelBytecode::DecodeC(instr));
168 return fp;
169}
170
171uint32_t BytecodeFingerprintHelper::CalculateFunctionFingerprint(
172 const Function& function) {
173 ASSERT(function.is_declared_in_bytecode());
174 const intptr_t kHashBits = 30;
175 uint32_t fp = 0;
176 fp = CombineHashes(fp, String::Handle(function.UserVisibleName()).Hash());
177 if (function.is_abstract()) {
178 return FinalizeHash(fp, kHashBits);
179 }
180 if (!function.HasBytecode()) {
181 kernel::BytecodeReader::ReadFunctionBytecode(Thread::Current(), function);
182 }
183 const Bytecode& code = Bytecode::Handle(function.bytecode());
184 const ObjectPool& pool = ObjectPool::Handle(code.object_pool());
185 const KBCInstr* const start =
186 reinterpret_cast<const KBCInstr*>(code.instructions());
187 for (const KBCInstr* instr = start; (instr - start) < code.Size();
188 instr = KernelBytecode::Next(instr)) {
189 const KernelBytecode::Opcode opcode = KernelBytecode::DecodeOpcode(instr);
190 fp = CombineHashes(fp, opcode);
191 switch (opcode) {
192#define FINGERPRINT_BYTECODE(name, encoding, kind, op1, op2, op3) \
193 case KernelBytecode::k##name: \
194 fp = Fingerprint##encoding(fp, instr, pool, Fp##op1, Fp##op2, Fp##op3); \
195 break;
196 KERNEL_BYTECODES_LIST(FINGERPRINT_BYTECODE)
197#undef FINGERPRINT_BYTECODE
198 default:
199 UNREACHABLE();
200 }
201 }
202
203 return FinalizeHash(fp, kHashBits);
204}
205
206} // namespace kernel
207} // namespace dart
208