From 181e8cc2a9b8044e91ee4d7ab1d4e0aaa4fe64bf Mon Sep 17 00:00:00 2001 From: Srdjan Mitrovic Date: Tue, 3 Nov 2015 16:18:24 -0800 Subject: [PATCH] Move resolving of natives to a late stage (during code emission). That eliminates unnecessary native resolution (e.g., when native gets recognized or rejected in the inliner). Removed tests that are now impossible to implement with AST (fake native functions). BUG= R=hausner@google.com Review URL: https://codereview.chromium.org/1420173006 . --- runtime/vm/ast.h | 9 - runtime/vm/code_generator_test.cc | 205 ---------------------- runtime/vm/compiler.cc | 9 +- runtime/vm/intermediate_language.cc | 25 +++ runtime/vm/intermediate_language.h | 18 +- runtime/vm/intermediate_language_arm.cc | 3 +- runtime/vm/intermediate_language_arm64.cc | 3 +- runtime/vm/intermediate_language_ia32.cc | 1 + runtime/vm/intermediate_language_mips.cc | 3 +- runtime/vm/intermediate_language_x64.cc | 3 +- runtime/vm/native_entry.cc | 2 +- runtime/vm/parser.cc | 21 +-- 12 files changed, 58 insertions(+), 244 deletions(-) diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h index c3b6ac1f6f8..14934fd3cef 100644 --- a/runtime/vm/ast.h +++ b/runtime/vm/ast.h @@ -1814,19 +1814,14 @@ class NativeBodyNode : public AstNode { NativeBodyNode(intptr_t token_pos, const Function& function, const String& native_c_function_name, - NativeFunction native_c_function, LocalScope* scope, - bool is_bootstrap_native, bool link_lazily = false) : AstNode(token_pos), function_(function), native_c_function_name_(native_c_function_name), - native_c_function_(native_c_function), scope_(scope), - is_bootstrap_native_(is_bootstrap_native), link_lazily_(link_lazily) { ASSERT(function_.IsZoneHandle()); - ASSERT(native_c_function_ != NULL); ASSERT(native_c_function_name_.IsZoneHandle()); ASSERT(native_c_function_name_.IsSymbol()); } @@ -1835,9 +1830,7 @@ class NativeBodyNode : public AstNode { const String& native_c_function_name() const { return native_c_function_name_; } - NativeFunction native_c_function() const { return native_c_function_; } LocalScope* scope() const { return scope_; } - bool is_bootstrap_native() const { return is_bootstrap_native_; } bool link_lazily() const { return link_lazily_; } @@ -1848,9 +1841,7 @@ class NativeBodyNode : public AstNode { private: const Function& function_; // Native Dart function. const String& native_c_function_name_; - NativeFunction native_c_function_; // Actual non-Dart implementation. LocalScope* scope_; - const bool is_bootstrap_native_; // Is a bootstrap native method. const bool link_lazily_; DISALLOW_IMPLICIT_CONSTRUCTORS(NativeBodyNode); diff --git a/runtime/vm/code_generator_test.cc b/runtime/vm/code_generator_test.cc index aac931182ef..2cdc6fbcc24 100644 --- a/runtime/vm/code_generator_test.cc +++ b/runtime/vm/code_generator_test.cc @@ -192,58 +192,6 @@ CODEGEN_TEST_GENERATE(BinaryOpCodegen, test) { CODEGEN_TEST_RUN(BinaryOpCodegen, Double::New(2.5)); -// Tested Dart code: -// int dec(int a, [int b = 1]) native: "TestSmiSub"; -// The native entry TestSmiSub implements dec natively. -CODEGEN_TEST_GENERATE(NativeDecCodegen, test) { - // A NativeBodyNode, preceded by an EnterNode and followed by a ReturnNode, - // implements the body of a native Dart function. Let's take this native - // function as an example: int dec(int a, int b = 1) native; - // Since this function has an optional parameter, its prologue will copy - // incoming parameters to locals. - SequenceNode* node_seq = test->node_sequence(); - const int num_fixed_params = 1; - const int num_opt_params = 1; - const int num_params = num_fixed_params + num_opt_params; - LocalScope* local_scope = node_seq->scope(); - local_scope->InsertParameterAt(0, NewTestLocalVariable("a")); - local_scope->InsertParameterAt(1, NewTestLocalVariable("b")); - ASSERT(local_scope->num_variables() == num_params); - ZoneGrowableArray* default_values = - new ZoneGrowableArray(num_opt_params); - default_values->Add(&Smi::ZoneHandle(Smi::New(1))); // b = 1. - test->set_default_parameter_values(default_values); - const Function& function = test->function(); - function.set_is_native(true); - function.set_num_fixed_parameters(num_fixed_params); - function.SetNumOptionalParameters(num_opt_params, true); - const String& native_name = - String::ZoneHandle(Symbols::New("TestSmiSub")); - NativeFunction native_function = - reinterpret_cast(TestSmiSub); - node_seq->Add( - new ReturnNode(kPos, - new NativeBodyNode(kPos, - function, - native_name, - native_function, - local_scope, - false /* not bootstrap native */))); -} - - -// Tested Dart code: -// return dec(5); -CODEGEN_TEST2_GENERATE(StaticDecCallCodegen, function, test) { - SequenceNode* node_seq = test->node_sequence(); - ArgumentListNode* arguments = new ArgumentListNode(kPos); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(5)))); - node_seq->Add(new ReturnNode(kPos, - new StaticCallNode(kPos, function, arguments))); -} -CODEGEN_TEST2_RUN(StaticDecCallCodegen, NativeDecCodegen, Smi::New(4)) - - CODEGEN_TEST_GENERATE(SmiUnaryOpCodegen, test) { SequenceNode* node_seq = test->node_sequence(); LiteralNode* a = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(12))); @@ -368,159 +316,6 @@ CODEGEN_TEST_GENERATE(InstanceCallCodegen, test) { CODEGEN_TEST_RUN(InstanceCallCodegen, Smi::New(42)) -// Tested Dart code: -// int sum(int a, int b, -// [int c = 10, int d = 21, int e = -32]) native: "TestSmiSum"; -// The native entry TestSmiSum implements sum natively. -CODEGEN_TEST_GENERATE(NativeSumCodegen, test) { - SequenceNode* node_seq = test->node_sequence(); - const int num_fixed_params = 2; - const int num_opt_params = 3; - const int num_params = num_fixed_params + num_opt_params; - LocalScope* local_scope = node_seq->scope(); - local_scope->InsertParameterAt(0, NewTestLocalVariable("a")); - local_scope->InsertParameterAt(1, NewTestLocalVariable("b")); - local_scope->InsertParameterAt(2, NewTestLocalVariable("c")); - local_scope->InsertParameterAt(3, NewTestLocalVariable("d")); - local_scope->InsertParameterAt(4, NewTestLocalVariable("e")); - ASSERT(local_scope->num_variables() == num_params); - ZoneGrowableArray* default_values = - new ZoneGrowableArray(num_opt_params); - default_values->Add(&Smi::ZoneHandle(Smi::New(10))); - default_values->Add(&Smi::ZoneHandle(Smi::New(21))); - default_values->Add(&Smi::ZoneHandle(Smi::New(-32))); - test->set_default_parameter_values(default_values); - const Function& function = test->function(); - function.set_is_native(true); - function.set_num_fixed_parameters(num_fixed_params); - function.SetNumOptionalParameters(num_opt_params, true); - function.set_parameter_types(Array::Handle(Array::New(num_params))); - function.set_parameter_names(Array::Handle(Array::New(num_params))); - const Type& param_type = Type::Handle(Type::DynamicType()); - for (int i = 0; i < num_params; i++) { - function.SetParameterTypeAt(i, param_type); - } - const String& native_name = - String::ZoneHandle(Symbols::New("TestSmiSum")); - NativeFunction native_function = - reinterpret_cast(TestSmiSum); - node_seq->Add( - new ReturnNode(kPos, - new NativeBodyNode(kPos, - function, - native_name, - native_function, - local_scope, - false /* Not bootstrap native */))); -} - - -// Tested Dart code, calling function sum declared above: -// return sum(1, 3); -// Optional arguments are not passed and hence are set to their default values. -CODEGEN_TEST2_GENERATE(StaticSumCallNoOptCodegen, function, test) { - SequenceNode* node_seq = test->node_sequence(); - ArgumentListNode* arguments = new ArgumentListNode(kPos); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1)))); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)))); - node_seq->Add(new ReturnNode(kPos, - new StaticCallNode(kPos, function, arguments))); -} -CODEGEN_TEST2_RUN(StaticSumCallNoOptCodegen, - NativeSumCodegen, - Smi::New(1 + 3 + 10 + 21 - 32)) - - -// Tested Dart code, calling function sum declared above: -// return sum(1, 3, 5); -// Only one out of three optional arguments is passed in; the second and third -// arguments are hence set to their default values. -CODEGEN_TEST2_GENERATE(StaticSumCallOneOptCodegen, function, test) { - SequenceNode* node_seq = test->node_sequence(); - ArgumentListNode* arguments = new ArgumentListNode(kPos); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1)))); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)))); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(5)))); - node_seq->Add(new ReturnNode(kPos, - new StaticCallNode(kPos, function, arguments))); -} -CODEGEN_TEST2_RUN(StaticSumCallOneOptCodegen, - NativeSumCodegen, - Smi::New(1 + 3 + 5 + 21 - 32)) - - -// Tested Dart code, calling function sum declared above: -// return sum(0, 1, 1, 2, 3); -// Optional arguments are passed in. -CODEGEN_TEST2_GENERATE(StaticSumCallTenFiboCodegen, function, test) { - SequenceNode* node_seq = test->node_sequence(); - ArgumentListNode* arguments = new ArgumentListNode(kPos); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(0)))); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1)))); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1)))); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2)))); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)))); - node_seq->Add(new ReturnNode(kPos, - new StaticCallNode(kPos, function, arguments))); -} -CODEGEN_TEST2_RUN( - StaticSumCallTenFiboCodegen, - NativeSumCodegen, - Smi::New(0 + 1 + 1 + 2 + 3)) - - -// Tested Dart code: -// int sum(a, b, c) native: "TestNonNullSmiSum"; -// The native entry TestNonNullSmiSum implements sum natively. -CODEGEN_TEST_GENERATE(NativeNonNullSumCodegen, test) { - SequenceNode* node_seq = test->node_sequence(); - const int num_params = 3; - LocalScope* local_scope = node_seq->scope(); - local_scope->InsertParameterAt(0, NewTestLocalVariable("a")); - local_scope->InsertParameterAt(1, NewTestLocalVariable("b")); - local_scope->InsertParameterAt(2, NewTestLocalVariable("c")); - ASSERT(local_scope->num_variables() == num_params); - const Function& function = test->function(); - function.set_is_native(true); - function.set_num_fixed_parameters(num_params); - ASSERT(!function.HasOptionalParameters()); - function.set_parameter_types(Array::Handle(Array::New(num_params))); - function.set_parameter_names(Array::Handle(Array::New(num_params))); - const Type& param_type = Type::Handle(Type::DynamicType()); - for (int i = 0; i < num_params; i++) { - function.SetParameterTypeAt(i, param_type); - } - const String& native_name = - String::ZoneHandle(Symbols::New("TestNonNullSmiSum")); - NativeFunction native_function = - reinterpret_cast(TestNonNullSmiSum); - node_seq->Add( - new ReturnNode(kPos, - new NativeBodyNode(kPos, - function, - native_name, - native_function, - local_scope, - false /* Not bootstrap native */))); -} - - -// Tested Dart code, calling function sum declared above: -// return sum(1, null, 3); -CODEGEN_TEST2_GENERATE(StaticNonNullSumCallCodegen, function, test) { - SequenceNode* node_seq = test->node_sequence(); - ArgumentListNode* arguments = new ArgumentListNode(kPos); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1)))); - arguments->Add(new LiteralNode(kPos, Instance::ZoneHandle())); - arguments->Add(new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3)))); - node_seq->Add(new ReturnNode(kPos, - new StaticCallNode(kPos, function, arguments))); -} -CODEGEN_TEST2_RUN(StaticNonNullSumCallCodegen, - NativeNonNullSumCodegen, - Smi::New(1 + 3)) - - // Test allocation of dart objects. CODEGEN_TEST_GENERATE(AllocateNewObjectCodegen, test) { const char* kScriptChars = diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc index 0422cf30622..43bbcbafdf6 100644 --- a/runtime/vm/compiler.cc +++ b/runtime/vm/compiler.cc @@ -852,7 +852,6 @@ static bool CompileParsedFunctionHelper(CompilationPipeline* pipeline, THR_Print("%s\n", error.ToErrorCString()); } done = true; - ASSERT(optimized); } // Clear the error if it was not a real error, but just a bailout. @@ -1091,8 +1090,14 @@ static RawError* CompileFunctionHelper(CompilationPipeline* pipeline, } function.SetIsOptimizable(false); return Error::null(); + } else { + // Encountered error. + Error& error = Error::Handle(); + // We got an error during compilation. + error = isolate->object_store()->sticky_error(); + isolate->object_store()->clear_sticky_error(); + return error.raw(); } - UNREACHABLE(); } per_compile_timer.Stop(); diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc index f063e7dae66..2293d9c179f 100644 --- a/runtime/vm/intermediate_language.cc +++ b/runtime/vm/intermediate_language.cc @@ -5,6 +5,7 @@ #include "vm/intermediate_language.h" #include "vm/bit_vector.h" +#include "vm/bootstrap.h" #include "vm/compiler.h" #include "vm/constant_propagator.h" #include "vm/cpu.h" @@ -3656,6 +3657,30 @@ intptr_t MergedMathInstr::OutputIndexOf(Token::Kind token) { } +void NativeCallInstr::SetupNative() { + Zone* Z = Thread::Current()->zone(); + const Class& cls = Class::Handle(Z, function().Owner()); + const Library& library = Library::Handle(Z, cls.library()); + const int num_params = + NativeArguments::ParameterCountForResolution(function()); + bool auto_setup_scope = true; + NativeFunction native_function = NativeEntry::ResolveNative( + library, native_name(), num_params, &auto_setup_scope); + if (native_function == NULL) { + Report::MessageF(Report::kError, + Script::Handle(function().script()), + function().token_pos(), + "native function '%s' (%" Pd " arguments) cannot be found", + native_name().ToCString(), + function().NumParameters()); + } + set_native_c_function(native_function); + function().SetIsNativeAutoSetupScope(auto_setup_scope); + Dart_NativeEntryResolver resolver = library.native_entry_resolver(); + bool is_bootstrap_native = Bootstrap::IsBootstapResolver(resolver); + set_is_bootstrap_native(is_bootstrap_native); +} + #undef __ } // namespace dart diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h index fbd405122c9..2b9b7625266 100644 --- a/runtime/vm/intermediate_language.h +++ b/runtime/vm/intermediate_language.h @@ -3393,7 +3393,9 @@ class StoreLocalInstr : public TemplateDefinition<1, NoThrow> { class NativeCallInstr : public TemplateDefinition<0, Throws> { public: explicit NativeCallInstr(NativeBodyNode* node) - : ast_node_(*node) {} + : ast_node_(*node), + native_c_function_(NULL), + is_bootstrap_native_(false) { } DECLARE_INSTRUCTION(NativeCall) @@ -3406,11 +3408,11 @@ class NativeCallInstr : public TemplateDefinition<0, Throws> { } NativeFunction native_c_function() const { - return ast_node_.native_c_function(); + return native_c_function_; } bool is_bootstrap_native() const { - return ast_node_.is_bootstrap_native(); + return is_bootstrap_native_; } bool link_lazily() const { @@ -3423,8 +3425,18 @@ class NativeCallInstr : public TemplateDefinition<0, Throws> { virtual EffectSet Effects() const { return EffectSet::All(); } + void SetupNative(); + private: + void set_native_c_function(NativeFunction value) { + native_c_function_ = value; + } + + void set_is_bootstrap_native(bool value) { is_bootstrap_native_ = value; } + const NativeBodyNode& ast_node_; + NativeFunction native_c_function_; + bool is_bootstrap_native_; DISALLOW_COPY_AND_ASSIGN(NativeCallInstr); }; diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc index a82b455e6fb..1f547339a0f 100644 --- a/runtime/vm/intermediate_language_arm.cc +++ b/runtime/vm/intermediate_language_arm.cc @@ -925,6 +925,7 @@ LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { + SetupNative(); const Register result = locs()->out(0).reg(); // Push the result place holder initialized to NULL. @@ -942,7 +943,7 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { uword entry; const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); const bool is_leaf_call = - (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; + (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; const StubEntry* stub_entry; if (link_lazily()) { stub_entry = StubCode::CallBootstrapCFunction_entry(); diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc index 892a2967853..7707e0b3d4c 100644 --- a/runtime/vm/intermediate_language_arm64.cc +++ b/runtime/vm/intermediate_language_arm64.cc @@ -779,6 +779,7 @@ LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { + SetupNative(); const Register result = locs()->out(0).reg(); // Push the result place holder initialized to NULL. @@ -796,7 +797,7 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { uword entry; const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); const bool is_leaf_call = - (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; + (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; const StubEntry* stub_entry; if (link_lazily()) { stub_entry = StubCode::CallBootstrapCFunction_entry(); diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc index eab55fb8d0e..b5a851faf9f 100644 --- a/runtime/vm/intermediate_language_ia32.cc +++ b/runtime/vm/intermediate_language_ia32.cc @@ -818,6 +818,7 @@ LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { + SetupNative(); Register result = locs()->out(0).reg(); const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); const bool is_leaf_call = diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc index 04713cd2f0f..c005041504d 100644 --- a/runtime/vm/intermediate_language_mips.cc +++ b/runtime/vm/intermediate_language_mips.cc @@ -975,6 +975,7 @@ LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { + SetupNative(); __ Comment("NativeCallInstr"); Register result = locs()->out(0).reg(); @@ -993,7 +994,7 @@ void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { uword entry; const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); const bool is_leaf_call = - (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; + (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; const StubEntry* stub_entry; if (link_lazily()) { stub_entry = StubCode::CallBootstrapCFunction_entry(); diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc index cc1967501c1..3d30dc0a2e6 100644 --- a/runtime/vm/intermediate_language_x64.cc +++ b/runtime/vm/intermediate_language_x64.cc @@ -772,10 +772,11 @@ LocationSummary* NativeCallInstr::MakeLocationSummary(Zone* zone, void NativeCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) { + SetupNative(); Register result = locs()->out(0).reg(); const intptr_t argc_tag = NativeArguments::ComputeArgcTag(function()); const bool is_leaf_call = - (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; + (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; // Push the result place holder initialized to NULL. __ PushObject(Object::null_object()); diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc index 5d5a59685cd..63c9a61a185 100644 --- a/runtime/vm/native_entry.cc +++ b/runtime/vm/native_entry.cc @@ -234,7 +234,7 @@ void NativeEntry::LinkNativeCall(Dart_NativeArguments args) { const intptr_t argc_tag = NativeArguments::ComputeArgcTag(func); const bool is_leaf_call = - (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; + (argc_tag & NativeArguments::AutoSetupScopeMask()) == 0; call_through_wrapper = !is_bootstrap_native && !is_leaf_call; diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc index 748c38d53e8..8271d481700 100644 --- a/runtime/vm/parser.cc +++ b/runtime/vm/parser.cc @@ -7339,39 +7339,20 @@ void Parser::AddFormalParamsToScope(const ParamList* params, void Parser::ParseNativeFunctionBlock(const ParamList* params, const Function& func) { ASSERT(func.is_native()); - TRACE_PARSER("ParseNativeFunctionBlock"); - const Class& cls = Class::Handle(Z, func.Owner()); - const Library& library = Library::Handle(Z, cls.library()); ASSERT(func.NumParameters() == params->parameters->length()); + TRACE_PARSER("ParseNativeFunctionBlock"); // Parse the function name out. - const intptr_t native_pos = TokenPos(); const String& native_name = ParseNativeDeclaration(); - // Now resolve the native function to the corresponding native entrypoint. - const int num_params = NativeArguments::ParameterCountForResolution(func); - bool auto_setup_scope = true; - NativeFunction native_function = NativeEntry::ResolveNative( - library, native_name, num_params, &auto_setup_scope); - if (native_function == NULL) { - ReportError(native_pos, - "native function '%s' (%" Pd " arguments) cannot be found", - native_name.ToCString(), func.NumParameters()); - } - func.SetIsNativeAutoSetupScope(auto_setup_scope); - // Now add the NativeBodyNode and return statement. - Dart_NativeEntryResolver resolver = library.native_entry_resolver(); - bool is_bootstrap_native = Bootstrap::IsBootstapResolver(resolver); current_block_->statements->Add(new(Z) ReturnNode( TokenPos(), new(Z) NativeBodyNode( TokenPos(), Function::ZoneHandle(Z, func.raw()), native_name, - native_function, current_block_->scope, - is_bootstrap_native, FLAG_link_natives_lazily))); }