Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
jixieweiren
minigame-unity-webgl-transform
提交
f081aa19
M
minigame-unity-webgl-transform
项目概览
jixieweiren
/
minigame-unity-webgl-transform
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
M
minigame-unity-webgl-transform
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
f081aa19
编写于
12月 28, 2022
作者:
O
oceanxiao
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
add memoryprofiler
上级
bc9e34c6
变更
5
显示空白变更内容
内联
并排
Showing
5 changed file
with
7446 addition
and
7 deletion
+7446
-7
Design/OptimizationMemory.md
Design/OptimizationMemory.md
+4
-4
Design/UsingMemoryProfiler.md
Design/UsingMemoryProfiler.md
+34
-2
README.md
README.md
+1
-1
tools/lauxlib.c
tools/lauxlib.c
+1053
-0
tools/simpledlmalloc.c
tools/simpledlmalloc.c
+6354
-0
未找到文件。
Design/OptimizationMemory.md
浏览文件 @
f081aa19
...
@@ -53,7 +53,7 @@ Unity WebGL是以WebAssembly+WebGL技术为基础的应用,运行在浏览器
...
@@ -53,7 +53,7 @@ Unity WebGL是以WebAssembly+WebGL技术为基础的应用,运行在浏览器
进程级别: Perfdog、Android Studio、 Mac Xcode Instrument
进程级别: Perfdog、Android Studio、 Mac Xcode Instrument
UnityHeap(CPU主内存): 性能面板、
MemoryProfiler
、JavaScript Heap
UnityHeap(CPU主内存): 性能面板、
ProfilingMemory
、JavaScript Heap
引擎与资源:UnityProfiler
引擎与资源:UnityProfiler
...
@@ -111,10 +111,10 @@ Unity引擎视角:
...
@@ -111,10 +111,10 @@ Unity引擎视角:
-
白色为预留部分,可被使用
-
白色为预留部分,可被使用
-
其他颜色,已被业务使用
-
其他颜色,已被业务使用
### 3.3
MemoryProfiler
### 3.3
ProfilingMemory
MemoryProfiler
可以分析UnityHeap底层分配器的分配细节,任何分配都会产生记录,因此我们可以通过该能力分析更详细具体的分配行为。
ProfilingMemory
可以分析UnityHeap底层分配器的分配细节,任何分配都会产生记录,因此我们可以通过该能力分析更详细具体的分配行为。
关于该能力的使用请查阅
[
使用
MemoryProfiler
分析内存
](
UsingMemoryProfiler.md
)
关于该能力的使用请查阅
[
使用
ProfilingMemory
分析内存
](
UsingMemoryProfiler.md
)
### 3.4 Unity Profiler
### 3.4 Unity Profiler
当发现UnityHeap(尤其是Native)占用比较高时,可通过UnityProfiler进一步分析问题所在。关于该工具在微信小游戏的使用请查阅
[
使用 Unity Profiler 性能调优
](
UnityProfiler.md
)
,推荐使用Unity InstantGame版本增强的Profiler功能,下载地址请查阅
[
推荐引擎版本
](
UnityVersion.md
)
。
当发现UnityHeap(尤其是Native)占用比较高时,可通过UnityProfiler进一步分析问题所在。关于该工具在微信小游戏的使用请查阅
[
使用 Unity Profiler 性能调优
](
UnityProfiler.md
)
,推荐使用Unity InstantGame版本增强的Profiler功能,下载地址请查阅
[
推荐引擎版本
](
UnityVersion.md
)
。
...
...
Design/UsingMemoryProfiler.md
浏览文件 @
f081aa19
# 使用
MemoryProfiler
内存分析
# 使用
ProfilingMemory
内存分析
## 概述
## 概述
利用
MemoryProfiler
,我们可以分析UnityHeap(CPU主内存)的详细分配堆栈与统计数值
利用
ProfilingMemory
,我们可以分析UnityHeap(CPU主内存)的详细分配堆栈与统计数值
## 步骤
## 步骤
1.
导出选项时勾选"Profiling Funcs"与"Profiling Memory"
1.
导出选项时勾选"Profiling Funcs"与"Profiling Memory"
...
@@ -56,4 +56,36 @@ Unity 2021:
...
@@ -56,4 +56,36 @@ Unity 2021:
Other: select * from alloc_used where callback not like "%xxx%" or callback not like "%xxx%"
Other: select * from alloc_used where callback not like "%xxx%" or callback not like "%xxx%"
```
```
## 常见问题
### 1. 开启ProflingMemory后非常慢,特别是在有Lua逻辑的情况
-
首先,这是正常情况,因为每次分配内存都会获取堆栈信息导致运行慢
-
Lua会存在大量分配行为,会加重这个问题, 因此我们提供了专门的内存分配器忽略Lua内存,具体做法:
1.
将
[
simpledlmalloc.c
](
../tools/simpledlmalloc.c
)
添加到xLua虚拟机源码目录下参与编译,(和lauxlib.c同一目录)
2.
参考
[
lauxlib.c
](
../tools/lauxlib.c
)
,在lua源码目录下的同名文件中增加
`simple_dlmalloc`
,并修改
`LUALIB_API lua_State *luaL_newstate (void)`
为如下所示
```
C
#include "simpledlmalloc.c"
static void *simple_dlmalloc (void *ud, void *ptr, size_t osize, size_t nsize) {
(void)ud; (void)osize; /* not used */
if (nsize == 0) {
dlfree(ptr);
return NULL;
}
else
return dlrealloc(ptr, nsize);
}
// using other_alloc instead of default dlmalloc to avoid print trace of lua
LUALIB_API lua_State *luaL_newstate (void) {
// lua_State *L = lua_newstate(l_alloc, NULL);
lua_State *L = lua_newstate(simple_dlmalloc, NULL);
if (L) lua_atpanic(L, &panic);
return L;
}
```
### 2. ProfilingMemory在真机上更容易出现内存崩溃
-
ProfilingMemory功能需要额外的内存记录堆栈与相关统计,因此JS侧内存压力会更大
-
不建议在真机上使用该功能,只需要在微信开发者工具上进行分析即可,UnityHeap(CPU主内存)在不同端上的行为基本是一致的
README.md
浏览文件 @
f081aa19
...
@@ -62,7 +62,7 @@
...
@@ -62,7 +62,7 @@
-
[
使用 Android CPU Profiler 性能调优
](
Design/AndroidProfile.md
)
-
[
使用 Android CPU Profiler 性能调优
](
Design/AndroidProfile.md
)
-
[
使用 Unity Profiler 性能调优
](
Design/UnityProfiler.md
)
-
[
使用 Unity Profiler 性能调优
](
Design/UnityProfiler.md
)
-
[
优化Unity WebGL的内存
](
Design/OptimizationMemory.md
)
-
[
优化Unity WebGL的内存
](
Design/OptimizationMemory.md
)
-
[
使用
MemoryProfiler
分析内存
](
Design/UsingMemoryProfiler.md
)
-
[
使用
ProfilingMemory
分析内存
](
Design/UsingMemoryProfiler.md
)
-
[
音频适配优化
](
Design/AudioOptimization.md
)
-
[
音频适配优化
](
Design/AudioOptimization.md
)
-
[
压缩纹理优化
](
Design/CompressedTexture.md
)
-
[
压缩纹理优化
](
Design/CompressedTexture.md
)
-
[
资源优化工具与建议
](
Design/AssetOptimization.md
)
-
[
资源优化工具与建议
](
Design/AssetOptimization.md
)
...
...
tools/lauxlib.c
0 → 100644
浏览文件 @
f081aa19
/*
** $Id: lauxlib.c,v 1.289 2016/12/20 18:37:00 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#define lauxlib_c
#define LUA_LIB
#include "lprefix.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
** This file uses only the official API of Lua.
** Any function declared here could be written as an application function.
*/
#include "lua.h"
#include "lauxlib.h"
/*
** {======================================================
** Traceback
** =======================================================
*/
#define LEVELS1 10
/* size of the first part of the stack */
#define LEVELS2 11
/* size of the second part of the stack */
/*
** search for 'objidx' in table at index -1.
** return 1 + string at top if find a good name.
*/
static
int
findfield
(
lua_State
*
L
,
int
objidx
,
int
level
)
{
if
(
level
==
0
||
!
lua_istable
(
L
,
-
1
))
return
0
;
/* not found */
lua_pushnil
(
L
);
/* start 'next' loop */
while
(
lua_next
(
L
,
-
2
))
{
/* for each pair in table */
if
(
lua_type
(
L
,
-
2
)
==
LUA_TSTRING
)
{
/* ignore non-string keys */
if
(
lua_rawequal
(
L
,
objidx
,
-
1
))
{
/* found object? */
lua_pop
(
L
,
1
);
/* remove value (but keep name) */
return
1
;
}
else
if
(
findfield
(
L
,
objidx
,
level
-
1
))
{
/* try recursively */
lua_remove
(
L
,
-
2
);
/* remove table (but keep name) */
lua_pushliteral
(
L
,
"."
);
lua_insert
(
L
,
-
2
);
/* place '.' between the two names */
lua_concat
(
L
,
3
);
return
1
;
}
}
lua_pop
(
L
,
1
);
/* remove value */
}
return
0
;
/* not found */
}
/*
** Search for a name for a function in all loaded modules
*/
static
int
pushglobalfuncname
(
lua_State
*
L
,
lua_Debug
*
ar
)
{
int
top
=
lua_gettop
(
L
);
lua_getinfo
(
L
,
"f"
,
ar
);
/* push function */
lua_getfield
(
L
,
LUA_REGISTRYINDEX
,
LUA_LOADED_TABLE
);
if
(
findfield
(
L
,
top
+
1
,
2
))
{
const
char
*
name
=
lua_tostring
(
L
,
-
1
);
if
(
strncmp
(
name
,
"_G."
,
3
)
==
0
)
{
/* name start with '_G.'? */
lua_pushstring
(
L
,
name
+
3
);
/* push name without prefix */
lua_remove
(
L
,
-
2
);
/* remove original name */
}
lua_copy
(
L
,
-
1
,
top
+
1
);
/* move name to proper place */
lua_pop
(
L
,
2
);
/* remove pushed values */
return
1
;
}
else
{
lua_settop
(
L
,
top
);
/* remove function and global table */
return
0
;
}
}
static
void
pushfuncname
(
lua_State
*
L
,
lua_Debug
*
ar
)
{
if
(
pushglobalfuncname
(
L
,
ar
))
{
/* try first a global name */
lua_pushfstring
(
L
,
"function '%s'"
,
lua_tostring
(
L
,
-
1
));
lua_remove
(
L
,
-
2
);
/* remove name */
}
else
if
(
*
ar
->
namewhat
!=
'\0'
)
/* is there a name from code? */
lua_pushfstring
(
L
,
"%s '%s'"
,
ar
->
namewhat
,
ar
->
name
);
/* use it */
else
if
(
*
ar
->
what
==
'm'
)
/* main? */
lua_pushliteral
(
L
,
"main chunk"
);
else
if
(
*
ar
->
what
!=
'C'
)
/* for Lua functions, use <file:line> */
lua_pushfstring
(
L
,
"function <%s:%d>"
,
ar
->
short_src
,
ar
->
linedefined
);
else
/* nothing left... */
lua_pushliteral
(
L
,
"?"
);
}
static
int
lastlevel
(
lua_State
*
L
)
{
lua_Debug
ar
;
int
li
=
1
,
le
=
1
;
/* find an upper bound */
while
(
lua_getstack
(
L
,
le
,
&
ar
))
{
li
=
le
;
le
*=
2
;
}
/* do a binary search */
while
(
li
<
le
)
{
int
m
=
(
li
+
le
)
/
2
;
if
(
lua_getstack
(
L
,
m
,
&
ar
))
li
=
m
+
1
;
else
le
=
m
;
}
return
le
-
1
;
}
LUALIB_API
void
luaL_traceback
(
lua_State
*
L
,
lua_State
*
L1
,
const
char
*
msg
,
int
level
)
{
lua_Debug
ar
;
int
top
=
lua_gettop
(
L
);
int
last
=
lastlevel
(
L1
);
int
n1
=
(
last
-
level
>
LEVELS1
+
LEVELS2
)
?
LEVELS1
:
-
1
;
if
(
msg
)
lua_pushfstring
(
L
,
"%s
\n
"
,
msg
);
luaL_checkstack
(
L
,
10
,
NULL
);
lua_pushliteral
(
L
,
"stack traceback:"
);
while
(
lua_getstack
(
L1
,
level
++
,
&
ar
))
{
if
(
n1
--
==
0
)
{
/* too many levels? */
lua_pushliteral
(
L
,
"
\n\t
..."
);
/* add a '...' */
level
=
last
-
LEVELS2
+
1
;
/* and skip to last ones */
}
else
{
lua_getinfo
(
L1
,
"Slnt"
,
&
ar
);
lua_pushfstring
(
L
,
"
\n\t
%s:"
,
ar
.
short_src
);
if
(
ar
.
currentline
>
0
)
lua_pushfstring
(
L
,
"%d:"
,
ar
.
currentline
);
lua_pushliteral
(
L
,
" in "
);
pushfuncname
(
L
,
&
ar
);
if
(
ar
.
istailcall
)
lua_pushliteral
(
L
,
"
\n\t
(...tail calls...)"
);
lua_concat
(
L
,
lua_gettop
(
L
)
-
top
);
}
}
lua_concat
(
L
,
lua_gettop
(
L
)
-
top
);
}
/* }====================================================== */
/*
** {======================================================
** Error-report functions
** =======================================================
*/
LUALIB_API
int
luaL_argerror
(
lua_State
*
L
,
int
arg
,
const
char
*
extramsg
)
{
lua_Debug
ar
;
if
(
!
lua_getstack
(
L
,
0
,
&
ar
))
/* no stack frame? */
return
luaL_error
(
L
,
"bad argument #%d (%s)"
,
arg
,
extramsg
);
lua_getinfo
(
L
,
"n"
,
&
ar
);
if
(
strcmp
(
ar
.
namewhat
,
"method"
)
==
0
)
{
arg
--
;
/* do not count 'self' */
if
(
arg
==
0
)
/* error is in the self argument itself? */
return
luaL_error
(
L
,
"calling '%s' on bad self (%s)"
,
ar
.
name
,
extramsg
);
}
if
(
ar
.
name
==
NULL
)
ar
.
name
=
(
pushglobalfuncname
(
L
,
&
ar
))
?
lua_tostring
(
L
,
-
1
)
:
"?"
;
return
luaL_error
(
L
,
"bad argument #%d to '%s' (%s)"
,
arg
,
ar
.
name
,
extramsg
);
}
static
int
typeerror
(
lua_State
*
L
,
int
arg
,
const
char
*
tname
)
{
const
char
*
msg
;
const
char
*
typearg
;
/* name for the type of the actual argument */
if
(
luaL_getmetafield
(
L
,
arg
,
"__name"
)
==
LUA_TSTRING
)
typearg
=
lua_tostring
(
L
,
-
1
);
/* use the given type name */
else
if
(
lua_type
(
L
,
arg
)
==
LUA_TLIGHTUSERDATA
)
typearg
=
"light userdata"
;
/* special name for messages */
else
typearg
=
luaL_typename
(
L
,
arg
);
/* standard name */
msg
=
lua_pushfstring
(
L
,
"%s expected, got %s"
,
tname
,
typearg
);
return
luaL_argerror
(
L
,
arg
,
msg
);
}
static
void
tag_error
(
lua_State
*
L
,
int
arg
,
int
tag
)
{
typeerror
(
L
,
arg
,
lua_typename
(
L
,
tag
));
}
/*
** The use of 'lua_pushfstring' ensures this function does not
** need reserved stack space when called.
*/
LUALIB_API
void
luaL_where
(
lua_State
*
L
,
int
level
)
{
lua_Debug
ar
;
if
(
lua_getstack
(
L
,
level
,
&
ar
))
{
/* check function at level */
lua_getinfo
(
L
,
"Sl"
,
&
ar
);
/* get info about it */
if
(
ar
.
currentline
>
0
)
{
/* is there info? */
lua_pushfstring
(
L
,
"%s:%d: "
,
ar
.
short_src
,
ar
.
currentline
);
return
;
}
}
lua_pushfstring
(
L
,
""
);
/* else, no information available... */
}
/*
** Again, the use of 'lua_pushvfstring' ensures this function does
** not need reserved stack space when called. (At worst, it generates
** an error with "stack overflow" instead of the given message.)
*/
LUALIB_API
int
luaL_error
(
lua_State
*
L
,
const
char
*
fmt
,
...)
{
va_list
argp
;
va_start
(
argp
,
fmt
);
luaL_where
(
L
,
1
);
lua_pushvfstring
(
L
,
fmt
,
argp
);
va_end
(
argp
);
lua_concat
(
L
,
2
);
return
lua_error
(
L
);
}
LUALIB_API
int
luaL_fileresult
(
lua_State
*
L
,
int
stat
,
const
char
*
fname
)
{
int
en
=
errno
;
/* calls to Lua API may change this value */
if
(
stat
)
{
lua_pushboolean
(
L
,
1
);
return
1
;
}
else
{
lua_pushnil
(
L
);
if
(
fname
)
lua_pushfstring
(
L
,
"%s: %s"
,
fname
,
strerror
(
en
));
else
lua_pushstring
(
L
,
strerror
(
en
));
lua_pushinteger
(
L
,
en
);
return
3
;
}
}
#if !defined(l_inspectstat)
/* { */
#if defined(LUA_USE_POSIX)
#include <sys/wait.h>
/*
** use appropriate macros to interpret 'pclose' return status
*/
#define l_inspectstat(stat,what) \
if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \
else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; }
#else
#define l_inspectstat(stat,what)
/* no op */
#endif
#endif
/* } */
LUALIB_API
int
luaL_execresult
(
lua_State
*
L
,
int
stat
)
{
const
char
*
what
=
"exit"
;
/* type of termination */
if
(
stat
==
-
1
)
/* error? */
return
luaL_fileresult
(
L
,
0
,
NULL
);
else
{
l_inspectstat
(
stat
,
what
);
/* interpret result */
if
(
*
what
==
'e'
&&
stat
==
0
)
/* successful termination? */
lua_pushboolean
(
L
,
1
);
else
lua_pushnil
(
L
);
lua_pushstring
(
L
,
what
);
lua_pushinteger
(
L
,
stat
);
return
3
;
/* return true/nil,what,code */
}
}
/* }====================================================== */
/*
** {======================================================
** Userdata's metatable manipulation
** =======================================================
*/
LUALIB_API
int
luaL_newmetatable
(
lua_State
*
L
,
const
char
*
tname
)
{
if
(
luaL_getmetatable
(
L
,
tname
)
!=
LUA_TNIL
)
/* name already in use? */
return
0
;
/* leave previous value on top, but return 0 */
lua_pop
(
L
,
1
);
lua_createtable
(
L
,
0
,
2
);
/* create metatable */
lua_pushstring
(
L
,
tname
);
lua_setfield
(
L
,
-
2
,
"__name"
);
/* metatable.__name = tname */
lua_pushvalue
(
L
,
-
1
);
lua_setfield
(
L
,
LUA_REGISTRYINDEX
,
tname
);
/* registry.name = metatable */
return
1
;
}
LUALIB_API
void
luaL_setmetatable
(
lua_State
*
L
,
const
char
*
tname
)
{
luaL_getmetatable
(
L
,
tname
);
lua_setmetatable
(
L
,
-
2
);
}
LUALIB_API
void
*
luaL_testudata
(
lua_State
*
L
,
int
ud
,
const
char
*
tname
)
{
void
*
p
=
lua_touserdata
(
L
,
ud
);
if
(
p
!=
NULL
)
{
/* value is a userdata? */
if
(
lua_getmetatable
(
L
,
ud
))
{
/* does it have a metatable? */
luaL_getmetatable
(
L
,
tname
);
/* get correct metatable */
if
(
!
lua_rawequal
(
L
,
-
1
,
-
2
))
/* not the same? */
p
=
NULL
;
/* value is a userdata with wrong metatable */
lua_pop
(
L
,
2
);
/* remove both metatables */
return
p
;
}
}
return
NULL
;
/* value is not a userdata with a metatable */
}
LUALIB_API
void
*
luaL_checkudata
(
lua_State
*
L
,
int
ud
,
const
char
*
tname
)
{
void
*
p
=
luaL_testudata
(
L
,
ud
,
tname
);
if
(
p
==
NULL
)
typeerror
(
L
,
ud
,
tname
);
return
p
;
}
/* }====================================================== */
/*
** {======================================================
** Argument check functions
** =======================================================
*/
LUALIB_API
int
luaL_checkoption
(
lua_State
*
L
,
int
arg
,
const
char
*
def
,
const
char
*
const
lst
[])
{
const
char
*
name
=
(
def
)
?
luaL_optstring
(
L
,
arg
,
def
)
:
luaL_checkstring
(
L
,
arg
);
int
i
;
for
(
i
=
0
;
lst
[
i
];
i
++
)
if
(
strcmp
(
lst
[
i
],
name
)
==
0
)
return
i
;
return
luaL_argerror
(
L
,
arg
,
lua_pushfstring
(
L
,
"invalid option '%s'"
,
name
));
}
/*
** Ensures the stack has at least 'space' extra slots, raising an error
** if it cannot fulfill the request. (The error handling needs a few
** extra slots to format the error message. In case of an error without
** this extra space, Lua will generate the same 'stack overflow' error,
** but without 'msg'.)
*/
LUALIB_API
void
luaL_checkstack
(
lua_State
*
L
,
int
space
,
const
char
*
msg
)
{
if
(
!
lua_checkstack
(
L
,
space
))
{
if
(
msg
)
luaL_error
(
L
,
"stack overflow (%s)"
,
msg
);
else
luaL_error
(
L
,
"stack overflow"
);
}
}
LUALIB_API
void
luaL_checktype
(
lua_State
*
L
,
int
arg
,
int
t
)
{
if
(
lua_type
(
L
,
arg
)
!=
t
)
tag_error
(
L
,
arg
,
t
);
}
LUALIB_API
void
luaL_checkany
(
lua_State
*
L
,
int
arg
)
{
if
(
lua_type
(
L
,
arg
)
==
LUA_TNONE
)
luaL_argerror
(
L
,
arg
,
"value expected"
);
}
LUALIB_API
const
char
*
luaL_checklstring
(
lua_State
*
L
,
int
arg
,
size_t
*
len
)
{
const
char
*
s
=
lua_tolstring
(
L
,
arg
,
len
);
if
(
!
s
)
tag_error
(
L
,
arg
,
LUA_TSTRING
);
return
s
;
}
LUALIB_API
const
char
*
luaL_optlstring
(
lua_State
*
L
,
int
arg
,
const
char
*
def
,
size_t
*
len
)
{
if
(
lua_isnoneornil
(
L
,
arg
))
{
if
(
len
)
*
len
=
(
def
?
strlen
(
def
)
:
0
);
return
def
;
}
else
return
luaL_checklstring
(
L
,
arg
,
len
);
}
LUALIB_API
lua_Number
luaL_checknumber
(
lua_State
*
L
,
int
arg
)
{
int
isnum
;
lua_Number
d
=
lua_tonumberx
(
L
,
arg
,
&
isnum
);
if
(
!
isnum
)
tag_error
(
L
,
arg
,
LUA_TNUMBER
);
return
d
;
}
LUALIB_API
lua_Number
luaL_optnumber
(
lua_State
*
L
,
int
arg
,
lua_Number
def
)
{
return
luaL_opt
(
L
,
luaL_checknumber
,
arg
,
def
);
}
static
void
interror
(
lua_State
*
L
,
int
arg
)
{
if
(
lua_isnumber
(
L
,
arg
))
luaL_argerror
(
L
,
arg
,
"number has no integer representation"
);
else
tag_error
(
L
,
arg
,
LUA_TNUMBER
);
}
LUALIB_API
lua_Integer
luaL_checkinteger
(
lua_State
*
L
,
int
arg
)
{
int
isnum
;
lua_Integer
d
=
lua_tointegerx
(
L
,
arg
,
&
isnum
);
if
(
!
isnum
)
{
interror
(
L
,
arg
);
}
return
d
;
}
LUALIB_API
lua_Integer
luaL_optinteger
(
lua_State
*
L
,
int
arg
,
lua_Integer
def
)
{
return
luaL_opt
(
L
,
luaL_checkinteger
,
arg
,
def
);
}
/* }====================================================== */
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
/* userdata to box arbitrary data */
typedef
struct
UBox
{
void
*
box
;
size_t
bsize
;
}
UBox
;
static
void
*
resizebox
(
lua_State
*
L
,
int
idx
,
size_t
newsize
)
{
void
*
ud
;
lua_Alloc
allocf
=
lua_getallocf
(
L
,
&
ud
);
UBox
*
box
=
(
UBox
*
)
lua_touserdata
(
L
,
idx
);
void
*
temp
=
allocf
(
ud
,
box
->
box
,
box
->
bsize
,
newsize
);
if
(
temp
==
NULL
&&
newsize
>
0
)
{
/* allocation error? */
resizebox
(
L
,
idx
,
0
);
/* free buffer */
luaL_error
(
L
,
"not enough memory for buffer allocation"
);
}
box
->
box
=
temp
;
box
->
bsize
=
newsize
;
return
temp
;
}
static
int
boxgc
(
lua_State
*
L
)
{
resizebox
(
L
,
1
,
0
);
return
0
;
}
static
void
*
newbox
(
lua_State
*
L
,
size_t
newsize
)
{
UBox
*
box
=
(
UBox
*
)
lua_newuserdata
(
L
,
sizeof
(
UBox
));
box
->
box
=
NULL
;
box
->
bsize
=
0
;
if
(
luaL_newmetatable
(
L
,
"LUABOX"
))
{
/* creating metatable? */
lua_pushcfunction
(
L
,
boxgc
);
lua_setfield
(
L
,
-
2
,
"__gc"
);
/* metatable.__gc = boxgc */
}
lua_setmetatable
(
L
,
-
2
);
return
resizebox
(
L
,
-
1
,
newsize
);
}
/*
** check whether buffer is using a userdata on the stack as a temporary
** buffer
*/
#define buffonstack(B) ((B)->b != (B)->initb)
/*
** returns a pointer to a free area with at least 'sz' bytes
*/
LUALIB_API
char
*
luaL_prepbuffsize
(
luaL_Buffer
*
B
,
size_t
sz
)
{
lua_State
*
L
=
B
->
L
;
if
(
B
->
size
-
B
->
n
<
sz
)
{
/* not enough space? */
char
*
newbuff
;
size_t
newsize
=
B
->
size
*
2
;
/* double buffer size */
if
(
newsize
-
B
->
n
<
sz
)
/* not big enough? */
newsize
=
B
->
n
+
sz
;
if
(
newsize
<
B
->
n
||
newsize
-
B
->
n
<
sz
)
luaL_error
(
L
,
"buffer too large"
);
/* create larger buffer */
if
(
buffonstack
(
B
))
newbuff
=
(
char
*
)
resizebox
(
L
,
-
1
,
newsize
);
else
{
/* no buffer yet */
newbuff
=
(
char
*
)
newbox
(
L
,
newsize
);
memcpy
(
newbuff
,
B
->
b
,
B
->
n
*
sizeof
(
char
));
/* copy original content */
}
B
->
b
=
newbuff
;
B
->
size
=
newsize
;
}
return
&
B
->
b
[
B
->
n
];
}
LUALIB_API
void
luaL_addlstring
(
luaL_Buffer
*
B
,
const
char
*
s
,
size_t
l
)
{
if
(
l
>
0
)
{
/* avoid 'memcpy' when 's' can be NULL */
char
*
b
=
luaL_prepbuffsize
(
B
,
l
);
memcpy
(
b
,
s
,
l
*
sizeof
(
char
));
luaL_addsize
(
B
,
l
);
}
}
LUALIB_API
void
luaL_addstring
(
luaL_Buffer
*
B
,
const
char
*
s
)
{
luaL_addlstring
(
B
,
s
,
strlen
(
s
));
}
LUALIB_API
void
luaL_pushresult
(
luaL_Buffer
*
B
)
{
lua_State
*
L
=
B
->
L
;
lua_pushlstring
(
L
,
B
->
b
,
B
->
n
);
if
(
buffonstack
(
B
))
{
resizebox
(
L
,
-
2
,
0
);
/* delete old buffer */
lua_remove
(
L
,
-
2
);
/* remove its header from the stack */
}
}
LUALIB_API
void
luaL_pushresultsize
(
luaL_Buffer
*
B
,
size_t
sz
)
{
luaL_addsize
(
B
,
sz
);
luaL_pushresult
(
B
);
}
LUALIB_API
void
luaL_addvalue
(
luaL_Buffer
*
B
)
{
lua_State
*
L
=
B
->
L
;
size_t
l
;
const
char
*
s
=
lua_tolstring
(
L
,
-
1
,
&
l
);
if
(
buffonstack
(
B
))
lua_insert
(
L
,
-
2
);
/* put value below buffer */
luaL_addlstring
(
B
,
s
,
l
);
lua_remove
(
L
,
(
buffonstack
(
B
))
?
-
2
:
-
1
);
/* remove value */
}
LUALIB_API
void
luaL_buffinit
(
lua_State
*
L
,
luaL_Buffer
*
B
)
{
B
->
L
=
L
;
B
->
b
=
B
->
initb
;
B
->
n
=
0
;
B
->
size
=
LUAL_BUFFERSIZE
;
}
LUALIB_API
char
*
luaL_buffinitsize
(
lua_State
*
L
,
luaL_Buffer
*
B
,
size_t
sz
)
{
luaL_buffinit
(
L
,
B
);
return
luaL_prepbuffsize
(
B
,
sz
);
}
/* }====================================================== */
/*
** {======================================================
** Reference system
** =======================================================
*/
/* index of free-list header */
#define freelist 0
LUALIB_API
int
luaL_ref
(
lua_State
*
L
,
int
t
)
{
int
ref
;
if
(
lua_isnil
(
L
,
-
1
))
{
lua_pop
(
L
,
1
);
/* remove from stack */
return
LUA_REFNIL
;
/* 'nil' has a unique fixed reference */
}
t
=
lua_absindex
(
L
,
t
);
lua_rawgeti
(
L
,
t
,
freelist
);
/* get first free element */
ref
=
(
int
)
lua_tointeger
(
L
,
-
1
);
/* ref = t[freelist] */
lua_pop
(
L
,
1
);
/* remove it from stack */
if
(
ref
!=
0
)
{
/* any free element? */
lua_rawgeti
(
L
,
t
,
ref
);
/* remove it from list */
lua_rawseti
(
L
,
t
,
freelist
);
/* (t[freelist] = t[ref]) */
}
else
/* no free elements */
ref
=
(
int
)
lua_rawlen
(
L
,
t
)
+
1
;
/* get a new reference */
lua_rawseti
(
L
,
t
,
ref
);
return
ref
;
}
LUALIB_API
void
luaL_unref
(
lua_State
*
L
,
int
t
,
int
ref
)
{
if
(
ref
>=
0
)
{
t
=
lua_absindex
(
L
,
t
);
lua_rawgeti
(
L
,
t
,
freelist
);
lua_rawseti
(
L
,
t
,
ref
);
/* t[ref] = t[freelist] */
lua_pushinteger
(
L
,
ref
);
lua_rawseti
(
L
,
t
,
freelist
);
/* t[freelist] = ref */
}
}
/* }====================================================== */
/*
** {======================================================
** Load functions
** =======================================================
*/
typedef
struct
LoadF
{
int
n
;
/* number of pre-read characters */
FILE
*
f
;
/* file being read */
char
buff
[
BUFSIZ
];
/* area for reading file */
}
LoadF
;
static
const
char
*
getF
(
lua_State
*
L
,
void
*
ud
,
size_t
*
size
)
{
LoadF
*
lf
=
(
LoadF
*
)
ud
;
(
void
)
L
;
/* not used */
if
(
lf
->
n
>
0
)
{
/* are there pre-read characters to be read? */
*
size
=
lf
->
n
;
/* return them (chars already in buffer) */
lf
->
n
=
0
;
/* no more pre-read characters */
}
else
{
/* read a block from file */
/* 'fread' can return > 0 *and* set the EOF flag. If next call to
'getF' called 'fread', it might still wait for user input.
The next check avoids this problem. */
if
(
feof
(
lf
->
f
))
return
NULL
;
*
size
=
fread
(
lf
->
buff
,
1
,
sizeof
(
lf
->
buff
),
lf
->
f
);
/* read block */
}
return
lf
->
buff
;
}
static
int
errfile
(
lua_State
*
L
,
const
char
*
what
,
int
fnameindex
)
{
const
char
*
serr
=
strerror
(
errno
);
const
char
*
filename
=
lua_tostring
(
L
,
fnameindex
)
+
1
;
lua_pushfstring
(
L
,
"cannot %s %s: %s"
,
what
,
filename
,
serr
);
lua_remove
(
L
,
fnameindex
);
return
LUA_ERRFILE
;
}
static
int
skipBOM
(
LoadF
*
lf
)
{
const
char
*
p
=
"
\xEF\xBB\xBF
"
;
/* UTF-8 BOM mark */
int
c
;
lf
->
n
=
0
;
do
{
c
=
getc
(
lf
->
f
);
if
(
c
==
EOF
||
c
!=
*
(
const
unsigned
char
*
)
p
++
)
return
c
;
lf
->
buff
[
lf
->
n
++
]
=
c
;
/* to be read by the parser */
}
while
(
*
p
!=
'\0'
);
lf
->
n
=
0
;
/* prefix matched; discard it */
return
getc
(
lf
->
f
);
/* return next character */
}
/*
** reads the first character of file 'f' and skips an optional BOM mark
** in its beginning plus its first line if it starts with '#'. Returns
** true if it skipped the first line. In any case, '*cp' has the
** first "valid" character of the file (after the optional BOM and
** a first-line comment).
*/
static
int
skipcomment
(
LoadF
*
lf
,
int
*
cp
)
{
int
c
=
*
cp
=
skipBOM
(
lf
);
if
(
c
==
'#'
)
{
/* first line is a comment (Unix exec. file)? */
do
{
/* skip first line */
c
=
getc
(
lf
->
f
);
}
while
(
c
!=
EOF
&&
c
!=
'\n'
);
*
cp
=
getc
(
lf
->
f
);
/* skip end-of-line, if present */
return
1
;
/* there was a comment */
}
else
return
0
;
/* no comment */
}
LUALIB_API
int
luaL_loadfilex
(
lua_State
*
L
,
const
char
*
filename
,
const
char
*
mode
)
{
LoadF
lf
;
int
status
,
readstatus
;
int
c
;
int
fnameindex
=
lua_gettop
(
L
)
+
1
;
/* index of filename on the stack */
if
(
filename
==
NULL
)
{
lua_pushliteral
(
L
,
"=stdin"
);
lf
.
f
=
stdin
;
}
else
{
lua_pushfstring
(
L
,
"@%s"
,
filename
);
lf
.
f
=
fopen
(
filename
,
"r"
);
if
(
lf
.
f
==
NULL
)
return
errfile
(
L
,
"open"
,
fnameindex
);
}
if
(
skipcomment
(
&
lf
,
&
c
))
/* read initial portion */
lf
.
buff
[
lf
.
n
++
]
=
'\n'
;
/* add line to correct line numbers */
if
(
c
==
LUA_SIGNATURE
[
0
]
&&
filename
)
{
/* binary file? */
lf
.
f
=
freopen
(
filename
,
"rb"
,
lf
.
f
);
/* reopen in binary mode */
if
(
lf
.
f
==
NULL
)
return
errfile
(
L
,
"reopen"
,
fnameindex
);
skipcomment
(
&
lf
,
&
c
);
/* re-read initial portion */
}
if
(
c
!=
EOF
)
lf
.
buff
[
lf
.
n
++
]
=
c
;
/* 'c' is the first character of the stream */
status
=
lua_load
(
L
,
getF
,
&
lf
,
lua_tostring
(
L
,
-
1
),
mode
);
readstatus
=
ferror
(
lf
.
f
);
if
(
filename
)
fclose
(
lf
.
f
);
/* close file (even in case of errors) */
if
(
readstatus
)
{
lua_settop
(
L
,
fnameindex
);
/* ignore results from 'lua_load' */
return
errfile
(
L
,
"read"
,
fnameindex
);
}
lua_remove
(
L
,
fnameindex
);
return
status
;
}
typedef
struct
LoadS
{
const
char
*
s
;
size_t
size
;
}
LoadS
;
static
const
char
*
getS
(
lua_State
*
L
,
void
*
ud
,
size_t
*
size
)
{
LoadS
*
ls
=
(
LoadS
*
)
ud
;
(
void
)
L
;
/* not used */
if
(
ls
->
size
==
0
)
return
NULL
;
*
size
=
ls
->
size
;
ls
->
size
=
0
;
return
ls
->
s
;
}
LUALIB_API
int
luaL_loadbufferx
(
lua_State
*
L
,
const
char
*
buff
,
size_t
size
,
const
char
*
name
,
const
char
*
mode
)
{
LoadS
ls
;
ls
.
s
=
buff
;
ls
.
size
=
size
;
return
lua_load
(
L
,
getS
,
&
ls
,
name
,
mode
);
}
LUALIB_API
int
luaL_loadstring
(
lua_State
*
L
,
const
char
*
s
)
{
return
luaL_loadbuffer
(
L
,
s
,
strlen
(
s
),
s
);
}
/* }====================================================== */
LUALIB_API
int
luaL_getmetafield
(
lua_State
*
L
,
int
obj
,
const
char
*
event
)
{
if
(
!
lua_getmetatable
(
L
,
obj
))
/* no metatable? */
return
LUA_TNIL
;
else
{
int
tt
;
lua_pushstring
(
L
,
event
);
tt
=
lua_rawget
(
L
,
-
2
);
if
(
tt
==
LUA_TNIL
)
/* is metafield nil? */
lua_pop
(
L
,
2
);
/* remove metatable and metafield */
else
lua_remove
(
L
,
-
2
);
/* remove only metatable */
return
tt
;
/* return metafield type */
}
}
LUALIB_API
int
luaL_callmeta
(
lua_State
*
L
,
int
obj
,
const
char
*
event
)
{
obj
=
lua_absindex
(
L
,
obj
);
if
(
luaL_getmetafield
(
L
,
obj
,
event
)
==
LUA_TNIL
)
/* no metafield? */
return
0
;
lua_pushvalue
(
L
,
obj
);
lua_call
(
L
,
1
,
1
);
return
1
;
}
LUALIB_API
lua_Integer
luaL_len
(
lua_State
*
L
,
int
idx
)
{
lua_Integer
l
;
int
isnum
;
lua_len
(
L
,
idx
);
l
=
lua_tointegerx
(
L
,
-
1
,
&
isnum
);
if
(
!
isnum
)
luaL_error
(
L
,
"object length is not an integer"
);
lua_pop
(
L
,
1
);
/* remove object */
return
l
;
}
LUALIB_API
const
char
*
luaL_tolstring
(
lua_State
*
L
,
int
idx
,
size_t
*
len
)
{
if
(
luaL_callmeta
(
L
,
idx
,
"__tostring"
))
{
/* metafield? */
if
(
!
lua_isstring
(
L
,
-
1
))
luaL_error
(
L
,
"'__tostring' must return a string"
);
}
else
{
switch
(
lua_type
(
L
,
idx
))
{
case
LUA_TNUMBER
:
{
if
(
lua_isinteger
(
L
,
idx
))
lua_pushfstring
(
L
,
"%I"
,
(
LUAI_UACINT
)
lua_tointeger
(
L
,
idx
));
else
lua_pushfstring
(
L
,
"%f"
,
(
LUAI_UACNUMBER
)
lua_tonumber
(
L
,
idx
));
break
;
}
case
LUA_TSTRING
:
lua_pushvalue
(
L
,
idx
);
break
;
case
LUA_TBOOLEAN
:
lua_pushstring
(
L
,
(
lua_toboolean
(
L
,
idx
)
?
"true"
:
"false"
));
break
;
case
LUA_TNIL
:
lua_pushliteral
(
L
,
"nil"
);
break
;
default:
{
int
tt
=
luaL_getmetafield
(
L
,
idx
,
"__name"
);
/* try name */
const
char
*
kind
=
(
tt
==
LUA_TSTRING
)
?
lua_tostring
(
L
,
-
1
)
:
luaL_typename
(
L
,
idx
);
lua_pushfstring
(
L
,
"%s: %p"
,
kind
,
lua_topointer
(
L
,
idx
));
if
(
tt
!=
LUA_TNIL
)
lua_remove
(
L
,
-
2
);
/* remove '__name' */
break
;
}
}
}
return
lua_tolstring
(
L
,
-
1
,
len
);
}
/*
** {======================================================
** Compatibility with 5.1 module functions
** =======================================================
*/
#if defined(LUA_COMPAT_MODULE)
static
const
char
*
luaL_findtable
(
lua_State
*
L
,
int
idx
,
const
char
*
fname
,
int
szhint
)
{
const
char
*
e
;
if
(
idx
)
lua_pushvalue
(
L
,
idx
);
do
{
e
=
strchr
(
fname
,
'.'
);
if
(
e
==
NULL
)
e
=
fname
+
strlen
(
fname
);
lua_pushlstring
(
L
,
fname
,
e
-
fname
);
if
(
lua_rawget
(
L
,
-
2
)
==
LUA_TNIL
)
{
/* no such field? */
lua_pop
(
L
,
1
);
/* remove this nil */
lua_createtable
(
L
,
0
,
(
*
e
==
'.'
?
1
:
szhint
));
/* new table for field */
lua_pushlstring
(
L
,
fname
,
e
-
fname
);
lua_pushvalue
(
L
,
-
2
);
lua_settable
(
L
,
-
4
);
/* set new table into field */
}
else
if
(
!
lua_istable
(
L
,
-
1
))
{
/* field has a non-table value? */
lua_pop
(
L
,
2
);
/* remove table and value */
return
fname
;
/* return problematic part of the name */
}
lua_remove
(
L
,
-
2
);
/* remove previous table */
fname
=
e
+
1
;
}
while
(
*
e
==
'.'
);
return
NULL
;
}
/*
** Count number of elements in a luaL_Reg list.
*/
static
int
libsize
(
const
luaL_Reg
*
l
)
{
int
size
=
0
;
for
(;
l
&&
l
->
name
;
l
++
)
size
++
;
return
size
;
}
/*
** Find or create a module table with a given name. The function
** first looks at the LOADED table and, if that fails, try a
** global variable with that name. In any case, leaves on the stack
** the module table.
*/
LUALIB_API
void
luaL_pushmodule
(
lua_State
*
L
,
const
char
*
modname
,
int
sizehint
)
{
luaL_findtable
(
L
,
LUA_REGISTRYINDEX
,
LUA_LOADED_TABLE
,
1
);
if
(
lua_getfield
(
L
,
-
1
,
modname
)
!=
LUA_TTABLE
)
{
/* no LOADED[modname]? */
lua_pop
(
L
,
1
);
/* remove previous result */
/* try global variable (and create one if it does not exist) */
lua_pushglobaltable
(
L
);
if
(
luaL_findtable
(
L
,
0
,
modname
,
sizehint
)
!=
NULL
)
luaL_error
(
L
,
"name conflict for module '%s'"
,
modname
);
lua_pushvalue
(
L
,
-
1
);
lua_setfield
(
L
,
-
3
,
modname
);
/* LOADED[modname] = new table */
}
lua_remove
(
L
,
-
2
);
/* remove LOADED table */
}
LUALIB_API
void
luaL_openlib
(
lua_State
*
L
,
const
char
*
libname
,
const
luaL_Reg
*
l
,
int
nup
)
{
luaL_checkversion
(
L
);
if
(
libname
)
{
luaL_pushmodule
(
L
,
libname
,
libsize
(
l
));
/* get/create library table */
lua_insert
(
L
,
-
(
nup
+
1
));
/* move library table to below upvalues */
}
if
(
l
)
luaL_setfuncs
(
L
,
l
,
nup
);
else
lua_pop
(
L
,
nup
);
/* remove upvalues */
}
#endif
/* }====================================================== */
/*
** set functions from list 'l' into table at top - 'nup'; each
** function gets the 'nup' elements at the top as upvalues.
** Returns with only the table at the stack.
*/
LUALIB_API
void
luaL_setfuncs
(
lua_State
*
L
,
const
luaL_Reg
*
l
,
int
nup
)
{
luaL_checkstack
(
L
,
nup
,
"too many upvalues"
);
for
(;
l
->
name
!=
NULL
;
l
++
)
{
/* fill the table with given functions */
int
i
;
for
(
i
=
0
;
i
<
nup
;
i
++
)
/* copy upvalues to the top */
lua_pushvalue
(
L
,
-
nup
);
lua_pushcclosure
(
L
,
l
->
func
,
nup
);
/* closure with those upvalues */
lua_setfield
(
L
,
-
(
nup
+
2
),
l
->
name
);
}
lua_pop
(
L
,
nup
);
/* remove upvalues */
}
/*
** ensure that stack[idx][fname] has a table and push that table
** into the stack
*/
LUALIB_API
int
luaL_getsubtable
(
lua_State
*
L
,
int
idx
,
const
char
*
fname
)
{
if
(
lua_getfield
(
L
,
idx
,
fname
)
==
LUA_TTABLE
)
return
1
;
/* table already there */
else
{
lua_pop
(
L
,
1
);
/* remove previous result */
idx
=
lua_absindex
(
L
,
idx
);
lua_newtable
(
L
);
lua_pushvalue
(
L
,
-
1
);
/* copy to be left at top */
lua_setfield
(
L
,
idx
,
fname
);
/* assign new table to field */
return
0
;
/* false, because did not find table there */
}
}
/*
** Stripped-down 'require': After checking "loaded" table, calls 'openf'
** to open a module, registers the result in 'package.loaded' table and,
** if 'glb' is true, also registers the result in the global table.
** Leaves resulting module on the top.
*/
LUALIB_API
void
luaL_requiref
(
lua_State
*
L
,
const
char
*
modname
,
lua_CFunction
openf
,
int
glb
)
{
luaL_getsubtable
(
L
,
LUA_REGISTRYINDEX
,
LUA_LOADED_TABLE
);
lua_getfield
(
L
,
-
1
,
modname
);
/* LOADED[modname] */
if
(
!
lua_toboolean
(
L
,
-
1
))
{
/* package not already loaded? */
lua_pop
(
L
,
1
);
/* remove field */
lua_pushcfunction
(
L
,
openf
);
lua_pushstring
(
L
,
modname
);
/* argument to open function */
lua_call
(
L
,
1
,
1
);
/* call 'openf' to open module */
lua_pushvalue
(
L
,
-
1
);
/* make copy of module (call result) */
lua_setfield
(
L
,
-
3
,
modname
);
/* LOADED[modname] = module */
}
lua_remove
(
L
,
-
2
);
/* remove LOADED table */
if
(
glb
)
{
lua_pushvalue
(
L
,
-
1
);
/* copy of module */
lua_setglobal
(
L
,
modname
);
/* _G[modname] = module */
}
}
LUALIB_API
const
char
*
luaL_gsub
(
lua_State
*
L
,
const
char
*
s
,
const
char
*
p
,
const
char
*
r
)
{
const
char
*
wild
;
size_t
l
=
strlen
(
p
);
luaL_Buffer
b
;
luaL_buffinit
(
L
,
&
b
);
while
((
wild
=
strstr
(
s
,
p
))
!=
NULL
)
{
luaL_addlstring
(
&
b
,
s
,
wild
-
s
);
/* push prefix */
luaL_addstring
(
&
b
,
r
);
/* push replacement in place of pattern */
s
=
wild
+
l
;
/* continue after 'p' */
}
luaL_addstring
(
&
b
,
s
);
/* push last suffix */
luaL_pushresult
(
&
b
);
return
lua_tostring
(
L
,
-
1
);
}
static
void
*
l_alloc
(
void
*
ud
,
void
*
ptr
,
size_t
osize
,
size_t
nsize
)
{
(
void
)
ud
;
(
void
)
osize
;
/* not used */
if
(
nsize
==
0
)
{
free
(
ptr
);
return
NULL
;
}
else
return
realloc
(
ptr
,
nsize
);
}
#include "simpledlmalloc.c"
static
void
*
simple_dlmalloc
(
void
*
ud
,
void
*
ptr
,
size_t
osize
,
size_t
nsize
)
{
(
void
)
ud
;
(
void
)
osize
;
/* not used */
if
(
nsize
==
0
)
{
dlfree
(
ptr
);
return
NULL
;
}
else
return
dlrealloc
(
ptr
,
nsize
);
}
static
int
panic
(
lua_State
*
L
)
{
lua_writestringerror
(
"PANIC: unprotected error in call to Lua API (%s)
\n
"
,
lua_tostring
(
L
,
-
1
));
return
0
;
/* return to Lua to abort */
}
// using other_alloc instead of default dlmalloc to avoid print trace of lua
LUALIB_API
lua_State
*
luaL_newstate
(
void
)
{
// lua_State *L = lua_newstate(l_alloc, NULL);
lua_State
*
L
=
lua_newstate
(
simple_dlmalloc
,
NULL
);
if
(
L
)
lua_atpanic
(
L
,
&
panic
);
return
L
;
}
LUALIB_API
void
luaL_checkversion_
(
lua_State
*
L
,
lua_Number
ver
,
size_t
sz
)
{
const
lua_Number
*
v
=
lua_version
(
L
);
if
(
sz
!=
LUAL_NUMSIZES
)
/* check numeric types */
luaL_error
(
L
,
"core and library have incompatible numeric types"
);
if
(
v
!=
lua_version
(
NULL
))
luaL_error
(
L
,
"multiple Lua VMs detected"
);
else
if
(
*
v
!=
ver
)
luaL_error
(
L
,
"version mismatch: app. needs %f, Lua core provides %f"
,
(
LUAI_UACNUMBER
)
ver
,
(
LUAI_UACNUMBER
)
*
v
);
}
tools/simpledlmalloc.c
0 → 100644
浏览文件 @
f081aa19
因为 它太大了无法显示 source diff 。你可以改为
查看blob
。
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录