Skip to content

Instantly share code, notes, and snippets.

@mkmik
Last active August 29, 2015 14:12
Show Gist options
  • Save mkmik/6dd7d1e728d436b993b3 to your computer and use it in GitHub Desktop.
Save mkmik/6dd7d1e728d436b993b3 to your computer and use it in GitHub Desktop.
&obj = 0x7fff5dbe50c8
&str = 0x7fff5dbe50c0
v7_object_to_value(&obj):
object 0x7fff5dbe50c8
v7_string_to_value(&str):
other value 0xfff97fff5dbe50c0
v7_double_to_value(42.24):
double value 42.24
v7_double_to_value(atof("nan")):
double value nan
v7_double_to_value(atof("-nan")):
double value nan
v7_double_to_value(atof("inf")):
double value inf
v7_double_to_value(atof("-inf")):
double value -inf
v7_boolean_to_value(1):
bool 1
v7_boolean_to_value(0):
bool 0
V7_NULL:
null
V7_UNDEFINED:
undefined
v7_double_to_value(v7_value_to_double(two) * v7_value_to_double(two)):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef unsigned long long uint64_t;
struct v7_object;
struct v7_str;
/* punboxing */
typedef uint64_t v7_value;
#define V7_TAG_OBJECT ((uint64_t) 0xFFFF << 48)
#define V7_TAG_FOREIGN ((uint64_t) 0xFFFE << 48)
#define V7_TAG_UNDEFINED ((uint64_t) 0xFFFD << 48)
#define V7_TAG_BOOLEAN ((uint64_t) 0xFFFC << 48)
#define V7_TAG_STRING ((uint64_t) 0xFFF9 << 48)
#define V7_TAG_NAN ((uint64_t) 0xFFF8 << 48)
#define V7_TAG_MASK ((uint64_t) 0xFFFF << 48)
#define V7_NULL V7_TAG_FOREIGN
#define V7_UNDEFINED V7_TAG_UNDEFINED
#define V7_SET_NAN(v) \
do { \
* (uint64_t *) &v = V7_TAG_NAN; \
} while(0) \
double v7_value_to_double(v7_value v);
int v7_is_double(v7_value v) {
v7_value nan;
V7_SET_NAN(nan);
return !(isnan(v7_value_to_double(v)) && v != nan);
}
int v7_is_object(v7_value v) {
return (v & V7_TAG_MASK) == V7_TAG_OBJECT;
}
int v7_is_boolean(v7_value v) {
return (v & V7_TAG_MASK) == V7_TAG_BOOLEAN;
}
int v7_is_null(v7_value v) {
return v == V7_NULL;
}
int v7_is_undefined(v7_value v) {
return v == V7_UNDEFINED;
}
static v7_value v7_pointer_to_value(void *p) {
return ((uint64_t) p & ((1L << 48) -1));
}
static void *v7_value_to_pointer(v7_value v) {
struct {uint64_t s:48;} h;
return (void *) (h.s = v);
}
v7_value v7_object_to_value(struct v7_object *o) {
return v7_pointer_to_value(o) | V7_TAG_OBJECT;
}
struct v7_object *v7_value_to_object(v7_value v) {
return (struct v7_object *) v7_value_to_pointer(v);
}
v7_value v7_foreign_to_value(struct v7_object *o) {
return v7_pointer_to_value(o) | V7_TAG_FOREIGN;
}
void *v7_value_to_foreign(v7_value v) {
return v7_value_to_pointer(v);
}
v7_value v7_string_to_value(struct v7_str *s) {
return v7_pointer_to_value(s) | V7_TAG_STRING;
}
struct v7_str *v7_value_to_string(v7_value v) {
return (struct v7_str *) v7_value_to_pointer(v);
}
v7_value v7_double_to_value(double v) {
v7_value res;
/* not every NaN is a JS NaN */
if (isnan(v)) {
V7_SET_NAN(res);
} else {
* (double *) &res = v;
}
return res;
}
double v7_value_to_double(v7_value v) {
return * (double *) &v;
}
v7_value v7_boolean_to_value(int v) {
return (!!v) | V7_TAG_BOOLEAN;
}
int v7_value_to_boolean(v7_value v) {
return v & 1;
}
/* DUMMY */
struct v7_object {
int dummy;
};
struct v7_str {
int dummy;
};
/* DEMO*/
#define ENTRY(expr) { # expr, expr }
/*
* Generates the following x86_64 machine code:
* mulsd %xmm0, %xmm0
* retq
*/
double dsquare(double v) {
return v * v;
}
/*
* Generates the following x86_64 machine code:
* movd %rdi, %xmm0
* mulsd %xmm0, %xmm0
* ucomisd %xmm0, %xmm0
* jp LBB12_1
* movd %xmm0, %rax
* retq
* LBB12_1:
* movabsq $-2251799813685248, %rax ## imm = 0xFFF8000000000000
* retq
*
* Since we don't know which kind of NaN values will be generated
* by the various platforms, we play safe and convert any arithmetic
* NaN into a canonical NaN.
*/
v7_value square(v7_value v) {
return v7_double_to_value(v7_value_to_double(v) * v7_value_to_double(v));
}
int main(void) {
struct v7_object obj = {};
struct v7_str str = {};
v7_value two = v7_double_to_value(2.0);
struct {
const char *expr;
v7_value value;
} values[] = {
ENTRY(v7_object_to_value(&obj)),
ENTRY(v7_string_to_value(&str)),
ENTRY(v7_double_to_value(42.24)),
ENTRY(v7_double_to_value(atof("nan"))),
ENTRY(v7_double_to_value(atof("-nan"))),
ENTRY(v7_double_to_value(atof("inf"))),
ENTRY(v7_double_to_value(atof("-inf"))),
ENTRY(v7_boolean_to_value(1)),
ENTRY(v7_boolean_to_value(0)),
ENTRY(V7_NULL),
ENTRY(V7_UNDEFINED),
ENTRY(v7_double_to_value(v7_value_to_double(two) * v7_value_to_double(two))),
};
int i;
printf("&obj = %p\n", &obj);
printf("&str = %p\n", &str);
for (i = 0; i < (int) (sizeof(values)/sizeof(values[0])); i++) {
printf("%s:\n\t", values[i].expr);
v7_value v = values[i].value;
if (v7_is_double(v)) {
printf("double value %lg\n", v7_value_to_double(v));
} else if (v7_is_object(v)) {
printf("object %p\n", v7_value_to_object(v));
} else if (v7_is_boolean(v)) {
printf("bool %d\n", v7_value_to_boolean(v));
} else if (v7_is_null(v)) {
printf("null\n");
} else if (v7_is_undefined(v)) {
printf("undefined\n");
} else {
printf("other value 0x%llx\n", v);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment