aboutsummaryrefslogtreecommitdiff
path: root/src/check_decl.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2024-01-07 19:56:00 +0000
committergingerBill <bill@gingerbill.org>2024-01-07 19:56:00 +0000
commitaff8f06e3cb1bdb9c3ffee98a68675c843df78fd (patch)
tree14045e04f2c06c1dfb78cad9cbd0a4528959ccad /src/check_decl.cpp
parent1e1228fb37bafd6ab277247a8bea91fab68914e0 (diff)
Add frontend stuff instrumentation tooling
//+no-instrumentation @(no_instrumentation) @(instrumentation_enter) @(instrumentation_exit)
Diffstat (limited to 'src/check_decl.cpp')
-rw-r--r--src/check_decl.cpp66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index 8a3f89877..c69d8185e 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -909,6 +909,72 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
e->Procedure.entry_point_only = ac.entry_point_only;
e->Procedure.is_export = ac.is_export;
+
+ bool no_instrumentation = false;
+ if (pl->body == nullptr) {
+ no_instrumentation = true;
+ if (ac.no_instrumentation != Instrumentation_Default) {
+ error(e->token, "@(no_instrumentation) is not allowed on foreign procedures");
+ }
+ } else {
+ if (e->file) {
+ no_instrumentation = (e->file->flags & AstFile_NoInstrumentation) != 0;
+ }
+
+ switch (ac.no_instrumentation) {
+ case Instrumentation_Enabled: no_instrumentation = false; break;
+ case Instrumentation_Default: break;
+ case Instrumentation_Disabled: no_instrumentation = true; break;
+ }
+ }
+ e->Procedure.no_instrumentation = no_instrumentation;
+
+ auto const is_valid_instrumentation_call = [](Type *type) -> bool {
+ if (type == nullptr || type->kind != Type_Proc) {
+ return false;
+ }
+ if (type->Proc.calling_convention != ProcCC_CDecl) {
+ return false;
+ }
+ if (type->Proc.result_count != 0) {
+ return false;
+ }
+ if (type->Proc.param_count != 2) {
+ return false;
+ }
+ Type *p0 = type->Proc.params->Tuple.variables[0]->type;
+ Type *p1 = type->Proc.params->Tuple.variables[1]->type;
+ return is_type_rawptr(p0) && is_type_rawptr(p1);
+ };
+
+ if (ac.instrumentation_enter && ac.instrumentation_exit) {
+ error(e->token, "A procedure cannot be marked with both @(instrumentation_enter) and @(instrumentation_exit)");
+ } else if (ac.instrumentation_enter) {
+ if (!is_valid_instrumentation_call(e->type)) {
+ gbString s = type_to_string(e->type);
+ error(e->token, "@(instrumentation_enter) procedures must have the type 'proc \"c\" (rawptr, rawptr)', got %s", s);
+ gb_string_free(s);
+ }
+ MUTEX_GUARD(&ctx->info->instrumentation_mutex);
+ if (ctx->info->instrumentation_enter_entity != nullptr) {
+ error(e->token, "@(instrumentation_enter) has already been set");
+ } else {
+ ctx->info->instrumentation_enter_entity = e;
+ }
+ } else if (ac.instrumentation_exit) {
+ if (!is_valid_instrumentation_call(e->type)) {
+ gbString s = type_to_string(e->type);
+ error(e->token, "@(instrumentation_exit) procedures must have the type 'proc \"c\" (rawptr, rawptr)', got %s", s);
+ gb_string_free(s);
+ }
+ MUTEX_GUARD(&ctx->info->instrumentation_mutex);
+ if (ctx->info->instrumentation_exit_entity != nullptr) {
+ error(e->token, "@(instrumentation_exit) has already been set");
+ } else {
+ ctx->info->instrumentation_exit_entity = e;
+ }
+ }
+
e->deprecated_message = ac.deprecated_message;
e->warning_message = ac.warning_message;
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);