-
-
Save mkmik/6dd7d1e728d436b993b3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
&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)): |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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