Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(48)

Side by Side Diff: src/compiler/js-call-reducer.cc

Issue 1466643002: [turbofan] Initial support for Array constructor specialization. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Addressed Michi's comments. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/js-call-reducer.h ('k') | src/compiler/js-generic-lowering.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/js-call-reducer.h" 5 #include "src/compiler/js-call-reducer.h"
6 6
7 #include "src/compiler/js-graph.h" 7 #include "src/compiler/js-graph.h"
8 #include "src/compiler/node-matchers.h" 8 #include "src/compiler/node-matchers.h"
9 #include "src/compiler/simplified-operator.h"
10 #include "src/objects-inl.h" 9 #include "src/objects-inl.h"
11 #include "src/type-feedback-vector-inl.h" 10 #include "src/type-feedback-vector-inl.h"
12 11
13 namespace v8 { 12 namespace v8 {
14 namespace internal { 13 namespace internal {
15 namespace compiler { 14 namespace compiler {
16 15
17 namespace { 16 namespace {
18 17
19 VectorSlotPair CallCountFeedback(VectorSlotPair p) { 18 VectorSlotPair CallCountFeedback(VectorSlotPair p) {
(...skipping 13 matching lines...) Expand all
33 CallICNexus nexus(vector, slot); 32 CallICNexus nexus(vector, slot);
34 nexus.ConfigureMegamorphic(call_count); 33 nexus.ConfigureMegamorphic(call_count);
35 return VectorSlotPair(vector, slot); 34 return VectorSlotPair(vector, slot);
36 } 35 }
37 36
38 } // namespace 37 } // namespace
39 38
40 39
41 Reduction JSCallReducer::Reduce(Node* node) { 40 Reduction JSCallReducer::Reduce(Node* node) {
42 switch (node->opcode()) { 41 switch (node->opcode()) {
42 case IrOpcode::kJSCallConstruct:
43 return ReduceJSCallConstruct(node);
43 case IrOpcode::kJSCallFunction: 44 case IrOpcode::kJSCallFunction:
44 return ReduceJSCallFunction(node); 45 return ReduceJSCallFunction(node);
45 default: 46 default:
46 break; 47 break;
47 } 48 }
48 return NoChange(); 49 return NoChange();
49 } 50 }
50 51
51 52
53 // ES6 section 22.1.1 The Array Constructor
54 Reduction JSCallReducer::ReduceArrayConstructor(Node* node) {
55 Node* target = NodeProperties::GetValueInput(node, 0);
56 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
57 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
58
59 // Check if we have an allocation site from the CallIC.
60 Handle<AllocationSite> site;
61 if (p.feedback().IsValid()) {
62 CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
63 Handle<Object> feedback(nexus.GetFeedback(), isolate());
64 if (feedback->IsAllocationSite()) {
65 site = Handle<AllocationSite>::cast(feedback);
66 }
67 }
68
69 // Turn the {node} into a {JSCreateArray} call.
70 DCHECK_LE(2u, p.arity());
71 size_t const arity = p.arity() - 2;
72 NodeProperties::ReplaceValueInput(node, target, 0);
73 NodeProperties::ReplaceValueInput(node, target, 1);
74 NodeProperties::RemoveFrameStateInput(node, 1);
75 // TODO(bmeurer): We might need to propagate the tail call mode to
76 // the JSCreateArray operator, because an Array call in tail call
77 // position must always properly consume the parent stack frame.
78 NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
79 return Changed(node);
80 }
81
82
52 // ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray ) 83 // ES6 section 19.2.3.1 Function.prototype.apply ( thisArg, argArray )
53 Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) { 84 Reduction JSCallReducer::ReduceFunctionPrototypeApply(Node* node) {
54 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); 85 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
55 Node* target = NodeProperties::GetValueInput(node, 0); 86 Node* target = NodeProperties::GetValueInput(node, 0);
56 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); 87 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
57 Handle<JSFunction> apply = 88 Handle<JSFunction> apply =
58 Handle<JSFunction>::cast(HeapObjectMatcher(target).Value()); 89 Handle<JSFunction>::cast(HeapObjectMatcher(target).Value());
59 size_t arity = p.arity(); 90 size_t arity = p.arity();
60 DCHECK_LE(2u, arity); 91 DCHECK_LE(2u, arity);
61 ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny; 92 ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny;
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 // Try to further reduce the JSCallFunction {node}. 194 // Try to further reduce the JSCallFunction {node}.
164 Reduction const reduction = ReduceJSCallFunction(node); 195 Reduction const reduction = ReduceJSCallFunction(node);
165 return reduction.Changed() ? reduction : Changed(node); 196 return reduction.Changed() ? reduction : Changed(node);
166 } 197 }
167 198
168 199
169 Reduction JSCallReducer::ReduceJSCallFunction(Node* node) { 200 Reduction JSCallReducer::ReduceJSCallFunction(Node* node) {
170 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); 201 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode());
171 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); 202 CallFunctionParameters const& p = CallFunctionParametersOf(node->op());
172 Node* target = NodeProperties::GetValueInput(node, 0); 203 Node* target = NodeProperties::GetValueInput(node, 0);
204 Node* context = NodeProperties::GetContextInput(node);
173 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 205 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
174 Node* control = NodeProperties::GetControlInput(node); 206 Node* control = NodeProperties::GetControlInput(node);
175 Node* effect = NodeProperties::GetEffectInput(node); 207 Node* effect = NodeProperties::GetEffectInput(node);
176 208
177 // Try to specialize JSCallFunction {node}s with constant {target}s. 209 // Try to specialize JSCallFunction {node}s with constant {target}s.
178 HeapObjectMatcher m(target); 210 HeapObjectMatcher m(target);
179 if (m.HasValue()) { 211 if (m.HasValue()) {
180 if (m.Value()->IsJSFunction()) { 212 if (m.Value()->IsJSFunction()) {
181 Handle<SharedFunctionInfo> shared( 213 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
182 Handle<JSFunction>::cast(m.Value())->shared(), isolate()); 214 Handle<SharedFunctionInfo> shared(function->shared(), isolate());
183 215
184 // Raise a TypeError if the {target} is a "classConstructor". 216 // Raise a TypeError if the {target} is a "classConstructor".
185 if (IsClassConstructor(shared->kind())) { 217 if (IsClassConstructor(shared->kind())) {
186 NodeProperties::RemoveFrameStateInput(node, 0); 218 NodeProperties::RemoveFrameStateInput(node, 0);
187 NodeProperties::RemoveValueInputs(node); 219 NodeProperties::RemoveValueInputs(node);
188 NodeProperties::ChangeOp( 220 NodeProperties::ChangeOp(
189 node, javascript()->CallRuntime( 221 node, javascript()->CallRuntime(
190 Runtime::kThrowConstructorNonCallableError, 0)); 222 Runtime::kThrowConstructorNonCallableError, 0));
191 return Changed(node); 223 return Changed(node);
192 } 224 }
193 225
194 // Check for known builtin functions. 226 // Check for known builtin functions.
195 if (shared->HasBuiltinFunctionId()) { 227 if (shared->HasBuiltinFunctionId()) {
196 switch (shared->builtin_function_id()) { 228 switch (shared->builtin_function_id()) {
197 case kFunctionApply: 229 case kFunctionApply:
198 return ReduceFunctionPrototypeApply(node); 230 return ReduceFunctionPrototypeApply(node);
199 case kFunctionCall: 231 case kFunctionCall:
200 return ReduceFunctionPrototypeCall(node); 232 return ReduceFunctionPrototypeCall(node);
201 default: 233 default:
202 break; 234 break;
203 } 235 }
204 } 236 }
237
238 // Check for the ArrayConstructor.
239 if (*function == function->native_context()->array_function()) {
240 return ReduceArrayConstructor(node);
241 }
205 } 242 }
243
206 // Don't mess with other {node}s that have a constant {target}. 244 // Don't mess with other {node}s that have a constant {target}.
207 // TODO(bmeurer): Also support optimizing bound functions and proxies here. 245 // TODO(bmeurer): Also support optimizing bound functions and proxies here.
208 return NoChange(); 246 return NoChange();
209 } 247 }
210 248
211 // Not much we can do if deoptimization support is disabled. 249 // Not much we can do if deoptimization support is disabled.
212 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); 250 if (!(flags() & kDeoptimizationEnabled)) return NoChange();
213 251
214 // Extract feedback from the {node} using the CallICNexus. 252 // Extract feedback from the {node} using the CallICNexus.
215 if (!p.feedback().IsValid()) return NoChange(); 253 if (!p.feedback().IsValid()) return NoChange();
216 CallICNexus nexus(p.feedback().vector(), p.feedback().slot()); 254 CallICNexus nexus(p.feedback().vector(), p.feedback().slot());
217 Handle<Object> feedback(nexus.GetFeedback(), isolate()); 255 Handle<Object> feedback(nexus.GetFeedback(), isolate());
218 if (feedback->IsWeakCell()) { 256 if (feedback->IsAllocationSite()) {
257 // Retrieve the Array function from the {node}.
258 Node* array_function;
259 Handle<Context> native_context;
260 if (GetNativeContext(node).ToHandle(&native_context)) {
261 array_function = jsgraph()->HeapConstant(
262 handle(native_context->array_function(), isolate()));
263 } else {
264 Node* global_object = effect = graph()->NewNode(
265 javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true),
266 context, context, effect);
267 Node* native_context = effect = graph()->NewNode(
268 javascript()->LoadNativeContext(), global_object, context, effect);
269 array_function = effect = graph()->NewNode(
270 javascript()->LoadContext(0, Context::ARRAY_FUNCTION_INDEX, true),
271 native_context, native_context, effect);
272 }
273
274 // Check that the {target} is still the {array_function}.
275 Node* check = effect =
276 graph()->NewNode(javascript()->StrictEqual(), target, array_function,
277 context, effect, control);
278 Node* branch =
279 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
280 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
281 Node* deoptimize =
282 graph()->NewNode(common()->Deoptimize(), frame_state, effect, if_false);
283 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
284 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
285 control = graph()->NewNode(common()->IfTrue(), branch);
286
287 // Turn the {node} into a {JSCreateArray} call.
288 NodeProperties::ReplaceValueInput(node, array_function, 0);
289 NodeProperties::ReplaceEffectInput(node, effect);
290 NodeProperties::ReplaceControlInput(node, control);
291 return ReduceArrayConstructor(node);
292 } else if (feedback->IsWeakCell()) {
219 Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback); 293 Handle<WeakCell> cell = Handle<WeakCell>::cast(feedback);
220 if (cell->value()->IsJSFunction()) { 294 if (cell->value()->IsJSFunction()) {
295 Node* target_function =
296 jsgraph()->Constant(handle(cell->value(), isolate()));
297
221 // Check that the {target} is still the {target_function}. 298 // Check that the {target} is still the {target_function}.
222 Node* target_function = jsgraph()->HeapConstant( 299 Node* check = effect =
223 handle(JSFunction::cast(cell->value()), isolate())); 300 graph()->NewNode(javascript()->StrictEqual(), target, target_function,
224 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), 301 context, effect, control);
225 target, target_function);
226 Node* branch = 302 Node* branch =
227 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); 303 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
228 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); 304 Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
229 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state, 305 Node* deoptimize = graph()->NewNode(common()->Deoptimize(), frame_state,
230 effect, if_false); 306 effect, if_false);
231 // TODO(bmeurer): This should be on the AdvancedReducer somehow. 307 // TODO(bmeurer): This should be on the AdvancedReducer somehow.
232 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize); 308 NodeProperties::MergeControlToEnd(graph(), common(), deoptimize);
233 control = graph()->NewNode(common()->IfTrue(), branch); 309 control = graph()->NewNode(common()->IfTrue(), branch);
234 310
235 // Specialize the JSCallFunction node to the {target_function}. 311 // Specialize the JSCallFunction node to the {target_function}.
236 NodeProperties::ReplaceValueInput(node, target_function, 0); 312 NodeProperties::ReplaceValueInput(node, target_function, 0);
313 NodeProperties::ReplaceEffectInput(node, effect);
237 NodeProperties::ReplaceControlInput(node, control); 314 NodeProperties::ReplaceControlInput(node, control);
238 315
239 // Try to further reduce the JSCallFunction {node}. 316 // Try to further reduce the JSCallFunction {node}.
240 Reduction const reduction = ReduceJSCallFunction(node); 317 Reduction const reduction = ReduceJSCallFunction(node);
241 return reduction.Changed() ? reduction : Changed(node); 318 return reduction.Changed() ? reduction : Changed(node);
242 } 319 }
243 } 320 }
244 return NoChange(); 321 return NoChange();
245 } 322 }
246 323
247 324
325 Reduction JSCallReducer::ReduceJSCallConstruct(Node* node) {
326 DCHECK_EQ(IrOpcode::kJSCallConstruct, node->opcode());
327 CallConstructParameters const& p = CallConstructParametersOf(node->op());
328 DCHECK_LE(2u, p.arity());
329 int const arity = static_cast<int>(p.arity() - 2);
330 Node* target = NodeProperties::GetValueInput(node, 0);
331 Node* new_target = NodeProperties::GetValueInput(node, arity + 1);
332
333 // Try to specialize JSCallConstruct {node}s with constant {target}s.
334 HeapObjectMatcher m(target);
335 if (m.HasValue()) {
336 if (m.Value()->IsJSFunction()) {
337 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
338
339 // Raise a TypeError if the {target} is not a constructor.
340 if (!function->IsConstructor()) {
341 NodeProperties::ReplaceValueInputs(node, target);
342 NodeProperties::ChangeOp(
343 node,
344 javascript()->CallRuntime(Runtime::kThrowCalledNonCallable, 1));
345 return Changed(node);
346 }
347
348 // Check for the ArrayConstructor.
349 if (*function == function->native_context()->array_function()) {
350 // Check if we have an allocation site.
351 Handle<AllocationSite> site;
352 if (p.feedback().IsValid()) {
353 Handle<Object> feedback(
354 p.feedback().vector()->Get(p.feedback().slot()), isolate());
355 if (feedback->IsAllocationSite()) {
356 site = Handle<AllocationSite>::cast(feedback);
357 }
358 }
359
360 // Turn the {node} into a {JSCreateArray} call.
361 for (int i = arity; i > 0; --i) {
362 NodeProperties::ReplaceValueInput(
363 node, NodeProperties::GetValueInput(node, i), i + 1);
364 }
365 NodeProperties::ReplaceValueInput(node, new_target, 1);
366 NodeProperties::ChangeOp(node, javascript()->CreateArray(arity, site));
367 return Changed(node);
368 }
369 }
370
371 // Don't mess with other {node}s that have a constant {target}.
372 // TODO(bmeurer): Also support optimizing bound functions and proxies here.
373 return NoChange();
374 }
375
376 return NoChange();
377 }
378
379
380 MaybeHandle<Context> JSCallReducer::GetNativeContext(Node* node) {
381 Node* const context = NodeProperties::GetContextInput(node);
382 return NodeProperties::GetSpecializationNativeContext(context,
383 native_context());
384 }
385
386
248 Graph* JSCallReducer::graph() const { return jsgraph()->graph(); } 387 Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
249 388
250 389
251 Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); } 390 Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
252 391
253 392
254 CommonOperatorBuilder* JSCallReducer::common() const { 393 CommonOperatorBuilder* JSCallReducer::common() const {
255 return jsgraph()->common(); 394 return jsgraph()->common();
256 } 395 }
257 396
258 397
259 JSOperatorBuilder* JSCallReducer::javascript() const { 398 JSOperatorBuilder* JSCallReducer::javascript() const {
260 return jsgraph()->javascript(); 399 return jsgraph()->javascript();
261 } 400 }
262 401
263
264 SimplifiedOperatorBuilder* JSCallReducer::simplified() const {
265 return jsgraph()->simplified();
266 }
267
268 } // namespace compiler 402 } // namespace compiler
269 } // namespace internal 403 } // namespace internal
270 } // namespace v8 404 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-call-reducer.h ('k') | src/compiler/js-generic-lowering.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698