251 lines
7.5 KiB
C
251 lines
7.5 KiB
C
/**************************************************************************/
|
|
/* */
|
|
/* OCaml */
|
|
/* */
|
|
/* Mark Shinwell and Leo White, Jane Street Europe */
|
|
/* */
|
|
/* Copyright 2013--2016, Jane Street Group, LLC */
|
|
/* */
|
|
/* All rights reserved. This file is distributed under the terms of */
|
|
/* the GNU Lesser General Public License version 2.1, with the */
|
|
/* special exception on linking described in the file LICENSE. */
|
|
/* */
|
|
/**************************************************************************/
|
|
|
|
#define CAML_INTERNALS
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <math.h>
|
|
|
|
#include "caml/alloc.h"
|
|
#include "caml/config.h"
|
|
#include "caml/fail.h"
|
|
#include "caml/gc.h"
|
|
#include "caml/intext.h"
|
|
#include "caml/major_gc.h"
|
|
#include "caml/memory.h"
|
|
#include "caml/minor_gc.h"
|
|
#include "caml/misc.h"
|
|
#include "caml/mlvalues.h"
|
|
#include "caml/roots.h"
|
|
#include "caml/signals.h"
|
|
#include "caml/stack.h"
|
|
#include "caml/sys.h"
|
|
#include "caml/spacetime.h"
|
|
|
|
#include "caml/s.h"
|
|
|
|
#define SPACETIME_PROFINFO_WIDTH 26
|
|
#define Spacetime_profinfo_hd(hd) \
|
|
(Gen_profinfo_hd(SPACETIME_PROFINFO_WIDTH, hd))
|
|
|
|
#ifdef ARCH_SIXTYFOUR
|
|
|
|
/* CR-someday lwhite: The following two definitions are copied from spacetime.c
|
|
because they are needed here, but must be inlined in spacetime.c
|
|
for performance. Perhaps a macro or "static inline" would be
|
|
more appropriate. */
|
|
|
|
c_node* caml_spacetime_offline_c_node_of_stored_pointer_not_null
|
|
(value node_stored)
|
|
{
|
|
CAMLassert(Is_c_node(node_stored));
|
|
return (c_node*) Hp_val(node_stored);
|
|
}
|
|
|
|
c_node_type caml_spacetime_offline_classify_c_node(c_node* node)
|
|
{
|
|
return (node->pc & 2) ? CALL : ALLOCATION;
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_compare_node(
|
|
value node1, value node2)
|
|
{
|
|
CAMLassert(!Is_in_value_area(node1));
|
|
CAMLassert(!Is_in_value_area(node2));
|
|
|
|
if (node1 == node2) {
|
|
return Val_long(0);
|
|
}
|
|
if (node1 < node2) {
|
|
return Val_long(-1);
|
|
}
|
|
return Val_long(1);
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_unmarshal_trie (value v_channel)
|
|
{
|
|
return caml_input_value_to_outside_heap(v_channel);
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_node_num_header_words(value unit)
|
|
{
|
|
return Val_long(Node_num_header_words);
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_is_ocaml_node(value node)
|
|
{
|
|
CAMLassert(Is_ocaml_node(node) || Is_c_node(node));
|
|
return Val_bool(Is_ocaml_node(node));
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_ocaml_function_identifier(value node)
|
|
{
|
|
CAMLassert(Is_ocaml_node(node));
|
|
return caml_copy_int64((uint64_t) Decode_node_pc(Node_pc(node)));
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_ocaml_tail_chain(value node)
|
|
{
|
|
CAMLassert(Is_ocaml_node(node));
|
|
return Tail_link(node);
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_classify_direct_call_point
|
|
(value node, value offset)
|
|
{
|
|
uintnat field;
|
|
value callee_node;
|
|
|
|
CAMLassert(Is_ocaml_node(node));
|
|
|
|
field = Long_val(offset);
|
|
|
|
callee_node = Direct_callee_node(node, field);
|
|
if (!Is_block(callee_node)) {
|
|
/* An unused call point (may be a tail call point). */
|
|
return Val_long(0);
|
|
} else if (Is_ocaml_node(callee_node)) {
|
|
return Val_long(1); /* direct call point to OCaml code */
|
|
} else {
|
|
return Val_long(2); /* direct call point to non-OCaml code */
|
|
}
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_ocaml_allocation_point_annotation
|
|
(value node, value offset)
|
|
{
|
|
uintnat profinfo_shifted;
|
|
profinfo_shifted = (uintnat) Alloc_point_profinfo(node, Long_val(offset));
|
|
return Val_long(Spacetime_profinfo_hd(profinfo_shifted));
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_ocaml_allocation_point_count
|
|
(value node, value offset)
|
|
{
|
|
value count = Alloc_point_count(node, Long_val(offset));
|
|
CAMLassert(!Is_block(count));
|
|
return count;
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_ocaml_direct_call_point_callee_node
|
|
(value node, value offset)
|
|
{
|
|
return Direct_callee_node(node, Long_val(offset));
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_ocaml_direct_call_point_call_count
|
|
(value node, value offset)
|
|
{
|
|
return Direct_call_count(node, Long_val(offset));
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_ocaml_indirect_call_point_callees
|
|
(value node, value offset)
|
|
{
|
|
value callees = Indirect_pc_linked_list(node, Long_val(offset));
|
|
CAMLassert(Is_block(callees));
|
|
CAMLassert(Is_c_node(callees));
|
|
return callees;
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_c_node_is_call(value node)
|
|
{
|
|
c_node* c_node;
|
|
CAMLassert(node != (value) NULL);
|
|
CAMLassert(Is_c_node(node));
|
|
c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
|
|
switch (caml_spacetime_offline_classify_c_node(c_node)) {
|
|
case CALL: return Val_true;
|
|
case ALLOCATION: return Val_false;
|
|
}
|
|
CAMLassert(0);
|
|
return Val_unit; /* silence compiler warning */
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_c_node_next(value node)
|
|
{
|
|
c_node* c_node;
|
|
|
|
CAMLassert(node != (value) NULL);
|
|
CAMLassert(Is_c_node(node));
|
|
c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
|
|
CAMLassert(c_node->next == Val_unit || Is_c_node(c_node->next));
|
|
return c_node->next;
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_c_node_call_site(value node)
|
|
{
|
|
c_node* c_node;
|
|
CAMLassert(node != (value) NULL);
|
|
CAMLassert(Is_c_node(node));
|
|
c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
|
|
return caml_copy_int64((uint64_t) Decode_c_node_pc(c_node->pc));
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_c_node_callee_node(value node)
|
|
{
|
|
c_node* c_node;
|
|
CAMLassert(node != (value) NULL);
|
|
CAMLassert(Is_c_node(node));
|
|
c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
|
|
CAMLassert(caml_spacetime_offline_classify_c_node(c_node) == CALL);
|
|
/* This might be an uninitialised tail call point: for example if an OCaml
|
|
callee was indirectly called but the callee wasn't instrumented (e.g. a
|
|
leaf function that doesn't allocate). */
|
|
if (Is_tail_caller_node_encoded(c_node->data.call.callee_node)) {
|
|
return Val_unit;
|
|
}
|
|
return c_node->data.call.callee_node;
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_c_node_call_count(value node)
|
|
{
|
|
c_node* c_node;
|
|
CAMLassert(node != (value) NULL);
|
|
CAMLassert(Is_c_node(node));
|
|
c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
|
|
CAMLassert(caml_spacetime_offline_classify_c_node(c_node) == CALL);
|
|
if (Is_tail_caller_node_encoded(c_node->data.call.callee_node)) {
|
|
return Val_long(0);
|
|
}
|
|
return c_node->data.call.call_count;
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_c_node_profinfo(value node)
|
|
{
|
|
c_node* c_node;
|
|
CAMLassert(node != (value) NULL);
|
|
CAMLassert(Is_c_node(node));
|
|
c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
|
|
CAMLassert(caml_spacetime_offline_classify_c_node(c_node) == ALLOCATION);
|
|
CAMLassert(!Is_block(c_node->data.allocation.profinfo));
|
|
return Val_long(Spacetime_profinfo_hd(c_node->data.allocation.profinfo));
|
|
}
|
|
|
|
CAMLprim value caml_spacetime_c_node_allocation_count(value node)
|
|
{
|
|
c_node* c_node;
|
|
CAMLassert(node != (value) NULL);
|
|
CAMLassert(Is_c_node(node));
|
|
c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
|
|
CAMLassert(caml_spacetime_offline_classify_c_node(c_node) == ALLOCATION);
|
|
CAMLassert(!Is_block(c_node->data.allocation.count));
|
|
return c_node->data.allocation.count;
|
|
}
|
|
|
|
#endif
|