[quickjs-devel] Work on MSVC support

  • From: Sam Hocevar <sam@xxxxxxxxxxx>
  • To: quickjs-devel@xxxxxxxxxxxxx
  • Date: Fri, 6 Sep 2019 00:08:11 +0200

   Hello,

   I needed QuickJS for a personal project and patched a few files so that they
compile with Visual Studio (2017 or later). There is little chance for most of
the changes to ever land upstream, but it could be a starting point for anyone
interested in porting more of it, so I'm leaving it here.

   Attached is a patch; it can also be read on GitHub:

      
https://github.com/horhof/quickjs/compare/master...samhocevar:task/msvc-support

   The files that now build (in C mode) are:

     cutils.c cutils.h
     libbf.c
     libregexp.c
     libunicode.c
     quickjs.c quickjs.h

   Note that quickjs.h also builds properly when included from C++ code using
extern "C", which is slightly more restrictive.

   I did not want to port all the atomic / pthread stuff so I just disabled
CONFIG_ATOMICS.

   This was enough for me to have QuickJS embedded in a C++ application that
builds and runs from Visual Studio using MSVC.

Cheers,
-- 
Sam.
diff --git a/cutils.c b/cutils.c
index 64a32d3..2c2e5bc 100644
--- a/cutils.c
+++ b/cutils.c
@@ -166,8 +166,12 @@ int dbuf_putstr(DynBuf *s, const char *str)
     return dbuf_put(s, (const uint8_t *)str, strlen(str));
 }
 
+#if defined(_MSC_VER)
+int dbuf_printf(DynBuf *s, const char *fmt, ...)
+#else
 int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
                                                       const char *fmt, ...)
+#endif
 {
     va_list ap;
     char buf[128];
@@ -257,6 +261,22 @@ int unicode_from_utf8(const uint8_t *p, int max_len, const 
uint8_t **pp)
         *pp = p;
         return c;
     }
+#if defined(_MSC_VER)
+    else if (c < 0xc0)
+        return -1;
+    else if (c < 0xe0)
+        l = 1;
+    else if (c < 0xf0)
+        l = 2;
+    else if (c < 0xf8)
+        l = 3;
+    else if (c < 0xfc)
+        l = 4;
+    else if (c < 0xfe)
+        l = 5;
+    else
+        return -1;
+#else
     switch(c) {
     case 0xc0 ... 0xdf:
         l = 1;
@@ -276,6 +296,7 @@ int unicode_from_utf8(const uint8_t *p, int max_len, const 
uint8_t **pp)
     default:
         return -1;
     }
+#endif
     /* check that we have enough characters */
     if (l > (max_len - 1))
         return -1;
diff --git a/cutils.h b/cutils.h
index fdbf44a..b09e61a 100644
--- a/cutils.h
+++ b/cutils.h
@@ -27,14 +27,24 @@
 
 #include <stdlib.h>
 #include <inttypes.h>
+#if defined(_MSC_VER)
+#include <intrin.h>
+#endif
 
 /* set if CPU is big endian */
 #undef WORDS_BIGENDIAN
 
+#if defined(_MSC_VER)
+#define likely(x)       (x)
+#define unlikely(x)     (x)
+#define force_inline inline
+#define no_inline
+#else
 #define likely(x)       __builtin_expect(!!(x), 1)
 #define unlikely(x)     __builtin_expect(!!(x), 0)
 #define force_inline inline __attribute__((always_inline))
 #define no_inline __attribute__((noinline))
+#endif
 
 #define xglue(x, y) x ## y
 #define glue(x, y) xglue(x, y)
@@ -113,27 +123,57 @@ static inline int64_t min_int64(int64_t a, int64_t b)
 /* WARNING: undefined if a = 0 */
 static inline int clz32(unsigned int a)
 {
+#if defined(_MSC_VER)
+    unsigned long ret = 0;
+    _BitScanReverse(&ret, a);
+    return (int)ret;
+#else
     return __builtin_clz(a);
+#endif
 }
 
 /* WARNING: undefined if a = 0 */
 static inline int clz64(uint64_t a)
 {
+#if defined(_MSC_VER)
+    unsigned long ret = 0;
+    _BitScanReverse64(&ret, a);
+    return (int)ret;
+#else
     return __builtin_clzll(a);
+#endif
 }
 
 /* WARNING: undefined if a = 0 */
 static inline int ctz32(unsigned int a)
 {
+#if defined(_MSC_VER)
+    unsigned long ret = 0;
+    _BitScanForward(&ret, a);
+    return (int)ret;
+#else
     return __builtin_ctz(a);
+#endif
 }
 
 /* WARNING: undefined if a = 0 */
 static inline int ctz64(uint64_t a)
 {
+#if defined(_MSC_VER)
+    unsigned long ret = 0;
+    _BitScanForward64(&ret, a);
+    return (int)ret;
+#else
     return __builtin_ctzll(a);
+#endif
 }
 
+#if defined(_MSC_VER)
+#pragma pack(push)
+#pragma pack(1)
+#define __attribute__(x) /* */
+#endif
+
 struct __attribute__((packed)) packed_u64 {
     uint64_t v;
 };
@@ -146,6 +186,11 @@ struct __attribute__((packed)) packed_u16 {
     uint16_t v;
 };
 
+#if defined(_MSC_VER)
+#pragma pack(pop)
+#undef __attribute__
+#endif
+
 static inline uint64_t get_u64(const uint8_t *tab)
 {
     return ((const struct packed_u64 *)tab)->v;
@@ -261,8 +306,12 @@ static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
 {
     return dbuf_put(s, (uint8_t *)&val, 8);
 }
+#if defined(_MSC_VER)
+int dbuf_printf(DynBuf *s, const char *fmt, ...);
+#else
 int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
                                                       const char *fmt, ...);
