Chromium Code Reviews| 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 |