Browse Source

add a DUK_HOBJECT_FLAG_NOTAIL flag and 'use duk notail' directive

pull/20/head
Sami Vaarala 11 years ago
parent
commit
c382af2209
  1. 3
      src/duk_api.c
  2. 25
      src/duk_hobject.h
  3. 3
      src/duk_js_call.c
  4. 17
      src/duk_js_compiler.c
  5. 1
      src/duk_js_compiler.h
  6. 3
      src/duk_js_var.c

3
src/duk_api.c

@ -2802,6 +2802,7 @@ int duk_push_c_function(duk_context *ctx, duk_c_function func, int nargs) {
DUK_HOBJECT_FLAG_NATIVEFUNCTION |
DUK_HOBJECT_FLAG_NEWENV |
DUK_HOBJECT_FLAG_STRICT |
DUK_HOBJECT_FLAG_NOTAIL |
DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
@ -2816,6 +2817,7 @@ void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, int nar
DUK_HOBJECT_FLAG_NATIVEFUNCTION |
DUK_HOBJECT_FLAG_NEWENV |
DUK_HOBJECT_FLAG_STRICT |
DUK_HOBJECT_FLAG_NOTAIL |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
(void) duk__push_c_function_raw(ctx, func, nargs, flags);
@ -2828,6 +2830,7 @@ void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function f
DUK_HOBJECT_FLAG_NATIVEFUNCTION |
DUK_HOBJECT_FLAG_NEWENV |
DUK_HOBJECT_FLAG_STRICT |
DUK_HOBJECT_FLAG_NOTAIL |
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
(void) duk__push_c_function_raw(ctx, func, nargs, flags);

25
src/duk_hobject.h

@ -41,17 +41,17 @@
#define DUK_HOBJECT_FLAG_THREAD DUK_HEAPHDR_USER_FLAG(6) /* object is a thread (duk_hthread) */
#define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(7) /* object has an array part (a_size may still be 0) */
#define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(8) /* function: function object is strict */
#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(9) /* function: create new environment when called (see duk_hcompiledfunction) */
#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(10) /* function: create binding for func name (function templates only, used for named function expressions) */
#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(11) /* function: create an arguments object on function call */
#define DUK_HOBJECT_FLAG_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(12) /* envrec: (declarative) record is closed */
#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(13) /* 'Array' object, array length and index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(14) /* 'String' object, array index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(15) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
#define DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC DUK_HEAPHDR_USER_FLAG(16) /* Duktape/C (nativefunction) object, exotic 'length' */
#define DUK_HOBJECT_FLAG_EXOTIC_BUFFEROBJ DUK_HEAPHDR_USER_FLAG(17) /* 'Buffer' object, array index exotic behavior, virtual 'length' */
#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(18) /* 'Proxy' object */
/* bit 19 unused */
#define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(9) /* function: function must not be tailcalled */
#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(10) /* function: create new environment when called (see duk_hcompiledfunction) */
#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(11) /* function: create binding for func name (function templates only, used for named function expressions) */
#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(12) /* function: create an arguments object on function call */
#define DUK_HOBJECT_FLAG_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(13) /* envrec: (declarative) record is closed */
#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(14) /* 'Array' object, array length and index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(15) /* 'String' object, array index exotic behavior */
#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(16) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
#define DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC DUK_HEAPHDR_USER_FLAG(17) /* Duktape/C (nativefunction) object, exotic 'length' */
#define DUK_HOBJECT_FLAG_EXOTIC_BUFFEROBJ DUK_HEAPHDR_USER_FLAG(18) /* 'Buffer' object, array index exotic behavior, virtual 'length' */
#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(19) /* 'Proxy' object */
/* bit 20 unused */
#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(21)
@ -126,6 +126,7 @@
#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
@ -145,6 +146,7 @@
#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
@ -164,6 +166,7 @@
#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
#define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
#define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
#define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
#define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)

3
src/duk_js_call.c

@ -1890,6 +1890,9 @@ void duk_handle_ecma_call_setup(duk_hthread *thr,
/* See: test-bug-tailcall-preventyield-assert.c. */
DUK_DDD(DUK_DDDPRINT("tailcall prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD"));
use_tailcall = 0;
} else if (DUK_HOBJECT_HAS_NOTAIL(func)) {
DUK_D(DUK_DPRINT("tailcall prevented by function having a notail flag"));
use_tailcall = 0;
}
if (use_tailcall) {

17
src/duk_js_compiler.c

@ -677,6 +677,11 @@ static void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
DUK_HOBJECT_SET_STRICT((duk_hobject *) h_res);
}
if (func->is_notail) {
DUK_DDD(DUK_DDDPRINT("function is notail -> set NOTAIL"));
DUK_HOBJECT_SET_NOTAIL((duk_hobject *) h_res);
}
/*
* Build function fixed size 'data' buffer, which contains bytecode,
* constants, and inner function references.
@ -5877,6 +5882,8 @@ static void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int all
/* XXX: how to compare 'use strict' most compactly?
* We don't necessarily want to add it to the built-ins
* because it's not needed at run time.
* The length comparisons are present to handle
* strings like "use strict\u0000foo" as required.
*/
if (DUK_HSTRING_GET_BYTELEN(h_dir) == 10 &&
@ -5884,6 +5891,11 @@ static void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int all
DUK_DDD(DUK_DDDPRINT("use strict directive detected: strict flag %d -> %d",
comp_ctx->curr_func.is_strict, 1));
comp_ctx->curr_func.is_strict = 1;
} else if (DUK_HSTRING_GET_BYTELEN(h_dir) == 14 &&
DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use duk notail", 14) == 0) {
DUK_DDD(DUK_DDDPRINT("use duk notail directive detected: notail flag %d -> %d",
comp_ctx->curr_func.is_notail, 1));
comp_ctx->curr_func.is_notail = 1;
} else {
DUK_DD(DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating "
"directive prologue", (duk_hobject *) h_dir));
@ -6814,9 +6826,10 @@ static int duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, int is_decl, in
/* inherit initial strictness from parent */
comp_ctx->curr_func.is_strict = old_func.is_strict;
DUK_ASSERT(comp_ctx->curr_func.is_notail == 0);
comp_ctx->curr_func.is_function = 1;
comp_ctx->curr_func.is_eval = 0;
comp_ctx->curr_func.is_global = 0;
DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
comp_ctx->curr_func.is_setget = is_setget;
comp_ctx->curr_func.is_decl = is_decl;

1
src/duk_js_compiler.h

@ -129,6 +129,7 @@ struct duk_compiler_func {
int is_setget; /* is a setter/getter */
int is_decl; /* is a function declaration (as opposed to function expression) */
int is_strict; /* function is strict */
int is_notail; /* function must not be tailcalled */
int in_directive_prologue; /* parsing in "directive prologue", recognize directives */
int in_scanning; /* parsing in "scanning" phase (first pass) */
int may_direct_eval; /* function may call direct eval */

3
src/duk_js_var.c

@ -180,6 +180,9 @@ void duk_js_push_closure(duk_hthread *thr,
if (DUK_HOBJECT_HAS_STRICT(&fun_temp->obj)) {
DUK_HOBJECT_SET_STRICT(&fun_clos->obj);
}
if (DUK_HOBJECT_HAS_NOTAIL(&fun_temp->obj)) {
DUK_HOBJECT_SET_NOTAIL(&fun_clos->obj);
}
/* DUK_HOBJECT_FLAG_NEWENV: handled below */
DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj));
if (DUK_HOBJECT_HAS_CREATEARGS(&fun_temp->obj)) {

Loading…
Cancel
Save