+#endif
 void dbuf_free(DynBuf *s);
 static inline BOOL dbuf_error(DynBuf *s) {
     return s->error;
diff --git a/libbf.c b/libbf.c
index cbabf95..70598e8 100644
--- a/libbf.c
+++ b/libbf.c
@@ -41,7 +41,11 @@
 #define USE_FFT_MUL
 
 //#define inline __attribute__((always_inline))
+#if defined(_MSC_VER)
+#define unused /* */
+#else
 #define unused __attribute__((unused))
+#endif
 
 #ifdef __AVX2__
 #define FFT_MUL_THRESHOLD 100 /* in limbs of the smallest factor */
diff --git a/libregexp.c b/libregexp.c
index ad1e6bf..c691aad 100644
--- a/libregexp.c
+++ b/libregexp.c
@@ -425,7 +425,11 @@ static void re_emit_op_u16(REParseState *s, int op, 
uint32_t val)
     dbuf_put_u16(&s->byte_code, val);
 }
 
+#if defined(_MSC_VER)
+static int re_parse_error(REParseState *s, const char *fmt, ...)
+#else
 static int __attribute__((format(printf, 2, 3))) re_parse_error(REParseState 
*s, const char *fmt, ...)
+#endif
 {
     va_list ap;
     va_start(ap, fmt);
@@ -557,7 +561,11 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
             }
         }
         break;
+#if defined(_MSC_VER)
+    case '0': case '1': case '2': case '3': case '4': case '5': case '6': case 
'7':
+#else
     case '0' ... '7':
+#endif
         c -= '0';
         if (allow_utf16 == 2) {
             /* only accept \0 not followed by digit */
@@ -1383,7 +1391,11 @@ static int re_parse_term(REParseState *s, BOOL 
is_backward_dir)
                 }
             }
             goto normal_char;
+#if defined(_MSC_VER)
+        case '1': case '2': case '3': case '4': case '5': case '6': case '7': 
case '8': case '9':
+#else
         case '1' ... '9':
