[VM] Make our NativeCallInstr work similar to all other call instructions

This CL makes NativeCallInstr instructions use PushArgument()s when
calling instead of directly using a pointer to the caller-provided
arguments (for functions without optional parameters) or relying on copy
arguments prologue (for functions with optional parameters).

Issue https://github.com/dart-lang/sdk/issues/31495

Change-Id: I36d4bf1b7dd10f48c7e40b0cafe37f8698aacb71
Reviewed-on: https://dart-review.googlesource.com/24961
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
This commit is contained in:
Martin Kustermann 2017-11-30 16:48:24 +00:00 committed by commit-bot@chromium.org
parent 83cabf36e3
commit 3c0422e6a6
8 changed files with 88 additions and 65 deletions

View file

@ -3516,27 +3516,28 @@ class StoreLocalInstr : public TemplateDefinition<1, NoThrow> {
DISALLOW_COPY_AND_ASSIGN(StoreLocalInstr);
};
class NativeCallInstr : public TemplateDefinition<0, Throws> {
class NativeCallInstr : public TemplateDartCall<0> {
public:
explicit NativeCallInstr(NativeBodyNode* node)
: native_name_(&node->native_c_function_name()),
function_(&node->function()),
native_c_function_(NULL),
is_bootstrap_native_(false),
link_lazily_(node->link_lazily()),
token_pos_(node->token_pos()) {}
NativeCallInstr(const String* name,
const Function* function,
bool link_lazily,
TokenPosition position)
: native_name_(name),
TokenPosition position,
ZoneGrowableArray<PushArgumentInstr*>* args)
: TemplateDartCall(Thread::kNoDeoptId,
0,
Array::null_array(),
args,
position),
native_name_(name),
function_(function),
native_c_function_(NULL),
is_bootstrap_native_(false),
is_auto_scope_(true),
link_lazily_(link_lazily),
token_pos_(position) {}
token_pos_(position) {
ASSERT(name->IsZoneHandle());
ASSERT(function->IsZoneHandle());
}
DECLARE_INSTRUCTION(NativeCall)

View file

@ -805,15 +805,15 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
SetupNative();
const Register result = locs()->out(0).reg();
// All arguments are already @SP due to preceding PushArgument()s.
ASSERT(ArgumentCount() == function().NumParameters());
// Push the result place holder initialized to NULL.
__ PushObject(Object::null_object());
// Pass a pointer to the first argument in R2.
if (!function().HasOptionalParameters()) {
__ AddImmediate(
R2, FP, (kParamEndSlotFromFp + function().NumParameters()) * kWordSize);
} else {
__ AddImmediate(R2, FP, kFirstLocalSlotFromFp * kWordSize);
}
__ add(R2, SP, Operand(ArgumentCount() * kWordSize));
// Compute the effective address. When running under the simulator,
// this is a redirection address that forces the simulator to call
// into the runtime system.
@ -854,6 +854,8 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
locs());
}
__ Pop(result);
__ Drop(ArgumentCount()); // Drop the arguments.
}
LocationSummary* OneByteStringFromCharCodeInstr::MakeLocationSummary(

View file

@ -664,15 +664,15 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
SetupNative();
const Register result = locs()->out(0).reg();
// All arguments are already @SP due to preceding PushArgument()s.
ASSERT(ArgumentCount() == function().NumParameters());
// Push the result place holder initialized to NULL.
__ PushObject(Object::null_object());
// Pass a pointer to the first argument in R2.
if (!function().HasOptionalParameters()) {
__ AddImmediate(
R2, FP, (kParamEndSlotFromFp + function().NumParameters()) * kWordSize);
} else {
__ AddImmediate(R2, FP, kFirstLocalSlotFromFp * kWordSize);
}
__ AddImmediate(R2, SP, ArgumentCount() * kWordSize);
// Compute the effective address. When running under the simulator,
// this is a redirection address that forces the simulator to call
// into the runtime system.
@ -713,6 +713,8 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
locs());
}
__ Pop(result);
__ Drop(ArgumentCount()); // Drop the arguments.
}
LocationSummary* OneByteStringFromCharCodeInstr::MakeLocationSummary(

View file

@ -737,16 +737,15 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register result = locs()->out(0).reg();
const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
// All arguments are already @ESP due to preceding PushArgument()s.
ASSERT(ArgumentCount() == function().NumParameters());
// Push the result place holder initialized to NULL.
__ PushObject(Object::null_object());
// Pass a pointer to the first argument in EAX.
if (!function().HasOptionalParameters()) {
__ leal(EAX,
Address(EBP, (kParamEndSlotFromFp + function().NumParameters()) *
kWordSize));
} else {
__ leal(EAX, Address(EBP, kFirstLocalSlotFromFp * kWordSize));
}
__ leal(EAX, Address(ESP, ArgumentCount() * kWordSize));
__ movl(EDX, Immediate(argc_tag));
const StubEntry* stub_entry;
@ -766,6 +765,8 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
locs());
__ popl(result);
__ Drop(ArgumentCount()); // Drop the arguments.
}
static bool CanBeImmediateIndex(Value* value, intptr_t cid) {

View file

@ -708,16 +708,15 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register result = locs()->out(0).reg();
const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function());
// All arguments are already @RSP due to preceding PushArgument()s.
ASSERT(ArgumentCount() == function().NumParameters());
// Push the result place holder initialized to NULL.
__ PushObject(Object::null_object());
// Pass a pointer to the first argument in RAX.
if (!function().HasOptionalParameters()) {
__ leaq(RAX,
Address(RBP, (kParamEndSlotFromFp + function().NumParameters()) *
kWordSize));
} else {
__ leaq(RAX, Address(RBP, kFirstLocalSlotFromFp * kWordSize));
}
__ leaq(RAX, Address(RSP, ArgumentCount() * kWordSize));
__ LoadImmediate(R10, Immediate(argc_tag));
const StubEntry* stub_entry;
if (link_lazily()) {
@ -740,6 +739,8 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
locs());
}
__ popq(result);
__ Drop(ArgumentCount()); // Drop the arguments.
}
static bool CanBeImmediateIndex(Value* index, intptr_t cid) {

View file

@ -3320,7 +3320,18 @@ void EffectGraphVisitor::VisitNativeBodyNode(NativeBodyNode* node) {
}
}
InlineBailout("EffectGraphVisitor::VisitNativeBodyNode");
NativeCallInstr* native_call = new (Z) NativeCallInstr(node);
const ParsedFunction& pf = owner_->parsed_function();
const String& name = String::ZoneHandle(Z, function.native_name());
ZoneGrowableArray<PushArgumentInstr*>& args =
*new (Z) ZoneGrowableArray<PushArgumentInstr*>(function.NumParameters());
for (intptr_t i = 0; i < function.NumParameters(); ++i) {
LocalVariable* parameter = pf.node_sequence()->scope()->VariableAt(i);
Value* value = Bind(new (Z) LoadLocalInstr(*parameter, node->token_pos()));
args.Add(PushArgument(value));
}
NativeCallInstr* native_call = new (Z) NativeCallInstr(
&name, &function, FLAG_link_natives_lazily, node->token_pos(), &args);
ReturnDefinition(native_call);
}

