Line data Source code
1 : // Copyright 2018 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/torque/instructions.h"
6 : #include "src/torque/cfg.h"
7 : #include "src/torque/type-oracle.h"
8 :
9 : namespace v8 {
10 : namespace internal {
11 : namespace torque {
12 :
13 : #define TORQUE_INSTRUCTION_BOILERPLATE_DEFINITIONS(Name) \
14 : const InstructionKind Name::kKind = InstructionKind::k##Name; \
15 : std::unique_ptr<InstructionBase> Name::Clone() const { \
16 : return std::unique_ptr<InstructionBase>(new Name(*this)); \
17 : } \
18 : void Name::Assign(const InstructionBase& other) { \
19 : *this = static_cast<const Name&>(other); \
20 : }
21 242706 : TORQUE_INSTRUCTION_LIST(TORQUE_INSTRUCTION_BOILERPLATE_DEFINITIONS)
22 : #undef TORQUE_INSTRUCTION_BOILERPLATE_DEFINITIONS
23 :
24 17632 : void PeekInstruction::TypeInstruction(Stack<const Type*>* stack,
25 : ControlFlowGraph* cfg) const {
26 17632 : const Type* type = stack->Peek(slot);
27 17632 : if (widened_type) {
28 17632 : if (type->IsTopType()) {
29 : const TopType* top_type = TopType::cast(type);
30 0 : ReportError("use of " + top_type->reason());
31 : }
32 17632 : if (!type->IsSubtypeOf(*widened_type)) {
33 0 : ReportError("type ", *type, " is not a subtype of ", **widened_type);
34 : }
35 17632 : type = *widened_type;
36 : }
37 : stack->Push(type);
38 17632 : }
39 :
40 606 : void PokeInstruction::TypeInstruction(Stack<const Type*>* stack,
41 : ControlFlowGraph* cfg) const {
42 606 : const Type* type = stack->Top();
43 606 : if (widened_type) {
44 606 : if (!type->IsSubtypeOf(*widened_type)) {
45 0 : ReportError("type ", type, " is not a subtype of ", *widened_type);
46 : }
47 606 : type = *widened_type;
48 : }
49 606 : stack->Poke(slot, type);
50 : stack->Pop();
51 606 : }
52 :
53 8971 : void DeleteRangeInstruction::TypeInstruction(Stack<const Type*>* stack,
54 : ControlFlowGraph* cfg) const {
55 8971 : stack->DeleteRange(range);
56 8971 : }
57 :
58 89 : void PushUninitializedInstruction::TypeInstruction(
59 : Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
60 89 : stack->Push(type);
61 89 : }
62 :
63 74 : void PushBuiltinPointerInstruction::TypeInstruction(
64 : Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
65 74 : stack->Push(type);
66 74 : }
67 :
68 355 : void NamespaceConstantInstruction::TypeInstruction(
69 : Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
70 710 : stack->PushMany(LowerType(constant->type()));
71 355 : }
72 :
73 282 : void InstructionBase::InvalidateTransientTypes(
74 : Stack<const Type*>* stack) const {
75 : auto current = stack->begin();
76 7710 : while (current != stack->end()) {
77 3714 : if ((*current)->IsTransient()) {
78 220 : std::stringstream stream;
79 220 : stream << "type " << **current
80 : << " is made invalid by transitioning callable invocation at "
81 220 : << PositionAsString(pos);
82 330 : *current = TypeOracle::GetTopType(stream.str(), *current);
83 : }
84 3714 : ++current;
85 : }
86 282 : }
87 :
88 109 : void CallIntrinsicInstruction::TypeInstruction(Stack<const Type*>* stack,
89 : ControlFlowGraph* cfg) const {
90 : std::vector<const Type*> parameter_types =
91 109 : LowerParameterTypes(intrinsic->signature().parameter_types);
92 201 : for (intptr_t i = parameter_types.size() - 1; i >= 0; --i) {
93 : const Type* arg_type = stack->Pop();
94 92 : const Type* parameter_type = parameter_types.back();
95 : parameter_types.pop_back();
96 92 : if (arg_type != parameter_type) {
97 : ReportError("parameter ", i, ": expected type ", *parameter_type,
98 0 : " but found type ", *arg_type);
99 : }
100 : }
101 109 : if (intrinsic->IsTransitioning()) {
102 0 : InvalidateTransientTypes(stack);
103 : }
104 218 : stack->PushMany(LowerType(intrinsic->signature().return_type));
105 109 : }
106 :
107 4770 : void CallCsaMacroInstruction::TypeInstruction(Stack<const Type*>* stack,
108 : ControlFlowGraph* cfg) const {
109 : std::vector<const Type*> parameter_types =
110 4770 : LowerParameterTypes(macro->signature().parameter_types);
111 10944 : for (intptr_t i = parameter_types.size() - 1; i >= 0; --i) {
112 : const Type* arg_type = stack->Pop();
113 6174 : const Type* parameter_type = parameter_types.back();
114 : parameter_types.pop_back();
115 6174 : if (arg_type != parameter_type) {
116 : ReportError("parameter ", i, ": expected type ", *parameter_type,
117 0 : " but found type ", *arg_type);
118 : }
119 : }
120 :
121 4770 : if (macro->IsTransitioning()) {
122 138 : InvalidateTransientTypes(stack);
123 : }
124 :
125 4770 : if (catch_block) {
126 : Stack<const Type*> catch_stack = *stack;
127 8 : catch_stack.Push(TypeOracle::GetObjectType());
128 8 : (*catch_block)->SetInputTypes(catch_stack);
129 : }
130 :
131 9540 : stack->PushMany(LowerType(macro->signature().return_type));
132 4770 : }
133 :
134 603 : void CallCsaMacroAndBranchInstruction::TypeInstruction(
135 : Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
136 : std::vector<const Type*> parameter_types =
137 603 : LowerParameterTypes(macro->signature().parameter_types);
138 1687 : for (intptr_t i = parameter_types.size() - 1; i >= 0; --i) {
139 : const Type* arg_type = stack->Pop();
140 1084 : const Type* parameter_type = parameter_types.back();
141 : parameter_types.pop_back();
142 1084 : if (arg_type != parameter_type) {
143 : ReportError("parameter ", i, ": expected type ", *parameter_type,
144 0 : " but found type ", *arg_type);
145 : }
146 : }
147 :
148 1206 : if (label_blocks.size() != macro->signature().labels.size()) {
149 0 : ReportError("wrong number of labels");
150 : }
151 1785 : for (size_t i = 0; i < label_blocks.size(); ++i) {
152 : Stack<const Type*> continuation_stack = *stack;
153 : continuation_stack.PushMany(
154 1773 : LowerParameterTypes(macro->signature().labels[i].types));
155 591 : label_blocks[i]->SetInputTypes(std::move(continuation_stack));
156 : }
157 :
158 603 : if (macro->IsTransitioning()) {
159 14 : InvalidateTransientTypes(stack);
160 : }
161 :
162 603 : if (catch_block) {
163 : Stack<const Type*> catch_stack = *stack;
164 4 : catch_stack.Push(TypeOracle::GetObjectType());
165 4 : (*catch_block)->SetInputTypes(catch_stack);
166 : }
167 :
168 603 : if (macro->signature().return_type != TypeOracle::GetNeverType()) {
169 : Stack<const Type*> return_stack = *stack;
170 850 : return_stack.PushMany(LowerType(macro->signature().return_type));
171 425 : if (return_continuation == base::nullopt) {
172 0 : ReportError("missing return continuation.");
173 : }
174 425 : (*return_continuation)->SetInputTypes(return_stack);
175 : } else {
176 178 : if (return_continuation != base::nullopt) {
177 0 : ReportError("unreachable return continuation.");
178 : }
179 : }
180 603 : }
181 :
182 139 : void CallBuiltinInstruction::TypeInstruction(Stack<const Type*>* stack,
183 : ControlFlowGraph* cfg) const {
184 139 : std::vector<const Type*> argument_types = stack->PopMany(argc);
185 139 : if (argument_types !=
186 278 : LowerParameterTypes(builtin->signature().parameter_types)) {
187 0 : ReportError("wrong argument types");
188 : }
189 139 : if (builtin->IsTransitioning()) {
190 97 : InvalidateTransientTypes(stack);
191 : }
192 :
193 139 : if (catch_block) {
194 : Stack<const Type*> catch_stack = *stack;
195 1 : catch_stack.Push(TypeOracle::GetObjectType());
196 1 : (*catch_block)->SetInputTypes(catch_stack);
197 : }
198 :
199 278 : stack->PushMany(LowerType(builtin->signature().return_type));
200 139 : }
201 :
202 31 : void CallBuiltinPointerInstruction::TypeInstruction(
203 : Stack<const Type*>* stack, ControlFlowGraph* cfg) const {
204 31 : std::vector<const Type*> argument_types = stack->PopMany(argc);
205 : const BuiltinPointerType* f = BuiltinPointerType::DynamicCast(stack->Pop());
206 31 : if (!f) ReportError("expected function pointer type");
207 62 : if (argument_types != LowerParameterTypes(f->parameter_types())) {
208 0 : ReportError("wrong argument types");
209 : }
210 : // TODO(tebbi): Only invalidate transient types if the function pointer type
211 : // is transitioning.
212 31 : InvalidateTransientTypes(stack);
213 62 : stack->PushMany(LowerType(f->return_type()));
214 31 : }
215 :
216 23 : void CallRuntimeInstruction::TypeInstruction(Stack<const Type*>* stack,
217 : ControlFlowGraph* cfg) const {
218 23 : std::vector<const Type*> argument_types = stack->PopMany(argc);
219 23 : if (argument_types !=
220 46 : LowerParameterTypes(runtime_function->signature().parameter_types,
221 23 : argc)) {
222 0 : ReportError("wrong argument types");
223 : }
224 23 : if (runtime_function->IsTransitioning()) {
225 2 : InvalidateTransientTypes(stack);
226 : }
227 :
228 23 : if (catch_block) {
229 : Stack<const Type*> catch_stack = *stack;
230 0 : catch_stack.Push(TypeOracle::GetObjectType());
231 0 : (*catch_block)->SetInputTypes(catch_stack);
232 : }
233 :
234 23 : const Type* return_type = runtime_function->signature().return_type;
235 23 : if (return_type != TypeOracle::GetNeverType()) {
236 24 : stack->PushMany(LowerType(return_type));
237 : }
238 23 : }
239 :
240 879 : void BranchInstruction::TypeInstruction(Stack<const Type*>* stack,
241 : ControlFlowGraph* cfg) const {
242 : const Type* condition_type = stack->Pop();
243 879 : if (condition_type != TypeOracle::GetBoolType()) {
244 0 : ReportError("condition has to have type bool");
245 : }
246 879 : if_true->SetInputTypes(*stack);
247 879 : if_false->SetInputTypes(*stack);
248 879 : }
249 :
250 53 : void ConstexprBranchInstruction::TypeInstruction(Stack<const Type*>* stack,
251 : ControlFlowGraph* cfg) const {
252 53 : if_true->SetInputTypes(*stack);
253 53 : if_false->SetInputTypes(*stack);
254 53 : }
255 :
256 4309 : void GotoInstruction::TypeInstruction(Stack<const Type*>* stack,
257 : ControlFlowGraph* cfg) const {
258 4309 : destination->SetInputTypes(*stack);
259 4309 : }
260 :
261 133 : void GotoExternalInstruction::TypeInstruction(Stack<const Type*>* stack,
262 : ControlFlowGraph* cfg) const {
263 133 : if (variable_names.size() != stack->Size()) {
264 0 : ReportError("goto external label with wrong parameter count.");
265 : }
266 133 : }
267 :
268 234 : void ReturnInstruction::TypeInstruction(Stack<const Type*>* stack,
269 : ControlFlowGraph* cfg) const {
270 234 : cfg->SetReturnType(stack->Pop());
271 234 : }
272 :
273 0 : void PrintConstantStringInstruction::TypeInstruction(
274 0 : Stack<const Type*>* stack, ControlFlowGraph* cfg) const {}
275 :
276 234 : void AbortInstruction::TypeInstruction(Stack<const Type*>* stack,
277 234 : ControlFlowGraph* cfg) const {}
278 :
279 40 : void UnsafeCastInstruction::TypeInstruction(Stack<const Type*>* stack,
280 : ControlFlowGraph* cfg) const {
281 80 : stack->Poke(stack->AboveTop() - 1, destination_type);
282 40 : }
283 :
284 246 : void LoadObjectFieldInstruction::TypeInstruction(Stack<const Type*>* stack,
285 : ControlFlowGraph* cfg) const {
286 246 : const ClassType* stack_class_type = ClassType::DynamicCast(stack->Top());
287 246 : if (!stack_class_type) {
288 : ReportError(
289 : "first argument to a LoadObjectFieldInstruction instruction isn't a "
290 0 : "class");
291 : }
292 246 : if (stack_class_type != class_type) {
293 : ReportError(
294 : "first argument to a LoadObjectFieldInstruction doesn't match "
295 0 : "instruction's type");
296 : }
297 246 : const Field& field = class_type->LookupField(field_name);
298 492 : stack->Poke(stack->AboveTop() - 1, field.name_and_type.type);
299 246 : }
300 :
301 280 : void StoreObjectFieldInstruction::TypeInstruction(Stack<const Type*>* stack,
302 : ControlFlowGraph* cfg) const {
303 : auto value = stack->Pop();
304 280 : const ClassType* stack_class_type = ClassType::DynamicCast(stack->Top());
305 280 : if (!stack_class_type) {
306 : ReportError(
307 : "first argument to a StoreObjectFieldInstruction instruction isn't a "
308 0 : "class");
309 : }
310 280 : if (stack_class_type != class_type) {
311 : ReportError(
312 : "first argument to a StoreObjectFieldInstruction doesn't match "
313 0 : "instruction's type");
314 : }
315 : stack->Pop();
316 : stack->Push(value);
317 280 : }
318 :
319 41 : bool CallRuntimeInstruction::IsBlockTerminator() const {
320 82 : return is_tailcall || runtime_function->signature().return_type ==
321 82 : TypeOracle::GetNeverType();
322 : }
323 :
324 : } // namespace torque
325 : } // namespace internal
326 6150 : } // namespace v8
|