+#endif
             {
                 const uint8_t *q = ++p;
                 
diff --git a/libunicode.c b/libunicode.c
index 6fe6945..29e4c10 100644
--- a/libunicode.c
+++ b/libunicode.c
@@ -271,7 +271,11 @@ BOOL lre_is_case_ignorable(uint32_t c)
 
 /* character range */
 
+#if defined(_MSC_VER)
+static void cr_dump(CharRange *cr)
+#else
 static __attribute__((unused)) void cr_dump(CharRange *cr)
+#endif
 {
     int i;
     for(i = 0; i < cr->len; i++)
@@ -527,7 +531,17 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
     } else {
         d = unicode_decomp_data + unicode_decomp_table2[idx];
         switch(type) {
+#if defined(_MSC_VER)
+        case DECOMP_TYPE_L1:
+        case DECOMP_TYPE_L2:
+        case DECOMP_TYPE_L3:
+        case DECOMP_TYPE_L4:
+        case DECOMP_TYPE_L5:
+        case DECOMP_TYPE_L6:
+        case DECOMP_TYPE_L7:
+#else
         case DECOMP_TYPE_L1 ... DECOMP_TYPE_L7:
+#endif
             l = type - DECOMP_TYPE_L1 + 1;
             d += (c - code) * l * 2;
             for(i = 0; i < l; i++) {
@@ -535,7 +549,12 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
                     return 0;
             }
             return l;
+#if defined(_MSC_VER)
+        case DECOMP_TYPE_LL1:
+        case DECOMP_TYPE_LL2:
+#else
         case DECOMP_TYPE_LL1 ... DECOMP_TYPE_LL2:
+#endif
             {
                 uint32_t k, p;
                 l = type - DECOMP_TYPE_LL1 + 1;
@@ -551,7 +570,15 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
                 }
             }
             return l;
+#if defined(_MSC_VER)
+        case DECOMP_TYPE_S1:
+        case DECOMP_TYPE_S2:
+        case DECOMP_TYPE_S3:
+        case DECOMP_TYPE_S4:
+        case DECOMP_TYPE_S5:
+#else
         case DECOMP_TYPE_S1 ... DECOMP_TYPE_S5:
+#endif
             l = type - DECOMP_TYPE_S1 + 1;
             d += (c - code) * l;
             for(i = 0; i < l; i++) {
@@ -582,7 +609,18 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
         case DECOMP_TYPE_B18:
             l = 18;
             goto decomp_type_b;
+#if defined(_MSC_VER)
+        case DECOMP_TYPE_B1:
+        case DECOMP_TYPE_B2:
+        case DECOMP_TYPE_B3:
+        case DECOMP_TYPE_B4:
+        case DECOMP_TYPE_B5:
+        case DECOMP_TYPE_B6:
+        case DECOMP_TYPE_B7:
+        case DECOMP_TYPE_B8:
+#else
         case DECOMP_TYPE_B1 ... DECOMP_TYPE_B8:
+#endif
             l = type - DECOMP_TYPE_B1 + 1;
         decomp_type_b:
             {
diff --git a/quickjs-libc.c b/quickjs-libc.c
index 37da67b..4b2fe47 100644
--- a/quickjs-libc.c
+++ b/quickjs-libc.c
@@ -28,18 +28,26 @@
 #include <inttypes.h>
 #include <string.h>
 #include <assert.h>
+#if !defined(_WIN32)
 #include <unistd.h>
+#endif
 #include <errno.h>
 #include <fcntl.h>
+#if !defined(_WIN32)
 #include <sys/time.h>
+#endif
 #include <time.h>
 #include <signal.h>
 #include <limits.h>
 #include <sys/stat.h>
+#if !defined(_WIN32)
 #include <dirent.h>
+#endif
 #if defined(_WIN32)
 #include <windows.h>
 #include <conio.h>
+typedef int64_t ssize_t;
+#define PATH_MAX MAX_PATH
 #else
 #include <dlfcn.h>
 #include <termios.h>
@@ -2067,9 +2075,15 @@ static JSValue js_os_stat(JSContext *ctx, JSValueConst 
this_val,
         JS_DefinePropertyValueStr(ctx, obj, "size",
                                   JS_NewInt64(ctx, st.st_size),
                                   JS_PROP_C_W_E);
+#if defined(_WIN32)
+        JS_DefinePropertyValueStr(ctx, obj, "blocks",
+                                  JS_NewInt64(ctx, 0),
+                                  JS_PROP_C_W_E);
+#else
         JS_DefinePropertyValueStr(ctx, obj, "blocks",
                                   JS_NewInt64(ctx, st.st_blocks),
                                   JS_PROP_C_W_E);
+#endif
 #if defined(__APPLE__)
         JS_DefinePropertyValueStr(ctx, obj, "atime",
                                   JS_NewInt64(ctx, 
timespec_to_ms(&st.st_atimespec)),
@@ -2080,6 +2094,16 @@ static JSValue js_os_stat(JSContext *ctx, JSValueConst 
this_val,
         JS_DefinePropertyValueStr(ctx, obj, "ctime",
                                   JS_NewInt64(ctx, 
timespec_to_ms(&st.st_ctimespec)),
                                   JS_PROP_C_W_E);
+#elif defined(_WIN32)
+        JS_DefinePropertyValueStr(ctx, obj, "atime",
+                                  JS_NewInt64(ctx, 
timespec_to_ms(&st.st_atime)),
+                                  JS_PROP_C_W_E);
+        JS_DefinePropertyValueStr(ctx, obj, "mtime",
+                                  JS_NewInt64(ctx, 
timespec_to_ms(&st.st_mtime)),
+                                  JS_PROP_C_W_E);
+        JS_DefinePropertyValueStr(ctx, obj, "ctime",
+                                  JS_NewInt64(ctx, 
timespec_to_ms(&st.st_ctime)),
+                                  JS_PROP_C_W_E);
 #else
         JS_DefinePropertyValueStr(ctx, obj, "atime",
                                   JS_NewInt64(ctx, 
timespec_to_ms(&st.st_atim)),
@@ -2143,6 +2167,9 @@ static JSValue js_os_readlink(JSContext *ctx, 
JSValueConst this_val,
 static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val,
                              int argc, JSValueConst *argv)
 {
+#if defined(_WIN32)
+       return JS_EXCEPTION; /* FIXME: use FindFirstFile() etc. */
+#else
     const char *path;
     DIR *f;
     struct dirent *d;
@@ -2180,6 +2207,7 @@ static JSValue js_os_readdir(JSContext *ctx, JSValueConst 
this_val,
     closedir(f);
  done:
     return make_obj_error(ctx, obj, err);
+#endif
 }
 
 static void ms_to_timeval(struct timeval *tv, uint64_t v)
@@ -2263,15 +2291,21 @@ static const JSCFunctionListEntry js_os_funcs[] = {
     JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ),
     /* st_mode constants */
     OS_FLAG(S_IFMT),
+#if !defined(_WIN32)
     OS_FLAG(S_IFIFO),
+#endif
     OS_FLAG(S_IFCHR),
     OS_FLAG(S_IFDIR),
+#if !defined(_WIN32)
     OS_FLAG(S_IFBLK),
+#endif
     OS_FLAG(S_IFREG),
+#if !defined(_WIN32)
     OS_FLAG(S_IFSOCK),
     OS_FLAG(S_IFLNK),
     OS_FLAG(S_ISGID),
     OS_FLAG(S_ISUID),
+#endif
     JS_CFUNC_DEF("symlink", 2, js_os_symlink ),
     JS_CFUNC_DEF("readlink", 1, js_os_readlink ),
     JS_CFUNC_DEF("readdir", 1, js_os_readdir ),
diff --git a/quickjs.c b/quickjs.c
index d5c1c83..6156453 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -28,7 +28,9 @@
 #include <inttypes.h>
 #include <string.h>
 #include <assert.h>
+#if !defined(_WIN32)
 #include <sys/time.h>
+#endif
 #include <time.h>
 #include <fenv.h>
 #include <math.h>
@@ -50,6 +52,8 @@
 #define SHORT_OPCODES    1
 #if defined(EMSCRIPTEN)
 #define DIRECT_DISPATCH  0
+#elif defined(_MSC_VER)
+#define DIRECT_DISPATCH  0
 #else
 #define DIRECT_DISPATCH  1
 #endif
@@ -67,7 +71,7 @@
 
 /* define to include Atomics.* operations which depend on the OS
    threads */
-#if !defined(EMSCRIPTEN)
+#if !defined(EMSCRIPTEN) && !defined(_MSC_VER)
 #define CONFIG_ATOMICS
 #endif
 
@@ -102,8 +106,10 @@
 //#define FORCE_GC_AT_MALLOC
 
 #ifdef CONFIG_ATOMICS
+#if !defined(_WIN32)
 #include <pthread.h>
 #include <stdatomic.h>
+#endif
 #include <errno.h>
 #endif
 
@@ -193,7 +199,14 @@ typedef enum JSErrorEnum {
 #define JS_STACK_SIZE_MAX 65536
 #define JS_STRING_LEN_MAX ((1 << 30) - 1)
 
+#if defined(_WIN32)
+#define __exception /* */
+#define unused /* */
+typedef int64_t ssize_t;
+#else
 #define __exception __attribute__((warn_unused_result))
+#define unused __attribute__((unused))
+#endif
 
 typedef struct JSShape JSShape;
 typedef struct JSString JSString;
@@ -688,9 +701,10 @@ typedef struct JSShapeProperty {
 } JSShapeProperty;
 
 struct JSShape {
-    uint32_t prop_hash_end[0]; /* hash table of size hash_mask + 1
-                                  before the start of the structure. */
-    JSRefCountHeader header; /* must come first, 32-bit */
+    union {
+        JSRefCountHeader header; /* must come first, 32-bit */
+        uint32_t prop_hash_end[1];
+    };
     JSGCHeader gc_header; /* must come after JSRefCountHeader, 8-bit */
     /* true if the shape is inserted in the shape hash table. If not,
        JSShape.hash is not valid */
@@ -853,19 +867,23 @@ static __exception int JS_ToArrayLengthFree(JSContext 
*ctx, uint32_t *plen,
                                             JSValue val);
 static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
                              JSValueConst val, int flags, int scope_idx);
+#if defined(_WIN32)
+JSValue JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
+#else
 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext 
*ctx, const char *fmt, ...);
-static __attribute__((unused)) void JS_DumpAtoms(JSRuntime *rt);
-static __attribute__((unused)) void JS_DumpString(JSRuntime *rt,
-                                                  const JSString *p);
-static __attribute__((unused)) void JS_DumpObjectHeader(JSRuntime *rt);
-static __attribute__((unused)) void JS_DumpObject(JSRuntime *rt, JSObject *p);
-static __attribute__((unused)) void JS_DumpValueShort(JSRuntime *rt,
-                                                      JSValueConst val);
-static __attribute__((unused)) void JS_DumpValue(JSContext *ctx, JSValueConst 
val);
-static __attribute__((unused)) void JS_PrintValue(JSContext *ctx,
-                                                  const char *str,
-                                                  JSValueConst val);
-static __attribute__((unused)) void JS_DumpShapes(JSRuntime *rt);
+#endif
+static unused void JS_DumpAtoms(JSRuntime *rt);
+static unused void JS_DumpString(JSRuntime *rt,
+                                 const JSString *p);
+static unused void JS_DumpObjectHeader(JSRuntime *rt);
+static unused void JS_DumpObject(JSRuntime *rt, JSObject *p);
+static unused void JS_DumpValueShort(JSRuntime *rt,
+                                     JSValueConst val);
+static unused void JS_DumpValue(JSContext *ctx, JSValueConst val);
+static unused void JS_PrintValue(JSContext *ctx,
+                                 const char *str,
+                                 JSValueConst val);
+static unused void JS_DumpShapes(JSRuntime *rt);
 static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
                                  int argc, JSValueConst *argv, int magic);
 static void js_array_finalizer(JSRuntime *rt, JSValue val);
@@ -1784,7 +1802,11 @@ static inline BOOL js_check_stack_overflow(JSContext 
*ctx, size_t alloca_size)
 /* Note: OS and CPU dependent */
 static inline uint8_t *js_get_stack_pointer(void)
 {
+#if defined(_MSC_VER)
+    return  _AddressOfReturnAddress();
+#else
     return __builtin_frame_address(0);
+#endif
 }
 
 static inline BOOL js_check_stack_overflow(JSContext *ctx, size_t alloca_size)
@@ -2133,8 +2155,7 @@ static uint32_t hash_string(const JSString *str, uint32_t 
h)
     return h;
 }
 
-static __attribute__((unused)) void JS_DumpString(JSRuntime *rt,
-                                                  const JSString *p)
+static unused void JS_DumpString(JSRuntime *rt, const JSString *p)
 {
     int i, c, sep;
 
@@ -2165,7 +2186,7 @@ static __attribute__((unused)) void 
JS_DumpString(JSRuntime *rt,
     putchar(sep);
 }
 
-static __attribute__((unused)) void JS_DumpAtoms(JSRuntime *rt)
+static unused void JS_DumpAtoms(JSRuntime *rt)
 {
     JSAtomStruct *p;
     int h, i;
@@ -2918,7 +2939,7 @@ static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, 
JSAtom v)
             !(p->len == 0 && p->is_wide_char != 0));
 }
 
-static __attribute__((unused)) void print_atom(JSContext *ctx, JSAtom atom)
+static unused void print_atom(JSContext *ctx, JSAtom atom)
 {
     char buf[ATOM_GET_STR_BUF_SIZE];
     const char *p;
@@ -4234,7 +4255,7 @@ static JSShape *find_hashed_shape_prop(JSRuntime *rt, 
JSShape *sh,
     return NULL;
 }
 
-static __attribute__((unused)) void JS_DumpShape(JSRuntime *rt, int i, JSShape 
*sh)
+static unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)
 {
     char atom_buf[ATOM_GET_STR_BUF_SIZE];
     int j;
@@ -4250,7 +4271,7 @@ static __attribute__((unused)) void 
JS_DumpShape(JSRuntime *rt, int i, JSShape *
     printf("\n");
 }
 
-static __attribute__((unused)) void JS_DumpShapes(JSRuntime *rt)
+static unused void JS_DumpShapes(JSRuntime *rt)
 {
     int i;
     JSShape *sh;
@@ -4332,7 +4353,23 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, 
JSShape *sh, JSClassID clas
         p->prop[0].u.value = JS_UNDEFINED;
         break;
     case JS_CLASS_ARGUMENTS:
+#if defined(_MSC_VER)
+    case JS_CLASS_UINT8C_ARRAY:
+    case JS_CLASS_INT8_ARRAY:
+    case JS_CLASS_UINT8_ARRAY:
+    case JS_CLASS_INT16_ARRAY:
+    case JS_CLASS_UINT16_ARRAY:
+    case JS_CLASS_INT32_ARRAY:
+    case JS_CLASS_UINT32_ARRAY:
+#ifdef CONFIG_BIGNUM
+    case JS_CLASS_BIG_INT64_ARRAY:
+    case JS_CLASS_BIG_UINT64_ARRAY:
+#endif
+    case JS_CLASS_FLOAT32_ARRAY:
+    case JS_CLASS_FLOAT64_ARRAY:
+#else
     case JS_CLASS_UINT8C_ARRAY ... JS_CLASS_FLOAT64_ARRAY:
+#endif
         p->is_exotic = 1;
         p->fast_array = 1;
         p->u.array.u.ptr = NULL;
@@ -6118,7 +6155,11 @@ static JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum 
error_num,
     return ret;
 }
 
+#if defined(_MSC_VER)
+JSValue JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)
+#else
 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext 
*ctx, const char *fmt, ...)
+#endif
 {
     JSValue val;
     va_list ap;
@@ -6129,7 +6170,11 @@ JSValue __attribute__((format(printf, 2, 3))) 
JS_ThrowSyntaxError(JSContext *ctx
     return val;
 }
 
+#if defined(_MSC_VER)
+JSValue JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)
+#else
 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext 
*ctx, const char *fmt, ...)
+#endif
 {
     JSValue val;
     va_list ap;
@@ -6140,7 +6185,11 @@ JSValue __attribute__((format(printf, 2, 3))) 
JS_ThrowTypeError(JSContext *ctx,
     return val;
 }
 
+#if defined(_MSC_VER)
+static int JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char 
*fmt, ...)
+#else
 static int __attribute__((format(printf, 3, 4))) 
JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)
+#endif
 {
     va_list ap;
 
@@ -6168,7 +6217,11 @@ static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int 
flags, JSAtom atom)
     }
 }
 
+#if defined(_MSC_VER)
+JSValue JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)
+#else
 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext 
