OLD | NEW |
---|---|
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/code-stubs.h" | |
7 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
9 #include "src/compiler/linkage.h" | |
8 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
9 #include "src/compiler/simplified-operator.h" | 11 #include "src/compiler/simplified-operator.h" |
10 #include "src/objects-inl.h" | 12 #include "src/objects-inl.h" |
11 #include "src/type-feedback-vector-inl.h" | 13 #include "src/type-feedback-vector-inl.h" |
12 | 14 |
13 namespace v8 { | 15 namespace v8 { |
14 namespace internal { | 16 namespace internal { |
15 namespace compiler { | 17 namespace compiler { |
16 | 18 |
17 Reduction JSCallReducer::Reduce(Node* node) { | 19 Reduction JSCallReducer::Reduce(Node* node) { |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
250 return MaybeHandle<Map>(); | 252 return MaybeHandle<Map>(); |
251 } | 253 } |
252 if (dominator->op()->EffectInputCount() != 1) { | 254 if (dominator->op()->EffectInputCount() != 1) { |
253 // Didn't find any appropriate CheckMaps node. | 255 // Didn't find any appropriate CheckMaps node. |
254 return MaybeHandle<Map>(); | 256 return MaybeHandle<Map>(); |
255 } | 257 } |
256 dominator = NodeProperties::GetEffectInput(dominator); | 258 dominator = NodeProperties::GetEffectInput(dominator); |
257 } | 259 } |
258 } | 260 } |
259 | 261 |
262 bool CanInlineApiCall(Isolate* isolate, Node* node, | |
263 Handle<FunctionTemplateInfo> function_template_info) { | |
264 DCHECK(node->opcode() == IrOpcode::kJSCallFunction); | |
265 if (function_template_info->call_code()->IsUndefined(isolate)) { | |
266 return false; | |
267 } | |
268 CallFunctionParameters const& params = CallFunctionParametersOf(node->op()); | |
269 int const argc = static_cast<int>(params.arity()) - 2; | |
Jarin
2016/12/08 12:31:53
As discussed before, it would be good to describe
epertoso
2016/12/08 13:33:19
Done here and in ReduceCallApiFunction.
| |
270 if (argc > CallApiCallbackStub::kArgMax || !params.feedback().IsValid()) { | |
271 return false; | |
272 } | |
273 HeapObjectMatcher receiver(NodeProperties::GetValueInput(node, 1)); | |
274 if (!receiver.HasValue()) { | |
275 return false; | |
276 } | |
277 return receiver.Value()->IsUndefined(isolate) || | |
278 (receiver.Value()->map()->IsJSObjectMap() && | |
279 !receiver.Value()->map()->is_access_check_needed()); | |
280 } | |
281 | |
260 } // namespace | 282 } // namespace |
261 | 283 |
284 JSCallReducer::HolderLookup JSCallReducer::LookupHolder( | |
285 Handle<JSObject> object, | |
286 Handle<FunctionTemplateInfo> function_template_info, | |
287 Handle<JSObject>* holder) { | |
288 DCHECK(object->map()->IsJSObjectMap()); | |
289 Handle<Map> object_map(object->map()); | |
290 Handle<FunctionTemplateInfo> expected_receiver_type; | |
291 if (!function_template_info->signature()->IsUndefined(isolate())) { | |
292 expected_receiver_type = | |
293 handle(FunctionTemplateInfo::cast(function_template_info->signature())); | |
Jarin
2016/12/08 12:31:53
Hmm, signature of FunctionTemplateInfo is Function
epertoso
2016/12/08 13:33:19
Yes. Not my fault.
| |
294 } | |
295 if (expected_receiver_type.is_null() || | |
296 expected_receiver_type->IsTemplateFor(*object_map)) { | |
297 *holder = Handle<JSObject>::null(); | |
298 return kHolderIsReceiver; | |
299 } | |
300 while (object_map->has_hidden_prototype()) { | |
301 Handle<JSObject> prototype(JSObject::cast(object_map->prototype())); | |
302 object_map = handle(prototype->map()); | |
303 if (expected_receiver_type->IsTemplateFor(*object_map)) { | |
304 *holder = prototype; | |
305 return kHolderFound; | |
306 } | |
307 } | |
308 return kHolderNotFound; | |
309 } | |
310 | |
262 // ES6 section B.2.2.1.1 get Object.prototype.__proto__ | 311 // ES6 section B.2.2.1.1 get Object.prototype.__proto__ |
263 Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) { | 312 Reduction JSCallReducer::ReduceObjectPrototypeGetProto(Node* node) { |
264 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); | 313 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); |
265 | 314 |
266 // Try to determine the {receiver} map. | 315 // Try to determine the {receiver} map. |
267 Handle<Map> receiver_map; | 316 Handle<Map> receiver_map; |
268 if (InferReceiverMap(node).ToHandle(&receiver_map)) { | 317 if (InferReceiverMap(node).ToHandle(&receiver_map)) { |
269 // Check if we can constant-fold the {receiver} map. | 318 // Check if we can constant-fold the {receiver} map. |
270 if (!receiver_map->IsJSProxyMap() && | 319 if (!receiver_map->IsJSProxyMap() && |
271 !receiver_map->has_hidden_prototype() && | 320 !receiver_map->has_hidden_prototype() && |
272 !receiver_map->is_access_check_needed()) { | 321 !receiver_map->is_access_check_needed()) { |
273 Handle<Object> receiver_prototype(receiver_map->prototype(), isolate()); | 322 Handle<Object> receiver_prototype(receiver_map->prototype(), isolate()); |
274 Node* value = jsgraph()->Constant(receiver_prototype); | 323 Node* value = jsgraph()->Constant(receiver_prototype); |
275 ReplaceWithValue(node, value); | 324 ReplaceWithValue(node, value); |
276 return Replace(value); | 325 return Replace(value); |
277 } | 326 } |
278 } | 327 } |
279 | 328 |
280 return NoChange(); | 329 return NoChange(); |
281 } | 330 } |
282 | 331 |
332 Reduction JSCallReducer::ReduceCallApiFunction( | |
333 Node* node, Node* target, | |
334 Handle<FunctionTemplateInfo> function_template_info) { | |
335 Isolate* isolate = this->isolate(); | |
336 CHECK(!isolate->serializer_enabled()); | |
337 HeapObjectMatcher m(target); | |
338 DCHECK(m.HasValue() && m.Value()->IsJSFunction()); | |
339 if (!CanInlineApiCall(isolate, node, function_template_info)) { | |
340 return NoChange(); | |
341 } | |
342 Handle<CallHandlerInfo> call_handler_info( | |
343 handle(CallHandlerInfo::cast(function_template_info->call_code()))); | |
344 Handle<Object> data(call_handler_info->data(), isolate); | |
345 | |
346 Node* receiver_node = NodeProperties::GetValueInput(node, 1); | |
347 CallFunctionParameters const& params = CallFunctionParametersOf(node->op()); | |
348 | |
349 Handle<HeapObject> receiver = HeapObjectMatcher(receiver_node).Value(); | |
350 bool const receiver_is_undefined = receiver->IsUndefined(isolate); | |
351 if (receiver_is_undefined) { | |
352 receiver = handle(Handle<JSFunction>::cast(m.Value())->global_proxy()); | |
353 } else { | |
354 DCHECK(receiver->map()->IsJSObjectMap() && | |
355 !receiver->map()->is_access_check_needed()); | |
356 } | |
357 | |
358 Handle<JSObject> holder; | |
359 HolderLookup lookup = LookupHolder(Handle<JSObject>::cast(receiver), | |
360 function_template_info, &holder); | |
361 if (lookup == kHolderNotFound) return NoChange(); | |
362 if (receiver_is_undefined) { | |
363 receiver_node = jsgraph()->HeapConstant(receiver); | |
364 NodeProperties::ReplaceValueInput(node, receiver_node, 1); | |
365 } | |
366 Node* holder_node = | |
367 lookup == kHolderFound ? jsgraph()->HeapConstant(holder) : receiver_node; | |
368 | |
369 Zone* zone = graph()->zone(); | |
370 int const argc = static_cast<int>(params.arity() - 2); | |
371 CallApiCallbackStub stub(isolate, argc, data->IsUndefined(isolate), false); | |
372 CallInterfaceDescriptor cid = stub.GetCallInterfaceDescriptor(); | |
373 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor( | |
374 isolate, zone, cid, | |
375 cid.GetStackParameterCount() + argc + 1 /* including receiver */, | |
376 CallDescriptor::kNeedsFrameState, Operator::kNoProperties, | |
377 MachineType::AnyTagged(), 1); | |
378 ApiFunction api_function(v8::ToCData<Address>(call_handler_info->callback())); | |
379 ExternalReference function_reference( | |
380 &api_function, ExternalReference::DIRECT_API_CALL, isolate); | |
381 | |
382 // CallApiCallbackStub's register arguments: code, target, call data, holder, | |
383 // function address. | |
384 node->InsertInput(zone, 0, jsgraph()->HeapConstant(stub.GetCode())); | |
385 node->InsertInput(zone, 2, jsgraph()->Constant(data)); | |
386 node->InsertInput(zone, 3, holder_node); | |
387 node->InsertInput(zone, 4, jsgraph()->ExternalConstant(function_reference)); | |
388 NodeProperties::ChangeOp(node, common()->Call(call_descriptor)); | |
389 return Changed(node); | |
390 } | |
391 | |
283 Reduction JSCallReducer::ReduceJSCallFunction(Node* node) { | 392 Reduction JSCallReducer::ReduceJSCallFunction(Node* node) { |
284 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); | 393 DCHECK_EQ(IrOpcode::kJSCallFunction, node->opcode()); |
285 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); | 394 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); |
286 Node* target = NodeProperties::GetValueInput(node, 0); | 395 Node* target = NodeProperties::GetValueInput(node, 0); |
287 Node* control = NodeProperties::GetControlInput(node); | 396 Node* control = NodeProperties::GetControlInput(node); |
288 Node* effect = NodeProperties::GetEffectInput(node); | 397 Node* effect = NodeProperties::GetEffectInput(node); |
289 | 398 |
290 // Try to specialize JSCallFunction {node}s with constant {target}s. | 399 // Try to specialize JSCallFunction {node}s with constant {target}s. |
291 HeapObjectMatcher m(target); | 400 HeapObjectMatcher m(target); |
292 if (m.HasValue()) { | 401 if (m.HasValue()) { |
(...skipping 23 matching lines...) Expand all Loading... | |
316 case Builtins::kObjectPrototypeGetProto: | 425 case Builtins::kObjectPrototypeGetProto: |
317 return ReduceObjectPrototypeGetProto(node); | 426 return ReduceObjectPrototypeGetProto(node); |
318 default: | 427 default: |
319 break; | 428 break; |
320 } | 429 } |
321 | 430 |
322 // Check for the Array constructor. | 431 // Check for the Array constructor. |
323 if (*function == function->native_context()->array_function()) { | 432 if (*function == function->native_context()->array_function()) { |
324 return ReduceArrayConstructor(node); | 433 return ReduceArrayConstructor(node); |
325 } | 434 } |
435 | |
436 if (shared->IsApiFunction()) { | |
437 return ReduceCallApiFunction( | |
438 node, target, | |
439 handle(FunctionTemplateInfo::cast(shared->function_data()))); | |
440 } | |
326 } else if (m.Value()->IsJSBoundFunction()) { | 441 } else if (m.Value()->IsJSBoundFunction()) { |
327 Handle<JSBoundFunction> function = | 442 Handle<JSBoundFunction> function = |
328 Handle<JSBoundFunction>::cast(m.Value()); | 443 Handle<JSBoundFunction>::cast(m.Value()); |
329 Handle<JSReceiver> bound_target_function( | 444 Handle<JSReceiver> bound_target_function( |
330 function->bound_target_function(), isolate()); | 445 function->bound_target_function(), isolate()); |
331 Handle<Object> bound_this(function->bound_this(), isolate()); | 446 Handle<Object> bound_this(function->bound_this(), isolate()); |
332 Handle<FixedArray> bound_arguments(function->bound_arguments(), | 447 Handle<FixedArray> bound_arguments(function->bound_arguments(), |
333 isolate()); | 448 isolate()); |
334 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); | 449 CallFunctionParameters const& p = CallFunctionParametersOf(node->op()); |
335 ConvertReceiverMode const convert_mode = | 450 ConvertReceiverMode const convert_mode = |
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
547 return jsgraph()->javascript(); | 662 return jsgraph()->javascript(); |
548 } | 663 } |
549 | 664 |
550 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { | 665 SimplifiedOperatorBuilder* JSCallReducer::simplified() const { |
551 return jsgraph()->simplified(); | 666 return jsgraph()->simplified(); |
552 } | 667 } |
553 | 668 |
554 } // namespace compiler | 669 } // namespace compiler |
555 } // namespace internal | 670 } // namespace internal |
556 } // namespace v8 | 671 } // namespace v8 |
OLD | NEW |