diff --git a/cmake/BuildLibYAML.cmake b/cmake/BuildLibYAML.cmake
index 50e66a35863cafc7274f16016e17ba5a7d1cdc52..01eb6116d74420ef98463cf494eb362fbb6a9e33 100644
--- a/cmake/BuildLibYAML.cmake
+++ b/cmake/BuildLibYAML.cmake
@@ -1,7 +1,7 @@
 #
 # A macro to build the bundled liblua-yaml
 macro(libyaml_build)
-    set(yaml_src ${PROJECT_SOURCE_DIR}/third_party/lua-yaml/lyaml.c
+    set(yaml_src ${PROJECT_SOURCE_DIR}/third_party/lua-yaml/lyaml.cc
 	             ${PROJECT_SOURCE_DIR}/third_party/lua-yaml/api.c
 	             ${PROJECT_SOURCE_DIR}/third_party/lua-yaml/dumper.c
 	             ${PROJECT_SOURCE_DIR}/third_party/lua-yaml/emitter.c
@@ -14,6 +14,10 @@ macro(libyaml_build)
 
     set_source_files_properties(${yaml_src} PROPERTIES COMPILE_FLAGS
         "-std=c99")
+    set_source_files_properties(
+        ${PROJECT_SOURCE_DIR}/third_party/lua-yaml/lyaml.cc
+        PROPERTIES COMPILE_FLAGS
+        "-std=gnu++0x -D__STDC_FORMAT_MACROS=1 -D__STDC_LIMIT_MACROS=1")
 
     add_library(yaml STATIC ${yaml_src})
 
diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt
index 43f9dfecea96e4fddcb33a8438fd901743f2b222..0dac09813a5628e03946c0167fd40954ae6617c6 100644
--- a/src/box/CMakeLists.txt
+++ b/src/box/CMakeLists.txt
@@ -9,6 +9,7 @@ lua_source(lua_sources lua/schema.lua)
 lua_source(lua_sources lua/box.lua)
 lua_source(lua_sources lua/box_net.lua)
 lua_source(lua_sources lua/misc.lua)
+lua_source(lua_sources lua/tuple.lua)
 
 add_custom_target(box_generate_lua_sources
     WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src/box
diff --git a/src/box/lua/call.cc b/src/box/lua/call.cc
index 9f68a0d3e78eabdae43d0eaee548bc8ff2d34b77..d112dd06f02338a249a25b06a233da73198ef6ab 100644
--- a/src/box/lua/call.cc
+++ b/src/box/lua/call.cc
@@ -168,9 +168,7 @@ port_add_lua_multret(struct port *port, struct lua_State *L)
 		 */
 		lua_pushnil(L);
 		int has_keys = lua_next(L, 1);
-		if (has_keys  &&
-		    (lua_istable(L, -1) || lua_isuserdata(L, -1))) {
-
+		if (has_keys  && (lua_istable(L, -1) || lua_istuple(L, -1))) {
 			do {
 				port_add_lua_ret(port, L, lua_gettop(L));
 				lua_pop(L, 1);
diff --git a/src/box/lua/tuple.cc b/src/box/lua/tuple.cc
index 5c71c113b21c94cded5f9511a5b39d29c00e9f27..d8522df9340539eb2230992622951fa31b0706ae 100644
--- a/src/box/lua/tuple.cc
+++ b/src/box/lua/tuple.cc
@@ -35,6 +35,9 @@
 #include "lua/utils.h"
 #include "lua/msgpack.h"
 #include "third_party/lua-yaml/lyaml.h"
+extern "C" {
+#include <lj_obj.h>
+}
 
 /** {{{ box.tuple Lua library
  *
@@ -52,26 +55,39 @@ static const char *tuplelib_name = "box.tuple";
 static const char *tuple_iteratorlib_name = "box.tuple.iterator";
 static int tuple_totable_mt_ref = 0; /* a precreated metable for totable() */
 
+extern char tuple_lua[]; /* Lua source */
+
+uint32_t CTID_CONST_STRUCT_TUPLE_REF;
 
 static inline struct tuple *
 lua_checktuple(struct lua_State *L, int narg)
 {
-	struct tuple *t = *(struct tuple **) luaL_checkudata(L, narg, tuplelib_name);
-	assert(t->refs);
-	return t;
+	struct tuple *tuple = lua_istuple(L, narg);
+	if (tuple == NULL)  {
+		luaL_error(L, "Invalid argument #%d (box.tuple expected, got %s)",
+		   narg, lua_typename(L, lua_type(L, narg)));
+	}
+
+	return tuple;
 }
 
 struct tuple *
 lua_istuple(struct lua_State *L, int narg)
 {
-	if (lua_getmetatable(L, narg) == 0)
+	assert(CTID_CONST_STRUCT_TUPLE_REF != 0);
+	uint32_t ctypeid;
+	void *data;
+
+	if (lua_type(L, narg) != LUA_TCDATA)
 		return NULL;
-	luaL_getmetatable(L, tuplelib_name);
-	struct tuple *tuple = 0;
-	if (lua_equal(L, -1, -2))
-		tuple = *(struct tuple **) lua_touserdata(L, narg);
-	lua_pop(L, 2);
-	return tuple;
+
+	data = luaL_checkcdata(L, narg, &ctypeid);
+	if (ctypeid != CTID_CONST_STRUCT_TUPLE_REF)
+		return NULL;
+
+	struct tuple *t = *(struct tuple **) data;
+	assert(t->refs);
+	return t;
 }
 
 static int
@@ -164,9 +180,8 @@ lbox_tuple_slice(struct lua_State *L)
 static void
 luamp_encode_extension_box(struct lua_State *L, int idx, struct tbuf *b)
 {
-	if (lua_type(L, idx) == LUA_TUSERDATA &&
-			lua_istuple(L, idx)) {
-		struct tuple *tuple = lua_checktuple(L, idx);
+	struct tuple *tuple = lua_istuple(L, idx);
+	if (tuple != NULL) {
 		tuple_to_tbuf(tuple, b);
 		return;
 	}
@@ -182,8 +197,7 @@ luamp_encode_extension_box(struct lua_State *L, int idx, struct tbuf *b)
 int
 luamp_encodestack(struct lua_State *L, struct tbuf *b, int first, int last)
 {
-	if (first == last && (lua_istable(L, first) ||
-	    (lua_isuserdata(L, first) && lua_istuple(L, first)))) {
+	if (first == last && (lua_istable(L, first) || lua_istuple(L, first))) {
 		/* New format */
 		luamp_encode(L, b, first);
 		return 1;
@@ -442,46 +456,19 @@ lbox_tuple_index(struct lua_State *L)
 	return 1;
 }
 
-static int
-lbox_tuple_tostring(struct lua_State *L)
-{
-	/*
-	 * The method does next things:
-	 * 1. Calls :unpack
-	 * 2. Serializes the result using yaml
-	 * 3. Strips start and end of yaml document symbols
-	 */
-
-	/* unpack */
-	lbox_tuple_totable(L);
-
-	/* serialize */
-	lua_replace(L, 1);
-	yamlL_encode(L);
-
-	/* strip yaml tags */
-	size_t len;
-	const char *str = lua_tolstring(L, -1, &len);
-	assert(strlen(str) == len);
-	const char *s = index(str, '[');
-	const char *e = rindex(str, ']');
-	assert(s != NULL && e != NULL && s + 1 <= e);
-	lua_pushlstring(L, s, e - s + 1);
-	return 1;
-}
-
 void
 lbox_pushtuple(struct lua_State *L, struct tuple *tuple)
 {
 	if (tuple) {
-		struct tuple **ptr = (struct tuple **)
-				lua_newuserdata(L, sizeof(*ptr));
-		luaL_getmetatable(L, tuplelib_name);
-		lua_setmetatable(L, -2);
+		assert(CTID_CONST_STRUCT_TUPLE_REF != 0);
+		struct tuple **ptr = (struct tuple **) luaL_pushcdata(L,
+			CTID_CONST_STRUCT_TUPLE_REF, sizeof(struct tuple *));
 		*ptr = tuple;
+		lua_pushcfunction(L, lbox_tuple_gc);
+		luaL_setcdatagc(L, -2);
 		tuple_ref(tuple, 1);
 	} else {
-		lua_pushnil(L);
+		return lua_pushnil(L);
 	}
 }
 
@@ -535,23 +522,10 @@ lbox_tuple_pairs(struct lua_State *L)
 	return 3;
 }
 
-
-/** tuple:bsize()
- *
- */
-static int
-lbox_tuple_bsize(struct lua_State *L)
-{
-	struct tuple *tuple = lua_checktuple(L, 1);
-	lua_pushnumber(L, tuple->bsize);
-	return 1;
-}
-
 static const struct luaL_reg lbox_tuple_meta[] = {
 	{"__gc", lbox_tuple_gc},
 	{"__len", lbox_tuple_len},
 	{"__index", lbox_tuple_index},
-	{"__tostring", lbox_tuple_tostring},
 	{"next", lbox_tuple_next},
 	{"pairs", lbox_tuple_pairs},
 	{"slice", lbox_tuple_slice},
@@ -560,7 +534,6 @@ static const struct luaL_reg lbox_tuple_meta[] = {
 	{"findall", lbox_tuple_findall},
 	{"unpack", lbox_tuple_unpack},
 	{"totable", lbox_tuple_totable},
-	{"bsize", lbox_tuple_bsize},
 	{NULL, NULL}
 };
 
@@ -598,7 +571,11 @@ lua_totuple(struct lua_State *L, int first, int last)
 void
 box_lua_tuple_init(struct lua_State *L)
 {
-	luaL_register_type(L, tuplelib_name, lbox_tuple_meta);
+	/* export C functions to Lua */
+	luaL_newmetatable(L, tuplelib_name);
+	luaL_register(L, NULL, lbox_tuple_meta);
+	/* save Lua/C functions to the global variable (cleaned by tuple.lua) */
+	lua_setglobal(L, "cfuncs");
 	luaL_register_type(L, tuple_iteratorlib_name,
 			   lbox_tuple_iterator_meta);
 	luaL_register(L, tuplelib_name, lbox_tuplelib);
@@ -614,6 +591,13 @@ box_lua_tuple_init(struct lua_State *L)
 	tuple_totable_mt_ref = luaL_ref(L, LUA_REGISTRYINDEX);
 	assert(tuple_totable_mt_ref != 0);
 
+	if (luaL_dostring(L, tuple_lua))
+		panic("Error loading Lua source %.160s...: %s",
+		      tuple_lua, lua_tostring(L, -1));
+	assert(lua_gettop(L) == 0);
+
+	/* Get CTypeIDs */
+	CTID_CONST_STRUCT_TUPLE_REF = luaL_ctypeid(L, "const struct tuple &");
+
 	box_lua_slab_init(L);
 }
-
diff --git a/src/box/lua/tuple.lua b/src/box/lua/tuple.lua
new file mode 100644
index 0000000000000000000000000000000000000000..c2989d2897f30f87076755eb5865330f158b7ae1
--- /dev/null
+++ b/src/box/lua/tuple.lua
@@ -0,0 +1,57 @@
+-- tuple.lua (internal file)
+
+local ffi = require('ffi')
+local yaml = require('yaml')
+
+ffi.cdef([[
+struct tuple
+{
+    uint32_t _version;
+    uint16_t _refs;
+    uint16_t _format_id;
+    uint32_t _bsize;
+    char data[0];
+} __attribute__((packed));
+]])
+
+local builtin = ffi.C
+
+-- cfuncs table is set by C part
+local methods = {
+    ["next"]        = cfuncs.next;
+    ["pairs"]       = cfuncs.pairs;
+    ["slice"]       = cfuncs.slice;
+    ["transform"]   = cfuncs.transform;
+    ["find"]        = cfuncs.find;
+    ["findall"]     = cfuncs.findall;
+    ["unpack"]      = cfuncs.unpack;
+    ["totable"]     = cfuncs.totable;
+    ["bsize"]       = function(tuple)
+        return tonumber(tuple._bsize)
+    end
+}
+
+local tuple_gc = cfuncs.__gc;
+
+local tuple_field = cfuncs.__index
+ffi.metatype('struct tuple', {
+    __gc = tuple_gc;
+    __len = cfuncs.__len;
+    __tostring = function(tuple)
+        -- Unpack tuple, call yaml.encode, remove yaml header and footer
+        -- 5 = '---\n\n' (header), -6 = '\n...\n' (footer)
+        return yaml.encode(methods.totable(tuple)):sub(5, -6)
+    end;
+    __index = function(tuple, key)
+        if type(key) == "number" then
+            return tuple_field(tuple, key)
+        end
+        return methods[key]
+    end
+})
+
+-- Remove the global variable
+cfuncs = nil
+
+-- export tuple_gc  */
+box.tuple._gc = tuple_gc;
diff --git a/src/lua/utils.c b/src/lua/utils.c
index afcfe948ca33761be5af667fb952f2967b9b8cef..35ca2c10d54a72e3555f86df56c60c5c22b965fa 100644
--- a/src/lua/utils.c
+++ b/src/lua/utils.c
@@ -41,6 +41,8 @@
 #include <lj_ctype.h>
 #include <lj_cdata.h>
 #include <lj_cconv.h>
+#include <lj_lib.h>
+#include <lj_tab.h>
 
 void *
 luaL_pushcdata(struct lua_State *L, uint32_t ctypeid, uint32_t size)
@@ -79,6 +81,61 @@ luaL_checkcdata(struct lua_State *L, int idx, uint32_t *ctypeid)
 	*ctypeid = cd->ctypeid;
 	return (void *)cdataptr(cd);
 }
+
+uint32_t
+luaL_ctypeid(struct lua_State *L, const char *ctypename)
+{
+	int idx = lua_gettop(L);
+	/* This function calls ffi.typeof to determine CDataType */
+
+	/* Get ffi.typeof function */
+	luaL_loadstring(L, "return require('ffi').typeof");
+	lua_call(L, 0, 1);
+	/* FFI must exist */
+	assert(lua_gettop(L) == idx + 1 && lua_isfunction(L, idx + 1));
+	/* Push the first argument to ffi.typeof */
+	lua_pushstring(L, ctypename);
+	/* Call ffi.typeof() */
+	lua_call(L, 1, 1);
+	/* Returned type must be LUA_TCDATA with CTID_CTYPEID */
+	uint32_t ctypetypeid;
+	CTypeID ctypeid = *(CTypeID *)luaL_checkcdata(L, idx + 1, &ctypetypeid);
+	assert(ctypetypeid == CTID_CTYPEID);
+
+	lua_settop(L, idx);
+	return ctypeid;
+}
+
+int
+luaL_setcdatagc(struct lua_State *L, int idx)
+{
+	if (idx < 0)
+		idx = lua_gettop(L) + idx + 1;
+	/* extracted from luajit/src/lib_ffi.c */
+	TValue *o = L->base + idx - 1;
+	assert(o < L->top && tviscdata(o));
+	GCcdata *cd = cdataV(o);
+	TValue *fin = lj_lib_checkany(L, lua_gettop(L));
+	CTState *cts = ctype_cts(L);
+	GCtab *t = cts->finalizer;
+#if !defined(NDEBUG)
+	CType *ct = ctype_raw(cts, cd->ctypeid);
+	assert(ctype_isptr(ct->info) || ctype_isstruct(ct->info) ||
+	       ctype_isrefarray(ct->info));
+#endif /* !defined(NDEBUG) */
+	if (gcref(t->metatable)) {  /* Update finalizer table, if still enabled. */
+		copyTV(L, lj_tab_set(L, t, L->base + idx - 1), fin);
+		lj_gc_anybarriert(L, t);
+		if (!tvisnil(fin))
+			cd->marked |= LJ_GC_CDATA_FIN;
+		else
+		cd->marked &= ~LJ_GC_CDATA_FIN;
+	}
+	lua_pop(L, 1);
+
+	return 1;
+}
+
 #endif /* defined(LUAJIT) */
 
 static void
diff --git a/src/lua/utils.h b/src/lua/utils.h
index 656083abc2ca0c2dbfcdd3da3170493f3ba07c32..55d32e77ad2a692db80742b09b9a71571e904162 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -74,6 +74,28 @@ luaL_pushcdata(struct lua_State *L, uint32_t ctypeid, uint32_t size);
 void *
 luaL_checkcdata(struct lua_State *L, int idx, uint32_t *ctypeid);
 
+/**
+ * @brief Sets finalizer function on a cdata object.
+ * Equivalent to call ffi.gc(obj, function).
+ * Finalizer function must be on the top of the stack.
+ * @param L Lua State
+ * @param idx object
+ * @return 1
+ */
+int
+luaL_setcdatagc(struct lua_State *L, int idx);
+
+/**
+* @brief Return CTypeID (FFI) of given СDATA type
+* @param L Lua State
+* @param ctypename С type name as string (e.g. "struct request" or "uint32_t")
+* @sa luaL_pushcdata
+* @sa luaL_checkcdata
+* @return CTypeID
+*/
+uint32_t
+luaL_ctypeid(struct lua_State *L, const char *ctypename);
+
 #endif /* defined(LUAJIT) */
 
 /** A single value on the Lua stack. */
diff --git a/test/box/misc.result b/test/box/misc.result
index 50709569789b3b4e97c15bff3284bbc74a03b826..d6884ceccc4dea7150d10f1d559a606eb0700d1d 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -493,3 +493,105 @@ space:delete{1}
 space:drop()
 ---
 ...
+----------------
+-- # yaml encode/decode on cdata
+----------------
+ffi = require('ffi')
+---
+...
+ffi.new('uint8_t', 128)
+---
+- 128
+...
+ffi.new('int8_t', -128)
+---
+- -128
+...
+ffi.new('uint16_t', 128)
+---
+- 128
+...
+ffi.new('int16_t', -128)
+---
+- -128
+...
+ffi.new('uint32_t', 128)
+---
+- 128
+...
+ffi.new('int32_t', -128)
+---
+- -128
+...
+ffi.new('uint64_t', 128)
+---
+- 128
+...
+ffi.new('int64_t', -128)
+---
+- -128
+...
+ffi.new('char', 128)
+---
+- -128
+...
+ffi.new('char', -128)
+---
+- -128
+...
+ffi.new('bool', true)
+---
+- true
+...
+ffi.new('bool', false)
+---
+- false
+...
+ffi.new('float', 1.23456)
+---
+- 1.2345600128174
+...
+ffi.new('float', 1e10)
+---
+- 10000000000
+...
+ffi.new('double', 1.23456)
+---
+- 1.23456
+...
+ffi.new('double', 1e10)
+---
+- 10000000000
+...
+ffi.cast('void *', 0)
+---
+- null
+...
+ffi.cast('void *', 0xabcdef)
+---
+- 'cdata<void *>: 0x00abcdef'
+...
+ffi.cdef([[struct test { int a; }; ]])
+---
+...
+ffi.cast('struct test *', 0)
+---
+- 'cdata<struct test *>: NULL'
+...
+--# setopt delimiter ';'
+type(ffi.metatype('struct test', {
+    __index = {
+        totable = function(test)
+            return { 'yaml totable test = ' .. test.a }
+        end
+    }
+}));
+---
+- cdata
+...
+--# setopt delimiter ''
+-- custom totable function will be called by yaml.encode
+ffi.new('struct test', { a = 15 })
+---
+- - yaml totable test = 15
+...
diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua
index 417761580c4304c2d0c10ca98a9581ed92bb9817..6e2f96d8594a6cd8b7fc87706ed11e8ba0784b91 100644
--- a/test/box/misc.test.lua
+++ b/test/box/misc.test.lua
@@ -157,3 +157,47 @@ fifo_top(space, 1)
 space:delete{1}
 
 space:drop()
+
+----------------
+-- # yaml encode/decode on cdata
+----------------
+
+ffi = require('ffi')
+
+ffi.new('uint8_t', 128)
+ffi.new('int8_t', -128)
+ffi.new('uint16_t', 128)
+ffi.new('int16_t', -128)
+ffi.new('uint32_t', 128)
+ffi.new('int32_t', -128)
+ffi.new('uint64_t', 128)
+ffi.new('int64_t', -128)
+
+ffi.new('char', 128)
+ffi.new('char', -128)
+ffi.new('bool', true)
+ffi.new('bool', false)
+
+ffi.new('float', 1.23456)
+ffi.new('float', 1e10)
+ffi.new('double', 1.23456)
+ffi.new('double', 1e10)
+
+ffi.cast('void *', 0)
+ffi.cast('void *', 0xabcdef)
+
+ffi.cdef([[struct test { int a; }; ]])
+ffi.cast('struct test *', 0)
+
+--# setopt delimiter ';'
+type(ffi.metatype('struct test', {
+    __index = {
+        totable = function(test)
+            return { 'yaml totable test = ' .. test.a }
+        end
+    }
+}));
+
+--# setopt delimiter ''
+-- custom totable function will be called by yaml.encode
+ffi.new('struct test', { a = 15 })
diff --git a/test/box/net.box.result b/test/box/net.box.result
index cbd5e4591315a382d824cc30f73cfa8c8718fc91..1870473c8020e8346bc91513f0d820c5545aadd8 100644
--- a/test/box/net.box.result
+++ b/test/box/net.box.result
@@ -185,7 +185,7 @@ tuple
 ...
 type(tuple)
 ---
-- userdata
+- cdata
 ...
 #tuple
 ---
diff --git a/test/box/tuple.result b/test/box/tuple.result
index 8e1900fec31c06933b6ba1828b70b930d2e51f5f..c7bfdd862d45994b569c054ea10fb54ccff743a0 100644
--- a/test/box/tuple.result
+++ b/test/box/tuple.result
@@ -311,8 +311,7 @@ t=space:insert{0, 8989}
 ...
 t[nil]
 ---
-- error: '[string "return t[nil] "]:1: bad argument #2 to ''__index'' (string expected,
-    got nil)'
+- null
 ...
 # test tuple iterators
 ---
@@ -330,7 +329,7 @@ t:next(1)
 ...
 t:next(t)
 ---
-- error: 'bad argument #2 to ''?'' (box.tuple.iterator expected, got userdata)'
+- error: 'tuple.next(): bad arguments'
 ...
 t:next(t:next())
 ---
diff --git a/third_party/lua-yaml/lyaml.c b/third_party/lua-yaml/lyaml.cc
similarity index 96%
rename from third_party/lua-yaml/lyaml.c
rename to third_party/lua-yaml/lyaml.cc
index 3baa167bae1fa40f5fc53d5c96f314e4ba3b7ea3..b94ab2a013f94306ae599cdeea6a953353d35344 100644
--- a/third_party/lua-yaml/lyaml.c
+++ b/third_party/lua-yaml/lyaml.cc
@@ -31,6 +31,7 @@
 #include <stdbool.h>
 #include <inttypes.h>
 
+extern "C" {
 #include <lauxlib.h>
 #include <lua.h>
 #include <lualib.h>
@@ -42,6 +43,7 @@
 
 #include "yaml.h"
 #include "b64.h"
+} /* extern "C" */
 #include "lua/utils.h"
 
 /* configurable flags */
@@ -555,24 +557,32 @@ dump_node(struct lua_yaml_dumper *dumper)
 	luaL_tofield(dumper->L, top, &field);
 
 	/* Unknown type on the stack, try to call 'totable' from metadata */
-	if (field.type == MP_EXT && lua_type(dumper->L, top) == LUA_TUSERDATA &&
-			lua_getmetatable(dumper->L, top)) {
-		/* has metatable, try to call 'totable' and use return value */
-		lua_pushliteral(dumper->L, "totable");
-		lua_rawget(dumper->L, -2);
-		if (lua_isfunction(dumper->L, -1)) {
-			lua_pushvalue(dumper->L, -3); /* copy object itself */
-			lua_call(dumper->L, 1, 1);
-			lua_replace(dumper->L, -3);
-			luaL_tofield(dumper->L, -1, &field);
-		} else {
-			lua_pop(dumper->L, 1); /* pop result */
+	int type = lua_type(dumper->L, top);
+	if (field.type == MP_EXT &&
+	    (type == LUA_TUSERDATA || type == LUA_TCDATA)) {
+		/* try to call 'totable' method on udata/cdata */
+		try {
+			/*
+			 * LuaJIT specific: lua_getfield raises exception on
+			 * cdata objects if field doesn't exist.
+			 */
+			lua_getfield(dumper->L, top, "totable");
+			if (lua_isfunction(dumper->L, -1)) {
+				/* copy object itself */
+				lua_pushvalue(dumper->L, top);
+				lua_call(dumper->L, 1, 1);
+				if (lua_istable(dumper->L, -1)) {
+					/* replace obj with the unpacked table*/
+					lua_replace(dumper->L, top);
+					luaL_tofield(dumper->L, -1, &field);
+				}
+			}
+		} catch (...) {
+			/* ignore lua_getfield exceptions */
 		}
-		lua_pop(dumper->L, 1);  /* pop metatable */
+		lua_settop(dumper->L, top); /* remove temporary objects */
 	}
 
-	luaL_tofield(dumper->L, top, &field);
-
 	/* Still have unknown type on the stack,
 	 * try to call 'tostring' */
 	if (field.type == MP_EXT) {
@@ -846,7 +856,7 @@ static int l_null(lua_State *L) {
    return 1;
 }
 
-LUALIB_API int luaopen_yaml(lua_State *L) {
+extern "C" int luaopen_yaml(lua_State *L) {
    const luaL_reg yamllib[] = {
       { "decode", l_load },
       { "encode", l_dump },
@@ -859,6 +869,6 @@ LUALIB_API int luaopen_yaml(lua_State *L) {
    return 1;
 }
 
-LUALIB_API int yamlL_encode(lua_State *L) {
+extern "C" int yamlL_encode(lua_State *L) {
 	return l_dump(L);
 }