*ctx, const char *fmt, ...)
+#endif
 {
     JSValue val;
     va_list ap;
@@ -6179,7 +6232,11 @@ JSValue __attribute__((format(printf, 2, 3))) 
JS_ThrowReferenceError(JSContext *
     return val;
 }
 
+#if defined(_MSC_VER)
+JSValue JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)
+#else
 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext 
*ctx, const char *fmt, ...)
+#endif
 {
     JSValue val;
     va_list ap;
@@ -6190,7 +6247,11 @@ JSValue __attribute__((format(printf, 2, 3))) 
JS_ThrowRangeError(JSContext *ctx,
     return val;
 }
 
+#if defined(_MSC_VER)
+JSValue JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)
+#else
 JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext 
*ctx, const char *fmt, ...)
+#endif
 {
     JSValue val;
     va_list ap;
@@ -6639,7 +6700,11 @@ static int JS_DefinePrivateField(JSContext *ctx, 
JSValueConst obj,
         JS_ThrowTypeErrorNotASymbol(ctx);
         goto fail;
     }
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+    prop = js_symbol_to_atom(ctx, name);
+#else
     prop = js_symbol_to_atom(ctx, (JSValue)name);
+#endif
     p = JS_VALUE_GET_OBJ(obj);
     prs = find_own_property(&pr, p, prop);
     if (prs) {
@@ -6671,7 +6736,11 @@ static JSValue JS_GetPrivateField(JSContext *ctx, 
JSValueConst obj,
     /* safety check */
     if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))
         return JS_ThrowTypeErrorNotASymbol(ctx);
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+    prop = js_symbol_to_atom(ctx, name);
+#else
     prop = js_symbol_to_atom(ctx, (JSValue)name);
+#endif
     p = JS_VALUE_GET_OBJ(obj);
     prs = find_own_property(&pr, p, prop);
     if (!prs) {
@@ -6698,7 +6767,11 @@ static int JS_SetPrivateField(JSContext *ctx, 
JSValueConst obj,
         JS_ThrowTypeErrorNotASymbol(ctx);
         goto fail;
     }
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+    prop = js_symbol_to_atom(ctx, name);
+#else
     prop = js_symbol_to_atom(ctx, (JSValue)name);
+#endif
     p = JS_VALUE_GET_OBJ(obj);
     prs = find_own_property(&pr, p, prop);
     if (!prs) {
@@ -6788,7 +6861,11 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst 
obj, JSValueConst func)
     if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
         goto not_obj;
     p = JS_VALUE_GET_OBJ(obj);
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+    prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, brand));
+#else
     prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand));
+#endif
     if (!prs) {
         JS_ThrowTypeError(ctx, "invalid brand on object");
         return -1;
@@ -9474,7 +9551,12 @@ static JSValue js_atod(JSContext *ctx, const char *str, 
const char **pp,
     } else {
  no_radix_prefix:
         if (!(flags & ATOD_INT_ONLY) && strstart(p, "Infinity", &p)) {
+#if defined(_MSC_VER)
+            double const zero = 0.0;
+            d = 1.0 / zero;
+#else
             d = 1.0 / 0.0;
+#endif
             goto done;
         }
     }
@@ -9752,7 +9834,7 @@ static JSValue JS_ToNumber(JSContext *ctx, JSValueConst 
val)
     return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
 }
 
-static __attribute__((unused)) JSValue JS_ToIntegerFree(JSContext *ctx, 
JSValue val)
+static unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
 {
     uint32_t tag;
     JSValue ret;
@@ -10821,14 +10903,14 @@ static JSValue JS_ToQuotedString(JSContext *ctx, 
JSValueConst val1)
     return JS_EXCEPTION;
 }
 
-static __attribute__((unused)) void JS_DumpObjectHeader(JSRuntime *rt)
+static unused void JS_DumpObjectHeader(JSRuntime *rt)
 {
     printf("%14s %4s %4s %14s %10s %s\n",
            "ADDRESS", "REFS", "SHRF", "PROTO", "CLASS", "PROPS");
 }
 
 /* for debug only: dump an object without side effect */
-static __attribute__((unused)) void JS_DumpObject(JSRuntime *rt, JSObject *p)
+static unused void JS_DumpObject(JSRuntime *rt, JSObject *p)
 {
     uint32_t i;
     char atom_buf[ATOM_GET_STR_BUF_SIZE];
@@ -10862,7 +10944,13 @@ static __attribute__((unused)) void 
JS_DumpObject(JSRuntime *rt, JSObject *p)
             case JS_CLASS_ARGUMENTS:
                 JS_DumpValueShort(rt, p->u.array.u.values[i]);
                 break;
+#if defined(_MSC_VER)
+            default:
+                if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
+                    p->class_id <= JS_CLASS_FLOAT64_ARRAY)
+#else
             case JS_CLASS_UINT8C_ARRAY ... JS_CLASS_FLOAT64_ARRAY:
+#endif
                 {
                     int size = 1 << typed_array_size_log2(p->class_id);
                     const uint8_t *b = p->u.array.u.uint8_ptr + i * size;
@@ -10920,8 +11008,7 @@ static __attribute__((unused)) void 
JS_DumpObject(JSRuntime *rt, JSObject *p)
     printf("\n");
 }
 
-static __attribute__((unused)) void JS_DumpValueShort(JSRuntime *rt,
-                                                      JSValueConst val)
+static unused void JS_DumpValueShort(JSRuntime *rt, JSValueConst val)
 {
     uint32_t tag = JS_VALUE_GET_NORM_TAG(val);
     const char *str;
@@ -11018,15 +11105,13 @@ static __attribute__((unused)) void 
JS_DumpValueShort(JSRuntime *rt,
     }
 }
 
-static __attribute__((unused)) void JS_DumpValue(JSContext *ctx,
-                                                 JSValueConst val)
+static unused void JS_DumpValue(JSContext *ctx, JSValueConst val)
 {
     JS_DumpValueShort(ctx->rt, val);
 }
 
-static __attribute__((unused)) void JS_PrintValue(JSContext *ctx,
-                                                  const char *str,
-                                                  JSValueConst val)
+static unused void JS_PrintValue(JSContext *ctx, const char *str,
+                                 JSValueConst val)
 {
     printf("%s=", str);
     JS_DumpValueShort(ctx->rt, val);
@@ -11245,7 +11330,7 @@ static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, 
JSValueConst val)
     return JS_ToBigIntFree(ctx, buf, JS_DupValue(ctx, val));
 }
 
-static __attribute__((unused)) JSValue JS_ToBigIntValueFree(JSContext *ctx, 
JSValue val)
+static unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val)
 {
     if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
         return val;
@@ -14606,7 +14691,11 @@ static JSValue js_call_c_function(JSContext *ctx, 
JSValueConst func_obj,
 #else
     sf->js_mode = 0;
 #endif
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+    sf->cur_func = func_obj;
+#else
     sf->cur_func = (JSValue)func_obj;
+#endif
     sf->arg_count = argc;
     arg_buf = argv;
 
@@ -14882,7 +14971,11 @@ static JSValue JS_CallInternal(JSContext *ctx, 
JSValueConst func_obj,
     sf->js_mode = b->js_mode;
     arg_buf = argv;
     sf->arg_count = argc;
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+    sf->cur_func = func_obj;
+#else
     sf->cur_func = (JSValue)func_obj;
+#endif
     init_list_head(&sf->var_ref_list);
     var_refs = p->u.func.var_refs;
 
@@ -18750,17 +18843,23 @@ static void free_token(JSParseState *s, JSToken 
*token)
         JS_FreeValue(s->ctx, token->u.regexp.flags);
         break;
     case TOK_IDENT:
+#if !defined(_MSC_VER)
     case TOK_FIRST_KEYWORD ... TOK_LAST_KEYWORD:
+#endif
     case TOK_PRIVATE_NAME:
         JS_FreeAtom(s->ctx, token->u.ident.atom);
         break;
     default:
+#if defined(_MSC_VER)
+        if (token->val >= TOK_FIRST_KEYWORD &&
+            token->val <= TOK_LAST_KEYWORD)
+            JS_FreeAtom(s->ctx, token->u.ident.atom);
+#endif
         break;
     }
 }
 
-static void __attribute((unused)) dump_token(JSParseState *s,
-                                             const JSToken *token)
+static void unused dump_token(JSParseState *s, const JSToken *token)
 {
     switch(token->val) {
     case TOK_NUMBER:
@@ -18820,7 +18919,11 @@ static void __attribute((unused)) 
dump_token(JSParseState *s,
     }
 }
 
+#if defined(_WIN32)
+int js_parse_error(JSParseState *s, const char *fmt, ...)
+#else
 int __attribute__((format(printf, 2, 3))) js_parse_error(JSParseState *s, 
const char *fmt, ...)
+#endif
 {
     JSContext *ctx = s->ctx;
     va_list ap;
@@ -19290,8 +19393,15 @@ static __exception int next_token(JSParseState *s)
             }
         }
         goto def_token;
+#if defined(_MSC_VER)
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 
'h': case 'i': case 'j': case 'k': case 'l': case 'm':
+    case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 
'u': case 'v': case 'w': case 'x': case 'y': case 'z':
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 
'H': case 'I': case 'J': case 'K': case 'L': case 'M':
+    case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 
'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
+#else
     case 'a' ... 'z':
     case 'A' ... 'Z':
+#endif
     case '_':
     case '$':
         /* identifier */
@@ -19420,7 +19530,11 @@ static __exception int next_token(JSParseState *s)
             goto fail;
         }
         goto parse_number;
+#if defined(_MSC_VER)
+    case '1': case '2': case '3': case '4': case '5': case '6': case '7': case 
'8': case '9':
+#else
     case '1' ... '9':
