netsurf: branch master updated. release/3.3-576-g673f3e6
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/673f3e6887586c31e3f25...
...commit http://git.netsurf-browser.org/netsurf.git/commit/673f3e6887586c31e3f2507...
...tree http://git.netsurf-browser.org/netsurf.git/tree/673f3e6887586c31e3f2507c6...
The branch, master has been updated
via 673f3e6887586c31e3f2507c6fd021c1e2c07209 (commit)
from 6ad939b5a6e7807eaad78d5b2e0486c859740cf3 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=673f3e6887586c31e3f...
commit 673f3e6887586c31e3f2507c6fd021c1e2c07209
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Fix some old and new GCC errors/warnings
diff --git a/amiga/arexx.c b/amiga/arexx.c
index 45f35f0..1960af0 100644
--- a/amiga/arexx.c
+++ b/amiga/arexx.c
@@ -145,7 +145,7 @@ void ami_arexx_execute(char *script)
char full_script_path[1025];
BPTR lock;
- if(lock = Lock(script, ACCESS_READ)) {
+ if((lock = Lock(script, ACCESS_READ))) {
DevNameFromLock(lock, full_script_path, 1024, DN_FULLPATH);
LOG("Executing script: %s", full_script_path);
IDoMethod(arexx_obj, AM_EXECUTE, full_script_path, NULL, NULL, NULL, NULL, NULL);
diff --git a/amiga/clipboard.c b/amiga/clipboard.c
index 10f0faf..92bf4df 100644
--- a/amiga/clipboard.c
+++ b/amiga/clipboard.c
@@ -175,7 +175,6 @@ static void gui_get_clipboard(char **buffer, size_t *length)
{
struct CollectionItem *ci = NULL;
struct StoredProperty *sp = NULL;
- ULONG error;
struct CSet *cset;
if(OpenIFF(iffh,IFFF_READ)) return;
@@ -185,7 +184,7 @@ static void gui_get_clipboard(char **buffer, size_t *length)
if(CollectionChunk(iffh,ID_FTXT,ID_UTF8)) return;
if(StopOnExit(iffh, ID_FTXT, ID_FORM)) return;
- error = ParseIFF(iffh,IFFPARSE_SCAN);
+ ParseIFF(iffh,IFFPARSE_SCAN);
if((ci = FindCollection(iffh, ID_FTXT, ID_UTF8))) {
*buffer = ami_clipboard_cat_collection(ci, 106, length);
diff --git a/amiga/drag.c b/amiga/drag.c
index 7aef426..67d1722 100644
--- a/amiga/drag.c
+++ b/amiga/drag.c
@@ -183,7 +183,7 @@ void ami_drag_save(struct Window *win)
break;
default:
- LOG("Unsupported drag save operation %ld", drag_save);
+ LOG("Unsupported drag save operation %d", drag_save);
break;
}
@@ -197,7 +197,6 @@ void ami_drag_icon_show(struct Window *win, const char *type)
{
struct DiskObject *dobj = NULL;
ULONG width, height;
- int err;
int deftype = WBPROJECT;
drag_in_progress = TRUE;
@@ -218,7 +217,7 @@ void ami_drag_icon_show(struct Window *win, const char *type)
ICONGETA_GetDefaultType, deftype,
TAG_DONE);
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_GetWidth,&width,
ICONCTRLA_GetHeight,&height,
TAG_DONE);
diff --git a/amiga/font_bitmap.c b/amiga/font_bitmap.c
index d9459b0..e1a1357 100644
--- a/amiga/font_bitmap.c
+++ b/amiga/font_bitmap.c
@@ -104,7 +104,7 @@ static size_t ami_font_bm_convert_local_to_utf8_offset(const char *utf8string, i
{
size_t chr = 0;
- for(int i = 0; i < offset; i++) {
+ for(size_t i = 0; i < offset; i++) {
chr = utf8_next(utf8string, length, chr);
}
diff --git a/amiga/font_bullet.c b/amiga/font_bullet.c
index 432ae88..72a2d90 100644
--- a/amiga/font_bullet.c
+++ b/amiga/font_bullet.c
@@ -24,6 +24,7 @@
#include <proto/bullet.h>
#endif
#include <proto/diskfont.h>
+#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/utility.h>
diff --git a/amiga/font_cache.c b/amiga/font_cache.c
index 09f9ef8..c94afb1 100644
--- a/amiga/font_cache.c
+++ b/amiga/font_cache.c
@@ -110,7 +110,7 @@ static void ami_font_cache_cleanup(struct MinList *ami_font_cache_list)
#ifdef __amigaos4__
static void ami_font_cache_del_skiplist(struct SkipList *skiplist)
{
- struct ami_font_cache_node *node;
+ struct SkipNode *node;
struct SkipNode *nnode;
node = (struct ami_font_cache_node *)GetFirstSkipNode(skiplist);
diff --git a/amiga/gui.c b/amiga/gui.c
index 6744d99..4490438 100644
--- a/amiga/gui.c
+++ b/amiga/gui.c
@@ -1838,9 +1838,9 @@ static void ami_set_border_gadget_size(struct gui_window_2 *gwin)
{
#ifdef __amigaos4__
/* Reset gadget widths according to new calculation */
- ULONG size1, size2, sz;
+ ULONG size1, size2;
- sz = ami_get_border_gadget_size(gwin, &size1, &size2);
+ ami_get_border_gadget_size(gwin, &size1, &size2);
RefreshSetGadgetAttrs((struct Gadget *)(APTR)gwin->objects[GID_STATUS],
gwin->win, NULL,
@@ -4322,10 +4322,10 @@ gui_window_create(struct browser_window *bw,
if(nsoption_bool(kiosk_mode) == false)
{
#ifdef __amigaos4__
- ULONG sz, width, height;
+ ULONG width, height;
struct DrawInfo *dri = GetScreenDrawInfo(scrn);
- sz = ami_get_border_gadget_size(g->shared,
+ ami_get_border_gadget_size(g->shared,
(ULONG *)&width, (ULONG *)&height);
g->shared->objects[GID_STATUS] = NewObject(
diff --git a/amiga/history_local.c b/amiga/history_local.c
index 3945649..20d5438 100755
--- a/amiga/history_local.c
+++ b/amiga/history_local.c
@@ -190,7 +190,7 @@ static bool ami_history_click(struct history_window *hw, uint16 code)
{
int x, y;
struct IBox *bbox;
- ULONG width,height,xs,ys;
+ ULONG xs, ys;
if(ami_gui_get_space_box(hw->objects[GID_BROWSER], &bbox) != NSERROR_OK) {
warn_user("NoMemory", "");
@@ -202,9 +202,6 @@ static bool ami_history_click(struct history_window *hw, uint16 code)
GetAttr(SCROLLER_Top,hw->objects[OID_VSCROLL],(ULONG *)&ys);
y = hw->win->MouseY - bbox->Top + ys;
- width=bbox->Width;
- height=bbox->Height;
-
ami_gui_free_space_box(bbox);
switch(code)
diff --git a/amiga/icon.c b/amiga/icon.c
index fd39fdd..f77f2eb 100644
--- a/amiga/icon.c
+++ b/amiga/icon.c
@@ -142,7 +142,6 @@ bool amiga_icon_convert(struct content *c)
ULONG size;
int width = 0, height = 0;
long format = 0;
- int err;
uint8 r, g, b, a;
ULONG offset;
char *filename = NULL;
@@ -171,7 +170,7 @@ bool amiga_icon_convert(struct content *c)
return false;
}
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_GetImageDataFormat,&format,
ICONCTRLA_GetWidth,&width,
ICONCTRLA_GetHeight,&height,
@@ -199,7 +198,7 @@ bool amiga_icon_convert(struct content *c)
return false;
}
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_GetImageData1, &imagebufptr,
TAG_DONE);
@@ -365,11 +364,10 @@ void amiga_icon_superimpose_favicon_internal(struct hlcache_handle *icon, struct
ULONG *icondata1, *icondata2;
ULONG width, height;
long format = 0;
- int err;
if(dobj == NULL) return;
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_GetImageDataFormat,&format,
ICONCTRLA_GetImageData1,&icondata1,
ICONCTRLA_GetImageData2,&icondata2,
@@ -421,7 +419,6 @@ void amiga_icon_superimpose_favicon(char *path, struct hlcache_handle *icon, cha
ULONG *icondata1, *icondata2;
ULONG width, height;
long format = 0;
- int err;
ULONG trans1, pals1;
ULONG trans2, pals2;
struct ColorRegister *pal1;
@@ -444,7 +441,7 @@ void amiga_icon_superimpose_favicon(char *path, struct hlcache_handle *icon, cha
if(dobj == NULL) return;
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_GetImageDataFormat,&format,
ICONCTRLA_GetImageData1,&icondata1,
ICONCTRLA_GetImageData2,&icondata2,
@@ -469,7 +466,7 @@ void amiga_icon_superimpose_favicon(char *path, struct hlcache_handle *icon, cha
icondata2 = amiga_icon_convertcolouricon32((UBYTE *)icondata2,
width, height, trans2, pals2, pal2, 0xff);
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_SetImageDataFormat, IDFMT_DIRECTMAPPED,
ICONCTRLA_SetImageData1, icondata1,
ICONCTRLA_SetImageData2, icondata2,
diff --git a/amiga/menu.c b/amiga/menu.c
index 831b8f7..7f7b5b3 100644
--- a/amiga/menu.c
+++ b/amiga/menu.c
@@ -124,10 +124,9 @@ HOOKF(void, ami_menu_item_project_newwin, APTR, window, struct IntuiMessage *)
HOOKF(void, ami_menu_item_project_newtab, APTR, window, struct IntuiMessage *)
{
struct gui_window_2 *gwin;
- nserror error;
GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
- error = ami_gui_new_blank_tab(gwin);
+ ami_gui_new_blank_tab(gwin);
}
HOOKF(void, ami_menu_item_project_open, APTR, window, struct IntuiMessage *)
@@ -792,7 +791,7 @@ static struct gui_window_2 *ami_menu_layout(struct gui_window_2 *gwin)
{
int i, j;
int txtlen = 0;
- int left_posn;
+ int left_posn = 0;
struct RastPort *rp = &scrn->RastPort;
struct DrawInfo *dri = GetScreenDrawInfo(scrn);
int space_width = TextLength(rp, " ", 1);
-----------------------------------------------------------------------
Summary of changes:
amiga/arexx.c | 2 +-
amiga/clipboard.c | 3 +--
amiga/drag.c | 5 ++---
amiga/font_bitmap.c | 2 +-
amiga/font_bullet.c | 1 +
amiga/font_cache.c | 2 +-
amiga/gui.c | 8 ++++----
amiga/history_local.c | 5 +----
amiga/icon.c | 13 +++++--------
amiga/menu.c | 5 ++---
10 files changed, 19 insertions(+), 27 deletions(-)
diff --git a/amiga/arexx.c b/amiga/arexx.c
index 45f35f0..1960af0 100644
--- a/amiga/arexx.c
+++ b/amiga/arexx.c
@@ -145,7 +145,7 @@ void ami_arexx_execute(char *script)
char full_script_path[1025];
BPTR lock;
- if(lock = Lock(script, ACCESS_READ)) {
+ if((lock = Lock(script, ACCESS_READ))) {
DevNameFromLock(lock, full_script_path, 1024, DN_FULLPATH);
LOG("Executing script: %s", full_script_path);
IDoMethod(arexx_obj, AM_EXECUTE, full_script_path, NULL, NULL, NULL, NULL, NULL);
diff --git a/amiga/clipboard.c b/amiga/clipboard.c
index 10f0faf..92bf4df 100644
--- a/amiga/clipboard.c
+++ b/amiga/clipboard.c
@@ -175,7 +175,6 @@ static void gui_get_clipboard(char **buffer, size_t *length)
{
struct CollectionItem *ci = NULL;
struct StoredProperty *sp = NULL;
- ULONG error;
struct CSet *cset;
if(OpenIFF(iffh,IFFF_READ)) return;
@@ -185,7 +184,7 @@ static void gui_get_clipboard(char **buffer, size_t *length)
if(CollectionChunk(iffh,ID_FTXT,ID_UTF8)) return;
if(StopOnExit(iffh, ID_FTXT, ID_FORM)) return;
- error = ParseIFF(iffh,IFFPARSE_SCAN);
+ ParseIFF(iffh,IFFPARSE_SCAN);
if((ci = FindCollection(iffh, ID_FTXT, ID_UTF8))) {
*buffer = ami_clipboard_cat_collection(ci, 106, length);
diff --git a/amiga/drag.c b/amiga/drag.c
index 7aef426..67d1722 100644
--- a/amiga/drag.c
+++ b/amiga/drag.c
@@ -183,7 +183,7 @@ void ami_drag_save(struct Window *win)
break;
default:
- LOG("Unsupported drag save operation %ld", drag_save);
+ LOG("Unsupported drag save operation %d", drag_save);
break;
}
@@ -197,7 +197,6 @@ void ami_drag_icon_show(struct Window *win, const char *type)
{
struct DiskObject *dobj = NULL;
ULONG width, height;
- int err;
int deftype = WBPROJECT;
drag_in_progress = TRUE;
@@ -218,7 +217,7 @@ void ami_drag_icon_show(struct Window *win, const char *type)
ICONGETA_GetDefaultType, deftype,
TAG_DONE);
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_GetWidth,&width,
ICONCTRLA_GetHeight,&height,
TAG_DONE);
diff --git a/amiga/font_bitmap.c b/amiga/font_bitmap.c
index d9459b0..e1a1357 100644
--- a/amiga/font_bitmap.c
+++ b/amiga/font_bitmap.c
@@ -104,7 +104,7 @@ static size_t ami_font_bm_convert_local_to_utf8_offset(const char *utf8string, i
{
size_t chr = 0;
- for(int i = 0; i < offset; i++) {
+ for(size_t i = 0; i < offset; i++) {
chr = utf8_next(utf8string, length, chr);
}
diff --git a/amiga/font_bullet.c b/amiga/font_bullet.c
index 432ae88..72a2d90 100644
--- a/amiga/font_bullet.c
+++ b/amiga/font_bullet.c
@@ -24,6 +24,7 @@
#include <proto/bullet.h>
#endif
#include <proto/diskfont.h>
+#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/utility.h>
diff --git a/amiga/font_cache.c b/amiga/font_cache.c
index 09f9ef8..c94afb1 100644
--- a/amiga/font_cache.c
+++ b/amiga/font_cache.c
@@ -110,7 +110,7 @@ static void ami_font_cache_cleanup(struct MinList *ami_font_cache_list)
#ifdef __amigaos4__
static void ami_font_cache_del_skiplist(struct SkipList *skiplist)
{
- struct ami_font_cache_node *node;
+ struct SkipNode *node;
struct SkipNode *nnode;
node = (struct ami_font_cache_node *)GetFirstSkipNode(skiplist);
diff --git a/amiga/gui.c b/amiga/gui.c
index 6744d99..4490438 100644
--- a/amiga/gui.c
+++ b/amiga/gui.c
@@ -1838,9 +1838,9 @@ static void ami_set_border_gadget_size(struct gui_window_2 *gwin)
{
#ifdef __amigaos4__
/* Reset gadget widths according to new calculation */
- ULONG size1, size2, sz;
+ ULONG size1, size2;
- sz = ami_get_border_gadget_size(gwin, &size1, &size2);
+ ami_get_border_gadget_size(gwin, &size1, &size2);
RefreshSetGadgetAttrs((struct Gadget *)(APTR)gwin->objects[GID_STATUS],
gwin->win, NULL,
@@ -4322,10 +4322,10 @@ gui_window_create(struct browser_window *bw,
if(nsoption_bool(kiosk_mode) == false)
{
#ifdef __amigaos4__
- ULONG sz, width, height;
+ ULONG width, height;
struct DrawInfo *dri = GetScreenDrawInfo(scrn);
- sz = ami_get_border_gadget_size(g->shared,
+ ami_get_border_gadget_size(g->shared,
(ULONG *)&width, (ULONG *)&height);
g->shared->objects[GID_STATUS] = NewObject(
diff --git a/amiga/history_local.c b/amiga/history_local.c
index 3945649..20d5438 100755
--- a/amiga/history_local.c
+++ b/amiga/history_local.c
@@ -190,7 +190,7 @@ static bool ami_history_click(struct history_window *hw, uint16 code)
{
int x, y;
struct IBox *bbox;
- ULONG width,height,xs,ys;
+ ULONG xs, ys;
if(ami_gui_get_space_box(hw->objects[GID_BROWSER], &bbox) != NSERROR_OK) {
warn_user("NoMemory", "");
@@ -202,9 +202,6 @@ static bool ami_history_click(struct history_window *hw, uint16 code)
GetAttr(SCROLLER_Top,hw->objects[OID_VSCROLL],(ULONG *)&ys);
y = hw->win->MouseY - bbox->Top + ys;
- width=bbox->Width;
- height=bbox->Height;
-
ami_gui_free_space_box(bbox);
switch(code)
diff --git a/amiga/icon.c b/amiga/icon.c
index fd39fdd..f77f2eb 100644
--- a/amiga/icon.c
+++ b/amiga/icon.c
@@ -142,7 +142,6 @@ bool amiga_icon_convert(struct content *c)
ULONG size;
int width = 0, height = 0;
long format = 0;
- int err;
uint8 r, g, b, a;
ULONG offset;
char *filename = NULL;
@@ -171,7 +170,7 @@ bool amiga_icon_convert(struct content *c)
return false;
}
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_GetImageDataFormat,&format,
ICONCTRLA_GetWidth,&width,
ICONCTRLA_GetHeight,&height,
@@ -199,7 +198,7 @@ bool amiga_icon_convert(struct content *c)
return false;
}
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_GetImageData1, &imagebufptr,
TAG_DONE);
@@ -365,11 +364,10 @@ void amiga_icon_superimpose_favicon_internal(struct hlcache_handle *icon, struct
ULONG *icondata1, *icondata2;
ULONG width, height;
long format = 0;
- int err;
if(dobj == NULL) return;
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_GetImageDataFormat,&format,
ICONCTRLA_GetImageData1,&icondata1,
ICONCTRLA_GetImageData2,&icondata2,
@@ -421,7 +419,6 @@ void amiga_icon_superimpose_favicon(char *path, struct hlcache_handle *icon, cha
ULONG *icondata1, *icondata2;
ULONG width, height;
long format = 0;
- int err;
ULONG trans1, pals1;
ULONG trans2, pals2;
struct ColorRegister *pal1;
@@ -444,7 +441,7 @@ void amiga_icon_superimpose_favicon(char *path, struct hlcache_handle *icon, cha
if(dobj == NULL) return;
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_GetImageDataFormat,&format,
ICONCTRLA_GetImageData1,&icondata1,
ICONCTRLA_GetImageData2,&icondata2,
@@ -469,7 +466,7 @@ void amiga_icon_superimpose_favicon(char *path, struct hlcache_handle *icon, cha
icondata2 = amiga_icon_convertcolouricon32((UBYTE *)icondata2,
width, height, trans2, pals2, pal2, 0xff);
- err = IconControl(dobj,
+ IconControl(dobj,
ICONCTRLA_SetImageDataFormat, IDFMT_DIRECTMAPPED,
ICONCTRLA_SetImageData1, icondata1,
ICONCTRLA_SetImageData2, icondata2,
diff --git a/amiga/menu.c b/amiga/menu.c
index 831b8f7..7f7b5b3 100644
--- a/amiga/menu.c
+++ b/amiga/menu.c
@@ -124,10 +124,9 @@ HOOKF(void, ami_menu_item_project_newwin, APTR, window, struct IntuiMessage *)
HOOKF(void, ami_menu_item_project_newtab, APTR, window, struct IntuiMessage *)
{
struct gui_window_2 *gwin;
- nserror error;
GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
- error = ami_gui_new_blank_tab(gwin);
+ ami_gui_new_blank_tab(gwin);
}
HOOKF(void, ami_menu_item_project_open, APTR, window, struct IntuiMessage *)
@@ -792,7 +791,7 @@ static struct gui_window_2 *ami_menu_layout(struct gui_window_2 *gwin)
{
int i, j;
int txtlen = 0;
- int left_posn;
+ int left_posn = 0;
struct RastPort *rp = &scrn->RastPort;
struct DrawInfo *dri = GetScreenDrawInfo(scrn);
int space_width = TextLength(rp, " ", 1);
--
NetSurf Browser
7 years, 10 months
netsurf: branch master updated. release/3.3-575-g6ad939b
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/6ad939b5a6e7807eaad78...
...commit http://git.netsurf-browser.org/netsurf.git/commit/6ad939b5a6e7807eaad78d5...
...tree http://git.netsurf-browser.org/netsurf.git/tree/6ad939b5a6e7807eaad78d5b2...
The branch, master has been updated
via 6ad939b5a6e7807eaad78d5b2e0486c859740cf3 (commit)
from f831d81ab1895b4f9c19f53f08d9c8fccd69c96e (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=6ad939b5a6e7807eaad...
commit 6ad939b5a6e7807eaad78d5b2e0486c859740cf3
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Make font engine selection bit more logical
diff --git a/amiga/Makefile.target b/amiga/Makefile.target
index 391dd6e..626110b 100644
--- a/amiga/Makefile.target
+++ b/amiga/Makefile.target
@@ -76,7 +76,7 @@ S_AMIGA := gui.c tree.c history.c hotlist.c schedule.c file.c \
datatypes.c dt_picture.c dt_anim.c dt_sound.c plugin_hack.c \
stringview/stringview.c stringview/urlhistory.c rtg.c \
agclass/amigaguide_class.c os3support.c font_bitmap.c \
- selectmenu.c hash/xxhash.c font_cache.c
+ selectmenu.c hash/xxhash.c font_cache.c font_bullet.c
S_AMIGA := $(addprefix amiga/,$(S_AMIGA))
# This is the final source build list
diff --git a/amiga/font.c b/amiga/font.c
index 3a141ac..5701758 100644
--- a/amiga/font.c
+++ b/amiga/font.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 - 2015 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2008 - 2016 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -25,11 +25,7 @@
#endif
#include <proto/diskfont.h>
#include <proto/exec.h>
-#include <proto/graphics.h>
-#include <proto/utility.h>
-#include <diskfont/diskfonttag.h>
-#include <diskfont/oterrors.h>
#include <graphics/rpattr.h>
#ifdef __amigaos4__
@@ -37,7 +33,6 @@
#endif
#include "utils/log.h"
-#include "utils/utf8.h"
#include "utils/utils.h"
#include "utils/nsoption.h"
#include "desktop/browser.h"
@@ -45,859 +40,10 @@
#include "desktop/gui_window.h"
#include "amiga/font.h"
-#include "amiga/font_cache.h"
#include "amiga/font_scan.h"
#include "amiga/gui.h"
#include "amiga/utf8.h"
-#define NSA_UNICODE_FONT PLOT_FONT_FAMILY_COUNT
-
-#define NSA_NORMAL 0
-#define NSA_ITALIC 1
-#define NSA_BOLD 2
-#define NSA_BOLDITALIC 3
-#define NSA_OBLIQUE 4
-#define NSA_BOLDOBLIQUE 6
-
-#define NSA_VALUE_BOLDX (1 << 12)
-#define NSA_VALUE_BOLDY 0
-#define NSA_VALUE_SHEARSIN (1 << 14)
-#define NSA_VALUE_SHEARCOS (1 << 16)
-
-#define NSA_FONT_EMWIDTH(s) (s / FONT_SIZE_SCALE) * (ami_xdpi / 72.0)
-
-const uint16 sc_table[] = {
- 0x0061, 0x1D00, /* a */
- 0x0062, 0x0299, /* b */
- 0x0063, 0x1D04, /* c */
- 0x0064, 0x1D05, /* d */
- 0x0065, 0x1D07, /* e */
- 0x0066, 0xA730, /* f */
- 0x0067, 0x0262, /* g */
- 0x0068, 0x029C, /* h */
- 0x0069, 0x026A, /* i */
- 0x006A, 0x1D0A, /* j */
- 0x006B, 0x1D0B, /* k */
- 0x006C, 0x029F, /* l */
- 0x006D, 0x1D0D, /* m */
- 0x006E, 0x0274, /* n */
- 0x006F, 0x1D0F, /* o */
- 0x0070, 0x1D18, /* p */
- 0x0071, 0xA7EE, /* q (proposed) (Adobe codepoint 0xF771) */
- 0x0072, 0x0280, /* r */
- 0x0073, 0xA731, /* s */
- 0x0074, 0x1D1B, /* t */
- 0x0075, 0x1D1C, /* u */
- 0x0076, 0x1D20, /* v */
- 0x0077, 0x1D21, /* w */
- 0x0078, 0xA7EF, /* x (proposed) (Adobe codepoint 0xF778) */
- 0x0079, 0x028F, /* y */
- 0x007A, 0x1D22, /* z */
-
- 0x00C6, 0x1D01, /* ae */
- 0x0153, 0x0276, /* oe */
-
-#if 0
-/* TODO: fill in the non-small caps character ids for these */
- 0x0000, 0x1D03, /* barred b */
- 0x0000, 0x0281, /* inverted r */
- 0x0000, 0x1D19, /* reversed r */
- 0x0000, 0x1D1A, /* turned r */
- 0x0000, 0x029B, /* g with hook */
- 0x0000, 0x1D06, /* eth � */
- 0x0000, 0x1D0C, /* l with stroke */
- 0x0000, 0xA7FA, /* turned m */
- 0x0000, 0x1D0E, /* reversed n */
- 0x0000, 0x1D10, /* open o */
- 0x0000, 0x1D15, /* ou */
- 0x0000, 0x1D23, /* ezh */
- 0x0000, 0x1D26, /* gamma */
- 0x0000, 0x1D27, /* lamda */
- 0x0000, 0x1D28, /* pi */
- 0x0000, 0x1D29, /* rho */
- 0x0000, 0x1D2A, /* psi */
- 0x0000, 0x1D2B, /* el */
- 0x0000, 0xA776, /* rum */
-
- 0x0000, 0x1DDB, /* combining g */
- 0x0000, 0x1DDE, /* combining l */
- 0x0000, 0x1DDF, /* combining m */
- 0x0000, 0x1DE1, /* combining n */
- 0x0000, 0x1DE2, /* combining r */
-
- 0x0000, 0x1DA6, /* modifier i */
- 0x0000, 0x1DA7, /* modifier i with stroke */
- 0x0000, 0x1DAB, /* modifier l */
- 0x0000, 0x1DB0, /* modifier n */
- 0x0000, 0x1DB8, /* modifier u */
-#endif
- 0, 0};
-
-lwc_string *glypharray[0xffff + 1];
-ULONG ami_devicedpi;
-ULONG ami_xdpi;
-
-static struct List ami_diskfontlib_list;
-
-static inline int32 ami_font_plot_glyph(struct OutlineFont *ofont, struct RastPort *rp,
- uint16 *char1, uint16 *char2, uint32 x, uint32 y, uint32 emwidth, bool aa);
-static inline int32 ami_font_width_glyph(struct OutlineFont *ofont,
- const uint16 *char1, const uint16 *char2, uint32 emwidth);
-static struct OutlineFont *ami_open_outline_font(const plot_font_style_t *fstyle,
- const uint16 *codepoint);
-static inline ULONG ami_font_unicode_width(const char *string, ULONG length,
- const plot_font_style_t *fstyle, ULONG x, ULONG y, bool aa);
-
-static inline int amiga_nsfont_utf16_char_length(const uint16 *char1)
-{
- if (__builtin_expect(((*char1 < 0xD800) || (0xDBFF < *char1)), 1)) {
- return 1;
- } else {
- return 2;
- }
-}
-
-static inline uint32 amiga_nsfont_decode_surrogate(const uint16 *char1)
-{
- if(__builtin_expect((amiga_nsfont_utf16_char_length(char1) == 2), 0)) {
- return ((uint32)char1[0] << 10) + char1[1] - 0x35FDC00;
- } else {
- return (uint32)*char1;
- }
-}
-
-static inline bool amiga_nsfont_width(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int *width)
-{
- *width = ami_font_unicode_width(string, length, fstyle, 0, 0, false);
-
- if(*width <= 0) *width == length; // fudge
-
- return true;
-}
-
-/**
- * Find the position in a string where an x coordinate falls.
- *
- * \param fstyle style for this text
- * \param string UTF-8 string to measure
- * \param length length of string
- * \param x x coordinate to search for
- * \param char_offset updated to offset in string of actual_x, [0..length]
- * \param actual_x updated to x coordinate of character closest to x
- * \return true on success, false on error and error reported
- */
-
-static inline bool amiga_nsfont_position_in_string(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x)
-{
- uint16 *utf16 = NULL, *outf16 = NULL;
- uint16 *utf16next = NULL;
- struct OutlineFont *ofont, *ufont = NULL;
- int tx = 0;
- uint32 utf8_pos = 0;
- int utf16charlen;
- ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
- int32 tempx;
-
- if(utf8_to_enc(string,"UTF-16",length,(char **)&utf16) != NSERROR_OK) return false;
- outf16 = utf16;
- if(!(ofont = ami_open_outline_font(fstyle, 0))) return false;
-
- *char_offset = 0;
- *actual_x = 0;
-
- while (utf8_pos < length) {
- utf16charlen = amiga_nsfont_utf16_char_length(utf16);
- utf16next = &utf16[utf16charlen];
-
- tempx = ami_font_width_glyph(ofont, utf16, utf16next, emwidth);
-
- if (tempx == 0) {
- if (ufont == NULL)
- ufont = ami_open_outline_font(fstyle, utf16);
-
- if (ufont)
- tempx = ami_font_width_glyph(ufont, utf16,
- utf16next, emwidth);
- }
-
- tx += tempx;
- utf16 = utf16next;
- utf8_pos = utf8_next(string, length, utf8_pos);
-
- if(tx < x) {
- *actual_x = tx;
- *char_offset = utf8_pos;
- } else {
- if((x - *actual_x) > (tx - x)) {
- *actual_x = tx;
- *char_offset = utf8_pos;
- }
- free(outf16);
- return true;
- }
- }
-
- *actual_x = tx;
- *char_offset = length;
-
- free(outf16);
- return true;
-}
-
-
-/**
- * Find where to split a string to make it fit a width.
- *
- * \param fstyle style for this text
- * \param string UTF-8 string to measure
- * \param length length of string
- * \param x width available
- * \param char_offset updated to offset in string of actual_x, [1..length]
- * \param actual_x updated to x coordinate of character closest to x
- * \return true on success, false on error and error reported
- *
- * On exit, char_offset indicates first character after split point.
- *
- * Note: char_offset of 0 should never be returned.
- *
- * Returns:
- * char_offset giving split point closest to x, where actual_x <= x
- * else
- * char_offset giving split point closest to x, where actual_x > x
- *
- * Returning char_offset == length means no split possible
- */
-
-static inline bool amiga_nsfont_split(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x)
-{
- uint16 *utf16_str = NULL;
- const uint16 *utf16 = NULL;
- const uint16 *utf16next = NULL;
- struct OutlineFont *ofont, *ufont = NULL;
- int tx = 0;
- uint32 utf8_pos = 0;
- int32 tempx = 0;
- ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
-
- /* Get utf16 conversion of string for glyph measuring routines */
- if (utf8_to_enc(string, "UTF-16", length, (char **)&utf16_str) !=
- NSERROR_OK)
- return false;
-
- utf16 = utf16_str;
- if (!(ofont = ami_open_outline_font(fstyle, 0)))
- return false;
-
- *char_offset = 0;
- *actual_x = 0;
-
- if (*utf16 == 0xFEFF) utf16++;
-
- while (utf8_pos < length) {
- if ((*utf16 < 0xD800) || (0xDBFF < *utf16))
- utf16next = utf16 + 1;
- else
- utf16next = utf16 + 2;
-
- tempx = ami_font_width_glyph(ofont, utf16, utf16next, emwidth);
-
- if (tempx == 0) {
- if (ufont == NULL)
- ufont = ami_open_outline_font(fstyle, utf16);
-
- if (ufont)
- tempx = ami_font_width_glyph(ufont, utf16,
- utf16next, emwidth);
- }
-
- /* Check whether we have a space */
- if (*(string + utf8_pos) == ' ') {
- /* Got a space */
- *actual_x = tx;
- *char_offset = utf8_pos;
- }
-
- tx += tempx;
- if ((x < tx) && (*char_offset != 0)) {
- /* Reached available width, and a space was found;
- * split there. */
- free(utf16_str);
- return true;
- }
-
- utf16 = utf16next;
- utf8_pos = utf8_next(string, length, utf8_pos);
- }
-
- free(utf16_str);
-
- /* No spaces to split at, or everything fits */
- assert(*char_offset == 0 || x >= tx);
-
- *char_offset = length;
- *actual_x = tx;
- return true;
-}
-
-/**
- * Search for a font in the list and load from disk if not present
- */
-static struct ami_font_cache_node *ami_font_open(const char *font, bool critical)
-{
- struct ami_font_cache_node *nodedata = ami_font_cache_locate(font);
- if(nodedata) return nodedata;
-
- nodedata = ami_font_cache_alloc_entry(font);
-
- if(nodedata == NULL) {
- warn_user("NoMemory", "");
- return NULL;
- }
-
- nodedata->font = OpenOutlineFont(font, &ami_diskfontlib_list, OFF_OPEN);
-
- if(!nodedata->font)
- {
- LOG("Requested font not found: %s", font);
- if(critical == true) warn_user("CompError", font);
- FreeVec(nodedata);
- return NULL;
- }
-
- nodedata->bold = (char *)GetTagData(OT_BName, 0, nodedata->font->olf_OTagList);
- if(nodedata->bold)
- LOG("Bold font defined for %s is %s", font, nodedata->bold);
- else
- LOG("Warning: No designed bold font defined for %s", font);
-
- nodedata->italic = (char *)GetTagData(OT_IName, 0, nodedata->font->olf_OTagList);
- if(nodedata->italic)
- LOG("Italic font defined for %s is %s", font, nodedata->italic);
- else
- LOG("Warning: No designed italic font defined for %s", font);
-
- nodedata->bolditalic = (char *)GetTagData(OT_BIName, 0, nodedata->font->olf_OTagList);
- if(nodedata->bolditalic)
- LOG("Bold-italic font defined for %s is %s", font, nodedata->bolditalic);
- else
- LOG("Warning: No designed bold-italic font defined for %s", font);
-
- ami_font_cache_insert(nodedata, font);
- return nodedata;
-}
-
-/**
- * Open an outline font in the specified size and style
- *
- * \param fstyle font style structure
- * \param codepoint open a default font instead of the one specified by fstyle
- * \return outline font or NULL on error
- */
-static struct OutlineFont *ami_open_outline_font(const plot_font_style_t *fstyle,
- const uint16 *codepoint)
-{
- struct ami_font_cache_node *node;
- struct ami_font_cache_node *designed_node = NULL;
- struct OutlineFont *ofont;
- char *fontname;
- ULONG ysize;
- int tstyle = 0;
- plot_font_generic_family_t fontfamily;
- ULONG emboldenx = 0;
- ULONG emboldeny = 0;
- ULONG shearsin = 0;
- ULONG shearcos = (1 << 16);
-
- if(codepoint) fontfamily = NSA_UNICODE_FONT;
- else fontfamily = fstyle->family;
-
- switch(fontfamily)
- {
- case PLOT_FONT_FAMILY_SANS_SERIF:
- fontname = nsoption_charp(font_sans);
- break;
- case PLOT_FONT_FAMILY_SERIF:
- fontname = nsoption_charp(font_serif);
- break;
- case PLOT_FONT_FAMILY_MONOSPACE:
- fontname = nsoption_charp(font_mono);
- break;
- case PLOT_FONT_FAMILY_CURSIVE:
- fontname = nsoption_charp(font_cursive);
- break;
- case PLOT_FONT_FAMILY_FANTASY:
- fontname = nsoption_charp(font_fantasy);
- break;
- case NSA_UNICODE_FONT:
- default:
- if(__builtin_expect((amiga_nsfont_utf16_char_length(codepoint) == 2), 0)) {
- /* Multi-byte character */
- fontname = nsoption_charp(font_surrogate);
- } else {
- fontname = (char *)ami_font_scan_lookup(codepoint, glypharray);
- }
- if(fontname == NULL) return NULL;
- break;
- }
-
- node = ami_font_open(fontname, true);
- if(!node) return NULL;
-
- if (fstyle->flags & FONTF_OBLIQUE)
- tstyle = NSA_OBLIQUE;
-
- if (fstyle->flags & FONTF_ITALIC)
- tstyle = NSA_ITALIC;
-
- if (fstyle->weight >= 700)
- tstyle += NSA_BOLD;
-
- switch(tstyle)
- {
- case NSA_ITALIC:
- if(node->italic) designed_node = ami_font_open(node->italic, false);
-
- if(designed_node == NULL) {
- shearsin = NSA_VALUE_SHEARSIN;
- shearcos = NSA_VALUE_SHEARCOS;
- }
- break;
-
- case NSA_OBLIQUE:
- shearsin = NSA_VALUE_SHEARSIN;
- shearcos = NSA_VALUE_SHEARCOS;
- break;
-
- case NSA_BOLD:
- if(node->bold) designed_node = ami_font_open(node->bold, false);
-
- if(designed_node == NULL) {
- emboldenx = NSA_VALUE_BOLDX;
- emboldeny = NSA_VALUE_BOLDY;
- }
- break;
-
- case NSA_BOLDOBLIQUE:
- shearsin = NSA_VALUE_SHEARSIN;
- shearcos = NSA_VALUE_SHEARCOS;
-
- if(node->bold) designed_node = ami_font_open(node->bold, false);
-
- if(designed_node == NULL) {
- emboldenx = NSA_VALUE_BOLDX;
- emboldeny = NSA_VALUE_BOLDY;
- }
- break;
-
- case NSA_BOLDITALIC:
- if(node->bolditalic) designed_node = ami_font_open(node->bolditalic, false);
-
- if(designed_node == NULL) {
- emboldenx = NSA_VALUE_BOLDX;
- emboldeny = NSA_VALUE_BOLDY;
- shearsin = NSA_VALUE_SHEARSIN;
- shearcos = NSA_VALUE_SHEARCOS;
- }
- break;
- }
-
- /* Scale to 16.16 fixed point */
- ysize = fstyle->size * ((1 << 16) / FONT_SIZE_SCALE);
-
- if(designed_node == NULL) {
- ofont = node->font;
- } else {
- ofont = designed_node->font;
- }
-
-#ifndef __amigaos4__
- struct BulletBase *BulletBase = ofont->BulletBase;
-#endif
-
- if(ESetInfo(AMI_OFONT_ENGINE,
- OT_DeviceDPI, ami_devicedpi,
- OT_PointHeight, ysize,
- OT_EmboldenX, emboldenx,
- OT_EmboldenY, emboldeny,
- OT_ShearSin, shearsin,
- OT_ShearCos, shearcos,
- TAG_END) == OTERR_Success)
- return ofont;
-
- return NULL;
-}
-
-static inline int32 ami_font_plot_glyph(struct OutlineFont *ofont, struct RastPort *rp,
- uint16 *char1, uint16 *char2, uint32 x, uint32 y, uint32 emwidth, bool aa)
-{
- struct GlyphMap *glyph;
- UBYTE *glyphbm;
- int32 char_advance = 0;
- FIXED kern = 0;
- ULONG glyphmaptag;
- ULONG template_type;
- uint32 long_char_1 = 0, long_char_2 = 0;
-#ifndef __amigaos4__
- struct BulletBase *BulletBase = ofont->BulletBase;
-#endif
-
-#ifndef __amigaos4__
- if (__builtin_expect(((*char1 >= 0xD800) && (*char1 <= 0xDBFF)), 0)) {
- /* We don't support UTF-16 surrogates yet, so just return. */
- return 0;
- }
-
- if (__builtin_expect(((*char2 >= 0xD800) && (*char2 <= 0xDBFF)), 0)) {
- /* Don't attempt to kern a UTF-16 surrogate */
- *char2 = 0;
- }
-#endif
-
-#ifdef __amigaos4__
- if(__builtin_expect(aa == true, 1)) {
- glyphmaptag = OT_GlyphMap8Bit;
- template_type = BLITT_ALPHATEMPLATE;
- } else {
-#endif
- glyphmaptag = OT_GlyphMap;
-#ifdef __amigaos4__
- template_type = BLITT_TEMPLATE;
- }
-#endif
-
- long_char_1 = amiga_nsfont_decode_surrogate(char1);
- long_char_2 = amiga_nsfont_decode_surrogate(char2);
- /**\todo use OT_GlyphCode_32 so we get an error for old font engines */
-
- if(ESetInfo(AMI_OFONT_ENGINE,
- OT_GlyphCode, long_char_1,
- OT_GlyphCode2, long_char_2,
- TAG_END) == OTERR_Success)
- {
- if(EObtainInfo(AMI_OFONT_ENGINE,
- glyphmaptag, &glyph,
- TAG_END) == 0)
- {
- glyphbm = glyph->glm_BitMap;
- if(!glyphbm) return 0;
-
- if(rp) {
-#ifdef __amigaos4__
- BltBitMapTags(BLITA_SrcX, glyph->glm_BlackLeft,
- BLITA_SrcY, glyph->glm_BlackTop,
- BLITA_DestX, x - glyph->glm_X0 + glyph->glm_BlackLeft,
- BLITA_DestY, y - glyph->glm_Y0 + glyph->glm_BlackTop,
- BLITA_Width, glyph->glm_BlackWidth,
- BLITA_Height, glyph->glm_BlackHeight,
- BLITA_Source, glyphbm,
- BLITA_SrcType, template_type,
- BLITA_Dest, rp,
- BLITA_DestType, BLITT_RASTPORT,
- BLITA_SrcBytesPerRow, glyph->glm_BMModulo,
- TAG_DONE);
-#else
- /* On OS3 the glyph needs to be in chip RAM */
- void *chip_glyph = AllocVec(glyph->glm_BMModulo * glyph->glm_BMRows, MEMF_CHIP);
- if(chip_glyph != NULL) {
- CopyMem(glyphbm, chip_glyph, glyph->glm_BMModulo * glyph->glm_BMRows);
-
- BltTemplate(chip_glyph + (glyph->glm_BMModulo * glyph->glm_BlackTop) +
- ((glyph->glm_BlackLeft >> 4) << 1),
- glyph->glm_BlackLeft & 0xF, glyph->glm_BMModulo, rp,
- x - glyph->glm_X0 + glyph->glm_BlackLeft,
- y - glyph->glm_Y0 + glyph->glm_BlackTop,
- glyph->glm_BlackWidth, glyph->glm_BlackHeight);
-
- FreeVec(chip_glyph);
- }
-#endif
- }
-
- kern = 0;
-
- if(*char2) EObtainInfo(AMI_OFONT_ENGINE,
- OT_TextKernPair, &kern,
- TAG_END);
-
- char_advance = (ULONG)(((glyph->glm_Width - kern) * emwidth) / 65536);
-
- EReleaseInfo(AMI_OFONT_ENGINE,
- glyphmaptag, glyph,
- TAG_END);
-
- if(*char2) EReleaseInfo(AMI_OFONT_ENGINE,
- OT_TextKernPair, kern,
- TAG_END);
- }
- }
-
- return char_advance;
-}
-
-static inline int32 ami_font_width_glyph(struct OutlineFont *ofont,
- const uint16 *char1, const uint16 *char2, uint32 emwidth)
-{
- int32 char_advance = 0;
- FIXED kern = 0;
- struct MinList *gwlist = NULL;
- FIXED char1w = 0;
- struct GlyphWidthEntry *gwnode;
- bool skip_c2 = false;
- uint32 long_char_1 = 0;
- uint32 long_char_2;
-#ifndef __amigaos4__
- struct BulletBase *BulletBase = ofont->BulletBase;
-#endif
-
-#ifndef __amigaos4__
- if (__builtin_expect(((*char1 >= 0xD800) && (*char1 <= 0xDBFF)), 0)) {
- /* We don't support UTF-16 surrogates yet, so just return. */
- return 0;
- }
-
- if (__builtin_expect(((*char2 >= 0xD800) && (*char2 <= 0xDBFF)), 0)) {
- /* Don't attempt to kern a UTF-16 surrogate */
- skip_c2 = true;
- }
-#endif
-
- if (*char2 < 0x0020) skip_c2 = true;
-
- long_char_1 = amiga_nsfont_decode_surrogate(char1);
- /**\todo use OT_GlyphCode_32 so we get an error for old font engines */
-
- if(ESetInfo(AMI_OFONT_ENGINE,
- OT_GlyphCode, long_char_1,
- OT_GlyphCode2, long_char_1,
- TAG_END) == OTERR_Success)
- {
- if(EObtainInfo(AMI_OFONT_ENGINE,
- OT_WidthList, &gwlist,
- TAG_END) == 0)
- {
- gwnode = (struct GlyphWidthEntry *)GetHead((struct List *)gwlist);
- if(gwnode) char1w = gwnode->gwe_Width;
-
- kern = 0;
-
- if(!skip_c2) {
- long_char_2 = amiga_nsfont_decode_surrogate(char2);
- if(ESetInfo(AMI_OFONT_ENGINE,
- OT_GlyphCode, long_char_1,
- OT_GlyphCode2, long_char_2,
- TAG_END) == OTERR_Success)
- {
- EObtainInfo(AMI_OFONT_ENGINE,
- OT_TextKernPair, &kern,
- TAG_END);
- }
- }
- char_advance = (ULONG)(((char1w - kern) * emwidth) / 65536);
-
- if(!skip_c2) EReleaseInfo(AMI_OFONT_ENGINE,
- OT_TextKernPair, kern,
- TAG_END);
-
- EReleaseInfo(AMI_OFONT_ENGINE,
- OT_WidthList, gwlist,
- TAG_END);
- }
- }
-
- return char_advance;
-}
-
-static const uint16 *ami_font_translate_smallcaps(uint16 *utf16char)
-{
- const uint16 *p;
- p = &sc_table[0];
-
- while (*p != 0)
- {
- if(*p == *utf16char) return &p[1];
- p++;
- }
-
- return utf16char;
-}
-
-ULONG ami_font_unicode_text(struct RastPort *rp, const char *string, ULONG length,
- const plot_font_style_t *fstyle, ULONG dx, ULONG dy, bool aa)
-{
- uint16 *utf16 = NULL, *outf16 = NULL;
- uint16 *utf16charsc = 0, *utf16nextsc = 0;
- uint16 *utf16next = 0;
- int utf16charlen;
- struct OutlineFont *ofont, *ufont = NULL;
- uint32 x=0;
- int32 tempx = 0;
- ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
- uint16 utf16_a = 0x41;
-
- if(!string || string[0]=='\0') return 0;
- if(!length) return 0;
- if(rp == NULL) return 0;
-
- if(__builtin_expect(nsoption_bool(use_diskfont) == true, 0)) {
- return ami_font_bm_text(rp, string, length, fstyle, dx, dy);
- }
-
- if(utf8_to_enc(string,"UTF-16",length,(char **)&utf16) != NSERROR_OK) return 0;
- outf16 = utf16;
- if(!(ofont = ami_open_outline_font(fstyle, 0))) {
- if(!(ofont = ami_open_outline_font(fstyle, &utf16_a))) return 0;
- }
-
- while(*utf16 != 0)
- {
- utf16charlen = amiga_nsfont_utf16_char_length(utf16);
- utf16next = &utf16[utf16charlen];
-
- if(fstyle->flags & FONTF_SMALLCAPS)
- {
- utf16charsc = (uint16 *)ami_font_translate_smallcaps(utf16);
- utf16nextsc = (uint16 *)ami_font_translate_smallcaps(utf16next);
-
- tempx = ami_font_plot_glyph(ofont, rp, utf16charsc, utf16nextsc,
- dx + x, dy, emwidth, aa);
- }
- else tempx = 0;
-
- if(tempx == 0) {
- tempx = ami_font_plot_glyph(ofont, rp, utf16, utf16next,
- dx + x, dy, emwidth, aa);
- }
-
- if(tempx == 0)
- {
- if(ufont == NULL)
- {
- ufont = ami_open_outline_font(fstyle, utf16);
- }
-
- if(ufont) {
- tempx = ami_font_plot_glyph(ufont, rp, utf16, utf16next,
- dx + x, dy, emwidth, aa);
- }
- }
-
- x += tempx;
-
- utf16 += utf16charlen;
- }
-
- free(outf16);
- return x;
-}
-
-static inline ULONG ami_font_unicode_width(const char *string, ULONG length,
- const plot_font_style_t *fstyle, ULONG dx, ULONG dy, bool aa)
-{
- uint16 *utf16 = NULL, *outf16 = NULL;
- uint16 *utf16charsc = 0, *utf16nextsc = 0;
- uint16 *utf16next = 0;
- int utf16charlen;
- struct OutlineFont *ofont, *ufont = NULL;
- uint32 x=0;
- int32 tempx = 0;
- ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
- uint16 utf16_a = 0x41;
-
- if(!string || string[0]=='\0') return 0;
- if(!length) return 0;
-
- if(utf8_to_enc(string,"UTF-16",length,(char **)&utf16) != NSERROR_OK) return 0;
- outf16 = utf16;
- if(!(ofont = ami_open_outline_font(fstyle, 0))) {
- if(!(ofont = ami_open_outline_font(fstyle, &utf16_a))) return 0;
- }
-
- while(*utf16 != 0)
- {
- utf16charlen = amiga_nsfont_utf16_char_length(utf16);
- utf16next = &utf16[utf16charlen];
-
- if(fstyle->flags & FONTF_SMALLCAPS)
- {
- utf16charsc = (uint16 *)ami_font_translate_smallcaps(utf16);
- utf16nextsc = (uint16 *)ami_font_translate_smallcaps(utf16next);
-
- tempx = ami_font_width_glyph(ofont, utf16charsc, utf16nextsc, emwidth);
- }
- else tempx = 0;
-
- if(tempx == 0) {
- tempx = ami_font_width_glyph(ofont, utf16, utf16next, emwidth);
- }
-
- if(tempx == 0)
- {
- if(ufont == NULL)
- {
- ufont = ami_open_outline_font(fstyle, utf16);
- }
-
- if(ufont)
- {
- tempx = ami_font_width_glyph(ufont, utf16, utf16next, emwidth);
- }
- }
-
- x += tempx;
-
- utf16 += utf16charlen;
- }
-
- free(outf16);
- return x;
-}
-
-void ami_font_initscanner(bool force, bool save)
-{
- ami_font_scan_init(nsoption_charp(font_unicode_file), force, save, glypharray);
-}
-
-void ami_font_finiscanner(void)
-{
- ami_font_scan_fini(glypharray);
-}
-
-void ami_font_savescanner(void)
-{
- ami_font_scan_save(nsoption_charp(font_unicode_file), glypharray);
-}
-
-void ami_init_fonts(void)
-{
- /* Initialise Unicode font scanner */
- ami_font_initscanner(false, true);
-
- /* Initialise font caching etc lists */
- ami_font_cache_init();
-
- /* List for diskfont internal cache */
- NewList(&ami_diskfontlib_list);
-}
-
-void ami_close_fonts(void)
-{
- ami_font_cache_fini();
- ami_font_finiscanner();
-}
-
-void ami_font_close(struct ami_font_cache_node *node)
-{
- /* Called from FreeObjList if node type is AMINS_FONT */
-
- CloseOutlineFont(node->font, &ami_diskfontlib_list);
-}
-
void ami_font_setdevicedpi(int id)
{
DisplayInfoHandle dih;
@@ -954,41 +100,46 @@ void ami_font_close_disk_font(struct TextFont *tfont)
CloseFont(tfont);
}
+/* Font initialisation */
+void ami_font_init(void)
+{
+ if(nsoption_bool(use_diskfont) == false) {
+ ami_font_bullet_init();
+ } else {
+ ami_font_diskfont_init();
+ }
+}
+
+void ami_font_fini(void)
+{
+ if(nsoption_bool(use_diskfont) == false) {
+ ami_font_bullet_fini();
+ }
+}
/* Stub entry points */
static bool nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width)
{
- if(__builtin_expect(nsoption_bool(use_diskfont) == false, 1)) {
- return amiga_nsfont_width(fstyle, string, length, width);
- } else {
- return amiga_bm_nsfont_width(fstyle, string, length, width);
- }
+ if(__builtin_expect(ami_nsfont == NULL, 0)) return false;
+ return ami_nsfont->width(fstyle, string, length, width);
}
static bool nsfont_position_in_string(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
- if(__builtin_expect(nsoption_bool(use_diskfont) == false, 1)) {
- return amiga_nsfont_position_in_string(fstyle, string, length, x,
- char_offset, actual_x);
- } else {
- return amiga_bm_nsfont_position_in_string(fstyle, string, length, x,
- char_offset, actual_x);
- }
+ if(__builtin_expect(ami_nsfont == NULL, 0)) return false;
+ return ami_nsfont->posn(fstyle, string, length, x, char_offset, actual_x);
}
static bool nsfont_split(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
- if(__builtin_expect(nsoption_bool(use_diskfont) == false, 1)) {
- return amiga_nsfont_split(fstyle, string, length, x, char_offset, actual_x);
- } else {
- return amiga_bm_nsfont_split(fstyle, string, length, x, char_offset, actual_x);
- }
+ if(__builtin_expect(ami_nsfont == NULL, 0)) return false;
+ return ami_nsfont->split(fstyle, string, length, x, char_offset, actual_x);
}
const struct font_functions nsfont = {
diff --git a/amiga/font.h b/amiga/font.h
index 98b0a0c..404a36e 100755
--- a/amiga/font.h
+++ b/amiga/font.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008, 2009, 2012 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2008, 2009, 2012, 2016 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -25,11 +25,16 @@
struct ami_font_cache_node;
-ULONG ami_font_unicode_text(struct RastPort *rp, const char *string,
- ULONG length, const plot_font_style_t *fstyle, ULONG x, ULONG y, bool aa);
void ami_font_setdevicedpi(int id);
-void ami_init_fonts(void);
-void ami_close_fonts(void);
+void ami_font_init(void);
+void ami_font_fini(void);
+
+/* In font_bitmap.c */
+void ami_font_diskfont_init(void);
+
+/* In font_bullet.c */
+void ami_font_bullet_init(void);
+void ami_font_bullet_fini(void);
void ami_font_close(struct ami_font_cache_node *node);
/* Alternate entry points into font_scan */
@@ -41,17 +46,28 @@ void ami_font_savescanner(void);
struct TextFont *ami_font_open_disk_font(struct TextAttr *tattr);
void ami_font_close_disk_font(struct TextFont *tfont);
-/* In font_bitmap.c */
-bool amiga_bm_nsfont_width(const plot_font_style_t *fstyle,
- const char *string, size_t length, int *width);
-bool amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x);
-bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x);
-ULONG ami_font_bm_text(struct RastPort *rp, const char *string, ULONG length,
- const plot_font_style_t *fstyle, ULONG dx, ULONG dy);
+/* Font engine tables */
+struct ami_font_functions {
+ bool (*width)(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int *width);
+
+ bool (*posn)(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x);
+
+ bool (*split)(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x);
+
+ ULONG (*text)(struct RastPort *rp, const char *string,
+ ULONG length, const plot_font_style_t *fstyle,
+ ULONG x, ULONG y, bool aa);
+};
+
+ULONG ami_devicedpi;
+ULONG ami_xdpi;
+const struct ami_font_functions *ami_nsfont;
#endif
diff --git a/amiga/font_bitmap.c b/amiga/font_bitmap.c
index eed43db..d9459b0 100644
--- a/amiga/font_bitmap.c
+++ b/amiga/font_bitmap.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 - 2015 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2008 - 2016 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -112,7 +112,7 @@ static size_t ami_font_bm_convert_local_to_utf8_offset(const char *utf8string, i
}
-bool amiga_bm_nsfont_width(const plot_font_style_t *fstyle,
+static bool amiga_bm_nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width)
{
@@ -149,7 +149,7 @@ bool amiga_bm_nsfont_width(const plot_font_style_t *fstyle,
* \return true on success, false on error and error reported
*/
-bool amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyle,
+static bool amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
@@ -203,7 +203,7 @@ bool amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyle,
* Returning char_offset == length means no split possible
*/
-bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
+static bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
@@ -243,7 +243,7 @@ bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
}
}
- if((co > 0) && (co < strlen(localtext))) {
+ if((co > 0) && (co <= strlen(localtext))) {
*actual_x = TextLength(glob->rp, localtext, co);
*char_offset = ami_font_bm_convert_local_to_utf8_offset(string, length, co);
} else {
@@ -257,9 +257,13 @@ bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
return true;
}
-ULONG ami_font_bm_text(struct RastPort *rp, const char *string, ULONG length,
- const plot_font_style_t *fstyle, ULONG dx, ULONG dy)
+static ULONG amiga_bm_nsfont_text(struct RastPort *rp, const char *string, ULONG length,
+ const plot_font_style_t *fstyle, ULONG dx, ULONG dy, bool aa)
{
+ if(!string || string[0]=='\0') return 0;
+ if(!length) return 0;
+ if(rp == NULL) return 0;
+
struct TextFont *bmfont = ami_font_bm_open(rp, fstyle);
char *localtext = NULL;
if(bmfont == NULL) return 0;
@@ -274,3 +278,16 @@ ULONG ami_font_bm_text(struct RastPort *rp, const char *string, ULONG length,
return 0;
}
+const struct ami_font_functions ami_font_diskfont_table = {
+ amiga_bm_nsfont_width,
+ amiga_bm_nsfont_position_in_string,
+ amiga_bm_nsfont_split,
+ amiga_bm_nsfont_text
+};
+
+void ami_font_diskfont_init(void)
+{
+ /* Set up table */
+ ami_nsfont = &ami_font_diskfont_table;
+}
+
diff --git a/amiga/font_bullet.c b/amiga/font_bullet.c
new file mode 100644
index 0000000..432ae88
--- /dev/null
+++ b/amiga/font_bullet.c
@@ -0,0 +1,892 @@
+/*
+ * Copyright 2008 - 2016 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "amiga/os3support.h"
+
+#include <stdlib.h>
+
+#ifndef __amigaos4__
+#include <proto/bullet.h>
+#endif
+#include <proto/diskfont.h>
+#include <proto/graphics.h>
+#include <proto/utility.h>
+
+#include <diskfont/diskfonttag.h>
+#include <diskfont/oterrors.h>
+
+#include "amiga/font.h"
+#include "amiga/font_cache.h"
+#include "amiga/font_scan.h"
+
+#include "utils/log.h"
+#include "utils/nsoption.h"
+#include "utils/utf8.h"
+#include "utils/utils.h"
+
+#define NSA_UNICODE_FONT PLOT_FONT_FAMILY_COUNT
+
+#define NSA_NORMAL 0
+#define NSA_ITALIC 1
+#define NSA_BOLD 2
+#define NSA_BOLDITALIC 3
+#define NSA_OBLIQUE 4
+#define NSA_BOLDOBLIQUE 6
+
+#define NSA_VALUE_BOLDX (1 << 12)
+#define NSA_VALUE_BOLDY 0
+#define NSA_VALUE_SHEARSIN (1 << 14)
+#define NSA_VALUE_SHEARCOS (1 << 16)
+
+#define NSA_FONT_EMWIDTH(s) (s / FONT_SIZE_SCALE) * (ami_xdpi / 72.0)
+
+const uint16 sc_table[] = {
+ 0x0061, 0x1D00, /* a */
+ 0x0062, 0x0299, /* b */
+ 0x0063, 0x1D04, /* c */
+ 0x0064, 0x1D05, /* d */
+ 0x0065, 0x1D07, /* e */
+ 0x0066, 0xA730, /* f */
+ 0x0067, 0x0262, /* g */
+ 0x0068, 0x029C, /* h */
+ 0x0069, 0x026A, /* i */
+ 0x006A, 0x1D0A, /* j */
+ 0x006B, 0x1D0B, /* k */
+ 0x006C, 0x029F, /* l */
+ 0x006D, 0x1D0D, /* m */
+ 0x006E, 0x0274, /* n */
+ 0x006F, 0x1D0F, /* o */
+ 0x0070, 0x1D18, /* p */
+ 0x0071, 0xA7EE, /* q (proposed) (Adobe codepoint 0xF771) */
+ 0x0072, 0x0280, /* r */
+ 0x0073, 0xA731, /* s */
+ 0x0074, 0x1D1B, /* t */
+ 0x0075, 0x1D1C, /* u */
+ 0x0076, 0x1D20, /* v */
+ 0x0077, 0x1D21, /* w */
+ 0x0078, 0xA7EF, /* x (proposed) (Adobe codepoint 0xF778) */
+ 0x0079, 0x028F, /* y */
+ 0x007A, 0x1D22, /* z */
+
+ 0x00C6, 0x1D01, /* ae */
+ 0x0153, 0x0276, /* oe */
+
+#if 0
+/* TODO: fill in the non-small caps character ids for these */
+ 0x0000, 0x1D03, /* barred b */
+ 0x0000, 0x0281, /* inverted r */
+ 0x0000, 0x1D19, /* reversed r */
+ 0x0000, 0x1D1A, /* turned r */
+ 0x0000, 0x029B, /* g with hook */
+ 0x0000, 0x1D06, /* eth Ð */
+ 0x0000, 0x1D0C, /* l with stroke */
+ 0x0000, 0xA7FA, /* turned m */
+ 0x0000, 0x1D0E, /* reversed n */
+ 0x0000, 0x1D10, /* open o */
+ 0x0000, 0x1D15, /* ou */
+ 0x0000, 0x1D23, /* ezh */
+ 0x0000, 0x1D26, /* gamma */
+ 0x0000, 0x1D27, /* lamda */
+ 0x0000, 0x1D28, /* pi */
+ 0x0000, 0x1D29, /* rho */
+ 0x0000, 0x1D2A, /* psi */
+ 0x0000, 0x1D2B, /* el */
+ 0x0000, 0xA776, /* rum */
+
+ 0x0000, 0x1DDB, /* combining g */
+ 0x0000, 0x1DDE, /* combining l */
+ 0x0000, 0x1DDF, /* combining m */
+ 0x0000, 0x1DE1, /* combining n */
+ 0x0000, 0x1DE2, /* combining r */
+
+ 0x0000, 0x1DA6, /* modifier i */
+ 0x0000, 0x1DA7, /* modifier i with stroke */
+ 0x0000, 0x1DAB, /* modifier l */
+ 0x0000, 0x1DB0, /* modifier n */
+ 0x0000, 0x1DB8, /* modifier u */
+#endif
+ 0, 0};
+
+lwc_string *glypharray[0xffff + 1];
+
+static struct List ami_diskfontlib_list;
+
+static inline int32 ami_font_plot_glyph(struct OutlineFont *ofont, struct RastPort *rp,
+ uint16 *char1, uint16 *char2, uint32 x, uint32 y, uint32 emwidth, bool aa);
+static inline int32 ami_font_width_glyph(struct OutlineFont *ofont,
+ const uint16 *char1, const uint16 *char2, uint32 emwidth);
+static struct OutlineFont *ami_open_outline_font(const plot_font_style_t *fstyle,
+ const uint16 *codepoint);
+static inline ULONG ami_font_unicode_width(const char *string, ULONG length,
+ const plot_font_style_t *fstyle, ULONG x, ULONG y, bool aa);
+
+static inline int amiga_nsfont_utf16_char_length(const uint16 *char1)
+{
+ if (__builtin_expect(((*char1 < 0xD800) || (0xDBFF < *char1)), 1)) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+static inline uint32 amiga_nsfont_decode_surrogate(const uint16 *char1)
+{
+ if(__builtin_expect((amiga_nsfont_utf16_char_length(char1) == 2), 0)) {
+ return ((uint32)char1[0] << 10) + char1[1] - 0x35FDC00;
+ } else {
+ return (uint32)*char1;
+ }
+}
+
+static inline bool amiga_nsfont_width(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int *width)
+{
+ *width = ami_font_unicode_width(string, length, fstyle, 0, 0, false);
+
+ if(*width <= 0) *width == length; // fudge
+
+ return true;
+}
+
+/**
+ * Find the position in a string where an x coordinate falls.
+ *
+ * \param fstyle style for this text
+ * \param string UTF-8 string to measure
+ * \param length length of string
+ * \param x x coordinate to search for
+ * \param char_offset updated to offset in string of actual_x, [0..length]
+ * \param actual_x updated to x coordinate of character closest to x
+ * \return true on success, false on error and error reported
+ */
+
+static inline bool amiga_nsfont_position_in_string(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x)
+{
+ uint16 *utf16 = NULL, *outf16 = NULL;
+ uint16 *utf16next = NULL;
+ struct OutlineFont *ofont, *ufont = NULL;
+ int tx = 0;
+ uint32 utf8_pos = 0;
+ int utf16charlen;
+ ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
+ int32 tempx;
+
+ if(utf8_to_enc(string,"UTF-16",length,(char **)&utf16) != NSERROR_OK) return false;
+ outf16 = utf16;
+ if(!(ofont = ami_open_outline_font(fstyle, 0))) return false;
+
+ *char_offset = 0;
+ *actual_x = 0;
+
+ while (utf8_pos < length) {
+ utf16charlen = amiga_nsfont_utf16_char_length(utf16);
+ utf16next = &utf16[utf16charlen];
+
+ tempx = ami_font_width_glyph(ofont, utf16, utf16next, emwidth);
+
+ if (tempx == 0) {
+ if (ufont == NULL)
+ ufont = ami_open_outline_font(fstyle, utf16);
+
+ if (ufont)
+ tempx = ami_font_width_glyph(ufont, utf16,
+ utf16next, emwidth);
+ }
+
+ tx += tempx;
+ utf16 = utf16next;
+ utf8_pos = utf8_next(string, length, utf8_pos);
+
+ if(tx < x) {
+ *actual_x = tx;
+ *char_offset = utf8_pos;
+ } else {
+ if((x - *actual_x) > (tx - x)) {
+ *actual_x = tx;
+ *char_offset = utf8_pos;
+ }
+ free(outf16);
+ return true;
+ }
+ }
+
+ *actual_x = tx;
+ *char_offset = length;
+
+ free(outf16);
+ return true;
+}
+
+
+/**
+ * Find where to split a string to make it fit a width.
+ *
+ * \param fstyle style for this text
+ * \param string UTF-8 string to measure
+ * \param length length of string
+ * \param x width available
+ * \param char_offset updated to offset in string of actual_x, [1..length]
+ * \param actual_x updated to x coordinate of character closest to x
+ * \return true on success, false on error and error reported
+ *
+ * On exit, char_offset indicates first character after split point.
+ *
+ * Note: char_offset of 0 should never be returned.
+ *
+ * Returns:
+ * char_offset giving split point closest to x, where actual_x <= x
+ * else
+ * char_offset giving split point closest to x, where actual_x > x
+ *
+ * Returning char_offset == length means no split possible
+ */
+
+static inline bool amiga_nsfont_split(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x)
+{
+ uint16 *utf16_str = NULL;
+ const uint16 *utf16 = NULL;
+ const uint16 *utf16next = NULL;
+ struct OutlineFont *ofont, *ufont = NULL;
+ int tx = 0;
+ uint32 utf8_pos = 0;
+ int32 tempx = 0;
+ ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
+
+ /* Get utf16 conversion of string for glyph measuring routines */
+ if (utf8_to_enc(string, "UTF-16", length, (char **)&utf16_str) !=
+ NSERROR_OK)
+ return false;
+
+ utf16 = utf16_str;
+ if (!(ofont = ami_open_outline_font(fstyle, 0)))
+ return false;
+
+ *char_offset = 0;
+ *actual_x = 0;
+
+ if (*utf16 == 0xFEFF) utf16++;
+
+ while (utf8_pos < length) {
+ if ((*utf16 < 0xD800) || (0xDBFF < *utf16))
+ utf16next = utf16 + 1;
+ else
+ utf16next = utf16 + 2;
+
+ tempx = ami_font_width_glyph(ofont, utf16, utf16next, emwidth);
+
+ if (tempx == 0) {
+ if (ufont == NULL)
+ ufont = ami_open_outline_font(fstyle, utf16);
+
+ if (ufont)
+ tempx = ami_font_width_glyph(ufont, utf16,
+ utf16next, emwidth);
+ }
+
+ /* Check whether we have a space */
+ if (*(string + utf8_pos) == ' ') {
+ /* Got a space */
+ *actual_x = tx;
+ *char_offset = utf8_pos;
+ }
+
+ tx += tempx;
+ if ((x < tx) && (*char_offset != 0)) {
+ /* Reached available width, and a space was found;
+ * split there. */
+ free(utf16_str);
+ return true;
+ }
+
+ utf16 = utf16next;
+ utf8_pos = utf8_next(string, length, utf8_pos);
+ }
+
+ free(utf16_str);
+
+ /* No spaces to split at, or everything fits */
+ assert(*char_offset == 0 || x >= tx);
+
+ *char_offset = length;
+ *actual_x = tx;
+ return true;
+}
+
+/**
+ * Search for a font in the list and load from disk if not present
+ */
+static struct ami_font_cache_node *ami_font_open(const char *font, bool critical)
+{
+ struct ami_font_cache_node *nodedata = ami_font_cache_locate(font);
+ if(nodedata) return nodedata;
+
+ nodedata = ami_font_cache_alloc_entry(font);
+
+ if(nodedata == NULL) {
+ warn_user("NoMemory", "");
+ return NULL;
+ }
+
+ nodedata->font = OpenOutlineFont(font, &ami_diskfontlib_list, OFF_OPEN);
+
+ if(!nodedata->font)
+ {
+ LOG("Requested font not found: %s", font);
+ if(critical == true) warn_user("CompError", font);
+ FreeVec(nodedata);
+ return NULL;
+ }
+
+ nodedata->bold = (char *)GetTagData(OT_BName, 0, nodedata->font->olf_OTagList);
+ if(nodedata->bold)
+ LOG("Bold font defined for %s is %s", font, nodedata->bold);
+ else
+ LOG("Warning: No designed bold font defined for %s", font);
+
+ nodedata->italic = (char *)GetTagData(OT_IName, 0, nodedata->font->olf_OTagList);
+ if(nodedata->italic)
+ LOG("Italic font defined for %s is %s", font, nodedata->italic);
+ else
+ LOG("Warning: No designed italic font defined for %s", font);
+
+ nodedata->bolditalic = (char *)GetTagData(OT_BIName, 0, nodedata->font->olf_OTagList);
+ if(nodedata->bolditalic)
+ LOG("Bold-italic font defined for %s is %s", font, nodedata->bolditalic);
+ else
+ LOG("Warning: No designed bold-italic font defined for %s", font);
+
+ ami_font_cache_insert(nodedata, font);
+ return nodedata;
+}
+
+/**
+ * Open an outline font in the specified size and style
+ *
+ * \param fstyle font style structure
+ * \param codepoint open a default font instead of the one specified by fstyle
+ * \return outline font or NULL on error
+ */
+static struct OutlineFont *ami_open_outline_font(const plot_font_style_t *fstyle,
+ const uint16 *codepoint)
+{
+ struct ami_font_cache_node *node;
+ struct ami_font_cache_node *designed_node = NULL;
+ struct OutlineFont *ofont;
+ char *fontname;
+ ULONG ysize;
+ int tstyle = 0;
+ plot_font_generic_family_t fontfamily;
+ ULONG emboldenx = 0;
+ ULONG emboldeny = 0;
+ ULONG shearsin = 0;
+ ULONG shearcos = (1 << 16);
+
+ if(codepoint) fontfamily = NSA_UNICODE_FONT;
+ else fontfamily = fstyle->family;
+
+ switch(fontfamily)
+ {
+ case PLOT_FONT_FAMILY_SANS_SERIF:
+ fontname = nsoption_charp(font_sans);
+ break;
+ case PLOT_FONT_FAMILY_SERIF:
+ fontname = nsoption_charp(font_serif);
+ break;
+ case PLOT_FONT_FAMILY_MONOSPACE:
+ fontname = nsoption_charp(font_mono);
+ break;
+ case PLOT_FONT_FAMILY_CURSIVE:
+ fontname = nsoption_charp(font_cursive);
+ break;
+ case PLOT_FONT_FAMILY_FANTASY:
+ fontname = nsoption_charp(font_fantasy);
+ break;
+ case NSA_UNICODE_FONT:
+ default:
+ if(__builtin_expect((amiga_nsfont_utf16_char_length(codepoint) == 2), 0)) {
+ /* Multi-byte character */
+ fontname = nsoption_charp(font_surrogate);
+ } else {
+ fontname = (char *)ami_font_scan_lookup(codepoint, glypharray);
+ }
+ if(fontname == NULL) return NULL;
+ break;
+ }
+
+ node = ami_font_open(fontname, true);
+ if(!node) return NULL;
+
+ if (fstyle->flags & FONTF_OBLIQUE)
+ tstyle = NSA_OBLIQUE;
+
+ if (fstyle->flags & FONTF_ITALIC)
+ tstyle = NSA_ITALIC;
+
+ if (fstyle->weight >= 700)
+ tstyle += NSA_BOLD;
+
+ switch(tstyle)
+ {
+ case NSA_ITALIC:
+ if(node->italic) designed_node = ami_font_open(node->italic, false);
+
+ if(designed_node == NULL) {
+ shearsin = NSA_VALUE_SHEARSIN;
+ shearcos = NSA_VALUE_SHEARCOS;
+ }
+ break;
+
+ case NSA_OBLIQUE:
+ shearsin = NSA_VALUE_SHEARSIN;
+ shearcos = NSA_VALUE_SHEARCOS;
+ break;
+
+ case NSA_BOLD:
+ if(node->bold) designed_node = ami_font_open(node->bold, false);
+
+ if(designed_node == NULL) {
+ emboldenx = NSA_VALUE_BOLDX;
+ emboldeny = NSA_VALUE_BOLDY;
+ }
+ break;
+
+ case NSA_BOLDOBLIQUE:
+ shearsin = NSA_VALUE_SHEARSIN;
+ shearcos = NSA_VALUE_SHEARCOS;
+
+ if(node->bold) designed_node = ami_font_open(node->bold, false);
+
+ if(designed_node == NULL) {
+ emboldenx = NSA_VALUE_BOLDX;
+ emboldeny = NSA_VALUE_BOLDY;
+ }
+ break;
+
+ case NSA_BOLDITALIC:
+ if(node->bolditalic) designed_node = ami_font_open(node->bolditalic, false);
+
+ if(designed_node == NULL) {
+ emboldenx = NSA_VALUE_BOLDX;
+ emboldeny = NSA_VALUE_BOLDY;
+ shearsin = NSA_VALUE_SHEARSIN;
+ shearcos = NSA_VALUE_SHEARCOS;
+ }
+ break;
+ }
+
+ /* Scale to 16.16 fixed point */
+ ysize = fstyle->size * ((1 << 16) / FONT_SIZE_SCALE);
+
+ if(designed_node == NULL) {
+ ofont = node->font;
+ } else {
+ ofont = designed_node->font;
+ }
+
+#ifndef __amigaos4__
+ struct BulletBase *BulletBase = ofont->BulletBase;
+#endif
+
+ if(ESetInfo(AMI_OFONT_ENGINE,
+ OT_DeviceDPI, ami_devicedpi,
+ OT_PointHeight, ysize,
+ OT_EmboldenX, emboldenx,
+ OT_EmboldenY, emboldeny,
+ OT_ShearSin, shearsin,
+ OT_ShearCos, shearcos,
+ TAG_END) == OTERR_Success)
+ return ofont;
+
+ return NULL;
+}
+
+static inline int32 ami_font_plot_glyph(struct OutlineFont *ofont, struct RastPort *rp,
+ uint16 *char1, uint16 *char2, uint32 x, uint32 y, uint32 emwidth, bool aa)
+{
+ struct GlyphMap *glyph;
+ UBYTE *glyphbm;
+ int32 char_advance = 0;
+ FIXED kern = 0;
+ ULONG glyphmaptag;
+ ULONG template_type;
+ uint32 long_char_1 = 0, long_char_2 = 0;
+#ifndef __amigaos4__
+ struct BulletBase *BulletBase = ofont->BulletBase;
+#endif
+
+#ifndef __amigaos4__
+ if (__builtin_expect(((*char1 >= 0xD800) && (*char1 <= 0xDBFF)), 0)) {
+ /* We don't support UTF-16 surrogates yet, so just return. */
+ return 0;
+ }
+
+ if (__builtin_expect(((*char2 >= 0xD800) && (*char2 <= 0xDBFF)), 0)) {
+ /* Don't attempt to kern a UTF-16 surrogate */
+ *char2 = 0;
+ }
+#endif
+
+#ifdef __amigaos4__
+ if(__builtin_expect(aa == true, 1)) {
+ glyphmaptag = OT_GlyphMap8Bit;
+ template_type = BLITT_ALPHATEMPLATE;
+ } else {
+#endif
+ glyphmaptag = OT_GlyphMap;
+#ifdef __amigaos4__
+ template_type = BLITT_TEMPLATE;
+ }
+#endif
+
+ long_char_1 = amiga_nsfont_decode_surrogate(char1);
+ long_char_2 = amiga_nsfont_decode_surrogate(char2);
+ /**\todo use OT_GlyphCode_32 so we get an error for old font engines */
+
+ if(ESetInfo(AMI_OFONT_ENGINE,
+ OT_GlyphCode, long_char_1,
+ OT_GlyphCode2, long_char_2,
+ TAG_END) == OTERR_Success)
+ {
+ if(EObtainInfo(AMI_OFONT_ENGINE,
+ glyphmaptag, &glyph,
+ TAG_END) == 0)
+ {
+ glyphbm = glyph->glm_BitMap;
+ if(!glyphbm) return 0;
+
+ if(rp) {
+#ifdef __amigaos4__
+ BltBitMapTags(BLITA_SrcX, glyph->glm_BlackLeft,
+ BLITA_SrcY, glyph->glm_BlackTop,
+ BLITA_DestX, x - glyph->glm_X0 + glyph->glm_BlackLeft,
+ BLITA_DestY, y - glyph->glm_Y0 + glyph->glm_BlackTop,
+ BLITA_Width, glyph->glm_BlackWidth,
+ BLITA_Height, glyph->glm_BlackHeight,
+ BLITA_Source, glyphbm,
+ BLITA_SrcType, template_type,
+ BLITA_Dest, rp,
+ BLITA_DestType, BLITT_RASTPORT,
+ BLITA_SrcBytesPerRow, glyph->glm_BMModulo,
+ TAG_DONE);
+#else
+ /* On OS3 the glyph needs to be in chip RAM */
+ void *chip_glyph = AllocVec(glyph->glm_BMModulo * glyph->glm_BMRows, MEMF_CHIP);
+ if(chip_glyph != NULL) {
+ CopyMem(glyphbm, chip_glyph, glyph->glm_BMModulo * glyph->glm_BMRows);
+
+ BltTemplate(chip_glyph + (glyph->glm_BMModulo * glyph->glm_BlackTop) +
+ ((glyph->glm_BlackLeft >> 4) << 1),
+ glyph->glm_BlackLeft & 0xF, glyph->glm_BMModulo, rp,
+ x - glyph->glm_X0 + glyph->glm_BlackLeft,
+ y - glyph->glm_Y0 + glyph->glm_BlackTop,
+ glyph->glm_BlackWidth, glyph->glm_BlackHeight);
+
+ FreeVec(chip_glyph);
+ }
+#endif
+ }
+
+ kern = 0;
+
+ if(*char2) EObtainInfo(AMI_OFONT_ENGINE,
+ OT_TextKernPair, &kern,
+ TAG_END);
+
+ char_advance = (ULONG)(((glyph->glm_Width - kern) * emwidth) / 65536);
+
+ EReleaseInfo(AMI_OFONT_ENGINE,
+ glyphmaptag, glyph,
+ TAG_END);
+
+ if(*char2) EReleaseInfo(AMI_OFONT_ENGINE,
+ OT_TextKernPair, kern,
+ TAG_END);
+ }
+ }
+
+ return char_advance;
+}
+
+static inline int32 ami_font_width_glyph(struct OutlineFont *ofont,
+ const uint16 *char1, const uint16 *char2, uint32 emwidth)
+{
+ int32 char_advance = 0;
+ FIXED kern = 0;
+ struct MinList *gwlist = NULL;
+ FIXED char1w = 0;
+ struct GlyphWidthEntry *gwnode;
+ bool skip_c2 = false;
+ uint32 long_char_1 = 0;
+ uint32 long_char_2;
+#ifndef __amigaos4__
+ struct BulletBase *BulletBase = ofont->BulletBase;
+#endif
+
+#ifndef __amigaos4__
+ if (__builtin_expect(((*char1 >= 0xD800) && (*char1 <= 0xDBFF)), 0)) {
+ /* We don't support UTF-16 surrogates yet, so just return. */
+ return 0;
+ }
+
+ if (__builtin_expect(((*char2 >= 0xD800) && (*char2 <= 0xDBFF)), 0)) {
+ /* Don't attempt to kern a UTF-16 surrogate */
+ skip_c2 = true;
+ }
+#endif
+
+ if (*char2 < 0x0020) skip_c2 = true;
+
+ long_char_1 = amiga_nsfont_decode_surrogate(char1);
+ /**\todo use OT_GlyphCode_32 so we get an error for old font engines */
+
+ if(ESetInfo(AMI_OFONT_ENGINE,
+ OT_GlyphCode, long_char_1,
+ OT_GlyphCode2, long_char_1,
+ TAG_END) == OTERR_Success)
+ {
+ if(EObtainInfo(AMI_OFONT_ENGINE,
+ OT_WidthList, &gwlist,
+ TAG_END) == 0)
+ {
+ gwnode = (struct GlyphWidthEntry *)GetHead((struct List *)gwlist);
+ if(gwnode) char1w = gwnode->gwe_Width;
+
+ kern = 0;
+
+ if(!skip_c2) {
+ long_char_2 = amiga_nsfont_decode_surrogate(char2);
+ if(ESetInfo(AMI_OFONT_ENGINE,
+ OT_GlyphCode, long_char_1,
+ OT_GlyphCode2, long_char_2,
+ TAG_END) == OTERR_Success)
+ {
+ EObtainInfo(AMI_OFONT_ENGINE,
+ OT_TextKernPair, &kern,
+ TAG_END);
+ }
+ }
+ char_advance = (ULONG)(((char1w - kern) * emwidth) / 65536);
+
+ if(!skip_c2) EReleaseInfo(AMI_OFONT_ENGINE,
+ OT_TextKernPair, kern,
+ TAG_END);
+
+ EReleaseInfo(AMI_OFONT_ENGINE,
+ OT_WidthList, gwlist,
+ TAG_END);
+ }
+ }
+
+ return char_advance;
+}
+
+static const uint16 *ami_font_translate_smallcaps(uint16 *utf16char)
+{
+ const uint16 *p;
+ p = &sc_table[0];
+
+ while (*p != 0)
+ {
+ if(*p == *utf16char) return &p[1];
+ p++;
+ }
+
+ return utf16char;
+}
+
+static ULONG amiga_nsfont_text(struct RastPort *rp, const char *string, ULONG length,
+ const plot_font_style_t *fstyle, ULONG dx, ULONG dy, bool aa)
+{
+ uint16 *utf16 = NULL, *outf16 = NULL;
+ uint16 *utf16charsc = 0, *utf16nextsc = 0;
+ uint16 *utf16next = 0;
+ int utf16charlen;
+ struct OutlineFont *ofont, *ufont = NULL;
+ uint32 x=0;
+ int32 tempx = 0;
+ ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
+ uint16 utf16_a = 0x41;
+
+ if(!string || string[0]=='\0') return 0;
+ if(!length) return 0;
+ if(rp == NULL) return 0;
+
+ if(utf8_to_enc(string,"UTF-16",length,(char **)&utf16) != NSERROR_OK) return 0;
+ outf16 = utf16;
+ if(!(ofont = ami_open_outline_font(fstyle, 0))) {
+ if(!(ofont = ami_open_outline_font(fstyle, &utf16_a))) return 0;
+ }
+
+ while(*utf16 != 0)
+ {
+ utf16charlen = amiga_nsfont_utf16_char_length(utf16);
+ utf16next = &utf16[utf16charlen];
+
+ if(fstyle->flags & FONTF_SMALLCAPS)
+ {
+ utf16charsc = (uint16 *)ami_font_translate_smallcaps(utf16);
+ utf16nextsc = (uint16 *)ami_font_translate_smallcaps(utf16next);
+
+ tempx = ami_font_plot_glyph(ofont, rp, utf16charsc, utf16nextsc,
+ dx + x, dy, emwidth, aa);
+ }
+ else tempx = 0;
+
+ if(tempx == 0) {
+ tempx = ami_font_plot_glyph(ofont, rp, utf16, utf16next,
+ dx + x, dy, emwidth, aa);
+ }
+
+ if(tempx == 0)
+ {
+ if(ufont == NULL)
+ {
+ ufont = ami_open_outline_font(fstyle, utf16);
+ }
+
+ if(ufont) {
+ tempx = ami_font_plot_glyph(ufont, rp, utf16, utf16next,
+ dx + x, dy, emwidth, aa);
+ }
+ }
+
+ x += tempx;
+
+ utf16 += utf16charlen;
+ }
+
+ free(outf16);
+ return x;
+}
+
+static inline ULONG ami_font_unicode_width(const char *string, ULONG length,
+ const plot_font_style_t *fstyle, ULONG dx, ULONG dy, bool aa)
+{
+ uint16 *utf16 = NULL, *outf16 = NULL;
+ uint16 *utf16charsc = 0, *utf16nextsc = 0;
+ uint16 *utf16next = 0;
+ int utf16charlen;
+ struct OutlineFont *ofont, *ufont = NULL;
+ uint32 x=0;
+ int32 tempx = 0;
+ ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
+ uint16 utf16_a = 0x41;
+
+ if(!string || string[0]=='\0') return 0;
+ if(!length) return 0;
+
+ if(utf8_to_enc(string,"UTF-16",length,(char **)&utf16) != NSERROR_OK) return 0;
+ outf16 = utf16;
+ if(!(ofont = ami_open_outline_font(fstyle, 0))) {
+ if(!(ofont = ami_open_outline_font(fstyle, &utf16_a))) return 0;
+ }
+
+ while(*utf16 != 0)
+ {
+ utf16charlen = amiga_nsfont_utf16_char_length(utf16);
+ utf16next = &utf16[utf16charlen];
+
+ if(fstyle->flags & FONTF_SMALLCAPS)
+ {
+ utf16charsc = (uint16 *)ami_font_translate_smallcaps(utf16);
+ utf16nextsc = (uint16 *)ami_font_translate_smallcaps(utf16next);
+
+ tempx = ami_font_width_glyph(ofont, utf16charsc, utf16nextsc, emwidth);
+ }
+ else tempx = 0;
+
+ if(tempx == 0) {
+ tempx = ami_font_width_glyph(ofont, utf16, utf16next, emwidth);
+ }
+
+ if(tempx == 0)
+ {
+ if(ufont == NULL)
+ {
+ ufont = ami_open_outline_font(fstyle, utf16);
+ }
+
+ if(ufont)
+ {
+ tempx = ami_font_width_glyph(ufont, utf16, utf16next, emwidth);
+ }
+ }
+
+ x += tempx;
+
+ utf16 += utf16charlen;
+ }
+
+ free(outf16);
+ return x;
+}
+
+void ami_font_initscanner(bool force, bool save)
+{
+ ami_font_scan_init(nsoption_charp(font_unicode_file), force, save, glypharray);
+}
+
+void ami_font_finiscanner(void)
+{
+ ami_font_scan_fini(glypharray);
+}
+
+void ami_font_savescanner(void)
+{
+ ami_font_scan_save(nsoption_charp(font_unicode_file), glypharray);
+}
+
+void ami_font_close(struct ami_font_cache_node *node)
+{
+ /* Called from FreeObjList if node type is AMINS_FONT */
+ CloseOutlineFont(node->font, &ami_diskfontlib_list);
+}
+
+const struct ami_font_functions ami_font_bullet_table = {
+ amiga_nsfont_width,
+ amiga_nsfont_position_in_string,
+ amiga_nsfont_split,
+ amiga_nsfont_text
+};
+
+void ami_font_bullet_init(void)
+{
+ /* Initialise Unicode font scanner */
+ ami_font_initscanner(false, true);
+
+ /* Initialise font caching etc lists */
+ ami_font_cache_init();
+
+ /* List for diskfont internal cache */
+ NewList(&ami_diskfontlib_list);
+
+ /* Set up table */
+ ami_nsfont = &ami_font_bullet_table;
+}
+
+void ami_font_bullet_fini(void)
+{
+ ami_font_cache_fini();
+ ami_font_finiscanner();
+}
+
diff --git a/amiga/gui.c b/amiga/gui.c
index 4eb2c47..6744d99 100644
--- a/amiga/gui.c
+++ b/amiga/gui.c
@@ -3016,7 +3016,7 @@ static void gui_quit(void)
ami_free_layers(&browserglob);
- ami_close_fonts();
+ ami_font_fini();
ami_help_free();
LOG("Closing screen");
@@ -5633,7 +5633,7 @@ int main(int argc, char** argv)
ami_clipboard_init();
ami_openurl_open();
ami_amiupdate(); /* set env-vars for AmiUpdate */
- ami_init_fonts();
+ ami_font_init();
save_complete_init();
ami_theme_init();
ami_init_mouse_pointers();
diff --git a/amiga/plotters.c b/amiga/plotters.c
index dc68f93..ea13285 100644
--- a/amiga/plotters.c
+++ b/amiga/plotters.c
@@ -434,7 +434,7 @@ static bool ami_text(int x, int y, const char *text, size_t length,
aa = false;
ami_plot_setapen(glob->rp, fstyle->foreground);
- ami_font_unicode_text(glob->rp, text, length, fstyle, x, y, aa);
+ ami_nsfont->text(glob->rp, text, length, fstyle, x, y, aa);
return true;
}
-----------------------------------------------------------------------
Summary of changes:
amiga/Makefile.target | 2 +-
amiga/font.c | 895 +--------------------------------------
amiga/font.h | 48 ++-
amiga/font_bitmap.c | 31 +-
amiga/{font.c => font_bullet.c} | 159 ++-----
amiga/gui.c | 4 +-
amiga/plotters.c | 2 +-
7 files changed, 109 insertions(+), 1032 deletions(-)
copy amiga/{font.c => font_bullet.c} (86%)
diff --git a/amiga/Makefile.target b/amiga/Makefile.target
index 391dd6e..626110b 100644
--- a/amiga/Makefile.target
+++ b/amiga/Makefile.target
@@ -76,7 +76,7 @@ S_AMIGA := gui.c tree.c history.c hotlist.c schedule.c file.c \
datatypes.c dt_picture.c dt_anim.c dt_sound.c plugin_hack.c \
stringview/stringview.c stringview/urlhistory.c rtg.c \
agclass/amigaguide_class.c os3support.c font_bitmap.c \
- selectmenu.c hash/xxhash.c font_cache.c
+ selectmenu.c hash/xxhash.c font_cache.c font_bullet.c
S_AMIGA := $(addprefix amiga/,$(S_AMIGA))
# This is the final source build list
diff --git a/amiga/font.c b/amiga/font.c
index 3a141ac..5701758 100644
--- a/amiga/font.c
+++ b/amiga/font.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 - 2015 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2008 - 2016 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -25,11 +25,7 @@
#endif
#include <proto/diskfont.h>
#include <proto/exec.h>
-#include <proto/graphics.h>
-#include <proto/utility.h>
-#include <diskfont/diskfonttag.h>
-#include <diskfont/oterrors.h>
#include <graphics/rpattr.h>
#ifdef __amigaos4__
@@ -37,7 +33,6 @@
#endif
#include "utils/log.h"
-#include "utils/utf8.h"
#include "utils/utils.h"
#include "utils/nsoption.h"
#include "desktop/browser.h"
@@ -45,859 +40,10 @@
#include "desktop/gui_window.h"
#include "amiga/font.h"
-#include "amiga/font_cache.h"
#include "amiga/font_scan.h"
#include "amiga/gui.h"
#include "amiga/utf8.h"
-#define NSA_UNICODE_FONT PLOT_FONT_FAMILY_COUNT
-
-#define NSA_NORMAL 0
-#define NSA_ITALIC 1
-#define NSA_BOLD 2
-#define NSA_BOLDITALIC 3
-#define NSA_OBLIQUE 4
-#define NSA_BOLDOBLIQUE 6
-
-#define NSA_VALUE_BOLDX (1 << 12)
-#define NSA_VALUE_BOLDY 0
-#define NSA_VALUE_SHEARSIN (1 << 14)
-#define NSA_VALUE_SHEARCOS (1 << 16)
-
-#define NSA_FONT_EMWIDTH(s) (s / FONT_SIZE_SCALE) * (ami_xdpi / 72.0)
-
-const uint16 sc_table[] = {
- 0x0061, 0x1D00, /* a */
- 0x0062, 0x0299, /* b */
- 0x0063, 0x1D04, /* c */
- 0x0064, 0x1D05, /* d */
- 0x0065, 0x1D07, /* e */
- 0x0066, 0xA730, /* f */
- 0x0067, 0x0262, /* g */
- 0x0068, 0x029C, /* h */
- 0x0069, 0x026A, /* i */
- 0x006A, 0x1D0A, /* j */
- 0x006B, 0x1D0B, /* k */
- 0x006C, 0x029F, /* l */
- 0x006D, 0x1D0D, /* m */
- 0x006E, 0x0274, /* n */
- 0x006F, 0x1D0F, /* o */
- 0x0070, 0x1D18, /* p */
- 0x0071, 0xA7EE, /* q (proposed) (Adobe codepoint 0xF771) */
- 0x0072, 0x0280, /* r */
- 0x0073, 0xA731, /* s */
- 0x0074, 0x1D1B, /* t */
- 0x0075, 0x1D1C, /* u */
- 0x0076, 0x1D20, /* v */
- 0x0077, 0x1D21, /* w */
- 0x0078, 0xA7EF, /* x (proposed) (Adobe codepoint 0xF778) */
- 0x0079, 0x028F, /* y */
- 0x007A, 0x1D22, /* z */
-
- 0x00C6, 0x1D01, /* ae */
- 0x0153, 0x0276, /* oe */
-
-#if 0
-/* TODO: fill in the non-small caps character ids for these */
- 0x0000, 0x1D03, /* barred b */
- 0x0000, 0x0281, /* inverted r */
- 0x0000, 0x1D19, /* reversed r */
- 0x0000, 0x1D1A, /* turned r */
- 0x0000, 0x029B, /* g with hook */
- 0x0000, 0x1D06, /* eth � */
- 0x0000, 0x1D0C, /* l with stroke */
- 0x0000, 0xA7FA, /* turned m */
- 0x0000, 0x1D0E, /* reversed n */
- 0x0000, 0x1D10, /* open o */
- 0x0000, 0x1D15, /* ou */
- 0x0000, 0x1D23, /* ezh */
- 0x0000, 0x1D26, /* gamma */
- 0x0000, 0x1D27, /* lamda */
- 0x0000, 0x1D28, /* pi */
- 0x0000, 0x1D29, /* rho */
- 0x0000, 0x1D2A, /* psi */
- 0x0000, 0x1D2B, /* el */
- 0x0000, 0xA776, /* rum */
-
- 0x0000, 0x1DDB, /* combining g */
- 0x0000, 0x1DDE, /* combining l */
- 0x0000, 0x1DDF, /* combining m */
- 0x0000, 0x1DE1, /* combining n */
- 0x0000, 0x1DE2, /* combining r */
-
- 0x0000, 0x1DA6, /* modifier i */
- 0x0000, 0x1DA7, /* modifier i with stroke */
- 0x0000, 0x1DAB, /* modifier l */
- 0x0000, 0x1DB0, /* modifier n */
- 0x0000, 0x1DB8, /* modifier u */
-#endif
- 0, 0};
-
-lwc_string *glypharray[0xffff + 1];
-ULONG ami_devicedpi;
-ULONG ami_xdpi;
-
-static struct List ami_diskfontlib_list;
-
-static inline int32 ami_font_plot_glyph(struct OutlineFont *ofont, struct RastPort *rp,
- uint16 *char1, uint16 *char2, uint32 x, uint32 y, uint32 emwidth, bool aa);
-static inline int32 ami_font_width_glyph(struct OutlineFont *ofont,
- const uint16 *char1, const uint16 *char2, uint32 emwidth);
-static struct OutlineFont *ami_open_outline_font(const plot_font_style_t *fstyle,
- const uint16 *codepoint);
-static inline ULONG ami_font_unicode_width(const char *string, ULONG length,
- const plot_font_style_t *fstyle, ULONG x, ULONG y, bool aa);
-
-static inline int amiga_nsfont_utf16_char_length(const uint16 *char1)
-{
- if (__builtin_expect(((*char1 < 0xD800) || (0xDBFF < *char1)), 1)) {
- return 1;
- } else {
- return 2;
- }
-}
-
-static inline uint32 amiga_nsfont_decode_surrogate(const uint16 *char1)
-{
- if(__builtin_expect((amiga_nsfont_utf16_char_length(char1) == 2), 0)) {
- return ((uint32)char1[0] << 10) + char1[1] - 0x35FDC00;
- } else {
- return (uint32)*char1;
- }
-}
-
-static inline bool amiga_nsfont_width(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int *width)
-{
- *width = ami_font_unicode_width(string, length, fstyle, 0, 0, false);
-
- if(*width <= 0) *width == length; // fudge
-
- return true;
-}
-
-/**
- * Find the position in a string where an x coordinate falls.
- *
- * \param fstyle style for this text
- * \param string UTF-8 string to measure
- * \param length length of string
- * \param x x coordinate to search for
- * \param char_offset updated to offset in string of actual_x, [0..length]
- * \param actual_x updated to x coordinate of character closest to x
- * \return true on success, false on error and error reported
- */
-
-static inline bool amiga_nsfont_position_in_string(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x)
-{
- uint16 *utf16 = NULL, *outf16 = NULL;
- uint16 *utf16next = NULL;
- struct OutlineFont *ofont, *ufont = NULL;
- int tx = 0;
- uint32 utf8_pos = 0;
- int utf16charlen;
- ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
- int32 tempx;
-
- if(utf8_to_enc(string,"UTF-16",length,(char **)&utf16) != NSERROR_OK) return false;
- outf16 = utf16;
- if(!(ofont = ami_open_outline_font(fstyle, 0))) return false;
-
- *char_offset = 0;
- *actual_x = 0;
-
- while (utf8_pos < length) {
- utf16charlen = amiga_nsfont_utf16_char_length(utf16);
- utf16next = &utf16[utf16charlen];
-
- tempx = ami_font_width_glyph(ofont, utf16, utf16next, emwidth);
-
- if (tempx == 0) {
- if (ufont == NULL)
- ufont = ami_open_outline_font(fstyle, utf16);
-
- if (ufont)
- tempx = ami_font_width_glyph(ufont, utf16,
- utf16next, emwidth);
- }
-
- tx += tempx;
- utf16 = utf16next;
- utf8_pos = utf8_next(string, length, utf8_pos);
-
- if(tx < x) {
- *actual_x = tx;
- *char_offset = utf8_pos;
- } else {
- if((x - *actual_x) > (tx - x)) {
- *actual_x = tx;
- *char_offset = utf8_pos;
- }
- free(outf16);
- return true;
- }
- }
-
- *actual_x = tx;
- *char_offset = length;
-
- free(outf16);
- return true;
-}
-
-
-/**
- * Find where to split a string to make it fit a width.
- *
- * \param fstyle style for this text
- * \param string UTF-8 string to measure
- * \param length length of string
- * \param x width available
- * \param char_offset updated to offset in string of actual_x, [1..length]
- * \param actual_x updated to x coordinate of character closest to x
- * \return true on success, false on error and error reported
- *
- * On exit, char_offset indicates first character after split point.
- *
- * Note: char_offset of 0 should never be returned.
- *
- * Returns:
- * char_offset giving split point closest to x, where actual_x <= x
- * else
- * char_offset giving split point closest to x, where actual_x > x
- *
- * Returning char_offset == length means no split possible
- */
-
-static inline bool amiga_nsfont_split(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x)
-{
- uint16 *utf16_str = NULL;
- const uint16 *utf16 = NULL;
- const uint16 *utf16next = NULL;
- struct OutlineFont *ofont, *ufont = NULL;
- int tx = 0;
- uint32 utf8_pos = 0;
- int32 tempx = 0;
- ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
-
- /* Get utf16 conversion of string for glyph measuring routines */
- if (utf8_to_enc(string, "UTF-16", length, (char **)&utf16_str) !=
- NSERROR_OK)
- return false;
-
- utf16 = utf16_str;
- if (!(ofont = ami_open_outline_font(fstyle, 0)))
- return false;
-
- *char_offset = 0;
- *actual_x = 0;
-
- if (*utf16 == 0xFEFF) utf16++;
-
- while (utf8_pos < length) {
- if ((*utf16 < 0xD800) || (0xDBFF < *utf16))
- utf16next = utf16 + 1;
- else
- utf16next = utf16 + 2;
-
- tempx = ami_font_width_glyph(ofont, utf16, utf16next, emwidth);
-
- if (tempx == 0) {
- if (ufont == NULL)
- ufont = ami_open_outline_font(fstyle, utf16);
-
- if (ufont)
- tempx = ami_font_width_glyph(ufont, utf16,
- utf16next, emwidth);
- }
-
- /* Check whether we have a space */
- if (*(string + utf8_pos) == ' ') {
- /* Got a space */
- *actual_x = tx;
- *char_offset = utf8_pos;
- }
-
- tx += tempx;
- if ((x < tx) && (*char_offset != 0)) {
- /* Reached available width, and a space was found;
- * split there. */
- free(utf16_str);
- return true;
- }
-
- utf16 = utf16next;
- utf8_pos = utf8_next(string, length, utf8_pos);
- }
-
- free(utf16_str);
-
- /* No spaces to split at, or everything fits */
- assert(*char_offset == 0 || x >= tx);
-
- *char_offset = length;
- *actual_x = tx;
- return true;
-}
-
-/**
- * Search for a font in the list and load from disk if not present
- */
-static struct ami_font_cache_node *ami_font_open(const char *font, bool critical)
-{
- struct ami_font_cache_node *nodedata = ami_font_cache_locate(font);
- if(nodedata) return nodedata;
-
- nodedata = ami_font_cache_alloc_entry(font);
-
- if(nodedata == NULL) {
- warn_user("NoMemory", "");
- return NULL;
- }
-
- nodedata->font = OpenOutlineFont(font, &ami_diskfontlib_list, OFF_OPEN);
-
- if(!nodedata->font)
- {
- LOG("Requested font not found: %s", font);
- if(critical == true) warn_user("CompError", font);
- FreeVec(nodedata);
- return NULL;
- }
-
- nodedata->bold = (char *)GetTagData(OT_BName, 0, nodedata->font->olf_OTagList);
- if(nodedata->bold)
- LOG("Bold font defined for %s is %s", font, nodedata->bold);
- else
- LOG("Warning: No designed bold font defined for %s", font);
-
- nodedata->italic = (char *)GetTagData(OT_IName, 0, nodedata->font->olf_OTagList);
- if(nodedata->italic)
- LOG("Italic font defined for %s is %s", font, nodedata->italic);
- else
- LOG("Warning: No designed italic font defined for %s", font);
-
- nodedata->bolditalic = (char *)GetTagData(OT_BIName, 0, nodedata->font->olf_OTagList);
- if(nodedata->bolditalic)
- LOG("Bold-italic font defined for %s is %s", font, nodedata->bolditalic);
- else
- LOG("Warning: No designed bold-italic font defined for %s", font);
-
- ami_font_cache_insert(nodedata, font);
- return nodedata;
-}
-
-/**
- * Open an outline font in the specified size and style
- *
- * \param fstyle font style structure
- * \param codepoint open a default font instead of the one specified by fstyle
- * \return outline font or NULL on error
- */
-static struct OutlineFont *ami_open_outline_font(const plot_font_style_t *fstyle,
- const uint16 *codepoint)
-{
- struct ami_font_cache_node *node;
- struct ami_font_cache_node *designed_node = NULL;
- struct OutlineFont *ofont;
- char *fontname;
- ULONG ysize;
- int tstyle = 0;
- plot_font_generic_family_t fontfamily;
- ULONG emboldenx = 0;
- ULONG emboldeny = 0;
- ULONG shearsin = 0;
- ULONG shearcos = (1 << 16);
-
- if(codepoint) fontfamily = NSA_UNICODE_FONT;
- else fontfamily = fstyle->family;
-
- switch(fontfamily)
- {
- case PLOT_FONT_FAMILY_SANS_SERIF:
- fontname = nsoption_charp(font_sans);
- break;
- case PLOT_FONT_FAMILY_SERIF:
- fontname = nsoption_charp(font_serif);
- break;
- case PLOT_FONT_FAMILY_MONOSPACE:
- fontname = nsoption_charp(font_mono);
- break;
- case PLOT_FONT_FAMILY_CURSIVE:
- fontname = nsoption_charp(font_cursive);
- break;
- case PLOT_FONT_FAMILY_FANTASY:
- fontname = nsoption_charp(font_fantasy);
- break;
- case NSA_UNICODE_FONT:
- default:
- if(__builtin_expect((amiga_nsfont_utf16_char_length(codepoint) == 2), 0)) {
- /* Multi-byte character */
- fontname = nsoption_charp(font_surrogate);
- } else {
- fontname = (char *)ami_font_scan_lookup(codepoint, glypharray);
- }
- if(fontname == NULL) return NULL;
- break;
- }
-
- node = ami_font_open(fontname, true);
- if(!node) return NULL;
-
- if (fstyle->flags & FONTF_OBLIQUE)
- tstyle = NSA_OBLIQUE;
-
- if (fstyle->flags & FONTF_ITALIC)
- tstyle = NSA_ITALIC;
-
- if (fstyle->weight >= 700)
- tstyle += NSA_BOLD;
-
- switch(tstyle)
- {
- case NSA_ITALIC:
- if(node->italic) designed_node = ami_font_open(node->italic, false);
-
- if(designed_node == NULL) {
- shearsin = NSA_VALUE_SHEARSIN;
- shearcos = NSA_VALUE_SHEARCOS;
- }
- break;
-
- case NSA_OBLIQUE:
- shearsin = NSA_VALUE_SHEARSIN;
- shearcos = NSA_VALUE_SHEARCOS;
- break;
-
- case NSA_BOLD:
- if(node->bold) designed_node = ami_font_open(node->bold, false);
-
- if(designed_node == NULL) {
- emboldenx = NSA_VALUE_BOLDX;
- emboldeny = NSA_VALUE_BOLDY;
- }
- break;
-
- case NSA_BOLDOBLIQUE:
- shearsin = NSA_VALUE_SHEARSIN;
- shearcos = NSA_VALUE_SHEARCOS;
-
- if(node->bold) designed_node = ami_font_open(node->bold, false);
-
- if(designed_node == NULL) {
- emboldenx = NSA_VALUE_BOLDX;
- emboldeny = NSA_VALUE_BOLDY;
- }
- break;
-
- case NSA_BOLDITALIC:
- if(node->bolditalic) designed_node = ami_font_open(node->bolditalic, false);
-
- if(designed_node == NULL) {
- emboldenx = NSA_VALUE_BOLDX;
- emboldeny = NSA_VALUE_BOLDY;
- shearsin = NSA_VALUE_SHEARSIN;
- shearcos = NSA_VALUE_SHEARCOS;
- }
- break;
- }
-
- /* Scale to 16.16 fixed point */
- ysize = fstyle->size * ((1 << 16) / FONT_SIZE_SCALE);
-
- if(designed_node == NULL) {
- ofont = node->font;
- } else {
- ofont = designed_node->font;
- }
-
-#ifndef __amigaos4__
- struct BulletBase *BulletBase = ofont->BulletBase;
-#endif
-
- if(ESetInfo(AMI_OFONT_ENGINE,
- OT_DeviceDPI, ami_devicedpi,
- OT_PointHeight, ysize,
- OT_EmboldenX, emboldenx,
- OT_EmboldenY, emboldeny,
- OT_ShearSin, shearsin,
- OT_ShearCos, shearcos,
- TAG_END) == OTERR_Success)
- return ofont;
-
- return NULL;
-}
-
-static inline int32 ami_font_plot_glyph(struct OutlineFont *ofont, struct RastPort *rp,
- uint16 *char1, uint16 *char2, uint32 x, uint32 y, uint32 emwidth, bool aa)
-{
- struct GlyphMap *glyph;
- UBYTE *glyphbm;
- int32 char_advance = 0;
- FIXED kern = 0;
- ULONG glyphmaptag;
- ULONG template_type;
- uint32 long_char_1 = 0, long_char_2 = 0;
-#ifndef __amigaos4__
- struct BulletBase *BulletBase = ofont->BulletBase;
-#endif
-
-#ifndef __amigaos4__
- if (__builtin_expect(((*char1 >= 0xD800) && (*char1 <= 0xDBFF)), 0)) {
- /* We don't support UTF-16 surrogates yet, so just return. */
- return 0;
- }
-
- if (__builtin_expect(((*char2 >= 0xD800) && (*char2 <= 0xDBFF)), 0)) {
- /* Don't attempt to kern a UTF-16 surrogate */
- *char2 = 0;
- }
-#endif
-
-#ifdef __amigaos4__
- if(__builtin_expect(aa == true, 1)) {
- glyphmaptag = OT_GlyphMap8Bit;
- template_type = BLITT_ALPHATEMPLATE;
- } else {
-#endif
- glyphmaptag = OT_GlyphMap;
-#ifdef __amigaos4__
- template_type = BLITT_TEMPLATE;
- }
-#endif
-
- long_char_1 = amiga_nsfont_decode_surrogate(char1);
- long_char_2 = amiga_nsfont_decode_surrogate(char2);
- /**\todo use OT_GlyphCode_32 so we get an error for old font engines */
-
- if(ESetInfo(AMI_OFONT_ENGINE,
- OT_GlyphCode, long_char_1,
- OT_GlyphCode2, long_char_2,
- TAG_END) == OTERR_Success)
- {
- if(EObtainInfo(AMI_OFONT_ENGINE,
- glyphmaptag, &glyph,
- TAG_END) == 0)
- {
- glyphbm = glyph->glm_BitMap;
- if(!glyphbm) return 0;
-
- if(rp) {
-#ifdef __amigaos4__
- BltBitMapTags(BLITA_SrcX, glyph->glm_BlackLeft,
- BLITA_SrcY, glyph->glm_BlackTop,
- BLITA_DestX, x - glyph->glm_X0 + glyph->glm_BlackLeft,
- BLITA_DestY, y - glyph->glm_Y0 + glyph->glm_BlackTop,
- BLITA_Width, glyph->glm_BlackWidth,
- BLITA_Height, glyph->glm_BlackHeight,
- BLITA_Source, glyphbm,
- BLITA_SrcType, template_type,
- BLITA_Dest, rp,
- BLITA_DestType, BLITT_RASTPORT,
- BLITA_SrcBytesPerRow, glyph->glm_BMModulo,
- TAG_DONE);
-#else
- /* On OS3 the glyph needs to be in chip RAM */
- void *chip_glyph = AllocVec(glyph->glm_BMModulo * glyph->glm_BMRows, MEMF_CHIP);
- if(chip_glyph != NULL) {
- CopyMem(glyphbm, chip_glyph, glyph->glm_BMModulo * glyph->glm_BMRows);
-
- BltTemplate(chip_glyph + (glyph->glm_BMModulo * glyph->glm_BlackTop) +
- ((glyph->glm_BlackLeft >> 4) << 1),
- glyph->glm_BlackLeft & 0xF, glyph->glm_BMModulo, rp,
- x - glyph->glm_X0 + glyph->glm_BlackLeft,
- y - glyph->glm_Y0 + glyph->glm_BlackTop,
- glyph->glm_BlackWidth, glyph->glm_BlackHeight);
-
- FreeVec(chip_glyph);
- }
-#endif
- }
-
- kern = 0;
-
- if(*char2) EObtainInfo(AMI_OFONT_ENGINE,
- OT_TextKernPair, &kern,
- TAG_END);
-
- char_advance = (ULONG)(((glyph->glm_Width - kern) * emwidth) / 65536);
-
- EReleaseInfo(AMI_OFONT_ENGINE,
- glyphmaptag, glyph,
- TAG_END);
-
- if(*char2) EReleaseInfo(AMI_OFONT_ENGINE,
- OT_TextKernPair, kern,
- TAG_END);
- }
- }
-
- return char_advance;
-}
-
-static inline int32 ami_font_width_glyph(struct OutlineFont *ofont,
- const uint16 *char1, const uint16 *char2, uint32 emwidth)
-{
- int32 char_advance = 0;
- FIXED kern = 0;
- struct MinList *gwlist = NULL;
- FIXED char1w = 0;
- struct GlyphWidthEntry *gwnode;
- bool skip_c2 = false;
- uint32 long_char_1 = 0;
- uint32 long_char_2;
-#ifndef __amigaos4__
- struct BulletBase *BulletBase = ofont->BulletBase;
-#endif
-
-#ifndef __amigaos4__
- if (__builtin_expect(((*char1 >= 0xD800) && (*char1 <= 0xDBFF)), 0)) {
- /* We don't support UTF-16 surrogates yet, so just return. */
- return 0;
- }
-
- if (__builtin_expect(((*char2 >= 0xD800) && (*char2 <= 0xDBFF)), 0)) {
- /* Don't attempt to kern a UTF-16 surrogate */
- skip_c2 = true;
- }
-#endif
-
- if (*char2 < 0x0020) skip_c2 = true;
-
- long_char_1 = amiga_nsfont_decode_surrogate(char1);
- /**\todo use OT_GlyphCode_32 so we get an error for old font engines */
-
- if(ESetInfo(AMI_OFONT_ENGINE,
- OT_GlyphCode, long_char_1,
- OT_GlyphCode2, long_char_1,
- TAG_END) == OTERR_Success)
- {
- if(EObtainInfo(AMI_OFONT_ENGINE,
- OT_WidthList, &gwlist,
- TAG_END) == 0)
- {
- gwnode = (struct GlyphWidthEntry *)GetHead((struct List *)gwlist);
- if(gwnode) char1w = gwnode->gwe_Width;
-
- kern = 0;
-
- if(!skip_c2) {
- long_char_2 = amiga_nsfont_decode_surrogate(char2);
- if(ESetInfo(AMI_OFONT_ENGINE,
- OT_GlyphCode, long_char_1,
- OT_GlyphCode2, long_char_2,
- TAG_END) == OTERR_Success)
- {
- EObtainInfo(AMI_OFONT_ENGINE,
- OT_TextKernPair, &kern,
- TAG_END);
- }
- }
- char_advance = (ULONG)(((char1w - kern) * emwidth) / 65536);
-
- if(!skip_c2) EReleaseInfo(AMI_OFONT_ENGINE,
- OT_TextKernPair, kern,
- TAG_END);
-
- EReleaseInfo(AMI_OFONT_ENGINE,
- OT_WidthList, gwlist,
- TAG_END);
- }
- }
-
- return char_advance;
-}
-
-static const uint16 *ami_font_translate_smallcaps(uint16 *utf16char)
-{
- const uint16 *p;
- p = &sc_table[0];
-
- while (*p != 0)
- {
- if(*p == *utf16char) return &p[1];
- p++;
- }
-
- return utf16char;
-}
-
-ULONG ami_font_unicode_text(struct RastPort *rp, const char *string, ULONG length,
- const plot_font_style_t *fstyle, ULONG dx, ULONG dy, bool aa)
-{
- uint16 *utf16 = NULL, *outf16 = NULL;
- uint16 *utf16charsc = 0, *utf16nextsc = 0;
- uint16 *utf16next = 0;
- int utf16charlen;
- struct OutlineFont *ofont, *ufont = NULL;
- uint32 x=0;
- int32 tempx = 0;
- ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
- uint16 utf16_a = 0x41;
-
- if(!string || string[0]=='\0') return 0;
- if(!length) return 0;
- if(rp == NULL) return 0;
-
- if(__builtin_expect(nsoption_bool(use_diskfont) == true, 0)) {
- return ami_font_bm_text(rp, string, length, fstyle, dx, dy);
- }
-
- if(utf8_to_enc(string,"UTF-16",length,(char **)&utf16) != NSERROR_OK) return 0;
- outf16 = utf16;
- if(!(ofont = ami_open_outline_font(fstyle, 0))) {
- if(!(ofont = ami_open_outline_font(fstyle, &utf16_a))) return 0;
- }
-
- while(*utf16 != 0)
- {
- utf16charlen = amiga_nsfont_utf16_char_length(utf16);
- utf16next = &utf16[utf16charlen];
-
- if(fstyle->flags & FONTF_SMALLCAPS)
- {
- utf16charsc = (uint16 *)ami_font_translate_smallcaps(utf16);
- utf16nextsc = (uint16 *)ami_font_translate_smallcaps(utf16next);
-
- tempx = ami_font_plot_glyph(ofont, rp, utf16charsc, utf16nextsc,
- dx + x, dy, emwidth, aa);
- }
- else tempx = 0;
-
- if(tempx == 0) {
- tempx = ami_font_plot_glyph(ofont, rp, utf16, utf16next,
- dx + x, dy, emwidth, aa);
- }
-
- if(tempx == 0)
- {
- if(ufont == NULL)
- {
- ufont = ami_open_outline_font(fstyle, utf16);
- }
-
- if(ufont) {
- tempx = ami_font_plot_glyph(ufont, rp, utf16, utf16next,
- dx + x, dy, emwidth, aa);
- }
- }
-
- x += tempx;
-
- utf16 += utf16charlen;
- }
-
- free(outf16);
- return x;
-}
-
-static inline ULONG ami_font_unicode_width(const char *string, ULONG length,
- const plot_font_style_t *fstyle, ULONG dx, ULONG dy, bool aa)
-{
- uint16 *utf16 = NULL, *outf16 = NULL;
- uint16 *utf16charsc = 0, *utf16nextsc = 0;
- uint16 *utf16next = 0;
- int utf16charlen;
- struct OutlineFont *ofont, *ufont = NULL;
- uint32 x=0;
- int32 tempx = 0;
- ULONG emwidth = (ULONG)NSA_FONT_EMWIDTH(fstyle->size);
- uint16 utf16_a = 0x41;
-
- if(!string || string[0]=='\0') return 0;
- if(!length) return 0;
-
- if(utf8_to_enc(string,"UTF-16",length,(char **)&utf16) != NSERROR_OK) return 0;
- outf16 = utf16;
- if(!(ofont = ami_open_outline_font(fstyle, 0))) {
- if(!(ofont = ami_open_outline_font(fstyle, &utf16_a))) return 0;
- }
-
- while(*utf16 != 0)
- {
- utf16charlen = amiga_nsfont_utf16_char_length(utf16);
- utf16next = &utf16[utf16charlen];
-
- if(fstyle->flags & FONTF_SMALLCAPS)
- {
- utf16charsc = (uint16 *)ami_font_translate_smallcaps(utf16);
- utf16nextsc = (uint16 *)ami_font_translate_smallcaps(utf16next);
-
- tempx = ami_font_width_glyph(ofont, utf16charsc, utf16nextsc, emwidth);
- }
- else tempx = 0;
-
- if(tempx == 0) {
- tempx = ami_font_width_glyph(ofont, utf16, utf16next, emwidth);
- }
-
- if(tempx == 0)
- {
- if(ufont == NULL)
- {
- ufont = ami_open_outline_font(fstyle, utf16);
- }
-
- if(ufont)
- {
- tempx = ami_font_width_glyph(ufont, utf16, utf16next, emwidth);
- }
- }
-
- x += tempx;
-
- utf16 += utf16charlen;
- }
-
- free(outf16);
- return x;
-}
-
-void ami_font_initscanner(bool force, bool save)
-{
- ami_font_scan_init(nsoption_charp(font_unicode_file), force, save, glypharray);
-}
-
-void ami_font_finiscanner(void)
-{
- ami_font_scan_fini(glypharray);
-}
-
-void ami_font_savescanner(void)
-{
- ami_font_scan_save(nsoption_charp(font_unicode_file), glypharray);
-}
-
-void ami_init_fonts(void)
-{
- /* Initialise Unicode font scanner */
- ami_font_initscanner(false, true);
-
- /* Initialise font caching etc lists */
- ami_font_cache_init();
-
- /* List for diskfont internal cache */
- NewList(&ami_diskfontlib_list);
-}
-
-void ami_close_fonts(void)
-{
- ami_font_cache_fini();
- ami_font_finiscanner();
-}
-
-void ami_font_close(struct ami_font_cache_node *node)
-{
- /* Called from FreeObjList if node type is AMINS_FONT */
-
- CloseOutlineFont(node->font, &ami_diskfontlib_list);
-}
-
void ami_font_setdevicedpi(int id)
{
DisplayInfoHandle dih;
@@ -954,41 +100,46 @@ void ami_font_close_disk_font(struct TextFont *tfont)
CloseFont(tfont);
}
+/* Font initialisation */
+void ami_font_init(void)
+{
+ if(nsoption_bool(use_diskfont) == false) {
+ ami_font_bullet_init();
+ } else {
+ ami_font_diskfont_init();
+ }
+}
+
+void ami_font_fini(void)
+{
+ if(nsoption_bool(use_diskfont) == false) {
+ ami_font_bullet_fini();
+ }
+}
/* Stub entry points */
static bool nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width)
{
- if(__builtin_expect(nsoption_bool(use_diskfont) == false, 1)) {
- return amiga_nsfont_width(fstyle, string, length, width);
- } else {
- return amiga_bm_nsfont_width(fstyle, string, length, width);
- }
+ if(__builtin_expect(ami_nsfont == NULL, 0)) return false;
+ return ami_nsfont->width(fstyle, string, length, width);
}
static bool nsfont_position_in_string(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
- if(__builtin_expect(nsoption_bool(use_diskfont) == false, 1)) {
- return amiga_nsfont_position_in_string(fstyle, string, length, x,
- char_offset, actual_x);
- } else {
- return amiga_bm_nsfont_position_in_string(fstyle, string, length, x,
- char_offset, actual_x);
- }
+ if(__builtin_expect(ami_nsfont == NULL, 0)) return false;
+ return ami_nsfont->posn(fstyle, string, length, x, char_offset, actual_x);
}
static bool nsfont_split(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
- if(__builtin_expect(nsoption_bool(use_diskfont) == false, 1)) {
- return amiga_nsfont_split(fstyle, string, length, x, char_offset, actual_x);
- } else {
- return amiga_bm_nsfont_split(fstyle, string, length, x, char_offset, actual_x);
- }
+ if(__builtin_expect(ami_nsfont == NULL, 0)) return false;
+ return ami_nsfont->split(fstyle, string, length, x, char_offset, actual_x);
}
const struct font_functions nsfont = {
diff --git a/amiga/font.h b/amiga/font.h
index 98b0a0c..404a36e 100755
--- a/amiga/font.h
+++ b/amiga/font.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008, 2009, 2012 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2008, 2009, 2012, 2016 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -25,11 +25,16 @@
struct ami_font_cache_node;
-ULONG ami_font_unicode_text(struct RastPort *rp, const char *string,
- ULONG length, const plot_font_style_t *fstyle, ULONG x, ULONG y, bool aa);
void ami_font_setdevicedpi(int id);
-void ami_init_fonts(void);
-void ami_close_fonts(void);
+void ami_font_init(void);
+void ami_font_fini(void);
+
+/* In font_bitmap.c */
+void ami_font_diskfont_init(void);
+
+/* In font_bullet.c */
+void ami_font_bullet_init(void);
+void ami_font_bullet_fini(void);
void ami_font_close(struct ami_font_cache_node *node);
/* Alternate entry points into font_scan */
@@ -41,17 +46,28 @@ void ami_font_savescanner(void);
struct TextFont *ami_font_open_disk_font(struct TextAttr *tattr);
void ami_font_close_disk_font(struct TextFont *tfont);
-/* In font_bitmap.c */
-bool amiga_bm_nsfont_width(const plot_font_style_t *fstyle,
- const char *string, size_t length, int *width);
-bool amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x);
-bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x);
-ULONG ami_font_bm_text(struct RastPort *rp, const char *string, ULONG length,
- const plot_font_style_t *fstyle, ULONG dx, ULONG dy);
+/* Font engine tables */
+struct ami_font_functions {
+ bool (*width)(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int *width);
+
+ bool (*posn)(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x);
+
+ bool (*split)(const plot_font_style_t *fstyle,
+ const char *string, size_t length,
+ int x, size_t *char_offset, int *actual_x);
+
+ ULONG (*text)(struct RastPort *rp, const char *string,
+ ULONG length, const plot_font_style_t *fstyle,
+ ULONG x, ULONG y, bool aa);
+};
+
+ULONG ami_devicedpi;
+ULONG ami_xdpi;
+const struct ami_font_functions *ami_nsfont;
#endif
diff --git a/amiga/font_bitmap.c b/amiga/font_bitmap.c
index eed43db..d9459b0 100644
--- a/amiga/font_bitmap.c
+++ b/amiga/font_bitmap.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 - 2015 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2008 - 2016 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -112,7 +112,7 @@ static size_t ami_font_bm_convert_local_to_utf8_offset(const char *utf8string, i
}
-bool amiga_bm_nsfont_width(const plot_font_style_t *fstyle,
+static bool amiga_bm_nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width)
{
@@ -149,7 +149,7 @@ bool amiga_bm_nsfont_width(const plot_font_style_t *fstyle,
* \return true on success, false on error and error reported
*/
-bool amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyle,
+static bool amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
@@ -203,7 +203,7 @@ bool amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyle,
* Returning char_offset == length means no split possible
*/
-bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
+static bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
const char *string, size_t length,
int x, size_t *char_offset, int *actual_x)
{
@@ -243,7 +243,7 @@ bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
}
}
- if((co > 0) && (co < strlen(localtext))) {
+ if((co > 0) && (co <= strlen(localtext))) {
*actual_x = TextLength(glob->rp, localtext, co);
*char_offset = ami_font_bm_convert_local_to_utf8_offset(string, length, co);
} else {
@@ -257,9 +257,13 @@ bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
return true;
}
-ULONG ami_font_bm_text(struct RastPort *rp, const char *string, ULONG length,
- const plot_font_style_t *fstyle, ULONG dx, ULONG dy)
+static ULONG amiga_bm_nsfont_text(struct RastPort *rp, const char *string, ULONG length,
+ const plot_font_style_t *fstyle, ULONG dx, ULONG dy, bool aa)
{
+ if(!string || string[0]=='\0') return 0;
+ if(!length) return 0;
+ if(rp == NULL) return 0;
+
struct TextFont *bmfont = ami_font_bm_open(rp, fstyle);
char *localtext = NULL;
if(bmfont == NULL) return 0;
@@ -274,3 +278,16 @@ ULONG ami_font_bm_text(struct RastPort *rp, const char *string, ULONG length,
return 0;
}
+const struct ami_font_functions ami_font_diskfont_table = {
+ amiga_bm_nsfont_width,
+ amiga_bm_nsfont_position_in_string,
+ amiga_bm_nsfont_split,
+ amiga_bm_nsfont_text
+};
+
+void ami_font_diskfont_init(void)
+{
+ /* Set up table */
+ ami_nsfont = &ami_font_diskfont_table;
+}
+
diff --git a/amiga/font.c b/amiga/font_bullet.c
similarity index 86%
copy from amiga/font.c
copy to amiga/font_bullet.c
index 3a141ac..432ae88 100644
--- a/amiga/font.c
+++ b/amiga/font_bullet.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008 - 2015 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2008 - 2016 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -18,37 +18,26 @@
#include "amiga/os3support.h"
-#include <assert.h>
+#include <stdlib.h>
#ifndef __amigaos4__
#include <proto/bullet.h>
#endif
#include <proto/diskfont.h>
-#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <diskfont/diskfonttag.h>
#include <diskfont/oterrors.h>
-#include <graphics/rpattr.h>
-#ifdef __amigaos4__
-#include <graphics/blitattr.h>
-#endif
+#include "amiga/font.h"
+#include "amiga/font_cache.h"
+#include "amiga/font_scan.h"
#include "utils/log.h"
+#include "utils/nsoption.h"
#include "utils/utf8.h"
#include "utils/utils.h"
-#include "utils/nsoption.h"
-#include "desktop/browser.h"
-#include "desktop/font.h"
-#include "desktop/gui_window.h"
-
-#include "amiga/font.h"
-#include "amiga/font_cache.h"
-#include "amiga/font_scan.h"
-#include "amiga/gui.h"
-#include "amiga/utf8.h"
#define NSA_UNICODE_FONT PLOT_FONT_FAMILY_COUNT
@@ -104,7 +93,7 @@ const uint16 sc_table[] = {
0x0000, 0x1D19, /* reversed r */
0x0000, 0x1D1A, /* turned r */
0x0000, 0x029B, /* g with hook */
- 0x0000, 0x1D06, /* eth � */
+ 0x0000, 0x1D06, /* eth Ð */
0x0000, 0x1D0C, /* l with stroke */
0x0000, 0xA7FA, /* turned m */
0x0000, 0x1D0E, /* reversed n */
@@ -134,8 +123,6 @@ const uint16 sc_table[] = {
0, 0};
lwc_string *glypharray[0xffff + 1];
-ULONG ami_devicedpi;
-ULONG ami_xdpi;
static struct List ami_diskfontlib_list;
@@ -727,7 +714,7 @@ static const uint16 *ami_font_translate_smallcaps(uint16 *utf16char)
return utf16char;
}
-ULONG ami_font_unicode_text(struct RastPort *rp, const char *string, ULONG length,
+static ULONG amiga_nsfont_text(struct RastPort *rp, const char *string, ULONG length,
const plot_font_style_t *fstyle, ULONG dx, ULONG dy, bool aa)
{
uint16 *utf16 = NULL, *outf16 = NULL;
@@ -744,10 +731,6 @@ ULONG ami_font_unicode_text(struct RastPort *rp, const char *string, ULONG lengt
if(!length) return 0;
if(rp == NULL) return 0;
- if(__builtin_expect(nsoption_bool(use_diskfont) == true, 0)) {
- return ami_font_bm_text(rp, string, length, fstyle, dx, dy);
- }
-
if(utf8_to_enc(string,"UTF-16",length,(char **)&utf16) != NSERROR_OK) return 0;
outf16 = utf16;
if(!(ofont = ami_open_outline_font(fstyle, 0))) {
@@ -873,127 +856,37 @@ void ami_font_savescanner(void)
ami_font_scan_save(nsoption_charp(font_unicode_file), glypharray);
}
-void ami_init_fonts(void)
-{
- /* Initialise Unicode font scanner */
- ami_font_initscanner(false, true);
-
- /* Initialise font caching etc lists */
- ami_font_cache_init();
-
- /* List for diskfont internal cache */
- NewList(&ami_diskfontlib_list);
-}
-
-void ami_close_fonts(void)
-{
- ami_font_cache_fini();
- ami_font_finiscanner();
-}
-
void ami_font_close(struct ami_font_cache_node *node)
{
/* Called from FreeObjList if node type is AMINS_FONT */
-
CloseOutlineFont(node->font, &ami_diskfontlib_list);
}
-void ami_font_setdevicedpi(int id)
-{
- DisplayInfoHandle dih;
- struct DisplayInfo dinfo;
- ULONG ydpi = nsoption_int(screen_ydpi);
- ULONG xdpi = nsoption_int(screen_ydpi);
-
- if(nsoption_bool(use_diskfont) == true) {
- LOG("WARNING: Using diskfont.library for text. Forcing DPI to 72.");
- nsoption_int(screen_ydpi) = 72;
- }
-
- browser_set_dpi(nsoption_int(screen_ydpi));
-
- if(id && (nsoption_int(monitor_aspect_x) != 0) && (nsoption_int(monitor_aspect_y) != 0))
- {
- if((dih = FindDisplayInfo(id)))
- {
- if(GetDisplayInfoData(dih, &dinfo, sizeof(struct DisplayInfo),
- DTAG_DISP, 0))
- {
- int xres = dinfo.Resolution.x;
- int yres = dinfo.Resolution.y;
-
- if((nsoption_int(monitor_aspect_x) != 4) || (nsoption_int(monitor_aspect_y) != 3))
- {
- /* AmigaOS sees 4:3 modes as square in the DisplayInfo database,
- * so we correct other modes to "4:3 equiv" here. */
- xres = (xres * nsoption_int(monitor_aspect_x)) / 4;
- yres = (yres * nsoption_int(monitor_aspect_y)) / 3;
- }
-
- xdpi = (yres * ydpi) / xres;
-
- LOG("XDPI = %ld, YDPI = %ld (DisplayInfo resolution %d x %d, corrected %d x %d)", xdpi, ydpi, dinfo.Resolution.x, dinfo.Resolution.y, xres, yres);
- }
- }
- }
-
- ami_xdpi = xdpi;
- ami_devicedpi = (xdpi << 16) | ydpi;
-}
-
-/* The below are simple font routines which should not be used for page rendering */
-
-struct TextFont *ami_font_open_disk_font(struct TextAttr *tattr)
-{
- struct TextFont *tfont = OpenDiskFont(tattr);
- return tfont;
-}
+const struct ami_font_functions ami_font_bullet_table = {
+ amiga_nsfont_width,
+ amiga_nsfont_position_in_string,
+ amiga_nsfont_split,
+ amiga_nsfont_text
+};
-void ami_font_close_disk_font(struct TextFont *tfont)
+void ami_font_bullet_init(void)
{
- CloseFont(tfont);
-}
+ /* Initialise Unicode font scanner */
+ ami_font_initscanner(false, true);
+ /* Initialise font caching etc lists */
+ ami_font_cache_init();
-/* Stub entry points */
-static bool nsfont_width(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int *width)
-{
- if(__builtin_expect(nsoption_bool(use_diskfont) == false, 1)) {
- return amiga_nsfont_width(fstyle, string, length, width);
- } else {
- return amiga_bm_nsfont_width(fstyle, string, length, width);
- }
-}
+ /* List for diskfont internal cache */
+ NewList(&ami_diskfontlib_list);
-static bool nsfont_position_in_string(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x)
-{
- if(__builtin_expect(nsoption_bool(use_diskfont) == false, 1)) {
- return amiga_nsfont_position_in_string(fstyle, string, length, x,
- char_offset, actual_x);
- } else {
- return amiga_bm_nsfont_position_in_string(fstyle, string, length, x,
- char_offset, actual_x);
- }
+ /* Set up table */
+ ami_nsfont = &ami_font_bullet_table;
}
-static bool nsfont_split(const plot_font_style_t *fstyle,
- const char *string, size_t length,
- int x, size_t *char_offset, int *actual_x)
+void ami_font_bullet_fini(void)
{
- if(__builtin_expect(nsoption_bool(use_diskfont) == false, 1)) {
- return amiga_nsfont_split(fstyle, string, length, x, char_offset, actual_x);
- } else {
- return amiga_bm_nsfont_split(fstyle, string, length, x, char_offset, actual_x);
- }
+ ami_font_cache_fini();
+ ami_font_finiscanner();
}
-const struct font_functions nsfont = {
- nsfont_width,
- nsfont_position_in_string,
- nsfont_split
-};
-
diff --git a/amiga/gui.c b/amiga/gui.c
index 4eb2c47..6744d99 100644
--- a/amiga/gui.c
+++ b/amiga/gui.c
@@ -3016,7 +3016,7 @@ static void gui_quit(void)
ami_free_layers(&browserglob);
- ami_close_fonts();
+ ami_font_fini();
ami_help_free();
LOG("Closing screen");
@@ -5633,7 +5633,7 @@ int main(int argc, char** argv)
ami_clipboard_init();
ami_openurl_open();
ami_amiupdate(); /* set env-vars for AmiUpdate */
- ami_init_fonts();
+ ami_font_init();
save_complete_init();
ami_theme_init();
ami_init_mouse_pointers();
diff --git a/amiga/plotters.c b/amiga/plotters.c
index dc68f93..ea13285 100644
--- a/amiga/plotters.c
+++ b/amiga/plotters.c
@@ -434,7 +434,7 @@ static bool ami_text(int x, int y, const char *text, size_t length,
aa = false;
ami_plot_setapen(glob->rp, fstyle->foreground);
- ami_font_unicode_text(glob->rp, text, length, fstyle, x, y, aa);
+ ami_nsfont->text(glob->rp, text, length, fstyle, x, y, aa);
return true;
}
--
NetSurf Browser
7 years, 10 months
netsurf: branch master updated. release/3.3-574-gf831d81
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/f831d81ab1895b4f9c19f...
...commit http://git.netsurf-browser.org/netsurf.git/commit/f831d81ab1895b4f9c19f53...
...tree http://git.netsurf-browser.org/netsurf.git/tree/f831d81ab1895b4f9c19f53f0...
The branch, master has been updated
via f831d81ab1895b4f9c19f53f08d9c8fccd69c96e (commit)
via 2937b2f8719b724ea1d06117cfd48ade1c946c0e (commit)
from 6122517bf4356a04cdde4119b8a3f3777eff4159 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=f831d81ab1895b4f9c1...
commit f831d81ab1895b4f9c19f53f08d9c8fccd69c96e
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Restore prevention of clang static analysis from 336326af3aab93f31474fa6de28782457ae4a1c0
diff --git a/javascript/duktape/duktape.c b/javascript/duktape/duktape.c
index dc62df8..105bdbe 100644
--- a/javascript/duktape/duktape.c
+++ b/javascript/duktape/duktape.c
@@ -1,3 +1,5 @@
+/* Omit from static analysis. */
+#ifndef __clang_analyzer__
/*
* Single source autogenerated distributable for Duktape 1.4.0.
*
@@ -88120,3 +88122,4 @@ DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
return t;
}
+#endif
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=2937b2f8719b724ea1d...
commit 2937b2f8719b724ea1d06117cfd48ade1c946c0e
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Update to Duktape 1.4.0 release.
diff --git a/javascript/duktape/duk_config.h b/javascript/duktape/duk_config.h
index f6ee91c..64c10ea 100644
--- a/javascript/duktape/duk_config.h
+++ b/javascript/duktape/duk_config.h
@@ -1,9 +1,9 @@
/*
* duk_config.h configuration header generated by genconfig.py.
*
- * Git commit: b7b1c5fd2d1d4550140d57e05a7b32f540082bfa
- * Git describe: v1.3.0-383-gb7b1c5f
- * Git branch: duk-config-improvements
+ * Git commit: cad6f595382a0cc1a7e4207794ade5be11b3e397
+ * Git describe: v1.4.0
+ * Git branch: master
*
* Supported platforms:
* - Mac OSX, iPhone, Darwin
@@ -199,6 +199,12 @@
#define DUK_F_NO_STDINT_H
#endif
+/* C++ */
+#undef DUK_F_CPP
+#if defined(__cplusplus)
+#define DUK_F_CPP
+#endif
+
/* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers),
* define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32.
* https://sites.google.com/site/x32abi/
@@ -273,12 +279,6 @@
#define DUK_F_CLANG
#endif
-/* C++ */
-#undef DUK_F_CPP
-#if defined(__cplusplus)
-#define DUK_F_CPP
-#endif
-
/* C99 or above */
#undef DUK_F_C99
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
@@ -334,11 +334,6 @@
#define DUK_F_VBCC
#endif
-/* uclibc */
-#if defined(__UCLIBC__)
-#define DUK_F_UCLIBC
-#endif
-
/*
* Platform autodetection
*/
@@ -688,6 +683,10 @@
#include <stdint.h>
#endif
+#if defined(DUK_F_CPP)
+#include <exception> /* std::exception */
+#endif
+
/*
* Architecture autodetection
*/
@@ -1264,6 +1263,11 @@
#define DUK_F_VARIADIC_MACROS_PROVIDED
#endif /* autodetect compiler */
+/* uclibc */
+#if defined(__UCLIBC__)
+#define DUK_F_UCLIBC
+#endif
+
/*
* Wrapper typedefs and constants for integer types, also sanity check types.
*
@@ -2671,6 +2675,14 @@ typedef FILE duk_file;
#define DUK_USE_COMMONJS_MODULES
#endif
+#if defined(DUK_OPT_CPP_EXCEPTIONS)
+#define DUK_USE_CPP_EXCEPTIONS
+#elif defined(DUK_OPT_NO_CPP_EXCEPTIONS)
+#undef DUK_USE_CPP_EXCEPTIONS
+#else
+#undef DUK_USE_CPP_EXCEPTIONS
+#endif
+
#if defined(DUK_OPT_DATAPTR16)
#define DUK_USE_DATAPTR16
#elif defined(DUK_OPT_NO_DATAPTR16)
@@ -2760,7 +2772,7 @@ typedef FILE duk_file;
#elif defined(DUK_OPT_NO_DEBUGGER_THROW_NOTIFY)
#undef DUK_USE_DEBUGGER_THROW_NOTIFY
#else
-#undef DUK_USE_DEBUGGER_THROW_NOTIFY
+#define DUK_USE_DEBUGGER_THROW_NOTIFY
#endif
#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE)
@@ -3484,27 +3496,9 @@ typedef FILE duk_file;
#if defined(DUK_USE_DATAPTR_ENC16) && !defined(DUK_USE_DATAPTR16)
#error config option DUK_USE_DATAPTR_ENC16 requires option DUK_USE_DATAPTR16 (which is missing)
#endif
-#if defined(DUK_USE_DEBUGGER_DUMPHEAP) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_DUMPHEAP requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
-#if defined(DUK_USE_DEBUGGER_FWD_LOGGING) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_FWD_LOGGING requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
-#if defined(DUK_USE_DEBUGGER_FWD_PRINTALERT) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_FWD_PRINTALERT requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
-#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_PAUSE_UNCAUGHT requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
#if defined(DUK_USE_DEBUGGER_SUPPORT) && !defined(DUK_USE_INTERRUPT_COUNTER)
#error config option DUK_USE_DEBUGGER_SUPPORT requires option DUK_USE_INTERRUPT_COUNTER (which is missing)
#endif
-#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_THROW_NOTIFY requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
-#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_TRANSPORT_TORTURE requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
#if defined(DUK_USE_DEEP_C_STACK)
#error unsupported config option used (option has been removed): DUK_USE_DEEP_C_STACK
#endif
@@ -3620,6 +3614,10 @@ typedef FILE duk_file;
#error unsupported config option used (option has been removed): DUK_USE_UNALIGNED_ACCESSES_POSSIBLE
#endif
+#if defined(DUK_USE_CPP_EXCEPTIONS) && !defined(__cplusplus)
+#error DUK_USE_CPP_EXCEPTIONS enabled but not compiling with a C++ compiler
+#endif
+
/*
* Convert DUK_USE_BYTEORDER, from whatever source, into currently used
* internal defines. If detection failed, #error out.
diff --git a/javascript/duktape/duktape.c b/javascript/duktape/duktape.c
index ef22161..dc62df8 100644
--- a/javascript/duktape/duktape.c
+++ b/javascript/duktape/duktape.c
@@ -1,10 +1,8 @@
-/* Omit from static analysis. */
-#ifndef __clang_analyzer__
/*
- * Single source autogenerated distributable for Duktape 1.3.99.
-
- * Git commit b7b1c5fd2d1d4550140d57e05a7b32f540082bfa (v1.3.0-383-gb7b1c5f).
- * Git branch duk-config-improvements.
+ * Single source autogenerated distributable for Duktape 1.4.0.
+ *
+ * Git commit cad6f595382a0cc1a7e4207794ade5be11b3e397 (v1.4.0).
+ * Git branch master.
*
* See Duktape AUTHORS.rst and LICENSE.txt for copyright and
* licensing information.
@@ -18,7 +16,7 @@
*
* (http://opensource.org/licenses/MIT)
*
-* Copyright (c) 2013-2015 by Duktape authors (see AUTHORS.rst)
+* Copyright (c) 2013-2016 by Duktape authors (see AUTHORS.rst)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -68,6 +66,7 @@
* * Legimet <legimet.calc(a)gmail.com>
* * Karl Skomski <karl(a)skomski.com>
* * Bruce Pascoe <fatcerberus1(a)gmail.com>
+* * Ren\u00e9 Hollander <rene(a)rene8888.at>
*
* Other contributions
* ===================
@@ -104,6 +103,7 @@
* * https://github.com/sstruchtrup
* * Michael Drake (https://github.com/tlsa)
* * https://github.com/chris-y
+* * Laurent Zubiaur (https://github.com/lzubiaur)
*
* If you are accidentally missing from this list, send me an e-mail
* (``sami.vaarala(a)iki.fi``) and I'll fix the omission.
@@ -201,6 +201,7 @@ DUK_INTERNAL_DECL int duk_repl_isinf(double x);
#ifndef DUK_JMPBUF_H_INCLUDED
#define DUK_JMPBUF_H_INCLUDED
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
struct duk_jmpbuf {
#if defined(DUK_USE_SETJMP) || defined(DUK_USE_UNDERSCORE_SETJMP)
jmp_buf jb;
@@ -210,8 +211,28 @@ struct duk_jmpbuf {
#error internal error, no long control transfer provider
#endif
};
+#endif
#endif /* DUK_JMPBUF_H_INCLUDED */
+#line 1 "duk_exception.h"
+/*
+ * Exception for Duktape internal throws when C++ exceptions are used
+ * for long control transfers.
+ *
+ * Doesn't inherit from any exception base class to minimize the chance
+ * that user code would accidentally catch this exception.
+ */
+
+#ifndef DUK_EXCEPTION_H_INCLUDED
+#define DUK_EXCEPTION_H_INCLUDED
+
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+class duk_internal_exception {
+ /* intentionally empty */
+};
+#endif
+
+#endif /* DUK_EXCEPTION_H_INCLUDED */
#line 1 "duk_forwdecl.h"
/*
* Forward declarations for all Duktape structures.
@@ -224,7 +245,11 @@ struct duk_jmpbuf {
* Forward declarations
*/
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+class duk_internal_exception;
+#else
struct duk_jmpbuf;
+#endif
/* duk_tval intentionally skipped */
struct duk_heaphdr;
@@ -275,7 +300,11 @@ struct duk_compiler_ctx;
struct duk_re_matcher_ctx;
struct duk_re_compiler_ctx;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+/* no typedef */
+#else
typedef struct duk_jmpbuf duk_jmpbuf;
+#endif
/* duk_tval intentionally skipped */
typedef struct duk_heaphdr duk_heaphdr;
@@ -1595,13 +1624,13 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1955];
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 1952
+#define DUK_BUILTINS_DATA_LENGTH 1955
#ifdef DUK_USE_BUILTIN_INITJS
#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
@@ -2940,13 +2969,13 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1955];
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 1952
+#define DUK_BUILTINS_DATA_LENGTH 1955
#ifdef DUK_USE_BUILTIN_INITJS
#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
@@ -4285,13 +4314,13 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1955];
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 1952
+#define DUK_BUILTINS_DATA_LENGTH 1955
#ifdef DUK_USE_BUILTIN_INITJS
#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
@@ -4374,7 +4403,7 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#error invalid endianness defines
#endif
#endif /* DUK_BUILTINS_H_INCLUDED */
-#line 50 "duk_internal.h"
+#line 51 "duk_internal.h"
#line 1 "duk_util.h"
/*
@@ -8202,7 +8231,7 @@ DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr
DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \
} while (0)
#define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \
- DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (f); \
+ DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \
} while (0)
#define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \
DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \
@@ -10033,7 +10062,9 @@ struct duk_strcache {
*/
struct duk_ljstate {
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */
+#endif
duk_small_uint_t type; /* longjmp type */
duk_bool_t iserror; /* isError flag for yield */
duk_tval value1; /* 1st related value (type specific) */
@@ -11272,12 +11303,11 @@ typedef struct {
#define DUK_JS_H_INCLUDED
/* Flags for call handling. */
-#define DUK_CALL_FLAG_PROTECTED (1 << 0) /* duk_handle_call: call is protected */
-#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 1) /* duk_handle_call: call ignores C recursion limit (for errhandler calls) */
-#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 2) /* duk_handle_call: constructor call (i.e. called as 'new Foo()') */
-#define DUK_CALL_FLAG_IS_RESUME (1 << 3) /* duk_handle_ecma_call_setup: setup for a resume() */
-#define DUK_CALL_FLAG_IS_TAILCALL (1 << 4) /* duk_handle_ecma_call_setup: setup for a tail call */
-#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 5) /* call is a direct eval call */
+#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 0) /* duk_handle_call_xxx: call ignores C recursion limit (for errhandler calls) */
+#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 1) /* duk_handle_call_xxx: constructor call (i.e. called as 'new Foo()') */
+#define DUK_CALL_FLAG_IS_RESUME (1 << 2) /* duk_handle_ecma_call_setup: setup for a resume() */
+#define DUK_CALL_FLAG_IS_TAILCALL (1 << 3) /* duk_handle_ecma_call_setup: setup for a tail call */
+#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 4) /* call is a direct eval call */
/* Flags for duk_js_equals_helper(). */
#define DUK_EQUALS_FLAG_SAMEVALUE (1 << 0) /* use SameValue instead of non-strict equality */
@@ -11354,7 +11384,8 @@ void duk_js_push_closure(duk_hthread *thr,
duk_hobject *outer_lex_env);
/* call handling */
-DUK_INTERNAL_DECL duk_int_t duk_handle_call(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL void duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, duk_idx_t num_stack_args, duk_idx_t num_stack_res);
DUK_INTERNAL_DECL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
@@ -11710,7 +11741,7 @@ DUK_INTERNAL_DECL void duk_selftest_run_tests(void);
#endif
#endif /* DUK_SELFTEST_H_INCLUDED */
-#line 77 "duk_internal.h"
+#line 78 "duk_internal.h"
#endif /* DUK_INTERNAL_H_INCLUDED */
#line 1 "duk_strings.c"
@@ -12279,7 +12310,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_typedarray_set,
};
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[1955] = {
105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
@@ -12321,50 +12352,50 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
97,236,66,80,1,151,169,10,248,0,211,208,133,124,0,109,230,66,254,0,56,242,
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
-195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
-239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
-203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
-252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
-54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
-206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
-255,242,27,16,26,85,197,34,194,175,193,80,26,240,5,149,109,110,236,90,192,
-144,26,208,59,206,126,191,144,139,185,143,218,176,63,160,138,217,81,197,
-125,207,218,144,3,185,73,133,94,242,246,207,218,112,6,11,81,21,62,200,66,
-80,26,80,51,78,223,217,167,168,57,143,218,48,51,78,223,217,167,168,61,143,
-210,104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,
-80,0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,
-21,61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,
-181,250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,
-3,255,252,81,252,0,0,0,0,8,4,252,68,0,129,167,1,26,144,9,165,0,26,177,199,
-197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
-223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
-113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
-159,192,0,31,245,97,10,100,0,0,0,0,0,0,0,32,10,164,130,97,221,191,113,3,20,
-178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
-196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
-242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
-70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
-64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
-0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
-144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
-203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
-38,81,7,1,132,128,0,133,105,252,19,140,0,0,0,0,0,0,15,3,240,25,127,102,0,1,
-91,127,4,227,0,0,0,0,0,0,3,192,252,6,95,218,128,0,87,31,193,56,192,0,0,0,0,
-0,0,240,63,1,151,246,224,0,21,215,240,78,48,0,0,0,0,0,0,0,16,0,101,253,200,
-0,5,121,252,19,140,0,0,0,0,0,0,0,4,0,25,127,118,0,1,95,127,4,227,0,0,0,0,0,
-0,0,65,0,6,95,222,128,0,88,31,193,56,192,0,0,0,0,0,0,16,64,1,151,247,224,0,
-22,23,240,78,48,0,0,0,0,0,0,4,16,0,101,254,8,0,5,137,252,19,140,0,0,0,0,0,
-0,2,4,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,132,
-248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,92,93,
-32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,116,
-128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,210,
-0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,136,25,
-98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,101,160,
-3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,225,150,
-128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,2,158,
-70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,87,98,
-112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
+195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,65,192,2,22,0,
+88,16,46,24,77,208,148,103,4,102,252,102,244,128,0,0,0,0,0,0,0,0,220,111,
+68,113,61,146,142,248,0,164,255,128,0,63,228,133,109,16,89,178,65,18,235,
+153,25,150,220,184,188,180,230,6,32,209,205,0,20,175,240,0,39,252,160,77,
+162,184,54,72,34,0,82,255,192,0,159,242,193,54,138,222,217,32,136,1,76,255,
+0,2,127,204,4,218,43,115,100,130,32,5,55,252,0,9,255,52,19,104,173,173,146,
+8,128,20,239,240,0,39,252,224,77,162,182,54,72,34,0,83,255,192,0,159,243,
+193,54,138,214,217,32,136,0,255,255,33,177,1,165,92,82,44,42,252,21,1,175,
+0,89,86,214,238,197,172,9,1,173,3,188,231,235,249,8,187,152,253,171,3,250,
+8,173,149,28,87,220,253,169,0,59,148,152,85,239,47,108,253,167,0,96,181,17,
+83,236,132,37,1,165,3,52,237,253,154,122,131,152,253,163,3,52,237,253,154,
+122,131,216,253,38,130,129,25,234,5,0,1,103,40,20,0,9,154,160,80,0,54,98,
+146,25,106,5,0,4,101,40,20,0,21,146,160,80,0,102,66,129,64,1,216,234,5,0,8,
+99,39,47,49,83,215,152,138,73,0,1,97,168,129,132,160,80,0,150,10,129,64,2,
+152,10,5,0,11,95,168,20,0,48,31,255,224,5,17,72,66,249,37,129,127,255,0,0,
+191,255,128,0,63,255,197,31,192,0,0,0,0,0,80,196,64,8,26,112,17,169,0,154,
+80,1,171,28,124,88,65,233,49,7,133,100,29,149,15,14,138,71,135,37,3,195,66,
+114,5,77,252,0,243,178,40,25,200,48,101,30,0,127,210,128,0,85,31,192,0,31,
+244,224,5,71,22,8,0,13,20,88,1,85,127,0,0,127,212,128,21,29,220,32,0,52,87,
+112,5,89,252,0,1,255,86,16,166,64,0,0,0,0,0,0,2,0,170,72,38,29,219,247,16,
+49,75,32,193,52,130,244,193,225,114,96,248,0,8,249,48,124,0,8,90,152,62,0,
+6,44,76,31,0,4,21,166,15,128,2,147,255,252,38,212,16,184,155,250,226,217,
+150,47,46,91,249,54,96,139,229,229,203,127,36,26,119,32,203,203,150,254,72,
+52,97,221,147,102,157,217,192,10,191,248,0,157,4,72,15,250,224,1,154,140,
+36,0,8,43,31,224,0,15,251,0,16,55,139,164,0,192,220,46,144,2,3,104,186,64,
+12,77,130,233,0,33,53,139,164,0,200,212,46,144,2,35,72,186,64,8,205,2,233,
+0,36,51,140,180,0,192,204,50,208,2,3,40,203,64,12,76,131,45,0,33,49,140,
+180,0,200,196,50,208,2,35,8,203,64,8,204,3,45,0,36,7,255,248,1,82,101,16,
+112,24,72,0,8,86,159,193,56,192,0,0,0,0,0,0,240,63,1,151,246,96,0,21,183,
+240,78,48,0,0,0,0,0,0,60,15,192,101,253,168,0,5,113,252,19,140,0,0,0,0,0,0,
+15,3,240,25,127,110,0,1,93,127,4,227,0,0,0,0,0,0,0,1,0,6,95,220,128,0,87,
+159,193,56,192,0,0,0,0,0,0,0,64,1,151,247,96,0,21,247,240,78,48,0,0,0,0,0,
+0,4,16,0,101,253,232,0,5,129,252,19,140,0,0,0,0,0,0,1,4,0,25,127,126,0,1,
+97,127,4,227,0,0,0,0,0,0,0,65,0,6,95,224,128,0,88,159,193,56,192,0,0,0,0,0,
+0,32,64,1,151,248,96,0,22,55,240,5,157,170,33,68,178,69,10,193,20,10,104,
+79,138,36,0,12,31,248,160,88,154,23,66,100,93,32,2,9,129,116,128,0,165,197,
+210,0,18,150,23,72,0,138,84,93,32,3,41,65,116,128,1,36,197,210,0,20,146,23,
+72,0,146,68,93,32,3,73,1,116,128,1,163,197,210,0,22,142,23,72,0,34,52,93,
+32,1,136,193,118,128,2,162,197,218,0,26,138,23,104,0,170,36,93,160,3,168,
+129,150,33,198,90,0,32,134,25,104,0,10,20,101,160,1,40,65,150,128,8,160,
+198,90,0,50,130,25,104,0,18,4,101,160,1,72,1,150,128,9,31,198,90,0,52,126,
+25,104,0,25,244,101,160,1,103,193,150,128,2,30,198,90,0,24,122,25,136,0,41,
+228,102,32,1,167,129,152,128,10,157,198,98,0,59,71,91,99,157,104,9,213,118,
+39,5,8,159,20,40,0,10,109,90,19,81,132,39,151,32,
};
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
@@ -12666,7 +12697,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_typedarray_set,
};
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[1955] = {
105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
@@ -12708,50 +12739,50 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
97,236,66,80,1,151,169,10,248,0,211,208,133,124,0,109,230,66,254,0,56,242,
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
-195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
-239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
-203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
-252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
-54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
-206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
-255,242,27,16,16,1,111,194,162,197,21,218,90,240,16,0,154,236,110,237,85,
-69,154,208,15,249,139,144,191,190,142,123,218,176,15,253,197,81,217,74,224,
-191,154,144,15,246,242,222,197,73,185,67,154,112,16,2,72,126,213,17,11,70,
-26,80,15,249,168,39,153,159,206,243,90,48,15,253,168,39,153,159,206,243,82,
-104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,80,
-0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,21,
-61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,181,
-250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,3,
-255,252,81,252,4,12,68,248,0,0,0,0,0,129,167,1,26,144,9,165,0,26,177,199,
-197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
-223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
-113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
-159,192,0,31,245,97,10,100,32,0,0,0,0,0,0,0,10,164,130,97,221,191,113,3,20,
-178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
-196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
-242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
-70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
-64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
-0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
-144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
-203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
-38,81,7,1,132,128,0,133,105,252,19,140,3,255,0,0,0,0,0,0,0,25,127,102,0,1,
-91,127,4,227,0,255,192,0,0,0,0,0,0,6,95,218,128,0,87,31,193,56,192,63,240,
-0,0,0,0,0,0,1,151,246,224,0,21,215,240,78,48,16,0,0,0,0,0,0,0,0,101,253,
-200,0,5,121,252,19,140,4,0,0,0,0,0,0,0,0,25,127,118,0,1,95,127,4,227,1,0,
-64,0,0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,64,16,0,0,0,0,0,0,1,151,247,
-224,0,22,23,240,78,48,16,4,0,0,0,0,0,0,0,101,254,8,0,5,137,252,19,140,4,2,
-0,0,0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,
-132,248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,
-92,93,32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,
-116,128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,
-210,0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,
-136,25,98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,
-101,160,3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,
-225,150,128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,
-2,158,70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,
-87,98,112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
+195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,65,192,2,22,0,
+88,16,46,24,77,208,148,103,4,102,252,102,244,128,0,0,0,0,0,0,0,0,220,111,
+68,113,61,146,142,248,0,164,255,128,0,63,228,133,109,16,89,178,65,18,235,
+153,25,150,220,184,188,180,230,6,32,209,205,0,20,175,240,0,39,252,160,77,
+162,184,54,72,34,0,82,255,192,0,159,242,193,54,138,222,217,32,136,1,76,255,
+0,2,127,204,4,218,43,115,100,130,32,5,55,252,0,9,255,52,19,104,173,173,146,
+8,128,20,239,240,0,39,252,224,77,162,182,54,72,34,0,83,255,192,0,159,243,
+193,54,138,214,217,32,136,0,255,255,33,177,1,0,22,252,42,44,81,93,165,175,
+1,0,9,174,198,238,213,84,89,173,0,255,152,185,11,251,232,231,189,171,0,255,
+220,85,29,148,174,11,249,169,0,255,111,45,236,84,155,148,57,167,1,0,36,135,
+237,81,16,180,97,165,0,255,154,130,121,153,252,239,53,163,0,255,218,130,
+121,153,252,239,53,38,130,129,25,234,5,0,1,103,40,20,0,9,154,160,80,0,54,
+98,146,25,106,5,0,4,101,40,20,0,21,146,160,80,0,102,66,129,64,1,216,234,5,
+0,8,99,39,47,49,83,215,152,138,73,0,1,97,168,129,132,160,80,0,150,10,129,
+64,2,152,10,5,0,11,95,168,20,0,48,31,255,224,5,17,72,66,249,37,129,127,255,
+0,0,191,255,128,0,63,255,197,31,192,64,196,80,0,0,0,0,0,8,26,112,17,169,0,
+154,80,1,171,28,124,88,65,233,49,7,133,100,29,149,15,14,138,71,135,37,3,
+195,66,114,5,77,252,0,243,178,40,25,200,48,101,30,0,127,210,128,0,85,31,
+192,0,31,244,224,5,71,22,8,0,13,20,88,1,85,127,0,0,127,212,128,21,29,220,
+32,0,52,87,112,5,89,252,0,1,255,86,16,166,66,0,0,0,0,0,0,0,0,170,72,38,29,
+219,247,16,49,75,32,193,52,130,244,193,225,114,96,248,0,8,249,48,124,0,8,
+90,152,62,0,6,44,76,31,0,4,21,166,15,128,2,147,255,252,38,212,16,184,155,
+250,226,217,150,47,46,91,249,54,96,139,229,229,203,127,36,26,119,32,203,
+203,150,254,72,52,97,221,147,102,157,217,192,10,191,248,0,157,4,72,15,250,
+224,1,154,140,36,0,8,43,31,224,0,15,251,0,16,55,139,164,0,192,220,46,144,2,
+3,104,186,64,12,77,130,233,0,33,53,139,164,0,200,212,46,144,2,35,72,186,64,
+8,205,2,233,0,36,51,140,180,0,192,204,50,208,2,3,40,203,64,12,76,131,45,0,
+33,49,140,180,0,200,196,50,208,2,35,8,203,64,8,204,3,45,0,36,7,255,248,1,
+82,101,16,112,24,72,0,8,86,159,193,56,192,63,240,0,0,0,0,0,0,1,151,246,96,
+0,21,183,240,78,48,15,252,0,0,0,0,0,0,0,101,253,168,0,5,113,252,19,140,3,
+255,0,0,0,0,0,0,0,25,127,110,0,1,93,127,4,227,1,0,0,0,0,0,0,0,0,6,95,220,
+128,0,87,159,193,56,192,64,0,0,0,0,0,0,0,1,151,247,96,0,21,247,240,78,48,
+16,4,0,0,0,0,0,0,0,101,253,232,0,5,129,252,19,140,4,1,0,0,0,0,0,0,0,25,127,
+126,0,1,97,127,4,227,1,0,64,0,0,0,0,0,0,6,95,224,128,0,88,159,193,56,192,
+64,32,0,0,0,0,0,0,1,151,248,96,0,22,55,240,5,157,170,33,68,178,69,10,193,
+20,10,104,79,138,36,0,12,31,248,160,88,154,23,66,100,93,32,2,9,129,116,128,
+0,165,197,210,0,18,150,23,72,0,138,84,93,32,3,41,65,116,128,1,36,197,210,0,
+20,146,23,72,0,146,68,93,32,3,73,1,116,128,1,163,197,210,0,22,142,23,72,0,
+34,52,93,32,1,136,193,118,128,2,162,197,218,0,26,138,23,104,0,170,36,93,
+160,3,168,129,150,33,198,90,0,32,134,25,104,0,10,20,101,160,1,40,65,150,
+128,8,160,198,90,0,50,130,25,104,0,18,4,101,160,1,72,1,150,128,9,31,198,90,
+0,52,126,25,104,0,25,244,101,160,1,103,193,150,128,2,30,198,90,0,24,122,25,
+136,0,41,228,102,32,1,167,129,152,128,10,157,198,98,0,59,71,91,99,157,104,
+9,213,118,39,5,8,159,20,40,0,10,109,90,19,81,132,39,151,32,
};
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
@@ -13053,7 +13084,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_typedarray_set,
};
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[1955] = {
105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
@@ -13095,50 +13126,50 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
97,236,66,80,1,151,169,10,248,0,211,208,133,124,0,109,230,66,254,0,56,242,
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
-195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
-239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
-203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
-252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
-54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
-206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
-255,242,27,16,2,175,193,80,26,85,197,34,218,240,44,90,192,144,5,149,109,
-110,218,208,16,139,185,143,251,206,126,191,154,176,17,197,125,207,255,160,
-138,217,90,144,30,242,246,207,195,185,73,133,90,112,62,200,66,80,6,11,81,
-21,26,80,39,168,57,143,243,78,223,217,154,48,39,168,61,143,243,78,223,217,
-146,104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,
-80,0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,
-21,61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,
-181,250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,
-3,255,252,81,252,8,4,252,68,0,0,0,0,0,129,167,1,26,144,9,165,0,26,177,199,
-197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
-223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
-113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
-159,192,0,31,245,97,10,100,0,0,0,32,0,0,0,0,10,164,130,97,221,191,113,3,20,
-178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
-196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
-242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
-70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
-64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
-0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
-144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
-203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
-38,81,7,1,132,128,0,133,105,252,19,140,0,0,15,3,240,0,0,0,0,25,127,102,0,1,
-91,127,4,227,0,0,3,192,252,0,0,0,0,6,95,218,128,0,87,31,193,56,192,0,0,240,
-63,0,0,0,0,1,151,246,224,0,21,215,240,78,48,0,0,0,16,0,0,0,0,0,101,253,200,
-0,5,121,252,19,140,0,0,0,4,0,0,0,0,0,25,127,118,0,1,95,127,4,227,0,0,0,65,
-0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,0,0,16,64,0,0,0,0,1,151,247,224,
-0,22,23,240,78,48,0,0,4,16,0,0,0,0,0,101,254,8,0,5,137,252,19,140,0,0,2,4,
-0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,132,
-248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,92,93,
-32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,116,
-128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,210,
-0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,136,25,
-98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,101,160,
-3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,225,150,
-128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,2,158,
-70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,87,98,
-112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
+195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,65,192,2,22,0,
+88,16,46,24,77,208,148,103,4,102,252,102,244,128,0,0,0,0,0,0,0,0,220,111,
+68,113,61,146,142,248,0,164,255,128,0,63,228,133,109,16,89,178,65,18,235,
+153,25,150,220,184,188,180,230,6,32,209,205,0,20,175,240,0,39,252,160,77,
+162,184,54,72,34,0,82,255,192,0,159,242,193,54,138,222,217,32,136,1,76,255,
+0,2,127,204,4,218,43,115,100,130,32,5,55,252,0,9,255,52,19,104,173,173,146,
+8,128,20,239,240,0,39,252,224,77,162,182,54,72,34,0,83,255,192,0,159,243,
+193,54,138,214,217,32,136,0,255,255,33,177,0,42,252,21,1,165,92,82,45,175,
+2,197,172,9,0,89,86,214,237,173,1,8,187,152,255,188,231,235,249,171,1,28,
+87,220,255,250,8,173,149,169,1,239,47,108,252,59,148,152,85,167,3,236,132,
+37,0,96,181,17,81,165,2,122,131,152,255,52,237,253,153,163,2,122,131,216,
+255,52,237,253,153,38,130,129,25,234,5,0,1,103,40,20,0,9,154,160,80,0,54,
+98,146,25,106,5,0,4,101,40,20,0,21,146,160,80,0,102,66,129,64,1,216,234,5,
+0,8,99,39,47,49,83,215,152,138,73,0,1,97,168,129,132,160,80,0,150,10,129,
+64,2,152,10,5,0,11,95,168,20,0,48,31,255,224,5,17,72,66,249,37,129,127,255,
+0,0,191,255,128,0,63,255,197,31,192,0,80,196,64,0,0,0,0,8,26,112,17,169,0,
+154,80,1,171,28,124,88,65,233,49,7,133,100,29,149,15,14,138,71,135,37,3,
+195,66,114,5,77,252,0,243,178,40,25,200,48,101,30,0,127,210,128,0,85,31,
+192,0,31,244,224,5,71,22,8,0,13,20,88,1,85,127,0,0,127,212,128,21,29,220,
+32,0,52,87,112,5,89,252,0,1,255,86,16,166,64,0,0,2,0,0,0,0,0,170,72,38,29,
+219,247,16,49,75,32,193,52,130,244,193,225,114,96,248,0,8,249,48,124,0,8,
+90,152,62,0,6,44,76,31,0,4,21,166,15,128,2,147,255,252,38,212,16,184,155,
+250,226,217,150,47,46,91,249,54,96,139,229,229,203,127,36,26,119,32,203,
+203,150,254,72,52,97,221,147,102,157,217,192,10,191,248,0,157,4,72,15,250,
+224,1,154,140,36,0,8,43,31,224,0,15,251,0,16,55,139,164,0,192,220,46,144,2,
+3,104,186,64,12,77,130,233,0,33,53,139,164,0,200,212,46,144,2,35,72,186,64,
+8,205,2,233,0,36,51,140,180,0,192,204,50,208,2,3,40,203,64,12,76,131,45,0,
+33,49,140,180,0,200,196,50,208,2,35,8,203,64,8,204,3,45,0,36,7,255,248,1,
+82,101,16,112,24,72,0,8,86,159,193,56,192,0,0,240,63,0,0,0,0,1,151,246,96,
+0,21,183,240,78,48,0,0,60,15,192,0,0,0,0,101,253,168,0,5,113,252,19,140,0,
+0,15,3,240,0,0,0,0,25,127,110,0,1,93,127,4,227,0,0,0,1,0,0,0,0,0,6,95,220,
+128,0,87,159,193,56,192,0,0,0,64,0,0,0,0,1,151,247,96,0,21,247,240,78,48,0,
+0,4,16,0,0,0,0,0,101,253,232,0,5,129,252,19,140,0,0,1,4,0,0,0,0,0,25,127,
+126,0,1,97,127,4,227,0,0,0,65,0,0,0,0,0,6,95,224,128,0,88,159,193,56,192,0,
+0,32,64,0,0,0,0,1,151,248,96,0,22,55,240,5,157,170,33,68,178,69,10,193,20,
+10,104,79,138,36,0,12,31,248,160,88,154,23,66,100,93,32,2,9,129,116,128,0,
+165,197,210,0,18,150,23,72,0,138,84,93,32,3,41,65,116,128,1,36,197,210,0,
+20,146,23,72,0,146,68,93,32,3,73,1,116,128,1,163,197,210,0,22,142,23,72,0,
+34,52,93,32,1,136,193,118,128,2,162,197,218,0,26,138,23,104,0,170,36,93,
+160,3,168,129,150,33,198,90,0,32,134,25,104,0,10,20,101,160,1,40,65,150,
+128,8,160,198,90,0,50,130,25,104,0,18,4,101,160,1,72,1,150,128,9,31,198,90,
+0,52,126,25,104,0,25,244,101,160,1,103,193,150,128,2,30,198,90,0,24,122,25,
+136,0,41,228,102,32,1,167,129,152,128,10,157,198,98,0,59,71,91,99,157,104,
+9,213,118,39,5,8,159,20,40,0,10,109,90,19,81,132,39,151,32,
};
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
@@ -15778,7 +15809,6 @@ DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_small_uint_t call_flags;
duk_idx_t idx_func;
- duk_int_t rc;
DUK_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(thr != NULL);
@@ -15797,17 +15827,15 @@ DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
call_flags = 0; /* not protected, respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
- DUK_UNREF(rc);
+ duk_handle_call_unprotected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
}
DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_small_uint_t call_flags;
duk_idx_t idx_func;
- duk_int_t rc;
DUK_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(thr != NULL);
@@ -15820,10 +15848,9 @@ DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
call_flags = 0; /* not protected, respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
- DUK_UNREF(rc);
+ duk_handle_call_unprotected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
}
DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
@@ -15872,11 +15899,11 @@ DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) {
duk_push_undefined(ctx);
duk_insert(ctx, idx_func + 1);
- call_flags = DUK_CALL_FLAG_PROTECTED; /* protected, respect reclimit, not constructor */
+ call_flags = 0; /* respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ rc = duk_handle_call_protected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
return rc;
}
@@ -15897,11 +15924,11 @@ DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) {
return DUK_EXEC_ERROR; /* unreachable */
}
- call_flags = DUK_CALL_FLAG_PROTECTED; /* protected, respect reclimit, not constructor */
+ call_flags = 0; /* respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ rc = duk_handle_call_protected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
return rc;
}
@@ -16010,7 +16037,6 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
duk_hobject *fallback;
duk_idx_t idx_cons;
duk_small_uint_t call_flags;
- duk_int_t rc;
DUK_ASSERT_CTX_VALID(ctx);
@@ -16104,15 +16130,13 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
- DUK_UNREF(rc);
+ duk_handle_call_unprotected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
/* [... fallback retval] */
- DUK_DDD(DUK_DDDPRINT("constructor call finished, rc=%ld, fallback=%!iT, retval=%!iT",
- (long) rc,
+ DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT",
(duk_tval *) duk_get_tval(ctx, -2),
(duk_tval *) duk_get_tval(ctx, -1)));
@@ -20672,16 +20696,16 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
* true
*/
duk_small_uint_t lf_flags;
- duk_small_uint_t nargs;
+ duk_idx_t nargs;
duk_small_uint_t lf_len;
duk_c_function func;
duk_hnativefunction *nf;
DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
- nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
+ nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
if (nargs == DUK_LFUNC_NARGS_VARARGS) {
- nargs = DUK_VARARGS;
+ nargs = (duk_idx_t) DUK_VARARGS;
}
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_CONSTRUCTABLE |
@@ -20691,10 +20715,10 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
DUK_HOBJECT_FLAG_NOTAIL |
/* DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC: omitted here intentionally */
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- (void) duk__push_c_function_raw(ctx, func, (duk_idx_t) nargs, flags);
+ (void) duk__push_c_function_raw(ctx, func, nargs, flags);
lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
- if (lf_len != nargs) {
+ if ((duk_idx_t) lf_len != nargs) {
/* Explicit length is only needed if it differs from 'nargs'. */
duk_push_int(ctx, (duk_int_t) lf_len);
duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
@@ -21889,7 +21913,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
duk_hnativefunction *obj;
duk_idx_t ret;
duk_tval *tv_slot;
- duk_uint16_t func_nargs;
+ duk_int16_t func_nargs;
DUK_ASSERT_CTX_VALID(ctx);
@@ -21901,7 +21925,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
goto api_error;
}
if (nargs >= 0 && nargs < DUK_HNATIVEFUNCTION_NARGS_MAX) {
- func_nargs = (duk_uint16_t) nargs;
+ func_nargs = (duk_int16_t) nargs;
} else if (nargs == DUK_VARARGS) {
func_nargs = DUK_HNATIVEFUNCTION_NARGS_VARARGS;
} else {
@@ -25623,8 +25647,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_HBUFFER_INCREF(thr, h_val);
h_bufobj->offset = h_bufarg->offset + byte_offset;
h_bufobj->length = byte_length;
- h_bufobj->shift = shift;
- h_bufobj->elem_type = elem_type;
+ h_bufobj->shift = (duk_uint8_t) shift;
+ h_bufobj->elem_type = (duk_uint8_t) elem_type;
h_bufobj->is_view = 1;
DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
@@ -25727,8 +25751,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_HBUFFER_INCREF(thr, h_val);
DUK_ASSERT(h_bufobj->offset == 0);
h_bufobj->length = byte_length;
- h_bufobj->shift = shift;
- h_bufobj->elem_type = elem_type;
+ h_bufobj->shift = (duk_uint8_t) shift;
+ h_bufobj->elem_type = (duk_uint8_t) elem_type;
h_bufobj->is_view = 1;
DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
@@ -31241,7 +31265,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
duk_small_uint_t comp_flags;
duk_int_t level = -2;
- DUK_ASSERT_TOP(ctx, 1);
+ DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */
DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
(thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */
@@ -38486,7 +38510,9 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
thr->heap->lj.iserror = is_error;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
+#endif
duk_err_longjmp(thr); /* execution resumes in bytecode executor */
return 0; /* never here */
@@ -38603,7 +38629,9 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
thr->heap->lj.iserror = is_error;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
+#endif
duk_err_longjmp(thr); /* execution resumes in bytecode executor */
return 0; /* never here */
@@ -41388,7 +41416,7 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
/* [ ... eval "eval" eval_input level ] */
- call_flags = DUK_CALL_FLAG_PROTECTED;
+ call_flags = 0;
if (thr->callstack_top >= (duk_size_t) -level) {
duk_activation *act;
duk_hobject *fun;
@@ -41405,7 +41433,7 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
}
}
- call_ret = duk_handle_call(thr, 2 /*num_stack_args*/, call_flags);
+ call_ret = duk_handle_call_protected(thr, 2 /*num_stack_args*/, call_flags);
if (call_ret == DUK_EXEC_SUCCESS) {
eval_err = 0;
@@ -42151,12 +42179,11 @@ DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_c
DUK_ASSERT(!DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)); /* since no recursive error handler calls */
DUK_HEAP_SET_ERRHANDLER_RUNNING(thr->heap);
- call_flags = DUK_CALL_FLAG_PROTECTED |
- DUK_CALL_FLAG_IGNORE_RECLIMIT; /* protected, ignore reclimit, not constructor */
+ call_flags = DUK_CALL_FLAG_IGNORE_RECLIMIT; /* ignore reclimit, not constructor */
- rc = duk_handle_call(thr,
- 1, /* num args */
- call_flags); /* call_flags */
+ rc = duk_handle_call_protected(thr,
+ 1, /* num args */
+ call_flags); /* call_flags */
DUK_UNREF(rc); /* no need to check now: both success and error are OK */
DUK_ASSERT(DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));
@@ -42591,6 +42618,12 @@ DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ /* XXX: detecting uncaught exception case for C++ case; perhaps need
+ * some marker in heap->lj state that a try-catch is active. For now,
+ * invokes C++ uncaught exception handling.
+ */
+#else
if (!thr->heap->lj.jmpbuf_ptr) {
/*
* If we don't have a jmpbuf_ptr, there is little we can do
@@ -42605,8 +42638,16 @@ DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
duk_fatal((duk_context *) thr, DUK_ERR_UNCAUGHT_ERROR, "uncaught error");
DUK_UNREACHABLE();
}
+#endif
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ {
+ duk_internal_exception exc; /* dummy */
+ throw exc;
+ }
+#else
DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb);
+#endif
DUK_UNREACHABLE();
}
#line 1 "duk_error_misc.c"
@@ -43731,7 +43772,9 @@ DUK_LOCAL void duk__dump_type_sizes(void) {
DUK__DUMPSZ(duk_tval);
/* structs from duk_forwdecl.h */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK__DUMPSZ(duk_jmpbuf);
+#endif
DUK__DUMPSZ(duk_heaphdr);
DUK__DUMPSZ(duk_heaphdr_string);
DUK__DUMPSZ(duk_hstring);
@@ -56652,22 +56695,80 @@ DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new
/*
* Call handling.
*
- * The main work horse functions are:
- * - duk_handle_call(): call to a C/Ecmascript functions
- * - duk_handle_safe_call(): make a protected C call within current activation
- * - duk_handle_ecma_call_setup(): Ecmascript-to-Ecmascript calls, including
- * tail calls and coroutine resume
+ * Main functions are:
+ *
+ * - duk_handle_call_unprotected(): unprotected call to Ecmascript or
+ * Duktape/C function
+ * - duk_handle_call_protected(): protected call to Ecmascript or
+ * Duktape/C function
+ * - duk_handle_safe_call(): make a protected C call within current
+ * activation
+ * - duk_handle_ecma_call_setup(): Ecmascript-to-Ecmascript calls
+ * (not always possible), including tail calls and coroutine resume
+ *
+ * See 'execution.rst'.
+ *
+ * Note: setjmp() and local variables have a nasty interaction,
+ * see execution.rst; non-volatile locals modified after setjmp()
+ * call are not guaranteed to keep their value.
*/
/* include removed: duk_internal.h */
/*
- * Misc
+ * Forward declarations.
+ */
+
+DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_small_uint_t call_flags,
+ duk_idx_t idx_func);
+DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_valstack_end,
+ duk_size_t entry_catchstack_top,
+ duk_size_t entry_callstack_top,
+ duk_int_t entry_call_recursion_depth,
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
+ duk_instr_t **entry_ptr_curr_pc,
+ duk_idx_t idx_func
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ );
+DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
+ duk_safe_call_function func,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_callstack_top,
+ duk_size_t entry_catchstack_top);
+DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_callstack_top,
+ duk_size_t entry_catchstack_top
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ );
+DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_int_t entry_call_recursion_depth,
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
+ duk_instr_t **entry_ptr_curr_pc);
+
+/*
+ * Interrupt counter fixup (for development only).
*/
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_thread) {
- /* XXX: Currently the bytecode executor and executor interrupt
+ /* Currently the bytecode executor and executor interrupt
* instruction counts are off because we don't execute the
* interrupt handler when we're about to exit from the initial
* user call into Duktape.
@@ -56699,18 +56800,17 @@ DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_th
/*
* Arguments object creation.
*
- * Creating arguments objects is a bit finicky, see E5 Section 10.6 for the
- * specific requirements. Much of the arguments object exotic behavior is
- * implemented in duk_hobject_props.c, and is enabled by the object flag
- * DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS.
+ * Creating arguments objects involves many small details, see E5 Section
+ * 10.6 for the specific requirements. Much of the arguments object exotic
+ * behavior is implemented in duk_hobject_props.c, and is enabled by the
+ * object flag DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS.
*/
-DUK_LOCAL
-void duk__create_arguments_object(duk_hthread *thr,
- duk_hobject *func,
- duk_hobject *varenv,
- duk_idx_t idx_argbase, /* idx of first argument on stack */
- duk_idx_t num_stack_args) { /* num args starting from idx_argbase */
+DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
+ duk_hobject *func,
+ duk_hobject *varenv,
+ duk_idx_t idx_argbase, /* idx of first argument on stack */
+ duk_idx_t num_stack_args) { /* num args starting from idx_argbase */
duk_context *ctx = (duk_context *) thr;
duk_hobject *arg; /* 'arguments' */
duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */
@@ -56789,7 +56889,7 @@ void duk__create_arguments_object(duk_hthread *thr,
-1); /* no prototype */
DUK_ASSERT(i_mappednames >= 0);
- /* [... formals arguments map mappedNames] */
+ /* [ ... formals arguments map mappedNames ] */
DUK_DDD(DUK_DDDPRINT("created arguments related objects: "
"arguments at index %ld -> %!O "
@@ -56831,14 +56931,14 @@ void duk__create_arguments_object(duk_hthread *thr,
duk_get_prop_index(ctx, i_formals, idx);
DUK_ASSERT(duk_is_string(ctx, -1));
- duk_dup(ctx, -1); /* [... name name] */
+ duk_dup(ctx, -1); /* [ ... name name ] */
if (!duk_has_prop(ctx, i_mappednames)) {
/* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping
* differs from the reference model
*/
- /* [... name] */
+ /* [ ... name ] */
need_map = 1;
@@ -56859,7 +56959,7 @@ void duk__create_arguments_object(duk_hthread *thr,
/* duk_has_prop() popped the second 'name' */
}
- /* [... name] */
+ /* [ ... name ] */
duk_pop(ctx); /* pop 'name' */
}
@@ -56893,18 +56993,17 @@ void duk__create_arguments_object(duk_hthread *thr,
/* steps 13-14 */
if (DUK_HOBJECT_HAS_STRICT(func)) {
- /*
- * Note: callee/caller are throwers and are not deletable etc.
- * They could be implemented as virtual properties, but currently
- * there is no support for virtual properties which are accessors
- * (only plain virtual properties). This would not be difficult
- * to change in duk_hobject_props, but we can make the throwers
- * normal, concrete properties just as easily.
+ /* Callee/caller are throwers and are not deletable etc. They
+ * could be implemented as virtual properties, but currently
+ * there is no support for virtual properties which are accessors
+ * (only plain virtual properties). This would not be difficult
+ * to change in duk_hobject_props, but we can make the throwers
+ * normal, concrete properties just as easily.
*
- * Note that the specification requires that the *same* thrower
- * built-in object is used here! See E5 Section 10.6 main
- * algoritm, step 14, and Section 13.2.3 which describes the
- * thrower. See test case test-arguments-throwers.js.
+ * Note that the specification requires that the *same* thrower
+ * built-in object is used here! See E5 Section 10.6 main
+ * algoritm, step 14, and Section 13.2.3 which describes the
+ * thrower. See test case test-arguments-throwers.js.
*/
DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers"));
@@ -56919,15 +57018,14 @@ void duk__create_arguments_object(duk_hthread *thr,
/* set exotic behavior only after we're done */
if (need_map) {
- /*
- * Note: exotic behaviors are only enabled for arguments
- * objects which have a parameter map (see E5 Section 10.6
- * main algorithm, step 12).
+ /* Exotic behaviors are only enabled for arguments objects
+ * which have a parameter map (see E5 Section 10.6 main
+ * algorithm, step 12).
*
- * In particular, a non-strict arguments object with no
- * mapped formals does *NOT* get exotic behavior, even
- * for e.g. "caller" property. This seems counterintuitive
- * but seems to be the case.
+ * In particular, a non-strict arguments object with no
+ * mapped formals does *NOT* get exotic behavior, even
+ * for e.g. "caller" property. This seems counterintuitive
+ * but seems to be the case.
*/
/* cannot be strict (never mapped variables) */
@@ -56939,7 +57037,6 @@ void duk__create_arguments_object(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("not enabling exotic behavior for arguments object"));
}
- /* nice log */
DUK_DDD(DUK_DDDPRINT("final arguments related objects: "
"arguments at index %ld -> %!O "
"map at index %ld -> %!O "
@@ -56948,20 +57045,22 @@ void duk__create_arguments_object(duk_hthread *thr,
(long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
(long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
- /* [args(n) [crud] formals arguments map mappednames] -> [args [crud] arguments] */
+ /* [ args(n) [crud] formals arguments map mappednames ] */
+
duk_pop_2(ctx);
duk_remove(ctx, -2);
+
+ /* [ args [crud] arguments ] */
}
/* Helper for creating the arguments object and adding it to the env record
* on top of the value stack. This helper has a very strict dependency on
* the shape of the input stack.
*/
-DUK_LOCAL
-void duk__handle_createargs_for_call(duk_hthread *thr,
- duk_hobject *func,
- duk_hobject *env,
- duk_idx_t num_stack_args) {
+DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr,
+ duk_hobject *func,
+ duk_hobject *env,
+ duk_idx_t num_stack_args) {
duk_context *ctx = (duk_context *) thr;
DUK_DDD(DUK_DDDPRINT("creating arguments object for function call"));
@@ -56972,7 +57071,7 @@ void duk__handle_createargs_for_call(duk_hthread *thr,
DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
DUK_ASSERT(duk_get_top(ctx) >= num_stack_args + 1);
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
duk__create_arguments_object(thr,
func,
@@ -56980,14 +57079,14 @@ void duk__handle_createargs_for_call(duk_hthread *thr,
duk_get_top(ctx) - num_stack_args - 1, /* idx_argbase */
num_stack_args);
- /* [... arg1 ... argN envobj argobj] */
+ /* [ ... arg1 ... argN envobj argobj ] */
duk_xdef_prop_stridx(ctx,
-2,
DUK_STRIDX_LC_ARGUMENTS,
DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */
DUK_PROPDESC_FLAGS_WE); /* non-strict: non-deletable, writable */
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
}
/*
@@ -57004,11 +57103,10 @@ void duk__handle_createargs_for_call(duk_hthread *thr,
* function. This would make call time handling much easier.
*/
-DUK_LOCAL
-void duk__handle_bound_chain_for_call(duk_hthread *thr,
- duk_idx_t idx_func,
- duk_idx_t *p_num_stack_args, /* may be changed by call */
- duk_bool_t is_constructor_call) {
+DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
+ duk_idx_t idx_func,
+ duk_idx_t *p_num_stack_args, /* may be changed by call */
+ duk_bool_t is_constructor_call) {
duk_context *ctx = (duk_context *) thr;
duk_idx_t num_stack_args;
duk_tval *tv_func;
@@ -57101,7 +57199,7 @@ void duk__handle_bound_chain_for_call(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(ctx, idx_func)));
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
tv_func = duk_require_tval(ctx, idx_func);
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func));
if (DUK_TVAL_IS_OBJECT(tv_func)) {
@@ -57122,10 +57220,9 @@ void duk__handle_bound_chain_for_call(duk_hthread *thr,
* assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag.
*/
-DUK_LOCAL
-void duk__handle_oldenv_for_call(duk_hthread *thr,
- duk_hobject *func,
- duk_activation *act) {
+DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr,
+ duk_hobject *func,
+ duk_activation *act) {
duk_tval *tv;
DUK_ASSERT(thr != NULL);
@@ -57161,7 +57258,7 @@ void duk__handle_oldenv_for_call(duk_hthread *thr,
* Helper for updating callee 'caller' property.
*/
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func) {
duk_tval *tv_caller;
duk_hobject *h_tmp;
@@ -57181,6 +57278,8 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
act_callee = thr->callstack + thr->callstack_top - 1;
act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL);
+ /* XXX: check .caller writability? */
+
/* Backup 'caller' property and update its value. */
tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
if (tv_caller) {
@@ -57263,10 +57362,9 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
* side effects, because ToObject() may be called.
*/
-DUK_LOCAL
-void duk__coerce_effective_this_binding(duk_hthread *thr,
- duk_hobject *func,
- duk_idx_t idx_this) {
+DUK_LOCAL void duk__coerce_effective_this_binding(duk_hthread *thr,
+ duk_hobject *func,
+ duk_idx_t idx_this) {
duk_context *ctx = (duk_context *) thr;
duk_tval *tv_this;
duk_hobject *obj_global;
@@ -57316,12 +57414,11 @@ void duk__coerce_effective_this_binding(duk_hthread *thr,
* Returns duk_hobject * to the final non-bound function (NULL for lightfunc).
*/
-DUK_LOCAL
-duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
- duk_idx_t idx_func,
- duk_idx_t *out_num_stack_args,
- duk_tval **out_tv_func,
- duk_small_uint_t call_flags) {
+DUK_LOCAL duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
+ duk_idx_t idx_func,
+ duk_idx_t *out_num_stack_args,
+ duk_tval **out_tv_func,
+ duk_small_uint_t call_flags) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_tval *tv_func;
duk_hobject *func;
@@ -57377,19 +57474,23 @@ duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
}
/*
- * Value stack resize and stack top adjustment helper
+ * Value stack resize and stack top adjustment helper.
*
* XXX: This should all be merged to duk_valstack_resize_raw().
*/
-DUK_LOCAL
-void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, duk_idx_t idx_args, duk_idx_t nregs, duk_idx_t nargs, duk_hobject *func) {
+DUK_LOCAL void duk__adjust_valstack_and_top(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_idx_t idx_args,
+ duk_idx_t nregs,
+ duk_idx_t nargs,
+ duk_hobject *func) {
duk_context *ctx = (duk_context *) thr;
duk_size_t vs_min_size;
duk_bool_t adjusted_top = 0;
- vs_min_size = (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
- idx_args; /* bottom of new func */
+ vs_min_size = (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
+ idx_args; /* bottom of new func */
if (nregs >= 0) {
DUK_ASSERT(nargs >= 0);
@@ -57400,15 +57501,17 @@ void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, du
vs_min_size += num_stack_args; /* num entries of new func at entry */
}
if (func == NULL || DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM; /* Duktape/C API guaranteed entries (on top of args) */
+ vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM; /* Duktape/C API guaranteed entries (on top of args) */
}
- vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA; /* + spare */
+ vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA; /* + spare */
- /* XXX: Awkward fix for GH-107: we can't resize the value stack to
- * a size smaller than the current top, so the order of the resize
- * and adjusting the stack top depends on the current vs. final size
- * of the value stack. Ideally duk_valstack_resize_raw() would have
- * a combined algorithm to avoid this.
+ /* XXX: We can't resize the value stack to a size smaller than the
+ * current top, so the order of the resize and adjusting the stack
+ * top depends on the current vs. final size of the value stack.
+ * The operations could be combined to avoid this, but the proper
+ * fix is to only grow the value stack on a function call, and only
+ * shrink it (without throwing if the shrink fails) on function
+ * return.
*/
if (vs_min_size < (duk_size_t) (thr->valstack_top - thr->valstack)) {
@@ -57436,14 +57539,111 @@ void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, du
}
/*
- * Helper for making various kinds of calls.
- *
- * Call flags:
+ * Manipulate value stack so that exactly 'num_stack_rets' return
+ * values are at 'idx_retbase' in every case, assuming there are
+ * 'rc' return values on top of stack.
*
- * DUK_CALL_FLAG_PROTECTED <--> protected call
- * DUK_CALL_FLAG_IGNORE_RECLIMIT <--> ignore C recursion limit,
- * for errhandler calls
- * DUK_CALL_FLAG_CONSTRUCTOR_CALL <--> for 'new Foo()' calls
+ * This is a bit tricky, because the called C function operates in
+ * the same activation record and may have e.g. popped the stack
+ * empty (below idx_retbase).
+ */
+
+DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_retbase, duk_idx_t num_stack_rets, duk_idx_t num_actual_rets) {
+ duk_context *ctx = (duk_context *) thr;
+ duk_idx_t idx_rcbase;
+
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(idx_retbase >= 0);
+ DUK_ASSERT(num_stack_rets >= 0);
+ DUK_ASSERT(num_actual_rets >= 0);
+
+ idx_rcbase = duk_get_top(ctx) - num_actual_rets; /* base of known return values */
+
+ DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
+ "num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld",
+ (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(ctx),
+ (long) idx_retbase, (long) idx_rcbase));
+
+ DUK_ASSERT(idx_rcbase >= 0); /* caller must check */
+
+ /* Ensure space for final configuration (idx_retbase + num_stack_rets)
+ * and intermediate configurations.
+ */
+ duk_require_stack_top(ctx,
+ (idx_rcbase > idx_retbase ? idx_rcbase : idx_retbase) +
+ num_stack_rets);
+
+ /* Chop extra retvals away / extend with undefined. */
+ duk_set_top(ctx, idx_rcbase + num_stack_rets);
+
+ if (idx_rcbase >= idx_retbase) {
+ duk_idx_t count = idx_rcbase - idx_retbase;
+ duk_idx_t i;
+
+ DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
+ "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
+
+ /* nuke values at idx_retbase to get the first retval (initially
+ * at idx_rcbase) to idx_retbase
+ */
+
+ DUK_ASSERT(count >= 0);
+
+ for (i = 0; i < count; i++) {
+ /* XXX: inefficient; block remove primitive */
+ duk_remove(ctx, idx_retbase);
+ }
+ } else {
+ duk_idx_t count = idx_retbase - idx_rcbase;
+ duk_idx_t i;
+
+ DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
+ "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
+
+ /* insert 'undefined' values at idx_rcbase to get the
+ * return values to idx_retbase
+ */
+
+ DUK_ASSERT(count > 0);
+
+ for (i = 0; i < count; i++) {
+ /* XXX: inefficient; block insert primitive */
+ duk_push_undefined(ctx);
+ duk_insert(ctx, idx_rcbase);
+ }
+ }
+}
+
+/*
+ * Misc shared helpers.
+ */
+
+/* Get valstack index for the func argument or throw if insane stack. */
+DUK_LOCAL duk_idx_t duk__get_idx_func(duk_hthread *thr, duk_idx_t num_stack_args) {
+ duk_size_t off_stack_top;
+ duk_size_t off_stack_args;
+ duk_size_t off_stack_all;
+ duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
+
+ /* Argument validation and func/args offset. */
+ off_stack_top = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack_bottom);
+ off_stack_args = (duk_size_t) ((duk_size_t) num_stack_args * sizeof(duk_tval));
+ off_stack_all = off_stack_args + 2 * sizeof(duk_tval);
+ if (DUK_UNLIKELY(off_stack_all > off_stack_top)) {
+ /* Since stack indices are not reliable, we can't do anything useful
+ * here. Invoke the existing setjmp catcher, or if it doesn't exist,
+ * call the fatal error handler.
+ */
+ DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ return 0;
+ }
+ idx_func = (duk_idx_t) ((off_stack_top - off_stack_all) / sizeof(duk_tval));
+ return idx_func;
+}
+
+/*
+ * duk_handle_call_protected() and duk_handle_call_unprotected():
+ * call into a Duktape/C or an Ecmascript function from any state.
*
* Input stack (thr):
*
@@ -57454,34 +57654,19 @@ void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, du
* [ retval ] (DUK_EXEC_SUCCESS)
* [ errobj ] (DUK_EXEC_ERROR (normal error), protected call)
*
- * Even when executing a protected call an error may be thrown in rare cases.
- * For instance, if we run out of memory when setting up the return stack
- * after a caught error, the out of memory is propagated to the caller.
- * Similarly, API errors (such as invalid input stack shape and invalid
- * indices) cause an error to propagate out of this function. If there is
- * no catchpoint for this error, the fatal error handler is called.
- *
- * See 'execution.rst'.
- *
- * The allowed thread states for making a call are:
- * - thr matches heap->curr_thread, and thr is already RUNNING
- * - thr does not match heap->curr_thread (may be NULL or other),
- * and thr is INACTIVE (in this case, a setjmp() catchpoint is
- * always used for thread book-keeping to work properly)
+ * Even when executing a protected call an error may be thrown in rare cases
+ * such as an insane num_stack_args argument. If there is no catchpoint for
+ * such errors, the fatal error handler is called.
*
- * Like elsewhere, gotos are used to keep indent level minimal and
- * avoiding a dozen helpers with awkward plumbing.
- *
- * Note: setjmp() and local variables have a nasty interaction,
- * see execution.rst; non-volatile locals modified after setjmp()
- * call are not guaranteed to keep their value.
+ * The error handling path should be error free, even for out-of-memory
+ * errors, to ensure safe sandboxing. (As of Duktape 1.4.0 this is not
+ * yet the case, see XXX notes below.)
*/
-DUK_INTERNAL
-duk_int_t duk_handle_call(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags) {
- duk_context *ctx = (duk_context *) thr;
+DUK_INTERNAL duk_int_t duk_handle_call_protected(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_small_uint_t call_flags) {
+ duk_context *ctx;
duk_size_t entry_valstack_bottom_index;
duk_size_t entry_valstack_end;
duk_size_t entry_callstack_top;
@@ -57490,37 +57675,33 @@ duk_int_t duk_handle_call(duk_hthread *thr,
duk_hthread *entry_curr_thread;
duk_uint_fast8_t entry_thread_state;
duk_instr_t **entry_ptr_curr_pc;
- volatile duk_bool_t need_setjmp;
- duk_jmpbuf * volatile old_jmpbuf_ptr = NULL; /* ptr is volatile (not the target) */
- volatile duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
- duk_idx_t idx_args; /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */
- duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
- duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
- duk_hobject *func; /* 'func' on stack (borrowed reference) */
- duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) or tv_func_copy */
- duk_tval tv_func_copy; /* to avoid relookups */
- duk_activation *act;
- duk_hobject *env;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ duk_jmpbuf *old_jmpbuf_ptr = NULL;
duk_jmpbuf our_jmpbuf;
- duk_int_t retval = DUK_EXEC_ERROR;
- duk_ret_t rc;
+#endif
+ duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
+
+ /* XXX: Multiple tv_func lookups are now avoided by making a local
+ * copy of tv_func. Another approach would be to compute an offset
+ * for tv_func from valstack bottom and recomputing the tv_func
+ * pointer quickly as valstack + offset instead of calling duk_get_tval().
+ */
+ ctx = (duk_context *) thr;
+ DUK_UNREF(ctx);
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(num_stack_args >= 0);
-
/* XXX: currently NULL allocations are not supported; remove if later allowed */
DUK_ASSERT(thr->valstack != NULL);
DUK_ASSERT(thr->callstack != NULL);
DUK_ASSERT(thr->catchstack != NULL);
- /*
- * Preliminaries, required by setjmp() handler.
- *
- * Must be careful not to throw an unintended error here.
- *
- * Note: careful with indices like '-x'; if 'x' is zero, it
- * refers to valstack_bottom.
+ /* Argument validation and func/args offset. */
+ idx_func = duk__get_idx_func(thr, num_stack_args);
+
+ /* Preliminaries, required by setjmp() handler. Must be careful not
+ * to throw an unintended error here.
*/
entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
@@ -57537,29 +57718,19 @@ duk_int_t duk_handle_call(duk_hthread *thr,
entry_thread_state = thr->state;
entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
- idx_func = duk_normalize_index(ctx, -num_stack_args - 2); /* idx_func must be valid, note: non-throwing! */
- idx_args = idx_func + 2; /* idx_args is not necessarily valid if num_stack_args == 0 (idx_args then equals top) */
-
- /* Need a setjmp() catchpoint if a protected call OR if we need to
- * do mandatory cleanup.
- */
- need_setjmp = ((call_flags & DUK_CALL_FLAG_PROTECTED) != 0) || (thr->heap->curr_thread != thr);
-
- DUK_DD(DUK_DDPRINT("duk_handle_call: thr=%p, num_stack_args=%ld, "
- "call_flags=0x%08lx (protected=%ld, ignorerec=%ld, constructor=%ld), need_setjmp=%ld, "
+ DUK_DD(DUK_DDPRINT("duk_handle_call_protected: thr=%p, num_stack_args=%ld, "
+ "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
"valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
"entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
"entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
(void *) thr,
(long) num_stack_args,
(unsigned long) call_flags,
- (long) ((call_flags & DUK_CALL_FLAG_PROTECTED) != 0 ? 1 : 0),
(long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
(long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
- (long) need_setjmp,
(long) duk_get_top(ctx),
(long) idx_func,
- (long) idx_args,
+ (long) (idx_func + 2),
(long) thr->heap->call_recursion_depth,
(long) thr->heap->call_recursion_limit,
(long) entry_valstack_bottom_index,
@@ -57569,161 +57740,207 @@ duk_int_t duk_handle_call(duk_hthread *thr,
(void *) entry_curr_thread,
(long) entry_thread_state));
- /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
- * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
- * activation when side effects occur.
- */
- duk_hthread_sync_and_null_currpc(thr);
-
- /* XXX: Multiple tv_func lookups are now avoided by making a local
- * copy of tv_func. Another approach would be to compute an offset
- * for tv_func from valstack bottom and recomputing the tv_func
- * pointer quickly as valstack + offset instead of calling duk_get_tval().
- */
-
- if (idx_func < 0 || idx_args < 0) {
- /*
- * Since stack indices are not reliable, we can't do anything useful
- * here. Invoke the existing setjmp catcher, or if it doesn't exist,
- * call the fatal error handler.
- */
-
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
-
- /*
- * Setup a setjmp() catchpoint first because even the call setup
- * may fail.
- */
-
- if (!need_setjmp) {
- DUK_DDD(DUK_DDDPRINT("don't need a setjmp catchpoint"));
- goto handle_call;
- }
-
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
+#endif
- if (DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0) {
- DUK_DDD(DUK_DDDPRINT("setjmp catchpoint setup complete"));
- goto handle_call;
- }
-
- /*
- * Error during setup, call, or postprocessing of the call.
- * The error value is in heap->lj.value1.
- *
- * Note: any local variables accessed here must have their value
- * assigned *before* the setjmp() call, OR they must be declared
- * volatile. Otherwise their value is not guaranteed to be correct.
- *
- * The following are such variables:
- * - duk_handle_call() parameters
- * - entry_*
- * - idx_func
- * - idx_args
- *
- * The very first thing we do is restore the previous setjmp catcher.
- * This means that any error in error handling will propagate outwards
- * instead of causing a setjmp() re-entry above. The *only* actual
- * errors that should happen here are allocation errors.
- */
-
- DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_call(): %!T",
- (duk_tval *) &thr->heap->lj.value1));
-
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
- DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
-
- /* We don't need to sync back thr->curr_pc here because the
- * bytecode executor always has a setjmp catchpoint which
- * does that before errors propagate to here.
- */
-
- /*
- * Restore previous setjmp catchpoint
- */
-
- /* Note: either pointer may be NULL (at entry), so don't assert */
- DUK_DDD(DUK_DDDPRINT("restore jmpbuf_ptr: %p -> %p",
- (void *) (thr && thr->heap ? thr->heap->lj.jmpbuf_ptr : NULL),
- (void *) old_jmpbuf_ptr));
-
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- if (!(call_flags & DUK_CALL_FLAG_PROTECTED)) {
- /*
- * Caller did not request a protected call but a setjmp
- * catchpoint was set up to allow cleanup. So, clean up
- * and rethrow.
- *
- * We must restore curr_thread here to ensure that its
- * current value doesn't end up pointing to a thread object
- * which has been freed. This is now a problem because some
- * call sites (namely duk_safe_call()) *first* unwind stacks
- * and only then deal with curr_thread. If those call sites
- * were fixed, this wouldn't matter here.
- *
- * Note: this case happens e.g. when heap->curr_thread is
- * NULL on entry.
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ try {
+#else
+ if (DUK_LIKELY(DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0)) {
+#endif
+ /* Call handling and success path. Success path exit cleans
+ * up almost all state.
*/
+ duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
- DUK_DDD(DUK_DDDPRINT("call is not protected -> clean up and rethrow"));
+ /* Success path handles */
+ DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
+ DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
- /* Restore entry thread executor curr_pc stack frame pointer. */
- thr->ptr_curr_pc = entry_ptr_curr_pc;
+ /* Longjmp state is kept clean in success path */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
- DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
- thr->state = entry_thread_state;
- DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
- (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
- (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+#endif
- /* XXX: should setjmp catcher be responsible for this instead? */
- thr->heap->call_recursion_depth = entry_call_recursion_depth;
- duk_err_longjmp(thr);
- DUK_UNREACHABLE();
- }
+ return DUK_EXEC_SUCCESS;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ } catch (duk_internal_exception &exc) {
+#else
+ } else {
+#endif
+ /* Error; error value is in heap->lj.value1. */
+
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_UNREF(exc);
+#endif
+
+ duk__handle_call_error(thr,
+ entry_valstack_bottom_index,
+ entry_valstack_end,
+ entry_catchstack_top,
+ entry_callstack_top,
+ entry_call_recursion_depth,
+ entry_curr_thread,
+ entry_thread_state,
+ entry_ptr_curr_pc,
+ idx_func
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , old_jmpbuf_ptr
+#endif
+ );
+
+ /* Longjmp state is cleaned up by error handling */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
+ return DUK_EXEC_ERROR;
+ }
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ catch (std::exception &exc) {
+ const char *what = exc.what();
+ if (!what) {
+ what = "unknown";
+ }
+ DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
+ duk__handle_call_error(thr,
+ entry_valstack_bottom_index,
+ entry_valstack_end,
+ entry_catchstack_top,
+ entry_callstack_top,
+ entry_call_recursion_depth,
+ entry_curr_thread,
+ entry_thread_state,
+ entry_ptr_curr_pc,
+ idx_func);
+ return DUK_EXEC_ERROR;
+ }
+ } catch (...) {
+ DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "caught invalid c++ exception (perhaps thrown by user code)");
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
+ duk__handle_call_error(thr,
+ entry_valstack_bottom_index,
+ entry_valstack_end,
+ entry_catchstack_top,
+ entry_callstack_top,
+ entry_call_recursion_depth,
+ entry_curr_thread,
+ entry_thread_state,
+ entry_ptr_curr_pc,
+ idx_func);
+ return DUK_EXEC_ERROR;
+ }
+ }
+#endif
+}
+
+DUK_INTERNAL void duk_handle_call_unprotected(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_small_uint_t call_flags) {
+ duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
+
+ /* Argument validation and func/args offset. */
+ idx_func = duk__get_idx_func(thr, num_stack_args);
+
+ duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
+}
+
+DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_small_uint_t call_flags,
+ duk_idx_t idx_func) {
+ duk_context *ctx;
+ duk_size_t entry_valstack_bottom_index;
+ duk_size_t entry_valstack_end;
+ duk_size_t entry_callstack_top;
+ duk_size_t entry_catchstack_top;
+ duk_int_t entry_call_recursion_depth;
+ duk_hthread *entry_curr_thread;
+ duk_uint_fast8_t entry_thread_state;
+ duk_instr_t **entry_ptr_curr_pc;
+ duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
+ duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
+ duk_hobject *func; /* 'func' on stack (borrowed reference) */
+ duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) or tv_func_copy */
+ duk_tval tv_func_copy; /* to avoid relookups */
+ duk_activation *act;
+ duk_hobject *env;
+ duk_ret_t rc;
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
+ ctx = (duk_context *) thr;
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT(num_stack_args >= 0);
+ /* XXX: currently NULL allocations are not supported; remove if later allowed */
+ DUK_ASSERT(thr->valstack != NULL);
+ DUK_ASSERT(thr->callstack != NULL);
+ DUK_ASSERT(thr->catchstack != NULL);
- /* [ ... func this (crud) errobj ] */
+ DUK_DD(DUK_DDPRINT("duk__handle_call_inner: num_stack_args=%ld, call_flags=0x%08lx, top=%ld",
+ (long) num_stack_args, (long) call_flags, (long) duk_get_top(ctx)));
- /* XXX: is there space? better implementation: write directly over
- * 'func' slot to avoid valstack grow issues.
+ /*
+ * Store entry state.
*/
- duk_push_tval(ctx, &thr->heap->lj.value1);
- /* [ ... func this (crud) errobj ] */
-
- duk_replace(ctx, idx_func);
- duk_set_top(ctx, idx_func + 1);
-
- /* [ ... errobj ] */
+ entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
+#if defined(DUK_USE_PREFER_SIZE)
+ entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
+#else
+ DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
+ entry_valstack_end = thr->valstack_size;
+#endif
+ entry_callstack_top = thr->callstack_top;
+ entry_catchstack_top = thr->catchstack_top;
+ entry_call_recursion_depth = thr->heap->call_recursion_depth;
+ entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
+ entry_thread_state = thr->state;
+ entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
- /* Ensure there is internal valstack spare before we exit; this may
- * throw an alloc error. The same guaranteed size must be available
- * as before the call. This is not optimal now: we store the valstack
- * allocated size during entry; this value may be higher than the
- * minimal guarantee for an application.
+ /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
+ * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
+ * activation when side effects occur.
*/
+ duk_hthread_sync_and_null_currpc(thr);
- (void) duk_valstack_resize_raw((duk_context *) thr,
- entry_valstack_end, /* same as during entry */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- DUK_VSRESIZE_FLAG_COMPACT |
- DUK_VSRESIZE_FLAG_THROW);
+ DUK_DD(DUK_DDPRINT("duk__handle_call_inner: thr=%p, num_stack_args=%ld, "
+ "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
+ "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
+ "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
+ "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
+ (void *) thr,
+ (long) num_stack_args,
+ (unsigned long) call_flags,
+ (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
+ (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
+ (long) duk_get_top(ctx),
+ (long) idx_func,
+ (long) (idx_func + 2),
+ (long) thr->heap->call_recursion_depth,
+ (long) thr->heap->call_recursion_limit,
+ (long) entry_valstack_bottom_index,
+ (long) entry_callstack_top,
+ (long) entry_catchstack_top,
+ (long) entry_call_recursion_depth,
+ (void *) entry_curr_thread,
+ (long) entry_thread_state));
- /* Note: currently a second setjmp restoration is done at the target;
- * this is OK, but could be refactored away.
- */
- retval = DUK_EXEC_ERROR;
- goto shrink_and_finished;
- handle_call:
/*
* Thread state check and book-keeping.
*/
@@ -57748,7 +57965,6 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* state, but not in the same "resume chain".
*/
}
-
DUK_ASSERT(thr->heap->curr_thread == thr);
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
@@ -57758,9 +57974,12 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* possible by recursive handle_call / handle_safe_call calls).
*/
+ /* XXX: remove DUK_CALL_FLAG_IGNORE_RECLIMIT flag: there's now the
+ * reclimit bump?
+ */
+
DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
-
if (call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) {
DUK_DD(DUK_DDPRINT("ignoring reclimit for this call (probably an errhandler call)"));
} else {
@@ -57802,45 +58021,10 @@ duk_int_t duk_handle_call(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
(duk_tval *) duk_get_tval(ctx, idx_func + 1)));
- /* These base values are never used, but if the compiler doesn't know
- * that DUK_ERROR() won't return, these are needed to silence warnings.
- * On the other hand, scan-build will warn about the values not being
- * used, so add a DUK_UNREF.
- */
- nargs = 0; DUK_UNREF(nargs);
- nregs = 0; DUK_UNREF(nregs);
-
- if (func == NULL) {
- duk_small_uint_t lf_flags;
-
- DUK_DDD(DUK_DDDPRINT("lightfunc call handling"));
- DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
- lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func);
- nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
- if (nargs == DUK_LFUNC_NARGS_VARARGS) {
- nargs = -1; /* vararg */
- }
- nregs = nargs;
- } else if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- nargs = ((duk_hcompiledfunction *) func)->nargs;
- nregs = ((duk_hcompiledfunction *) func)->nregs;
- DUK_ASSERT(nregs >= nargs);
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- /* Note: nargs (and nregs) may be negative for a native,
- * function, which indicates that the function wants the
- * input stack "as is" (i.e. handles "vararg" arguments).
- */
- nargs = ((duk_hnativefunction *) func)->nargs;
- nregs = nargs;
- } else {
- /* XXX: this should be an assert */
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_CALLABLE);
- }
-
/* [ ... func this arg1 ... argN ] */
/*
- * Setup a preliminary activation.
+ * Setup a preliminary activation and figure out nargs/nregs.
*
* Don't touch valstack_bottom or valstack_top yet so that Duktape API
* calls work normally.
@@ -57870,41 +58054,77 @@ duk_int_t duk_handle_call(duk_hthread *thr,
DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
act->flags = 0;
- if (func == NULL || DUK_HOBJECT_HAS_STRICT(func)) {
- act->flags |= DUK_ACT_FLAG_STRICT;
- }
+
+ /* For now all calls except Ecma-to-Ecma calls prevent a yield. */
+ act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
if (call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) {
act->flags |= DUK_ACT_FLAG_CONSTRUCT;
- /*act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;*/
- }
- if (func == NULL || DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- /*act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;*/
}
if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
}
- /* As a first approximation, all calls except Ecmascript-to-Ecmascript
- * calls prevent a yield.
+ /* These base values are never used, but if the compiler doesn't know
+ * that DUK_ERROR() won't return, these are needed to silence warnings.
+ * On the other hand, scan-build will warn about the values not being
+ * used, so add a DUK_UNREF.
*/
- act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
+ nargs = 0; DUK_UNREF(nargs);
+ nregs = 0; DUK_UNREF(nregs);
+
+ if (DUK_LIKELY(func != NULL)) {
+ if (DUK_HOBJECT_HAS_STRICT(func)) {
+ act->flags |= DUK_ACT_FLAG_STRICT;
+ }
+ if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
+ nargs = ((duk_hcompiledfunction *) func)->nargs;
+ nregs = ((duk_hcompiledfunction *) func)->nregs;
+ DUK_ASSERT(nregs >= nargs);
+ } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
+ /* Note: nargs (and nregs) may be negative for a native,
+ * function, which indicates that the function wants the
+ * input stack "as is" (i.e. handles "vararg" arguments).
+ */
+ nargs = ((duk_hnativefunction *) func)->nargs;
+ nregs = nargs;
+ } else {
+ /* XXX: this should be an assert */
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_CALLABLE);
+ }
+ } else {
+ duk_small_uint_t lf_flags;
+
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
+ lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func);
+ nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
+ if (nargs == DUK_LFUNC_NARGS_VARARGS) {
+ nargs = -1; /* vararg */
+ }
+ nregs = nargs;
+
+ act->flags |= DUK_ACT_FLAG_STRICT;
+ }
act->func = func; /* NULL for lightfunc */
act->var_env = NULL;
act->lex_env = NULL;
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
act->prev_caller = NULL;
#endif
act->curr_pc = NULL;
#if defined(DUK_USE_DEBUGGER_SUPPORT)
act->prev_line = 0;
#endif
- act->idx_bottom = entry_valstack_bottom_index + idx_args;
+ act->idx_bottom = entry_valstack_bottom_index + idx_func + 2;
#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
act->idx_retval = 0;
#endif
DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */
+ /* XXX: remove the preventcount and make yield walk the callstack?
+ * Or perhaps just use a single flag, not a counter, faster to just
+ * set and restore?
+ */
if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
/* duk_hthread_callstack_unwind() will decrease this on unwind */
thr->callstack_preventcount++;
@@ -57916,14 +58136,14 @@ duk_int_t duk_handle_call(duk_hthread *thr,
*/
DUK_HOBJECT_INCREF_ALLOWNULL(thr, func); /* act->func */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
if (func) {
duk__update_func_caller_prop(thr, func);
}
act = thr->callstack + thr->callstack_top - 1;
#endif
- /* [... func this arg1 ... argN] */
+ /* [ ... func this arg1 ... argN ] */
/*
* Environment record creation and 'arguments' object creation.
@@ -57940,49 +58160,57 @@ duk_int_t duk_handle_call(duk_hthread *thr,
DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
- if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
- /* use existing env (e.g. for non-strict eval); cannot have
- * an own 'arguments' object (but can refer to the existing one)
- */
+ if (DUK_LIKELY(func != NULL)) {
+ if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) {
+ if (DUK_LIKELY(!DUK_HOBJECT_HAS_CREATEARGS(func))) {
+ /* Use a new environment but there's no 'arguments' object;
+ * delayed environment initialization. This is the most
+ * common case.
+ */
+ DUK_ASSERT(act->lex_env == NULL);
+ DUK_ASSERT(act->var_env == NULL);
+ } else {
+ /* Use a new environment and there's an 'arguments' object.
+ * We need to initialize it right now.
+ */
- DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
+ /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
+ env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
+ DUK_ASSERT(env != NULL);
- duk__handle_oldenv_for_call(thr, func, act);
+ /* [ ... func this arg1 ... argN envobj ] */
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
- goto env_done;
- }
+ DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
+ duk__handle_createargs_for_call(thr, func, env, num_stack_args);
- DUK_ASSERT(func == NULL || DUK_HOBJECT_HAS_NEWENV(func));
+ /* [ ... func this arg1 ... argN envobj ] */
- if (func == NULL || !DUK_HOBJECT_HAS_CREATEARGS(func)) {
- /* no need to create environment record now; leave as NULL */
- DUK_ASSERT(act->lex_env == NULL);
- DUK_ASSERT(act->var_env == NULL);
- goto env_done;
- }
-
- /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
- env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
- DUK_ASSERT(env != NULL);
-
- /* [... func this arg1 ... argN envobj] */
+ act = thr->callstack + thr->callstack_top - 1;
+ act->lex_env = env;
+ act->var_env = env;
+ DUK_HOBJECT_INCREF(thr, env);
+ DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */
+ duk_pop(ctx);
+ }
+ } else {
+ /* Use existing env (e.g. for non-strict eval); cannot have
+ * an own 'arguments' object (but can refer to an existing one).
+ */
- DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- duk__handle_createargs_for_call(thr, func, env, num_stack_args);
+ DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
- /* [... func this arg1 ... argN envobj] */
+ duk__handle_oldenv_for_call(thr, func, act);
- act = thr->callstack + thr->callstack_top - 1;
- act->lex_env = env;
- act->var_env = env;
- DUK_HOBJECT_INCREF(thr, env);
- DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */
- duk_pop(ctx);
+ DUK_ASSERT(act->lex_env != NULL);
+ DUK_ASSERT(act->var_env != NULL);
+ }
+ } else {
+ /* Lightfuncs are always native functions and have "newenv". */
+ DUK_ASSERT(act->lex_env == NULL);
+ DUK_ASSERT(act->var_env == NULL);
+ }
- env_done:
- /* [... func this arg1 ... argN] */
+ /* [ ... func this arg1 ... argN ] */
/*
* Setup value stack: clamp to 'nargs', fill up to 'nregs'
@@ -57993,109 +58221,158 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* wants all args (= 'num_stack_args').
*/
+ /* XXX: optimize value stack operation */
+ /* XXX: don't want to shrink allocation here */
+
duk__adjust_valstack_and_top(thr,
num_stack_args,
- idx_args,
+ idx_func + 2,
nregs,
nargs,
func);
/*
- * Determine call type; then setup activation and call
+ * Determine call type, then finalize activation, shift to
+ * new value stack bottom, and call the target.
*/
if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- goto ecmascript_call;
- } else {
- goto native_call;
- }
- DUK_UNREACHABLE();
+ /*
+ * Ecmascript call
+ */
- /*
- * Native (C) call
- */
+ duk_tval *tv_ret;
+ duk_tval *tv_funret;
- native_call:
- /*
- * Shift to new valstack_bottom.
- */
+ DUK_ASSERT(func != NULL);
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
+ act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
- thr->valstack_bottom = thr->valstack_bottom + idx_args;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- DUK_ASSERT(func == NULL || ((duk_hnativefunction *) func)->func != NULL);
+ thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
+ /* keep current valstack_top */
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- /* [... func this | arg1 ... argN] ('this' must precede new bottom) */
+ /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
- /*
- * Actual function call and return value check.
- *
- * Return values:
- * 0 success, no return value (default to 'undefined')
- * 1 success, one return value on top of stack
- * < 0 error, throw a "magic" error
- * other invalid
- */
+ /*
+ * Bytecode executor call.
+ *
+ * Execute bytecode, handling any recursive function calls and
+ * thread resumptions. Returns when execution would return from
+ * the entry level activation. When the executor returns, a
+ * single return value is left on the stack top.
+ *
+ * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
+ * other types are handled internally by the executor.
+ */
- /* For native calls must be NULL so we don't sync back */
- DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ /* thr->ptr_curr_pc is set by bytecode executor early on entry */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
+ duk_js_execute_bytecode(thr);
+ DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
- if (func) {
- rc = ((duk_hnativefunction *) func)->func((duk_context *) thr);
- } else {
- duk_c_function funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
- rc = funcptr((duk_context *) thr);
- }
+ /* Unwind. */
- if (rc < 0) {
- duk_error_throw_from_negative_rc(thr, rc);
- DUK_UNREACHABLE();
- } else if (rc > 1) {
- DUK_ERROR_API(thr, "c function returned invalid rc");
- }
- DUK_ASSERT(rc == 0 || rc == 1);
+ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
+ duk_hthread_catchstack_shrink_check(thr);
+ duk_hthread_callstack_unwind(thr, entry_callstack_top);
+ duk_hthread_callstack_shrink_check(thr);
- /*
- * Unwind stack(s) and shift back to old valstack_bottom.
- */
+ thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
+ /* keep current valstack_top */
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
- DUK_ASSERT(thr->catchstack_top == entry_catchstack_top);
- DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ /* Return value handling. */
-#if 0 /* should be no need to unwind */
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
+ /* [ ... func this (crud) retval ] */
+
+ tv_ret = thr->valstack_bottom + idx_func;
+ tv_funret = thr->valstack_top - 1;
+#if defined(DUK_USE_FASTINT)
+ /* Explicit check for fastint downgrade. */
+ DUK_TVAL_CHKFAST_INPLACE(tv_funret);
#endif
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
+ } else {
+ /*
+ * Native call.
+ */
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- /* keep current valstack_top */
+ duk_tval *tv_ret;
+ duk_tval *tv_funret;
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
+ thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
+ /* keep current valstack_top */
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(func == NULL || ((duk_hnativefunction *) func)->func != NULL);
- /*
- * Manipulate value stack so that return value is on top
- * (pushing an 'undefined' if necessary).
- */
+ /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
- /* XXX: should this happen in the callee's activation or after unwinding? */
- if (rc == 0) {
- duk_require_stack(ctx, 1);
- duk_push_undefined(ctx);
- }
- /* [... func this (crud) retval] */
+ /* For native calls must be NULL so we don't sync back */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
- DUK_DDD(DUK_DDDPRINT("native call retval -> %!T (rc=%ld)",
- (duk_tval *) duk_get_tval(ctx, -1), (long) rc));
+ if (func) {
+ rc = ((duk_hnativefunction *) func)->func((duk_context *) thr);
+ } else {
+ duk_c_function funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
+ rc = funcptr((duk_context *) thr);
+ }
- duk_replace(ctx, idx_func);
- duk_set_top(ctx, idx_func + 1);
+ /* Automatic error throwing, retval check. */
- /* [... retval] */
+ if (rc < 0) {
+ duk_error_throw_from_negative_rc(thr, rc);
+ DUK_UNREACHABLE();
+ } else if (rc > 1) {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "c function returned invalid rc");
+ }
+ DUK_ASSERT(rc == 0 || rc == 1);
+
+ /* Unwind. */
+
+ DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ duk_hthread_callstack_unwind(thr, entry_callstack_top);
+ duk_hthread_callstack_shrink_check(thr);
+
+ thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
+ /* keep current valstack_top */
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
+
+ /* Return value handling. */
+
+ /* XXX: should this happen in the callee's activation or after unwinding? */
+ tv_ret = thr->valstack_bottom + idx_func;
+ if (rc == 0) {
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv_ret); /* side effects */
+ } else {
+ /* [ ... func this (crud) retval ] */
+ tv_funret = thr->valstack_top - 1;
+#if defined(DUK_USE_FASTINT)
+ /* Explicit check for fastint downgrade. */
+ DUK_TVAL_CHKFAST_INPLACE(tv_funret);
+#endif
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
+ }
+ }
+
+ duk_set_top(ctx, idx_func + 1); /* XXX: unnecessary, handle in adjust */
+
+ /* [ ... retval ] */
/* Ensure there is internal valstack spare before we exit; this may
* throw an alloc error. The same guaranteed size must be available
@@ -58104,88 +58381,123 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* minimal guarantee for an application.
*/
+ /* XXX: we should never shrink here; when we error out later, we'd
+ * need to potentially grow the value stack in error unwind which could
+ * cause another error.
+ */
+
(void) duk_valstack_resize_raw((duk_context *) thr,
entry_valstack_end, /* same as during entry */
DUK_VSRESIZE_FLAG_SHRINK | /* flags */
DUK_VSRESIZE_FLAG_COMPACT |
DUK_VSRESIZE_FLAG_THROW);
+ /* Restore entry thread executor curr_pc stack frame pointer. */
+ thr->ptr_curr_pc = entry_ptr_curr_pc;
- /*
- * Shrink checks and return with success.
- */
+ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
+ thr->state = (duk_uint8_t) entry_thread_state;
+
+ DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
+ (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
+ (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
- retval = DUK_EXEC_SUCCESS;
- goto shrink_and_finished;
+ thr->heap->call_recursion_depth = entry_call_recursion_depth;
- /*
- * Ecmascript call
+ /* If the debugger is active we need to force an interrupt so that
+ * debugger breakpoints are rechecked. This is important for function
+ * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
+ * GH-303. Only needed for success path, error path always causes a
+ * breakpoint recheck in the executor. It would be enough to set this
+ * only when returning to an Ecmascript activation, but setting the flag
+ * on every return should have no ill effect.
*/
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
+ DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
+ DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
+ thr->interrupt_init -= thr->interrupt_counter;
+ thr->interrupt_counter = 0;
+ thr->heap->dbg_force_restart = 1;
+ }
+#endif
- ecmascript_call:
+#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
+ duk__interrupt_fixup(thr, entry_curr_thread);
+#endif
- /*
- * Shift to new valstack_bottom.
- */
+ return;
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
- act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
+ thread_state_error:
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%ld)", (long) thr->state);
+ DUK_UNREACHABLE();
+ return; /* never executed */
+}
+
+DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_valstack_end,
+ duk_size_t entry_catchstack_top,
+ duk_size_t entry_callstack_top,
+ duk_int_t entry_call_recursion_depth,
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
+ duk_instr_t **entry_ptr_curr_pc,
+ duk_idx_t idx_func
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ ) {
+ duk_context *ctx;
+ duk_tval *tv_ret;
- thr->valstack_bottom = thr->valstack_bottom + idx_args;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ ctx = (duk_context *) thr;
- /* [... func this | arg1 ... argN] ('this' must precede new bottom) */
+ DUK_DDD(DUK_DDDPRINT("error caught during duk__handle_call_inner(): %!T",
+ (duk_tval *) &thr->heap->lj.value1));
- /*
- * Bytecode executor call.
- *
- * Execute bytecode, handling any recursive function calls and
- * thread resumptions. Returns when execution would return from
- * the entry level activation. When the executor returns, a
- * single return value is left on the stack top.
- *
- * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
- * other types are handled internally by the executor.
- *
+ /* Other longjmp types are handled by executor before propagating
+ * the error here.
*/
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
+ DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
+ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
- /* thr->ptr_curr_pc is set by bytecode executor early on entry */
+ /* We don't need to sync back thr->ptr_curr_pc here because
+ * the bytecode executor always has a setjmp catchpoint which
+ * does that before errors propagate to here.
+ */
DUK_ASSERT(thr->ptr_curr_pc == NULL);
- DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
- duk_js_execute_bytecode(thr);
- DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
- /*
- * Unwind stack(s) and shift back to old valstack_bottom.
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* Restore the previous setjmp catcher so that any error in
+ * error handling will propagate outwards rather than re-enter
+ * the same handler. However, the error handling path must be
+ * designed to be error free so that sandboxing guarantees are
+ * reliable, see e.g. https://github.com/svaarala/duktape/issues/476.
*/
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+#endif
- DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
-
+ /* XXX: callstack unwind may now throw an error when closing
+ * scopes; this is a sandboxing issue, described in:
+ * https://github.com/svaarala/duktape/issues/476
+ */
duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
+ duk_hthread_catchstack_shrink_check(thr);
duk_hthread_callstack_unwind(thr, entry_callstack_top);
+ duk_hthread_callstack_shrink_check(thr);
thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- /* keep current valstack_top */
-
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
-
- /*
- * Manipulate value stack so that return value is on top.
- */
-
- /* [... func this (crud) retval] */
-
- duk_replace(ctx, idx_func);
- duk_set_top(ctx, idx_func + 1);
+ tv_ret = thr->valstack_bottom + idx_func; /* XXX: byte offset? */
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, &thr->heap->lj.value1); /* side effects */
+#if defined(DUK_USE_FASTINT)
+ /* Explicit check for fastint downgrade. */
+ DUK_TVAL_CHKFAST_INPLACE(tv_ret);
+#endif
+ duk_set_top(ctx, idx_func + 1); /* XXX: could be eliminated with valstack adjust */
- /* [... retval] */
+ /* [ ... errobj ] */
/* Ensure there is internal valstack spare before we exit; this may
* throw an alloc error. The same guaranteed size must be available
@@ -58194,60 +58506,29 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* minimal guarantee for an application.
*/
+ /* XXX: this needs to be reworked so that we never shrink the value
+ * stack on function entry so that we never need to grow it here.
+ * Needing to grow here is a sandboxing issue because we need to
+ * allocate which may cause an error in the error handling path
+ * and thus propagate an error out of a protected call.
+ */
+
(void) duk_valstack_resize_raw((duk_context *) thr,
entry_valstack_end, /* same as during entry */
DUK_VSRESIZE_FLAG_SHRINK | /* flags */
DUK_VSRESIZE_FLAG_COMPACT |
DUK_VSRESIZE_FLAG_THROW);
- /*
- * Shrink checks and return with success.
- */
-
- retval = DUK_EXEC_SUCCESS;
- goto shrink_and_finished;
-
- shrink_and_finished:
-#if defined(DUK_USE_FASTINT)
- /* Explicit check for fastint downgrade. */
- {
- duk_tval *tv_fi;
- tv_fi = duk_get_tval(ctx, -1);
- DUK_ASSERT(tv_fi != NULL);
- DUK_TVAL_CHKFAST_INPLACE(tv_fi);
- }
-#endif
-
- /* these are "soft" shrink checks, whose failures are ignored */
- /* XXX: would be nice if fast path was inlined */
- duk_hthread_catchstack_shrink_check(thr);
- duk_hthread_callstack_shrink_check(thr);
- goto finished;
-
- finished:
- if (need_setjmp) {
- /* Note: either pointer may be NULL (at entry), so don't assert;
- * this is now done potentially twice, which is OK
- */
- DUK_DDD(DUK_DDDPRINT("restore jmpbuf_ptr: %p -> %p (possibly already done)",
- (void *) (thr && thr->heap ? thr->heap->lj.jmpbuf_ptr : NULL),
- (void *) old_jmpbuf_ptr));
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
- /* These are just convenience "wiping" of state */
- thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
- thr->heap->lj.iserror = 0;
-
- /* Side effects should not be an issue here: tv_tmp is local and
- * thr->heap (and thr->heap->lj) have a stable pointer. Finalizer
- * runs etc capture even out-of-memory errors so nothing should
- * throw here.
- */
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
-
- DUK_DDD(DUK_DDDPRINT("setjmp catchpoint torn down"));
- }
+ /* These are just convenience "wiping" of state. Side effects should
+ * not be an issue here: thr->heap and thr->heap->lj have a stable
+ * pointer. Finalizer runs etc capture even out-of-memory errors so
+ * nothing should throw here.
+ */
+ thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
+ thr->heap->lj.iserror = 0;
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
/* Restore entry thread executor curr_pc stack frame pointer. */
thr->ptr_curr_pc = entry_ptr_curr_pc;
@@ -58271,7 +58552,7 @@ duk_int_t duk_handle_call(duk_hthread *thr,
*/
#if defined(DUK_USE_DEBUGGER_SUPPORT)
if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- DUK_DD(DUK_DDPRINT("returning to ecmascript activation with debugger enabled, force interrupt"));
+ DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
thr->interrupt_init -= thr->interrupt_counter;
thr->interrupt_counter = 0;
@@ -58282,119 +58563,25 @@ duk_int_t duk_handle_call(duk_hthread *thr,
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
duk__interrupt_fixup(thr, entry_curr_thread);
#endif
-
- return retval;
-
- thread_state_error:
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%ld)", (long) thr->state);
- DUK_UNREACHABLE();
- return DUK_EXEC_ERROR; /* never executed */
-}
-
-/*
- * Manipulate value stack so that exactly 'num_stack_rets' return
- * values are at 'idx_retbase' in every case, assuming there are
- * 'rc' return values on top of stack.
- *
- * This is a bit tricky, because the called C function operates in
- * the same activation record and may have e.g. popped the stack
- * empty (below idx_retbase).
- */
-
-DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_retbase, duk_idx_t num_stack_rets, duk_idx_t num_actual_rets) {
- duk_context *ctx = (duk_context *) thr;
- duk_idx_t idx_rcbase;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(idx_retbase >= 0);
- DUK_ASSERT(num_stack_rets >= 0);
- DUK_ASSERT(num_actual_rets >= 0);
-
- idx_rcbase = duk_get_top(ctx) - num_actual_rets; /* base of known return values */
-
- DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
- "num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld",
- (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(ctx),
- (long) idx_retbase, (long) idx_rcbase));
-
- DUK_ASSERT(idx_rcbase >= 0); /* caller must check */
-
- /* ensure space for final configuration (idx_retbase + num_stack_rets) and
- * intermediate configurations
- */
- duk_require_stack_top(ctx,
- (idx_rcbase > idx_retbase ? idx_rcbase : idx_retbase) +
- num_stack_rets);
-
- /* chop extra retvals away / extend with undefined */
- duk_set_top(ctx, idx_rcbase + num_stack_rets);
-
- if (idx_rcbase >= idx_retbase) {
- duk_idx_t count = idx_rcbase - idx_retbase;
- duk_idx_t i;
-
- DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
- "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
-
- /* nuke values at idx_retbase to get the first retval (initially
- * at idx_rcbase) to idx_retbase
- */
-
- DUK_ASSERT(count >= 0);
-
- for (i = 0; i < count; i++) {
- /* XXX: inefficient; block remove primitive */
- duk_remove(ctx, idx_retbase);
- }
- } else {
- duk_idx_t count = idx_retbase - idx_rcbase;
- duk_idx_t i;
-
- DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
- "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
-
- /* insert 'undefined' values at idx_rcbase to get the
- * return values to idx_retbase
- */
-
- DUK_ASSERT(count > 0);
-
- for (i = 0; i < count; i++) {
- /* XXX: inefficient; block insert primitive */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_rcbase);
- }
- }
}
/*
- * Make a "C protected call" within the current activation.
+ * duk_handle_safe_call(): make a "C protected call" within the
+ * current activation.
*
* The allowed thread states for making a call are the same as for
- * duk_handle_call().
- *
- * Note that like duk_handle_call(), even if this call is protected,
- * there are a few situations where the current (pre-entry) setjmp
- * catcher (or a fatal error handler if no such catcher exists) is
- * invoked:
- *
- * - Blatant API argument errors (e.g. num_stack_args is invalid,
- * so we can't form a reasonable return stack)
+ * duk_handle_call_xxx().
*
- * - Errors during error handling, e.g. failure to reallocate
- * space in the value stack due to an alloc error
- *
- * Such errors propagate outwards, ultimately to the fatal error
- * handler if nothing else.
+ * Error handling is similar to duk_handle_call_xxx(); errors may be thrown
+ * (and result in a fatal error) for insane arguments.
*/
/* XXX: bump preventcount by one for the duration of this call? */
-DUK_INTERNAL
-duk_int_t duk_handle_safe_call(duk_hthread *thr,
- duk_safe_call_function func,
- duk_idx_t num_stack_args,
- duk_idx_t num_stack_rets) {
+DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
+ duk_safe_call_function func,
+ duk_idx_t num_stack_args,
+ duk_idx_t num_stack_rets) {
duk_context *ctx = (duk_context *) thr;
duk_size_t entry_valstack_bottom_index;
duk_size_t entry_callstack_top;
@@ -58403,11 +58590,12 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
duk_hthread *entry_curr_thread;
duk_uint_fast8_t entry_thread_state;
duk_instr_t **entry_ptr_curr_pc;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
duk_jmpbuf *old_jmpbuf_ptr = NULL;
duk_jmpbuf our_jmpbuf;
+#endif
duk_idx_t idx_retbase;
duk_int_t retval;
- duk_ret_t rc;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(ctx != NULL);
@@ -58442,10 +58630,9 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
(long) entry_thread_state));
if (idx_retbase < 0) {
- /*
- * Since stack indices are not reliable, we can't do anything useful
- * here. Invoke the existing setjmp catcher, or if it doesn't exist,
- * call the fatal error handler.
+ /* Since stack indices are not reliable, we can't do anything useful
+ * here. Invoke the existing setjmp catcher, or if it doesn't exist,
+ * call the fatal error handler.
*/
DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
@@ -58453,74 +58640,136 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
/* setjmp catchpoint setup */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
+#endif
- if (DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0) {
- goto handle_call;
- }
-
- /*
- * Error during call. The error value is at heap->lj.value1.
- *
- * Careful with variable accesses here; must be assigned to before
- * setjmp() or be declared volatile. See duk_handle_call().
- *
- * The following are such variables:
- * - duk_handle_safe_call() parameters
- * - entry_*
- * - idx_retbase
- *
- * The very first thing we do is restore the previous setjmp catcher.
- * This means that any error in error handling will propagate outwards
- * instead of causing a setjmp() re-entry above. The *only* actual
- * errors that should happen here are allocation errors.
- */
-
- DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()"));
-
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
- DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
-
- /* Note: either pointer may be NULL (at entry), so don't assert;
- * these are now restored twice which is OK.
- */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
-
- /* [ ... | (crud) ] */
-
- /* XXX: space in valstack? see discussion in duk_handle_call. */
- duk_push_tval(ctx, &thr->heap->lj.value1);
-
- /* [ ... | (crud) errobj ] */
-
- DUK_ASSERT(duk_get_top(ctx) >= 1); /* at least errobj must be on stack */
-
- /* check that the valstack has space for the final amount and any
- * intermediate space needed; this is unoptimal but should be safe
- */
- duk_require_stack_top(ctx, idx_retbase + num_stack_rets); /* final configuration */
- duk_require_stack(ctx, num_stack_rets);
-
- duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */
-
- /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ try {
+#else
+ if (DUK_LIKELY(DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0)) {
+ /* Success path. */
+#endif
+ DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
+
+ duk__handle_safe_call_inner(thr,
+ func,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top);
+
+ /* Longjmp state is kept clean in success path */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* Note: either pointer may be NULL (at entry), so don't assert */
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+#endif
- retval = DUK_EXEC_ERROR;
- goto shrink_and_finished;
+ retval = DUK_EXEC_SUCCESS;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ } catch (duk_internal_exception &exc) {
+#else
+ } else {
+ /* Error path. */
+#endif
+
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_UNREF(exc);
+#endif
+
+ duk__handle_safe_call_error(thr,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , old_jmpbuf_ptr
+#endif
+ );
+
+ /* Longjmp state is cleaned up by error handling */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
+
+ retval = DUK_EXEC_ERROR;
+ }
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ catch (std::exception &exc) {
+ const char *what = exc.what();
+ if (!what) {
+ what = "unknown";
+ }
+ DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
+ duk__handle_safe_call_error(thr,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top);
+ retval = DUK_EXEC_ERROR;
+ }
+ } catch (...) {
+ DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "caught invalid c++ exception (perhaps thrown by user code)");
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
+ duk__handle_safe_call_error(thr,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top);
+ retval = DUK_EXEC_ERROR;
+ }
+ }
+#endif
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
+#endif
+
+ duk__handle_safe_call_shared(thr,
+ idx_retbase,
+ num_stack_rets,
+ entry_call_recursion_depth,
+ entry_curr_thread,
+ entry_thread_state,
+ entry_ptr_curr_pc);
- /*
- * Handle call (inside setjmp)
- */
+ return retval;
+}
- handle_call:
+DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
+ duk_safe_call_function func,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_callstack_top,
+ duk_size_t entry_catchstack_top) {
+ duk_context *ctx;
+ duk_ret_t rc;
- DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
+ DUK_ASSERT(thr != NULL);
+ ctx = (duk_context *) thr;
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_UNREF(entry_valstack_bottom_index);
+ DUK_UNREF(entry_callstack_top);
+ DUK_UNREF(entry_catchstack_top);
/*
* Thread state check and book-keeping.
@@ -58583,7 +58832,7 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc));
/*
- * Valstack manipulation for results
+ * Valstack manipulation for results.
*/
/* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
@@ -58603,36 +58852,108 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
DUK_ERROR_API(thr, "not enough stack values for safe_call rc");
}
+ DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top);
+
duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc);
+ return;
- /* Note: no need from callstack / catchstack shrink check */
- retval = DUK_EXEC_SUCCESS;
- goto finished;
+ thread_state_error:
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%ld)", (long) thr->state);
+ DUK_UNREACHABLE();
+}
+
+DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_callstack_top,
+ duk_size_t entry_catchstack_top
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ ) {
+ duk_context *ctx;
- shrink_and_finished:
- /* these are "soft" shrink checks, whose failures are ignored */
- /* XXX: would be nice if fast path was inlined */
+ DUK_ASSERT(thr != NULL);
+ ctx = (duk_context *) thr;
+ DUK_ASSERT_CTX_VALID(ctx);
+
+ /*
+ * Error during call. The error value is at heap->lj.value1.
+ *
+ * The very first thing we do is restore the previous setjmp catcher.
+ * This means that any error in error handling will propagate outwards
+ * instead of causing a setjmp() re-entry above.
+ */
+
+ DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()"));
+
+ /* Other longjmp types are handled by executor before propagating
+ * the error here.
+ */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
+ DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
+ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
+
+ /* Note: either pointer may be NULL (at entry), so don't assert. */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+#endif
+
+ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
+ DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
+ duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
duk_hthread_catchstack_shrink_check(thr);
+ duk_hthread_callstack_unwind(thr, entry_callstack_top);
duk_hthread_callstack_shrink_check(thr);
- goto finished;
+ thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- finished:
- /* Note: either pointer may be NULL (at entry), so don't assert */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+ /* [ ... | (crud) ] */
- /* These are just convenience "wiping" of state */
- thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
- thr->heap->lj.iserror = 0;
+ /* XXX: space in valstack? see discussion in duk_handle_call_xxx(). */
+ duk_push_tval(ctx, &thr->heap->lj.value1);
+
+ /* [ ... | (crud) errobj ] */
+
+ DUK_ASSERT(duk_get_top(ctx) >= 1); /* at least errobj must be on stack */
+
+ /* check that the valstack has space for the final amount and any
+ * intermediate space needed; this is unoptimal but should be safe
+ */
+ duk_require_stack_top(ctx, idx_retbase + num_stack_rets); /* final configuration */
+ duk_require_stack(ctx, num_stack_rets);
- /* Side effects should not be an issue here: tv_tmp is local and
- * thr->heap (and thr->heap->lj) have a stable pointer. Finalizer
- * runs etc capture even out-of-memory errors so nothing should
- * throw here.
+ duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */
+
+ /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
+
+ /* These are just convenience "wiping" of state. Side effects should
+ * not be an issue here: thr->heap and thr->heap->lj have a stable
+ * pointer. Finalizer runs etc capture even out-of-memory errors so
+ * nothing should throw here.
*/
+ thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
+ thr->heap->lj.iserror = 0;
DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
+}
- DUK_DDD(DUK_DDDPRINT("setjmp catchpoint torn down"));
+DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_int_t entry_call_recursion_depth,
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
+ duk_instr_t **entry_ptr_curr_pc) {
+ duk_context *ctx;
+
+ DUK_ASSERT(thr != NULL);
+ ctx = (duk_context *) thr;
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_UNREF(ctx);
+ DUK_UNREF(idx_retbase);
+ DUK_UNREF(num_stack_rets);
/* Restore entry thread executor curr_pc stack frame pointer. */
thr->ptr_curr_pc = entry_ptr_curr_pc;
@@ -58662,13 +58983,6 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
duk__interrupt_fixup(thr, entry_curr_thread);
#endif
-
- return retval;
-
- thread_state_error:
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%ld)", (long) thr->state);
- DUK_UNREACHABLE();
- return DUK_EXEC_ERROR; /* never executed */
}
/*
@@ -58697,10 +59011,9 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
* return an error so caller can fall back to a normal call path.
*/
-DUK_INTERNAL
-duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags) {
+DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_small_uint_t call_flags) {
duk_context *ctx = (duk_context *) thr;
duk_size_t entry_valstack_bottom_index;
duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
@@ -58740,7 +59053,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
* - an Ecmascript activation must be on top of the callstack
* - there cannot be any active catchstack entries
*/
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
if (call_flags & DUK_CALL_FLAG_IS_TAILCALL) {
duk_size_t our_callstack_index;
duk_size_t i;
@@ -58766,6 +59079,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
#endif /* DUK_USE_ASSERTIONS */
entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
+ /* XXX: rework */
idx_func = duk_normalize_index(thr, -num_stack_args - 2);
idx_args = idx_func + 2;
@@ -58781,7 +59095,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
(long) idx_args,
(long) entry_valstack_bottom_index));
- if (idx_func < 0 || idx_args < 0) {
+ if (DUK_UNLIKELY(idx_func < 0 || idx_args < 0)) {
/* XXX: assert? compiler is responsible for this never happening */
DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
}
@@ -58916,7 +59230,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
/* Start filling in the activation */
act->func = func; /* don't want an intermediate exposed state with func == NULL */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
act->prev_caller = NULL;
#endif
DUK_ASSERT(func != NULL);
@@ -58927,13 +59241,13 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
act->prev_line = 0;
#endif
DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_HOBJECT_INCREF(thr, func);
act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */
#endif
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#ifdef DUK_USE_TAILCALL
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
+#if defined(DUK_USE_TAILCALL)
#error incorrect options: tail calls enabled with function caller property
#endif
/* XXX: this doesn't actually work properly for tail calls, so
@@ -59019,7 +59333,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
act->func = func;
act->var_env = NULL;
act->lex_env = NULL;
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
act->prev_caller = NULL;
#endif
DUK_ASSERT(func != NULL);
@@ -59037,14 +59351,14 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
DUK_HOBJECT_INCREF(thr, func); /* act->func */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
duk__update_func_caller_prop(thr, func);
act = thr->callstack + thr->callstack_top - 1;
#endif
}
- /* [... func this arg1 ... argN] (not tail call)
- * [this | arg1 ... argN] (tail call)
+ /* [ ... func this arg1 ... argN ] (not tail call)
+ * [ this | arg1 ... argN ] (tail call)
*
* idx_args updated to match
*/
@@ -59058,6 +59372,8 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
* Delayed creation (on demand) is handled in duk_js_var.c.
*/
+ /* XXX: unify handling with native call. */
+
DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
if (!DUK_HOBJECT_HAS_NEWENV(func)) {
@@ -59085,7 +59401,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
DUK_ASSERT(env != NULL);
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
/* original input stack before nargs/nregs handling must be
* intact for 'arguments' object
@@ -59093,7 +59409,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
duk__handle_createargs_for_call(thr, func, env, num_stack_args);
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
act = thr->callstack + thr->callstack_top - 1;
act->lex_env = env;
@@ -59103,7 +59419,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
duk_pop(ctx);
env_done:
- /* [... arg1 ... argN] */
+ /* [ ... arg1 ... argN ] */
/*
* Setup value stack: clamp to 'nargs', fill up to 'nregs'
@@ -60056,8 +60372,8 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
*/
DUK_ASSERT(func->temp_max >= 0);
- h_res->nregs = func->temp_max;
- h_res->nargs = duk_hobject_get_length(thr, func->h_argnames);
+ h_res->nregs = (duk_uint16_t) func->temp_max;
+ h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames);
DUK_ASSERT(h_res->nregs >= h_res->nargs); /* pass2 allocation handles this */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
h_res->start_line = (duk_uint32_t) func->min_line;
@@ -67407,7 +67723,7 @@ DUK_LOCAL void duk__vm_arith_unary_op(duk_hthread *thr, duk_tval *tv_x, duk_idx_
#endif
}
-DUK_LOCAL void duk__vm_bitwise_not(duk_hthread *thr, duk_tval *tv_x, duk_small_uint_fast_t idx_z) {
+DUK_LOCAL void duk__vm_bitwise_not(duk_hthread *thr, duk_tval *tv_x, duk_uint_fast_t idx_z) {
/*
* E5 Section 11.4.8
*/
@@ -68311,6 +68627,9 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
* Return value is already on the stack top: [ ... retval ].
*/
+ /* XXX: could unwind catchstack here, so that call handling
+ * didn't need to do that?
+ */
DUK_DDD(DUK_DDDPRINT("-> return propagated up to entry level, exit bytecode executor"));
return DUK__RETHAND_FINISHED;
}
@@ -68895,16 +69214,66 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
thr->ptr_curr_pc = NULL; \
} while (0)
+DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
+ duk_hthread *entry_thread,
+ duk_size_t entry_callstack_top,
+ duk_int_t entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *entry_jmpbuf_ptr
+#endif
+ ) {
+ duk_small_uint_t lj_ret;
+
+ /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc
+ * before longjmp.
+ */
+ DUK_ASSERT(heap->curr_thread != NULL);
+ DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL);
+
+ /* XXX: signalling the need to shrink check (only if unwound) */
+
+ /* Must be restored here to handle e.g. yields properly. */
+ heap->call_recursion_depth = entry_call_recursion_depth;
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* Switch to caller's setjmp() catcher so that if an error occurs
+ * during error handling, it is always propagated outwards instead
+ * of causing an infinite loop in our own handler.
+ */
+ heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
+#endif
+
+ lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top);
+
+ if (lj_ret == DUK__LONGJMP_RESTART) {
+ /* Restart bytecode execution, possibly with a changed thread. */
+ ;
+ } else {
+ /* Rethrow error to calling state. */
+ DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW);
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* Longjmp handling has restored jmpbuf_ptr. */
+ DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
+#endif
+
+ /* Thread may have changed, e.g. YIELD converted to THROW. */
+ duk_err_longjmp(heap->curr_thread);
+ DUK_UNREACHABLE();
+ }
+}
+
/* Outer executor with setjmp/longjmp handling. */
DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
/* Entry level info. */
duk_hthread *entry_thread;
duk_size_t entry_callstack_top;
duk_int_t entry_call_recursion_depth;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
duk_jmpbuf *entry_jmpbuf_ptr;
-
- duk_heap *heap;
duk_jmpbuf jmpbuf;
+#endif
+ duk_heap *heap;
DUK_ASSERT(exec_thr != NULL);
DUK_ASSERT(exec_thr->heap != NULL);
@@ -68918,7 +69287,9 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
heap = entry_thread->heap;
entry_callstack_top = entry_thread->callstack_top;
entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
+#endif
/*
* Note: we currently assume that the setjmp() catchpoint is
@@ -68930,55 +69301,83 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
*/
for (;;) {
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
heap->lj.jmpbuf_ptr = &jmpbuf;
DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL);
+#endif
- if (DUK_SETJMP(heap->lj.jmpbuf_ptr->jb) != 0) {
- duk_small_uint_t lj_ret;
-
- DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
-
- /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc
- * before longjmp.
- */
- DUK_ASSERT(heap->curr_thread != NULL);
- DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL);
-
- /* XXX: signalling the need to shrink check (only if unwound) */
-
- /* Must be restored here to handle e.g. yields properly. */
- heap->call_recursion_depth = entry_call_recursion_depth;
-
- /* Switch to caller's setjmp() catcher so that if an error occurs
- * during error handling, it is always propagated outwards instead
- * of causing an infinite loop in our own handler.
- */
- heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
-
- lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top);
-
- if (lj_ret == DUK__LONGJMP_RESTART) {
- /* Restart bytecode execution, possibly with a changed thread. */
- ;
- } else {
- /* Rethrow error to calling state. */
- DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW);
-
- /* Longjmp handling has restored jmpbuf_ptr. */
- DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
-
- /* Thread may have changed, e.g. YIELD converted to THROW. */
- duk_err_longjmp(heap->curr_thread);
- DUK_UNREACHABLE();
- }
- } else {
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ try {
+#else
+ if (DUK_LIKELY(DUK_SETJMP(heap->lj.jmpbuf_ptr->jb) == 0)) {
+#endif
/* Execute bytecode until returned or longjmp(). */
duk__js_execute_bytecode_inner(entry_thread, entry_callstack_top);
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
/* Successful return: restore jmpbuf and return to caller. */
heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
+#endif
+
return;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ } catch (duk_internal_exception &exc) {
+#else
+ } else {
+#endif
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_UNREF(exc);
+#endif
+ DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
+
+ duk__handle_executor_error(heap,
+ entry_thread,
+ entry_callstack_top,
+ entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , entry_jmpbuf_ptr
+#endif
+ );
+ }
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ catch (std::exception &exc) {
+ const char *what = exc.what();
+ if (!what) {
+ what = "unknown";
+ }
+ DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
+ try {
+ DUK_ASSERT(heap->curr_thread != NULL);
+ DUK_ERROR(heap->curr_thread, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
+ duk__handle_executor_error(heap,
+ entry_thread,
+ entry_callstack_top,
+ entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , entry_jmpbuf_ptr
+#endif
+ );
+ }
+ } catch (...) {
+ DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ try {
+ DUK_ASSERT(heap->curr_thread != NULL);
+ DUK_ERROR(heap->curr_thread, DUK_ERR_API_ERROR, "caught invalid c++ exception (perhaps thrown by user code)");
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
+ duk__handle_executor_error(heap,
+ entry_thread,
+ entry_callstack_top,
+ entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , entry_jmpbuf_ptr
+#endif
+ );
+ }
}
+#endif
}
DUK_UNREACHABLE();
@@ -70238,9 +70637,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
*/
DUK_ASSERT(DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func) != duk_bi_global_object_eval);
- duk_handle_call(thr,
- num_stack_args,
- call_flags);
+ duk_handle_call_unprotected(thr,
+ num_stack_args,
+ call_flags);
/* duk_js_call.c is required to restore the stack reserve
* so we only need to reset the top.
@@ -70284,9 +70683,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
}
}
- duk_handle_call(thr,
- num_stack_args,
- call_flags);
+ duk_handle_call_unprotected(thr,
+ num_stack_args,
+ call_flags);
/* duk_js_call.c is required to restore the stack reserve
* so we only need to reset the top.
@@ -71136,7 +71535,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type);
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
+#endif
duk_err_longjmp(thr);
DUK_UNREACHABLE();
}
@@ -71173,7 +71574,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
+#endif
duk_err_longjmp(thr);
DUK_UNREACHABLE();
break;
@@ -74846,7 +75249,7 @@ DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t s
lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
lex_ctx->input_line = input_line;
- DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "char decode failed");
+ DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "utf8 decode failed");
}
DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
@@ -75006,7 +75409,7 @@ DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) {
error_clipped: /* clipped codepoint */
error_encoding: /* invalid codepoint encoding or codepoint */
- DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "char decode failed");
+ DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "utf8 decode failed");
return 0;
}
@@ -77784,7 +78187,7 @@ DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify
DUK_DDD(DUK_DDDPRINT("digit before carry: %ld", (long) t));
if (++t < nc_ctx->B) {
DUK_DDD(DUK_DDDPRINT("rounding carry terminated"));
- *p = t;
+ *p = (duk_uint8_t) t;
break;
}
@@ -87717,4 +88120,3 @@ DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
return t;
}
-#endif
diff --git a/javascript/duktape/duktape.h b/javascript/duktape/duktape.h
index d672ede..7f7a7c3 100644
--- a/javascript/duktape/duktape.h
+++ b/javascript/duktape/duktape.h
@@ -1,12 +1,12 @@
/*
- * Duktape public API for Duktape 1.3.99.
+ * Duktape public API for Duktape 1.4.0.
* See the API reference for documentation on call semantics.
* The exposed API is inside the DUK_API_PUBLIC_H_INCLUDED
* include guard. Other parts of the header are Duktape
* internal and related to platform/compiler/feature detection.
*
- * Git commit b7b1c5fd2d1d4550140d57e05a7b32f540082bfa (v1.3.0-383-gb7b1c5f).
- * Git branch duk-config-improvements.
+ * Git commit cad6f595382a0cc1a7e4207794ade5be11b3e397 (v1.4.0).
+ * Git branch master.
*
* See Duktape AUTHORS.rst and LICENSE.txt for copyright and
* licensing information.
@@ -20,7 +20,7 @@
*
* (http://opensource.org/licenses/MIT)
*
- * Copyright (c) 2013-2015 by Duktape authors (see AUTHORS.rst)
+ * Copyright (c) 2013-2016 by Duktape authors (see AUTHORS.rst)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -71,6 +71,7 @@
* * Legimet <legimet.calc(a)gmail.com>
* * Karl Skomski <karl(a)skomski.com>
* * Bruce Pascoe <fatcerberus1(a)gmail.com>
+ * * Ren\u00e9 Hollander <rene(a)rene8888.at>
*
* Other contributions
* ===================
@@ -107,6 +108,7 @@
* * https://github.com/sstruchtrup
* * Michael Drake (https://github.com/tlsa)
* * https://github.com/chris-y
+ * * Laurent Zubiaur (https://github.com/lzubiaur)
*
* If you are accidentally missing from this list, send me an e-mail
* (``sami.vaarala(a)iki.fi``) and I'll fix the omission.
@@ -211,16 +213,16 @@ struct duk_number_list_entry {
* have 99 for patch level (e.g. 0.10.99 would be a development version
* after 0.10.0 but before the next official release).
*/
-#define DUK_VERSION 10399L
+#define DUK_VERSION 10400L
/* Git commit, describe, and branch for Duktape build. Useful for
* non-official snapshot builds so that application code can easily log
* which Duktape snapshot was used. Not available in the Ecmascript
* environment.
*/
-#define DUK_GIT_COMMIT "b7b1c5fd2d1d4550140d57e05a7b32f540082bfa"
-#define DUK_GIT_DESCRIBE "v1.3.0-383-gb7b1c5f"
-#define DUK_GIT_BRANCH "duk-config-improvements"
+#define DUK_GIT_COMMIT "cad6f595382a0cc1a7e4207794ade5be11b3e397"
+#define DUK_GIT_DESCRIBE "v1.4.0"
+#define DUK_GIT_BRANCH "master"
/* Duktape debug protocol version used by this build. */
#define DUK_DEBUG_PROTOCOL_VERSION 1
@@ -556,7 +558,7 @@ DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_e
DUK_EXTERNAL_DECL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags);
#define duk_push_buffer(ctx,size,dynamic) \
- duk_push_buffer_raw((ctx), (size), (dynamic) ? DUK_BUF_FLAG_DYNAMIC : 0);
+ duk_push_buffer_raw((ctx), (size), (dynamic) ? DUK_BUF_FLAG_DYNAMIC : 0)
#define duk_push_fixed_buffer(ctx,size) \
duk_push_buffer_raw((ctx), (size), 0 /*flags*/)
#define duk_push_dynamic_buffer(ctx,size) \
-----------------------------------------------------------------------
Summary of changes:
javascript/duktape/duk_config.h | 64 +-
javascript/duktape/duktape.c | 2435 +++++++++++++++++++++++----------------
javascript/duktape/duktape.h | 20 +-
3 files changed, 1462 insertions(+), 1057 deletions(-)
diff --git a/javascript/duktape/duk_config.h b/javascript/duktape/duk_config.h
index f6ee91c..64c10ea 100644
--- a/javascript/duktape/duk_config.h
+++ b/javascript/duktape/duk_config.h
@@ -1,9 +1,9 @@
/*
* duk_config.h configuration header generated by genconfig.py.
*
- * Git commit: b7b1c5fd2d1d4550140d57e05a7b32f540082bfa
- * Git describe: v1.3.0-383-gb7b1c5f
- * Git branch: duk-config-improvements
+ * Git commit: cad6f595382a0cc1a7e4207794ade5be11b3e397
+ * Git describe: v1.4.0
+ * Git branch: master
*
* Supported platforms:
* - Mac OSX, iPhone, Darwin
@@ -199,6 +199,12 @@
#define DUK_F_NO_STDINT_H
#endif
+/* C++ */
+#undef DUK_F_CPP
+#if defined(__cplusplus)
+#define DUK_F_CPP
+#endif
+
/* Intel x86 (32-bit), x64 (64-bit) or x32 (64-bit but 32-bit pointers),
* define only one of DUK_F_X86, DUK_F_X64, DUK_F_X32.
* https://sites.google.com/site/x32abi/
@@ -273,12 +279,6 @@
#define DUK_F_CLANG
#endif
-/* C++ */
-#undef DUK_F_CPP
-#if defined(__cplusplus)
-#define DUK_F_CPP
-#endif
-
/* C99 or above */
#undef DUK_F_C99
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
@@ -334,11 +334,6 @@
#define DUK_F_VBCC
#endif
-/* uclibc */
-#if defined(__UCLIBC__)
-#define DUK_F_UCLIBC
-#endif
-
/*
* Platform autodetection
*/
@@ -688,6 +683,10 @@
#include <stdint.h>
#endif
+#if defined(DUK_F_CPP)
+#include <exception> /* std::exception */
+#endif
+
/*
* Architecture autodetection
*/
@@ -1264,6 +1263,11 @@
#define DUK_F_VARIADIC_MACROS_PROVIDED
#endif /* autodetect compiler */
+/* uclibc */
+#if defined(__UCLIBC__)
+#define DUK_F_UCLIBC
+#endif
+
/*
* Wrapper typedefs and constants for integer types, also sanity check types.
*
@@ -2671,6 +2675,14 @@ typedef FILE duk_file;
#define DUK_USE_COMMONJS_MODULES
#endif
+#if defined(DUK_OPT_CPP_EXCEPTIONS)
+#define DUK_USE_CPP_EXCEPTIONS
+#elif defined(DUK_OPT_NO_CPP_EXCEPTIONS)
+#undef DUK_USE_CPP_EXCEPTIONS
+#else
+#undef DUK_USE_CPP_EXCEPTIONS
+#endif
+
#if defined(DUK_OPT_DATAPTR16)
#define DUK_USE_DATAPTR16
#elif defined(DUK_OPT_NO_DATAPTR16)
@@ -2760,7 +2772,7 @@ typedef FILE duk_file;
#elif defined(DUK_OPT_NO_DEBUGGER_THROW_NOTIFY)
#undef DUK_USE_DEBUGGER_THROW_NOTIFY
#else
-#undef DUK_USE_DEBUGGER_THROW_NOTIFY
+#define DUK_USE_DEBUGGER_THROW_NOTIFY
#endif
#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE)
@@ -3484,27 +3496,9 @@ typedef FILE duk_file;
#if defined(DUK_USE_DATAPTR_ENC16) && !defined(DUK_USE_DATAPTR16)
#error config option DUK_USE_DATAPTR_ENC16 requires option DUK_USE_DATAPTR16 (which is missing)
#endif
-#if defined(DUK_USE_DEBUGGER_DUMPHEAP) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_DUMPHEAP requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
-#if defined(DUK_USE_DEBUGGER_FWD_LOGGING) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_FWD_LOGGING requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
-#if defined(DUK_USE_DEBUGGER_FWD_PRINTALERT) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_FWD_PRINTALERT requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
-#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_PAUSE_UNCAUGHT requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
#if defined(DUK_USE_DEBUGGER_SUPPORT) && !defined(DUK_USE_INTERRUPT_COUNTER)
#error config option DUK_USE_DEBUGGER_SUPPORT requires option DUK_USE_INTERRUPT_COUNTER (which is missing)
#endif
-#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_THROW_NOTIFY requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
-#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE) && !defined(DUK_USE_DEBUGGER_SUPPORT)
-#error config option DUK_USE_DEBUGGER_TRANSPORT_TORTURE requires option DUK_USE_DEBUGGER_SUPPORT (which is missing)
-#endif
#if defined(DUK_USE_DEEP_C_STACK)
#error unsupported config option used (option has been removed): DUK_USE_DEEP_C_STACK
#endif
@@ -3620,6 +3614,10 @@ typedef FILE duk_file;
#error unsupported config option used (option has been removed): DUK_USE_UNALIGNED_ACCESSES_POSSIBLE
#endif
+#if defined(DUK_USE_CPP_EXCEPTIONS) && !defined(__cplusplus)
+#error DUK_USE_CPP_EXCEPTIONS enabled but not compiling with a C++ compiler
+#endif
+
/*
* Convert DUK_USE_BYTEORDER, from whatever source, into currently used
* internal defines. If detection failed, #error out.
diff --git a/javascript/duktape/duktape.c b/javascript/duktape/duktape.c
index ef22161..105bdbe 100644
--- a/javascript/duktape/duktape.c
+++ b/javascript/duktape/duktape.c
@@ -1,10 +1,10 @@
/* Omit from static analysis. */
#ifndef __clang_analyzer__
/*
- * Single source autogenerated distributable for Duktape 1.3.99.
-
- * Git commit b7b1c5fd2d1d4550140d57e05a7b32f540082bfa (v1.3.0-383-gb7b1c5f).
- * Git branch duk-config-improvements.
+ * Single source autogenerated distributable for Duktape 1.4.0.
+ *
+ * Git commit cad6f595382a0cc1a7e4207794ade5be11b3e397 (v1.4.0).
+ * Git branch master.
*
* See Duktape AUTHORS.rst and LICENSE.txt for copyright and
* licensing information.
@@ -18,7 +18,7 @@
*
* (http://opensource.org/licenses/MIT)
*
-* Copyright (c) 2013-2015 by Duktape authors (see AUTHORS.rst)
+* Copyright (c) 2013-2016 by Duktape authors (see AUTHORS.rst)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -68,6 +68,7 @@
* * Legimet <legimet.calc(a)gmail.com>
* * Karl Skomski <karl(a)skomski.com>
* * Bruce Pascoe <fatcerberus1(a)gmail.com>
+* * Ren\u00e9 Hollander <rene(a)rene8888.at>
*
* Other contributions
* ===================
@@ -104,6 +105,7 @@
* * https://github.com/sstruchtrup
* * Michael Drake (https://github.com/tlsa)
* * https://github.com/chris-y
+* * Laurent Zubiaur (https://github.com/lzubiaur)
*
* If you are accidentally missing from this list, send me an e-mail
* (``sami.vaarala(a)iki.fi``) and I'll fix the omission.
@@ -201,6 +203,7 @@ DUK_INTERNAL_DECL int duk_repl_isinf(double x);
#ifndef DUK_JMPBUF_H_INCLUDED
#define DUK_JMPBUF_H_INCLUDED
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
struct duk_jmpbuf {
#if defined(DUK_USE_SETJMP) || defined(DUK_USE_UNDERSCORE_SETJMP)
jmp_buf jb;
@@ -210,8 +213,28 @@ struct duk_jmpbuf {
#error internal error, no long control transfer provider
#endif
};
+#endif
#endif /* DUK_JMPBUF_H_INCLUDED */
+#line 1 "duk_exception.h"
+/*
+ * Exception for Duktape internal throws when C++ exceptions are used
+ * for long control transfers.
+ *
+ * Doesn't inherit from any exception base class to minimize the chance
+ * that user code would accidentally catch this exception.
+ */
+
+#ifndef DUK_EXCEPTION_H_INCLUDED
+#define DUK_EXCEPTION_H_INCLUDED
+
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+class duk_internal_exception {
+ /* intentionally empty */
+};
+#endif
+
+#endif /* DUK_EXCEPTION_H_INCLUDED */
#line 1 "duk_forwdecl.h"
/*
* Forward declarations for all Duktape structures.
@@ -224,7 +247,11 @@ struct duk_jmpbuf {
* Forward declarations
*/
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+class duk_internal_exception;
+#else
struct duk_jmpbuf;
+#endif
/* duk_tval intentionally skipped */
struct duk_heaphdr;
@@ -275,7 +302,11 @@ struct duk_compiler_ctx;
struct duk_re_matcher_ctx;
struct duk_re_compiler_ctx;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+/* no typedef */
+#else
typedef struct duk_jmpbuf duk_jmpbuf;
+#endif
/* duk_tval intentionally skipped */
typedef struct duk_heaphdr duk_heaphdr;
@@ -1595,13 +1626,13 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1955];
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 1952
+#define DUK_BUILTINS_DATA_LENGTH 1955
#ifdef DUK_USE_BUILTIN_INITJS
#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
@@ -2940,13 +2971,13 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1955];
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 1952
+#define DUK_BUILTINS_DATA_LENGTH 1955
#ifdef DUK_USE_BUILTIN_INITJS
#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
@@ -4285,13 +4316,13 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[2624];
#if !defined(DUK_SINGLE_FILE)
DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1952];
+DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[1955];
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#endif /* DUK_USE_BUILTIN_INITJS */
#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 1952
+#define DUK_BUILTINS_DATA_LENGTH 1955
#ifdef DUK_USE_BUILTIN_INITJS
#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
#endif /* DUK_USE_BUILTIN_INITJS */
@@ -4374,7 +4405,7 @@ DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
#error invalid endianness defines
#endif
#endif /* DUK_BUILTINS_H_INCLUDED */
-#line 50 "duk_internal.h"
+#line 51 "duk_internal.h"
#line 1 "duk_util.h"
/*
@@ -8202,7 +8233,7 @@ DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr
DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \
} while (0)
#define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \
- DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (f); \
+ DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \
} while (0)
#define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \
DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \
@@ -10033,7 +10064,9 @@ struct duk_strcache {
*/
struct duk_ljstate {
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */
+#endif
duk_small_uint_t type; /* longjmp type */
duk_bool_t iserror; /* isError flag for yield */
duk_tval value1; /* 1st related value (type specific) */
@@ -11272,12 +11305,11 @@ typedef struct {
#define DUK_JS_H_INCLUDED
/* Flags for call handling. */
-#define DUK_CALL_FLAG_PROTECTED (1 << 0) /* duk_handle_call: call is protected */
-#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 1) /* duk_handle_call: call ignores C recursion limit (for errhandler calls) */
-#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 2) /* duk_handle_call: constructor call (i.e. called as 'new Foo()') */
-#define DUK_CALL_FLAG_IS_RESUME (1 << 3) /* duk_handle_ecma_call_setup: setup for a resume() */
-#define DUK_CALL_FLAG_IS_TAILCALL (1 << 4) /* duk_handle_ecma_call_setup: setup for a tail call */
-#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 5) /* call is a direct eval call */
+#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 0) /* duk_handle_call_xxx: call ignores C recursion limit (for errhandler calls) */
+#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 1) /* duk_handle_call_xxx: constructor call (i.e. called as 'new Foo()') */
+#define DUK_CALL_FLAG_IS_RESUME (1 << 2) /* duk_handle_ecma_call_setup: setup for a resume() */
+#define DUK_CALL_FLAG_IS_TAILCALL (1 << 3) /* duk_handle_ecma_call_setup: setup for a tail call */
+#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 4) /* call is a direct eval call */
/* Flags for duk_js_equals_helper(). */
#define DUK_EQUALS_FLAG_SAMEVALUE (1 << 0) /* use SameValue instead of non-strict equality */
@@ -11354,7 +11386,8 @@ void duk_js_push_closure(duk_hthread *thr,
duk_hobject *outer_lex_env);
/* call handling */
-DUK_INTERNAL_DECL duk_int_t duk_handle_call(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
+DUK_INTERNAL_DECL void duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call(duk_hthread *thr, duk_safe_call_function func, duk_idx_t num_stack_args, duk_idx_t num_stack_res);
DUK_INTERNAL_DECL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
@@ -11710,7 +11743,7 @@ DUK_INTERNAL_DECL void duk_selftest_run_tests(void);
#endif
#endif /* DUK_SELFTEST_H_INCLUDED */
-#line 77 "duk_internal.h"
+#line 78 "duk_internal.h"
#endif /* DUK_INTERNAL_H_INCLUDED */
#line 1 "duk_strings.c"
@@ -12279,7 +12312,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_typedarray_set,
};
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[1955] = {
105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
@@ -12321,50 +12354,50 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
97,236,66,80,1,151,169,10,248,0,211,208,133,124,0,109,230,66,254,0,56,242,
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
-195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
-239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
-203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
-252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
-54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
-206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
-255,242,27,16,26,85,197,34,194,175,193,80,26,240,5,149,109,110,236,90,192,
-144,26,208,59,206,126,191,144,139,185,143,218,176,63,160,138,217,81,197,
-125,207,218,144,3,185,73,133,94,242,246,207,218,112,6,11,81,21,62,200,66,
-80,26,80,51,78,223,217,167,168,57,143,218,48,51,78,223,217,167,168,61,143,
-210,104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,
-80,0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,
-21,61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,
-181,250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,
-3,255,252,81,252,0,0,0,0,8,4,252,68,0,129,167,1,26,144,9,165,0,26,177,199,
-197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
-223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
-113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
-159,192,0,31,245,97,10,100,0,0,0,0,0,0,0,32,10,164,130,97,221,191,113,3,20,
-178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
-196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
-242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
-70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
-64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
-0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
-144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
-203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
-38,81,7,1,132,128,0,133,105,252,19,140,0,0,0,0,0,0,15,3,240,25,127,102,0,1,
-91,127,4,227,0,0,0,0,0,0,3,192,252,6,95,218,128,0,87,31,193,56,192,0,0,0,0,
-0,0,240,63,1,151,246,224,0,21,215,240,78,48,0,0,0,0,0,0,0,16,0,101,253,200,
-0,5,121,252,19,140,0,0,0,0,0,0,0,4,0,25,127,118,0,1,95,127,4,227,0,0,0,0,0,
-0,0,65,0,6,95,222,128,0,88,31,193,56,192,0,0,0,0,0,0,16,64,1,151,247,224,0,
-22,23,240,78,48,0,0,0,0,0,0,4,16,0,101,254,8,0,5,137,252,19,140,0,0,0,0,0,
-0,2,4,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,132,
-248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,92,93,
-32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,116,
-128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,210,
-0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,136,25,
-98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,101,160,
-3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,225,150,
-128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,2,158,
-70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,87,98,
-112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
+195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,65,192,2,22,0,
+88,16,46,24,77,208,148,103,4,102,252,102,244,128,0,0,0,0,0,0,0,0,220,111,
+68,113,61,146,142,248,0,164,255,128,0,63,228,133,109,16,89,178,65,18,235,
+153,25,150,220,184,188,180,230,6,32,209,205,0,20,175,240,0,39,252,160,77,
+162,184,54,72,34,0,82,255,192,0,159,242,193,54,138,222,217,32,136,1,76,255,
+0,2,127,204,4,218,43,115,100,130,32,5,55,252,0,9,255,52,19,104,173,173,146,
+8,128,20,239,240,0,39,252,224,77,162,182,54,72,34,0,83,255,192,0,159,243,
+193,54,138,214,217,32,136,0,255,255,33,177,1,165,92,82,44,42,252,21,1,175,
+0,89,86,214,238,197,172,9,1,173,3,188,231,235,249,8,187,152,253,171,3,250,
+8,173,149,28,87,220,253,169,0,59,148,152,85,239,47,108,253,167,0,96,181,17,
+83,236,132,37,1,165,3,52,237,253,154,122,131,152,253,163,3,52,237,253,154,
+122,131,216,253,38,130,129,25,234,5,0,1,103,40,20,0,9,154,160,80,0,54,98,
+146,25,106,5,0,4,101,40,20,0,21,146,160,80,0,102,66,129,64,1,216,234,5,0,8,
+99,39,47,49,83,215,152,138,73,0,1,97,168,129,132,160,80,0,150,10,129,64,2,
+152,10,5,0,11,95,168,20,0,48,31,255,224,5,17,72,66,249,37,129,127,255,0,0,
+191,255,128,0,63,255,197,31,192,0,0,0,0,0,80,196,64,8,26,112,17,169,0,154,
+80,1,171,28,124,88,65,233,49,7,133,100,29,149,15,14,138,71,135,37,3,195,66,
+114,5,77,252,0,243,178,40,25,200,48,101,30,0,127,210,128,0,85,31,192,0,31,
+244,224,5,71,22,8,0,13,20,88,1,85,127,0,0,127,212,128,21,29,220,32,0,52,87,
+112,5,89,252,0,1,255,86,16,166,64,0,0,0,0,0,0,2,0,170,72,38,29,219,247,16,
+49,75,32,193,52,130,244,193,225,114,96,248,0,8,249,48,124,0,8,90,152,62,0,
+6,44,76,31,0,4,21,166,15,128,2,147,255,252,38,212,16,184,155,250,226,217,
+150,47,46,91,249,54,96,139,229,229,203,127,36,26,119,32,203,203,150,254,72,
+52,97,221,147,102,157,217,192,10,191,248,0,157,4,72,15,250,224,1,154,140,
+36,0,8,43,31,224,0,15,251,0,16,55,139,164,0,192,220,46,144,2,3,104,186,64,
+12,77,130,233,0,33,53,139,164,0,200,212,46,144,2,35,72,186,64,8,205,2,233,
+0,36,51,140,180,0,192,204,50,208,2,3,40,203,64,12,76,131,45,0,33,49,140,
+180,0,200,196,50,208,2,35,8,203,64,8,204,3,45,0,36,7,255,248,1,82,101,16,
+112,24,72,0,8,86,159,193,56,192,0,0,0,0,0,0,240,63,1,151,246,96,0,21,183,
+240,78,48,0,0,0,0,0,0,60,15,192,101,253,168,0,5,113,252,19,140,0,0,0,0,0,0,
+15,3,240,25,127,110,0,1,93,127,4,227,0,0,0,0,0,0,0,1,0,6,95,220,128,0,87,
+159,193,56,192,0,0,0,0,0,0,0,64,1,151,247,96,0,21,247,240,78,48,0,0,0,0,0,
+0,4,16,0,101,253,232,0,5,129,252,19,140,0,0,0,0,0,0,1,4,0,25,127,126,0,1,
+97,127,4,227,0,0,0,0,0,0,0,65,0,6,95,224,128,0,88,159,193,56,192,0,0,0,0,0,
+0,32,64,1,151,248,96,0,22,55,240,5,157,170,33,68,178,69,10,193,20,10,104,
+79,138,36,0,12,31,248,160,88,154,23,66,100,93,32,2,9,129,116,128,0,165,197,
+210,0,18,150,23,72,0,138,84,93,32,3,41,65,116,128,1,36,197,210,0,20,146,23,
+72,0,146,68,93,32,3,73,1,116,128,1,163,197,210,0,22,142,23,72,0,34,52,93,
+32,1,136,193,118,128,2,162,197,218,0,26,138,23,104,0,170,36,93,160,3,168,
+129,150,33,198,90,0,32,134,25,104,0,10,20,101,160,1,40,65,150,128,8,160,
+198,90,0,50,130,25,104,0,18,4,101,160,1,72,1,150,128,9,31,198,90,0,52,126,
+25,104,0,25,244,101,160,1,103,193,150,128,2,30,198,90,0,24,122,25,136,0,41,
+228,102,32,1,167,129,152,128,10,157,198,98,0,59,71,91,99,157,104,9,213,118,
+39,5,8,159,20,40,0,10,109,90,19,81,132,39,151,32,
};
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
@@ -12666,7 +12699,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_typedarray_set,
};
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[1955] = {
105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
@@ -12708,50 +12741,50 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
97,236,66,80,1,151,169,10,248,0,211,208,133,124,0,109,230,66,254,0,56,242,
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
-195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
-239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
-203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
-252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
-54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
-206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
-255,242,27,16,16,1,111,194,162,197,21,218,90,240,16,0,154,236,110,237,85,
-69,154,208,15,249,139,144,191,190,142,123,218,176,15,253,197,81,217,74,224,
-191,154,144,15,246,242,222,197,73,185,67,154,112,16,2,72,126,213,17,11,70,
-26,80,15,249,168,39,153,159,206,243,90,48,15,253,168,39,153,159,206,243,82,
-104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,80,
-0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,21,
-61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,181,
-250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,3,
-255,252,81,252,4,12,68,248,0,0,0,0,0,129,167,1,26,144,9,165,0,26,177,199,
-197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
-223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
-113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
-159,192,0,31,245,97,10,100,32,0,0,0,0,0,0,0,10,164,130,97,221,191,113,3,20,
-178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
-196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
-242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
-70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
-64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
-0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
-144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
-203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
-38,81,7,1,132,128,0,133,105,252,19,140,3,255,0,0,0,0,0,0,0,25,127,102,0,1,
-91,127,4,227,0,255,192,0,0,0,0,0,0,6,95,218,128,0,87,31,193,56,192,63,240,
-0,0,0,0,0,0,1,151,246,224,0,21,215,240,78,48,16,0,0,0,0,0,0,0,0,101,253,
-200,0,5,121,252,19,140,4,0,0,0,0,0,0,0,0,25,127,118,0,1,95,127,4,227,1,0,
-64,0,0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,64,16,0,0,0,0,0,0,1,151,247,
-224,0,22,23,240,78,48,16,4,0,0,0,0,0,0,0,101,254,8,0,5,137,252,19,140,4,2,
-0,0,0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,
-132,248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,
-92,93,32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,
-116,128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,
-210,0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,
-136,25,98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,
-101,160,3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,
-225,150,128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,
-2,158,70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,
-87,98,112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
+195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,65,192,2,22,0,
+88,16,46,24,77,208,148,103,4,102,252,102,244,128,0,0,0,0,0,0,0,0,220,111,
+68,113,61,146,142,248,0,164,255,128,0,63,228,133,109,16,89,178,65,18,235,
+153,25,150,220,184,188,180,230,6,32,209,205,0,20,175,240,0,39,252,160,77,
+162,184,54,72,34,0,82,255,192,0,159,242,193,54,138,222,217,32,136,1,76,255,
+0,2,127,204,4,218,43,115,100,130,32,5,55,252,0,9,255,52,19,104,173,173,146,
+8,128,20,239,240,0,39,252,224,77,162,182,54,72,34,0,83,255,192,0,159,243,
+193,54,138,214,217,32,136,0,255,255,33,177,1,0,22,252,42,44,81,93,165,175,
+1,0,9,174,198,238,213,84,89,173,0,255,152,185,11,251,232,231,189,171,0,255,
+220,85,29,148,174,11,249,169,0,255,111,45,236,84,155,148,57,167,1,0,36,135,
+237,81,16,180,97,165,0,255,154,130,121,153,252,239,53,163,0,255,218,130,
+121,153,252,239,53,38,130,129,25,234,5,0,1,103,40,20,0,9,154,160,80,0,54,
+98,146,25,106,5,0,4,101,40,20,0,21,146,160,80,0,102,66,129,64,1,216,234,5,
+0,8,99,39,47,49,83,215,152,138,73,0,1,97,168,129,132,160,80,0,150,10,129,
+64,2,152,10,5,0,11,95,168,20,0,48,31,255,224,5,17,72,66,249,37,129,127,255,
+0,0,191,255,128,0,63,255,197,31,192,64,196,80,0,0,0,0,0,8,26,112,17,169,0,
+154,80,1,171,28,124,88,65,233,49,7,133,100,29,149,15,14,138,71,135,37,3,
+195,66,114,5,77,252,0,243,178,40,25,200,48,101,30,0,127,210,128,0,85,31,
+192,0,31,244,224,5,71,22,8,0,13,20,88,1,85,127,0,0,127,212,128,21,29,220,
+32,0,52,87,112,5,89,252,0,1,255,86,16,166,66,0,0,0,0,0,0,0,0,170,72,38,29,
+219,247,16,49,75,32,193,52,130,244,193,225,114,96,248,0,8,249,48,124,0,8,
+90,152,62,0,6,44,76,31,0,4,21,166,15,128,2,147,255,252,38,212,16,184,155,
+250,226,217,150,47,46,91,249,54,96,139,229,229,203,127,36,26,119,32,203,
+203,150,254,72,52,97,221,147,102,157,217,192,10,191,248,0,157,4,72,15,250,
+224,1,154,140,36,0,8,43,31,224,0,15,251,0,16,55,139,164,0,192,220,46,144,2,
+3,104,186,64,12,77,130,233,0,33,53,139,164,0,200,212,46,144,2,35,72,186,64,
+8,205,2,233,0,36,51,140,180,0,192,204,50,208,2,3,40,203,64,12,76,131,45,0,
+33,49,140,180,0,200,196,50,208,2,35,8,203,64,8,204,3,45,0,36,7,255,248,1,
+82,101,16,112,24,72,0,8,86,159,193,56,192,63,240,0,0,0,0,0,0,1,151,246,96,
+0,21,183,240,78,48,15,252,0,0,0,0,0,0,0,101,253,168,0,5,113,252,19,140,3,
+255,0,0,0,0,0,0,0,25,127,110,0,1,93,127,4,227,1,0,0,0,0,0,0,0,0,6,95,220,
+128,0,87,159,193,56,192,64,0,0,0,0,0,0,0,1,151,247,96,0,21,247,240,78,48,
+16,4,0,0,0,0,0,0,0,101,253,232,0,5,129,252,19,140,4,1,0,0,0,0,0,0,0,25,127,
+126,0,1,97,127,4,227,1,0,64,0,0,0,0,0,0,6,95,224,128,0,88,159,193,56,192,
+64,32,0,0,0,0,0,0,1,151,248,96,0,22,55,240,5,157,170,33,68,178,69,10,193,
+20,10,104,79,138,36,0,12,31,248,160,88,154,23,66,100,93,32,2,9,129,116,128,
+0,165,197,210,0,18,150,23,72,0,138,84,93,32,3,41,65,116,128,1,36,197,210,0,
+20,146,23,72,0,146,68,93,32,3,73,1,116,128,1,163,197,210,0,22,142,23,72,0,
+34,52,93,32,1,136,193,118,128,2,162,197,218,0,26,138,23,104,0,170,36,93,
+160,3,168,129,150,33,198,90,0,32,134,25,104,0,10,20,101,160,1,40,65,150,
+128,8,160,198,90,0,50,130,25,104,0,18,4,101,160,1,72,1,150,128,9,31,198,90,
+0,52,126,25,104,0,25,244,101,160,1,103,193,150,128,2,30,198,90,0,24,122,25,
+136,0,41,228,102,32,1,167,129,152,128,10,157,198,98,0,59,71,91,99,157,104,
+9,213,118,39,5,8,159,20,40,0,10,109,90,19,81,132,39,151,32,
};
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
@@ -13053,7 +13086,7 @@ DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
duk_bi_typedarray_set,
};
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
+DUK_INTERNAL const duk_uint8_t duk_builtins_data[1955] = {
105,195,75,32,121,40,105,53,14,252,104,54,8,131,72,0,115,225,65,165,244,55,
243,6,145,32,210,24,210,186,25,249,35,120,216,99,226,13,79,33,116,177,164,
180,44,192,4,202,52,150,220,24,0,169,70,146,219,123,0,23,40,210,91,110,96,
@@ -13095,50 +13128,50 @@ DUK_INTERNAL const duk_uint8_t duk_builtins_data[1952] = {
97,236,66,80,1,151,169,10,248,0,211,208,133,124,0,109,230,66,254,0,56,242,
33,127,0,29,120,144,207,128,15,60,8,103,192,7,221,228,37,0,32,119,16,148,0,
133,218,66,190,0,68,236,33,95,0,35,117,144,191,128,18,58,136,95,192,9,92,
-195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,64,192,2,2,225,
-132,221,9,70,112,70,111,198,111,72,0,0,0,0,0,0,0,0,13,198,244,71,19,217,40,
-239,128,10,79,248,0,3,254,72,86,209,5,155,36,17,46,185,145,153,109,203,139,
-203,78,96,98,13,28,208,1,74,255,0,2,127,202,4,218,43,131,100,130,32,5,47,
-252,0,9,255,44,19,104,173,237,146,8,128,20,207,240,0,39,252,192,77,162,183,
-54,72,34,0,83,127,192,0,159,243,65,54,138,218,217,32,136,1,78,255,0,2,127,
-206,4,218,43,99,100,130,32,5,63,252,0,9,255,60,19,104,173,109,146,8,128,15,
-255,242,27,16,2,175,193,80,26,85,197,34,218,240,44,90,192,144,5,149,109,
-110,218,208,16,139,185,143,251,206,126,191,154,176,17,197,125,207,255,160,
-138,217,90,144,30,242,246,207,195,185,73,133,90,112,62,200,66,80,6,11,81,
-21,26,80,39,168,57,143,243,78,223,217,154,48,39,168,61,143,243,78,223,217,
-146,104,40,17,158,160,80,0,22,114,129,64,0,153,170,5,0,3,102,41,33,150,160,
-80,0,70,82,129,64,1,89,42,5,0,6,100,40,20,0,29,142,160,80,0,134,50,114,243,
-21,61,121,136,164,144,0,22,26,136,24,74,5,0,9,96,168,20,0,41,128,160,80,0,
-181,250,129,64,3,1,255,254,0,81,20,132,47,146,88,23,255,240,0,11,255,248,0,
-3,255,252,81,252,8,4,252,68,0,0,0,0,0,129,167,1,26,144,9,165,0,26,177,199,
-197,132,30,147,16,120,86,65,217,80,240,232,164,120,114,80,60,52,39,32,84,
-223,192,15,59,34,129,156,131,6,81,224,7,253,40,0,5,81,252,0,1,255,78,0,84,
-113,96,128,0,209,69,128,21,87,240,0,7,253,72,1,81,221,194,0,3,69,119,0,85,
-159,192,0,31,245,97,10,100,0,0,0,32,0,0,0,0,10,164,130,97,221,191,113,3,20,
-178,12,19,72,47,76,30,23,38,15,128,0,143,147,7,192,0,133,169,131,224,0,98,
-196,193,240,0,65,90,96,248,0,41,63,255,194,109,65,11,137,191,174,45,153,98,
-242,229,191,147,102,8,190,94,92,183,242,65,167,114,12,188,185,111,228,131,
-70,29,217,54,105,221,156,0,171,255,128,9,208,68,128,255,174,0,25,168,194,
-64,0,130,177,254,0,0,255,176,1,3,120,186,64,12,13,194,233,0,32,54,139,164,
-0,196,216,46,144,2,19,88,186,64,12,141,66,233,0,34,52,139,164,0,140,208,46,
-144,2,67,56,203,64,12,12,195,45,0,32,50,140,180,0,196,200,50,208,2,19,24,
-203,64,12,140,67,45,0,34,48,140,180,0,140,192,50,208,2,64,127,255,128,21,
-38,81,7,1,132,128,0,133,105,252,19,140,0,0,15,3,240,0,0,0,0,25,127,102,0,1,
-91,127,4,227,0,0,3,192,252,0,0,0,0,6,95,218,128,0,87,31,193,56,192,0,0,240,
-63,0,0,0,0,1,151,246,224,0,21,215,240,78,48,0,0,0,16,0,0,0,0,0,101,253,200,
-0,5,121,252,19,140,0,0,0,4,0,0,0,0,0,25,127,118,0,1,95,127,4,227,0,0,0,65,
-0,0,0,0,0,6,95,222,128,0,88,31,193,56,192,0,0,16,64,0,0,0,0,1,151,247,224,
-0,22,23,240,78,48,0,0,4,16,0,0,0,0,0,101,254,8,0,5,137,252,19,140,0,0,2,4,
-0,0,0,0,0,25,127,134,0,1,99,127,0,89,218,162,20,75,36,80,172,17,64,166,132,
-248,162,64,0,193,255,138,5,137,161,116,38,69,210,0,32,152,23,72,0,10,92,93,
-32,1,41,97,116,128,8,165,69,210,0,50,148,23,72,0,18,76,93,32,1,73,33,116,
-128,9,36,69,210,0,52,144,23,72,0,26,60,93,32,1,104,225,116,128,2,35,69,210,
-0,24,140,23,104,0,42,44,93,160,1,168,161,118,128,10,162,69,218,0,58,136,25,
-98,28,101,160,2,8,97,150,128,0,161,70,90,0,18,132,25,104,0,138,12,101,160,
-3,40,33,150,128,1,32,70,90,0,20,128,25,104,0,145,252,101,160,3,71,225,150,
-128,1,159,70,90,0,22,124,25,104,0,33,236,101,160,1,135,161,152,128,2,158,
-70,98,0,26,120,25,136,0,169,220,102,32,3,180,117,182,57,214,128,157,87,98,
-112,80,137,241,66,128,0,166,213,161,53,24,66,121,114,0,
+195,225,0,38,114,144,148,0,156,41,31,224,0,15,249,1,138,144,65,192,2,22,0,
+88,16,46,24,77,208,148,103,4,102,252,102,244,128,0,0,0,0,0,0,0,0,220,111,
+68,113,61,146,142,248,0,164,255,128,0,63,228,133,109,16,89,178,65,18,235,
+153,25,150,220,184,188,180,230,6,32,209,205,0,20,175,240,0,39,252,160,77,
+162,184,54,72,34,0,82,255,192,0,159,242,193,54,138,222,217,32,136,1,76,255,
+0,2,127,204,4,218,43,115,100,130,32,5,55,252,0,9,255,52,19,104,173,173,146,
+8,128,20,239,240,0,39,252,224,77,162,182,54,72,34,0,83,255,192,0,159,243,
+193,54,138,214,217,32,136,0,255,255,33,177,0,42,252,21,1,165,92,82,45,175,
+2,197,172,9,0,89,86,214,237,173,1,8,187,152,255,188,231,235,249,171,1,28,
+87,220,255,250,8,173,149,169,1,239,47,108,252,59,148,152,85,167,3,236,132,
+37,0,96,181,17,81,165,2,122,131,152,255,52,237,253,153,163,2,122,131,216,
+255,52,237,253,153,38,130,129,25,234,5,0,1,103,40,20,0,9,154,160,80,0,54,
+98,146,25,106,5,0,4,101,40,20,0,21,146,160,80,0,102,66,129,64,1,216,234,5,
+0,8,99,39,47,49,83,215,152,138,73,0,1,97,168,129,132,160,80,0,150,10,129,
+64,2,152,10,5,0,11,95,168,20,0,48,31,255,224,5,17,72,66,249,37,129,127,255,
+0,0,191,255,128,0,63,255,197,31,192,0,80,196,64,0,0,0,0,8,26,112,17,169,0,
+154,80,1,171,28,124,88,65,233,49,7,133,100,29,149,15,14,138,71,135,37,3,
+195,66,114,5,77,252,0,243,178,40,25,200,48,101,30,0,127,210,128,0,85,31,
+192,0,31,244,224,5,71,22,8,0,13,20,88,1,85,127,0,0,127,212,128,21,29,220,
+32,0,52,87,112,5,89,252,0,1,255,86,16,166,64,0,0,2,0,0,0,0,0,170,72,38,29,
+219,247,16,49,75,32,193,52,130,244,193,225,114,96,248,0,8,249,48,124,0,8,
+90,152,62,0,6,44,76,31,0,4,21,166,15,128,2,147,255,252,38,212,16,184,155,
+250,226,217,150,47,46,91,249,54,96,139,229,229,203,127,36,26,119,32,203,
+203,150,254,72,52,97,221,147,102,157,217,192,10,191,248,0,157,4,72,15,250,
+224,1,154,140,36,0,8,43,31,224,0,15,251,0,16,55,139,164,0,192,220,46,144,2,
+3,104,186,64,12,77,130,233,0,33,53,139,164,0,200,212,46,144,2,35,72,186,64,
+8,205,2,233,0,36,51,140,180,0,192,204,50,208,2,3,40,203,64,12,76,131,45,0,
+33,49,140,180,0,200,196,50,208,2,35,8,203,64,8,204,3,45,0,36,7,255,248,1,
+82,101,16,112,24,72,0,8,86,159,193,56,192,0,0,240,63,0,0,0,0,1,151,246,96,
+0,21,183,240,78,48,0,0,60,15,192,0,0,0,0,101,253,168,0,5,113,252,19,140,0,
+0,15,3,240,0,0,0,0,25,127,110,0,1,93,127,4,227,0,0,0,1,0,0,0,0,0,6,95,220,
+128,0,87,159,193,56,192,0,0,0,64,0,0,0,0,1,151,247,96,0,21,247,240,78,48,0,
+0,4,16,0,0,0,0,0,101,253,232,0,5,129,252,19,140,0,0,1,4,0,0,0,0,0,25,127,
+126,0,1,97,127,4,227,0,0,0,65,0,0,0,0,0,6,95,224,128,0,88,159,193,56,192,0,
+0,32,64,0,0,0,0,1,151,248,96,0,22,55,240,5,157,170,33,68,178,69,10,193,20,
+10,104,79,138,36,0,12,31,248,160,88,154,23,66,100,93,32,2,9,129,116,128,0,
+165,197,210,0,18,150,23,72,0,138,84,93,32,3,41,65,116,128,1,36,197,210,0,
+20,146,23,72,0,146,68,93,32,3,73,1,116,128,1,163,197,210,0,22,142,23,72,0,
+34,52,93,32,1,136,193,118,128,2,162,197,218,0,26,138,23,104,0,170,36,93,
+160,3,168,129,150,33,198,90,0,32,134,25,104,0,10,20,101,160,1,40,65,150,
+128,8,160,198,90,0,50,130,25,104,0,18,4,101,160,1,72,1,150,128,9,31,198,90,
+0,52,126,25,104,0,25,244,101,160,1,103,193,150,128,2,30,198,90,0,24,122,25,
+136,0,41,228,102,32,1,167,129,152,128,10,157,198,98,0,59,71,91,99,157,104,
+9,213,118,39,5,8,159,20,40,0,10,109,90,19,81,132,39,151,32,
};
#ifdef DUK_USE_BUILTIN_INITJS
DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
@@ -15778,7 +15811,6 @@ DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_small_uint_t call_flags;
duk_idx_t idx_func;
- duk_int_t rc;
DUK_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(thr != NULL);
@@ -15797,17 +15829,15 @@ DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
call_flags = 0; /* not protected, respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
- DUK_UNREF(rc);
+ duk_handle_call_unprotected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
}
DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_small_uint_t call_flags;
duk_idx_t idx_func;
- duk_int_t rc;
DUK_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(thr != NULL);
@@ -15820,10 +15850,9 @@ DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
call_flags = 0; /* not protected, respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
- DUK_UNREF(rc);
+ duk_handle_call_unprotected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
}
DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
@@ -15872,11 +15901,11 @@ DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) {
duk_push_undefined(ctx);
duk_insert(ctx, idx_func + 1);
- call_flags = DUK_CALL_FLAG_PROTECTED; /* protected, respect reclimit, not constructor */
+ call_flags = 0; /* respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ rc = duk_handle_call_protected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
return rc;
}
@@ -15897,11 +15926,11 @@ DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) {
return DUK_EXEC_ERROR; /* unreachable */
}
- call_flags = DUK_CALL_FLAG_PROTECTED; /* protected, respect reclimit, not constructor */
+ call_flags = 0; /* respect reclimit, not constructor */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
+ rc = duk_handle_call_protected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
return rc;
}
@@ -16010,7 +16039,6 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
duk_hobject *fallback;
duk_idx_t idx_cons;
duk_small_uint_t call_flags;
- duk_int_t rc;
DUK_ASSERT_CTX_VALID(ctx);
@@ -16104,15 +16132,13 @@ DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */
- rc = duk_handle_call(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
- DUK_UNREF(rc);
+ duk_handle_call_unprotected(thr, /* thread */
+ nargs, /* num_stack_args */
+ call_flags); /* call_flags */
/* [... fallback retval] */
- DUK_DDD(DUK_DDDPRINT("constructor call finished, rc=%ld, fallback=%!iT, retval=%!iT",
- (long) rc,
+ DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT",
(duk_tval *) duk_get_tval(ctx, -2),
(duk_tval *) duk_get_tval(ctx, -1)));
@@ -20672,16 +20698,16 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
* true
*/
duk_small_uint_t lf_flags;
- duk_small_uint_t nargs;
+ duk_idx_t nargs;
duk_small_uint_t lf_len;
duk_c_function func;
duk_hnativefunction *nf;
DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
- nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
+ nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
if (nargs == DUK_LFUNC_NARGS_VARARGS) {
- nargs = DUK_VARARGS;
+ nargs = (duk_idx_t) DUK_VARARGS;
}
flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
DUK_HOBJECT_FLAG_CONSTRUCTABLE |
@@ -20691,10 +20717,10 @@ DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
DUK_HOBJECT_FLAG_NOTAIL |
/* DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC: omitted here intentionally */
DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
- (void) duk__push_c_function_raw(ctx, func, (duk_idx_t) nargs, flags);
+ (void) duk__push_c_function_raw(ctx, func, nargs, flags);
lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
- if (lf_len != nargs) {
+ if ((duk_idx_t) lf_len != nargs) {
/* Explicit length is only needed if it differs from 'nargs'. */
duk_push_int(ctx, (duk_int_t) lf_len);
duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
@@ -21889,7 +21915,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
duk_hnativefunction *obj;
duk_idx_t ret;
duk_tval *tv_slot;
- duk_uint16_t func_nargs;
+ duk_int16_t func_nargs;
DUK_ASSERT_CTX_VALID(ctx);
@@ -21901,7 +21927,7 @@ DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function fu
goto api_error;
}
if (nargs >= 0 && nargs < DUK_HNATIVEFUNCTION_NARGS_MAX) {
- func_nargs = (duk_uint16_t) nargs;
+ func_nargs = (duk_int16_t) nargs;
} else if (nargs == DUK_VARARGS) {
func_nargs = DUK_HNATIVEFUNCTION_NARGS_VARARGS;
} else {
@@ -25623,8 +25649,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_HBUFFER_INCREF(thr, h_val);
h_bufobj->offset = h_bufarg->offset + byte_offset;
h_bufobj->length = byte_length;
- h_bufobj->shift = shift;
- h_bufobj->elem_type = elem_type;
+ h_bufobj->shift = (duk_uint8_t) shift;
+ h_bufobj->elem_type = (duk_uint8_t) elem_type;
h_bufobj->is_view = 1;
DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
@@ -25727,8 +25753,8 @@ DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
DUK_HBUFFER_INCREF(thr, h_val);
DUK_ASSERT(h_bufobj->offset == 0);
h_bufobj->length = byte_length;
- h_bufobj->shift = shift;
- h_bufobj->elem_type = elem_type;
+ h_bufobj->shift = (duk_uint8_t) shift;
+ h_bufobj->elem_type = (duk_uint8_t) elem_type;
h_bufobj->is_view = 1;
DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
@@ -31241,7 +31267,7 @@ DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
duk_small_uint_t comp_flags;
duk_int_t level = -2;
- DUK_ASSERT_TOP(ctx, 1);
+ DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */
DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
(thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */
@@ -38486,7 +38512,9 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
thr->heap->lj.iserror = is_error;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
+#endif
duk_err_longjmp(thr); /* execution resumes in bytecode executor */
return 0; /* never here */
@@ -38603,7 +38631,9 @@ DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
thr->heap->lj.iserror = is_error;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
+#endif
duk_err_longjmp(thr); /* execution resumes in bytecode executor */
return 0; /* never here */
@@ -41388,7 +41418,7 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
/* [ ... eval "eval" eval_input level ] */
- call_flags = DUK_CALL_FLAG_PROTECTED;
+ call_flags = 0;
if (thr->callstack_top >= (duk_size_t) -level) {
duk_activation *act;
duk_hobject *fun;
@@ -41405,7 +41435,7 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
}
}
- call_ret = duk_handle_call(thr, 2 /*num_stack_args*/, call_flags);
+ call_ret = duk_handle_call_protected(thr, 2 /*num_stack_args*/, call_flags);
if (call_ret == DUK_EXEC_SUCCESS) {
eval_err = 0;
@@ -42151,12 +42181,11 @@ DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_c
DUK_ASSERT(!DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)); /* since no recursive error handler calls */
DUK_HEAP_SET_ERRHANDLER_RUNNING(thr->heap);
- call_flags = DUK_CALL_FLAG_PROTECTED |
- DUK_CALL_FLAG_IGNORE_RECLIMIT; /* protected, ignore reclimit, not constructor */
+ call_flags = DUK_CALL_FLAG_IGNORE_RECLIMIT; /* ignore reclimit, not constructor */
- rc = duk_handle_call(thr,
- 1, /* num args */
- call_flags); /* call_flags */
+ rc = duk_handle_call_protected(thr,
+ 1, /* num args */
+ call_flags); /* call_flags */
DUK_UNREF(rc); /* no need to check now: both success and error are OK */
DUK_ASSERT(DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));
@@ -42591,6 +42620,12 @@ DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
DUK_ASSERT(thr != NULL);
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ /* XXX: detecting uncaught exception case for C++ case; perhaps need
+ * some marker in heap->lj state that a try-catch is active. For now,
+ * invokes C++ uncaught exception handling.
+ */
+#else
if (!thr->heap->lj.jmpbuf_ptr) {
/*
* If we don't have a jmpbuf_ptr, there is little we can do
@@ -42605,8 +42640,16 @@ DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
duk_fatal((duk_context *) thr, DUK_ERR_UNCAUGHT_ERROR, "uncaught error");
DUK_UNREACHABLE();
}
+#endif
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ {
+ duk_internal_exception exc; /* dummy */
+ throw exc;
+ }
+#else
DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb);
+#endif
DUK_UNREACHABLE();
}
#line 1 "duk_error_misc.c"
@@ -43731,7 +43774,9 @@ DUK_LOCAL void duk__dump_type_sizes(void) {
DUK__DUMPSZ(duk_tval);
/* structs from duk_forwdecl.h */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK__DUMPSZ(duk_jmpbuf);
+#endif
DUK__DUMPSZ(duk_heaphdr);
DUK__DUMPSZ(duk_heaphdr_string);
DUK__DUMPSZ(duk_hstring);
@@ -56652,22 +56697,80 @@ DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new
/*
* Call handling.
*
- * The main work horse functions are:
- * - duk_handle_call(): call to a C/Ecmascript functions
- * - duk_handle_safe_call(): make a protected C call within current activation
- * - duk_handle_ecma_call_setup(): Ecmascript-to-Ecmascript calls, including
- * tail calls and coroutine resume
+ * Main functions are:
+ *
+ * - duk_handle_call_unprotected(): unprotected call to Ecmascript or
+ * Duktape/C function
+ * - duk_handle_call_protected(): protected call to Ecmascript or
+ * Duktape/C function
+ * - duk_handle_safe_call(): make a protected C call within current
+ * activation
+ * - duk_handle_ecma_call_setup(): Ecmascript-to-Ecmascript calls
+ * (not always possible), including tail calls and coroutine resume
+ *
+ * See 'execution.rst'.
+ *
+ * Note: setjmp() and local variables have a nasty interaction,
+ * see execution.rst; non-volatile locals modified after setjmp()
+ * call are not guaranteed to keep their value.
*/
/* include removed: duk_internal.h */
/*
- * Misc
+ * Forward declarations.
+ */
+
+DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_small_uint_t call_flags,
+ duk_idx_t idx_func);
+DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_valstack_end,
+ duk_size_t entry_catchstack_top,
+ duk_size_t entry_callstack_top,
+ duk_int_t entry_call_recursion_depth,
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
+ duk_instr_t **entry_ptr_curr_pc,
+ duk_idx_t idx_func
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ );
+DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
+ duk_safe_call_function func,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_callstack_top,
+ duk_size_t entry_catchstack_top);
+DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_callstack_top,
+ duk_size_t entry_catchstack_top
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ );
+DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_int_t entry_call_recursion_depth,
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
+ duk_instr_t **entry_ptr_curr_pc);
+
+/*
+ * Interrupt counter fixup (for development only).
*/
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_thread) {
- /* XXX: Currently the bytecode executor and executor interrupt
+ /* Currently the bytecode executor and executor interrupt
* instruction counts are off because we don't execute the
* interrupt handler when we're about to exit from the initial
* user call into Duktape.
@@ -56699,18 +56802,17 @@ DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_th
/*
* Arguments object creation.
*
- * Creating arguments objects is a bit finicky, see E5 Section 10.6 for the
- * specific requirements. Much of the arguments object exotic behavior is
- * implemented in duk_hobject_props.c, and is enabled by the object flag
- * DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS.
+ * Creating arguments objects involves many small details, see E5 Section
+ * 10.6 for the specific requirements. Much of the arguments object exotic
+ * behavior is implemented in duk_hobject_props.c, and is enabled by the
+ * object flag DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS.
*/
-DUK_LOCAL
-void duk__create_arguments_object(duk_hthread *thr,
- duk_hobject *func,
- duk_hobject *varenv,
- duk_idx_t idx_argbase, /* idx of first argument on stack */
- duk_idx_t num_stack_args) { /* num args starting from idx_argbase */
+DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
+ duk_hobject *func,
+ duk_hobject *varenv,
+ duk_idx_t idx_argbase, /* idx of first argument on stack */
+ duk_idx_t num_stack_args) { /* num args starting from idx_argbase */
duk_context *ctx = (duk_context *) thr;
duk_hobject *arg; /* 'arguments' */
duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */
@@ -56789,7 +56891,7 @@ void duk__create_arguments_object(duk_hthread *thr,
-1); /* no prototype */
DUK_ASSERT(i_mappednames >= 0);
- /* [... formals arguments map mappedNames] */
+ /* [ ... formals arguments map mappedNames ] */
DUK_DDD(DUK_DDDPRINT("created arguments related objects: "
"arguments at index %ld -> %!O "
@@ -56831,14 +56933,14 @@ void duk__create_arguments_object(duk_hthread *thr,
duk_get_prop_index(ctx, i_formals, idx);
DUK_ASSERT(duk_is_string(ctx, -1));
- duk_dup(ctx, -1); /* [... name name] */
+ duk_dup(ctx, -1); /* [ ... name name ] */
if (!duk_has_prop(ctx, i_mappednames)) {
/* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping
* differs from the reference model
*/
- /* [... name] */
+ /* [ ... name ] */
need_map = 1;
@@ -56859,7 +56961,7 @@ void duk__create_arguments_object(duk_hthread *thr,
/* duk_has_prop() popped the second 'name' */
}
- /* [... name] */
+ /* [ ... name ] */
duk_pop(ctx); /* pop 'name' */
}
@@ -56893,18 +56995,17 @@ void duk__create_arguments_object(duk_hthread *thr,
/* steps 13-14 */
if (DUK_HOBJECT_HAS_STRICT(func)) {
- /*
- * Note: callee/caller are throwers and are not deletable etc.
- * They could be implemented as virtual properties, but currently
- * there is no support for virtual properties which are accessors
- * (only plain virtual properties). This would not be difficult
- * to change in duk_hobject_props, but we can make the throwers
- * normal, concrete properties just as easily.
+ /* Callee/caller are throwers and are not deletable etc. They
+ * could be implemented as virtual properties, but currently
+ * there is no support for virtual properties which are accessors
+ * (only plain virtual properties). This would not be difficult
+ * to change in duk_hobject_props, but we can make the throwers
+ * normal, concrete properties just as easily.
*
- * Note that the specification requires that the *same* thrower
- * built-in object is used here! See E5 Section 10.6 main
- * algoritm, step 14, and Section 13.2.3 which describes the
- * thrower. See test case test-arguments-throwers.js.
+ * Note that the specification requires that the *same* thrower
+ * built-in object is used here! See E5 Section 10.6 main
+ * algoritm, step 14, and Section 13.2.3 which describes the
+ * thrower. See test case test-arguments-throwers.js.
*/
DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers"));
@@ -56919,15 +57020,14 @@ void duk__create_arguments_object(duk_hthread *thr,
/* set exotic behavior only after we're done */
if (need_map) {
- /*
- * Note: exotic behaviors are only enabled for arguments
- * objects which have a parameter map (see E5 Section 10.6
- * main algorithm, step 12).
+ /* Exotic behaviors are only enabled for arguments objects
+ * which have a parameter map (see E5 Section 10.6 main
+ * algorithm, step 12).
*
- * In particular, a non-strict arguments object with no
- * mapped formals does *NOT* get exotic behavior, even
- * for e.g. "caller" property. This seems counterintuitive
- * but seems to be the case.
+ * In particular, a non-strict arguments object with no
+ * mapped formals does *NOT* get exotic behavior, even
+ * for e.g. "caller" property. This seems counterintuitive
+ * but seems to be the case.
*/
/* cannot be strict (never mapped variables) */
@@ -56939,7 +57039,6 @@ void duk__create_arguments_object(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("not enabling exotic behavior for arguments object"));
}
- /* nice log */
DUK_DDD(DUK_DDDPRINT("final arguments related objects: "
"arguments at index %ld -> %!O "
"map at index %ld -> %!O "
@@ -56948,20 +57047,22 @@ void duk__create_arguments_object(duk_hthread *thr,
(long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
(long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
- /* [args(n) [crud] formals arguments map mappednames] -> [args [crud] arguments] */
+ /* [ args(n) [crud] formals arguments map mappednames ] */
+
duk_pop_2(ctx);
duk_remove(ctx, -2);
+
+ /* [ args [crud] arguments ] */
}
/* Helper for creating the arguments object and adding it to the env record
* on top of the value stack. This helper has a very strict dependency on
* the shape of the input stack.
*/
-DUK_LOCAL
-void duk__handle_createargs_for_call(duk_hthread *thr,
- duk_hobject *func,
- duk_hobject *env,
- duk_idx_t num_stack_args) {
+DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr,
+ duk_hobject *func,
+ duk_hobject *env,
+ duk_idx_t num_stack_args) {
duk_context *ctx = (duk_context *) thr;
DUK_DDD(DUK_DDDPRINT("creating arguments object for function call"));
@@ -56972,7 +57073,7 @@ void duk__handle_createargs_for_call(duk_hthread *thr,
DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
DUK_ASSERT(duk_get_top(ctx) >= num_stack_args + 1);
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
duk__create_arguments_object(thr,
func,
@@ -56980,14 +57081,14 @@ void duk__handle_createargs_for_call(duk_hthread *thr,
duk_get_top(ctx) - num_stack_args - 1, /* idx_argbase */
num_stack_args);
- /* [... arg1 ... argN envobj argobj] */
+ /* [ ... arg1 ... argN envobj argobj ] */
duk_xdef_prop_stridx(ctx,
-2,
DUK_STRIDX_LC_ARGUMENTS,
DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */
DUK_PROPDESC_FLAGS_WE); /* non-strict: non-deletable, writable */
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
}
/*
@@ -57004,11 +57105,10 @@ void duk__handle_createargs_for_call(duk_hthread *thr,
* function. This would make call time handling much easier.
*/
-DUK_LOCAL
-void duk__handle_bound_chain_for_call(duk_hthread *thr,
- duk_idx_t idx_func,
- duk_idx_t *p_num_stack_args, /* may be changed by call */
- duk_bool_t is_constructor_call) {
+DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
+ duk_idx_t idx_func,
+ duk_idx_t *p_num_stack_args, /* may be changed by call */
+ duk_bool_t is_constructor_call) {
duk_context *ctx = (duk_context *) thr;
duk_idx_t num_stack_args;
duk_tval *tv_func;
@@ -57101,7 +57201,7 @@ void duk__handle_bound_chain_for_call(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(ctx, idx_func)));
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
tv_func = duk_require_tval(ctx, idx_func);
DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func));
if (DUK_TVAL_IS_OBJECT(tv_func)) {
@@ -57122,10 +57222,9 @@ void duk__handle_bound_chain_for_call(duk_hthread *thr,
* assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag.
*/
-DUK_LOCAL
-void duk__handle_oldenv_for_call(duk_hthread *thr,
- duk_hobject *func,
- duk_activation *act) {
+DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr,
+ duk_hobject *func,
+ duk_activation *act) {
duk_tval *tv;
DUK_ASSERT(thr != NULL);
@@ -57161,7 +57260,7 @@ void duk__handle_oldenv_for_call(duk_hthread *thr,
* Helper for updating callee 'caller' property.
*/
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func) {
duk_tval *tv_caller;
duk_hobject *h_tmp;
@@ -57181,6 +57280,8 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
act_callee = thr->callstack + thr->callstack_top - 1;
act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL);
+ /* XXX: check .caller writability? */
+
/* Backup 'caller' property and update its value. */
tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
if (tv_caller) {
@@ -57263,10 +57364,9 @@ DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func)
* side effects, because ToObject() may be called.
*/
-DUK_LOCAL
-void duk__coerce_effective_this_binding(duk_hthread *thr,
- duk_hobject *func,
- duk_idx_t idx_this) {
+DUK_LOCAL void duk__coerce_effective_this_binding(duk_hthread *thr,
+ duk_hobject *func,
+ duk_idx_t idx_this) {
duk_context *ctx = (duk_context *) thr;
duk_tval *tv_this;
duk_hobject *obj_global;
@@ -57316,12 +57416,11 @@ void duk__coerce_effective_this_binding(duk_hthread *thr,
* Returns duk_hobject * to the final non-bound function (NULL for lightfunc).
*/
-DUK_LOCAL
-duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
- duk_idx_t idx_func,
- duk_idx_t *out_num_stack_args,
- duk_tval **out_tv_func,
- duk_small_uint_t call_flags) {
+DUK_LOCAL duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
+ duk_idx_t idx_func,
+ duk_idx_t *out_num_stack_args,
+ duk_tval **out_tv_func,
+ duk_small_uint_t call_flags) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_tval *tv_func;
duk_hobject *func;
@@ -57377,19 +57476,23 @@ duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
}
/*
- * Value stack resize and stack top adjustment helper
+ * Value stack resize and stack top adjustment helper.
*
* XXX: This should all be merged to duk_valstack_resize_raw().
*/
-DUK_LOCAL
-void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, duk_idx_t idx_args, duk_idx_t nregs, duk_idx_t nargs, duk_hobject *func) {
+DUK_LOCAL void duk__adjust_valstack_and_top(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_idx_t idx_args,
+ duk_idx_t nregs,
+ duk_idx_t nargs,
+ duk_hobject *func) {
duk_context *ctx = (duk_context *) thr;
duk_size_t vs_min_size;
duk_bool_t adjusted_top = 0;
- vs_min_size = (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
- idx_args; /* bottom of new func */
+ vs_min_size = (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
+ idx_args; /* bottom of new func */
if (nregs >= 0) {
DUK_ASSERT(nargs >= 0);
@@ -57400,15 +57503,17 @@ void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, du
vs_min_size += num_stack_args; /* num entries of new func at entry */
}
if (func == NULL || DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM; /* Duktape/C API guaranteed entries (on top of args) */
+ vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM; /* Duktape/C API guaranteed entries (on top of args) */
}
- vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA; /* + spare */
+ vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA; /* + spare */
- /* XXX: Awkward fix for GH-107: we can't resize the value stack to
- * a size smaller than the current top, so the order of the resize
- * and adjusting the stack top depends on the current vs. final size
- * of the value stack. Ideally duk_valstack_resize_raw() would have
- * a combined algorithm to avoid this.
+ /* XXX: We can't resize the value stack to a size smaller than the
+ * current top, so the order of the resize and adjusting the stack
+ * top depends on the current vs. final size of the value stack.
+ * The operations could be combined to avoid this, but the proper
+ * fix is to only grow the value stack on a function call, and only
+ * shrink it (without throwing if the shrink fails) on function
+ * return.
*/
if (vs_min_size < (duk_size_t) (thr->valstack_top - thr->valstack)) {
@@ -57436,14 +57541,111 @@ void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, du
}
/*
- * Helper for making various kinds of calls.
- *
- * Call flags:
+ * Manipulate value stack so that exactly 'num_stack_rets' return
+ * values are at 'idx_retbase' in every case, assuming there are
+ * 'rc' return values on top of stack.
*
- * DUK_CALL_FLAG_PROTECTED <--> protected call
- * DUK_CALL_FLAG_IGNORE_RECLIMIT <--> ignore C recursion limit,
- * for errhandler calls
- * DUK_CALL_FLAG_CONSTRUCTOR_CALL <--> for 'new Foo()' calls
+ * This is a bit tricky, because the called C function operates in
+ * the same activation record and may have e.g. popped the stack
+ * empty (below idx_retbase).
+ */
+
+DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_retbase, duk_idx_t num_stack_rets, duk_idx_t num_actual_rets) {
+ duk_context *ctx = (duk_context *) thr;
+ duk_idx_t idx_rcbase;
+
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT(idx_retbase >= 0);
+ DUK_ASSERT(num_stack_rets >= 0);
+ DUK_ASSERT(num_actual_rets >= 0);
+
+ idx_rcbase = duk_get_top(ctx) - num_actual_rets; /* base of known return values */
+
+ DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
+ "num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld",
+ (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(ctx),
+ (long) idx_retbase, (long) idx_rcbase));
+
+ DUK_ASSERT(idx_rcbase >= 0); /* caller must check */
+
+ /* Ensure space for final configuration (idx_retbase + num_stack_rets)
+ * and intermediate configurations.
+ */
+ duk_require_stack_top(ctx,
+ (idx_rcbase > idx_retbase ? idx_rcbase : idx_retbase) +
+ num_stack_rets);
+
+ /* Chop extra retvals away / extend with undefined. */
+ duk_set_top(ctx, idx_rcbase + num_stack_rets);
+
+ if (idx_rcbase >= idx_retbase) {
+ duk_idx_t count = idx_rcbase - idx_retbase;
+ duk_idx_t i;
+
+ DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
+ "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
+
+ /* nuke values at idx_retbase to get the first retval (initially
+ * at idx_rcbase) to idx_retbase
+ */
+
+ DUK_ASSERT(count >= 0);
+
+ for (i = 0; i < count; i++) {
+ /* XXX: inefficient; block remove primitive */
+ duk_remove(ctx, idx_retbase);
+ }
+ } else {
+ duk_idx_t count = idx_retbase - idx_rcbase;
+ duk_idx_t i;
+
+ DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
+ "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
+
+ /* insert 'undefined' values at idx_rcbase to get the
+ * return values to idx_retbase
+ */
+
+ DUK_ASSERT(count > 0);
+
+ for (i = 0; i < count; i++) {
+ /* XXX: inefficient; block insert primitive */
+ duk_push_undefined(ctx);
+ duk_insert(ctx, idx_rcbase);
+ }
+ }
+}
+
+/*
+ * Misc shared helpers.
+ */
+
+/* Get valstack index for the func argument or throw if insane stack. */
+DUK_LOCAL duk_idx_t duk__get_idx_func(duk_hthread *thr, duk_idx_t num_stack_args) {
+ duk_size_t off_stack_top;
+ duk_size_t off_stack_args;
+ duk_size_t off_stack_all;
+ duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
+
+ /* Argument validation and func/args offset. */
+ off_stack_top = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack_bottom);
+ off_stack_args = (duk_size_t) ((duk_size_t) num_stack_args * sizeof(duk_tval));
+ off_stack_all = off_stack_args + 2 * sizeof(duk_tval);
+ if (DUK_UNLIKELY(off_stack_all > off_stack_top)) {
+ /* Since stack indices are not reliable, we can't do anything useful
+ * here. Invoke the existing setjmp catcher, or if it doesn't exist,
+ * call the fatal error handler.
+ */
+ DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
+ return 0;
+ }
+ idx_func = (duk_idx_t) ((off_stack_top - off_stack_all) / sizeof(duk_tval));
+ return idx_func;
+}
+
+/*
+ * duk_handle_call_protected() and duk_handle_call_unprotected():
+ * call into a Duktape/C or an Ecmascript function from any state.
*
* Input stack (thr):
*
@@ -57454,34 +57656,19 @@ void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, du
* [ retval ] (DUK_EXEC_SUCCESS)
* [ errobj ] (DUK_EXEC_ERROR (normal error), protected call)
*
- * Even when executing a protected call an error may be thrown in rare cases.
- * For instance, if we run out of memory when setting up the return stack
- * after a caught error, the out of memory is propagated to the caller.
- * Similarly, API errors (such as invalid input stack shape and invalid
- * indices) cause an error to propagate out of this function. If there is
- * no catchpoint for this error, the fatal error handler is called.
- *
- * See 'execution.rst'.
- *
- * The allowed thread states for making a call are:
- * - thr matches heap->curr_thread, and thr is already RUNNING
- * - thr does not match heap->curr_thread (may be NULL or other),
- * and thr is INACTIVE (in this case, a setjmp() catchpoint is
- * always used for thread book-keeping to work properly)
+ * Even when executing a protected call an error may be thrown in rare cases
+ * such as an insane num_stack_args argument. If there is no catchpoint for
+ * such errors, the fatal error handler is called.
*
- * Like elsewhere, gotos are used to keep indent level minimal and
- * avoiding a dozen helpers with awkward plumbing.
- *
- * Note: setjmp() and local variables have a nasty interaction,
- * see execution.rst; non-volatile locals modified after setjmp()
- * call are not guaranteed to keep their value.
+ * The error handling path should be error free, even for out-of-memory
+ * errors, to ensure safe sandboxing. (As of Duktape 1.4.0 this is not
+ * yet the case, see XXX notes below.)
*/
-DUK_INTERNAL
-duk_int_t duk_handle_call(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags) {
- duk_context *ctx = (duk_context *) thr;
+DUK_INTERNAL duk_int_t duk_handle_call_protected(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_small_uint_t call_flags) {
+ duk_context *ctx;
duk_size_t entry_valstack_bottom_index;
duk_size_t entry_valstack_end;
duk_size_t entry_callstack_top;
@@ -57490,37 +57677,33 @@ duk_int_t duk_handle_call(duk_hthread *thr,
duk_hthread *entry_curr_thread;
duk_uint_fast8_t entry_thread_state;
duk_instr_t **entry_ptr_curr_pc;
- volatile duk_bool_t need_setjmp;
- duk_jmpbuf * volatile old_jmpbuf_ptr = NULL; /* ptr is volatile (not the target) */
- volatile duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
- duk_idx_t idx_args; /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */
- duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
- duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
- duk_hobject *func; /* 'func' on stack (borrowed reference) */
- duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) or tv_func_copy */
- duk_tval tv_func_copy; /* to avoid relookups */
- duk_activation *act;
- duk_hobject *env;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ duk_jmpbuf *old_jmpbuf_ptr = NULL;
duk_jmpbuf our_jmpbuf;
- duk_int_t retval = DUK_EXEC_ERROR;
- duk_ret_t rc;
+#endif
+ duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
+
+ /* XXX: Multiple tv_func lookups are now avoided by making a local
+ * copy of tv_func. Another approach would be to compute an offset
+ * for tv_func from valstack bottom and recomputing the tv_func
+ * pointer quickly as valstack + offset instead of calling duk_get_tval().
+ */
+ ctx = (duk_context *) thr;
+ DUK_UNREF(ctx);
DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT_CTX_VALID(ctx);
DUK_ASSERT(num_stack_args >= 0);
-
/* XXX: currently NULL allocations are not supported; remove if later allowed */
DUK_ASSERT(thr->valstack != NULL);
DUK_ASSERT(thr->callstack != NULL);
DUK_ASSERT(thr->catchstack != NULL);
- /*
- * Preliminaries, required by setjmp() handler.
- *
- * Must be careful not to throw an unintended error here.
- *
- * Note: careful with indices like '-x'; if 'x' is zero, it
- * refers to valstack_bottom.
+ /* Argument validation and func/args offset. */
+ idx_func = duk__get_idx_func(thr, num_stack_args);
+
+ /* Preliminaries, required by setjmp() handler. Must be careful not
+ * to throw an unintended error here.
*/
entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
@@ -57537,29 +57720,19 @@ duk_int_t duk_handle_call(duk_hthread *thr,
entry_thread_state = thr->state;
entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
- idx_func = duk_normalize_index(ctx, -num_stack_args - 2); /* idx_func must be valid, note: non-throwing! */
- idx_args = idx_func + 2; /* idx_args is not necessarily valid if num_stack_args == 0 (idx_args then equals top) */
-
- /* Need a setjmp() catchpoint if a protected call OR if we need to
- * do mandatory cleanup.
- */
- need_setjmp = ((call_flags & DUK_CALL_FLAG_PROTECTED) != 0) || (thr->heap->curr_thread != thr);
-
- DUK_DD(DUK_DDPRINT("duk_handle_call: thr=%p, num_stack_args=%ld, "
- "call_flags=0x%08lx (protected=%ld, ignorerec=%ld, constructor=%ld), need_setjmp=%ld, "
+ DUK_DD(DUK_DDPRINT("duk_handle_call_protected: thr=%p, num_stack_args=%ld, "
+ "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
"valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
"entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
"entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
(void *) thr,
(long) num_stack_args,
(unsigned long) call_flags,
- (long) ((call_flags & DUK_CALL_FLAG_PROTECTED) != 0 ? 1 : 0),
(long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
(long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
- (long) need_setjmp,
(long) duk_get_top(ctx),
(long) idx_func,
- (long) idx_args,
+ (long) (idx_func + 2),
(long) thr->heap->call_recursion_depth,
(long) thr->heap->call_recursion_limit,
(long) entry_valstack_bottom_index,
@@ -57569,161 +57742,207 @@ duk_int_t duk_handle_call(duk_hthread *thr,
(void *) entry_curr_thread,
(long) entry_thread_state));
- /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
- * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
- * activation when side effects occur.
- */
- duk_hthread_sync_and_null_currpc(thr);
-
- /* XXX: Multiple tv_func lookups are now avoided by making a local
- * copy of tv_func. Another approach would be to compute an offset
- * for tv_func from valstack bottom and recomputing the tv_func
- * pointer quickly as valstack + offset instead of calling duk_get_tval().
- */
-
- if (idx_func < 0 || idx_args < 0) {
- /*
- * Since stack indices are not reliable, we can't do anything useful
- * here. Invoke the existing setjmp catcher, or if it doesn't exist,
- * call the fatal error handler.
- */
-
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
-
- /*
- * Setup a setjmp() catchpoint first because even the call setup
- * may fail.
- */
-
- if (!need_setjmp) {
- DUK_DDD(DUK_DDDPRINT("don't need a setjmp catchpoint"));
- goto handle_call;
- }
-
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
+#endif
- if (DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0) {
- DUK_DDD(DUK_DDDPRINT("setjmp catchpoint setup complete"));
- goto handle_call;
- }
-
- /*
- * Error during setup, call, or postprocessing of the call.
- * The error value is in heap->lj.value1.
- *
- * Note: any local variables accessed here must have their value
- * assigned *before* the setjmp() call, OR they must be declared
- * volatile. Otherwise their value is not guaranteed to be correct.
- *
- * The following are such variables:
- * - duk_handle_call() parameters
- * - entry_*
- * - idx_func
- * - idx_args
- *
- * The very first thing we do is restore the previous setjmp catcher.
- * This means that any error in error handling will propagate outwards
- * instead of causing a setjmp() re-entry above. The *only* actual
- * errors that should happen here are allocation errors.
- */
-
- DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_call(): %!T",
- (duk_tval *) &thr->heap->lj.value1));
-
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
- DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
-
- /* We don't need to sync back thr->curr_pc here because the
- * bytecode executor always has a setjmp catchpoint which
- * does that before errors propagate to here.
- */
-
- /*
- * Restore previous setjmp catchpoint
- */
-
- /* Note: either pointer may be NULL (at entry), so don't assert */
- DUK_DDD(DUK_DDDPRINT("restore jmpbuf_ptr: %p -> %p",
- (void *) (thr && thr->heap ? thr->heap->lj.jmpbuf_ptr : NULL),
- (void *) old_jmpbuf_ptr));
-
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- if (!(call_flags & DUK_CALL_FLAG_PROTECTED)) {
- /*
- * Caller did not request a protected call but a setjmp
- * catchpoint was set up to allow cleanup. So, clean up
- * and rethrow.
- *
- * We must restore curr_thread here to ensure that its
- * current value doesn't end up pointing to a thread object
- * which has been freed. This is now a problem because some
- * call sites (namely duk_safe_call()) *first* unwind stacks
- * and only then deal with curr_thread. If those call sites
- * were fixed, this wouldn't matter here.
- *
- * Note: this case happens e.g. when heap->curr_thread is
- * NULL on entry.
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ try {
+#else
+ if (DUK_LIKELY(DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0)) {
+#endif
+ /* Call handling and success path. Success path exit cleans
+ * up almost all state.
*/
+ duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
- DUK_DDD(DUK_DDDPRINT("call is not protected -> clean up and rethrow"));
+ /* Success path handles */
+ DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
+ DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
- /* Restore entry thread executor curr_pc stack frame pointer. */
- thr->ptr_curr_pc = entry_ptr_curr_pc;
+ /* Longjmp state is kept clean in success path */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
- DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
- thr->state = entry_thread_state;
- DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
- (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
- (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+#endif
- /* XXX: should setjmp catcher be responsible for this instead? */
- thr->heap->call_recursion_depth = entry_call_recursion_depth;
- duk_err_longjmp(thr);
- DUK_UNREACHABLE();
- }
+ return DUK_EXEC_SUCCESS;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ } catch (duk_internal_exception &exc) {
+#else
+ } else {
+#endif
+ /* Error; error value is in heap->lj.value1. */
+
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_UNREF(exc);
+#endif
+
+ duk__handle_call_error(thr,
+ entry_valstack_bottom_index,
+ entry_valstack_end,
+ entry_catchstack_top,
+ entry_callstack_top,
+ entry_call_recursion_depth,
+ entry_curr_thread,
+ entry_thread_state,
+ entry_ptr_curr_pc,
+ idx_func
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , old_jmpbuf_ptr
+#endif
+ );
+
+ /* Longjmp state is cleaned up by error handling */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
+ return DUK_EXEC_ERROR;
+ }
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ catch (std::exception &exc) {
+ const char *what = exc.what();
+ if (!what) {
+ what = "unknown";
+ }
+ DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
+ duk__handle_call_error(thr,
+ entry_valstack_bottom_index,
+ entry_valstack_end,
+ entry_catchstack_top,
+ entry_callstack_top,
+ entry_call_recursion_depth,
+ entry_curr_thread,
+ entry_thread_state,
+ entry_ptr_curr_pc,
+ idx_func);
+ return DUK_EXEC_ERROR;
+ }
+ } catch (...) {
+ DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "caught invalid c++ exception (perhaps thrown by user code)");
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
+ duk__handle_call_error(thr,
+ entry_valstack_bottom_index,
+ entry_valstack_end,
+ entry_catchstack_top,
+ entry_callstack_top,
+ entry_call_recursion_depth,
+ entry_curr_thread,
+ entry_thread_state,
+ entry_ptr_curr_pc,
+ idx_func);
+ return DUK_EXEC_ERROR;
+ }
+ }
+#endif
+}
+
+DUK_INTERNAL void duk_handle_call_unprotected(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_small_uint_t call_flags) {
+ duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
+
+ /* Argument validation and func/args offset. */
+ idx_func = duk__get_idx_func(thr, num_stack_args);
+
+ duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
+}
+
+DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_small_uint_t call_flags,
+ duk_idx_t idx_func) {
+ duk_context *ctx;
+ duk_size_t entry_valstack_bottom_index;
+ duk_size_t entry_valstack_end;
+ duk_size_t entry_callstack_top;
+ duk_size_t entry_catchstack_top;
+ duk_int_t entry_call_recursion_depth;
+ duk_hthread *entry_curr_thread;
+ duk_uint_fast8_t entry_thread_state;
+ duk_instr_t **entry_ptr_curr_pc;
+ duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
+ duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
+ duk_hobject *func; /* 'func' on stack (borrowed reference) */
+ duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) or tv_func_copy */
+ duk_tval tv_func_copy; /* to avoid relookups */
+ duk_activation *act;
+ duk_hobject *env;
+ duk_ret_t rc;
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
+ ctx = (duk_context *) thr;
+ DUK_ASSERT(thr != NULL);
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_ASSERT(ctx != NULL);
+ DUK_ASSERT(num_stack_args >= 0);
+ /* XXX: currently NULL allocations are not supported; remove if later allowed */
+ DUK_ASSERT(thr->valstack != NULL);
+ DUK_ASSERT(thr->callstack != NULL);
+ DUK_ASSERT(thr->catchstack != NULL);
- /* [ ... func this (crud) errobj ] */
+ DUK_DD(DUK_DDPRINT("duk__handle_call_inner: num_stack_args=%ld, call_flags=0x%08lx, top=%ld",
+ (long) num_stack_args, (long) call_flags, (long) duk_get_top(ctx)));
- /* XXX: is there space? better implementation: write directly over
- * 'func' slot to avoid valstack grow issues.
+ /*
+ * Store entry state.
*/
- duk_push_tval(ctx, &thr->heap->lj.value1);
- /* [ ... func this (crud) errobj ] */
-
- duk_replace(ctx, idx_func);
- duk_set_top(ctx, idx_func + 1);
-
- /* [ ... errobj ] */
+ entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
+#if defined(DUK_USE_PREFER_SIZE)
+ entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
+#else
+ DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
+ entry_valstack_end = thr->valstack_size;
+#endif
+ entry_callstack_top = thr->callstack_top;
+ entry_catchstack_top = thr->catchstack_top;
+ entry_call_recursion_depth = thr->heap->call_recursion_depth;
+ entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
+ entry_thread_state = thr->state;
+ entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
- /* Ensure there is internal valstack spare before we exit; this may
- * throw an alloc error. The same guaranteed size must be available
- * as before the call. This is not optimal now: we store the valstack
- * allocated size during entry; this value may be higher than the
- * minimal guarantee for an application.
+ /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
+ * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
+ * activation when side effects occur.
*/
+ duk_hthread_sync_and_null_currpc(thr);
- (void) duk_valstack_resize_raw((duk_context *) thr,
- entry_valstack_end, /* same as during entry */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- DUK_VSRESIZE_FLAG_COMPACT |
- DUK_VSRESIZE_FLAG_THROW);
+ DUK_DD(DUK_DDPRINT("duk__handle_call_inner: thr=%p, num_stack_args=%ld, "
+ "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
+ "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
+ "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
+ "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
+ (void *) thr,
+ (long) num_stack_args,
+ (unsigned long) call_flags,
+ (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
+ (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
+ (long) duk_get_top(ctx),
+ (long) idx_func,
+ (long) (idx_func + 2),
+ (long) thr->heap->call_recursion_depth,
+ (long) thr->heap->call_recursion_limit,
+ (long) entry_valstack_bottom_index,
+ (long) entry_callstack_top,
+ (long) entry_catchstack_top,
+ (long) entry_call_recursion_depth,
+ (void *) entry_curr_thread,
+ (long) entry_thread_state));
- /* Note: currently a second setjmp restoration is done at the target;
- * this is OK, but could be refactored away.
- */
- retval = DUK_EXEC_ERROR;
- goto shrink_and_finished;
- handle_call:
/*
* Thread state check and book-keeping.
*/
@@ -57748,7 +57967,6 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* state, but not in the same "resume chain".
*/
}
-
DUK_ASSERT(thr->heap->curr_thread == thr);
DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
@@ -57758,9 +57976,12 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* possible by recursive handle_call / handle_safe_call calls).
*/
+ /* XXX: remove DUK_CALL_FLAG_IGNORE_RECLIMIT flag: there's now the
+ * reclimit bump?
+ */
+
DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
-
if (call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) {
DUK_DD(DUK_DDPRINT("ignoring reclimit for this call (probably an errhandler call)"));
} else {
@@ -57802,45 +58023,10 @@ duk_int_t duk_handle_call(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
(duk_tval *) duk_get_tval(ctx, idx_func + 1)));
- /* These base values are never used, but if the compiler doesn't know
- * that DUK_ERROR() won't return, these are needed to silence warnings.
- * On the other hand, scan-build will warn about the values not being
- * used, so add a DUK_UNREF.
- */
- nargs = 0; DUK_UNREF(nargs);
- nregs = 0; DUK_UNREF(nregs);
-
- if (func == NULL) {
- duk_small_uint_t lf_flags;
-
- DUK_DDD(DUK_DDDPRINT("lightfunc call handling"));
- DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
- lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func);
- nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
- if (nargs == DUK_LFUNC_NARGS_VARARGS) {
- nargs = -1; /* vararg */
- }
- nregs = nargs;
- } else if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- nargs = ((duk_hcompiledfunction *) func)->nargs;
- nregs = ((duk_hcompiledfunction *) func)->nregs;
- DUK_ASSERT(nregs >= nargs);
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- /* Note: nargs (and nregs) may be negative for a native,
- * function, which indicates that the function wants the
- * input stack "as is" (i.e. handles "vararg" arguments).
- */
- nargs = ((duk_hnativefunction *) func)->nargs;
- nregs = nargs;
- } else {
- /* XXX: this should be an assert */
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_CALLABLE);
- }
-
/* [ ... func this arg1 ... argN ] */
/*
- * Setup a preliminary activation.
+ * Setup a preliminary activation and figure out nargs/nregs.
*
* Don't touch valstack_bottom or valstack_top yet so that Duktape API
* calls work normally.
@@ -57870,41 +58056,77 @@ duk_int_t duk_handle_call(duk_hthread *thr,
DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
act->flags = 0;
- if (func == NULL || DUK_HOBJECT_HAS_STRICT(func)) {
- act->flags |= DUK_ACT_FLAG_STRICT;
- }
+
+ /* For now all calls except Ecma-to-Ecma calls prevent a yield. */
+ act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
if (call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) {
act->flags |= DUK_ACT_FLAG_CONSTRUCT;
- /*act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;*/
- }
- if (func == NULL || DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- /*act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;*/
}
if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
}
- /* As a first approximation, all calls except Ecmascript-to-Ecmascript
- * calls prevent a yield.
+ /* These base values are never used, but if the compiler doesn't know
+ * that DUK_ERROR() won't return, these are needed to silence warnings.
+ * On the other hand, scan-build will warn about the values not being
+ * used, so add a DUK_UNREF.
*/
- act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
+ nargs = 0; DUK_UNREF(nargs);
+ nregs = 0; DUK_UNREF(nregs);
+
+ if (DUK_LIKELY(func != NULL)) {
+ if (DUK_HOBJECT_HAS_STRICT(func)) {
+ act->flags |= DUK_ACT_FLAG_STRICT;
+ }
+ if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
+ nargs = ((duk_hcompiledfunction *) func)->nargs;
+ nregs = ((duk_hcompiledfunction *) func)->nregs;
+ DUK_ASSERT(nregs >= nargs);
+ } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
+ /* Note: nargs (and nregs) may be negative for a native,
+ * function, which indicates that the function wants the
+ * input stack "as is" (i.e. handles "vararg" arguments).
+ */
+ nargs = ((duk_hnativefunction *) func)->nargs;
+ nregs = nargs;
+ } else {
+ /* XXX: this should be an assert */
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_CALLABLE);
+ }
+ } else {
+ duk_small_uint_t lf_flags;
+
+ DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
+ lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func);
+ nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
+ if (nargs == DUK_LFUNC_NARGS_VARARGS) {
+ nargs = -1; /* vararg */
+ }
+ nregs = nargs;
+
+ act->flags |= DUK_ACT_FLAG_STRICT;
+ }
act->func = func; /* NULL for lightfunc */
act->var_env = NULL;
act->lex_env = NULL;
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
act->prev_caller = NULL;
#endif
act->curr_pc = NULL;
#if defined(DUK_USE_DEBUGGER_SUPPORT)
act->prev_line = 0;
#endif
- act->idx_bottom = entry_valstack_bottom_index + idx_args;
+ act->idx_bottom = entry_valstack_bottom_index + idx_func + 2;
#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
act->idx_retval = 0;
#endif
DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */
+ /* XXX: remove the preventcount and make yield walk the callstack?
+ * Or perhaps just use a single flag, not a counter, faster to just
+ * set and restore?
+ */
if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
/* duk_hthread_callstack_unwind() will decrease this on unwind */
thr->callstack_preventcount++;
@@ -57916,14 +58138,14 @@ duk_int_t duk_handle_call(duk_hthread *thr,
*/
DUK_HOBJECT_INCREF_ALLOWNULL(thr, func); /* act->func */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
if (func) {
duk__update_func_caller_prop(thr, func);
}
act = thr->callstack + thr->callstack_top - 1;
#endif
- /* [... func this arg1 ... argN] */
+ /* [ ... func this arg1 ... argN ] */
/*
* Environment record creation and 'arguments' object creation.
@@ -57940,49 +58162,57 @@ duk_int_t duk_handle_call(duk_hthread *thr,
DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
- if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
- /* use existing env (e.g. for non-strict eval); cannot have
- * an own 'arguments' object (but can refer to the existing one)
- */
+ if (DUK_LIKELY(func != NULL)) {
+ if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) {
+ if (DUK_LIKELY(!DUK_HOBJECT_HAS_CREATEARGS(func))) {
+ /* Use a new environment but there's no 'arguments' object;
+ * delayed environment initialization. This is the most
+ * common case.
+ */
+ DUK_ASSERT(act->lex_env == NULL);
+ DUK_ASSERT(act->var_env == NULL);
+ } else {
+ /* Use a new environment and there's an 'arguments' object.
+ * We need to initialize it right now.
+ */
- DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
+ /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
+ env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
+ DUK_ASSERT(env != NULL);
- duk__handle_oldenv_for_call(thr, func, act);
+ /* [ ... func this arg1 ... argN envobj ] */
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
- goto env_done;
- }
+ DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
+ duk__handle_createargs_for_call(thr, func, env, num_stack_args);
- DUK_ASSERT(func == NULL || DUK_HOBJECT_HAS_NEWENV(func));
+ /* [ ... func this arg1 ... argN envobj ] */
- if (func == NULL || !DUK_HOBJECT_HAS_CREATEARGS(func)) {
- /* no need to create environment record now; leave as NULL */
- DUK_ASSERT(act->lex_env == NULL);
- DUK_ASSERT(act->var_env == NULL);
- goto env_done;
- }
-
- /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
- env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
- DUK_ASSERT(env != NULL);
-
- /* [... func this arg1 ... argN envobj] */
+ act = thr->callstack + thr->callstack_top - 1;
+ act->lex_env = env;
+ act->var_env = env;
+ DUK_HOBJECT_INCREF(thr, env);
+ DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */
+ duk_pop(ctx);
+ }
+ } else {
+ /* Use existing env (e.g. for non-strict eval); cannot have
+ * an own 'arguments' object (but can refer to an existing one).
+ */
- DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- duk__handle_createargs_for_call(thr, func, env, num_stack_args);
+ DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
- /* [... func this arg1 ... argN envobj] */
+ duk__handle_oldenv_for_call(thr, func, act);
- act = thr->callstack + thr->callstack_top - 1;
- act->lex_env = env;
- act->var_env = env;
- DUK_HOBJECT_INCREF(thr, env);
- DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */
- duk_pop(ctx);
+ DUK_ASSERT(act->lex_env != NULL);
+ DUK_ASSERT(act->var_env != NULL);
+ }
+ } else {
+ /* Lightfuncs are always native functions and have "newenv". */
+ DUK_ASSERT(act->lex_env == NULL);
+ DUK_ASSERT(act->var_env == NULL);
+ }
- env_done:
- /* [... func this arg1 ... argN] */
+ /* [ ... func this arg1 ... argN ] */
/*
* Setup value stack: clamp to 'nargs', fill up to 'nregs'
@@ -57993,109 +58223,158 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* wants all args (= 'num_stack_args').
*/
+ /* XXX: optimize value stack operation */
+ /* XXX: don't want to shrink allocation here */
+
duk__adjust_valstack_and_top(thr,
num_stack_args,
- idx_args,
+ idx_func + 2,
nregs,
nargs,
func);
/*
- * Determine call type; then setup activation and call
+ * Determine call type, then finalize activation, shift to
+ * new value stack bottom, and call the target.
*/
if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- goto ecmascript_call;
- } else {
- goto native_call;
- }
- DUK_UNREACHABLE();
+ /*
+ * Ecmascript call
+ */
- /*
- * Native (C) call
- */
+ duk_tval *tv_ret;
+ duk_tval *tv_funret;
- native_call:
- /*
- * Shift to new valstack_bottom.
- */
+ DUK_ASSERT(func != NULL);
+ DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
+ act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
- thr->valstack_bottom = thr->valstack_bottom + idx_args;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- DUK_ASSERT(func == NULL || ((duk_hnativefunction *) func)->func != NULL);
+ thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
+ /* keep current valstack_top */
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- /* [... func this | arg1 ... argN] ('this' must precede new bottom) */
+ /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
- /*
- * Actual function call and return value check.
- *
- * Return values:
- * 0 success, no return value (default to 'undefined')
- * 1 success, one return value on top of stack
- * < 0 error, throw a "magic" error
- * other invalid
- */
+ /*
+ * Bytecode executor call.
+ *
+ * Execute bytecode, handling any recursive function calls and
+ * thread resumptions. Returns when execution would return from
+ * the entry level activation. When the executor returns, a
+ * single return value is left on the stack top.
+ *
+ * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
+ * other types are handled internally by the executor.
+ */
- /* For native calls must be NULL so we don't sync back */
- DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ /* thr->ptr_curr_pc is set by bytecode executor early on entry */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
+ DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
+ duk_js_execute_bytecode(thr);
+ DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
- if (func) {
- rc = ((duk_hnativefunction *) func)->func((duk_context *) thr);
- } else {
- duk_c_function funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
- rc = funcptr((duk_context *) thr);
- }
+ /* Unwind. */
- if (rc < 0) {
- duk_error_throw_from_negative_rc(thr, rc);
- DUK_UNREACHABLE();
- } else if (rc > 1) {
- DUK_ERROR_API(thr, "c function returned invalid rc");
- }
- DUK_ASSERT(rc == 0 || rc == 1);
+ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
+ duk_hthread_catchstack_shrink_check(thr);
+ duk_hthread_callstack_unwind(thr, entry_callstack_top);
+ duk_hthread_callstack_shrink_check(thr);
- /*
- * Unwind stack(s) and shift back to old valstack_bottom.
- */
+ thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
+ /* keep current valstack_top */
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
- DUK_ASSERT(thr->catchstack_top == entry_catchstack_top);
- DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ /* Return value handling. */
-#if 0 /* should be no need to unwind */
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
+ /* [ ... func this (crud) retval ] */
+
+ tv_ret = thr->valstack_bottom + idx_func;
+ tv_funret = thr->valstack_top - 1;
+#if defined(DUK_USE_FASTINT)
+ /* Explicit check for fastint downgrade. */
+ DUK_TVAL_CHKFAST_INPLACE(tv_funret);
#endif
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
+ } else {
+ /*
+ * Native call.
+ */
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- /* keep current valstack_top */
+ duk_tval *tv_ret;
+ duk_tval *tv_funret;
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
+ thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
+ /* keep current valstack_top */
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(func == NULL || ((duk_hnativefunction *) func)->func != NULL);
- /*
- * Manipulate value stack so that return value is on top
- * (pushing an 'undefined' if necessary).
- */
+ /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
- /* XXX: should this happen in the callee's activation or after unwinding? */
- if (rc == 0) {
- duk_require_stack(ctx, 1);
- duk_push_undefined(ctx);
- }
- /* [... func this (crud) retval] */
+ /* For native calls must be NULL so we don't sync back */
+ DUK_ASSERT(thr->ptr_curr_pc == NULL);
- DUK_DDD(DUK_DDDPRINT("native call retval -> %!T (rc=%ld)",
- (duk_tval *) duk_get_tval(ctx, -1), (long) rc));
+ if (func) {
+ rc = ((duk_hnativefunction *) func)->func((duk_context *) thr);
+ } else {
+ duk_c_function funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
+ rc = funcptr((duk_context *) thr);
+ }
- duk_replace(ctx, idx_func);
- duk_set_top(ctx, idx_func + 1);
+ /* Automatic error throwing, retval check. */
- /* [... retval] */
+ if (rc < 0) {
+ duk_error_throw_from_negative_rc(thr, rc);
+ DUK_UNREACHABLE();
+ } else if (rc > 1) {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "c function returned invalid rc");
+ }
+ DUK_ASSERT(rc == 0 || rc == 1);
+
+ /* Unwind. */
+
+ DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
+ duk_hthread_callstack_unwind(thr, entry_callstack_top);
+ duk_hthread_callstack_shrink_check(thr);
+
+ thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
+ /* keep current valstack_top */
+ DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
+ DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
+ DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
+
+ /* Return value handling. */
+
+ /* XXX: should this happen in the callee's activation or after unwinding? */
+ tv_ret = thr->valstack_bottom + idx_func;
+ if (rc == 0) {
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv_ret); /* side effects */
+ } else {
+ /* [ ... func this (crud) retval ] */
+ tv_funret = thr->valstack_top - 1;
+#if defined(DUK_USE_FASTINT)
+ /* Explicit check for fastint downgrade. */
+ DUK_TVAL_CHKFAST_INPLACE(tv_funret);
+#endif
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
+ }
+ }
+
+ duk_set_top(ctx, idx_func + 1); /* XXX: unnecessary, handle in adjust */
+
+ /* [ ... retval ] */
/* Ensure there is internal valstack spare before we exit; this may
* throw an alloc error. The same guaranteed size must be available
@@ -58104,88 +58383,123 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* minimal guarantee for an application.
*/
+ /* XXX: we should never shrink here; when we error out later, we'd
+ * need to potentially grow the value stack in error unwind which could
+ * cause another error.
+ */
+
(void) duk_valstack_resize_raw((duk_context *) thr,
entry_valstack_end, /* same as during entry */
DUK_VSRESIZE_FLAG_SHRINK | /* flags */
DUK_VSRESIZE_FLAG_COMPACT |
DUK_VSRESIZE_FLAG_THROW);
+ /* Restore entry thread executor curr_pc stack frame pointer. */
+ thr->ptr_curr_pc = entry_ptr_curr_pc;
- /*
- * Shrink checks and return with success.
- */
+ DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
+ thr->state = (duk_uint8_t) entry_thread_state;
+
+ DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
+ (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
+ (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
- retval = DUK_EXEC_SUCCESS;
- goto shrink_and_finished;
+ thr->heap->call_recursion_depth = entry_call_recursion_depth;
- /*
- * Ecmascript call
+ /* If the debugger is active we need to force an interrupt so that
+ * debugger breakpoints are rechecked. This is important for function
+ * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
+ * GH-303. Only needed for success path, error path always causes a
+ * breakpoint recheck in the executor. It would be enough to set this
+ * only when returning to an Ecmascript activation, but setting the flag
+ * on every return should have no ill effect.
*/
+#if defined(DUK_USE_DEBUGGER_SUPPORT)
+ if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
+ DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
+ DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
+ thr->interrupt_init -= thr->interrupt_counter;
+ thr->interrupt_counter = 0;
+ thr->heap->dbg_force_restart = 1;
+ }
+#endif
- ecmascript_call:
+#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
+ duk__interrupt_fixup(thr, entry_curr_thread);
+#endif
- /*
- * Shift to new valstack_bottom.
- */
+ return;
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
- act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
+ thread_state_error:
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%ld)", (long) thr->state);
+ DUK_UNREACHABLE();
+ return; /* never executed */
+}
+
+DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_valstack_end,
+ duk_size_t entry_catchstack_top,
+ duk_size_t entry_callstack_top,
+ duk_int_t entry_call_recursion_depth,
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
+ duk_instr_t **entry_ptr_curr_pc,
+ duk_idx_t idx_func
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ ) {
+ duk_context *ctx;
+ duk_tval *tv_ret;
- thr->valstack_bottom = thr->valstack_bottom + idx_args;
- /* keep current valstack_top */
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
+ ctx = (duk_context *) thr;
- /* [... func this | arg1 ... argN] ('this' must precede new bottom) */
+ DUK_DDD(DUK_DDDPRINT("error caught during duk__handle_call_inner(): %!T",
+ (duk_tval *) &thr->heap->lj.value1));
- /*
- * Bytecode executor call.
- *
- * Execute bytecode, handling any recursive function calls and
- * thread resumptions. Returns when execution would return from
- * the entry level activation. When the executor returns, a
- * single return value is left on the stack top.
- *
- * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
- * other types are handled internally by the executor.
- *
+ /* Other longjmp types are handled by executor before propagating
+ * the error here.
*/
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
+ DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
+ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
- /* thr->ptr_curr_pc is set by bytecode executor early on entry */
+ /* We don't need to sync back thr->ptr_curr_pc here because
+ * the bytecode executor always has a setjmp catchpoint which
+ * does that before errors propagate to here.
+ */
DUK_ASSERT(thr->ptr_curr_pc == NULL);
- DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
- duk_js_execute_bytecode(thr);
- DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
- /*
- * Unwind stack(s) and shift back to old valstack_bottom.
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* Restore the previous setjmp catcher so that any error in
+ * error handling will propagate outwards rather than re-enter
+ * the same handler. However, the error handling path must be
+ * designed to be error free so that sandboxing guarantees are
+ * reliable, see e.g. https://github.com/svaarala/duktape/issues/476.
*/
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+#endif
- DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
-
+ /* XXX: callstack unwind may now throw an error when closing
+ * scopes; this is a sandboxing issue, described in:
+ * https://github.com/svaarala/duktape/issues/476
+ */
duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
+ duk_hthread_catchstack_shrink_check(thr);
duk_hthread_callstack_unwind(thr, entry_callstack_top);
+ duk_hthread_callstack_shrink_check(thr);
thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- /* keep current valstack_top */
-
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
- DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
-
- /*
- * Manipulate value stack so that return value is on top.
- */
-
- /* [... func this (crud) retval] */
-
- duk_replace(ctx, idx_func);
- duk_set_top(ctx, idx_func + 1);
+ tv_ret = thr->valstack_bottom + idx_func; /* XXX: byte offset? */
+ DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, &thr->heap->lj.value1); /* side effects */
+#if defined(DUK_USE_FASTINT)
+ /* Explicit check for fastint downgrade. */
+ DUK_TVAL_CHKFAST_INPLACE(tv_ret);
+#endif
+ duk_set_top(ctx, idx_func + 1); /* XXX: could be eliminated with valstack adjust */
- /* [... retval] */
+ /* [ ... errobj ] */
/* Ensure there is internal valstack spare before we exit; this may
* throw an alloc error. The same guaranteed size must be available
@@ -58194,60 +58508,29 @@ duk_int_t duk_handle_call(duk_hthread *thr,
* minimal guarantee for an application.
*/
+ /* XXX: this needs to be reworked so that we never shrink the value
+ * stack on function entry so that we never need to grow it here.
+ * Needing to grow here is a sandboxing issue because we need to
+ * allocate which may cause an error in the error handling path
+ * and thus propagate an error out of a protected call.
+ */
+
(void) duk_valstack_resize_raw((duk_context *) thr,
entry_valstack_end, /* same as during entry */
DUK_VSRESIZE_FLAG_SHRINK | /* flags */
DUK_VSRESIZE_FLAG_COMPACT |
DUK_VSRESIZE_FLAG_THROW);
- /*
- * Shrink checks and return with success.
- */
-
- retval = DUK_EXEC_SUCCESS;
- goto shrink_and_finished;
-
- shrink_and_finished:
-#if defined(DUK_USE_FASTINT)
- /* Explicit check for fastint downgrade. */
- {
- duk_tval *tv_fi;
- tv_fi = duk_get_tval(ctx, -1);
- DUK_ASSERT(tv_fi != NULL);
- DUK_TVAL_CHKFAST_INPLACE(tv_fi);
- }
-#endif
-
- /* these are "soft" shrink checks, whose failures are ignored */
- /* XXX: would be nice if fast path was inlined */
- duk_hthread_catchstack_shrink_check(thr);
- duk_hthread_callstack_shrink_check(thr);
- goto finished;
-
- finished:
- if (need_setjmp) {
- /* Note: either pointer may be NULL (at entry), so don't assert;
- * this is now done potentially twice, which is OK
- */
- DUK_DDD(DUK_DDDPRINT("restore jmpbuf_ptr: %p -> %p (possibly already done)",
- (void *) (thr && thr->heap ? thr->heap->lj.jmpbuf_ptr : NULL),
- (void *) old_jmpbuf_ptr));
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
- /* These are just convenience "wiping" of state */
- thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
- thr->heap->lj.iserror = 0;
-
- /* Side effects should not be an issue here: tv_tmp is local and
- * thr->heap (and thr->heap->lj) have a stable pointer. Finalizer
- * runs etc capture even out-of-memory errors so nothing should
- * throw here.
- */
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
-
- DUK_DDD(DUK_DDDPRINT("setjmp catchpoint torn down"));
- }
+ /* These are just convenience "wiping" of state. Side effects should
+ * not be an issue here: thr->heap and thr->heap->lj have a stable
+ * pointer. Finalizer runs etc capture even out-of-memory errors so
+ * nothing should throw here.
+ */
+ thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
+ thr->heap->lj.iserror = 0;
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
+ DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
/* Restore entry thread executor curr_pc stack frame pointer. */
thr->ptr_curr_pc = entry_ptr_curr_pc;
@@ -58271,7 +58554,7 @@ duk_int_t duk_handle_call(duk_hthread *thr,
*/
#if defined(DUK_USE_DEBUGGER_SUPPORT)
if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- DUK_DD(DUK_DDPRINT("returning to ecmascript activation with debugger enabled, force interrupt"));
+ DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
thr->interrupt_init -= thr->interrupt_counter;
thr->interrupt_counter = 0;
@@ -58282,119 +58565,25 @@ duk_int_t duk_handle_call(duk_hthread *thr,
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
duk__interrupt_fixup(thr, entry_curr_thread);
#endif
-
- return retval;
-
- thread_state_error:
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%ld)", (long) thr->state);
- DUK_UNREACHABLE();
- return DUK_EXEC_ERROR; /* never executed */
-}
-
-/*
- * Manipulate value stack so that exactly 'num_stack_rets' return
- * values are at 'idx_retbase' in every case, assuming there are
- * 'rc' return values on top of stack.
- *
- * This is a bit tricky, because the called C function operates in
- * the same activation record and may have e.g. popped the stack
- * empty (below idx_retbase).
- */
-
-DUK_LOCAL void duk__safe_call_adjust_valstack(duk_hthread *thr, duk_idx_t idx_retbase, duk_idx_t num_stack_rets, duk_idx_t num_actual_rets) {
- duk_context *ctx = (duk_context *) thr;
- duk_idx_t idx_rcbase;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(idx_retbase >= 0);
- DUK_ASSERT(num_stack_rets >= 0);
- DUK_ASSERT(num_actual_rets >= 0);
-
- idx_rcbase = duk_get_top(ctx) - num_actual_rets; /* base of known return values */
-
- DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
- "num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld",
- (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(ctx),
- (long) idx_retbase, (long) idx_rcbase));
-
- DUK_ASSERT(idx_rcbase >= 0); /* caller must check */
-
- /* ensure space for final configuration (idx_retbase + num_stack_rets) and
- * intermediate configurations
- */
- duk_require_stack_top(ctx,
- (idx_rcbase > idx_retbase ? idx_rcbase : idx_retbase) +
- num_stack_rets);
-
- /* chop extra retvals away / extend with undefined */
- duk_set_top(ctx, idx_rcbase + num_stack_rets);
-
- if (idx_rcbase >= idx_retbase) {
- duk_idx_t count = idx_rcbase - idx_retbase;
- duk_idx_t i;
-
- DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
- "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
-
- /* nuke values at idx_retbase to get the first retval (initially
- * at idx_rcbase) to idx_retbase
- */
-
- DUK_ASSERT(count >= 0);
-
- for (i = 0; i < count; i++) {
- /* XXX: inefficient; block remove primitive */
- duk_remove(ctx, idx_retbase);
- }
- } else {
- duk_idx_t count = idx_retbase - idx_rcbase;
- duk_idx_t i;
-
- DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
- "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
-
- /* insert 'undefined' values at idx_rcbase to get the
- * return values to idx_retbase
- */
-
- DUK_ASSERT(count > 0);
-
- for (i = 0; i < count; i++) {
- /* XXX: inefficient; block insert primitive */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_rcbase);
- }
- }
}
/*
- * Make a "C protected call" within the current activation.
+ * duk_handle_safe_call(): make a "C protected call" within the
+ * current activation.
*
* The allowed thread states for making a call are the same as for
- * duk_handle_call().
- *
- * Note that like duk_handle_call(), even if this call is protected,
- * there are a few situations where the current (pre-entry) setjmp
- * catcher (or a fatal error handler if no such catcher exists) is
- * invoked:
- *
- * - Blatant API argument errors (e.g. num_stack_args is invalid,
- * so we can't form a reasonable return stack)
+ * duk_handle_call_xxx().
*
- * - Errors during error handling, e.g. failure to reallocate
- * space in the value stack due to an alloc error
- *
- * Such errors propagate outwards, ultimately to the fatal error
- * handler if nothing else.
+ * Error handling is similar to duk_handle_call_xxx(); errors may be thrown
+ * (and result in a fatal error) for insane arguments.
*/
/* XXX: bump preventcount by one for the duration of this call? */
-DUK_INTERNAL
-duk_int_t duk_handle_safe_call(duk_hthread *thr,
- duk_safe_call_function func,
- duk_idx_t num_stack_args,
- duk_idx_t num_stack_rets) {
+DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
+ duk_safe_call_function func,
+ duk_idx_t num_stack_args,
+ duk_idx_t num_stack_rets) {
duk_context *ctx = (duk_context *) thr;
duk_size_t entry_valstack_bottom_index;
duk_size_t entry_callstack_top;
@@ -58403,11 +58592,12 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
duk_hthread *entry_curr_thread;
duk_uint_fast8_t entry_thread_state;
duk_instr_t **entry_ptr_curr_pc;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
duk_jmpbuf *old_jmpbuf_ptr = NULL;
duk_jmpbuf our_jmpbuf;
+#endif
duk_idx_t idx_retbase;
duk_int_t retval;
- duk_ret_t rc;
DUK_ASSERT(thr != NULL);
DUK_ASSERT(ctx != NULL);
@@ -58442,10 +58632,9 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
(long) entry_thread_state));
if (idx_retbase < 0) {
- /*
- * Since stack indices are not reliable, we can't do anything useful
- * here. Invoke the existing setjmp catcher, or if it doesn't exist,
- * call the fatal error handler.
+ /* Since stack indices are not reliable, we can't do anything useful
+ * here. Invoke the existing setjmp catcher, or if it doesn't exist,
+ * call the fatal error handler.
*/
DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
@@ -58453,74 +58642,136 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
/* setjmp catchpoint setup */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
+#endif
- if (DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0) {
- goto handle_call;
- }
-
- /*
- * Error during call. The error value is at heap->lj.value1.
- *
- * Careful with variable accesses here; must be assigned to before
- * setjmp() or be declared volatile. See duk_handle_call().
- *
- * The following are such variables:
- * - duk_handle_safe_call() parameters
- * - entry_*
- * - idx_retbase
- *
- * The very first thing we do is restore the previous setjmp catcher.
- * This means that any error in error handling will propagate outwards
- * instead of causing a setjmp() re-entry above. The *only* actual
- * errors that should happen here are allocation errors.
- */
-
- DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()"));
-
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
- DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
-
- /* Note: either pointer may be NULL (at entry), so don't assert;
- * these are now restored twice which is OK.
- */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
- duk_hthread_callstack_unwind(thr, entry_callstack_top);
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
-
- /* [ ... | (crud) ] */
-
- /* XXX: space in valstack? see discussion in duk_handle_call. */
- duk_push_tval(ctx, &thr->heap->lj.value1);
-
- /* [ ... | (crud) errobj ] */
-
- DUK_ASSERT(duk_get_top(ctx) >= 1); /* at least errobj must be on stack */
-
- /* check that the valstack has space for the final amount and any
- * intermediate space needed; this is unoptimal but should be safe
- */
- duk_require_stack_top(ctx, idx_retbase + num_stack_rets); /* final configuration */
- duk_require_stack(ctx, num_stack_rets);
-
- duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */
-
- /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ try {
+#else
+ if (DUK_LIKELY(DUK_SETJMP(thr->heap->lj.jmpbuf_ptr->jb) == 0)) {
+ /* Success path. */
+#endif
+ DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
+
+ duk__handle_safe_call_inner(thr,
+ func,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top);
+
+ /* Longjmp state is kept clean in success path */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* Note: either pointer may be NULL (at entry), so don't assert */
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+#endif
- retval = DUK_EXEC_ERROR;
- goto shrink_and_finished;
+ retval = DUK_EXEC_SUCCESS;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ } catch (duk_internal_exception &exc) {
+#else
+ } else {
+ /* Error path. */
+#endif
+
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_UNREF(exc);
+#endif
+
+ duk__handle_safe_call_error(thr,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , old_jmpbuf_ptr
+#endif
+ );
+
+ /* Longjmp state is cleaned up by error handling */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
+ DUK_ASSERT(thr->heap->lj.iserror == 0);
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
+ DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
+
+ retval = DUK_EXEC_ERROR;
+ }
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ catch (std::exception &exc) {
+ const char *what = exc.what();
+ if (!what) {
+ what = "unknown";
+ }
+ DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
+ duk__handle_safe_call_error(thr,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top);
+ retval = DUK_EXEC_ERROR;
+ }
+ } catch (...) {
+ DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ try {
+ DUK_ERROR(thr, DUK_ERR_API_ERROR, "caught invalid c++ exception (perhaps thrown by user code)");
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
+ duk__handle_safe_call_error(thr,
+ idx_retbase,
+ num_stack_rets,
+ entry_valstack_bottom_index,
+ entry_callstack_top,
+ entry_catchstack_top);
+ retval = DUK_EXEC_ERROR;
+ }
+ }
+#endif
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
+#endif
+
+ duk__handle_safe_call_shared(thr,
+ idx_retbase,
+ num_stack_rets,
+ entry_call_recursion_depth,
+ entry_curr_thread,
+ entry_thread_state,
+ entry_ptr_curr_pc);
- /*
- * Handle call (inside setjmp)
- */
+ return retval;
+}
- handle_call:
+DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
+ duk_safe_call_function func,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_callstack_top,
+ duk_size_t entry_catchstack_top) {
+ duk_context *ctx;
+ duk_ret_t rc;
- DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
+ DUK_ASSERT(thr != NULL);
+ ctx = (duk_context *) thr;
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_UNREF(entry_valstack_bottom_index);
+ DUK_UNREF(entry_callstack_top);
+ DUK_UNREF(entry_catchstack_top);
/*
* Thread state check and book-keeping.
@@ -58583,7 +58834,7 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc));
/*
- * Valstack manipulation for results
+ * Valstack manipulation for results.
*/
/* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
@@ -58603,36 +58854,108 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
DUK_ERROR_API(thr, "not enough stack values for safe_call rc");
}
+ DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
+ DUK_ASSERT(thr->callstack_top == entry_callstack_top);
+
duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc);
+ return;
- /* Note: no need from callstack / catchstack shrink check */
- retval = DUK_EXEC_SUCCESS;
- goto finished;
+ thread_state_error:
+ DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%ld)", (long) thr->state);
+ DUK_UNREACHABLE();
+}
+
+DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_size_t entry_valstack_bottom_index,
+ duk_size_t entry_callstack_top,
+ duk_size_t entry_catchstack_top
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *old_jmpbuf_ptr
+#endif
+ ) {
+ duk_context *ctx;
- shrink_and_finished:
- /* these are "soft" shrink checks, whose failures are ignored */
- /* XXX: would be nice if fast path was inlined */
+ DUK_ASSERT(thr != NULL);
+ ctx = (duk_context *) thr;
+ DUK_ASSERT_CTX_VALID(ctx);
+
+ /*
+ * Error during call. The error value is at heap->lj.value1.
+ *
+ * The very first thing we do is restore the previous setjmp catcher.
+ * This means that any error in error handling will propagate outwards
+ * instead of causing a setjmp() re-entry above.
+ */
+
+ DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()"));
+
+ /* Other longjmp types are handled by executor before propagating
+ * the error here.
+ */
+ DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
+ DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
+ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
+
+ /* Note: either pointer may be NULL (at entry), so don't assert. */
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+#endif
+
+ DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
+ DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
+ duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
duk_hthread_catchstack_shrink_check(thr);
+ duk_hthread_callstack_unwind(thr, entry_callstack_top);
duk_hthread_callstack_shrink_check(thr);
- goto finished;
+ thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
- finished:
- /* Note: either pointer may be NULL (at entry), so don't assert */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
+ /* [ ... | (crud) ] */
- /* These are just convenience "wiping" of state */
- thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
- thr->heap->lj.iserror = 0;
+ /* XXX: space in valstack? see discussion in duk_handle_call_xxx(). */
+ duk_push_tval(ctx, &thr->heap->lj.value1);
+
+ /* [ ... | (crud) errobj ] */
+
+ DUK_ASSERT(duk_get_top(ctx) >= 1); /* at least errobj must be on stack */
+
+ /* check that the valstack has space for the final amount and any
+ * intermediate space needed; this is unoptimal but should be safe
+ */
+ duk_require_stack_top(ctx, idx_retbase + num_stack_rets); /* final configuration */
+ duk_require_stack(ctx, num_stack_rets);
- /* Side effects should not be an issue here: tv_tmp is local and
- * thr->heap (and thr->heap->lj) have a stable pointer. Finalizer
- * runs etc capture even out-of-memory errors so nothing should
- * throw here.
+ duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */
+
+ /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
+
+ /* These are just convenience "wiping" of state. Side effects should
+ * not be an issue here: thr->heap and thr->heap->lj have a stable
+ * pointer. Finalizer runs etc capture even out-of-memory errors so
+ * nothing should throw here.
*/
+ thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
+ thr->heap->lj.iserror = 0;
DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
+}
- DUK_DDD(DUK_DDDPRINT("setjmp catchpoint torn down"));
+DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
+ duk_idx_t idx_retbase,
+ duk_idx_t num_stack_rets,
+ duk_int_t entry_call_recursion_depth,
+ duk_hthread *entry_curr_thread,
+ duk_uint_fast8_t entry_thread_state,
+ duk_instr_t **entry_ptr_curr_pc) {
+ duk_context *ctx;
+
+ DUK_ASSERT(thr != NULL);
+ ctx = (duk_context *) thr;
+ DUK_ASSERT_CTX_VALID(ctx);
+ DUK_UNREF(ctx);
+ DUK_UNREF(idx_retbase);
+ DUK_UNREF(num_stack_rets);
/* Restore entry thread executor curr_pc stack frame pointer. */
thr->ptr_curr_pc = entry_ptr_curr_pc;
@@ -58662,13 +58985,6 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
duk__interrupt_fixup(thr, entry_curr_thread);
#endif
-
- return retval;
-
- thread_state_error:
- DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%ld)", (long) thr->state);
- DUK_UNREACHABLE();
- return DUK_EXEC_ERROR; /* never executed */
}
/*
@@ -58697,10 +59013,9 @@ duk_int_t duk_handle_safe_call(duk_hthread *thr,
* return an error so caller can fall back to a normal call path.
*/
-DUK_INTERNAL
-duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
- duk_idx_t num_stack_args,
- duk_small_uint_t call_flags) {
+DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
+ duk_idx_t num_stack_args,
+ duk_small_uint_t call_flags) {
duk_context *ctx = (duk_context *) thr;
duk_size_t entry_valstack_bottom_index;
duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
@@ -58740,7 +59055,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
* - an Ecmascript activation must be on top of the callstack
* - there cannot be any active catchstack entries
*/
-#ifdef DUK_USE_ASSERTIONS
+#if defined(DUK_USE_ASSERTIONS)
if (call_flags & DUK_CALL_FLAG_IS_TAILCALL) {
duk_size_t our_callstack_index;
duk_size_t i;
@@ -58766,6 +59081,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
#endif /* DUK_USE_ASSERTIONS */
entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
+ /* XXX: rework */
idx_func = duk_normalize_index(thr, -num_stack_args - 2);
idx_args = idx_func + 2;
@@ -58781,7 +59097,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
(long) idx_args,
(long) entry_valstack_bottom_index));
- if (idx_func < 0 || idx_args < 0) {
+ if (DUK_UNLIKELY(idx_func < 0 || idx_args < 0)) {
/* XXX: assert? compiler is responsible for this never happening */
DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
}
@@ -58916,7 +59232,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
/* Start filling in the activation */
act->func = func; /* don't want an intermediate exposed state with func == NULL */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
act->prev_caller = NULL;
#endif
DUK_ASSERT(func != NULL);
@@ -58927,13 +59243,13 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
act->prev_line = 0;
#endif
DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
-#ifdef DUK_USE_REFERENCE_COUNTING
+#if defined(DUK_USE_REFERENCE_COUNTING)
DUK_HOBJECT_INCREF(thr, func);
act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */
#endif
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#ifdef DUK_USE_TAILCALL
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
+#if defined(DUK_USE_TAILCALL)
#error incorrect options: tail calls enabled with function caller property
#endif
/* XXX: this doesn't actually work properly for tail calls, so
@@ -59019,7 +59335,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
act->func = func;
act->var_env = NULL;
act->lex_env = NULL;
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
act->prev_caller = NULL;
#endif
DUK_ASSERT(func != NULL);
@@ -59037,14 +59353,14 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
DUK_HOBJECT_INCREF(thr, func); /* act->func */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
+#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
duk__update_func_caller_prop(thr, func);
act = thr->callstack + thr->callstack_top - 1;
#endif
}
- /* [... func this arg1 ... argN] (not tail call)
- * [this | arg1 ... argN] (tail call)
+ /* [ ... func this arg1 ... argN ] (not tail call)
+ * [ this | arg1 ... argN ] (tail call)
*
* idx_args updated to match
*/
@@ -59058,6 +59374,8 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
* Delayed creation (on demand) is handled in duk_js_var.c.
*/
+ /* XXX: unify handling with native call. */
+
DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
if (!DUK_HOBJECT_HAS_NEWENV(func)) {
@@ -59085,7 +59403,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
DUK_ASSERT(env != NULL);
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
/* original input stack before nargs/nregs handling must be
* intact for 'arguments' object
@@ -59093,7 +59411,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
duk__handle_createargs_for_call(thr, func, env, num_stack_args);
- /* [... arg1 ... argN envobj] */
+ /* [ ... arg1 ... argN envobj ] */
act = thr->callstack + thr->callstack_top - 1;
act->lex_env = env;
@@ -59103,7 +59421,7 @@ duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
duk_pop(ctx);
env_done:
- /* [... arg1 ... argN] */
+ /* [ ... arg1 ... argN ] */
/*
* Setup value stack: clamp to 'nargs', fill up to 'nregs'
@@ -60056,8 +60374,8 @@ DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_boo
*/
DUK_ASSERT(func->temp_max >= 0);
- h_res->nregs = func->temp_max;
- h_res->nargs = duk_hobject_get_length(thr, func->h_argnames);
+ h_res->nregs = (duk_uint16_t) func->temp_max;
+ h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames);
DUK_ASSERT(h_res->nregs >= h_res->nargs); /* pass2 allocation handles this */
#if defined(DUK_USE_DEBUGGER_SUPPORT)
h_res->start_line = (duk_uint32_t) func->min_line;
@@ -67407,7 +67725,7 @@ DUK_LOCAL void duk__vm_arith_unary_op(duk_hthread *thr, duk_tval *tv_x, duk_idx_
#endif
}
-DUK_LOCAL void duk__vm_bitwise_not(duk_hthread *thr, duk_tval *tv_x, duk_small_uint_fast_t idx_z) {
+DUK_LOCAL void duk__vm_bitwise_not(duk_hthread *thr, duk_tval *tv_x, duk_uint_fast_t idx_z) {
/*
* E5 Section 11.4.8
*/
@@ -68311,6 +68629,9 @@ DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
* Return value is already on the stack top: [ ... retval ].
*/
+ /* XXX: could unwind catchstack here, so that call handling
+ * didn't need to do that?
+ */
DUK_DDD(DUK_DDDPRINT("-> return propagated up to entry level, exit bytecode executor"));
return DUK__RETHAND_FINISHED;
}
@@ -68895,16 +69216,66 @@ DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *
thr->ptr_curr_pc = NULL; \
} while (0)
+DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
+ duk_hthread *entry_thread,
+ duk_size_t entry_callstack_top,
+ duk_int_t entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , duk_jmpbuf *entry_jmpbuf_ptr
+#endif
+ ) {
+ duk_small_uint_t lj_ret;
+
+ /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc
+ * before longjmp.
+ */
+ DUK_ASSERT(heap->curr_thread != NULL);
+ DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL);
+
+ /* XXX: signalling the need to shrink check (only if unwound) */
+
+ /* Must be restored here to handle e.g. yields properly. */
+ heap->call_recursion_depth = entry_call_recursion_depth;
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* Switch to caller's setjmp() catcher so that if an error occurs
+ * during error handling, it is always propagated outwards instead
+ * of causing an infinite loop in our own handler.
+ */
+ heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
+#endif
+
+ lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top);
+
+ if (lj_ret == DUK__LONGJMP_RESTART) {
+ /* Restart bytecode execution, possibly with a changed thread. */
+ ;
+ } else {
+ /* Rethrow error to calling state. */
+ DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW);
+
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ /* Longjmp handling has restored jmpbuf_ptr. */
+ DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
+#endif
+
+ /* Thread may have changed, e.g. YIELD converted to THROW. */
+ duk_err_longjmp(heap->curr_thread);
+ DUK_UNREACHABLE();
+ }
+}
+
/* Outer executor with setjmp/longjmp handling. */
DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
/* Entry level info. */
duk_hthread *entry_thread;
duk_size_t entry_callstack_top;
duk_int_t entry_call_recursion_depth;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
duk_jmpbuf *entry_jmpbuf_ptr;
-
- duk_heap *heap;
duk_jmpbuf jmpbuf;
+#endif
+ duk_heap *heap;
DUK_ASSERT(exec_thr != NULL);
DUK_ASSERT(exec_thr->heap != NULL);
@@ -68918,7 +69289,9 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
heap = entry_thread->heap;
entry_callstack_top = entry_thread->callstack_top;
entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
+#endif
/*
* Note: we currently assume that the setjmp() catchpoint is
@@ -68930,55 +69303,83 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
*/
for (;;) {
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
heap->lj.jmpbuf_ptr = &jmpbuf;
DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL);
+#endif
- if (DUK_SETJMP(heap->lj.jmpbuf_ptr->jb) != 0) {
- duk_small_uint_t lj_ret;
-
- DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
-
- /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc
- * before longjmp.
- */
- DUK_ASSERT(heap->curr_thread != NULL);
- DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL);
-
- /* XXX: signalling the need to shrink check (only if unwound) */
-
- /* Must be restored here to handle e.g. yields properly. */
- heap->call_recursion_depth = entry_call_recursion_depth;
-
- /* Switch to caller's setjmp() catcher so that if an error occurs
- * during error handling, it is always propagated outwards instead
- * of causing an infinite loop in our own handler.
- */
- heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
-
- lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top);
-
- if (lj_ret == DUK__LONGJMP_RESTART) {
- /* Restart bytecode execution, possibly with a changed thread. */
- ;
- } else {
- /* Rethrow error to calling state. */
- DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW);
-
- /* Longjmp handling has restored jmpbuf_ptr. */
- DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
-
- /* Thread may have changed, e.g. YIELD converted to THROW. */
- duk_err_longjmp(heap->curr_thread);
- DUK_UNREACHABLE();
- }
- } else {
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ try {
+#else
+ if (DUK_LIKELY(DUK_SETJMP(heap->lj.jmpbuf_ptr->jb) == 0)) {
+#endif
/* Execute bytecode until returned or longjmp(). */
duk__js_execute_bytecode_inner(entry_thread, entry_callstack_top);
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
/* Successful return: restore jmpbuf and return to caller. */
heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
+#endif
+
return;
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ } catch (duk_internal_exception &exc) {
+#else
+ } else {
+#endif
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ DUK_UNREF(exc);
+#endif
+ DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
+
+ duk__handle_executor_error(heap,
+ entry_thread,
+ entry_callstack_top,
+ entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , entry_jmpbuf_ptr
+#endif
+ );
}
+#if defined(DUK_USE_CPP_EXCEPTIONS)
+ catch (std::exception &exc) {
+ const char *what = exc.what();
+ if (!what) {
+ what = "unknown";
+ }
+ DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
+ try {
+ DUK_ASSERT(heap->curr_thread != NULL);
+ DUK_ERROR(heap->curr_thread, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
+ duk__handle_executor_error(heap,
+ entry_thread,
+ entry_callstack_top,
+ entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , entry_jmpbuf_ptr
+#endif
+ );
+ }
+ } catch (...) {
+ DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
+ try {
+ DUK_ASSERT(heap->curr_thread != NULL);
+ DUK_ERROR(heap->curr_thread, DUK_ERR_API_ERROR, "caught invalid c++ exception (perhaps thrown by user code)");
+ } catch (duk_internal_exception exc) {
+ DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
+ duk__handle_executor_error(heap,
+ entry_thread,
+ entry_callstack_top,
+ entry_call_recursion_depth
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
+ , entry_jmpbuf_ptr
+#endif
+ );
+ }
+ }
+#endif
}
DUK_UNREACHABLE();
@@ -70238,9 +70639,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
*/
DUK_ASSERT(DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func) != duk_bi_global_object_eval);
- duk_handle_call(thr,
- num_stack_args,
- call_flags);
+ duk_handle_call_unprotected(thr,
+ num_stack_args,
+ call_flags);
/* duk_js_call.c is required to restore the stack reserve
* so we only need to reset the top.
@@ -70284,9 +70685,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
}
}
- duk_handle_call(thr,
- num_stack_args,
- call_flags);
+ duk_handle_call_unprotected(thr,
+ num_stack_args,
+ call_flags);
/* duk_js_call.c is required to restore the stack reserve
* so we only need to reset the top.
@@ -71136,7 +71537,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type);
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
+#endif
duk_err_longjmp(thr);
DUK_UNREACHABLE();
}
@@ -71173,7 +71576,9 @@ DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_th
duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
+#if !defined(DUK_USE_CPP_EXCEPTIONS)
DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
+#endif
duk_err_longjmp(thr);
DUK_UNREACHABLE();
break;
@@ -74846,7 +75251,7 @@ DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t s
lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
lex_ctx->input_line = input_line;
- DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "char decode failed");
+ DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "utf8 decode failed");
}
DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
@@ -75006,7 +75411,7 @@ DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) {
error_clipped: /* clipped codepoint */
error_encoding: /* invalid codepoint encoding or codepoint */
- DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "char decode failed");
+ DUK_ERROR(lex_ctx->thr, DUK_ERR_SYNTAX_ERROR, "utf8 decode failed");
return 0;
}
@@ -77784,7 +78189,7 @@ DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify
DUK_DDD(DUK_DDDPRINT("digit before carry: %ld", (long) t));
if (++t < nc_ctx->B) {
DUK_DDD(DUK_DDDPRINT("rounding carry terminated"));
- *p = t;
+ *p = (duk_uint8_t) t;
break;
}
diff --git a/javascript/duktape/duktape.h b/javascript/duktape/duktape.h
index d672ede..7f7a7c3 100644
--- a/javascript/duktape/duktape.h
+++ b/javascript/duktape/duktape.h
@@ -1,12 +1,12 @@
/*
- * Duktape public API for Duktape 1.3.99.
+ * Duktape public API for Duktape 1.4.0.
* See the API reference for documentation on call semantics.
* The exposed API is inside the DUK_API_PUBLIC_H_INCLUDED
* include guard. Other parts of the header are Duktape
* internal and related to platform/compiler/feature detection.
*
- * Git commit b7b1c5fd2d1d4550140d57e05a7b32f540082bfa (v1.3.0-383-gb7b1c5f).
- * Git branch duk-config-improvements.
+ * Git commit cad6f595382a0cc1a7e4207794ade5be11b3e397 (v1.4.0).
+ * Git branch master.
*
* See Duktape AUTHORS.rst and LICENSE.txt for copyright and
* licensing information.
@@ -20,7 +20,7 @@
*
* (http://opensource.org/licenses/MIT)
*
- * Copyright (c) 2013-2015 by Duktape authors (see AUTHORS.rst)
+ * Copyright (c) 2013-2016 by Duktape authors (see AUTHORS.rst)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -71,6 +71,7 @@
* * Legimet <legimet.calc(a)gmail.com>
* * Karl Skomski <karl(a)skomski.com>
* * Bruce Pascoe <fatcerberus1(a)gmail.com>
+ * * Ren\u00e9 Hollander <rene(a)rene8888.at>
*
* Other contributions
* ===================
@@ -107,6 +108,7 @@
* * https://github.com/sstruchtrup
* * Michael Drake (https://github.com/tlsa)
* * https://github.com/chris-y
+ * * Laurent Zubiaur (https://github.com/lzubiaur)
*
* If you are accidentally missing from this list, send me an e-mail
* (``sami.vaarala(a)iki.fi``) and I'll fix the omission.
@@ -211,16 +213,16 @@ struct duk_number_list_entry {
* have 99 for patch level (e.g. 0.10.99 would be a development version
* after 0.10.0 but before the next official release).
*/
-#define DUK_VERSION 10399L
+#define DUK_VERSION 10400L
/* Git commit, describe, and branch for Duktape build. Useful for
* non-official snapshot builds so that application code can easily log
* which Duktape snapshot was used. Not available in the Ecmascript
* environment.
*/
-#define DUK_GIT_COMMIT "b7b1c5fd2d1d4550140d57e05a7b32f540082bfa"
-#define DUK_GIT_DESCRIBE "v1.3.0-383-gb7b1c5f"
-#define DUK_GIT_BRANCH "duk-config-improvements"
+#define DUK_GIT_COMMIT "cad6f595382a0cc1a7e4207794ade5be11b3e397"
+#define DUK_GIT_DESCRIBE "v1.4.0"
+#define DUK_GIT_BRANCH "master"
/* Duktape debug protocol version used by this build. */
#define DUK_DEBUG_PROTOCOL_VERSION 1
@@ -556,7 +558,7 @@ DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_e
DUK_EXTERNAL_DECL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags);
#define duk_push_buffer(ctx,size,dynamic) \
- duk_push_buffer_raw((ctx), (size), (dynamic) ? DUK_BUF_FLAG_DYNAMIC : 0);
+ duk_push_buffer_raw((ctx), (size), (dynamic) ? DUK_BUF_FLAG_DYNAMIC : 0)
#define duk_push_fixed_buffer(ctx,size) \
duk_push_buffer_raw((ctx), (size), 0 /*flags*/)
#define duk_push_dynamic_buffer(ctx,size) \
--
NetSurf Browser
7 years, 10 months
netsurf: branch master updated. release/3.3-572-g6122517
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/6122517bf4356a04cdde4...
...commit http://git.netsurf-browser.org/netsurf.git/commit/6122517bf4356a04cdde411...
...tree http://git.netsurf-browser.org/netsurf.git/tree/6122517bf4356a04cdde4119b...
The branch, master has been updated
via 6122517bf4356a04cdde4119b8a3f3777eff4159 (commit)
from 30f992730e4957d4cf6319524c1054f8ec77c716 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=6122517bf4356a04cdd...
commit 6122517bf4356a04cdde4119b8a3f3777eff4159
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Only show context menu text selection options if there is text selected
diff --git a/amiga/ctxmenu.c b/amiga/ctxmenu.c
index 8b3b03a..e9de270 100644
--- a/amiga/ctxmenu.c
+++ b/amiga/ctxmenu.c
@@ -112,7 +112,7 @@ HOOKF(void, ami_ctxmenu_item_websearch, APTR, window, struct IntuiMessage *)
nsurl *url;
struct gui_window_2 *gwin = (struct gui_window_2 *)hook->h_Data;
- const char *sel = browser_window_get_selection(gwin->gw->bw);
+ char *sel = browser_window_get_selection(gwin->gw->bw);
ret = search_web_omni(sel, SEARCH_WEB_OMNI_SEARCHONLY, &url);
if (ret == NSERROR_OK) {
@@ -128,6 +128,8 @@ HOOKF(void, ami_ctxmenu_item_websearch, APTR, window, struct IntuiMessage *)
if (ret != NSERROR_OK) {
warn_user(messages_get_errorcode(ret), 0);
}
+
+ free(sel);
}
HOOKF(void, ami_ctxmenu_item_urlopentab, APTR, window, struct IntuiMessage *)
@@ -290,6 +292,7 @@ static uint32 ami_ctxmenu_hook_func(struct Hook *hook, struct Window *window, st
int mx = window->MouseX;
int my = window->MouseY;
int x, y;
+ char *sel;
if(msg->State != CM_QUERY) return 0;
if(nsoption_bool(kiosk_mode) == true) return 0;
@@ -315,12 +318,14 @@ static uint32 ami_ctxmenu_hook_func(struct Hook *hook, struct Window *window, st
browser_window_get_features(gwin->gw->bw, x, y, &ccdata);
if((browser_window_can_select(gwin->gw->bw)) &&
- ((browser_window_get_editor_flags(gwin->gw->bw) & BW_EDITOR_CAN_COPY))) {
+ ((browser_window_get_editor_flags(gwin->gw->bw) & BW_EDITOR_CAN_COPY)) &&
+ (sel = browser_window_get_selection(gwin->gw->bw))) {
ami_ctxmenu_add_item(root_menu, AMI_CTX_ID_SELCOPY, gwin);
ami_ctxmenu_add_item(root_menu, AMI_CTX_ID_WEBSEARCH, gwin);
ctxmenu_has_content = true;
+ free(sel);
}
if(ccdata.link) {
-----------------------------------------------------------------------
Summary of changes:
amiga/ctxmenu.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/amiga/ctxmenu.c b/amiga/ctxmenu.c
index 8b3b03a..e9de270 100644
--- a/amiga/ctxmenu.c
+++ b/amiga/ctxmenu.c
@@ -112,7 +112,7 @@ HOOKF(void, ami_ctxmenu_item_websearch, APTR, window, struct IntuiMessage *)
nsurl *url;
struct gui_window_2 *gwin = (struct gui_window_2 *)hook->h_Data;
- const char *sel = browser_window_get_selection(gwin->gw->bw);
+ char *sel = browser_window_get_selection(gwin->gw->bw);
ret = search_web_omni(sel, SEARCH_WEB_OMNI_SEARCHONLY, &url);
if (ret == NSERROR_OK) {
@@ -128,6 +128,8 @@ HOOKF(void, ami_ctxmenu_item_websearch, APTR, window, struct IntuiMessage *)
if (ret != NSERROR_OK) {
warn_user(messages_get_errorcode(ret), 0);
}
+
+ free(sel);
}
HOOKF(void, ami_ctxmenu_item_urlopentab, APTR, window, struct IntuiMessage *)
@@ -290,6 +292,7 @@ static uint32 ami_ctxmenu_hook_func(struct Hook *hook, struct Window *window, st
int mx = window->MouseX;
int my = window->MouseY;
int x, y;
+ char *sel;
if(msg->State != CM_QUERY) return 0;
if(nsoption_bool(kiosk_mode) == true) return 0;
@@ -315,12 +318,14 @@ static uint32 ami_ctxmenu_hook_func(struct Hook *hook, struct Window *window, st
browser_window_get_features(gwin->gw->bw, x, y, &ccdata);
if((browser_window_can_select(gwin->gw->bw)) &&
- ((browser_window_get_editor_flags(gwin->gw->bw) & BW_EDITOR_CAN_COPY))) {
+ ((browser_window_get_editor_flags(gwin->gw->bw) & BW_EDITOR_CAN_COPY)) &&
+ (sel = browser_window_get_selection(gwin->gw->bw))) {
ami_ctxmenu_add_item(root_menu, AMI_CTX_ID_SELCOPY, gwin);
ami_ctxmenu_add_item(root_menu, AMI_CTX_ID_WEBSEARCH, gwin);
ctxmenu_has_content = true;
+ free(sel);
}
if(ccdata.link) {
--
NetSurf Browser
7 years, 10 months
netsurf: branch master updated. release/3.3-571-g30f9927
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/30f992730e4957d4cf631...
...commit http://git.netsurf-browser.org/netsurf.git/commit/30f992730e4957d4cf63195...
...tree http://git.netsurf-browser.org/netsurf.git/tree/30f992730e4957d4cf6319524...
The branch, master has been updated
via 30f992730e4957d4cf6319524c1054f8ec77c716 (commit)
from f5dc18010555cb58079214ccbd5749e7e1e86696 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=30f992730e4957d4cf6...
commit 30f992730e4957d4cf6319524c1054f8ec77c716
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Re-instate the ability to do a web search for selected text
diff --git a/amiga/ctxmenu.c b/amiga/ctxmenu.c
index 42d0da3..8b3b03a 100644
--- a/amiga/ctxmenu.c
+++ b/amiga/ctxmenu.c
@@ -47,6 +47,7 @@
#include "desktop/browser.h"
#include "desktop/browser_history.h"
#include "desktop/mouse.h"
+#include "desktop/searchweb.h"
#include "desktop/textinput.h"
#include "utils/log.h"
@@ -58,6 +59,7 @@ enum {
/* Text selection */
AMI_CTX_ID_SELCOPY,
+ AMI_CTX_ID_WEBSEARCH,
/* Links */
AMI_CTX_ID_URLOPENTAB,
@@ -104,6 +106,30 @@ HOOKF(void, ami_ctxmenu_item_selcopy, APTR, window, struct IntuiMessage *)
browser_window_key_press(gwin->gw->bw, NS_KEY_CLEAR_SELECTION);
}
+HOOKF(void, ami_ctxmenu_item_websearch, APTR, window, struct IntuiMessage *)
+{
+ nserror ret = NSERROR_OK;
+ nsurl *url;
+
+ struct gui_window_2 *gwin = (struct gui_window_2 *)hook->h_Data;
+ const char *sel = browser_window_get_selection(gwin->gw->bw);
+
+ ret = search_web_omni(sel, SEARCH_WEB_OMNI_SEARCHONLY, &url);
+ if (ret == NSERROR_OK) {
+ browser_window_navigate(gwin->gw->bw,
+ url,
+ NULL,
+ BW_NAVIGATE_HISTORY,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+ if (ret != NSERROR_OK) {
+ warn_user(messages_get_errorcode(ret), 0);
+ }
+}
+
HOOKF(void, ami_ctxmenu_item_urlopentab, APTR, window, struct IntuiMessage *)
{
struct browser_window *bw;
@@ -292,6 +318,7 @@ static uint32 ami_ctxmenu_hook_func(struct Hook *hook, struct Window *window, st
((browser_window_get_editor_flags(gwin->gw->bw) & BW_EDITOR_CAN_COPY))) {
ami_ctxmenu_add_item(root_menu, AMI_CTX_ID_SELCOPY, gwin);
+ ami_ctxmenu_add_item(root_menu, AMI_CTX_ID_WEBSEARCH, gwin);
ctxmenu_has_content = true;
}
@@ -417,6 +444,8 @@ void ami_ctxmenu_init(void)
ami_ctxmenu_alloc_item(AMI_CTX_ID_SELCOPY, "CopyNS", "C", "TBImages:list_copy",
ami_ctxmenu_item_selcopy);
+ ami_ctxmenu_alloc_item(AMI_CTX_ID_WEBSEARCH, "SearchWeb", NULL, "TBImages:list_search",
+ ami_ctxmenu_item_websearch);
ami_ctxmenu_alloc_item(AMI_CTX_ID_URLOPENTAB, "LinkNewTab", NULL, "TBImages:list_tab",
ami_ctxmenu_item_urlopentab);
-----------------------------------------------------------------------
Summary of changes:
amiga/ctxmenu.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/amiga/ctxmenu.c b/amiga/ctxmenu.c
index 42d0da3..8b3b03a 100644
--- a/amiga/ctxmenu.c
+++ b/amiga/ctxmenu.c
@@ -47,6 +47,7 @@
#include "desktop/browser.h"
#include "desktop/browser_history.h"
#include "desktop/mouse.h"
+#include "desktop/searchweb.h"
#include "desktop/textinput.h"
#include "utils/log.h"
@@ -58,6 +59,7 @@ enum {
/* Text selection */
AMI_CTX_ID_SELCOPY,
+ AMI_CTX_ID_WEBSEARCH,
/* Links */
AMI_CTX_ID_URLOPENTAB,
@@ -104,6 +106,30 @@ HOOKF(void, ami_ctxmenu_item_selcopy, APTR, window, struct IntuiMessage *)
browser_window_key_press(gwin->gw->bw, NS_KEY_CLEAR_SELECTION);
}
+HOOKF(void, ami_ctxmenu_item_websearch, APTR, window, struct IntuiMessage *)
+{
+ nserror ret = NSERROR_OK;
+ nsurl *url;
+
+ struct gui_window_2 *gwin = (struct gui_window_2 *)hook->h_Data;
+ const char *sel = browser_window_get_selection(gwin->gw->bw);
+
+ ret = search_web_omni(sel, SEARCH_WEB_OMNI_SEARCHONLY, &url);
+ if (ret == NSERROR_OK) {
+ browser_window_navigate(gwin->gw->bw,
+ url,
+ NULL,
+ BW_NAVIGATE_HISTORY,
+ NULL,
+ NULL,
+ NULL);
+ nsurl_unref(url);
+ }
+ if (ret != NSERROR_OK) {
+ warn_user(messages_get_errorcode(ret), 0);
+ }
+}
+
HOOKF(void, ami_ctxmenu_item_urlopentab, APTR, window, struct IntuiMessage *)
{
struct browser_window *bw;
@@ -292,6 +318,7 @@ static uint32 ami_ctxmenu_hook_func(struct Hook *hook, struct Window *window, st
((browser_window_get_editor_flags(gwin->gw->bw) & BW_EDITOR_CAN_COPY))) {
ami_ctxmenu_add_item(root_menu, AMI_CTX_ID_SELCOPY, gwin);
+ ami_ctxmenu_add_item(root_menu, AMI_CTX_ID_WEBSEARCH, gwin);
ctxmenu_has_content = true;
}
@@ -417,6 +444,8 @@ void ami_ctxmenu_init(void)
ami_ctxmenu_alloc_item(AMI_CTX_ID_SELCOPY, "CopyNS", "C", "TBImages:list_copy",
ami_ctxmenu_item_selcopy);
+ ami_ctxmenu_alloc_item(AMI_CTX_ID_WEBSEARCH, "SearchWeb", NULL, "TBImages:list_search",
+ ami_ctxmenu_item_websearch);
ami_ctxmenu_alloc_item(AMI_CTX_ID_URLOPENTAB, "LinkNewTab", NULL, "TBImages:list_tab",
ami_ctxmenu_item_urlopentab);
--
NetSurf Browser
7 years, 10 months
netsurf: branch master updated. release/3.3-570-gf5dc180
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/f5dc18010555cb5807921...
...commit http://git.netsurf-browser.org/netsurf.git/commit/f5dc18010555cb58079214c...
...tree http://git.netsurf-browser.org/netsurf.git/tree/f5dc18010555cb58079214ccb...
The branch, master has been updated
via f5dc18010555cb58079214ccbd5749e7e1e86696 (commit)
from bc8bf0e57517f30d5143004d6b0b679552a74870 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=f5dc18010555cb58079...
commit f5dc18010555cb58079214ccbd5749e7e1e86696
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Use layers.library for bitmap tiling on OS3
This solves the worst of the rendering problems on that platform.
diff --git a/amiga/os3support.h b/amiga/os3support.h
index 553dcb2..c6160ca 100644
--- a/amiga/os3support.h
+++ b/amiga/os3support.h
@@ -198,6 +198,14 @@ struct OutlineFont {
struct TagItem *olf_OTagList;
};
+/* BackFillMessage */
+struct BackFillMessage {
+ struct Layer *Layer;
+ struct Rectangle Bounds;
+ LONG OffsetX;
+ LONG OffsetY;
+};
+
/* icon.library v51 (ie. AfA_OS version) */
#define ICONCTRLA_SetImageDataFormat (ICONA_Dummy + 0x67) /*103*/
#define ICONCTRLA_GetImageDataFormat (ICONA_Dummy + 0x68) /*104*/
diff --git a/amiga/plotters.c b/amiga/plotters.c
index 0af5dd5..dc68f93 100644
--- a/amiga/plotters.c
+++ b/amiga/plotters.c
@@ -48,9 +48,7 @@
#include "amiga/rtg.h"
#include "amiga/utf8.h"
-#ifdef __amigaos4__
-static void ami_bitmap_tile_hook(struct Hook *hook,struct RastPort *rp,struct BackFillMessage *bfmsg);
-#endif
+HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage *);
struct bfbitmap {
struct BitMap *bm;
@@ -614,7 +612,7 @@ static bool ami_bitmap_tile(int x, int y, int width, int height,
tbm = ami_bitmap_get_native(bitmap,width,height,glob->rp->BitMap);
if(!tbm) return true;
-#ifdef __amigaos4__
+
ox = x;
oy = y;
@@ -650,7 +648,7 @@ static bool ami_bitmap_tile(int x, int y, int width, int height,
yf = y + height;
ym = y;
}
-
+#ifdef __amigaos4__
if(bitmap->opaque)
{
bfh = CreateBackFillHook(BFHA_BitMap,tbm,
@@ -661,6 +659,7 @@ static bool ami_bitmap_tile(int x, int y, int width, int height,
TAG_DONE);
}
else
+#endif
{
bfbm.bm = tbm;
bfbm.width = width;
@@ -668,82 +667,50 @@ static bool ami_bitmap_tile(int x, int y, int width, int height,
bfbm.offsetx = ox;
bfbm.offsety = oy;
bfbm.mask = ami_bitmap_get_mask(bitmap, width, height, tbm);
- bfh = AllocVecTags(sizeof(struct Hook), AVT_ClearWithValue, 0, TAG_DONE); /* NB: Was not MEMF_PRIVATE */
+ bfh = ami_misc_allocvec_clear(sizeof(struct Hook), 0); /* NB: Was not MEMF_PRIVATE */
bfh->h_Entry = (HOOKFUNC)ami_bitmap_tile_hook;
bfh->h_SubEntry = 0;
bfh->h_Data = &bfbm;
}
InstallLayerHook(glob->rp->Layer,bfh);
-
EraseRect(glob->rp,xm,ym,xf,yf);
-
InstallLayerHook(glob->rp->Layer,LAYERS_NOBACKFILL);
- if(bitmap->opaque) DeleteBackFillHook(bfh);
- else FreeVec(bfh);
-#else
- /* get left most tile position */
- if (repeat_x)
- for (; x > glob->rect.MinX; x -= width)
- ;
-
- /* get top most tile position */
- if (repeat_y)
- for (; y > glob->rect.MinY; y -= height)
- ;
- /* tile down and across to extents */
- for (xf = x; xf < glob->rect.MaxX; xf += width) {
- for (yf = y; yf < glob->rect.MaxY; yf += height) {
-
- ULONG tag, tag_data = NULL, minterm = 0xc0;
-
- if(bitmap->opaque) {
- minterm = 0xc0;
- } else {
- if((tag_data = (ULONG)ami_bitmap_get_mask(bitmap, width, height, tbm)))
- minterm = (ABC|ABNC|ANBC);
- }
-
- if(tag_data) {
- BltMaskBitMapRastPort(tbm, 0, 0, glob->rp, x, y, width, height, minterm, tag_data);
- } else {
- BltBitMapRastPort(tbm, 0, 0, glob->rp, x, y, width, height, 0xc0);
- }
- }
- }
+#ifdef __amigaos4__
+ if(bitmap->opaque) DeleteBackFillHook(bfh);
+ else
#endif
+ FreeVec(bfh);
- if((bitmap->dto == NULL) && (tbm != bitmap->nativebm))
- {
+ if((bitmap->dto == NULL) && (tbm != bitmap->nativebm)) {
ami_rtg_freebitmap(tbm);
}
return true;
}
-#ifdef __amigaos4__
-static void ami_bitmap_tile_hook(struct Hook *hook,struct RastPort *rp,struct BackFillMessage *bfmsg)
+HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage *)
{
int xf,yf;
struct bfbitmap *bfbm = (struct bfbitmap *)hook->h_Data;
- /* tile down and across to extents (bfmsg->Bounds.MinX)*/
- for (xf = -bfbm->offsetx; xf < bfmsg->Bounds.MaxX; xf += bfbm->width) {
- for (yf = -bfbm->offsety; yf < bfmsg->Bounds.MaxY; yf += bfbm->height) {
+ /* tile down and across to extents (msg->Bounds.MinX)*/
+ for (xf = -bfbm->offsetx; xf < msg->Bounds.MaxX; xf += bfbm->width) {
+ for (yf = -bfbm->offsety; yf < msg->Bounds.MaxY; yf += bfbm->height) {
#ifdef __amigaos4__
if(__builtin_expect((GfxBase->LibNode.lib_Version >= 53) &&
(palette_mapped == false), 1)) {
CompositeTags(COMPOSITE_Src_Over_Dest, bfbm->bm, rp->BitMap,
COMPTAG_Flags, COMPFLAG_IgnoreDestAlpha,
- COMPTAG_DestX,bfmsg->Bounds.MinX,
- COMPTAG_DestY,bfmsg->Bounds.MinY,
- COMPTAG_DestWidth,bfmsg->Bounds.MaxX - bfmsg->Bounds.MinX + 1,
- COMPTAG_DestHeight,bfmsg->Bounds.MaxY - bfmsg->Bounds.MinY + 1,
- COMPTAG_SrcWidth,bfbm->width,
- COMPTAG_SrcHeight,bfbm->height,
- COMPTAG_OffsetX,xf,
- COMPTAG_OffsetY,yf,
+ COMPTAG_DestX, msg->Bounds.MinX,
+ COMPTAG_DestY, msg->Bounds.MinY,
+ COMPTAG_DestWidth, msg->Bounds.MaxX - msg->Bounds.MinX + 1,
+ COMPTAG_DestHeight, msg->Bounds.MaxY - msg->Bounds.MinY + 1,
+ COMPTAG_SrcWidth, bfbm->width,
+ COMPTAG_SrcHeight, bfbm->height,
+ COMPTAG_OffsetX, xf,
+ COMPTAG_OffsetY, yf,
COMPTAG_FriendBitMap, scrn->RastPort.BitMap,
TAG_DONE);
}
@@ -761,7 +728,7 @@ static void ami_bitmap_tile_hook(struct Hook *hook,struct RastPort *rp,struct Ba
if((tag_data = (ULONG)bfbm->mask))
minterm = MINTERM_SRCMASK;
}
-
+#ifdef __amigaos4__
BltBitMapTags(BLITA_Width, bfbm->width,
BLITA_Height, bfbm->height,
BLITA_Source, bfbm->bm,
@@ -773,11 +740,19 @@ static void ami_bitmap_tile_hook(struct Hook *hook,struct RastPort *rp,struct Ba
BLITA_Minterm, minterm,
tag, tag_data,
TAG_DONE);
+#else
+ if(tag_data) {
+ BltMaskBitMapRastPort(bfbm->bm, 0, 0, rp, xf, yf,
+ bfbm->width, bfbm->height, minterm, tag_data);
+ } else {
+ BltBitMapRastPort(bfbm->bm, 0, 0, rp, xf, yf,
+ bfbm->width, bfbm->height, minterm);
+ }
+#endif
}
}
}
}
-#endif
static void ami_bezier(struct bez_point *a, struct bez_point *b, struct bez_point *c,
struct bez_point *d, double t, struct bez_point *p) {
-----------------------------------------------------------------------
Summary of changes:
amiga/os3support.h | 8 +++++
amiga/plotters.c | 89 +++++++++++++++++++---------------------------------
2 files changed, 40 insertions(+), 57 deletions(-)
diff --git a/amiga/os3support.h b/amiga/os3support.h
index 553dcb2..c6160ca 100644
--- a/amiga/os3support.h
+++ b/amiga/os3support.h
@@ -198,6 +198,14 @@ struct OutlineFont {
struct TagItem *olf_OTagList;
};
+/* BackFillMessage */
+struct BackFillMessage {
+ struct Layer *Layer;
+ struct Rectangle Bounds;
+ LONG OffsetX;
+ LONG OffsetY;
+};
+
/* icon.library v51 (ie. AfA_OS version) */
#define ICONCTRLA_SetImageDataFormat (ICONA_Dummy + 0x67) /*103*/
#define ICONCTRLA_GetImageDataFormat (ICONA_Dummy + 0x68) /*104*/
diff --git a/amiga/plotters.c b/amiga/plotters.c
index 0af5dd5..dc68f93 100644
--- a/amiga/plotters.c
+++ b/amiga/plotters.c
@@ -48,9 +48,7 @@
#include "amiga/rtg.h"
#include "amiga/utf8.h"
-#ifdef __amigaos4__
-static void ami_bitmap_tile_hook(struct Hook *hook,struct RastPort *rp,struct BackFillMessage *bfmsg);
-#endif
+HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage *);
struct bfbitmap {
struct BitMap *bm;
@@ -614,7 +612,7 @@ static bool ami_bitmap_tile(int x, int y, int width, int height,
tbm = ami_bitmap_get_native(bitmap,width,height,glob->rp->BitMap);
if(!tbm) return true;
-#ifdef __amigaos4__
+
ox = x;
oy = y;
@@ -650,7 +648,7 @@ static bool ami_bitmap_tile(int x, int y, int width, int height,
yf = y + height;
ym = y;
}
-
+#ifdef __amigaos4__
if(bitmap->opaque)
{
bfh = CreateBackFillHook(BFHA_BitMap,tbm,
@@ -661,6 +659,7 @@ static bool ami_bitmap_tile(int x, int y, int width, int height,
TAG_DONE);
}
else
+#endif
{
bfbm.bm = tbm;
bfbm.width = width;
@@ -668,82 +667,50 @@ static bool ami_bitmap_tile(int x, int y, int width, int height,
bfbm.offsetx = ox;
bfbm.offsety = oy;
bfbm.mask = ami_bitmap_get_mask(bitmap, width, height, tbm);
- bfh = AllocVecTags(sizeof(struct Hook), AVT_ClearWithValue, 0, TAG_DONE); /* NB: Was not MEMF_PRIVATE */
+ bfh = ami_misc_allocvec_clear(sizeof(struct Hook), 0); /* NB: Was not MEMF_PRIVATE */
bfh->h_Entry = (HOOKFUNC)ami_bitmap_tile_hook;
bfh->h_SubEntry = 0;
bfh->h_Data = &bfbm;
}
InstallLayerHook(glob->rp->Layer,bfh);
-
EraseRect(glob->rp,xm,ym,xf,yf);
-
InstallLayerHook(glob->rp->Layer,LAYERS_NOBACKFILL);
- if(bitmap->opaque) DeleteBackFillHook(bfh);
- else FreeVec(bfh);
-#else
- /* get left most tile position */
- if (repeat_x)
- for (; x > glob->rect.MinX; x -= width)
- ;
-
- /* get top most tile position */
- if (repeat_y)
- for (; y > glob->rect.MinY; y -= height)
- ;
- /* tile down and across to extents */
- for (xf = x; xf < glob->rect.MaxX; xf += width) {
- for (yf = y; yf < glob->rect.MaxY; yf += height) {
-
- ULONG tag, tag_data = NULL, minterm = 0xc0;
-
- if(bitmap->opaque) {
- minterm = 0xc0;
- } else {
- if((tag_data = (ULONG)ami_bitmap_get_mask(bitmap, width, height, tbm)))
- minterm = (ABC|ABNC|ANBC);
- }
-
- if(tag_data) {
- BltMaskBitMapRastPort(tbm, 0, 0, glob->rp, x, y, width, height, minterm, tag_data);
- } else {
- BltBitMapRastPort(tbm, 0, 0, glob->rp, x, y, width, height, 0xc0);
- }
- }
- }
+#ifdef __amigaos4__
+ if(bitmap->opaque) DeleteBackFillHook(bfh);
+ else
#endif
+ FreeVec(bfh);
- if((bitmap->dto == NULL) && (tbm != bitmap->nativebm))
- {
+ if((bitmap->dto == NULL) && (tbm != bitmap->nativebm)) {
ami_rtg_freebitmap(tbm);
}
return true;
}
-#ifdef __amigaos4__
-static void ami_bitmap_tile_hook(struct Hook *hook,struct RastPort *rp,struct BackFillMessage *bfmsg)
+HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage *)
{
int xf,yf;
struct bfbitmap *bfbm = (struct bfbitmap *)hook->h_Data;
- /* tile down and across to extents (bfmsg->Bounds.MinX)*/
- for (xf = -bfbm->offsetx; xf < bfmsg->Bounds.MaxX; xf += bfbm->width) {
- for (yf = -bfbm->offsety; yf < bfmsg->Bounds.MaxY; yf += bfbm->height) {
+ /* tile down and across to extents (msg->Bounds.MinX)*/
+ for (xf = -bfbm->offsetx; xf < msg->Bounds.MaxX; xf += bfbm->width) {
+ for (yf = -bfbm->offsety; yf < msg->Bounds.MaxY; yf += bfbm->height) {
#ifdef __amigaos4__
if(__builtin_expect((GfxBase->LibNode.lib_Version >= 53) &&
(palette_mapped == false), 1)) {
CompositeTags(COMPOSITE_Src_Over_Dest, bfbm->bm, rp->BitMap,
COMPTAG_Flags, COMPFLAG_IgnoreDestAlpha,
- COMPTAG_DestX,bfmsg->Bounds.MinX,
- COMPTAG_DestY,bfmsg->Bounds.MinY,
- COMPTAG_DestWidth,bfmsg->Bounds.MaxX - bfmsg->Bounds.MinX + 1,
- COMPTAG_DestHeight,bfmsg->Bounds.MaxY - bfmsg->Bounds.MinY + 1,
- COMPTAG_SrcWidth,bfbm->width,
- COMPTAG_SrcHeight,bfbm->height,
- COMPTAG_OffsetX,xf,
- COMPTAG_OffsetY,yf,
+ COMPTAG_DestX, msg->Bounds.MinX,
+ COMPTAG_DestY, msg->Bounds.MinY,
+ COMPTAG_DestWidth, msg->Bounds.MaxX - msg->Bounds.MinX + 1,
+ COMPTAG_DestHeight, msg->Bounds.MaxY - msg->Bounds.MinY + 1,
+ COMPTAG_SrcWidth, bfbm->width,
+ COMPTAG_SrcHeight, bfbm->height,
+ COMPTAG_OffsetX, xf,
+ COMPTAG_OffsetY, yf,
COMPTAG_FriendBitMap, scrn->RastPort.BitMap,
TAG_DONE);
}
@@ -761,7 +728,7 @@ static void ami_bitmap_tile_hook(struct Hook *hook,struct RastPort *rp,struct Ba
if((tag_data = (ULONG)bfbm->mask))
minterm = MINTERM_SRCMASK;
}
-
+#ifdef __amigaos4__
BltBitMapTags(BLITA_Width, bfbm->width,
BLITA_Height, bfbm->height,
BLITA_Source, bfbm->bm,
@@ -773,11 +740,19 @@ static void ami_bitmap_tile_hook(struct Hook *hook,struct RastPort *rp,struct Ba
BLITA_Minterm, minterm,
tag, tag_data,
TAG_DONE);
+#else
+ if(tag_data) {
+ BltMaskBitMapRastPort(bfbm->bm, 0, 0, rp, xf, yf,
+ bfbm->width, bfbm->height, minterm, tag_data);
+ } else {
+ BltBitMapRastPort(bfbm->bm, 0, 0, rp, xf, yf,
+ bfbm->width, bfbm->height, minterm);
+ }
+#endif
}
}
}
}
-#endif
static void ami_bezier(struct bez_point *a, struct bez_point *b, struct bez_point *c,
struct bez_point *d, double t, struct bez_point *p) {
--
NetSurf Browser
7 years, 10 months
netsurf: branch master updated. release/3.3-569-gbc8bf0e
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/bc8bf0e57517f30d51430...
...commit http://git.netsurf-browser.org/netsurf.git/commit/bc8bf0e57517f30d5143004...
...tree http://git.netsurf-browser.org/netsurf.git/tree/bc8bf0e57517f30d5143004d6...
The branch, master has been updated
via bc8bf0e57517f30d5143004d6b0b679552a74870 (commit)
from 93fbed0f2cdbd84def2af8c444f2a63a7e9f5f22 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=bc8bf0e57517f30d514...
commit bc8bf0e57517f30d5143004d6b0b679552a74870
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Fix the bitmap font layout a bit
diff --git a/amiga/font_bitmap.c b/amiga/font_bitmap.c
index 01815ef..eed43db 100644
--- a/amiga/font_bitmap.c
+++ b/amiga/font_bitmap.c
@@ -100,20 +100,38 @@ static void ami_font_bm_close(struct TextFont *bmfont)
CloseFont(bmfont);
}
+static size_t ami_font_bm_convert_local_to_utf8_offset(const char *utf8string, int length, size_t offset)
+{
+ size_t chr = 0;
+
+ for(int i = 0; i < offset; i++) {
+ chr = utf8_next(utf8string, length, chr);
+ }
+
+ return chr;
+}
+
+
bool amiga_bm_nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width)
{
- *width = length;
+ char *localtext = NULL;
if((glob == NULL) || (glob->rp == NULL)) return false;
+ *width = length;
struct TextFont *bmfont = ami_font_bm_open(glob->rp, fstyle);
-
if(bmfont == NULL) return false;
-// convert to local charset
- *width = TextLength(glob->rp, string, length);
+ if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
+ ami_font_bm_close(bmfont);
+ return false;
+ }
+
+ *width = TextLength(glob->rp, localtext, strlen(localtext));
+ free(localtext);
+
ami_font_bm_close(bmfont);
return true;
@@ -137,19 +155,25 @@ bool amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyle,
{
struct TextExtent extent;
struct TextFont *bmfont;
+ char *localtext = NULL;
+ size_t co = 0;
if((glob == NULL) || (glob->rp == NULL)) return false;
bmfont = ami_font_bm_open(glob->rp, fstyle);
-
if(bmfont == NULL) return false;
- // convert to local charset
- *char_offset = TextFit(glob->rp, string, length,
- &extent, NULL, 1, x, 32767);
+ if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
+ ami_font_bm_close(bmfont);
+ return false;
+ }
+ co = TextFit(glob->rp, localtext, strlen(localtext),
+ &extent, NULL, 1, x, 32767);
+ *char_offset = ami_font_bm_convert_local_to_utf8_offset(string, length, co);
*actual_x = extent.te_Extent.MaxX;
+ free(localtext);
ami_font_bm_close(bmfont);
return true;
@@ -184,33 +208,50 @@ bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
int x, size_t *char_offset, int *actual_x)
{
struct TextExtent extent;
- ULONG co;
+ size_t co, offset;
char *charp;
+ char *localtext;
if((glob == NULL) || (glob->rp == NULL)) return false;
struct TextFont *bmfont = ami_font_bm_open(glob->rp, fstyle);
-
if(bmfont == NULL) return false;
- co = TextFit(glob->rp, string, length,
+ if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
+ ami_font_bm_close(bmfont);
+ return false;
+ }
+
+ offset = TextFit(glob->rp, localtext, strlen(localtext),
&extent, NULL, 1, x, 32767);
- charp = string + co;
+ co = offset;
+ charp = localtext + co;
+
- while(((*charp != ' ')) && (charp > string)) {
+ while((*charp != ' ') && (co > 0)) {
charp--;
co--;
}
- if(co > 0) {
- *actual_x = TextLength(glob->rp, string, co);
- *char_offset = co;
+ if(co == 0) {
+ co = offset;
+ charp = localtext + co;
+ while((*charp != ' ') && (co < strlen(localtext))) {
+ charp++;
+ co++;
+ }
+ }
+
+ if((co > 0) && (co < strlen(localtext))) {
+ *actual_x = TextLength(glob->rp, localtext, co);
+ *char_offset = ami_font_bm_convert_local_to_utf8_offset(string, length, co);
} else {
*actual_x = x;
*char_offset = length;
}
+ free(localtext);
ami_font_bm_close(bmfont);
return true;
@@ -224,7 +265,7 @@ ULONG ami_font_bm_text(struct RastPort *rp, const char *string, ULONG length,
if(bmfont == NULL) return 0;
if(utf8_to_local_encoding(string, length, &localtext) == NSERROR_OK) {
Move(rp, dx, dy);
- Text(rp, localtext, length);
+ Text(rp, localtext, strlen(localtext));
free(localtext);
}
-----------------------------------------------------------------------
Summary of changes:
amiga/font_bitmap.c | 75 +++++++++++++++++++++++++++++++++++++++------------
1 file changed, 58 insertions(+), 17 deletions(-)
diff --git a/amiga/font_bitmap.c b/amiga/font_bitmap.c
index 01815ef..eed43db 100644
--- a/amiga/font_bitmap.c
+++ b/amiga/font_bitmap.c
@@ -100,20 +100,38 @@ static void ami_font_bm_close(struct TextFont *bmfont)
CloseFont(bmfont);
}
+static size_t ami_font_bm_convert_local_to_utf8_offset(const char *utf8string, int length, size_t offset)
+{
+ size_t chr = 0;
+
+ for(int i = 0; i < offset; i++) {
+ chr = utf8_next(utf8string, length, chr);
+ }
+
+ return chr;
+}
+
+
bool amiga_bm_nsfont_width(const plot_font_style_t *fstyle,
const char *string, size_t length,
int *width)
{
- *width = length;
+ char *localtext = NULL;
if((glob == NULL) || (glob->rp == NULL)) return false;
+ *width = length;
struct TextFont *bmfont = ami_font_bm_open(glob->rp, fstyle);
-
if(bmfont == NULL) return false;
-// convert to local charset
- *width = TextLength(glob->rp, string, length);
+ if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
+ ami_font_bm_close(bmfont);
+ return false;
+ }
+
+ *width = TextLength(glob->rp, localtext, strlen(localtext));
+ free(localtext);
+
ami_font_bm_close(bmfont);
return true;
@@ -137,19 +155,25 @@ bool amiga_bm_nsfont_position_in_string(const plot_font_style_t *fstyle,
{
struct TextExtent extent;
struct TextFont *bmfont;
+ char *localtext = NULL;
+ size_t co = 0;
if((glob == NULL) || (glob->rp == NULL)) return false;
bmfont = ami_font_bm_open(glob->rp, fstyle);
-
if(bmfont == NULL) return false;
- // convert to local charset
- *char_offset = TextFit(glob->rp, string, length,
- &extent, NULL, 1, x, 32767);
+ if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
+ ami_font_bm_close(bmfont);
+ return false;
+ }
+ co = TextFit(glob->rp, localtext, strlen(localtext),
+ &extent, NULL, 1, x, 32767);
+ *char_offset = ami_font_bm_convert_local_to_utf8_offset(string, length, co);
*actual_x = extent.te_Extent.MaxX;
+ free(localtext);
ami_font_bm_close(bmfont);
return true;
@@ -184,33 +208,50 @@ bool amiga_bm_nsfont_split(const plot_font_style_t *fstyle,
int x, size_t *char_offset, int *actual_x)
{
struct TextExtent extent;
- ULONG co;
+ size_t co, offset;
char *charp;
+ char *localtext;
if((glob == NULL) || (glob->rp == NULL)) return false;
struct TextFont *bmfont = ami_font_bm_open(glob->rp, fstyle);
-
if(bmfont == NULL) return false;
- co = TextFit(glob->rp, string, length,
+ if(utf8_to_local_encoding(string, length, &localtext) != NSERROR_OK) {
+ ami_font_bm_close(bmfont);
+ return false;
+ }
+
+ offset = TextFit(glob->rp, localtext, strlen(localtext),
&extent, NULL, 1, x, 32767);
- charp = string + co;
+ co = offset;
+ charp = localtext + co;
+
- while(((*charp != ' ')) && (charp > string)) {
+ while((*charp != ' ') && (co > 0)) {
charp--;
co--;
}
- if(co > 0) {
- *actual_x = TextLength(glob->rp, string, co);
- *char_offset = co;
+ if(co == 0) {
+ co = offset;
+ charp = localtext + co;
+ while((*charp != ' ') && (co < strlen(localtext))) {
+ charp++;
+ co++;
+ }
+ }
+
+ if((co > 0) && (co < strlen(localtext))) {
+ *actual_x = TextLength(glob->rp, localtext, co);
+ *char_offset = ami_font_bm_convert_local_to_utf8_offset(string, length, co);
} else {
*actual_x = x;
*char_offset = length;
}
+ free(localtext);
ami_font_bm_close(bmfont);
return true;
@@ -224,7 +265,7 @@ ULONG ami_font_bm_text(struct RastPort *rp, const char *string, ULONG length,
if(bmfont == NULL) return 0;
if(utf8_to_local_encoding(string, length, &localtext) == NSERROR_OK) {
Move(rp, dx, dy);
- Text(rp, localtext, length);
+ Text(rp, localtext, strlen(localtext));
free(localtext);
}
--
NetSurf Browser
7 years, 11 months
netsurf: branch master updated. release/3.3-568-g93fbed0
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/93fbed0f2cdbd84def2af...
...commit http://git.netsurf-browser.org/netsurf.git/commit/93fbed0f2cdbd84def2af8c...
...tree http://git.netsurf-browser.org/netsurf.git/tree/93fbed0f2cdbd84def2af8c44...
The branch, master has been updated
via 93fbed0f2cdbd84def2af8c444f2a63a7e9f5f22 (commit)
from 1886aaf6af39d8814033c896b300e300e292b329 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=93fbed0f2cdbd84def2...
commit 93fbed0f2cdbd84def2af8c444f2a63a7e9f5f22
Author: Rob Kendrick <rob.kendrick(a)codethink.co.uk>
Commit: Rob Kendrick <rob.kendrick(a)codethink.co.uk>
Style fixes
diff --git a/gtk/fetch.c b/gtk/fetch.c
index 13ffceb..06770b6 100644
--- a/gtk/fetch.c
+++ b/gtk/fetch.c
@@ -1,5 +1,6 @@
/*
- * Copyright 2014 vincent Sanders <vince(a)netsurf-browser.org>
+ * Copyright 2007, 2014 Vincent Sanders <vince(a)netsurf-browser.org>
+ * Copyright 2007 Rob Kendrick <rjek(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -37,6 +38,9 @@
#include "gtk/resources.h"
#include "gtk/fetch.h"
+#define HASH_SIZE 117
+#define MAX_LINE_LEN 256
+
static struct hash_table *mime_hash = NULL;
void gtk_fetch_filetype_init(const char *mimefile)
@@ -44,7 +48,7 @@ void gtk_fetch_filetype_init(const char *mimefile)
struct stat statbuf;
FILE *fh = NULL;
- mime_hash = hash_create(117);
+ mime_hash = hash_create(HASH_SIZE);
/* first, check to see if /etc/mime.types in preference */
@@ -78,13 +82,13 @@ void gtk_fetch_filetype_init(const char *mimefile)
return;
}
- while (!feof(fh)) {
- char line[256], *ptr, *type, *ext;
+ while (feof(fh) == 0) {
+ char line[MAX_LINE_LEN], *ptr, *type, *ext;
- if (fgets(line, 256, fh) == NULL)
+ if (fgets(line, sizeof(line), fh) == NULL)
break;
- if (!feof(fh) && line[0] != '#') {
+ if ((feof(fh) == 0) && line[0] != '#') {
ptr = line;
/* search for the first non-whitespace character */
@@ -120,7 +124,7 @@ void gtk_fetch_filetype_init(const char *mimefile)
ptr++;
}
- while(true) {
+ while (true) {
ext = ptr;
/* search for the first whitespace char or
-----------------------------------------------------------------------
Summary of changes:
gtk/fetch.c | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/gtk/fetch.c b/gtk/fetch.c
index 13ffceb..06770b6 100644
--- a/gtk/fetch.c
+++ b/gtk/fetch.c
@@ -1,5 +1,6 @@
/*
- * Copyright 2014 vincent Sanders <vince(a)netsurf-browser.org>
+ * Copyright 2007, 2014 Vincent Sanders <vince(a)netsurf-browser.org>
+ * Copyright 2007 Rob Kendrick <rjek(a)netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -37,6 +38,9 @@
#include "gtk/resources.h"
#include "gtk/fetch.h"
+#define HASH_SIZE 117
+#define MAX_LINE_LEN 256
+
static struct hash_table *mime_hash = NULL;
void gtk_fetch_filetype_init(const char *mimefile)
@@ -44,7 +48,7 @@ void gtk_fetch_filetype_init(const char *mimefile)
struct stat statbuf;
FILE *fh = NULL;
- mime_hash = hash_create(117);
+ mime_hash = hash_create(HASH_SIZE);
/* first, check to see if /etc/mime.types in preference */
@@ -78,13 +82,13 @@ void gtk_fetch_filetype_init(const char *mimefile)
return;
}
- while (!feof(fh)) {
- char line[256], *ptr, *type, *ext;
+ while (feof(fh) == 0) {
+ char line[MAX_LINE_LEN], *ptr, *type, *ext;
- if (fgets(line, 256, fh) == NULL)
+ if (fgets(line, sizeof(line), fh) == NULL)
break;
- if (!feof(fh) && line[0] != '#') {
+ if ((feof(fh) == 0) && line[0] != '#') {
ptr = line;
/* search for the first non-whitespace character */
@@ -120,7 +124,7 @@ void gtk_fetch_filetype_init(const char *mimefile)
ptr++;
}
- while(true) {
+ while (true) {
ext = ptr;
/* search for the first whitespace char or
--
NetSurf Browser
7 years, 11 months
netsurf: branch master updated. release/3.3-566-g178dd6b
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/178dd6bbaea01f6f4206e...
...commit http://git.netsurf-browser.org/netsurf.git/commit/178dd6bbaea01f6f4206e16...
...tree http://git.netsurf-browser.org/netsurf.git/tree/178dd6bbaea01f6f4206e167b...
The branch, master has been updated
via 178dd6bbaea01f6f4206e167b0cb0481804e4a9f (commit)
from adccaadb57224f7a1b149e12862f845f3c729efa (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=178dd6bbaea01f6f420...
commit 178dd6bbaea01f6f4206e167b0cb0481804e4a9f
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Fix OS4 build errors/warnings
diff --git a/amiga/font_cache.c b/amiga/font_cache.c
index 5814f83..09f9ef8 100644
--- a/amiga/font_cache.c
+++ b/amiga/font_cache.c
@@ -17,6 +17,7 @@
*/
#include "amiga/os3support.h"
+#include <string.h>
#include <proto/timer.h>
#include <proto/utility.h>
diff --git a/amiga/font_cache.h b/amiga/font_cache.h
index 813b67d..7c95ba5 100644
--- a/amiga/font_cache.h
+++ b/amiga/font_cache.h
@@ -18,6 +18,9 @@
#ifndef AMIGA_FONT_CACHE_H
#define AMIGA_FONT_CACHE_H
+
+#include <proto/timer.h>
+
struct ami_font_cache_node
{
#ifdef __amigaos4__
-----------------------------------------------------------------------
Summary of changes:
amiga/font_cache.c | 1 +
amiga/font_cache.h | 3 +++
2 files changed, 4 insertions(+)
diff --git a/amiga/font_cache.c b/amiga/font_cache.c
index 5814f83..09f9ef8 100644
--- a/amiga/font_cache.c
+++ b/amiga/font_cache.c
@@ -17,6 +17,7 @@
*/
#include "amiga/os3support.h"
+#include <string.h>
#include <proto/timer.h>
#include <proto/utility.h>
diff --git a/amiga/font_cache.h b/amiga/font_cache.h
index 813b67d..7c95ba5 100644
--- a/amiga/font_cache.h
+++ b/amiga/font_cache.h
@@ -18,6 +18,9 @@
#ifndef AMIGA_FONT_CACHE_H
#define AMIGA_FONT_CACHE_H
+
+#include <proto/timer.h>
+
struct ami_font_cache_node
{
#ifdef __amigaos4__
--
NetSurf Browser
7 years, 11 months