Introduce inline cache reload rule attribute to static call AST node and ICData.
Reload rule describes how inline cache has to be processed during hot reload, whether it should be updated, reset or preserved. Bug: dartbug.com/30639 Change-Id: I40b63ade786456ec48d4fa205a076654c2996bce Reviewed-on: https://dart-review.googlesource.com/7586 Commit-Queue: Alexander Aprelev <aam@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
5263d17f74
commit
68a727fa5c
+13
-2
@@ -1637,10 +1637,17 @@ class StaticSetterNode : public AstNode {
|
||||
|
||||
class StaticCallNode : public AstNode {
|
||||
public:
|
||||
// The rule below is mapped to ICData::RebindRule (runtime/vm/object.h).
|
||||
enum RebindRule { kNSMDispatch, kStatic, kSuper };
|
||||
|
||||
StaticCallNode(TokenPosition token_pos,
|
||||
const Function& function,
|
||||
ArgumentListNode* arguments)
|
||||
: AstNode(token_pos), function_(function), arguments_(arguments) {
|
||||
ArgumentListNode* arguments,
|
||||
RebindRule rebind_rule)
|
||||
: AstNode(token_pos),
|
||||
function_(function),
|
||||
arguments_(arguments),
|
||||
rebind_rule_(rebind_rule) {
|
||||
ASSERT(function_.IsZoneHandle());
|
||||
ASSERT(arguments_ != NULL);
|
||||
}
|
||||
@@ -1648,6 +1655,9 @@ class StaticCallNode : public AstNode {
|
||||
const Function& function() const { return function_; }
|
||||
ArgumentListNode* arguments() const { return arguments_; }
|
||||
|
||||
RebindRule rebind_rule() const { return rebind_rule_; }
|
||||
void set_rebind_rule(RebindRule rule) { rebind_rule_ = rule; }
|
||||
|
||||
virtual void VisitChildren(AstNodeVisitor* visitor) const {
|
||||
arguments()->Visit(visitor);
|
||||
}
|
||||
@@ -1659,6 +1669,7 @@ class StaticCallNode : public AstNode {
|
||||
private:
|
||||
const Function& function_;
|
||||
ArgumentListNode* arguments_;
|
||||
RebindRule rebind_rule_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(StaticCallNode);
|
||||
};
|
||||
|
||||
@@ -178,8 +178,9 @@ void AwaitTransformer::VisitAwaitNode(AwaitNode* node) {
|
||||
async_await_helper_args->Add(
|
||||
new (Z) LoadLocalNode(token_pos, async_catch_error_callback));
|
||||
async_await_helper_args->Add(new (Z) LoadLocalNode(token_pos, async_op));
|
||||
StaticCallNode* await_helper_call = new (Z) StaticCallNode(
|
||||
node->token_pos(), async_await_helper, async_await_helper_args);
|
||||
StaticCallNode* await_helper_call =
|
||||
new (Z) StaticCallNode(node->token_pos(), async_await_helper,
|
||||
async_await_helper_args, StaticCallNode::kStatic);
|
||||
|
||||
preamble_->Add(
|
||||
new (Z) StoreLocalNode(token_pos, result_param, await_helper_call));
|
||||
@@ -362,8 +363,8 @@ void AwaitTransformer::VisitInstanceCallNode(InstanceCallNode* node) {
|
||||
void AwaitTransformer::VisitStaticCallNode(StaticCallNode* node) {
|
||||
ArgumentListNode* new_args =
|
||||
Transform(node->arguments())->AsArgumentListNode();
|
||||
result_ = MakeName(
|
||||
new (Z) StaticCallNode(node->token_pos(), node->function(), new_args));
|
||||
result_ = MakeName(new (Z) StaticCallNode(node->token_pos(), node->function(),
|
||||
new_args, node->rebind_rule()));
|
||||
}
|
||||
|
||||
void AwaitTransformer::VisitConstructorCallNode(ConstructorCallNode* node) {
|
||||
|
||||
@@ -37,8 +37,8 @@ ASSEMBLER_TEST_GENERATE(IcDataAccess, assembler) {
|
||||
const intptr_t kNumArgs = 1;
|
||||
const Array& args_descriptor = Array::Handle(
|
||||
ArgumentsDescriptor::New(kTypeArgsLen, kNumArgs, Object::null_array()));
|
||||
const ICData& ic_data = ICData::ZoneHandle(
|
||||
ICData::New(function, target_name, args_descriptor, 15, 1, false));
|
||||
const ICData& ic_data = ICData::ZoneHandle(ICData::New(
|
||||
function, target_name, args_descriptor, 15, 1, ICData::kInstance));
|
||||
|
||||
// Code accessing pp is generated, but not executed. Uninitialized pp is OK.
|
||||
__ set_constant_pool_allowed(true);
|
||||
|
||||
@@ -206,10 +206,10 @@ bool AotCallSpecializer::TryReplaceWithHaveSameRuntimeType(
|
||||
args->Add(arg);
|
||||
const intptr_t kTypeArgsLen = 0;
|
||||
ASSERT(call->type_args_len() == kTypeArgsLen);
|
||||
StaticCallInstr* static_call = new (Z)
|
||||
StaticCallInstr(call->token_pos(), have_same_runtime_type, kTypeArgsLen,
|
||||
Object::null_array(), // argument_names
|
||||
args, call->deopt_id(), call->CallCount());
|
||||
StaticCallInstr* static_call = new (Z) StaticCallInstr(
|
||||
call->token_pos(), have_same_runtime_type, kTypeArgsLen,
|
||||
Object::null_array(), // argument_names
|
||||
args, call->deopt_id(), call->CallCount(), ICData::kOptimized);
|
||||
static_call->set_result_cid(kBoolCid);
|
||||
ReplaceCall(call, static_call);
|
||||
return true;
|
||||
@@ -678,7 +678,7 @@ void AotCallSpecializer::VisitInstanceCall(InstanceCallInstr* instr) {
|
||||
// the computed single_target.
|
||||
ic_data = ICData::New(function, instr->function_name(),
|
||||
args_desc_array, Thread::kNoDeoptId,
|
||||
/* args_tested = */ 1, false);
|
||||
/* args_tested = */ 1, ICData::kOptimized);
|
||||
for (intptr_t j = 0; j < i; j++) {
|
||||
ic_data.AddReceiverCheck(class_ids[j], single_target);
|
||||
}
|
||||
@@ -699,7 +699,7 @@ void AotCallSpecializer::VisitInstanceCall(InstanceCallInstr* instr) {
|
||||
const ICData& ic_data = ICData::Handle(
|
||||
ICData::New(flow_graph()->function(), instr->function_name(),
|
||||
args_desc_array, Thread::kNoDeoptId,
|
||||
/* args_tested = */ 1, false));
|
||||
/* args_tested = */ 1, ICData::kOptimized));
|
||||
cls = single_target.Owner();
|
||||
ic_data.AddReceiverCheck(cls.id(), single_target);
|
||||
instr->set_ic_data(&ic_data);
|
||||
@@ -819,10 +819,10 @@ bool AotCallSpecializer::TryReplaceInstanceOfWithRangeCheck(
|
||||
ASSERT(target.IsRecognized() && target.always_inline());
|
||||
|
||||
const intptr_t kTypeArgsLen = 0;
|
||||
StaticCallInstr* new_call =
|
||||
new (Z) StaticCallInstr(call->token_pos(), target, kTypeArgsLen,
|
||||
Object::null_array(), // argument_names
|
||||
args, call->deopt_id(), call->CallCount());
|
||||
StaticCallInstr* new_call = new (Z) StaticCallInstr(
|
||||
call->token_pos(), target, kTypeArgsLen,
|
||||
Object::null_array(), // argument_names
|
||||
args, call->deopt_id(), call->CallCount(), ICData::kOptimized);
|
||||
Environment* copy =
|
||||
call->env()->DeepCopy(Z, call->env()->Length() - call->ArgumentCount());
|
||||
for (intptr_t i = 0; i < args->length(); ++i) {
|
||||
@@ -896,10 +896,10 @@ bool AotCallSpecializer::TryReplaceTypeCastWithRangeCheck(
|
||||
ASSERT(target.always_inline());
|
||||
|
||||
const intptr_t kTypeArgsLen = 0;
|
||||
StaticCallInstr* new_call =
|
||||
new (Z) StaticCallInstr(call->token_pos(), target, kTypeArgsLen,
|
||||
Object::null_array(), // argument_names
|
||||
args, call->deopt_id(), call->CallCount());
|
||||
StaticCallInstr* new_call = new (Z) StaticCallInstr(
|
||||
call->token_pos(), target, kTypeArgsLen,
|
||||
Object::null_array(), // argument_names
|
||||
args, call->deopt_id(), call->CallCount(), ICData::kOptimized);
|
||||
Environment* copy =
|
||||
call->env()->DeepCopy(Z, call->env()->Length() - call->ArgumentCount());
|
||||
for (intptr_t i = 0; i < args->length(); ++i) {
|
||||
|
||||
@@ -2623,9 +2623,10 @@ void Precompiler::PopulateWithICData(const Function& function,
|
||||
const Array& arguments_descriptor =
|
||||
Array::Handle(zone, call->GetArgumentsDescriptor());
|
||||
const ICData& ic_data = ICData::ZoneHandle(
|
||||
zone, ICData::New(function, call->function_name(),
|
||||
arguments_descriptor, call->deopt_id(),
|
||||
call->checked_argument_count(), false));
|
||||
zone,
|
||||
ICData::New(function, call->function_name(), arguments_descriptor,
|
||||
call->deopt_id(), call->checked_argument_count(),
|
||||
ICData::kInstance));
|
||||
call->set_ic_data(&ic_data);
|
||||
}
|
||||
} else if (instr->IsStaticCall()) {
|
||||
@@ -2649,7 +2650,7 @@ void Precompiler::PopulateWithICData(const Function& function,
|
||||
const ICData& ic_data = ICData::ZoneHandle(
|
||||
zone, ICData::New(function, String::Handle(zone, target.name()),
|
||||
arguments_descriptor, call->deopt_id(),
|
||||
num_args_checked, true));
|
||||
num_args_checked, ICData::kStatic));
|
||||
ic_data.AddTarget(target);
|
||||
call->set_ic_data(&ic_data);
|
||||
}
|
||||
|
||||
@@ -1117,7 +1117,8 @@ void FlowGraphCompiler::GenerateStaticCall(intptr_t deopt_id,
|
||||
const Function& function,
|
||||
ArgumentsInfo args_info,
|
||||
LocationSummary* locs,
|
||||
const ICData& ic_data_in) {
|
||||
const ICData& ic_data_in,
|
||||
ICData::RebindRule rebind_rule) {
|
||||
const ICData& ic_data = ICData::ZoneHandle(ic_data_in.Original());
|
||||
const Array& arguments_descriptor = Array::ZoneHandle(
|
||||
zone(), ic_data.IsNull() ? args_info.ToArgumentsDescriptor()
|
||||
@@ -1134,7 +1135,7 @@ void FlowGraphCompiler::GenerateStaticCall(intptr_t deopt_id,
|
||||
const intptr_t kNumArgsChecked = 0;
|
||||
call_ic_data =
|
||||
GetOrAddStaticCallICData(deopt_id, function, arguments_descriptor,
|
||||
kNumArgsChecked)
|
||||
kNumArgsChecked, rebind_rule)
|
||||
->raw();
|
||||
}
|
||||
AddCurrentDescriptor(RawPcDescriptors::kRewind, deopt_id, token_pos);
|
||||
@@ -1551,10 +1552,10 @@ const ICData* FlowGraphCompiler::GetOrAddInstanceCallICData(
|
||||
ASSERT(!res->is_static_call());
|
||||
return res;
|
||||
}
|
||||
const ICData& ic_data =
|
||||
ICData::ZoneHandle(zone(), ICData::New(parsed_function().function(),
|
||||
target_name, arguments_descriptor,
|
||||
deopt_id, num_args_tested, false));
|
||||
const ICData& ic_data = ICData::ZoneHandle(
|
||||
zone(), ICData::New(parsed_function().function(), target_name,
|
||||
arguments_descriptor, deopt_id, num_args_tested,
|
||||
ICData::kInstance));
|
||||
#if defined(TAG_IC_DATA)
|
||||
ic_data.set_tag(Instruction::kInstanceCall);
|
||||
#endif
|
||||
@@ -1569,7 +1570,8 @@ const ICData* FlowGraphCompiler::GetOrAddStaticCallICData(
|
||||
intptr_t deopt_id,
|
||||
const Function& target,
|
||||
const Array& arguments_descriptor,
|
||||
intptr_t num_args_tested) {
|
||||
intptr_t num_args_tested,
|
||||
ICData::RebindRule rebind_rule) {
|
||||
if ((deopt_id_to_ic_data_ != NULL) &&
|
||||
((*deopt_id_to_ic_data_)[deopt_id] != NULL)) {
|
||||
const ICData* res = (*deopt_id_to_ic_data_)[deopt_id];
|
||||
@@ -1581,11 +1583,12 @@ const ICData* FlowGraphCompiler::GetOrAddStaticCallICData(
|
||||
ASSERT(res->is_static_call());
|
||||
return res;
|
||||
}
|
||||
|
||||
const ICData& ic_data = ICData::ZoneHandle(
|
||||
zone(),
|
||||
ICData::New(parsed_function().function(),
|
||||
String::Handle(zone(), target.name()), arguments_descriptor,
|
||||
deopt_id, num_args_tested, true));
|
||||
deopt_id, num_args_tested, rebind_rule));
|
||||
ic_data.AddTarget(target);
|
||||
#if defined(TAG_IC_DATA)
|
||||
ic_data.set_tag(Instruction::kStaticCall);
|
||||
|
||||
@@ -385,7 +385,8 @@ class FlowGraphCompiler : public ValueObject {
|
||||
const Function& function,
|
||||
ArgumentsInfo args_info,
|
||||
LocationSummary* locs,
|
||||
const ICData& ic_data);
|
||||
const ICData& ic_data_in,
|
||||
ICData::RebindRule rebind_rule);
|
||||
|
||||
void GenerateNumberTypeCheck(Register kClassIdReg,
|
||||
const AbstractType& type,
|
||||
@@ -570,7 +571,8 @@ class FlowGraphCompiler : public ValueObject {
|
||||
const ICData* GetOrAddStaticCallICData(intptr_t deopt_id,
|
||||
const Function& target,
|
||||
const Array& arguments_descriptor,
|
||||
intptr_t num_args_tested);
|
||||
intptr_t num_args_tested,
|
||||
ICData::RebindRule rebind_rule);
|
||||
|
||||
static const CallTargets* ResolveCallTargetsForReceiverCid(
|
||||
intptr_t cid,
|
||||
|
||||
@@ -3463,7 +3463,8 @@ void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
break;
|
||||
}
|
||||
call_ic_data = compiler->GetOrAddStaticCallICData(
|
||||
deopt_id(), function(), arguments_descriptor, num_args_checked);
|
||||
deopt_id(), function(), arguments_descriptor, num_args_checked,
|
||||
rebind_rule_);
|
||||
} else {
|
||||
call_ic_data = &ICData::ZoneHandle(ic_data()->raw());
|
||||
}
|
||||
@@ -3471,7 +3472,7 @@ void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
#if !defined(TARGET_ARCH_DBC)
|
||||
ArgumentsInfo args_info(type_args_len(), ArgumentCount(), argument_names());
|
||||
compiler->GenerateStaticCall(deopt_id(), token_pos(), function(), args_info,
|
||||
locs(), *call_ic_data);
|
||||
locs(), *call_ic_data, rebind_rule_);
|
||||
#else
|
||||
const Array& arguments_descriptor = Array::Handle(
|
||||
zone, (ic_data() == NULL) ? GetArgumentsDescriptor()
|
||||
|
||||
@@ -3283,7 +3283,8 @@ class StaticCallInstr : public TemplateDartCall<0> {
|
||||
const Array& argument_names,
|
||||
ZoneGrowableArray<PushArgumentInstr*>* arguments,
|
||||
const ZoneGrowableArray<const ICData*>& ic_data_array,
|
||||
intptr_t deopt_id)
|
||||
intptr_t deopt_id,
|
||||
ICData::RebindRule rebind_rule)
|
||||
: TemplateDartCall(deopt_id,
|
||||
type_args_len,
|
||||
argument_names,
|
||||
@@ -3292,6 +3293,7 @@ class StaticCallInstr : public TemplateDartCall<0> {
|
||||
ic_data_(NULL),
|
||||
call_count_(0),
|
||||
function_(function),
|
||||
rebind_rule_(rebind_rule),
|
||||
result_cid_(kDynamicCid),
|
||||
is_known_list_constructor_(false),
|
||||
identity_(AliasIdentity::Unknown()) {
|
||||
@@ -3306,7 +3308,8 @@ class StaticCallInstr : public TemplateDartCall<0> {
|
||||
const Array& argument_names,
|
||||
ZoneGrowableArray<PushArgumentInstr*>* arguments,
|
||||
intptr_t deopt_id,
|
||||
intptr_t call_count)
|
||||
intptr_t call_count,
|
||||
ICData::RebindRule rebind_rule)
|
||||
: TemplateDartCall(deopt_id,
|
||||
type_args_len,
|
||||
argument_names,
|
||||
@@ -3315,6 +3318,7 @@ class StaticCallInstr : public TemplateDartCall<0> {
|
||||
ic_data_(NULL),
|
||||
call_count_(call_count),
|
||||
function_(function),
|
||||
rebind_rule_(rebind_rule),
|
||||
result_cid_(kDynamicCid),
|
||||
is_known_list_constructor_(false),
|
||||
identity_(AliasIdentity::Unknown()) {
|
||||
@@ -3333,9 +3337,10 @@ class StaticCallInstr : public TemplateDartCall<0> {
|
||||
for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
|
||||
args->Add(call->PushArgumentAt(i));
|
||||
}
|
||||
return new (zone) StaticCallInstr(
|
||||
call->token_pos(), target, call->type_args_len(),
|
||||
call->argument_names(), args, call->deopt_id(), call->CallCount());
|
||||
return new (zone)
|
||||
StaticCallInstr(call->token_pos(), target, call->type_args_len(),
|
||||
call->argument_names(), args, call->deopt_id(),
|
||||
call->CallCount(), ICData::kStatic);
|
||||
}
|
||||
|
||||
// ICData for static calls carries call count.
|
||||
@@ -3383,6 +3388,7 @@ class StaticCallInstr : public TemplateDartCall<0> {
|
||||
const ICData* ic_data_;
|
||||
const intptr_t call_count_;
|
||||
const Function& function_;
|
||||
const ICData::RebindRule rebind_rule_;
|
||||
intptr_t result_cid_; // For some library functions we know the result.
|
||||
|
||||
// 'True' for recognized list constructors.
|
||||
|
||||
@@ -912,7 +912,8 @@ void StringInterpolateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
const Array& kNoArgumentNames = Object::null_array();
|
||||
ArgumentsInfo args_info(kTypeArgsLen, kNumberOfArguments, kNoArgumentNames);
|
||||
compiler->GenerateStaticCall(deopt_id(), token_pos(), CallFunction(),
|
||||
args_info, locs(), ICData::Handle());
|
||||
args_info, locs(), ICData::Handle(),
|
||||
ICData::kStatic);
|
||||
ASSERT(locs()->out(0).reg() == R0);
|
||||
}
|
||||
|
||||
@@ -5573,7 +5574,8 @@ void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
const Array& kNoArgumentNames = Object::null_array();
|
||||
ArgumentsInfo args_info(kTypeArgsLen, kNumberOfArguments, kNoArgumentNames);
|
||||
compiler->GenerateStaticCall(deopt_id(), instance_call()->token_pos(), target,
|
||||
args_info, locs(), ICData::Handle());
|
||||
args_info, locs(), ICData::Handle(),
|
||||
ICData::kStatic);
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
|
||||
@@ -774,7 +774,8 @@ void StringInterpolateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
const Array& kNoArgumentNames = Object::null_array();
|
||||
ArgumentsInfo args_info(kTypeArgsLen, kNumberOfArguments, kNoArgumentNames);
|
||||
compiler->GenerateStaticCall(deopt_id(), token_pos(), CallFunction(),
|
||||
args_info, locs(), ICData::Handle());
|
||||
args_info, locs(), ICData::Handle(),
|
||||
ICData::kStatic);
|
||||
ASSERT(locs()->out(0).reg() == R0);
|
||||
}
|
||||
|
||||
@@ -4798,7 +4799,8 @@ void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
const Array& kNoArgumentNames = Object::null_array();
|
||||
ArgumentsInfo args_info(kTypeArgsLen, kNumberOfArguments, kNoArgumentNames);
|
||||
compiler->GenerateStaticCall(deopt_id(), instance_call()->token_pos(), target,
|
||||
args_info, locs(), ICData::Handle());
|
||||
args_info, locs(), ICData::Handle(),
|
||||
ICData::kStatic);
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
|
||||
@@ -841,7 +841,8 @@ void StringInterpolateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
const Array& kNoArgumentNames = Object::null_array();
|
||||
ArgumentsInfo args_info(kTypeArgsLen, kNumberOfArguments, kNoArgumentNames);
|
||||
compiler->GenerateStaticCall(deopt_id(), token_pos(), CallFunction(),
|
||||
args_info, locs(), ICData::Handle());
|
||||
args_info, locs(), ICData::Handle(),
|
||||
ICData::kStatic);
|
||||
ASSERT(locs()->out(0).reg() == EAX);
|
||||
}
|
||||
|
||||
@@ -5101,7 +5102,8 @@ void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
const Array& kNoArgumentNames = Object::null_array();
|
||||
ArgumentsInfo args_info(kTypeArgsLen, kNumberOfArguments, kNoArgumentNames);
|
||||
compiler->GenerateStaticCall(deopt_id(), instance_call()->token_pos(), target,
|
||||
args_info, locs(), ICData::Handle());
|
||||
args_info, locs(), ICData::Handle(),
|
||||
ICData::kStatic);
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
|
||||
@@ -814,7 +814,8 @@ void StringInterpolateInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
const Array& kNoArgumentNames = Object::null_array();
|
||||
ArgumentsInfo args_info(kTypeArgsLen, kNumberOfArguments, kNoArgumentNames);
|
||||
compiler->GenerateStaticCall(deopt_id(), token_pos(), CallFunction(),
|
||||
args_info, locs(), ICData::Handle());
|
||||
args_info, locs(), ICData::Handle(),
|
||||
ICData::kStatic);
|
||||
ASSERT(locs()->out(0).reg() == RAX);
|
||||
}
|
||||
|
||||
@@ -5058,7 +5059,8 @@ void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
const Array& kNoArgumentNames = Object::null_array();
|
||||
ArgumentsInfo args_info(kTypeArgsLen, kNumberOfArguments, kNoArgumentNames);
|
||||
compiler->GenerateStaticCall(deopt_id(), instance_call()->token_pos(), target,
|
||||
args_info, locs(), ICData::Handle());
|
||||
args_info, locs(), ICData::Handle(),
|
||||
ICData::kStatic);
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
|
||||
@@ -1449,10 +1449,10 @@ void CallSpecializer::ReplaceWithTypeCast(InstanceCallInstr* call) {
|
||||
ASSERT(target.always_inline());
|
||||
|
||||
const intptr_t kTypeArgsLen = 0;
|
||||
StaticCallInstr* new_call =
|
||||
new (Z) StaticCallInstr(call->token_pos(), target, kTypeArgsLen,
|
||||
Object::null_array(), // argument_names
|
||||
args, call->deopt_id(), call->CallCount());
|
||||
StaticCallInstr* new_call = new (Z) StaticCallInstr(
|
||||
call->token_pos(), target, kTypeArgsLen,
|
||||
Object::null_array(), // argument_names
|
||||
args, call->deopt_id(), call->CallCount(), ICData::kStatic);
|
||||
Environment* copy =
|
||||
call->env()->DeepCopy(Z, call->env()->Length() - call->ArgumentCount());
|
||||
for (intptr_t i = 0; i < args->length(); ++i) {
|
||||
|
||||
@@ -37,7 +37,8 @@ CODEGEN_TEST2_GENERATE(SimpleStaticCallCodegen, function, test) {
|
||||
// Wrap the SmiReturnCodegen test above as a static function and call it.
|
||||
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
|
||||
test->node_sequence()->Add(
|
||||
new ReturnNode(kPos, new StaticCallNode(kPos, function, no_arguments)));
|
||||
new ReturnNode(kPos, new StaticCallNode(kPos, function, no_arguments,
|
||||
StaticCallNode::kStatic)));
|
||||
}
|
||||
CODEGEN_TEST2_RUN(SimpleStaticCallCodegen, SmiReturnCodegen, Smi::New(3))
|
||||
|
||||
@@ -67,8 +68,9 @@ CODEGEN_TEST2_GENERATE(StaticCallReturnParameterCodegen, function, test) {
|
||||
SequenceNode* node_seq = test->node_sequence();
|
||||
ArgumentListNode* arguments = new ArgumentListNode(kPos);
|
||||
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))));
|
||||
node_seq->Add(
|
||||
new ReturnNode(kPos, new StaticCallNode(kPos, function, arguments)));
|
||||
node_seq->Add(new ReturnNode(
|
||||
kPos,
|
||||
new StaticCallNode(kPos, function, arguments, StaticCallNode::kStatic)));
|
||||
}
|
||||
CODEGEN_TEST2_RUN(StaticCallReturnParameterCodegen,
|
||||
ReturnParameterCodegen,
|
||||
@@ -102,8 +104,9 @@ CODEGEN_TEST2_GENERATE(StaticCallSmiParamSumCodegen, function, test) {
|
||||
ArgumentListNode* arguments = new ArgumentListNode(kPos);
|
||||
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))));
|
||||
arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2))));
|
||||
node_seq->Add(
|
||||
new ReturnNode(kPos, new StaticCallNode(kPos, function, arguments)));
|
||||
node_seq->Add(new ReturnNode(
|
||||
kPos,
|
||||
new StaticCallNode(kPos, function, arguments, StaticCallNode::kStatic)));
|
||||
}
|
||||
CODEGEN_TEST2_RUN(StaticCallSmiParamSumCodegen, SmiParamSumCodegen, Smi::New(5))
|
||||
|
||||
@@ -246,10 +249,10 @@ CODEGEN_TEST_GENERATE(StaticCallCodegen, test) {
|
||||
EXPECT(function_fly.HasCode());
|
||||
|
||||
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
|
||||
StaticCallNode* call_bar =
|
||||
new StaticCallNode(kPos, function_bar, no_arguments);
|
||||
StaticCallNode* call_fly =
|
||||
new StaticCallNode(kPos, function_fly, no_arguments);
|
||||
StaticCallNode* call_bar = new StaticCallNode(
|
||||
kPos, function_bar, no_arguments, StaticCallNode::kStatic);
|
||||
StaticCallNode* call_fly = new StaticCallNode(
|
||||
kPos, function_fly, no_arguments, StaticCallNode::kStatic);
|
||||
|
||||
BinaryOpNode* add_node =
|
||||
new BinaryOpNode(kPos, Token::kADD, call_bar, call_fly);
|
||||
|
||||
@@ -1110,11 +1110,12 @@ void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) {
|
||||
ZoneGrowableArray<PushArgumentInstr*>* no_arguments =
|
||||
new (Z) ZoneGrowableArray<PushArgumentInstr*>(0);
|
||||
const int kTypeArgsLen = 0;
|
||||
StaticCallInstr* call_async_clear_thread_stack_trace = new (Z)
|
||||
StaticCallInstr(node->token_pos().ToSynthetic(),
|
||||
async_clear_thread_stack_trace, kTypeArgsLen,
|
||||
Object::null_array(), no_arguments,
|
||||
owner()->ic_data_array(), owner()->GetNextDeoptId());
|
||||
StaticCallInstr* call_async_clear_thread_stack_trace =
|
||||
new (Z) StaticCallInstr(node->token_pos().ToSynthetic(),
|
||||
async_clear_thread_stack_trace, kTypeArgsLen,
|
||||
Object::null_array(), no_arguments,
|
||||
owner()->ic_data_array(),
|
||||
owner()->GetNextDeoptId(), ICData::kStatic);
|
||||
Do(call_async_clear_thread_stack_trace);
|
||||
}
|
||||
|
||||
@@ -1150,7 +1151,7 @@ void EffectGraphVisitor::VisitReturnNode(ReturnNode* node) {
|
||||
StaticCallInstr* call = new (Z) StaticCallInstr(
|
||||
node->token_pos().ToSynthetic(), complete_on_async_return, kTypeArgsLen,
|
||||
Object::null_array(), arguments, owner()->ic_data_array(),
|
||||
owner()->GetNextDeoptId());
|
||||
owner()->GetNextDeoptId(), ICData::kStatic);
|
||||
Do(call);
|
||||
|
||||
// Rebind the return value for the actual return call to be null.
|
||||
@@ -2247,7 +2248,7 @@ void EffectGraphVisitor::VisitStringInterpolateNode(
|
||||
kTypeArgsLen, kNumberOfArguments, kNoArgumentNames));
|
||||
StaticCallInstr* call = new (Z) StaticCallInstr(
|
||||
node->token_pos(), function, kTypeArgsLen, kNoArgumentNames, values,
|
||||
owner()->ic_data_array(), owner()->GetNextDeoptId());
|
||||
owner()->ic_data_array(), owner()->GetNextDeoptId(), ICData::kStatic);
|
||||
ReturnDefinition(call);
|
||||
return;
|
||||
}
|
||||
@@ -2476,6 +2477,21 @@ void EffectGraphVisitor::VisitInstanceCallNode(InstanceCallNode* node) {
|
||||
}
|
||||
}
|
||||
|
||||
static ICData::RebindRule ConvertRebindRule(
|
||||
StaticCallNode::RebindRule rebind_rule_ast) {
|
||||
switch (rebind_rule_ast) {
|
||||
case StaticCallNode::kNSMDispatch:
|
||||
return ICData::kNSMDispatch;
|
||||
case StaticCallNode::kSuper:
|
||||
return ICData::kSuper;
|
||||
case StaticCallNode::kStatic:
|
||||
return ICData::kStatic;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return ICData::kStatic;
|
||||
}
|
||||
}
|
||||
|
||||
// <Expression> ::= StaticCall { function: Function
|
||||
// arguments: <ArgumentList> }
|
||||
void EffectGraphVisitor::VisitStaticCallNode(StaticCallNode* node) {
|
||||
@@ -2487,7 +2503,7 @@ void EffectGraphVisitor::VisitStaticCallNode(StaticCallNode* node) {
|
||||
StaticCallInstr* call = new (Z) StaticCallInstr(
|
||||
node->token_pos(), node->function(), node->arguments()->type_args_len(),
|
||||
node->arguments()->names(), arguments, owner()->ic_data_array(),
|
||||
owner()->GetNextDeoptId());
|
||||
owner()->GetNextDeoptId(), ConvertRebindRule(node->rebind_rule()));
|
||||
if (node->function().recognized_kind() != MethodRecognizer::kUnknown) {
|
||||
call->set_result_cid(MethodRecognizer::ResultCid(node->function()));
|
||||
}
|
||||
@@ -2581,10 +2597,10 @@ void EffectGraphVisitor::BuildConstructorCall(
|
||||
|
||||
BuildPushArguments(*node->arguments(), arguments);
|
||||
const intptr_t kTypeArgsLen = 0;
|
||||
Do(new (Z)
|
||||
StaticCallInstr(node->token_pos(), node->constructor(), kTypeArgsLen,
|
||||
node->arguments()->names(), arguments,
|
||||
owner()->ic_data_array(), owner()->GetNextDeoptId()));
|
||||
Do(new (Z) StaticCallInstr(node->token_pos(), node->constructor(),
|
||||
kTypeArgsLen, node->arguments()->names(),
|
||||
arguments, owner()->ic_data_array(),
|
||||
owner()->GetNextDeoptId(), ICData::kStatic));
|
||||
}
|
||||
|
||||
static intptr_t GetResultCidOfListFactory(ConstructorCallNode* node) {
|
||||
@@ -2621,10 +2637,10 @@ void EffectGraphVisitor::VisitConstructorCallNode(ConstructorCallNode* node) {
|
||||
ASSERT(arguments->length() == 1);
|
||||
BuildPushArguments(*node->arguments(), arguments);
|
||||
const int kTypeArgsLen = 0;
|
||||
StaticCallInstr* call = new (Z)
|
||||
StaticCallInstr(node->token_pos(), node->constructor(), kTypeArgsLen,
|
||||
node->arguments()->names(), arguments,
|
||||
owner()->ic_data_array(), owner()->GetNextDeoptId());
|
||||
StaticCallInstr* call = new (Z) StaticCallInstr(
|
||||
node->token_pos(), node->constructor(), kTypeArgsLen,
|
||||
node->arguments()->names(), arguments, owner()->ic_data_array(),
|
||||
owner()->GetNextDeoptId(), ICData::kStatic);
|
||||
const intptr_t result_cid = GetResultCidOfListFactory(node);
|
||||
if (result_cid != kDynamicCid) {
|
||||
call->set_result_cid(result_cid);
|
||||
@@ -3020,10 +3036,11 @@ void EffectGraphVisitor::VisitStaticGetterNode(StaticGetterNode* node) {
|
||||
}
|
||||
ASSERT(!getter_function.IsNull());
|
||||
const intptr_t kTypeArgsLen = 0;
|
||||
StaticCallInstr* call = new (Z) StaticCallInstr(
|
||||
node->token_pos(), getter_function, kTypeArgsLen,
|
||||
Object::null_array(), // No names
|
||||
arguments, owner()->ic_data_array(), owner()->GetNextDeoptId());
|
||||
StaticCallInstr* call =
|
||||
new (Z) StaticCallInstr(node->token_pos(), getter_function, kTypeArgsLen,
|
||||
Object::null_array(), // No names
|
||||
arguments, owner()->ic_data_array(),
|
||||
owner()->GetNextDeoptId(), ICData::kStatic);
|
||||
ReturnDefinition(call);
|
||||
}
|
||||
|
||||
@@ -3085,7 +3102,7 @@ void EffectGraphVisitor::BuildStaticSetter(StaticSetterNode* node,
|
||||
call = new (Z) StaticCallInstr(token_pos, setter_function, kTypeArgsLen,
|
||||
Object::null_array(), // No names.
|
||||
arguments, owner()->ic_data_array(),
|
||||
owner()->GetNextDeoptId());
|
||||
owner()->GetNextDeoptId(), ICData::kStatic);
|
||||
}
|
||||
if (result_is_needed) {
|
||||
Do(call);
|
||||
@@ -3515,7 +3532,8 @@ void EffectGraphVisitor::VisitLoadIndexedNode(LoadIndexedNode* node) {
|
||||
// Generate static call to super operator.
|
||||
StaticCallInstr* load = new (Z) StaticCallInstr(
|
||||
node->token_pos(), *super_function, kTypeArgsLen, Object::null_array(),
|
||||
arguments, owner()->ic_data_array(), owner()->GetNextDeoptId());
|
||||
arguments, owner()->ic_data_array(), owner()->GetNextDeoptId(),
|
||||
ICData::kStatic);
|
||||
ReturnDefinition(load);
|
||||
} else {
|
||||
// Generate dynamic call to index operator.
|
||||
@@ -3588,7 +3606,8 @@ Definition* EffectGraphVisitor::BuildStoreIndexedValues(StoreIndexedNode* node,
|
||||
|
||||
StaticCallInstr* store = new (Z) StaticCallInstr(
|
||||
token_pos, *super_function, kTypeArgsLen, Object::null_array(),
|
||||
arguments, owner()->ic_data_array(), owner()->GetNextDeoptId());
|
||||
arguments, owner()->ic_data_array(), owner()->GetNextDeoptId(),
|
||||
ICData::kStatic);
|
||||
if (result_is_needed) {
|
||||
Do(store);
|
||||
return BuildLoadExprTemp(token_pos);
|
||||
@@ -3796,7 +3815,8 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) {
|
||||
type_args_val = Bind(new (Z) StaticCallInstr(
|
||||
node->token_pos(), prepend_function, kTypeArgsLen,
|
||||
Object::null_array(), // No names.
|
||||
arguments, owner()->ic_data_array(), owner()->GetNextDeoptId()));
|
||||
arguments, owner()->ic_data_array(), owner()->GetNextDeoptId(),
|
||||
ICData::kStatic));
|
||||
}
|
||||
Do(BuildStoreLocal(*type_args_var, type_args_val, ST(node->token_pos())));
|
||||
if (type_args_var->is_captured()) {
|
||||
@@ -3838,11 +3858,12 @@ void EffectGraphVisitor::VisitSequenceNode(SequenceNode* node) {
|
||||
ASSERT(!async_set_thread_stack_trace.IsNull());
|
||||
// Call _asyncSetThreadStackTrace
|
||||
const intptr_t kTypeArgsLen = 0;
|
||||
StaticCallInstr* call_async_set_thread_stack_trace = new (Z)
|
||||
StaticCallInstr(node->token_pos().ToSynthetic(),
|
||||
async_set_thread_stack_trace, kTypeArgsLen,
|
||||
Object::null_array(), arguments,
|
||||
owner()->ic_data_array(), owner()->GetNextDeoptId());
|
||||
StaticCallInstr* call_async_set_thread_stack_trace =
|
||||
new (Z) StaticCallInstr(node->token_pos().ToSynthetic(),
|
||||
async_set_thread_stack_trace, kTypeArgsLen,
|
||||
Object::null_array(), arguments,
|
||||
owner()->ic_data_array(),
|
||||
owner()->GetNextDeoptId(), ICData::kStatic);
|
||||
Do(call_async_set_thread_stack_trace);
|
||||
}
|
||||
|
||||
@@ -4199,9 +4220,10 @@ StaticCallInstr* EffectGraphVisitor::BuildStaticNoSuchMethodCall(
|
||||
ZoneGrowableArray<PushArgumentInstr*>* push_arguments =
|
||||
new (Z) ZoneGrowableArray<PushArgumentInstr*>(2);
|
||||
BuildPushArguments(*args, push_arguments);
|
||||
return new (Z) StaticCallInstr(
|
||||
args_pos, no_such_method_func, kTypeArgsLen, Object::null_array(),
|
||||
push_arguments, owner()->ic_data_array(), owner()->GetNextDeoptId());
|
||||
return new (Z) StaticCallInstr(args_pos, no_such_method_func, kTypeArgsLen,
|
||||
Object::null_array(), push_arguments,
|
||||
owner()->ic_data_array(),
|
||||
owner()->GetNextDeoptId(), ICData::kStatic);
|
||||
}
|
||||
|
||||
StaticCallInstr* EffectGraphVisitor::BuildThrowNoSuchMethodError(
|
||||
@@ -4267,7 +4289,7 @@ StaticCallInstr* EffectGraphVisitor::BuildThrowNoSuchMethodError(
|
||||
return new (Z) StaticCallInstr(token_pos, func, kTypeArgsLen,
|
||||
Object::null_array(), // No names.
|
||||
arguments, owner()->ic_data_array(),
|
||||
owner()->GetNextDeoptId());
|
||||
owner()->GetNextDeoptId(), ICData::kStatic);
|
||||
}
|
||||
|
||||
void EffectGraphVisitor::BuildThrowNode(ThrowNode* node) {
|
||||
|
||||
@@ -3408,8 +3408,9 @@ Fragment StreamingFlowGraphBuilder::BuildInitializers(
|
||||
|
||||
const Function& target = Function::ZoneHandle(
|
||||
Z, H.LookupConstructorByKernelConstructor(canonical_target));
|
||||
instructions += StaticCall(TokenPosition::kNoSource, target,
|
||||
argument_count, argument_names);
|
||||
instructions +=
|
||||
StaticCall(TokenPosition::kNoSource, target, argument_count,
|
||||
argument_names, ICData::kStatic);
|
||||
instructions += Drop();
|
||||
break;
|
||||
}
|
||||
@@ -3429,8 +3430,9 @@ Fragment StreamingFlowGraphBuilder::BuildInitializers(
|
||||
|
||||
const Function& target = Function::ZoneHandle(
|
||||
Z, H.LookupConstructorByKernelConstructor(canonical_target));
|
||||
instructions += StaticCall(TokenPosition::kNoSource, target,
|
||||
argument_count, argument_names);
|
||||
instructions +=
|
||||
StaticCall(TokenPosition::kNoSource, target, argument_count,
|
||||
argument_names, ICData::kStatic);
|
||||
instructions += Drop();
|
||||
break;
|
||||
}
|
||||
@@ -3538,7 +3540,7 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfImplicitClosureFunction(
|
||||
intptr_t argument_count = positional_argument_count + named_argument_count;
|
||||
if (!target.is_static()) ++argument_count;
|
||||
body += StaticCall(TokenPosition::kNoSource, target, argument_count,
|
||||
argument_names);
|
||||
argument_names, ICData::kNoRebind);
|
||||
|
||||
// Return the result.
|
||||
body += Return(function_node_helper.end_position_);
|
||||
@@ -3829,7 +3831,8 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction(bool constructor) {
|
||||
instructions += PushArgument();
|
||||
|
||||
// Call _asyncSetThreadStackTrace
|
||||
instructions += StaticCall(TokenPosition::kNoSource, target, 1);
|
||||
instructions += StaticCall(TokenPosition::kNoSource, target,
|
||||
/* argument_count = */ 1, ICData::kStatic);
|
||||
instructions += Drop();
|
||||
|
||||
// TODO(29737): This sequence should be generated in order.
|
||||
@@ -4995,17 +4998,21 @@ Fragment StreamingFlowGraphBuilder::LoadStaticField() {
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
|
||||
const Function& target,
|
||||
intptr_t argument_count) {
|
||||
return flow_graph_builder_->StaticCall(position, target, argument_count);
|
||||
intptr_t argument_count,
|
||||
ICData::RebindRule rebind_rule) {
|
||||
return flow_graph_builder_->StaticCall(position, target, argument_count,
|
||||
rebind_rule);
|
||||
}
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
|
||||
const Function& target,
|
||||
intptr_t argument_count,
|
||||
const Array& argument_names,
|
||||
ICData::RebindRule rebind_rule,
|
||||
intptr_t type_args_count) {
|
||||
return flow_graph_builder_->StaticCall(position, target, argument_count,
|
||||
argument_names, type_args_count);
|
||||
argument_names, rebind_rule,
|
||||
type_args_count);
|
||||
}
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::InstanceCall(
|
||||
@@ -5463,7 +5470,12 @@ Fragment StreamingFlowGraphBuilder::BuildDirectPropertyGet(TokenPosition* p) {
|
||||
}
|
||||
|
||||
instructions += PushArgument();
|
||||
return instructions + StaticCall(position, target, 1);
|
||||
// Static calls are marked as "no-rebind", which is currently safe because
|
||||
// DirectPropertyGet are only used in enums (index in toString) and enums
|
||||
// can't change their structure during hot reload.
|
||||
// If there are other sources of DirectPropertyGet in the future, this code
|
||||
// have to be adjusted.
|
||||
return instructions + StaticCall(position, target, 1, ICData::kNoRebind);
|
||||
}
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::BuildDirectPropertySet(TokenPosition* p) {
|
||||
@@ -5487,7 +5499,12 @@ Fragment StreamingFlowGraphBuilder::BuildDirectPropertySet(TokenPosition* p) {
|
||||
instructions += StoreLocal(TokenPosition::kNoSource, value);
|
||||
instructions += PushArgument();
|
||||
|
||||
instructions += StaticCall(position, target, 2);
|
||||
// Static calls are marked as "no-rebind", which is currently safe because
|
||||
// DirectPropertyGet are only used in enums (index in toString) and enums
|
||||
// can't change their structure during hot reload.
|
||||
// If there are other sources of DirectPropertyGet in the future, this code
|
||||
// have to be adjusted.
|
||||
instructions += StaticCall(position, target, 2, ICData::kNoRebind);
|
||||
|
||||
return instructions + Drop();
|
||||
}
|
||||
@@ -5514,7 +5531,7 @@ Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) {
|
||||
Fragment instructions = Constant(field);
|
||||
return instructions + LoadStaticField();
|
||||
} else {
|
||||
return StaticCall(position, getter, 0);
|
||||
return StaticCall(position, getter, 0, ICData::kStatic);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -5522,7 +5539,7 @@ Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) {
|
||||
Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
|
||||
|
||||
if (H.IsGetter(target)) {
|
||||
return StaticCall(position, function, 0);
|
||||
return StaticCall(position, function, 0, ICData::kStatic);
|
||||
} else if (H.IsMethod(target)) {
|
||||
return Constant(constant_evaluator_.EvaluateExpression(offset));
|
||||
} else {
|
||||
@@ -5566,7 +5583,7 @@ Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) {
|
||||
// Invoke the setter function.
|
||||
const Function& function =
|
||||
Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
|
||||
instructions += StaticCall(position, function, 1);
|
||||
instructions += StaticCall(position, function, 1, ICData::kStatic);
|
||||
|
||||
// Drop the unused result & leave the stored value on the stack.
|
||||
return instructions + Drop();
|
||||
@@ -5721,7 +5738,8 @@ Fragment StreamingFlowGraphBuilder::BuildDirectMethodInvocation(
|
||||
BuildArguments(&argument_names, &argument_count); // read arguments.
|
||||
++argument_count;
|
||||
return instructions + StaticCall(TokenPosition::kNoSource, target,
|
||||
argument_count, argument_names);
|
||||
argument_count, argument_names,
|
||||
ICData::kNoRebind);
|
||||
}
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const,
|
||||
@@ -5799,8 +5817,8 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const,
|
||||
ASSERT(argument_count == 2);
|
||||
instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true);
|
||||
} else {
|
||||
instructions +=
|
||||
StaticCall(position, target, argument_count, argument_names);
|
||||
instructions += StaticCall(position, target, argument_count, argument_names,
|
||||
ICData::kStatic);
|
||||
if (target.IsGenerativeConstructor()) {
|
||||
// Drop the result of the constructor call and leave [instance_variable]
|
||||
// on top-of-stack.
|
||||
@@ -5897,7 +5915,8 @@ Fragment StreamingFlowGraphBuilder::BuildConstructorInvocation(
|
||||
const Function& target = Function::ZoneHandle(
|
||||
Z, H.LookupConstructorByKernelConstructor(klass, kernel_name));
|
||||
++argument_count;
|
||||
instructions += StaticCall(position, target, argument_count, argument_names);
|
||||
instructions += StaticCall(position, target, argument_count, argument_names,
|
||||
ICData::kStatic);
|
||||
return instructions + Drop();
|
||||
}
|
||||
|
||||
@@ -6261,7 +6280,8 @@ Fragment StreamingFlowGraphBuilder::BuildListLiteral(bool is_const,
|
||||
Z, factory_class.LookupFactory(
|
||||
Library::PrivateCoreLibName(Symbols::ListLiteralFactory())));
|
||||
|
||||
return instructions + StaticCall(position, factory_method, 2);
|
||||
return instructions +
|
||||
StaticCall(position, factory_method, 2, ICData::kStatic);
|
||||
}
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::BuildMapLiteral(bool is_const,
|
||||
@@ -6321,7 +6341,8 @@ Fragment StreamingFlowGraphBuilder::BuildMapLiteral(bool is_const,
|
||||
Z, map_class.LookupFactory(
|
||||
Library::PrivateCoreLibName(Symbols::MapLiteralFactory())));
|
||||
|
||||
return instructions + StaticCall(position, factory_method, 2);
|
||||
return instructions +
|
||||
StaticCall(position, factory_method, 2, ICData::kStatic);
|
||||
}
|
||||
|
||||
Fragment StreamingFlowGraphBuilder::BuildFunctionExpression() {
|
||||
@@ -6593,7 +6614,8 @@ Fragment StreamingFlowGraphBuilder::BuildAssertStatement() {
|
||||
}
|
||||
otherwise_fragment += PushArgument(); // message
|
||||
|
||||
otherwise_fragment += StaticCall(TokenPosition::kNoSource, target, 3);
|
||||
otherwise_fragment +=
|
||||
StaticCall(TokenPosition::kNoSource, target, 3, ICData::kStatic);
|
||||
otherwise_fragment += Drop();
|
||||
|
||||
return Fragment(instructions.entry, then);
|
||||
@@ -6900,7 +6922,8 @@ Fragment StreamingFlowGraphBuilder::BuildSwitchStatement() {
|
||||
body_fragment += NullConstant();
|
||||
body_fragment += PushArgument(); // line
|
||||
|
||||
body_fragment += StaticCall(TokenPosition::kNoSource, constructor, 3);
|
||||
body_fragment +=
|
||||
StaticCall(TokenPosition::kNoSource, constructor, 3, ICData::kStatic);
|
||||
body_fragment += Drop();
|
||||
|
||||
// Throw the exception
|
||||
|
||||
@@ -952,11 +952,13 @@ class StreamingFlowGraphBuilder {
|
||||
Fragment LoadStaticField();
|
||||
Fragment StaticCall(TokenPosition position,
|
||||
const Function& target,
|
||||
intptr_t argument_count);
|
||||
intptr_t argument_count,
|
||||
ICData::RebindRule rebind_rule);
|
||||
Fragment StaticCall(TokenPosition position,
|
||||
const Function& target,
|
||||
intptr_t argument_count,
|
||||
const Array& argument_names,
|
||||
ICData::RebindRule rebind_rule,
|
||||
intptr_t type_args_len = 0);
|
||||
Fragment InstanceCall(TokenPosition position,
|
||||
const String& name,
|
||||
|
||||
@@ -1239,7 +1239,8 @@ Fragment FlowGraphBuilder::Return(TokenPosition position) {
|
||||
const Function& target = Function::ZoneHandle(
|
||||
Z, I->object_store()->async_clear_thread_stack_trace());
|
||||
ASSERT(!target.IsNull());
|
||||
instructions += StaticCall(TokenPosition::kNoSource, target, 0);
|
||||
instructions += StaticCall(TokenPosition::kNoSource, target,
|
||||
/* argument_count = */ 0, ICData::kStatic);
|
||||
instructions += Drop();
|
||||
}
|
||||
|
||||
@@ -1254,8 +1255,10 @@ Fragment FlowGraphBuilder::Return(TokenPosition position) {
|
||||
|
||||
Fragment FlowGraphBuilder::StaticCall(TokenPosition position,
|
||||
const Function& target,
|
||||
intptr_t argument_count) {
|
||||
return StaticCall(position, target, argument_count, Array::null_array());
|
||||
intptr_t argument_count,
|
||||
ICData::RebindRule rebind_rule) {
|
||||
return StaticCall(position, target, argument_count, Array::null_array(),
|
||||
rebind_rule);
|
||||
}
|
||||
|
||||
static intptr_t GetResultCidOfListFactory(Zone* zone,
|
||||
@@ -1283,11 +1286,12 @@ Fragment FlowGraphBuilder::StaticCall(TokenPosition position,
|
||||
const Function& target,
|
||||
intptr_t argument_count,
|
||||
const Array& argument_names,
|
||||
ICData::RebindRule rebind_rule,
|
||||
intptr_t type_args_count) {
|
||||
ArgumentArray arguments = GetArguments(argument_count);
|
||||
StaticCallInstr* call =
|
||||
new (Z) StaticCallInstr(position, target, type_args_count, argument_names,
|
||||
arguments, ic_data_array_, GetNextDeoptId());
|
||||
StaticCallInstr* call = new (Z)
|
||||
StaticCallInstr(position, target, type_args_count, argument_names,
|
||||
arguments, ic_data_array_, GetNextDeoptId(), rebind_rule);
|
||||
const intptr_t list_cid =
|
||||
GetResultCidOfListFactory(Z, target, argument_count);
|
||||
if (list_cid != kDynamicCid) {
|
||||
@@ -1412,7 +1416,8 @@ Fragment FlowGraphBuilder::StringInterpolateSingle(TokenPosition position) {
|
||||
kTypeArgsLen, kNumberOfArguments, kNoArgumentNames));
|
||||
Fragment instructions;
|
||||
instructions += PushArgument();
|
||||
instructions += StaticCall(position, function, 1);
|
||||
instructions +=
|
||||
StaticCall(position, function, /* argument_count = */ 1, ICData::kStatic);
|
||||
return instructions;
|
||||
}
|
||||
|
||||
@@ -1451,7 +1456,8 @@ Fragment FlowGraphBuilder::ThrowTypeError() {
|
||||
instructions += Constant(H.DartSymbol("Malformed type."));
|
||||
instructions += PushArgument(); // message
|
||||
|
||||
instructions += StaticCall(TokenPosition::kNoSource, constructor, 5);
|
||||
instructions += StaticCall(TokenPosition::kNoSource, constructor,
|
||||
/* argument_count = */ 5, ICData::kStatic);
|
||||
instructions += Drop();
|
||||
|
||||
// Throw the exception
|
||||
@@ -1490,7 +1496,8 @@ Fragment FlowGraphBuilder::ThrowNoSuchMethodError() {
|
||||
instructions += NullConstant();
|
||||
instructions += PushArgument(); // existingArgumentNames
|
||||
|
||||
instructions += StaticCall(TokenPosition::kNoSource, throw_function, 6);
|
||||
instructions += StaticCall(TokenPosition::kNoSource, throw_function,
|
||||
/* argument_count = */ 6, ICData::kStatic);
|
||||
// Leave "result" on the stack since callers expect it to be there (even
|
||||
// though the function will result in an exception).
|
||||
|
||||
@@ -1858,7 +1865,8 @@ Fragment FlowGraphBuilder::EvaluateAssertion() {
|
||||
Function::ZoneHandle(Z, klass.LookupStaticFunctionAllowPrivate(
|
||||
H.DartSymbol("_evaluateAssertion")));
|
||||
ASSERT(!target.IsNull());
|
||||
return StaticCall(TokenPosition::kNoSource, target, 1);
|
||||
return StaticCall(TokenPosition::kNoSource, target, /* argument_count = */ 1,
|
||||
ICData::kStatic);
|
||||
}
|
||||
|
||||
Fragment FlowGraphBuilder::CheckReturnTypeInCheckedMode() {
|
||||
@@ -2037,7 +2045,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher(
|
||||
Z, mirror_class.LookupStaticFunction(
|
||||
Library::PrivateCoreLibName(Symbols::AllocateInvocationMirror())));
|
||||
ASSERT(!allocation_function.IsNull());
|
||||
body += StaticCall(TokenPosition::kMinSource, allocation_function, 4);
|
||||
body += StaticCall(TokenPosition::kMinSource, allocation_function,
|
||||
/* argument_count = */ 4, ICData::kStatic);
|
||||
body += PushArgument(); // For the call to noSuchMethod.
|
||||
|
||||
const int kTypeArgsLen = 0;
|
||||
@@ -2054,7 +2063,8 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher(
|
||||
Class::Handle(Z, I->object_store()->object_class()),
|
||||
Symbols::NoSuchMethod(), two_arguments);
|
||||
}
|
||||
body += StaticCall(TokenPosition::kMinSource, no_such_method, 2);
|
||||
body += StaticCall(TokenPosition::kMinSource, no_such_method,
|
||||
/* argument_count = */ 2, ICData::kNSMDispatch);
|
||||
body += Return(TokenPosition::kNoSource);
|
||||
|
||||
return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
|
||||
|
||||
@@ -560,11 +560,13 @@ class FlowGraphBuilder {
|
||||
Fragment Return(TokenPosition position);
|
||||
Fragment StaticCall(TokenPosition position,
|
||||
const Function& target,
|
||||
intptr_t argument_count);
|
||||
intptr_t argument_count,
|
||||
ICData::RebindRule rebind_rule);
|
||||
Fragment StaticCall(TokenPosition position,
|
||||
const Function& target,
|
||||
intptr_t argument_count,
|
||||
const Array& argument_names,
|
||||
ICData::RebindRule rebind_rule,
|
||||
intptr_t type_args_len = 0);
|
||||
Fragment StoreIndexed(intptr_t class_id);
|
||||
Fragment StoreInstanceFieldGuarded(const Field& field,
|
||||
|
||||
+13
-9
@@ -12877,13 +12877,17 @@ void ICData::AddDeoptReason(DeoptReasonId reason) const {
|
||||
}
|
||||
}
|
||||
|
||||
void ICData::SetIsStaticCall(bool static_call) const {
|
||||
ICData::RebindRule ICData::rebind_rule() const {
|
||||
return (ICData::RebindRule)RebindRuleBits::decode(raw_ptr()->state_bits_);
|
||||
}
|
||||
|
||||
void ICData::set_rebind_rule(uint32_t rebind_rule) const {
|
||||
StoreNonPointer(&raw_ptr()->state_bits_,
|
||||
StaticCallBit::update(static_call, raw_ptr()->state_bits_));
|
||||
RebindRuleBits::update(rebind_rule, raw_ptr()->state_bits_));
|
||||
}
|
||||
|
||||
bool ICData::is_static_call() const {
|
||||
return StaticCallBit::decode(raw_ptr()->state_bits_);
|
||||
return rebind_rule() != kInstance;
|
||||
}
|
||||
|
||||
void ICData::set_state_bits(uint32_t bits) const {
|
||||
@@ -13673,7 +13677,7 @@ RawICData* ICData::NewDescriptor(Zone* zone,
|
||||
const Array& arguments_descriptor,
|
||||
intptr_t deopt_id,
|
||||
intptr_t num_args_tested,
|
||||
bool is_static_call) {
|
||||
RebindRule rebind_rule) {
|
||||
ASSERT(!owner.IsNull());
|
||||
ASSERT(!target_name.IsNull());
|
||||
ASSERT(!arguments_descriptor.IsNull());
|
||||
@@ -13695,7 +13699,7 @@ RawICData* ICData::NewDescriptor(Zone* zone,
|
||||
#if defined(TAG_IC_DATA)
|
||||
result.set_tag(-1);
|
||||
#endif
|
||||
result.SetIsStaticCall(is_static_call);
|
||||
result.set_rebind_rule(rebind_rule);
|
||||
result.SetNumArgsTested(num_args_tested);
|
||||
return result.raw();
|
||||
}
|
||||
@@ -13727,11 +13731,11 @@ RawICData* ICData::New(const Function& owner,
|
||||
const Array& arguments_descriptor,
|
||||
intptr_t deopt_id,
|
||||
intptr_t num_args_tested,
|
||||
bool is_static_call) {
|
||||
RebindRule rebind_rule) {
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
const ICData& result = ICData::Handle(
|
||||
zone, NewDescriptor(zone, owner, target_name, arguments_descriptor,
|
||||
deopt_id, num_args_tested, is_static_call));
|
||||
deopt_id, num_args_tested, rebind_rule));
|
||||
result.set_ic_data_array(
|
||||
Array::Handle(zone, CachedEmptyICDataArray(num_args_tested)));
|
||||
return result.raw();
|
||||
@@ -13741,7 +13745,7 @@ RawICData* ICData::NewFrom(const ICData& from, intptr_t num_args_tested) {
|
||||
const ICData& result = ICData::Handle(ICData::New(
|
||||
Function::Handle(from.Owner()), String::Handle(from.target_name()),
|
||||
Array::Handle(from.arguments_descriptor()), from.deopt_id(),
|
||||
num_args_tested, from.is_static_call()));
|
||||
num_args_tested, from.rebind_rule()));
|
||||
// Copy deoptimization reasons.
|
||||
result.SetDeoptReasons(from.DeoptReasons());
|
||||
return result.raw();
|
||||
@@ -13753,7 +13757,7 @@ RawICData* ICData::Clone(const ICData& from) {
|
||||
zone, Function::Handle(zone, from.Owner()),
|
||||
String::Handle(zone, from.target_name()),
|
||||
Array::Handle(zone, from.arguments_descriptor()), from.deopt_id(),
|
||||
from.NumArgsTested(), from.is_static_call()));
|
||||
from.NumArgsTested(), from.rebind_rule()));
|
||||
// Clone entry array.
|
||||
const Array& from_array = Array::Handle(zone, from.ic_data());
|
||||
const intptr_t len = from_array.Length();
|
||||
|
||||
+24
-9
@@ -1748,6 +1748,20 @@ class ICData : public Object {
|
||||
bool HasDeoptReason(ICData::DeoptReasonId reason) const;
|
||||
void AddDeoptReason(ICData::DeoptReasonId reason) const;
|
||||
|
||||
// Call site classification that is helpful for hot-reload. Call sites with
|
||||
// different `RebindRule` have to be rebound differently.
|
||||
enum RebindRule {
|
||||
kInstance,
|
||||
kNoRebind,
|
||||
kNSMDispatch,
|
||||
kOptimized,
|
||||
kStatic,
|
||||
kSuper,
|
||||
kNumRebindRules,
|
||||
};
|
||||
RebindRule rebind_rule() const;
|
||||
void set_rebind_rule(uint32_t rebind_rule) const;
|
||||
|
||||
// The length of the array. This includes all sentinel entries including
|
||||
// the final one.
|
||||
intptr_t Length() const;
|
||||
@@ -1887,7 +1901,7 @@ class ICData : public Object {
|
||||
const Array& arguments_descriptor,
|
||||
intptr_t deopt_id,
|
||||
intptr_t num_args_tested,
|
||||
bool is_static_call);
|
||||
RebindRule rebind_rule);
|
||||
static RawICData* NewFrom(const ICData& from, intptr_t num_args_tested);
|
||||
|
||||
// Generates a new ICData with descriptor and data array copied (deep clone).
|
||||
@@ -1921,7 +1935,6 @@ class ICData : public Object {
|
||||
intptr_t tag() const { return raw_ptr()->tag_; }
|
||||
#endif
|
||||
|
||||
void SetIsStaticCall(bool static_call) const;
|
||||
bool is_static_call() const;
|
||||
|
||||
private:
|
||||
@@ -1944,10 +1957,12 @@ class ICData : public Object {
|
||||
kNumArgsTestedSize = 2,
|
||||
kDeoptReasonPos = kNumArgsTestedPos + kNumArgsTestedSize,
|
||||
kDeoptReasonSize = kLastRecordedDeoptReason + 1,
|
||||
kStaticCallPos = kDeoptReasonPos + kDeoptReasonSize,
|
||||
kStaticCallSize = 1,
|
||||
kRebindRulePos = kDeoptReasonPos + kDeoptReasonSize,
|
||||
kRebindRuleSize = 3
|
||||
};
|
||||
|
||||
COMPILE_ASSERT(kNumRebindRules <= (1 << kRebindRuleSize));
|
||||
|
||||
class NumArgsTestedBits : public BitField<uint32_t,
|
||||
uint32_t,
|
||||
kNumArgsTestedPos,
|
||||
@@ -1956,10 +1971,10 @@ class ICData : public Object {
|
||||
uint32_t,
|
||||
ICData::kDeoptReasonPos,
|
||||
ICData::kDeoptReasonSize> {};
|
||||
class StaticCallBit : public BitField<uint32_t,
|
||||
bool,
|
||||
ICData::kStaticCallPos,
|
||||
ICData::kStaticCallSize> {};
|
||||
class RebindRuleBits : public BitField<uint32_t,
|
||||
uint32_t,
|
||||
ICData::kRebindRulePos,
|
||||
ICData::kRebindRuleSize> {};
|
||||
#if defined(DEBUG)
|
||||
// Used in asserts to verify that a check is not added twice.
|
||||
bool HasCheck(const GrowableArray<intptr_t>& cids) const;
|
||||
@@ -1974,7 +1989,7 @@ class ICData : public Object {
|
||||
const Array& arguments_descriptor,
|
||||
intptr_t deopt_id,
|
||||
intptr_t num_args_tested,
|
||||
bool is_static_call);
|
||||
RebindRule rebind_rule);
|
||||
|
||||
static void WriteSentinel(const Array& data, intptr_t test_entry_length);
|
||||
|
||||
|
||||
+26
-38
@@ -687,7 +687,22 @@ void Library::CheckReload(const Library& replacement,
|
||||
static const Function* static_call_target = NULL;
|
||||
|
||||
void ICData::Reset(Zone* zone) const {
|
||||
if (is_static_call()) {
|
||||
RebindRule rule = rebind_rule();
|
||||
if (rule == kInstance) {
|
||||
intptr_t num_args = NumArgsTested();
|
||||
if (num_args == 2) {
|
||||
ClearWithSentinel();
|
||||
} else {
|
||||
const Array& data_array =
|
||||
Array::Handle(zone, CachedEmptyICDataArray(num_args));
|
||||
set_ic_data_array(data_array);
|
||||
}
|
||||
return;
|
||||
} else if (rule == kNoRebind || rule == kNSMDispatch) {
|
||||
// TODO(30877) we should account for addition/removal of NSM.
|
||||
// Don't rebind dispatchers.
|
||||
return;
|
||||
} else if (rule == kStatic || rule == kSuper) {
|
||||
const Function& old_target = Function::Handle(zone, GetTargetAt(0));
|
||||
if (old_target.IsNull()) {
|
||||
FATAL("old_target is NULL.\n");
|
||||
@@ -696,34 +711,19 @@ void ICData::Reset(Zone* zone) const {
|
||||
|
||||
const String& selector = String::Handle(zone, old_target.name());
|
||||
Function& new_target = Function::Handle(zone);
|
||||
if (!old_target.is_static()) {
|
||||
if (old_target.kind() == RawFunction::kConstructor) {
|
||||
return; // Super constructor call.
|
||||
}
|
||||
|
||||
if (rule == kStatic) {
|
||||
ASSERT(old_target.is_static() ||
|
||||
old_target.kind() == RawFunction::kConstructor);
|
||||
// This can be incorrect if the call site was an unqualified invocation.
|
||||
const Class& cls = Class::Handle(zone, old_target.Owner());
|
||||
new_target = cls.LookupStaticFunction(selector);
|
||||
} else {
|
||||
// Super call.
|
||||
Function& caller = Function::Handle(zone);
|
||||
caller ^= Owner();
|
||||
ASSERT(!caller.is_static());
|
||||
Class& cls = Class::Handle(zone, caller.Owner());
|
||||
if (cls.raw() == old_target.Owner()) {
|
||||
// Dispatcher.
|
||||
if (caller.IsImplicitClosureFunction()) {
|
||||
return; // Tear-off.
|
||||
}
|
||||
if (caller.kind() == RawFunction::kNoSuchMethodDispatcher) {
|
||||
// TODO(rmacnak): noSuchMethod might have been redefined.
|
||||
return;
|
||||
}
|
||||
const Function& caller_parent =
|
||||
Function::Handle(zone, caller.parent_function());
|
||||
if (!caller_parent.IsNull()) {
|
||||
if (caller_parent.kind() == RawFunction::kInvokeFieldDispatcher) {
|
||||
return; // Call-through-getter.
|
||||
}
|
||||
}
|
||||
FATAL2("Unexpected dispatcher-like call site: %s from %s\n",
|
||||
selector.ToCString(), caller.ToQualifiedCString());
|
||||
}
|
||||
// Super call.
|
||||
cls = cls.SuperClass();
|
||||
while (!cls.IsNull()) {
|
||||
// TODO(rmacnak): Should use Resolver::ResolveDynamicAnyArgs to handle
|
||||
@@ -735,12 +735,7 @@ void ICData::Reset(Zone* zone) const {
|
||||
}
|
||||
cls = cls.SuperClass();
|
||||
}
|
||||
} else {
|
||||
// This can be incorrect if the call site was an unqualified invocation.
|
||||
const Class& cls = Class::Handle(zone, old_target.Owner());
|
||||
new_target = cls.LookupStaticFunction(selector);
|
||||
}
|
||||
|
||||
const Array& args_desc_array = Array::Handle(zone, arguments_descriptor());
|
||||
ArgumentsDescriptor args_desc(args_desc_array);
|
||||
if (new_target.IsNull() || !new_target.AreValidArguments(args_desc, NULL)) {
|
||||
@@ -752,14 +747,7 @@ void ICData::Reset(Zone* zone) const {
|
||||
}
|
||||
ClearAndSetStaticTarget(new_target);
|
||||
} else {
|
||||
intptr_t num_args = NumArgsTested();
|
||||
if (num_args == 2) {
|
||||
ClearWithSentinel();
|
||||
} else {
|
||||
const Array& data_array =
|
||||
Array::Handle(zone, CachedEmptyICDataArray(num_args));
|
||||
set_ic_data_array(data_array);
|
||||
}
|
||||
FATAL("Unexpected rebind rule.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2987,7 +2987,7 @@ ISOLATE_UNIT_TEST_CASE(ICData) {
|
||||
ArgumentsDescriptor::New(kTypeArgsLen, kNumArgs, Object::null_array()));
|
||||
ICData& o1 = ICData::Handle();
|
||||
o1 = ICData::New(function, target_name, args_descriptor, id, num_args_tested,
|
||||
false);
|
||||
ICData::kInstance);
|
||||
EXPECT_EQ(1, o1.NumArgsTested());
|
||||
EXPECT_EQ(id, o1.deopt_id());
|
||||
EXPECT_EQ(function.raw(), o1.Owner());
|
||||
@@ -3026,7 +3026,8 @@ ISOLATE_UNIT_TEST_CASE(ICData) {
|
||||
EXPECT_EQ(2, o1.NumberOfUsedChecks());
|
||||
|
||||
ICData& o2 = ICData::Handle();
|
||||
o2 = ICData::New(function, target_name, args_descriptor, 57, 2, false);
|
||||
o2 = ICData::New(function, target_name, args_descriptor, 57, 2,
|
||||
ICData::kInstance);
|
||||
EXPECT_EQ(2, o2.NumArgsTested());
|
||||
EXPECT_EQ(57, o2.deopt_id());
|
||||
EXPECT_EQ(function.raw(), o2.Owner());
|
||||
@@ -3044,8 +3045,9 @@ ISOLATE_UNIT_TEST_CASE(ICData) {
|
||||
|
||||
// Check ICData for unoptimized static calls.
|
||||
const intptr_t kNumArgsChecked = 0;
|
||||
const ICData& scall_icdata = ICData::Handle(ICData::New(
|
||||
function, target_name, args_descriptor, 57, kNumArgsChecked, false));
|
||||
const ICData& scall_icdata =
|
||||
ICData::Handle(ICData::New(function, target_name, args_descriptor, 57,
|
||||
kNumArgsChecked, ICData::kInstance));
|
||||
scall_icdata.AddTarget(target1);
|
||||
EXPECT_EQ(target1.raw(), scall_icdata.GetTargetAt(0));
|
||||
}
|
||||
|
||||
+46
-31
@@ -1626,7 +1626,8 @@ SequenceNode* Parser::ParseImplicitClosure(const Function& func) {
|
||||
// receiver.
|
||||
if (!target.IsNull() &&
|
||||
(parent.num_fixed_parameters() == target.num_fixed_parameters())) {
|
||||
call = new StaticCallNode(token_pos, target, func_args);
|
||||
call = new StaticCallNode(token_pos, target, func_args,
|
||||
StaticCallNode::kStatic);
|
||||
} else if (!parent.is_static()) {
|
||||
NOT_IN_PRODUCT(ASSERT(Isolate::Current()->HasAttemptedReload()));
|
||||
// If a subsequent reload reintroduces the target in the middle of the
|
||||
@@ -1649,7 +1650,8 @@ SequenceNode* Parser::ParseImplicitClosure(const Function& func) {
|
||||
Class::Handle(Z, I->object_store()->object_class()),
|
||||
Symbols::NoSuchMethod(), args_desc);
|
||||
}
|
||||
call = new StaticCallNode(token_pos, no_such_method, arguments);
|
||||
call = new StaticCallNode(token_pos, no_such_method, arguments,
|
||||
StaticCallNode::kStatic);
|
||||
} else {
|
||||
NOT_IN_PRODUCT(ASSERT(Isolate::Current()->HasAttemptedReload()));
|
||||
// If a subsequent reload reintroduces the target in the middle of the
|
||||
@@ -1804,8 +1806,8 @@ SequenceNode* Parser::ParseNoSuchMethodDispatcher(const Function& func) {
|
||||
Class::Handle(Z, I->object_store()->object_class()),
|
||||
Symbols::NoSuchMethod(), args_desc);
|
||||
}
|
||||
StaticCallNode* call =
|
||||
new StaticCallNode(token_pos, no_such_method, arguments);
|
||||
StaticCallNode* call = new StaticCallNode(
|
||||
token_pos, no_such_method, arguments, StaticCallNode::kNSMDispatch);
|
||||
|
||||
ReturnNode* return_node = new ReturnNode(token_pos, call);
|
||||
current_block_->statements->Add(return_node);
|
||||
@@ -2452,7 +2454,8 @@ StaticCallNode* Parser::BuildInvocationMirrorAllocation(
|
||||
Function::ZoneHandle(mirror_class.LookupStaticFunction(
|
||||
Library::PrivateCoreLibName(Symbols::AllocateInvocationMirror())));
|
||||
ASSERT(!allocation_function.IsNull());
|
||||
return new StaticCallNode(call_pos, allocation_function, arguments);
|
||||
return new StaticCallNode(call_pos, allocation_function, arguments,
|
||||
StaticCallNode::kStatic);
|
||||
}
|
||||
|
||||
ArgumentListNode* Parser::BuildNoSuchMethodArguments(
|
||||
@@ -2508,7 +2511,8 @@ AstNode* Parser::ParseSuperCall(const String& function_name,
|
||||
arguments = BuildNoSuchMethodArguments(supercall_pos, function_name,
|
||||
*arguments, NULL, true);
|
||||
}
|
||||
return new StaticCallNode(supercall_pos, super_function, arguments);
|
||||
return new StaticCallNode(supercall_pos, super_function, arguments,
|
||||
StaticCallNode::kSuper);
|
||||
}
|
||||
|
||||
// Simple test if a node is side effect free.
|
||||
@@ -2535,7 +2539,8 @@ AstNode* Parser::BuildUnarySuperOperator(Token::Kind op, PrimaryNode* super) {
|
||||
op_arguments = BuildNoSuchMethodArguments(
|
||||
super_pos, operator_function_name, *op_arguments, NULL, true);
|
||||
}
|
||||
super_op = new StaticCallNode(super_pos, super_operator, op_arguments);
|
||||
super_op = new StaticCallNode(super_pos, super_operator, op_arguments,
|
||||
StaticCallNode::kSuper);
|
||||
} else {
|
||||
ReportError(super_pos, "illegal super operator call");
|
||||
}
|
||||
@@ -2588,7 +2593,8 @@ AstNode* Parser::ParseSuperOperator() {
|
||||
op_arguments = BuildNoSuchMethodArguments(
|
||||
operator_pos, operator_function_name, *op_arguments, NULL, true);
|
||||
}
|
||||
super_op = new StaticCallNode(operator_pos, super_operator, op_arguments);
|
||||
super_op = new StaticCallNode(operator_pos, super_operator, op_arguments,
|
||||
StaticCallNode::kSuper);
|
||||
if (negate_result) {
|
||||
super_op = new UnaryOpNode(operator_pos, Token::kNOT, super_op);
|
||||
}
|
||||
@@ -2715,7 +2721,8 @@ StaticCallNode* Parser::GenerateSuperConstructorCall(
|
||||
String::Handle(Z, super_class.Name()).ToCString(),
|
||||
error_message.ToCString());
|
||||
}
|
||||
return new StaticCallNode(supercall_pos, super_ctor, arguments);
|
||||
return new StaticCallNode(supercall_pos, super_ctor, arguments,
|
||||
StaticCallNode::kSuper);
|
||||
}
|
||||
|
||||
StaticCallNode* Parser::ParseSuperInitializer(const Class& cls,
|
||||
@@ -2769,7 +2776,8 @@ StaticCallNode* Parser::ParseSuperInitializer(const Class& cls,
|
||||
"invalid arguments passed to super class constructor '%s': %s",
|
||||
ctor_name.ToCString(), error_message.ToCString());
|
||||
}
|
||||
return new StaticCallNode(supercall_pos, super_ctor, arguments);
|
||||
return new StaticCallNode(supercall_pos, super_ctor, arguments,
|
||||
StaticCallNode::kSuper);
|
||||
}
|
||||
|
||||
AstNode* Parser::ParseInitializer(const Class& cls,
|
||||
@@ -3163,8 +3171,8 @@ void Parser::ParseConstructorRedirection(const Class& cls,
|
||||
String::Handle(Z, redirect_ctor.UserVisibleName()).ToCString(),
|
||||
error_message.ToCString());
|
||||
}
|
||||
current_block_->statements->Add(
|
||||
new StaticCallNode(call_pos, redirect_ctor, arguments));
|
||||
current_block_->statements->Add(new StaticCallNode(
|
||||
call_pos, redirect_ctor, arguments, StaticCallNode::kStatic));
|
||||
}
|
||||
|
||||
SequenceNode* Parser::MakeImplicitConstructor(const Function& func) {
|
||||
@@ -7371,8 +7379,9 @@ SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func,
|
||||
new (Z) ArgumentListNode(TokenPosition::kNoSource);
|
||||
async_stack_trace_helper_args->Add(
|
||||
new (Z) LoadLocalNode(TokenPosition::kNoSource, async_op_var));
|
||||
StaticCallNode* async_stack_trace_helper_call = new (Z) StaticCallNode(
|
||||
token_pos, async_stack_trace_helper, async_stack_trace_helper_args);
|
||||
StaticCallNode* async_stack_trace_helper_call = new (Z)
|
||||
StaticCallNode(token_pos, async_stack_trace_helper,
|
||||
async_stack_trace_helper_args, StaticCallNode::kStatic);
|
||||
LocalVariable* async_stack_trace_var =
|
||||
current_block_->scope->LookupVariable(Symbols::AsyncStackTraceVar(),
|
||||
false);
|
||||
@@ -7392,7 +7401,7 @@ SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func,
|
||||
new (Z) LoadLocalNode(TokenPosition::kNoSource, async_op_var));
|
||||
StaticCallNode* then_wrapper_call = new (Z)
|
||||
StaticCallNode(TokenPosition::kNoSource, async_then_wrapper_helper,
|
||||
async_then_wrapper_helper_args);
|
||||
async_then_wrapper_helper_args, StaticCallNode::kStatic);
|
||||
LocalVariable* async_then_callback_var =
|
||||
current_block_->scope->LookupVariable(Symbols::AsyncThenCallback(),
|
||||
false);
|
||||
@@ -7413,7 +7422,7 @@ SequenceNode* Parser::CloseAsyncGeneratorFunction(const Function& closure_func,
|
||||
new (Z) LoadLocalNode(TokenPosition::kNoSource, async_op_var));
|
||||
StaticCallNode* error_wrapper_call = new (Z)
|
||||
StaticCallNode(TokenPosition::kNoSource, async_error_wrapper_helper,
|
||||
async_error_wrapper_helper_args);
|
||||
async_error_wrapper_helper_args, StaticCallNode::kStatic);
|
||||
LocalVariable* async_catch_error_callback_var =
|
||||
current_block_->scope->LookupVariable(Symbols::AsyncCatchErrorCallback(),
|
||||
false);
|
||||
@@ -7590,8 +7599,9 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
|
||||
new (Z) ArgumentListNode(token_pos);
|
||||
async_stack_trace_helper_args->Add(
|
||||
new (Z) LoadLocalNode(token_pos, async_op_var));
|
||||
StaticCallNode* async_stack_trace_helper_call = new (Z) StaticCallNode(
|
||||
token_pos, async_stack_trace_helper, async_stack_trace_helper_args);
|
||||
StaticCallNode* async_stack_trace_helper_call = new (Z)
|
||||
StaticCallNode(token_pos, async_stack_trace_helper,
|
||||
async_stack_trace_helper_args, StaticCallNode::kStatic);
|
||||
LocalVariable* async_stack_trace_var =
|
||||
current_block_->scope->LookupVariable(Symbols::AsyncStackTraceVar(),
|
||||
false);
|
||||
@@ -7609,8 +7619,9 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
|
||||
new (Z) ArgumentListNode(token_pos);
|
||||
async_then_wrapper_helper_args->Add(
|
||||
new (Z) LoadLocalNode(token_pos, async_op_var));
|
||||
StaticCallNode* then_wrapper_call = new (Z) StaticCallNode(
|
||||
token_pos, async_then_wrapper_helper, async_then_wrapper_helper_args);
|
||||
StaticCallNode* then_wrapper_call = new (Z)
|
||||
StaticCallNode(token_pos, async_then_wrapper_helper,
|
||||
async_then_wrapper_helper_args, StaticCallNode::kStatic);
|
||||
LocalVariable* async_then_callback_var =
|
||||
current_block_->scope->LookupVariable(Symbols::AsyncThenCallback(),
|
||||
false);
|
||||
@@ -7629,8 +7640,9 @@ SequenceNode* Parser::CloseAsyncFunction(const Function& closure,
|
||||
new (Z) ArgumentListNode(token_pos);
|
||||
async_error_wrapper_helper_args->Add(
|
||||
new (Z) LoadLocalNode(token_pos, async_op_var));
|
||||
StaticCallNode* error_wrapper_call = new (Z) StaticCallNode(
|
||||
token_pos, async_error_wrapper_helper, async_error_wrapper_helper_args);
|
||||
StaticCallNode* error_wrapper_call = new (Z)
|
||||
StaticCallNode(token_pos, async_error_wrapper_helper,
|
||||
async_error_wrapper_helper_args, StaticCallNode::kStatic);
|
||||
LocalVariable* async_catch_error_callback_var =
|
||||
current_block_->scope->LookupVariable(Symbols::AsyncCatchErrorCallback(),
|
||||
false);
|
||||
@@ -9110,8 +9122,8 @@ AstNode* Parser::DartPrint(const char* str) {
|
||||
new (Z) ArgumentListNode(TokenPosition::kNoSource);
|
||||
String& msg = String::ZoneHandle(Symbols::NewFormatted(T, "%s", str));
|
||||
one_arg->Add(new (Z) LiteralNode(TokenPosition::kNoSource, msg));
|
||||
AstNode* print_call =
|
||||
new (Z) StaticCallNode(TokenPosition::kNoSource, print_fn, one_arg);
|
||||
AstNode* print_call = new (Z) StaticCallNode(
|
||||
TokenPosition::kNoSource, print_fn, one_arg, StaticCallNode::kStatic);
|
||||
return print_call;
|
||||
}
|
||||
|
||||
@@ -9193,8 +9205,9 @@ AstNode* Parser::ParseAwaitForStatement(String* label_name) {
|
||||
new (Z) LoadLocalNode(stream_expr_pos, stream_var));
|
||||
async_star_listen_helper_args->Add(
|
||||
new (Z) LoadLocalNode(stream_expr_pos, async_op_var));
|
||||
StaticCallNode* async_star_listen_helper_call = new (Z) StaticCallNode(
|
||||
stream_expr_pos, async_star_listen_helper, async_star_listen_helper_args);
|
||||
StaticCallNode* async_star_listen_helper_call = new (Z)
|
||||
StaticCallNode(stream_expr_pos, async_star_listen_helper,
|
||||
async_star_listen_helper_args, StaticCallNode::kStatic);
|
||||
|
||||
current_block_->statements->Add(async_star_listen_helper_call);
|
||||
|
||||
@@ -9264,9 +9277,9 @@ AstNode* Parser::ParseAwaitForStatement(String* label_name) {
|
||||
new (Z) ArgumentListNode(stream_expr_pos);
|
||||
async_star_move_next_helper_args->Add(
|
||||
new (Z) LoadLocalNode(stream_expr_pos, stream_var));
|
||||
StaticCallNode* async_star_move_next_helper_call =
|
||||
new (Z) StaticCallNode(stream_expr_pos, async_star_move_next_helper,
|
||||
async_star_move_next_helper_args);
|
||||
StaticCallNode* async_star_move_next_helper_call = new (Z)
|
||||
StaticCallNode(stream_expr_pos, async_star_move_next_helper,
|
||||
async_star_move_next_helper_args, StaticCallNode::kStatic);
|
||||
current_block_->statements->Add(async_star_move_next_helper_call);
|
||||
#endif
|
||||
AstNode* await_moveNext = new (Z) AwaitNode(
|
||||
@@ -9626,7 +9639,8 @@ AstNode* Parser::MakeStaticCall(const String& cls_name,
|
||||
Z, Resolver::ResolveStatic(cls, func_name, kTypeArgsLen,
|
||||
arguments->length(), arguments->names()));
|
||||
ASSERT(!func.IsNull());
|
||||
return new (Z) StaticCallNode(arguments->token_pos(), func, arguments);
|
||||
return new (Z) StaticCallNode(arguments->token_pos(), func, arguments,
|
||||
StaticCallNode::kStatic);
|
||||
}
|
||||
|
||||
AstNode* Parser::ParseAssertStatement(bool is_const) {
|
||||
@@ -11682,7 +11696,8 @@ AstNode* Parser::ParseStaticCall(const Class& cls,
|
||||
return new (Z) ComparisonNode(ident_pos, Token::kEQ_STRICT,
|
||||
arguments->NodeAt(0), arguments->NodeAt(1));
|
||||
}
|
||||
return new (Z) StaticCallNode(ident_pos, func, arguments);
|
||||
return new (Z)
|
||||
StaticCallNode(ident_pos, func, arguments, StaticCallNode::kStatic);
|
||||
}
|
||||
|
||||
AstNode* Parser::ParseInstanceCall(AstNode* receiver,
|
||||
|
||||
@@ -443,41 +443,45 @@ ComparisonInstr* IRRegExpMacroAssembler::Comparison(ComparisonKind kind,
|
||||
}
|
||||
|
||||
StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
|
||||
const Function& function) const {
|
||||
const Function& function,
|
||||
ICData::RebindRule rebind_rule) const {
|
||||
ZoneGrowableArray<PushArgumentInstr*>* arguments =
|
||||
new (Z) ZoneGrowableArray<PushArgumentInstr*>(0);
|
||||
return StaticCall(function, arguments);
|
||||
}
|
||||
|
||||
StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
|
||||
const Function& function,
|
||||
PushArgumentInstr* arg1) const {
|
||||
ZoneGrowableArray<PushArgumentInstr*>* arguments =
|
||||
new (Z) ZoneGrowableArray<PushArgumentInstr*>(1);
|
||||
arguments->Add(arg1);
|
||||
|
||||
return StaticCall(function, arguments);
|
||||
return StaticCall(function, arguments, rebind_rule);
|
||||
}
|
||||
|
||||
StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
|
||||
const Function& function,
|
||||
PushArgumentInstr* arg1,
|
||||
PushArgumentInstr* arg2) const {
|
||||
ICData::RebindRule rebind_rule) const {
|
||||
ZoneGrowableArray<PushArgumentInstr*>* arguments =
|
||||
new (Z) ZoneGrowableArray<PushArgumentInstr*>(1);
|
||||
arguments->Add(arg1);
|
||||
|
||||
return StaticCall(function, arguments, rebind_rule);
|
||||
}
|
||||
|
||||
StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
|
||||
const Function& function,
|
||||
PushArgumentInstr* arg1,
|
||||
PushArgumentInstr* arg2,
|
||||
ICData::RebindRule rebind_rule) const {
|
||||
ZoneGrowableArray<PushArgumentInstr*>* arguments =
|
||||
new (Z) ZoneGrowableArray<PushArgumentInstr*>(2);
|
||||
arguments->Add(arg1);
|
||||
arguments->Add(arg2);
|
||||
|
||||
return StaticCall(function, arguments);
|
||||
return StaticCall(function, arguments, rebind_rule);
|
||||
}
|
||||
|
||||
StaticCallInstr* IRRegExpMacroAssembler::StaticCall(
|
||||
const Function& function,
|
||||
ZoneGrowableArray<PushArgumentInstr*>* arguments) const {
|
||||
ZoneGrowableArray<PushArgumentInstr*>* arguments,
|
||||
ICData::RebindRule rebind_rule) const {
|
||||
const intptr_t kTypeArgsLen = 0;
|
||||
return new (Z) StaticCallInstr(TokenPosition::kNoSource, function,
|
||||
kTypeArgsLen, Object::null_array(), arguments,
|
||||
ic_data_array_, GetNextDeoptId());
|
||||
ic_data_array_, GetNextDeoptId(), rebind_rule);
|
||||
}
|
||||
|
||||
InstanceCallInstr* IRRegExpMacroAssembler::InstanceCall(
|
||||
@@ -640,7 +644,7 @@ void IRRegExpMacroAssembler::Print(PushArgumentInstr* argument) {
|
||||
const Library& lib = Library::Handle(Library::CoreLibrary());
|
||||
const Function& print_fn =
|
||||
Function::ZoneHandle(Z, lib.LookupFunctionAllowPrivate(Symbols::print()));
|
||||
Do(StaticCall(print_fn, argument));
|
||||
Do(StaticCall(print_fn, argument, ICData::kStatic));
|
||||
}
|
||||
|
||||
void IRRegExpMacroAssembler::PrintBlocks() {
|
||||
@@ -1469,7 +1473,8 @@ void IRRegExpMacroAssembler::GrowStack() {
|
||||
const Library& lib = Library::Handle(Library::InternalLibrary());
|
||||
const Function& grow_function = Function::ZoneHandle(
|
||||
Z, lib.LookupFunctionAllowPrivate(Symbols::GrowRegExpStack()));
|
||||
StoreLocal(stack_, Bind(StaticCall(grow_function, PushLocal(stack_))));
|
||||
StoreLocal(stack_, Bind(StaticCall(grow_function, PushLocal(stack_),
|
||||
ICData::kStatic)));
|
||||
|
||||
// Note: :stack and stack_array_cell content might diverge because each
|
||||
// instance of :matcher code has its own stack_array_cell embedded into it
|
||||
|
||||
@@ -243,15 +243,18 @@ class IRRegExpMacroAssembler : public RegExpMacroAssembler {
|
||||
const InstanceCallDescriptor& desc,
|
||||
ZoneGrowableArray<PushArgumentInstr*>* arguments) const;
|
||||
|
||||
StaticCallInstr* StaticCall(const Function& function) const;
|
||||
StaticCallInstr* StaticCall(const Function& function,
|
||||
PushArgumentInstr* arg1) const;
|
||||
ICData::RebindRule rebind_rule) const;
|
||||
StaticCallInstr* StaticCall(const Function& function,
|
||||
PushArgumentInstr* arg1,
|
||||
PushArgumentInstr* arg2) const;
|
||||
StaticCallInstr* StaticCall(
|
||||
const Function& function,
|
||||
ZoneGrowableArray<PushArgumentInstr*>* arguments) const;
|
||||
ICData::RebindRule rebind_rule) const;
|
||||
StaticCallInstr* StaticCall(const Function& function,
|
||||
PushArgumentInstr* arg1,
|
||||
PushArgumentInstr* arg2,
|
||||
ICData::RebindRule rebind_rule) const;
|
||||
StaticCallInstr* StaticCall(const Function& function,
|
||||
ZoneGrowableArray<PushArgumentInstr*>* arguments,
|
||||
ICData::RebindRule rebind_rule) const;
|
||||
|
||||
// Creates a new block consisting simply of a goto to dst.
|
||||
TargetEntryInstr* TargetWithJoinGoto(JoinEntryInstr* dst);
|
||||
|
||||
@@ -1133,7 +1133,7 @@ DEFINE_RUNTIME_ENTRY(SingleTargetMiss, 1) {
|
||||
const ICData& ic_data =
|
||||
ICData::Handle(zone, ICData::New(caller_function, name, descriptor,
|
||||
Thread::kNoDeoptId, 1, /* args_tested */
|
||||
false /* static_call */));
|
||||
ICData::kInstance));
|
||||
|
||||
// Maybe add the new target.
|
||||
Class& cls = Class::Handle(zone, receiver.clazz());
|
||||
@@ -1209,7 +1209,7 @@ DEFINE_RUNTIME_ENTRY(UnlinkedCall, 2) {
|
||||
const ICData& ic_data =
|
||||
ICData::Handle(zone, ICData::New(caller_function, name, descriptor,
|
||||
Thread::kNoDeoptId, 1, /* args_tested */
|
||||
false /* static_call */));
|
||||
ICData::kInstance));
|
||||
|
||||
Class& cls = Class::Handle(zone, receiver.clazz());
|
||||
ArgumentsDescriptor args_desc(descriptor);
|
||||
@@ -1289,7 +1289,7 @@ DEFINE_RUNTIME_ENTRY(MonomorphicMiss, 1) {
|
||||
const ICData& ic_data =
|
||||
ICData::Handle(zone, ICData::New(caller_function, name, descriptor,
|
||||
Thread::kNoDeoptId, 1, /* args_tested */
|
||||
false /* static_call */));
|
||||
ICData::kInstance));
|
||||
|
||||
// Add the first target.
|
||||
ic_data.AddReceiverCheck(old_expected_cid.Value(), old_target);
|
||||
|
||||
Reference in New Issue
Block a user