+#endif
         /* number */
     parse_number:
 #ifdef CONFIG_BIGNUM
@@ -27158,8 +27272,8 @@ static void dump_byte_code(JSContext *ctx, int pass,
     js_free(ctx, bits);
 }
 
-static __attribute__((unused)) void dump_pc2line(JSContext *ctx, const uint8_t 
*buf, int len,
-                                                 int line_num)
+static unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len,
+                                int line_num)
 {
     const uint8_t *p_end, *p_next, *p;
     int pc, v;
@@ -27203,7 +27317,7 @@ static __attribute__((unused)) void 
dump_pc2line(JSContext *ctx, const uint8_t *
     }
 }
 
-static __attribute__((unused)) void js_dump_function_bytecode(JSContext *ctx, 
JSFunctionBytecode *b)
+static unused void js_dump_function_bytecode(JSContext *ctx, 
JSFunctionBytecode *b)
 {
     int i;
     char atom_buf[ATOM_GET_STR_BUF_SIZE];
@@ -31666,7 +31780,7 @@ static void bc_put_u16(BCWriterState *s, uint16_t v)
     dbuf_put_u16(&s->dbuf, v);
 }
 
-static __attribute__((unused)) void bc_put_u32(BCWriterState *s, uint32_t v)
+static unused void bc_put_u32(BCWriterState *s, uint32_t v)
 {
     if (s->byte_swap)
         v = bswap32(v);
@@ -32363,7 +32477,7 @@ static int bc_get_u16(BCReaderState *s, uint16_t *pval)
     return 0;
 }
 
-static __attribute__((unused)) int bc_get_u32(BCReaderState *s, uint32_t *pval)
+static unused int bc_get_u32(BCReaderState *s, uint32_t *pval)
 {
     if (unlikely(s->buf_end - s->ptr < 4)) {
         *pval = 0; /* avoid warning */
@@ -36326,8 +36440,13 @@ static int64_t JS_FlattenIntoArray(JSContext *ctx, 
JSValueConst target,
         if (!JS_IsUndefined(mapperFunction)) {
             JSValueConst args[3] = { element, JS_NewInt64(ctx, sourceIndex), 
source };
             element = JS_Call(ctx, mapperFunction, thisArg, 3, args);
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+            JS_FreeValue(ctx, args[0]);
+            JS_FreeValue(ctx, args[1]);
+#else
             JS_FreeValue(ctx, (JSValue)args[0]);
             JS_FreeValue(ctx, (JSValue)args[1]);
+#endif
             if (JS_IsException(element))
                 return -1;
         }
@@ -37916,7 +38035,11 @@ static JSValue js_string_match(JSContext *ctx, 
JSValueConst this_val,
         str = JS_NewString(ctx, "g");
         if (JS_IsException(str))
             goto fail;
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+        args[args_len++] = str;
+#else
         args[args_len++] = (JSValueConst)str;
+#endif
     }
     rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);
     JS_FreeValue(ctx, str);
@@ -39290,7 +39413,12 @@ static JSValue js_math_min_max(JSContext *ctx, 
JSValueConst this_val,
     uint32_t tag;
 
     if (unlikely(argc == 0)) {
+#if defined(_MSC_VER)
+        double const zero = 0.0;
+        return __JS_NewFloat64(ctx, is_max ? -1.0 / zero : 1.0 / zero);
+#else
         return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
+#endif
     }
 
     tag = JS_VALUE_GET_TAG(argv[0]);
@@ -39445,9 +39573,13 @@ static uint64_t xorshift64star(uint64_t *pstate)
 
 static void js_random_init(JSContext *ctx)
 {
+#if defined(_MSC_VER) // FIXME: implement this
+    ctx->random_state = 42;
+#else
     struct timeval tv;
     gettimeofday(&tv, NULL);
     ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
+#endif
     /* the state must be non zero */
     if (ctx->random_state == 0)
         ctx->random_state = 1;
@@ -39465,6 +39597,11 @@ static JSValue js_math_random(JSContext *ctx, 
JSValueConst this_val,
     return __JS_NewFloat64(ctx, u.d - 1.0);
 }
 
+#if defined(_MSC_VER)
+static double const_floor(double x) { return floor(x); }
+static double const_ceil(double x) { return ceil(x); }
+#endif
+
 static const JSCFunctionListEntry js_math_funcs[] = {
     JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
     JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
@@ -39473,8 +39610,13 @@ static const JSCFunctionListEntry js_math_funcs[] = {
 #else
     JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
 #endif
+#if defined(_MSC_VER)
+    JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, const_floor ),
+    JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, const_ceil ),
+#else
     JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
     JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
+#endif
     JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
     JS_CFUNC_SPECIAL_DEF("sqrt", 1, f_f, sqrt ),
 
@@ -39542,9 +39684,13 @@ static JSValue js___date_clock(JSContext *ctx, 
JSValueConst this_val,
                                int argc, JSValueConst *argv)
 {
     int64_t d;
+#if defined(_MSC_VER) // FIXME: implement this
+    d = 42;
+#else
     struct timeval tv;
     gettimeofday(&tv, NULL);
     d = (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+#endif
     return JS_NewInt64(ctx, d);
 }
 
@@ -42048,7 +42194,11 @@ static JSValueConst js_proxy_getPrototypeOf(JSContext 
*ctx, JSValueConst obj)
     }
     /* store the prototype in the proxy so that its refcount is at least 1 */
     set_value(ctx, &s->proto, ret);
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+    return ret;
+#else
     return (JSValueConst)ret;
+#endif
 }
 
 static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
@@ -43280,7 +43430,11 @@ static JSMapRecord *map_add_record(JSContext *ctx, 
JSMapState *s,
     } else {
         JS_DupValue(ctx, key);
     }
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+    mr->key = key;
+#else
     mr->key = (JSValue)key;
+#endif
     h = map_hash_key(ctx, key) & (s->hash_size - 1);
     list_add_tail(&mr->hash_link, &s->hash_table[h]);
     list_add_tail(&mr->link, &s->records);
@@ -43502,7 +43656,11 @@ static JSValue js_map_forEach(JSContext *ctx, 
JSValueConst this_val,
                 args[0] = args[1];
             else
                 args[0] = JS_DupValue(ctx, mr->value);
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+            args[2] = this_val;
+#else
             args[2] = (JSValue)this_val;
+#endif
             ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);
             JS_FreeValue(ctx, args[0]);
             if (!magic)
@@ -44452,7 +44610,11 @@ static JSValue js_promise_all(JSContext *ctx, 
JSValueConst this_val,
                 goto fail_reject;
             }
             resolve_element_data[0] = JS_NewBool(ctx, FALSE);
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+            resolve_element_data[1] = JS_NewInt32(ctx, index);
+#else
             resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);
+#endif
             resolve_element_data[2] = values;
             resolve_element_data[3] = resolving_funcs[0];
             resolve_element_data[4] = resolve_element_env;
@@ -44801,7 +44963,11 @@ static JSValue 
js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,
 {
     JSValueConst func_data[1];
 
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+    func_data[0] = JS_NewBool(ctx, done);
+#else
     func_data[0] = (JSValueConst)JS_NewBool(ctx, done);
+#endif
     return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap,
                                1, 0, 1, func_data);
 }
@@ -45105,7 +45271,11 @@ static int isURIReserved(int c) {
     return c < 0x100 && memchr(";/?:@&=+$,#", c, sizeof(";/?:@&=+$,#") - 1) != 
NULL;
 }
 
+#if defined(_MSC_VER)
+static int js_throw_URIError(JSContext *ctx, const char *fmt, ...)
+#else
 static int __attribute__((format(printf, 2, 3))) js_throw_URIError(JSContext 
*ctx, const char *fmt, ...)
+#endif
 {
     va_list ap;
 
@@ -45718,9 +45888,13 @@ static JSValue get_date_string(JSContext *ctx, 
JSValueConst this_val,
 
 /* OS dependent: return the UTC time in ms since 1970. */
 static int64_t date_now(void) {
+#if defined(_MSC_VER) // FIXME: implement this
+    return 42;
+#else
     struct timeval tv;
     gettimeofday(&tv, NULL);
     return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);
+#endif
 }
 
 static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
@@ -48791,7 +48965,11 @@ struct TA_sort_context {
     JSValueConst arr;
     JSValueConst cmp;
     JSValue (*getfun)(JSContext *ctx, const void *a);
+#if defined(_MSC_VER)
+    char *array_ptr;
+#else
     void *array_ptr; /* cannot change unless the array is detached */
+#endif
     int elt_size;
 };
 
@@ -48836,8 +49014,13 @@ static int js_TA_cmp_generic(const void *a, const void 
*b, void *opaque) {
             psc->exception = 1;
         }
     done:
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+        JS_FreeValue(ctx, argv[0]);
+        JS_FreeValue(ctx, argv[1]);
+#else
         JS_FreeValue(ctx, (JSValue)argv[0]);
         JS_FreeValue(ctx, (JSValue)argv[1]);
+#endif
     }
     return cmp;
 }
