Revision c3861f5c7371fea2fc5d20404a7f77c927bbd61b authored by Shuhei Kadowaki on 14 August 2021, 12:49:21 UTC, committed by Shuhei Kadowaki on 23 August 2021, 15:09:13 UTC
Built on top of #41882, this PR sorts out the constant-prop' interface yet more, particularly generalizes `force_const_prop` to `const_prop_config` so that it can turn on and off each heuristic. The main motivation here is, in #41882, we want to force const-prop' on `setproperty` even when its return type is already `Const` for the sake of succeeding inlining, by skipping all the `const_prop_xxx_heuristic` checks. But I still found we want to apply `const_prop_entry_heuristic` to `getproperty`, because if we already know very accurate result for a `getproperty` call, usually there is really no motivation for constant-prop', e.g.: ```julia struct FZero end Base.getproperty(::FZero, ::Symbol) = 0.0 getproperty(FZero(), :val) # const-prop' doesn't need to happen here ``` Now `force_const_prop(...) -> force::Bool` is refactored to `const_prop_config(...) -> config::UInt8`, which can turn on and off each heuristic based on the value of `config`. I also included another refactoring that inlines `const_prop_rettype_heuristic` into `const_prop_argument_heuristic`, because they really seem tightly coupled.
1 parent e1e4986
symbol.c
// This file is a part of Julia. License is MIT: https://julialang.org/license
/*
Symbol table
*/
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "julia.h"
#include "julia_internal.h"
#include "julia_assert.h"
#ifdef __cplusplus
extern "C" {
#endif
static jl_sym_t *symtab = NULL;
#define MAX_SYM_LEN ((size_t)INTPTR_MAX - sizeof(jl_taggedvalue_t) - sizeof(jl_sym_t) - 1)
static uintptr_t hash_symbol(const char *str, size_t len) JL_NOTSAFEPOINT
{
uintptr_t oid = memhash(str, len) ^ ~(uintptr_t)0/3*2;
// compute the same hash value as v1.6 and earlier, which used `hash_uint(3h - objectid(sym))`
return inthash(-oid);
}
static size_t symbol_nbytes(size_t len) JL_NOTSAFEPOINT
{
return (sizeof(jl_taggedvalue_t) + sizeof(jl_sym_t) + len + 1 + 7) & -8;
}
static jl_sym_t *mk_symbol(const char *str, size_t len) JL_NOTSAFEPOINT
{
jl_sym_t *sym;
size_t nb = symbol_nbytes(len);
assert(jl_symbol_type && "not initialized");
jl_taggedvalue_t *tag = (jl_taggedvalue_t*)jl_gc_perm_alloc_nolock(nb, 0, sizeof(void*), 0);
sym = (jl_sym_t*)jl_valueof(tag);
// set to old marked so that we won't look at it in the GC or write barrier.
tag->header = ((uintptr_t)jl_symbol_type) | GC_OLD_MARKED;
sym->left = sym->right = NULL;
sym->hash = hash_symbol(str, len);
memcpy(jl_symbol_name(sym), str, len);
jl_symbol_name(sym)[len] = 0;
return sym;
}
static jl_sym_t *symtab_lookup(jl_sym_t **ptree, const char *str, size_t len, jl_sym_t ***slot) JL_NOTSAFEPOINT
{
jl_sym_t *node = jl_atomic_load_acquire(ptree); // consume
uintptr_t h = hash_symbol(str, len);
// Tree nodes sorted by major key of (int(hash)) and minor key of (str).
while (node != NULL) {
intptr_t x = (intptr_t)(h - node->hash);
if (x == 0) {
x = strncmp(str, jl_symbol_name(node), len);
if (x == 0 && jl_symbol_name(node)[len] == 0) {
if (slot != NULL)
*slot = ptree;
return node;
}
}
if (x < 0)
ptree = &node->left;
else
ptree = &node->right;
node = jl_atomic_load_acquire(ptree); // consume
}
if (slot != NULL)
*slot = ptree;
return node;
}
jl_sym_t *_jl_symbol(const char *str, size_t len) JL_NOTSAFEPOINT // (or throw)
{
#ifndef __clang_analyzer__
// Hide the error throwing from the analyser since there isn't a way to express
// "safepoint only when throwing error" currently.
if (len > MAX_SYM_LEN)
jl_exceptionf(jl_argumenterror_type, "Symbol name too long");
#endif
assert(!memchr(str, 0, len));
jl_sym_t **slot;
jl_sym_t *node = symtab_lookup(&symtab, str, len, &slot);
if (node == NULL) {
JL_LOCK_NOGC(&gc_perm_lock);
// Someone might have updated it, check and look up again
if (*slot != NULL && (node = symtab_lookup(slot, str, len, &slot))) {
JL_UNLOCK_NOGC(&gc_perm_lock);
return node;
}
node = mk_symbol(str, len);
jl_atomic_store_release(slot, node);
JL_UNLOCK_NOGC(&gc_perm_lock);
}
return node;
}
JL_DLLEXPORT jl_sym_t *jl_symbol(const char *str) JL_NOTSAFEPOINT // (or throw)
{
return _jl_symbol(str, strlen(str));
}
JL_DLLEXPORT jl_sym_t *jl_symbol_lookup(const char *str) JL_NOTSAFEPOINT
{
return symtab_lookup(&symtab, str, strlen(str), NULL);
}
JL_DLLEXPORT jl_sym_t *jl_symbol_n(const char *str, size_t len)
{
if (memchr(str, 0, len))
jl_exceptionf(jl_argumenterror_type, "Symbol name may not contain \\0");
return _jl_symbol(str, len);
}
JL_DLLEXPORT jl_sym_t *jl_get_root_symbol(void)
{
return symtab;
}
static uint32_t gs_ctr = 0; // TODO: per-thread
uint32_t jl_get_gs_ctr(void) { return gs_ctr; }
void jl_set_gs_ctr(uint32_t ctr) { gs_ctr = ctr; }
JL_DLLEXPORT jl_sym_t *jl_gensym(void)
{
char name[16];
char *n;
uint32_t ctr = jl_atomic_fetch_add(&gs_ctr, 1);
n = uint2str(&name[2], sizeof(name)-2, ctr, 10);
*(--n) = '#'; *(--n) = '#';
return jl_symbol(n);
}
JL_DLLEXPORT jl_sym_t *jl_tagged_gensym(const char *str, size_t len)
{
if (len == (size_t)-1) {
len = strlen(str);
}
else if (memchr(str, 0, len)) {
jl_exceptionf(jl_argumenterror_type, "Symbol name may not contain \\0");
}
char gs_name[14];
size_t alloc_len = sizeof(gs_name) + len + 3;
if (len > MAX_SYM_LEN || alloc_len > MAX_SYM_LEN)
jl_exceptionf(jl_argumenterror_type, "Symbol name too long");
char *name = (char*)(len >= 256 ? malloc_s(alloc_len) : alloca(alloc_len));
char *n;
name[0] = '#';
name[1] = '#';
name[2 + len] = '#';
memcpy(name + 2, str, len);
uint32_t ctr = jl_atomic_fetch_add(&gs_ctr, 1);
n = uint2str(gs_name, sizeof(gs_name), ctr, 10);
memcpy(name + 3 + len, n, sizeof(gs_name) - (n - gs_name));
jl_sym_t *sym = _jl_symbol(name, alloc_len - (n - gs_name)- 1);
if (len >= 256)
free(name);
return sym;
}
#ifdef __cplusplus
}
#endif
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...