| Index: runtime/vm/flow_graph_compiler_x64.cc
|
| diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
|
| index 8627315296a9e223ea58b9d97eb696c85962f711..649e9190624fc013184ec546faea37bfca0f9251 100644
|
| --- a/runtime/vm/flow_graph_compiler_x64.cc
|
| +++ b/runtime/vm/flow_graph_compiler_x64.cc
|
| @@ -1471,33 +1471,77 @@ void FlowGraphCompiler::ClobberDeadTempRegisters(LocationSummary* locs) {
|
|
|
|
|
| void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data,
|
| - Register class_id_reg,
|
| intptr_t argument_count,
|
| const Array& argument_names,
|
| - Label* deopt,
|
| + Label* failed,
|
| + Label* match_found,
|
| intptr_t deopt_id,
|
| intptr_t token_index,
|
| LocationSummary* locs) {
|
| ASSERT(is_optimizing());
|
| - ASSERT(!ic_data.IsNull() && (ic_data.NumberOfUsedChecks() > 0));
|
| - Label match_found;
|
| - const intptr_t len = ic_data.NumberOfChecks();
|
| - GrowableArray<CidTarget> sorted(len);
|
| - SortICDataByCount(ic_data, &sorted, /* drop_smi = */ false);
|
| - ASSERT(class_id_reg != R10);
|
| - ASSERT(len > 0); // Why bother otherwise.
|
| +
|
| + __ Comment("EmitTestAndCall");
|
| const Array& arguments_descriptor =
|
| Array::ZoneHandle(ArgumentsDescriptor::New(argument_count,
|
| argument_names));
|
| StubCode* stub_code = isolate()->stub_code();
|
| -
|
| + // Load receiver into RAX.
|
| + __ movq(RAX,
|
| + Address(RSP, (argument_count - 1) * kWordSize));
|
| __ LoadObject(R10, arguments_descriptor, PP);
|
| - for (intptr_t i = 0; i < len; i++) {
|
| - const bool is_last_check = (i == (len - 1));
|
| +
|
| + const bool kFirstCheckIsSmi = ic_data.GetReceiverClassIdAt(0) == kSmiCid;
|
| + const intptr_t kNumChecks = ic_data.NumberOfChecks();
|
| +
|
| + ASSERT(!ic_data.IsNull() && (kNumChecks > 0));
|
| +
|
| + Label after_smi_test;
|
| + __ testq(RAX, Immediate(kSmiTagMask));
|
| + if (kFirstCheckIsSmi) {
|
| + // Jump if receiver is not Smi.
|
| + if (kNumChecks == 1) {
|
| + __ j(NOT_ZERO, failed);
|
| + } else {
|
| + __ j(NOT_ZERO, &after_smi_test);
|
| + }
|
| + // Do not use the code from the function, but let the code be patched so
|
| + // that we can record the outgoing edges to other code.
|
| + GenerateDartCall(deopt_id,
|
| + token_index,
|
| + &stub_code->CallStaticFunctionLabel(),
|
| + RawPcDescriptors::kOther,
|
| + locs);
|
| + const Function& function = Function::Handle(ic_data.GetTargetAt(0));
|
| + AddStaticCallTarget(function);
|
| + __ Drop(argument_count, RCX);
|
| + if (kNumChecks > 1) {
|
| + __ jmp(match_found);
|
| + }
|
| + } else {
|
| + // Receiver is Smi, but Smi is not a valid class therefore fail.
|
| + // (Smi class must be first in the list).
|
| + __ j(ZERO, failed);
|
| + }
|
| + __ Bind(&after_smi_test);
|
| +
|
| + ASSERT(!ic_data.IsNull() && (kNumChecks > 0));
|
| + GrowableArray<CidTarget> sorted(kNumChecks);
|
| + SortICDataByCount(ic_data, &sorted, /* drop_smi = */ true);
|
| +
|
| + const intptr_t kSortedLen = sorted.length();
|
| + // If kSortedLen is 0 then only a Smi check was needed; the Smi check above
|
| + // will fail if there was only one check and receiver is not Smi.
|
| + if (kSortedLen == 0) return;
|
| +
|
| + // Value is not Smi,
|
| + __ LoadClassId(RDI, RAX);
|
| + for (intptr_t i = 0; i < kSortedLen; i++) {
|
| + const bool kIsLastCheck = (i == (kSortedLen - 1));
|
| + ASSERT(sorted[i].cid != kSmiCid);
|
| Label next_test;
|
| - __ cmpl(class_id_reg, Immediate(sorted[i].cid));
|
| - if (is_last_check) {
|
| - __ j(NOT_EQUAL, deopt);
|
| + __ cmpl(RDI, Immediate(sorted[i].cid));
|
| + if (kIsLastCheck) {
|
| + __ j(NOT_EQUAL, failed);
|
| } else {
|
| __ j(NOT_EQUAL, &next_test);
|
| }
|
| @@ -1511,12 +1555,11 @@ void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data,
|
| const Function& function = *sorted[i].target;
|
| AddStaticCallTarget(function);
|
| __ Drop(argument_count, RCX);
|
| - if (!is_last_check) {
|
| - __ jmp(&match_found);
|
| + if (!kIsLastCheck) {
|
| + __ jmp(match_found);
|
| }
|
| __ Bind(&next_test);
|
| }
|
| - __ Bind(&match_found);
|
| }
|
|
|
|
|
|
|