diff --git a/quickjs.h b/quickjs.h
index 206516b..a116a7c 100644
--- a/quickjs.h
+++ b/quickjs.h
@@ -53,7 +53,7 @@ typedef struct JSClass JSClass;
 typedef uint32_t JSClassID;
 typedef uint32_t JSAtom;
 
-#if defined(__x86_64__) || defined(__aarch64__)
+#if defined(__x86_64__) || defined(__aarch64__) || defined(_WIN64)
 #define JS_PTR64
 #define JS_PTR64_DEF(a) a
 #else
@@ -185,9 +185,9 @@ static inline int JS_VALUE_GET_NORM_TAG(JSValue v)
 #else /* !JS_NAN_BOXING */
 
 typedef union JSValueUnion {
+    void *ptr;
     int32_t int32;
     double float64;
-    void *ptr;
 } JSValueUnion;
 
 typedef struct JSValue {
@@ -205,8 +205,17 @@ typedef struct JSValue {
 #define JS_VALUE_GET_FLOAT64(v) ((v).u.float64)
 #define JS_VALUE_GET_PTR(v) ((v).u.ptr)
 
+#if defined(_MSC_VER) && defined(__cplusplus)
+#define JS_MKVAL(tag, val) [&](){ JSValue tmp { { (void *)((intptr_t)val << 
32) }, tag }; return tmp; }()
+#define JS_MKPTR(tag, p) [&](){ JSValue tmp { { p }, tag }; return tmp; }()
+#elif defined(_MSC_VER)
+#define JS_VALUE_CANNOT_BE_CAST 1
+#define JS_MKVAL(tag, val) (JSValue){ { (void *)(intptr_t)(val) }, tag }
+#define JS_MKPTR(tag, p) (JSValue){ { p }, tag }
+#else
 #define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }
 #define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag }
+#endif
 
 #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)
 
@@ -586,7 +595,11 @@ static inline JSValue JS_DupValue(JSContext *ctx, 
JSValueConst v)
         JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
         p->ref_count++;
     }
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+    return v;
+#else
     return (JSValue)v;
+#endif
 }
 
 static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)
@@ -595,7 +608,11 @@ static inline JSValue JS_DupValueRT(JSRuntime *rt, 
JSValueConst v)
         JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
         p->ref_count++;
     }
+#if defined(JS_VALUE_CANNOT_BE_CAST)
+    return v;
+#else
     return (JSValue)v;
+#endif
 }
 
 int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION 
*/

Other related posts: