| Index: runtime/vm/flow_graph_compiler_ia32.cc
|
| diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
|
| index 5284273d9164930d262af4dc95036903c900f36b..46ce12d0ec45ac860f7ee57fb6952ad6a0b7e1bf 100644
|
| --- a/runtime/vm/flow_graph_compiler_ia32.cc
|
| +++ b/runtime/vm/flow_graph_compiler_ia32.cc
|
| @@ -1509,35 +1509,78 @@ 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 != EDX);
|
| - 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 EAX.
|
| + __ movl(EAX, Address(ESP, (argument_count - 1) * kWordSize));
|
| __ LoadObject(EDX, arguments_descriptor);
|
| - 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;
|
| + __ testl(EAX, 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);
|
| + 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);
|
| +
|
| + // Value is not Smi,
|
| + // LoadValueCid(this, EDI, EAX, failed);
|
| + 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;
|
| +
|
| + __ LoadClassId(EDI, EAX);
|
| + for (intptr_t i = 0; i < kSortedLen; i++) {
|
| + const bool kIsLastCheck = (i == (kSortedLen - 1));
|
| + ASSERT(sorted[i].cid != kSmiCid);
|
| Label next_test;
|
| - assembler()->cmpl(class_id_reg, Immediate(sorted[i].cid));
|
| - if (is_last_check) {
|
| - assembler()->j(NOT_EQUAL, deopt);
|
| + __ cmpl(EDI, Immediate(sorted[i].cid));
|
| + if (kIsLastCheck) {
|
| + __ j(NOT_EQUAL, failed);
|
| } else {
|
| - assembler()->j(NOT_EQUAL, &next_test);
|
| + __ j(NOT_EQUAL, &next_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.
|
| @@ -1549,12 +1592,11 @@ void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data,
|
| const Function& function = *sorted[i].target;
|
| AddStaticCallTarget(function);
|
| __ Drop(argument_count);
|
| - if (!is_last_check) {
|
| - assembler()->jmp(&match_found);
|
| + if (!kIsLastCheck) {
|
| + __ jmp(match_found);
|
| }
|
| - assembler()->Bind(&next_test);
|
| + __ Bind(&next_test);
|
| }
|
| - assembler()->Bind(&match_found);
|
| }
|
|
|
|
|
|
|