View file

@ -1389,8 +1389,10 @@ Fragment BaseFlowGraphBuilder::NullConstant() {
Fragment FlowGraphBuilder::NativeCall(const String* name,
const Function* function) {
InlineBailout("kernel::FlowGraphBuilder::NativeCall");
NativeCallInstr* call = new (Z) NativeCallInstr(
name, function, FLAG_link_natives_lazily, TokenPosition::kNoSource);
ArgumentArray arguments = GetArguments(function->NumParameters());
NativeCallInstr* call =
new (Z) NativeCallInstr(name, function, FLAG_link_natives_lazily,
TokenPosition::kNoSource, arguments);
Push(call);
return Fragment(call);
}
@ -2005,6 +2007,11 @@ Fragment FlowGraphBuilder::NativeFunctionBody(intptr_t first_positional_offset,
break;
default: {
String& name = String::ZoneHandle(Z, function.native_name());
for (intptr_t i = 0; i < function.NumParameters(); ++i) {
body += LoadLocal(
parsed_function_->node_sequence()->scope()->VariableAt(i));
body += PushArgument();
}
body += NativeCall(&name, &function);
break;
}

View file

@ -1954,61 +1954,59 @@ RawObject* Simulator::Call(const Code& code,
{
BYTECODE(NativeBootstrapCall, 0);
RawFunction* function = FrameFunction(FP);
RawObject** incoming_args =
(function->ptr()->num_optional_parameters_ == 0)
? FrameArguments(FP, function->ptr()->num_fixed_parameters_)
: FP;
intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
const intptr_t num_arguments = NativeArguments::ArgcBits::decode(argc_tag);
RawObject** incoming_args = SP - 1 - num_arguments;
RawObject** return_slot = SP - 1;
SimulatorBootstrapNativeCall native_target =
reinterpret_cast<SimulatorBootstrapNativeCall>(SP[-1]);
intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
SP[-0] = 0; // Note: argc_tag is not smi-tagged.
SP[-1] = null_value;
Exit(thread, FP, SP + 1, pc);
NativeArguments args(thread, argc_tag, incoming_args, SP - 1);
NativeArguments args(thread, argc_tag, incoming_args, return_slot);
INVOKE_BOOTSTRAP_NATIVE(native_target, args);
SP -= 1;
*(SP - 1 - num_arguments) = *return_slot;
SP -= 1 + num_arguments;
DISPATCH();
}
{
BYTECODE(NativeNoScopeCall, 0);
RawFunction* function = FrameFunction(FP);
RawObject** incoming_args =
(function->ptr()->num_optional_parameters_ == 0)
? FrameArguments(FP, function->ptr()->num_fixed_parameters_)
: FP;
intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
const intptr_t num_arguments = NativeArguments::ArgcBits::decode(argc_tag);
RawObject** incoming_args = SP - 1 - num_arguments;
RawObject** return_slot = SP - 1;
Dart_NativeFunction native_target =
reinterpret_cast<Dart_NativeFunction>(SP[-1]);
intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
SP[-0] = 0; // argc_tag is not smi tagged!
SP[-1] = null_value;
Exit(thread, FP, SP + 1, pc);
NativeArguments args(thread, argc_tag, incoming_args, SP - 1);
NativeArguments args(thread, argc_tag, incoming_args, return_slot);
INVOKE_NATIVE_NO_SCOPE(native_target, args);
SP -= 1;
*(SP - 1 - num_arguments) = *return_slot;
SP -= 1 + num_arguments;
DISPATCH();
}
{
BYTECODE(NativeAutoScopeCall, 0);
RawFunction* function = FrameFunction(FP);
RawObject** incoming_args =
(function->ptr()->num_optional_parameters_ == 0)
? FrameArguments(FP, function->ptr()->num_fixed_parameters_)
: FP;
intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
const intptr_t num_arguments = NativeArguments::ArgcBits::decode(argc_tag);
RawObject** incoming_args = SP - 1 - num_arguments;
RawObject** return_slot = SP - 1;
Dart_NativeFunction native_target =
reinterpret_cast<Dart_NativeFunction>(SP[-1]);
intptr_t argc_tag = reinterpret_cast<intptr_t>(SP[-0]);
SP[-0] = 0; // argc_tag is not smi tagged!
SP[-1] = null_value;
Exit(thread, FP, SP + 1, pc);
NativeArguments args(thread, argc_tag, incoming_args, SP - 1);
NativeArguments args(thread, argc_tag, incoming_args, return_slot);
INVOKE_NATIVE_AUTO_SCOPE(native_target, args);
SP -= 1;
*(SP - 1 - num_arguments) = *return_slot;
SP -= 1 + num_arguments;
DISPATCH();
}